using System; using System.Collections.Generic; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using CadParamPluging.Common; namespace CadParamPluging.Cad { /// /// 车加工-轧制-环形 独立绘图器 /// 物理隔离的绘图逻辑,不依赖 FeatureDrivenDrawer 的具体实现(除了部分通用工具方法) /// public static class RingMachinedRollingDrawer { #region 参数Key常量 (复用 FeatureDrivenDrawer 的定义) public const string KeyOuterDiameter1 = "OuterDiameter1"; public const string KeyOuterDiameter1TolPlus = "OuterDiameter1TolPlus"; public const string KeyOuterDiameter1TolMinus = "OuterDiameter1TolMinus"; public const string KeyInnerDiameter2 = "InnerDiameter2"; public const string KeyInnerDiameter2TolPlus = "InnerDiameter2TolPlus"; public const string KeyInnerDiameter2TolMinus = "InnerDiameter2TolMinus"; public const string KeyHeight1 = "Height1"; public const string KeyHeight1TolPlus = "Height1TolPlus"; public const string KeyHeight1TolMinus = "Height1TolMinus"; public const string KeyMinWallThickness = "MinWallThickness"; public const string KeyUnspecifiedFilletRadiusMax = "UnspecifiedFilletRadiusMax"; public const string KeyOuterDiameter1Prime = "OuterDiameter1Prime"; public const string KeyInnerDiameter2Prime = "InnerDiameter2Prime"; public const string KeyHeight1Prime = "Height1Prime"; public const string KeyMarkingContent = "MarkingContent"; #endregion 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)); // 缩放处理 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; } var context = new FeatureDrivenDrawer.DrawingContext { Ctx = ctx, Bag = effectiveBag, OriginalBag = bag, Center = center, DeliveryStatus = "车加工", StructuralFeature = "环形", ProcessMethod = "轧制", Btr = btr, Style = new DrawingStyleManager(db, tr) }; var outerDia = effectiveBag.GetDoubleOrNull(KeyOuterDiameter1); var height = effectiveBag.GetDoubleOrNull(KeyHeight1); if (!outerDia.HasValue || outerDia.Value <= 0 || !height.HasValue || height.Value <= 0) { return; } // 调用核心绘制逻辑 // 此处传递 true 以启用 UnspecifiedFillet 逻辑 (与 FeatureDrivenDrawer.DrawRingRollingWithUnspecifiedFillet 保持一致) DrawCore(context, outerDia.Value, height.Value, true); } private static void DrawCore(FeatureDrivenDrawer.DrawingContext ctx, double outerDia, double height, bool applyUnspecifiedFillet) { var bag = ctx.Bag; // --- 几何与视觉映射计算 --- double H = height; double physicalOuterR = outerDia / 2.0; double physicalInnerR = 0; var innerDia = bag.GetDoubleOrNull(KeyInnerDiameter2); if (innerDia.HasValue && innerDia.Value > 0) { physicalInnerR = innerDia.Value / 2.0; } // 1. 确定视觉半径 double visualOuterR = physicalOuterR; double visualInnerR = physicalInnerR; // 轧制示意图几何按名义壁厚画;Tmin 标注文字仍使用考虑公差后的 MinWallThickness。 if (ctx.IsMachined) { var nominalWallThickness = (physicalOuterR - physicalInnerR); if (physicalInnerR > 0 && nominalWallThickness > 0) { visualInnerR = nominalWallThickness * 2.0; visualOuterR = nominalWallThickness * 3.0; } else { visualOuterR = H * 3.0; visualInnerR = visualOuterR * (2.0/3.0); } } // 3. 定义半径映射函数 double MapRadius(double r) { if (r <= 0) return 0; if (physicalInnerR <= 1e-6) { return r * (visualOuterR / physicalOuterR); } if (r <= physicalInnerR) { return r * (visualInnerR / physicalInnerR); } else { double wallScale = (visualOuterR - visualInnerR) / (physicalOuterR - physicalInnerR); return visualInnerR + (r - physicalInnerR) * wallScale; } } // --- 绘图坐标计算 --- double ox = ctx.Center.X - visualOuterR / 2.0; // 对称轴位置 double oy = ctx.Center.Y - H / 2.0; // 车加工态零件尺寸 double? outerDiaPrime = null; double? innerDiaPrime = null; double? heightPrime = null; if (ctx.IsMachined) { outerDiaPrime = bag.GetDoubleOrNull(KeyOuterDiameter1Prime); innerDiaPrime = bag.GetDoubleOrNull(KeyInnerDiameter2Prime); heightPrime = bag.GetDoubleOrNull(KeyHeight1Prime); } // === 特征1: 锻件外轮廓 === var unspecifiedFillet = bag.GetDoubleOrNull(KeyUnspecifiedFilletRadiusMax); bool hasUnspecifiedFillet = applyUnspecifiedFillet && unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0; if (!hasUnspecifiedFillet) { DrawForgingOuterContourHalf(ctx, ox, oy, visualOuterR, H, null); } // === 特征1.1: 对称轴 === DrawRingSymmetryAxis(ctx, ox, oy, H); // === 特征2: 外径公差标注 === var outerTolPlus = bag.GetDoubleOrNull(KeyOuterDiameter1TolPlus); var outerTolMinus = bag.GetDoubleOrNull(KeyOuterDiameter1TolMinus); DrawOuterDiameterDimensionHalf(ctx, ox, oy, visualOuterR, H, outerDia, outerTolPlus, outerTolMinus, outerDiaPrime); // === 特征3: 内孔/内径 === double? xInnerRight = null; if (innerDia.HasValue && innerDia.Value > 0 && innerDia.Value < outerDia) { xInnerRight = ox + visualInnerR; var innerTolPlus = bag.GetDoubleOrNull(KeyInnerDiameter2TolPlus); var innerTolMinus = bag.GetDoubleOrNull(KeyInnerDiameter2TolMinus); if (hasUnspecifiedFillet) { FeatureDrivenDrawer.DrawRingSectionContourWithFillet(ctx, xInnerRight.Value, ox + visualOuterR, oy, H, unspecifiedFillet.Value); DrawHoleHorizontalLinesWithLeftExtension(ctx, ox, xInnerRight.Value, oy, H, unspecifiedFillet.Value); var sectionWidth = (ox + visualOuterR) - (xInnerRight.Value); var maxR = Math.Min(sectionWidth * 0.5, H * 0.5); var r = Math.Min(unspecifiedFillet.Value, maxR); var dimExtensionOffset = 0.0; if (r > 0.01) dimExtensionOffset = r; DrawInnerDiameterDimensionHalf(ctx, ox, xInnerRight.Value, oy, H, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime, dimExtensionOffset); FeatureDrivenDrawer.DrawRingSectionHatchWithFillet(ctx, xInnerRight.Value, ox + visualOuterR, oy, H, unspecifiedFillet.Value); } else { DrawInnerHoleHalf(ctx, ox, xInnerRight.Value, oy, H); DrawInnerDiameterDimensionHalf(ctx, ox, xInnerRight.Value, oy, H, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime); FeatureDrivenDrawer.DrawRingSectionHatch(ctx, xInnerRight.Value, ox + visualOuterR, oy, H); FeatureDrivenDrawer.DrawSectionInnerBoundaryBold(ctx, xInnerRight.Value, oy, H); } } // === 特征5: 高度标注 === var heightTolPlus = bag.GetDoubleOrNull(KeyHeight1TolPlus); var heightTolMinus = bag.GetDoubleOrNull(KeyHeight1TolMinus); double heightDimIndentX = 0.0; if (hasUnspecifiedFillet) { var sWidth = (ox + visualOuterR) - (xInnerRight.Value); var maxR = Math.Min(sWidth * 0.5, H * 0.5); var r = Math.Min(unspecifiedFillet.Value, maxR); if (r > 0.01) heightDimIndentX = r; } DrawHeightDimensionHalf(ctx, ox, oy, visualOuterR, H, heightTolPlus, heightTolMinus, heightPrime, heightDimIndentX); // === 特征6: 未注圆角 === if (!applyUnspecifiedFillet && unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) { FeatureDrivenDrawer.DrawUnspecifiedFilletNote(ctx, ox, oy, H, visualOuterR, unspecifiedFillet.Value); } // === 特征7: 最小壁厚min标注 === var minWallThickness = bag.GetDoubleOrNull(KeyMinWallThickness); if (minWallThickness.HasValue && minWallThickness.Value > 0 && xInnerRight.HasValue) { var dimExtensionOffset = 0.0; if (applyUnspecifiedFillet && unspecifiedFillet.HasValue) { var sWidth = Math.Abs((ox + visualOuterR) - (xInnerRight.Value)); var maxR = Math.Min(sWidth * 0.5, H * 0.5); var rCalc = Math.Min(unspecifiedFillet.Value, maxR); if (rCalc > 0.01) dimExtensionOffset = rCalc; } FeatureDrivenDrawer.DrawMinWallThicknessNote(ctx, xInnerRight.Value, ox + visualOuterR, oy, minWallThickness.Value, dimExtensionOffset); } // === 特征8: 零件轮廓 === if (ctx.IsMachined && outerDiaPrime.HasValue && outerDiaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0) { // 1. 外径 double physicalPartOuterR = outerDiaPrime.Value / 2.0; double visualPartOuterR = MapRadius(physicalPartOuterR); var scaledOuterDiaPrime = visualPartOuterR * 2.0; // 2. 内径 double? scaledInnerDiaPrime = null; if (innerDiaPrime.HasValue && innerDiaPrime.Value > 0) { double physicalPartInnerR = innerDiaPrime.Value / 2.0; double visualPartInnerR = MapRadius(physicalPartInnerR); scaledInnerDiaPrime = visualPartInnerR * 2.0; } // 3. 高度 var scaledHeightPrime = heightPrime.Value; DrawPartContourHalf(ctx, ox, oy, H, scaledOuterDiaPrime, scaledInnerDiaPrime, scaledHeightPrime); } // === 特征10: 轧制+车加工 特殊引线标注 (HB5936-13) === // 需满足: 车加工 + 轧制(本方法即为轧制) + 有内孔 if (ctx.IsMachined && innerDia.HasValue && innerDia.Value > 0) { // 指向锻件内孔右上角 DrawSpecialInnerHoleLeader(ctx, ox, oy, H, visualInnerR); } // === 特征9: 硬度符号 (HB) === // 【已移除】按用户需求,此模板不绘制红色方框中的硬度符号 // === 特征11: 粗糙度符号 (右上角) === var roughnessVal = bag.GetString("SurfaceRoughness"); if (!string.IsNullOrWhiteSpace(roughnessVal) && roughnessVal != "空") { DrawAllRoughnessSymbol(ctx, roughnessVal); } } private static void DrawAllRoughnessSymbol(FeatureDrivenDrawer.DrawingContext ctx, string value) { try { // 获取整个模板右上方坐标 double maxX = 0; double maxY = 0; var frameExtents = TemplateDrawingService.ComputeWhiteFrameExtents(ctx?.Ctx); if (frameExtents.HasValue) { maxX = frameExtents.Value.MaxPoint.X; maxY = frameExtents.Value.MaxPoint.Y; } else { // Fallback, 以中心+200估算 maxX = ctx.Center.X + 200; maxY = ctx.Center.Y + 200; } // 定位:距离右上角内缩一定边距,调整为更靠近右上角 (5.0) double pRightX = maxX - 5.0; double pTopY = maxY - 5.0; double hTotal = 11.0; double hTriangle = 5.5; double dxTotal = hTotal * Math.Tan(30.0 * Math.PI / 180.0); double originX = pRightX - dxTotal; double originY = pTopY - hTotal; var p0 = new Point3d(originX, originY, 0); double dxTriangle = hTriangle * Math.Tan(30.0 * Math.PI / 180.0); var p1 = new Point3d(originX - dxTriangle, originY + hTriangle, 0); var p2 = new Point3d(originX + dxTriangle, originY + hTriangle, 0); var p3 = new Point3d(pRightX, pTopY, 0); var line1 = new Line(p1, p0); var line2 = new Line(p0, p3); var line3 = new Line(p1, p2); line1.ColorIndex = 7; // White line2.ColorIndex = 7; line3.ColorIndex = 7; ctx.Btr.AppendEntity(line1); ctx.Tr.AddNewlyCreatedDBObject(line1, true); ctx.Btr.AppendEntity(line2); ctx.Tr.AddNewlyCreatedDBObject(line2, true); ctx.Btr.AppendEntity(line3); ctx.Tr.AddNewlyCreatedDBObject(line3, true); // 粗糙度数值 (如1.6) var textVal = new DBText(); textVal.TextString = value; textVal.Height = 3.5; textVal.ColorIndex = 7; textVal.HorizontalMode = TextHorizontalMode.TextCenter; textVal.VerticalMode = TextVerticalMode.TextBottom; textVal.AlignmentPoint = new Point3d(originX, originY + hTriangle + 1.0, 0); textVal.Position = textVal.AlignmentPoint; ctx.Btr.AppendEntity(textVal); ctx.Tr.AddNewlyCreatedDBObject(textVal, true); // “所有”文本 var textAll = new DBText(); textAll.TextString = "所有"; textAll.Height = 3.5; textAll.ColorIndex = 7; textAll.HorizontalMode = TextHorizontalMode.TextRight; textAll.VerticalMode = TextVerticalMode.TextVerticalMid; // 向左偏移一点,中心对齐三角线高度 textAll.AlignmentPoint = new Point3d(p1.X - 2.0, originY + hTriangle, 0); textAll.Position = textAll.AlignmentPoint; ctx.Btr.AppendEntity(textAll); ctx.Tr.AddNewlyCreatedDBObject(textAll, true); } catch { } } private static void DrawSpecialInnerHoleLeader(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double height, double visualInnerR) { try { // 内孔右侧X坐标 (锻件) double xInner = ox + visualInnerR; // 目标Y坐标:锻件内孔右上角向下偏移一点 (引线不应直指角点,而是指在直线上) double yTarget = oy + height - 5.0; // 箭头点 (指向内孔竖线) var p1 = new Point3d(xInner, yTarget, 0); // 转折点 (向左上) var p2 = new Point3d(xInner - 12, yTarget + 12, 0); // 终点 (水平向左, 长度约35适配文字宽度 "HB5936-13") var p3 = new Point3d(p2.X - 35, p2.Y, 0); // 使用 Leader 实体绘制带箭头的引线 var leader = new Leader(); leader.SetDatabaseDefaults(); leader.AppendVertex(p1); leader.AppendVertex(p2); leader.AppendVertex(p3); leader.HasArrowHead = false; leader.ColorIndex = 7; // 白色 leader.Layer = "0"; ctx.Btr.AppendEntity(leader); ctx.Tr.AddNewlyCreatedDBObject(leader, true); FeatureDrivenDrawer.DrawLeaderArrowHead(ctx, p1, p2, 7); // 绘制文字 var text = new DBText(); text.TextString = "HB5936-13"; text.Height = 3.5; text.ColorIndex = 7; // 白色 text.Layer = "0"; // 文字位置:左对齐,基点为 p3 (线段最左端) // 位于线段上方 (VerticalMode = TextBottom) text.HorizontalMode = TextHorizontalMode.TextLeft; text.VerticalMode = TextVerticalMode.TextBottom; text.AlignmentPoint = new Point3d(p3.X, p3.Y + 1.0, 0); text.Position = text.AlignmentPoint; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { // ignore } } #region 私有辅助绘图方法 private static void DrawForgingOuterContourHalf(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double radius, double height, double? filletRadius) { var rawR = filletRadius.GetValueOrDefault(); if (rawR > 0) { var maxR = Math.Min(radius * 0.5, height * 0.5); var r = Math.Min(rawR, maxR); if (r > 0.01) { var bulge = Math.Tan(Math.PI / 8.0); var polyFillet = new Polyline(); polyFillet.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0); polyFillet.AddVertexAt(1, new Point2d(ox + radius - r, oy), bulge, 0, 0); polyFillet.AddVertexAt(2, new Point2d(ox + radius, oy + r), 0, 0, 0); polyFillet.AddVertexAt(3, new Point2d(ox + radius, oy + height - r), bulge, 0, 0); polyFillet.AddVertexAt(4, new Point2d(ox + radius - r, oy + height), 0, 0, 0); polyFillet.AddVertexAt(5, new Point2d(ox, oy + height), 0, 0, 0); polyFillet.Closed = false; ctx.Style?.Apply(polyFillet, DrawingStyleManager.Role.OutlineBold); ctx.Btr.AppendEntity(polyFillet); ctx.Tr.AddNewlyCreatedDBObject(polyFillet, true); return; } } DrawOpenHalfOutlineWithLeftExtension(ctx, ox, oy, radius, height); } private static void DrawRingSymmetryAxis(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double height) { const double lineSpacing = 3.0; FeatureDrivenDrawer.DrawSBreakLinePair(ctx, ox, oy, oy + height, -lineSpacing); } private static void DrawHoleHorizontalLinesWithLeftExtension(FeatureDrivenDrawer.DrawingContext ctx, double xAxis, double xSectionLeft, double yBottom, double height, double filletR) { const double leftExtension = 10.0; const double lineSpacing = 3.0; var yTop = yBottom + height; var maxR = Math.Min(100.0, height * 0.5); var r = Math.Min(filletR, maxR); var xTarget = r > 0.01 ? xSectionLeft + r : xSectionLeft; var xLeft = xAxis - leftExtension; DrawOutlineLine(ctx, xLeft, yBottom, xAxis - lineSpacing, yBottom); DrawOutlineLine(ctx, xAxis, yBottom, xTarget, yBottom); DrawOutlineLine(ctx, xLeft, yTop, xAxis - lineSpacing, yTop); DrawOutlineLine(ctx, xAxis, yTop, xTarget, yTop); DrawLeftCutCenterLine(ctx, xLeft, yBottom, height); } private static void DrawOpenHalfOutlineWithLeftExtension(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double radius, double height) { const double leftExtension = 10.0; const double lineSpacing = 3.0; var xLeft = ox - leftExtension; var xBreakLeft = ox - lineSpacing; var xRight = ox + radius; var yTop = oy + height; DrawOutlineLine(ctx, xLeft, oy, xBreakLeft, oy); DrawOutlineLine(ctx, ox, oy, xRight, oy); DrawOutlineLine(ctx, xRight, oy, xRight, yTop); DrawOutlineLine(ctx, xRight, yTop, ox, yTop); DrawOutlineLine(ctx, xBreakLeft, yTop, xLeft, yTop); DrawLeftCutCenterLine(ctx, xLeft, oy, height); } private static void DrawOutlineLine(FeatureDrivenDrawer.DrawingContext ctx, double x1, double y1, double x2, double y2) { var line = new Line(new Point3d(x1, y1, 0), new Point3d(x2, y2, 0)); ctx.Style?.Apply(line, DrawingStyleManager.Role.OutlineBold); ctx.Btr.AppendEntity(line); ctx.Tr.AddNewlyCreatedDBObject(line, true); } private static void DrawLeftCutCenterLine(FeatureDrivenDrawer.DrawingContext ctx, double x, double yBottom, double height) { var yTop = yBottom + height; var centerLine = new Line(new Point3d(x, yBottom - 5.0, 0), new Point3d(x, yTop + 5.0, 0)); ctx.Style?.Apply(centerLine, DrawingStyleManager.Role.Centerline); centerLine.LinetypeScale = 8.0; ctx.Btr.AppendEntity(centerLine); ctx.Tr.AddNewlyCreatedDBObject(centerLine, true); } private static void DrawOuterDiameterDimensionHalf(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double radius, double height, double diameter, double? tolPlus, double? tolMinus, double? diameterPrime) { var diameterVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1) ?? diameter; var diameterStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1); var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1TolPlus) ?? tolPlus; var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1TolMinus) ?? tolMinus; var tolPlusStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1TolPlus); var tolMinusStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1TolMinus); var diameterPrimeVal = diameterPrime; if (ctx.OriginalBag != null) { var p = ctx.OriginalBag.GetDoubleOrNull(KeyOuterDiameter1Prime); if (p.HasValue) diameterPrimeVal = p.Value; } var baseText = FeatureDrivenDrawer.BuildDimensionText($"%%c{FeatureDrivenDrawer.FormatDimNumber(diameterVal, diameterStr)}", tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr); var dimText = diameterPrimeVal.HasValue && diameterPrimeVal.Value > 0 ? baseText + $"\\X(%%c{FeatureDrivenDrawer.FormatDimNumber(diameterPrimeVal.Value)})" : baseText; const double leftExtension = 10.0; var xLeft = ox - leftExtension; AddLinearDim( ctx, new Point3d(xLeft, oy, 0), new Point3d(ox + radius, oy, 0), new Point3d((xLeft + ox + radius) / 2.0, oy - 25, 0), 0, dimText, ApplyHalfSideDimStyle); } private static void DrawInnerHoleHalf(FeatureDrivenDrawer.DrawingContext ctx, double oxAxis, double xInnerRight, double yBottom, double height) { var yTop = yBottom + height; var lineRight = new Line(new Point3d(xInnerRight, yBottom, 0), new Point3d(xInnerRight, yTop, 0)); ctx.Style?.Apply(lineRight, DrawingStyleManager.Role.Hidden); ctx.Btr.AppendEntity(lineRight); ctx.Tr.AddNewlyCreatedDBObject(lineRight, true); } private static void DrawInnerDiameterDimensionHalf(FeatureDrivenDrawer.DrawingContext ctx, double oxAxis, double xInnerRight, double yBottom, double height, double diameter, double? tolPlus, double? tolMinus, double? diameterPrime, double offsetY = 0) { var diameterVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2) ?? diameter; var diameterStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2); var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2TolPlus) ?? tolPlus; var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2TolMinus) ?? tolMinus; var tolPlusStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2TolPlus); var tolMinusStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2TolMinus); var diameterPrimeVal = diameterPrime; if (ctx.OriginalBag != null) { var p = ctx.OriginalBag.GetDoubleOrNull(KeyInnerDiameter2Prime); if (p.HasValue) diameterPrimeVal = p.Value; } var baseText = FeatureDrivenDrawer.BuildDimensionText($"%%c{FeatureDrivenDrawer.FormatDimNumber(diameterVal, diameterStr)}", tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr); var dimText = diameterPrimeVal.HasValue && diameterPrimeVal.Value > 0 ? baseText + $"\\X(%%c{FeatureDrivenDrawer.FormatDimNumber(diameterPrimeVal.Value)})" : baseText; double innerRadius = xInnerRight - oxAxis; var dimLineY = yBottom - 10; const double leftExtension = 10.0; var xLeft = oxAxis - leftExtension; AddLinearDim( ctx, new Point3d(xLeft, yBottom, 0), new Point3d(xInnerRight, yBottom + offsetY, 0), new Point3d((xLeft + xInnerRight) / 2.0, dimLineY, 0), 0, dimText, ApplyHalfSideDimStyle); } private static void DrawHeightDimensionHalf(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double radius, double height, double? tolPlus, double? tolMinus, double? heightPrime, double indentX = 0) { var heightVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1) ?? height; var heightStr = ctx.OriginalBag?.GetString(KeyHeight1); var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1TolPlus) ?? tolPlus; var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1TolMinus) ?? tolMinus; var tolPlusStr = ctx.OriginalBag?.GetString(KeyHeight1TolPlus); var tolMinusStr = ctx.OriginalBag?.GetString(KeyHeight1TolMinus); var heightPrimeVal = heightPrime; if (ctx.OriginalBag != null) { var p = ctx.OriginalBag.GetDoubleOrNull(KeyHeight1Prime); if (p.HasValue) heightPrimeVal = p.Value; } var baseText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(heightVal, heightStr), tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr); var dimText = heightPrimeVal.HasValue && heightPrimeVal.Value > 0 ? baseText + $"\\X({FeatureDrivenDrawer.FormatDimNumber(heightPrimeVal.Value)})" : baseText; var xLine = ox + radius - indentX; FeatureDrivenDrawer.AddLinearDim( ctx, new Point3d(xLine, oy, 0), new Point3d(xLine, oy + height, 0), new Point3d(ox + radius + 20, oy + height / 2, 0), 90, dimText); } private static void DrawPartContourHalf(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double forgingHeight, double outerDiaPrime, double? innerDiaPrime, double heightPrime) { var Rp = outerDiaPrime / 2.0; var h = heightPrime; var offsetY = (forgingHeight - h) / 2.0; var y0 = oy + offsetY; double minX = ox; if (innerDiaPrime.HasValue && innerDiaPrime.Value > 0) { minX = ox + innerDiaPrime.Value / 2.0; } double maxX = ox + Rp; var polyPart = new Polyline(); polyPart.AddVertexAt(0, new Point2d(minX, y0), 0, 0, 0); polyPart.AddVertexAt(1, new Point2d(maxX, y0), 0, 0, 0); polyPart.AddVertexAt(2, new Point2d(maxX, y0 + h), 0, 0, 0); polyPart.AddVertexAt(3, new Point2d(minX, y0 + h), 0, 0, 0); polyPart.Closed = true; ctx.Style?.Apply(polyPart, DrawingStyleManager.Role.PartContour); ctx.Btr.AppendEntity(polyPart); ctx.Tr.AddNewlyCreatedDBObject(polyPart, true); } #endregion #region 本地标注样式辅助方法 (从 FeatureDrivenDrawer 复制以保持隔离) private static void ApplyHalfSideDimStyle(Dimension dim, FeatureDrivenDrawer.DrawingContext ctx) { TrySetDimProp(dim, "Dimse1", true); TrySetDimProp(dim, "Dimse2", false); try { TrySetDimProp(dim, "Dimsah", true); EnsureNoneBlock(ctx.Db, ctx.Tr); var bt = (BlockTable)ctx.Tr.GetObject(ctx.Db.BlockTableId, OpenMode.ForRead); if (bt.Has("_NONE")) { dim.Dimblk1 = bt["_NONE"]; } } catch { } } private static void EnsureNoneBlock(Database db, Transaction tr) { try { var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); if (!bt.Has("_NONE")) { using (var btr = new BlockTableRecord()) { btr.Name = "_NONE"; btr.Origin = Point3d.Origin; bt.UpgradeOpen(); bt.Add(btr); tr.AddNewlyCreatedDBObject(btr, true); } } } catch { } } private static void AddLinearDim(FeatureDrivenDrawer.DrawingContext ctx, Point3d pt1, Point3d pt2, Point3d dimLinePt, double rotationDeg, string textOverride, Action customizer = null) { try { var prevDb = HostApplicationServices.WorkingDatabase; HostApplicationServices.WorkingDatabase = ctx.Db; try { double rotRad = rotationDeg * Math.PI / 180.0; var dim = new RotatedDimension(rotRad, pt1, pt2, dimLinePt, textOverride, ctx.Db.Dimstyle); try { dim.SetDatabaseDefaults(); } catch { } dim.ColorIndex = 3; if (!string.IsNullOrEmpty(textOverride)) { dim.DimensionText = textOverride; } try { dim.Normal = Vector3d.ZAxis; } catch { } TryApplyDimSizeOverrides(dim); TryApplyDimLayoutOverrides(dim); customizer?.Invoke(dim, ctx); ctx.Style?.Apply(dim, DrawingStyleManager.Role.Dimension); dim.ColorIndex = 3; ctx.Btr.AppendEntity(dim); ctx.Tr.AddNewlyCreatedDBObject(dim, true); try { dim.RecomputeDimensionBlock(true); } catch { } } finally { HostApplicationServices.WorkingDatabase = prevDb; } } catch { } } private static void TryApplyDimSizeOverrides(Dimension dim) { if (dim == null) return; TrySetDimProp(dim, "Dimtxt", 3.5); TrySetDimProp(dim, "Dimasz", FeatureDrivenDrawer.DimensionArrowSize); TrySetDimProp(dim, "Dimgap", 1.0); TrySetDimProp(dim, "Dimexe", 1.0); TrySetDimProp(dim, "Dimexo", 0.0); TrySetDimProp(dim, "Dimtofl", true); TrySetDimProp(dim, "Dimatfit", 3); TrySetDimProp(dim, "Dimtad", 1); TrySetDimProp(dim, "Dimclrd", 3); TrySetDimProp(dim, "Dimclre", 3); TrySetDimProp(dim, "Dimclrt", 3); } private static void TryApplyDimLayoutOverrides(Dimension dim) { if (dim == null) return; TrySetDimProp(dim, "Dimtih", false); TrySetDimProp(dim, "Dimtoh", false); TrySetDimProp(dim, "Dimse1", false); TrySetDimProp(dim, "Dimse2", false); } private static void TrySetDimProp(object obj, string propName, double value) { if (obj == null) return; try { var prop = obj.GetType().GetProperty(propName); if (prop != null && prop.CanWrite && prop.PropertyType == typeof(double)) prop.SetValue(obj, value, null); } catch { } } private static void TrySetDimProp(object obj, string propName, bool value) { if (obj == null) return; try { var prop = obj.GetType().GetProperty(propName); if (prop != null && prop.CanWrite && prop.PropertyType == typeof(bool)) prop.SetValue(obj, value, null); } catch { } } private static void TrySetDimProp(object obj, string propName, int value) { if (obj == null) return; try { var prop = obj.GetType().GetProperty(propName); if (prop != null && prop.CanWrite && prop.PropertyType == typeof(int)) prop.SetValue(obj, value, null); } catch { } } private static ParamBag ScaleParamBag(ParamBag original, double scaleFactor) { if (original == null || Math.Abs(scaleFactor - 1.0) < 0.000001) return original; var newBag = new ParamBag(); foreach(var k in original.GetKeys()) { var v = original.GetString(k); if (k.Contains("Diameter") || k.Contains("Length") || k.Contains("Radius") || k.Contains("Prime") || k.Contains("Height") || k.Contains("Thickness") || k.Contains("Size")) { if (double.TryParse(v, out var d)) { newBag.Set(k, (d * scaleFactor).ToString("0.###")); } else { newBag.Set(k, v); } } else { newBag.Set(k, v); } } return newBag; } #endregion } }