using System; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using CadParamPluging.Common; namespace CadParamPluging.Cad.Drawers { public static class RingRawFreeForgeCenterPunchDrawer { public static void Draw(CadContext ctx, ParamBag bag, Point3d center, double scaleFactor = 1.0) { if (ctx == null) throw new ArgumentNullException(nameof(ctx)); if (bag == null) throw new ArgumentNullException(nameof(bag)); // Apply scaling var effectiveBag = scaleFactor < 1.0 ? ScaleParamBag(bag, scaleFactor) : bag; var db = ctx.Database; var tr = ctx.Transaction; var prevDb = HostApplicationServices.WorkingDatabase; HostApplicationServices.WorkingDatabase = db; BlockTableRecord btr; try { var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); } finally { HostApplicationServices.WorkingDatabase = prevDb; } // Construct DrawingContext // Note: SpecialCondition needs to be "中心冲孔" var context = new FeatureDrivenDrawer.DrawingContext { Ctx = ctx, Bag = effectiveBag, OriginalBag = bag, Center = center, DeliveryStatus = "毛料态", StructuralFeature = "环形", SpecialCondition = "中心冲孔", ProcessMethod = "自由锻", Btr = btr, // We need to instantiate DrawingStyleManager. Accessing internal constructor via reflection or if it's internal to assembly we are fine. // Assuming same assembly. Style = new DrawingStyleManager(db, tr) }; DrawCore(context); } private static ParamBag ScaleParamBag(ParamBag original, double scaleFactor) { if (original == null || scaleFactor <= 0 || (Math.Abs(scaleFactor - 1.0) < 1e-6)) { return original; } var scaled = new ParamBag(); // 需要缩放的尺寸参数Key列表 var sizeKeys = new System.Collections.Generic.HashSet(StringComparer.OrdinalIgnoreCase) { // 环形参数 FeatureDrivenDrawer.KeyOuterDiameter1, FeatureDrivenDrawer.KeyInnerDiameter2, FeatureDrivenDrawer.KeyHeight1, FeatureDrivenDrawer.KeyOuterDiameter1Prime, FeatureDrivenDrawer.KeyInnerDiameter2Prime, FeatureDrivenDrawer.KeyHeight1Prime, FeatureDrivenDrawer.KeyMinWallThickness, // 圆角参数 FeatureDrivenDrawer.KeyUnspecifiedFilletRadiusMax, FeatureDrivenDrawer.KeyInnerRadiusMax, // 包含公差参数以保持一致性 FeatureDrivenDrawer.KeyOuterDiameter1TolPlus, FeatureDrivenDrawer.KeyOuterDiameter1TolMinus, FeatureDrivenDrawer.KeyInnerDiameter2TolPlus, FeatureDrivenDrawer.KeyInnerDiameter2TolMinus, FeatureDrivenDrawer.KeyHeight1TolPlus, FeatureDrivenDrawer.KeyHeight1TolMinus }; foreach (var key in original.GetKeys()) { var value = original.GetString(key); if (sizeKeys.Contains(key)) { // 尝试解析为数值并缩放 if (double.TryParse(value, out var numValue)) { var scaledValue = numValue * scaleFactor; // 保留适当的小数位数,避免精度问题 scaled.Set(key, scaledValue.ToString("F4")); } else { scaled.Set(key, value); } } else { // 非尺寸参数直接复制 scaled.Set(key, value); } } return scaled; } private static void DrawCore(FeatureDrivenDrawer.DrawingContext ctx) { var bag = ctx.Bag; var outerDia = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyOuterDiameter1); var height = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1); if (!outerDia.HasValue || !height.HasValue) return; double W = outerDia.Value; double H = height.Value; double ox = ctx.Center.X - W / 2.0; double oy = ctx.Center.Y - H / 2.0; // Unconditionally retrieve variables for Part Contour (Prime parameters) var outerDiaPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyOuterDiameter1Prime); var innerDiaPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyInnerDiameter2Prime); var heightPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1Prime); // Radii var outerFilletR = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyUnspecifiedFilletRadiusMax) ?? 0; var innerFilletR = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyInnerRadiusMax) ?? 0; // Pre-calculate inner hole parameters var innerDia = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyInnerDiameter2); var innerTolPlus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyInnerDiameter2TolPlus); var innerTolMinus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyInnerDiameter2TolMinus); double? xInnerLeft = null; double? xInnerRight = null; // Full Section: Draw Contour with Fillet for both sides if (innerDia.HasValue && innerDia.Value > 0 && innerDia.Value < W) { double xInnerLeftVal = ctx.Center.X - innerDia.Value / 2.0; double xInnerRightVal = ctx.Center.X + innerDia.Value / 2.0; // Draw Left Section Contour (Outer Edge: ox, Inner Edge: xInnerLeftVal) // Left Side of Left Section is Outer -> outerFilletR // Right Side of Left Section is Inner -> innerFilletR DrawSectionWithAsymmetricFillets(ctx, ox, xInnerLeftVal, oy, H, outerFilletR, innerFilletR); if (innerFilletR > 0) { double cxLeft = xInnerLeftVal - innerFilletR; double cyLeft = oy + H - innerFilletR; DrawInnerRadiusLeader(ctx, cxLeft, cyLeft, innerFilletR, true); } // Draw Right Section Contour (Inner Edge: xInnerRightVal, Outer Edge: ox + W) // Left Side of Right Section is Inner -> innerFilletR // Right Side of Right Section is Outer -> outerFilletR DrawSectionWithAsymmetricFillets(ctx, xInnerRightVal, ox + W, oy, H, innerFilletR, outerFilletR); // Draw Connecting Lines (Hole Back View) - Top and Bottom // Extend into the inner fillet radius double lineStart = xInnerLeftVal - innerFilletR; double lineEnd = xInnerRightVal + innerFilletR; var connectingLineTop = new Line(new Point3d(lineStart, oy + H, 0), new Point3d(lineEnd, oy + H, 0)); ctx.Style?.Apply(connectingLineTop, DrawingStyleManager.Role.OutlineBold); ctx.Btr.AppendEntity(connectingLineTop); ctx.Tr.AddNewlyCreatedDBObject(connectingLineTop, true); var connectingLineBottom = new Line(new Point3d(lineStart, oy, 0), new Point3d(lineEnd, oy, 0)); ctx.Style?.Apply(connectingLineBottom, DrawingStyleManager.Role.OutlineBold); ctx.Btr.AppendEntity(connectingLineBottom); ctx.Tr.AddNewlyCreatedDBObject(connectingLineBottom, true); // Adjust Inner Dim to attach to vertical wall (offset by innerFilletR) FeatureDrivenDrawer.DrawInnerDiameterDimension(ctx, xInnerLeftVal, xInnerRightVal, oy + innerFilletR, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime); // Store values for later use in dimensions/notes xInnerRight = xInnerRightVal; xInnerLeft = xInnerLeftVal; } else { // Fallback if no inner hole (should not happen for a ring but safe to keep) // FeatureDrivenDrawer.DrawForgingOuterContour(ctx, ox, oy, W, H); } // 1.1 Centerline // 改为竖直中心线,两头超出3mm var cx = ctx.Center.X; var vLine = new Line(new Point3d(cx, oy - 3, 0), new Point3d(cx, oy + H + 3, 0)); ctx.Style?.Apply(vLine, DrawingStyleManager.Role.Centerline); ctx.Btr.AppendEntity(vLine); ctx.Tr.AddNewlyCreatedDBObject(vLine, true); // 2. Outer Diameter Dimension var outerTolPlus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyOuterDiameter1TolPlus); var outerTolMinus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyOuterDiameter1TolMinus); // Adjust Y by outerFilletR FeatureDrivenDrawer.DrawOuterDiameterDimension(ctx, ox, oy + outerFilletR, W, W, outerTolPlus, outerTolMinus, outerDiaPrime); // 5. Height Dimension var displayBag = ctx.OriginalBag ?? ctx.Bag; var displayHeightVal = displayBag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1) ?? H; var displayHeightStr = displayBag.GetString(FeatureDrivenDrawer.KeyHeight1); var displayTolPlus = displayBag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1TolPlus); var displayTolMinus = displayBag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1TolMinus); var displayTolPlusStr = displayBag.GetString(FeatureDrivenDrawer.KeyHeight1TolPlus); var displayTolMinusStr = displayBag.GetString(FeatureDrivenDrawer.KeyHeight1TolMinus); var displayHeightPrime = displayBag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1Prime); var heightBaseText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(displayHeightVal, displayHeightStr), displayTolPlus, displayTolMinus, displayTolPlusStr, displayTolMinusStr); var heightDimText = heightBaseText; if (displayHeightPrime.HasValue && displayHeightPrime.Value > 0) { heightDimText = heightBaseText + $"\\X({FeatureDrivenDrawer.FormatDimNumber(displayHeightPrime.Value)})"; } // Custom Height Dimension Logic to ensure "Closed" look with fillets // Move X definition points inward by outerFilletR double dimX = ox + W - outerFilletR; FeatureDrivenDrawer.AddLinearDim( ctx, new Point3d(dimX, oy, 0), new Point3d(dimX, oy + H, 0), new Point3d(ox + W + 25, oy + H / 2, 0), 90, heightDimText); // 7. Min Wall Thickness var minWallThickness = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyMinWallThickness); if (minWallThickness.HasValue && minWallThickness.Value > 0) { if (xInnerRight.HasValue) { var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyMinWallThickness) ?? minWallThickness.Value; var dimText = $"{FeatureDrivenDrawer.FormatDimNumber(val)}min"; FeatureDrivenDrawer.AddLinearDim( ctx, new Point3d(xInnerRight.Value, oy + innerFilletR, 0), new Point3d(ox + W, oy + outerFilletR, 0), new Point3d((xInnerRight.Value + ox + W) / 2, oy + innerFilletR - 25, 0), 0, dimText); } } // 8. Part Contour (Machined Parameters present) if (outerDiaPrime.HasValue && outerDiaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0) { FeatureDrivenDrawer.DrawPartContour(ctx, ctx.Center, outerDiaPrime.Value, innerDiaPrime, heightPrime.Value); } // 9. Hardness Symbol var hardnessVal = bag.GetString(FeatureDrivenDrawer.KeyHardness); if (!string.IsNullOrWhiteSpace(hardnessVal) && hardnessVal != "空") { if (xInnerRight.HasValue) { double xStart = (xInnerRight.Value + ox + W) / 2.0; double yStart = oy; FeatureDrivenDrawer.DrawHardnessSymbol(ctx, xStart, yStart, hardnessVal); } else { FeatureDrivenDrawer.DrawHardnessSymbol(ctx, ox + W / 2.0, oy, hardnessVal); } } // 10. Marking Content var markingText = bag.GetString(FeatureDrivenDrawer.KeyMarkingContent); if (!string.IsNullOrWhiteSpace(markingText)) { if (xInnerRight.HasValue) { double xTarget = (xInnerRight.Value + ox + W) / 2.0; double yTarget = oy + H; FeatureDrivenDrawer.DrawSpecialHBLeaderToTop(ctx, xTarget, yTarget, markingText); } else { FeatureDrivenDrawer.DrawSpecialHBLeaderToTop(ctx, ox + W / 2.0, oy + H, markingText); } } } /// /// Draws a section rectangle with potentially different fillet radii for left and right sides. /// Also handles hatching. /// rLeft: Radius for Top-Left and Bottom-Left corners. /// rRight: Radius for Top-Right and Bottom-Right corners. /// private static void DrawSectionWithAsymmetricFillets(FeatureDrivenDrawer.DrawingContext ctx, double xLeft, double xRight, double yBottom, double height, double rLeft, double rRight) { var yTop = yBottom + height; var width = xRight - xLeft; // Constrain radii var maxR = Math.Min(width * 0.5, height * 0.5); var rl = Math.Min(rLeft, maxR); var rr = Math.Min(rRight, maxR); if (rl < 0) rl = 0; if (rr < 0) rr = 0; // If radii are negligible, draw rectangle if (rl <= 0.01 && rr <= 0.01) { // ... (Logic from FeatureDrivenDrawer but combined) // Use reuse logic or just implement simply. // Simple Polyline var simplePoly = new Polyline(); simplePoly.AddVertexAt(0, new Point2d(xLeft, yBottom), 0, 0, 0); simplePoly.AddVertexAt(1, new Point2d(xRight, yBottom), 0, 0, 0); simplePoly.AddVertexAt(2, new Point2d(xRight, yTop), 0, 0, 0); simplePoly.AddVertexAt(3, new Point2d(xLeft, yTop), 0, 0, 0); simplePoly.Closed = true; ctx.Style?.Apply(simplePoly, DrawingStyleManager.Role.OutlineBold); ctx.Btr.AppendEntity(simplePoly); ctx.Tr.AddNewlyCreatedDBObject(simplePoly, true); // Hatch CreateHatchForPolyline(ctx, simplePoly); return; } var bulge = Math.Tan(Math.PI / 8.0); var poly = new Polyline(); // 1. Bottom Line Start (xLeft + rl) poly.AddVertexAt(0, new Point2d(xLeft + rl, yBottom), 0, 0, 0); // 2. Bottom Line End / Bottom-Right Arc Start (xRight - rr) poly.AddVertexAt(1, new Point2d(xRight - rr, yBottom), bulge, 0, 0); // 3. Right Line Start / Bottom-Right Arc End (xRight, yBottom + rr) poly.AddVertexAt(2, new Point2d(xRight, yBottom + rr), 0, 0, 0); // 4. Right Line End / Top-Right Arc Start (xRight, yTop - rr) poly.AddVertexAt(3, new Point2d(xRight, yTop - rr), bulge, 0, 0); // 5. Top Line Start / Top-Right Arc End (xRight - rr, yTop) poly.AddVertexAt(4, new Point2d(xRight - rr, yTop), 0, 0, 0); // 6. Top Line End / Top-Left Arc Start (xLeft + rl, yTop) poly.AddVertexAt(5, new Point2d(xLeft + rl, yTop), bulge, 0, 0); // 7. Left Line Start / Top-Left Arc End (xLeft, yTop - rl) poly.AddVertexAt(6, new Point2d(xLeft, yTop - rl), 0, 0, 0); // 8. Left Line End / Bottom-Left Arc Start (xLeft, yBottom + rl) poly.AddVertexAt(7, new Point2d(xLeft, yBottom + rl), bulge, 0, 0); poly.Closed = true; ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold); ctx.Btr.AppendEntity(poly); ctx.Tr.AddNewlyCreatedDBObject(poly, true); // Hatch CreateHatchForPolyline(ctx, poly); } private static void DrawInnerRadiusLeader(FeatureDrivenDrawer.DrawingContext ctx, double cx, double cy, double r, bool isLeftSection) { try { var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyInnerRadiusMax); if (!val.HasValue || val.Value <= 0) return; double angleDeg = isLeftSection ? 45 : 135; double angleRad = angleDeg * Math.PI / 180.0; // 起点(指向圆弧:圆心延角度方向在圆弧上的点) double px = cx + r * Math.Cos(angleRad); double py = cy + r * Math.Sin(angleRad); // 终点 double ex = px + 25 * Math.Cos(angleRad); double ey = py + 25 * Math.Sin(angleRad); // 画线 var line = new Line(new Point3d(px, py, 0), new Point3d(ex, ey, 0)); ctx.Style?.Apply(line, DrawingStyleManager.Role.Dimension); line.ColorIndex = 4; // Cyan ctx.Btr.AppendEntity(line); ctx.Tr.AddNewlyCreatedDBObject(line, true); // 绘制实心剪头,调大尺寸 double arrowLength = 5.0; // 箭头长度 (原为 3.0) double arrowWidth = 1.5; // 箭头宽度 (原为 1.0) double baseX = px + arrowLength * Math.Cos(angleRad); double baseY = py + arrowLength * Math.Sin(angleRad); double perpAngle = angleRad + Math.PI / 2; double p1X = baseX + (arrowWidth / 2) * Math.Cos(perpAngle); double p1Y = baseY + (arrowWidth / 2) * Math.Sin(perpAngle); double p2X = baseX - (arrowWidth / 2) * Math.Cos(perpAngle); double p2Y = baseY - (arrowWidth / 2) * Math.Sin(perpAngle); var arrow = new Solid(new Point3d(px, py, 0), new Point3d(p1X, p1Y, 0), new Point3d(p2X, p2Y, 0)); arrow.ColorIndex = 4; ctx.Btr.AppendEntity(arrow); ctx.Tr.AddNewlyCreatedDBObject(arrow, true); // 文字(与线对齐同角度) var textStr = $"R\\U+2264{val.Value}"; var text = new DBText(); text.TextString = textStr; text.Height = 3.5; text.ColorIndex = 4; // 倾斜文字角度 double textRotation = angleRad; if (!isLeftSection) { // For the right side (135 degrees), we want the text to read left-to-right textRotation = angleRad - Math.PI; } text.Rotation = textRotation; // 对齐设置 text.HorizontalMode = TextHorizontalMode.TextCenter; text.VerticalMode = TextVerticalMode.TextBottom; // 计算文字放置点 double offsetX = 2.0 * Math.Cos(textRotation + Math.PI / 2); double offsetY = 2.0 * Math.Sin(textRotation + Math.PI / 2); var tp = new Point3d(ex + offsetX, ey + offsetY, 0); text.AlignmentPoint = tp; text.Position = tp; ctx.Style?.Apply(text, DrawingStyleManager.Role.Text); text.ColorIndex = 4; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { // ignore } } private static void CreateHatchForPolyline(FeatureDrivenDrawer.DrawingContext ctx, Polyline boundary) { try { var hatch = new Hatch(); hatch.SetDatabaseDefaults(); hatch.Normal = new Vector3d(0, 0, 1); hatch.Elevation = 0.0; ctx.Btr.AppendEntity(hatch); ctx.Tr.AddNewlyCreatedDBObject(hatch, true); hatch.SetHatchPattern(HatchPatternType.PreDefined, "ANSI31"); hatch.PatternScale = 10; hatch.PatternAngle = 0; hatch.Associative = false; ctx.Style?.Apply(hatch, DrawingStyleManager.Role.Hatch); var ids = new ObjectIdCollection(); ids.Add(boundary.ObjectId); hatch.AppendLoop(HatchLoopTypes.External, ids); hatch.EvaluateHatch(true); } catch { // ignore hatch errors } } } }