using System; using System.Collections.Generic; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using CadParamPluging.Common; namespace CadParamPluging.Cad { /// /// 特征驱动绘图引擎 - 根据参数存在性动态绘制图形 /// public static class FeatureDrivenDrawer { #region 参数Key常量 // 环形参数 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 KeyInnerRadiusMax = "InnerRadiusMax"; // 内径半径R≤(中心冲孔) // 环形零件尺寸(车加工态) public const string KeyOuterDiameter1Prime = "OuterDiameter1Prime"; public const string KeyInnerDiameter2Prime = "InnerDiameter2Prime"; public const string KeyHeight1Prime = "Height1Prime"; // 饼盘参数 public const string KeyDiskDiameter = "DiskDiameter"; public const string KeyDiskDiameterTolPlus = "DiskDiameterTolPlus"; public const string KeyDiskDiameterTolMinus = "DiskDiameterTolMinus"; public const string KeyDiskHeight = "DiskHeight"; public const string KeyDiskHeightTolPlus = "DiskHeightTolPlus"; public const string KeyDiskHeightTolMinus = "DiskHeightTolMinus"; public const string KeyDiskFilletRadiusMax = "DiskFilletRadiusMax"; // 饼盘未注圆角 public const string KeyDiskDiameterPrime = "DiskDiameterPrime"; // 饼盘零件直径 public const string KeyDiskHeightPrime = "DiskHeightPrime"; // 饼盘零件高度 // 轴杆参数(圆轴) public const string KeyDiameter = "Diameter"; public const string KeyDiameterTolPlus = "DiameterTolPlus"; public const string KeyDiameterTolMinus = "DiameterTolMinus"; public const string KeyLength = "Length"; public const string KeyLengthTolPlus = "LengthTolPlus"; public const string KeyLengthTolMinus = "LengthTolMinus"; public const string KeyShaftFilletRadiusMax = "ShaftFilletRadiusMax"; // 轴杆未注圆角 public const string KeyDiameterPrime = "DiameterPrime"; // 轴杆零件直径 public const string KeyLengthPrime = "LengthPrime"; // 轴杆零件长度 // 方体参数 public const string KeyBoxSize1 = "BoxSize1"; public const string KeyBoxSize1TolPlus = "BoxSize1TolPlus"; public const string KeyBoxSize1TolMinus = "BoxSize1TolMinus"; public const string KeyBoxSize2 = "BoxSize2"; public const string KeyBoxSize2TolPlus = "BoxSize2TolPlus"; public const string KeyBoxSize2TolMinus = "BoxSize2TolMinus"; public const string KeyBoxSize3 = "BoxSize3"; public const string KeyBoxSize3TolPlus = "BoxSize3TolPlus"; public const string KeyBoxSize3TolMinus = "BoxSize3TolMinus"; public const string KeyBoxFilletRadiusMax = "BoxFilletRadiusMax"; // 方体未注圆角 public const string KeyBoxRoundHeadFilletRadiusMax = "BoxRoundHeadFilletRadiusMax"; // 方体圆头处圆角 public const string KeyBoxSize1Prime = "BoxSize1Prime"; // 方体零件尺寸1 public const string KeyBoxSize2Prime = "BoxSize2Prime"; // 方体零件尺寸2 public const string KeyBoxSize3Prime = "BoxSize3Prime"; // 方体零件尺寸3 #endregion #region 绘图上下文 public class DrawingContext { public CadContext Ctx { get; set; } public ParamBag Bag { get; set; } public Point3d Center { get; set; } public string DeliveryStatus { get; set; } public string StructuralFeature { get; set; } public string SpecialCondition { get; set; } public Database Db => Ctx?.Database; public Transaction Tr => Ctx?.Transaction; public BlockTableRecord Btr { get; set; } public bool IsMachined => !string.IsNullOrWhiteSpace(DeliveryStatus) && DeliveryStatus.IndexOf("车加工", StringComparison.OrdinalIgnoreCase) >= 0; public bool IsCenterPunched => !string.IsNullOrWhiteSpace(SpecialCondition) && SpecialCondition.IndexOf("中心冲孔", StringComparison.OrdinalIgnoreCase) >= 0; public bool HasRoundHead => !string.IsNullOrWhiteSpace(SpecialCondition) && SpecialCondition.IndexOf("有圆头", StringComparison.OrdinalIgnoreCase) >= 0; } #endregion #region 预期图形尺寸计算 /// /// 预期图形尺寸 /// public class ExpectedDrawingSize { public double Width { get; set; } public double Height { get; set; } public bool IsValid => Width > 0 && Height > 0; } /// /// 根据参数计算预期绘制图形的尺寸(不包含标注,仅计算图形主体) /// public static ExpectedDrawingSize CalculateExpectedSize(ParamBag bag, string structuralFeature) { if (bag == null) { return new ExpectedDrawingSize(); } if (IsRing(structuralFeature)) { return CalculateRingSize(bag); } if (IsDisk(structuralFeature)) { return CalculateDiskSize(bag); } if (IsShaft(structuralFeature)) { return CalculateShaftSize(bag); } if (IsBlock(structuralFeature)) { return CalculateBlockSize(bag); } return new ExpectedDrawingSize(); } private static ExpectedDrawingSize CalculateRingSize(ParamBag bag) { var outerDia = bag.GetDoubleOrNull(KeyOuterDiameter1) ?? 0; var height = bag.GetDoubleOrNull(KeyHeight1) ?? 0; // 环形图形:宽度=高度参数(X方向),高度=外径(Y方向) // 加上标注的额外空间(约40像素每侧) var extraMargin = 40; return new ExpectedDrawingSize { Width = height + extraMargin * 2, Height = outerDia + extraMargin * 2 }; } private static ExpectedDrawingSize CalculateDiskSize(ParamBag bag) { var diameter = bag.GetDoubleOrNull(KeyDiskDiameter) ?? 0; var height = bag.GetDoubleOrNull(KeyDiskHeight) ?? 0; var extraMargin = 40; return new ExpectedDrawingSize { Width = diameter + extraMargin * 2, Height = height + extraMargin * 2 }; } private static ExpectedDrawingSize CalculateShaftSize(ParamBag bag) { var diameter = bag.GetDoubleOrNull(KeyDiameter) ?? 0; var length = bag.GetDoubleOrNull(KeyLength) ?? 0; var extraMargin = 40; return new ExpectedDrawingSize { Width = length + extraMargin * 2, Height = diameter + extraMargin * 2 }; } private static ExpectedDrawingSize CalculateBlockSize(ParamBag bag) { var size1 = bag.GetDoubleOrNull(KeyBoxSize1) ?? 0; var size2 = bag.GetDoubleOrNull(KeyBoxSize2) ?? size1; var extraMargin = 40; return new ExpectedDrawingSize { Width = size1 + extraMargin * 2, Height = size2 + extraMargin * 2 }; } #endregion #region 主入口 /// /// 绘制图形(带缩放支持) /// /// CAD上下文 /// 参数包 /// 交付状态 /// 结构特征 /// 特殊条件 /// 绘图中心点 /// 缩放比例(1.0表示不缩放) public static void Draw(CadContext ctx, ParamBag bag, string deliveryStatus, string structuralFeature, string specialCondition = null, Point3d? center = null, 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 btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); var context = new DrawingContext { Ctx = ctx, Bag = effectiveBag, Center = center ?? Point3d.Origin, DeliveryStatus = deliveryStatus, StructuralFeature = structuralFeature, SpecialCondition = specialCondition, Btr = btr }; // 根据结构特征分发到对应绘制器 if (IsRing(structuralFeature)) { DrawRingFeatures(context); } else if (IsDisk(structuralFeature)) { DrawDiskFeatures(context); } else if (IsShaft(structuralFeature)) { DrawShaftFeatures(context); } else if (IsBlock(structuralFeature)) { DrawBlockFeatures(context); } } #endregion #region 结构特征判断 private static bool IsRing(string feature) { return !string.IsNullOrWhiteSpace(feature) && feature.IndexOf("环形", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool IsDisk(string feature) { return !string.IsNullOrWhiteSpace(feature) && (feature.IndexOf("饼盘", StringComparison.OrdinalIgnoreCase) >= 0 || feature.IndexOf("饼", StringComparison.OrdinalIgnoreCase) >= 0 || feature.IndexOf("盘", StringComparison.OrdinalIgnoreCase) >= 0); } private static bool IsShaft(string feature) { return !string.IsNullOrWhiteSpace(feature) && (feature.IndexOf("轴杆", StringComparison.OrdinalIgnoreCase) >= 0 || feature.IndexOf("轴", StringComparison.OrdinalIgnoreCase) >= 0 || feature.IndexOf("杆", StringComparison.OrdinalIgnoreCase) >= 0); } private static bool IsBlock(string feature) { return !string.IsNullOrWhiteSpace(feature) && feature.IndexOf("方体", StringComparison.OrdinalIgnoreCase) >= 0; } #endregion #region 环形绘制 - 特征驱动 private static void DrawRingFeatures(DrawingContext ctx) { var bag = ctx.Bag; // 必需参数检测 var outerDia = bag.GetDoubleOrNull(KeyOuterDiameter1); var height = bag.GetDoubleOrNull(KeyHeight1); if (!outerDia.HasValue || outerDia.Value <= 0) { return; // 缺少外径,无法绘制 } if (!height.HasValue || height.Value <= 0) { return; // 缺少高度,无法绘制 } // 计算图形偏移,使其居中 double ox = ctx.Center.X - height.Value / 2.0; double oy = ctx.Center.Y; double R = outerDia.Value / 2.0; // 加载虚线线型 TryLoadLinetype(ctx.Db, ctx.Tr, "DASHED"); // === 特征1: 锻件外轮廓(必绘) === DrawForgingOuterContour(ctx, ox, oy, R, height.Value); // === 特征2: 外径公差标注(如果有公差参数) === var outerTolPlus = bag.GetDoubleOrNull(KeyOuterDiameter1TolPlus); var outerTolMinus = bag.GetDoubleOrNull(KeyOuterDiameter1TolMinus); DrawOuterDiameterDimension(ctx, ox, oy, R, outerDia.Value, outerTolPlus, outerTolMinus); // === 特征3: 内孔(如果有内径参数) === var innerDia = bag.GetDoubleOrNull(KeyInnerDiameter2); if (innerDia.HasValue && innerDia.Value > 0) { double r = innerDia.Value / 2.0; var innerTolPlus = bag.GetDoubleOrNull(KeyInnerDiameter2TolPlus); var innerTolMinus = bag.GetDoubleOrNull(KeyInnerDiameter2TolMinus); DrawInnerHole(ctx, ox, oy, r, height.Value); DrawInnerDiameterDimension(ctx, ox, oy, r, height.Value, innerDia.Value, innerTolPlus, innerTolMinus); // === 特征4: 内径圆角(如果有内径半径R参数,且是中心冲孔) === var innerRadiusMax = bag.GetDoubleOrNull(KeyInnerRadiusMax); if (innerRadiusMax.HasValue && innerRadiusMax.Value > 0 && ctx.IsCenterPunched) { DrawInnerFillets(ctx, ox, oy, r, height.Value, innerRadiusMax.Value); } } // === 特征5: 高度/长度标注 === var heightTolPlus = bag.GetDoubleOrNull(KeyHeight1TolPlus); var heightTolMinus = bag.GetDoubleOrNull(KeyHeight1TolMinus); DrawHeightDimension(ctx, ox, oy, R, height.Value, heightTolPlus, heightTolMinus); // === 特征6: 未注圆角(如果有该参数) === var unspecifiedFillet = bag.GetDoubleOrNull(KeyUnspecifiedFilletRadiusMax); if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) { DrawUnspecifiedFilletNote(ctx, ox, oy, R, height.Value, unspecifiedFillet.Value); } // === 特征7: 最小壁厚T标注(如果有该参数) === var minWallThickness = bag.GetDoubleOrNull(KeyMinWallThickness); if (minWallThickness.HasValue && minWallThickness.Value > 0 && innerDia.HasValue) { DrawMinWallThicknessNote(ctx, ox, oy, R, innerDia.Value / 2.0, minWallThickness.Value); } // === 特征8: 零件轮廓(车加工态) === if (ctx.IsMachined) { var outerDiaPrime = bag.GetDoubleOrNull(KeyOuterDiameter1Prime); var innerDiaPrime = bag.GetDoubleOrNull(KeyInnerDiameter2Prime); var heightPrime = bag.GetDoubleOrNull(KeyHeight1Prime); if (outerDiaPrime.HasValue && outerDiaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0) { DrawPartContour(ctx, ox, oy, height.Value, outerDiaPrime.Value, innerDiaPrime, heightPrime.Value); } } } private static void DrawForgingOuterContour(DrawingContext ctx, double ox, double oy, double R, double height) { var poly = new Polyline(); poly.AddVertexAt(0, new Point2d(ox, oy - R), 0, 0, 0); poly.AddVertexAt(1, new Point2d(ox + height, oy - R), 0, 0, 0); poly.AddVertexAt(2, new Point2d(ox + height, oy + R), 0, 0, 0); poly.AddVertexAt(3, new Point2d(ox, oy + R), 0, 0, 0); poly.Closed = true; poly.ColorIndex = 7; ctx.Btr.AppendEntity(poly); ctx.Tr.AddNewlyCreatedDBObject(poly, true); } private static void DrawInnerHole(DrawingContext ctx, double ox, double oy, double r, double height) { var lineTop = new Line(new Point3d(ox, oy + r, 0), new Point3d(ox + height, oy + r, 0)); lineTop.ColorIndex = 2; lineTop.Linetype = "DASHED"; ctx.Btr.AppendEntity(lineTop); ctx.Tr.AddNewlyCreatedDBObject(lineTop, true); var lineBot = new Line(new Point3d(ox, oy - r, 0), new Point3d(ox + height, oy - r, 0)); lineBot.ColorIndex = 2; lineBot.Linetype = "DASHED"; ctx.Btr.AppendEntity(lineBot); ctx.Tr.AddNewlyCreatedDBObject(lineBot, true); } private static void DrawInnerFillets(DrawingContext ctx, double ox, double oy, double r, double height, double filletR) { // 在内孔四角绘制圆角示意 // 左上角 DrawFilletArc(ctx, ox + filletR, oy + r - filletR, filletR, Math.PI / 2, Math.PI); // 左下角 DrawFilletArc(ctx, ox + filletR, oy - r + filletR, filletR, Math.PI, Math.PI * 1.5); // 右上角 DrawFilletArc(ctx, ox + height - filletR, oy + r - filletR, filletR, 0, Math.PI / 2); // 右下角 DrawFilletArc(ctx, ox + height - filletR, oy - r + filletR, filletR, Math.PI * 1.5, Math.PI * 2); } private static void DrawFilletArc(DrawingContext ctx, double cx, double cy, double r, double startAngle, double endAngle) { try { var arc = new Arc(new Point3d(cx, cy, 0), r, startAngle, endAngle); arc.ColorIndex = 7; ctx.Btr.AppendEntity(arc); ctx.Tr.AddNewlyCreatedDBObject(arc, true); } catch { // 忽略圆弧创建错误 } } private static void DrawOuterDiameterDimension(DrawingContext ctx, double ox, double oy, double R, double diameter, double? tolPlus, double? tolMinus) { var dimText = BuildDimensionText($"%%c{diameter}", tolPlus, tolMinus); AddLinearDim(ctx, new Point3d(ox, oy + R, 0), new Point3d(ox, oy - R, 0), new Point3d(ox - 20, oy, 0), 90, dimText); } private static void DrawInnerDiameterDimension(DrawingContext ctx, double ox, double oy, double r, double height, double diameter, double? tolPlus, double? tolMinus) { var dimText = BuildDimensionText($"%%c{diameter}", tolPlus, tolMinus); AddLinearDim(ctx, new Point3d(ox, oy + r, 0), new Point3d(ox, oy - r, 0), new Point3d(ox + height + 20, oy, 0), 90, dimText); } private static void DrawHeightDimension(DrawingContext ctx, double ox, double oy, double R, double height, double? tolPlus, double? tolMinus) { var baseText = $"{height}min"; var dimText = BuildDimensionText(baseText, tolPlus, tolMinus); AddLinearDim(ctx, new Point3d(ox, oy - R, 0), new Point3d(ox + height, oy - R, 0), new Point3d(ox + height / 2, oy - R - 20, 0), 0, dimText); } private static void DrawUnspecifiedFilletNote(DrawingContext ctx, double ox, double oy, double R, double height, double filletR) { // 在图纸右上角添加文字说明 try { var text = new DBText(); text.TextString = $"未注圆角半径R≤{filletR}"; text.Position = new Point3d(ox + height + 10, oy + R + 15, 0); text.Height = 5; text.ColorIndex = 7; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { // 忽略 } } private static void DrawMinWallThicknessNote(DrawingContext ctx, double ox, double oy, double R, double r, double thickness) { // 壁厚标注线 - 在截面中间位置 try { // 在内外径之间画一条标注线 var midX = ox; var midY = oy + (R + r) / 2; var leader = new Line(new Point3d(midX, oy + r, 0), new Point3d(midX, oy + R, 0)); leader.ColorIndex = 4; ctx.Btr.AppendEntity(leader); ctx.Tr.AddNewlyCreatedDBObject(leader, true); var text = new DBText(); text.TextString = $"T≥{thickness}"; text.Position = new Point3d(midX - 20, midY, 0); text.Height = 4; text.ColorIndex = 4; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { // 忽略 } } private static void DrawPartContour(DrawingContext ctx, double ox, double oy, double forgingHeight, double outerDiaPrime, double? innerDiaPrime, double heightPrime) { double offsetX = (forgingHeight - heightPrime) / 2.0; double Rp = outerDiaPrime / 2.0; // 零件外轮廓 var polyPart = new Polyline(); polyPart.AddVertexAt(0, new Point2d(ox + offsetX, oy - Rp), 0, 0, 0); polyPart.AddVertexAt(1, new Point2d(ox + offsetX + heightPrime, oy - Rp), 0, 0, 0); polyPart.AddVertexAt(2, new Point2d(ox + offsetX + heightPrime, oy + Rp), 0, 0, 0); polyPart.AddVertexAt(3, new Point2d(ox + offsetX, oy + Rp), 0, 0, 0); polyPart.Closed = true; polyPart.ColorIndex = 7; ctx.Btr.AppendEntity(polyPart); ctx.Tr.AddNewlyCreatedDBObject(polyPart, true); // 填充 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 = 0.8; hatch.PatternAngle = 0; hatch.Associative = false; hatch.ColorIndex = 7; var ids = new ObjectIdCollection(); ids.Add(polyPart.ObjectId); hatch.AppendLoop(HatchLoopTypes.External, ids); hatch.EvaluateHatch(true); } catch { // 忽略 } // 零件外径标注 AddLinearDim(ctx, new Point3d(ox + offsetX, oy + Rp, 0), new Point3d(ox + offsetX, oy - Rp, 0), new Point3d(ox + offsetX - 10, oy, 0), 90, $"%%c{outerDiaPrime}"); // 零件高度标注 AddLinearDim(ctx, new Point3d(ox + offsetX, oy - Rp, 0), new Point3d(ox + offsetX + heightPrime, oy - Rp, 0), new Point3d(ox + offsetX + heightPrime / 2, oy - Rp - 10, 0), 0, $"{heightPrime}"); } #endregion #region 饼盘绘制 - 特征驱动 private static void DrawDiskFeatures(DrawingContext ctx) { var bag = ctx.Bag; var diameter = bag.GetDoubleOrNull(KeyDiskDiameter); var height = bag.GetDoubleOrNull(KeyDiskHeight); if (!diameter.HasValue || diameter.Value <= 0) return; if (!height.HasValue || height.Value <= 0) return; double ox = ctx.Center.X - diameter.Value / 2.0; double oy = ctx.Center.Y - height.Value / 2.0; double R = diameter.Value / 2.0; double H = height.Value; // 绘制饼盘轮廓(俯视图为圆,侧视图为矩形) // 这里绘制侧视图 var poly = new Polyline(); poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0); poly.AddVertexAt(1, new Point2d(ox + diameter.Value, oy), 0, 0, 0); poly.AddVertexAt(2, new Point2d(ox + diameter.Value, oy + H), 0, 0, 0); poly.AddVertexAt(3, new Point2d(ox, oy + H), 0, 0, 0); poly.Closed = true; poly.ColorIndex = 7; ctx.Btr.AppendEntity(poly); ctx.Tr.AddNewlyCreatedDBObject(poly, true); // 直径标注 var diaTolPlus = bag.GetDoubleOrNull(KeyDiskDiameterTolPlus); var diaTolMinus = bag.GetDoubleOrNull(KeyDiskDiameterTolMinus); var diaDimText = BuildDimensionText($"%%c{diameter.Value}", diaTolPlus, diaTolMinus); AddLinearDim(ctx, new Point3d(ox, oy, 0), new Point3d(ox + diameter.Value, oy, 0), new Point3d(ctx.Center.X, oy - 20, 0), 0, diaDimText); // 高度标注 var htTolPlus = bag.GetDoubleOrNull(KeyDiskHeightTolPlus); var htTolMinus = bag.GetDoubleOrNull(KeyDiskHeightTolMinus); var htDimText = BuildDimensionText($"{H}", htTolPlus, htTolMinus); AddLinearDim(ctx, new Point3d(ox + diameter.Value, oy, 0), new Point3d(ox + diameter.Value, oy + H, 0), new Point3d(ox + diameter.Value + 20, ctx.Center.Y, 0), 90, htDimText); // 未注圆角(使用饼盘专用Key) var unspecifiedFillet = bag.GetDoubleOrNull(KeyDiskFilletRadiusMax); if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) { DrawUnspecifiedFilletNote(ctx, ox, oy + H, R, diameter.Value, unspecifiedFillet.Value); } // 零件尺寸(如果有) var diaPrime = bag.GetDoubleOrNull(KeyDiskDiameterPrime); var heightPrime = bag.GetDoubleOrNull(KeyDiskHeightPrime); if (diaPrime.HasValue && diaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0) { DrawDiskPartContour(ctx, ox, oy, diameter.Value, H, diaPrime.Value, heightPrime.Value); } } private static void DrawDiskPartContour(DrawingContext ctx, double ox, double oy, double forgingDia, double forgingH, double partDia, double partH) { double offsetX = (forgingDia - partDia) / 2.0; double offsetY = (forgingH - partH) / 2.0; var polyPart = new Polyline(); polyPart.AddVertexAt(0, new Point2d(ox + offsetX, oy + offsetY), 0, 0, 0); polyPart.AddVertexAt(1, new Point2d(ox + offsetX + partDia, oy + offsetY), 0, 0, 0); polyPart.AddVertexAt(2, new Point2d(ox + offsetX + partDia, oy + offsetY + partH), 0, 0, 0); polyPart.AddVertexAt(3, new Point2d(ox + offsetX, oy + offsetY + partH), 0, 0, 0); polyPart.Closed = true; polyPart.ColorIndex = 7; ctx.Btr.AppendEntity(polyPart); ctx.Tr.AddNewlyCreatedDBObject(polyPart, true); // 填充 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 = 0.8; hatch.PatternAngle = 0; hatch.Associative = false; hatch.ColorIndex = 7; var ids = new ObjectIdCollection(); ids.Add(polyPart.ObjectId); hatch.AppendLoop(HatchLoopTypes.External, ids); hatch.EvaluateHatch(true); } catch { } // 零件直径标注 AddLinearDim(ctx, new Point3d(ox + offsetX, oy + offsetY, 0), new Point3d(ox + offsetX + partDia, oy + offsetY, 0), new Point3d(ox + offsetX + partDia / 2, oy + offsetY - 10, 0), 0, $"%%c{partDia}"); // 零件高度标注 AddLinearDim(ctx, new Point3d(ox + offsetX + partDia, oy + offsetY, 0), new Point3d(ox + offsetX + partDia, oy + offsetY + partH, 0), new Point3d(ox + offsetX + partDia + 10, oy + offsetY + partH / 2, 0), 90, $"{partH}"); } #endregion #region 轴杆绘制 - 特征驱动 private static void DrawShaftFeatures(DrawingContext ctx) { var bag = ctx.Bag; // 圆轴使用Diameter/Length,方轴使用BoxSize1/2/3 var isSquareShaft = !string.IsNullOrWhiteSpace(ctx.SpecialCondition) && ctx.SpecialCondition.IndexOf("方轴", StringComparison.OrdinalIgnoreCase) >= 0; if (isSquareShaft) { // 方轴使用方体参数绘制 DrawSquareShaftFeatures(ctx); return; } // 圆轴绘制 var diameter = bag.GetDoubleOrNull(KeyDiameter); var length = bag.GetDoubleOrNull(KeyLength); if (!diameter.HasValue || diameter.Value <= 0) return; if (!length.HasValue || length.Value <= 0) return; double ox = ctx.Center.X - length.Value / 2.0; double oy = ctx.Center.Y; double R = diameter.Value / 2.0; double L = length.Value; TryLoadLinetype(ctx.Db, ctx.Tr, "CENTER"); // 绘制轴杆轮廓(侧视图为矩形) var poly = new Polyline(); poly.AddVertexAt(0, new Point2d(ox, oy - R), 0, 0, 0); poly.AddVertexAt(1, new Point2d(ox + L, oy - R), 0, 0, 0); poly.AddVertexAt(2, new Point2d(ox + L, oy + R), 0, 0, 0); poly.AddVertexAt(3, new Point2d(ox, oy + R), 0, 0, 0); poly.Closed = true; poly.ColorIndex = 7; ctx.Btr.AppendEntity(poly); ctx.Tr.AddNewlyCreatedDBObject(poly, true); // 中心线 var centerLine = new Line(new Point3d(ox - 10, oy, 0), new Point3d(ox + L + 10, oy, 0)); centerLine.ColorIndex = 1; centerLine.Linetype = "CENTER"; ctx.Btr.AppendEntity(centerLine); ctx.Tr.AddNewlyCreatedDBObject(centerLine, true); // 直径标注 var diaTolPlus = bag.GetDoubleOrNull(KeyDiameterTolPlus); var diaTolMinus = bag.GetDoubleOrNull(KeyDiameterTolMinus); var diaDimText = BuildDimensionText($"%%c{diameter.Value}", diaTolPlus, diaTolMinus); AddLinearDim(ctx, new Point3d(ox, oy + R, 0), new Point3d(ox, oy - R, 0), new Point3d(ox - 20, oy, 0), 90, diaDimText); // 长度标注 var lenTolPlus = bag.GetDoubleOrNull(KeyLengthTolPlus); var lenTolMinus = bag.GetDoubleOrNull(KeyLengthTolMinus); var lenDimText = BuildDimensionText($"{L}", lenTolPlus, lenTolMinus); AddLinearDim(ctx, new Point3d(ox, oy - R, 0), new Point3d(ox + L, oy - R, 0), new Point3d(ctx.Center.X, oy - R - 20, 0), 0, lenDimText); // 未注圆角(使用轴杆专用Key) var unspecifiedFillet = bag.GetDoubleOrNull(KeyShaftFilletRadiusMax); if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) { DrawUnspecifiedFilletNote(ctx, ox, oy, R, L, unspecifiedFillet.Value); } // 零件尺寸(如果有) var diaPrime = bag.GetDoubleOrNull(KeyDiameterPrime); var lenPrime = bag.GetDoubleOrNull(KeyLengthPrime); if (diaPrime.HasValue && diaPrime.Value > 0 && lenPrime.HasValue && lenPrime.Value > 0) { DrawShaftPartContour(ctx, ox, oy, R, L, diaPrime.Value, lenPrime.Value); } } /// /// 方轴绘制(使用方体参数) /// private static void DrawSquareShaftFeatures(DrawingContext ctx) { var bag = ctx.Bag; var size1 = bag.GetDoubleOrNull(KeyBoxSize1); var size2 = bag.GetDoubleOrNull(KeyBoxSize2); var size3 = bag.GetDoubleOrNull(KeyBoxSize3); if (!size1.HasValue || size1.Value <= 0) return; double width = size1.Value; double height = size2.HasValue && size2.Value > 0 ? size2.Value : size1.Value; double depth = size3.HasValue && size3.Value > 0 ? size3.Value : 0; double ox = ctx.Center.X - width / 2.0; double oy = ctx.Center.Y - height / 2.0; // 绘制正视图(矩形) var poly = new Polyline(); poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0); poly.AddVertexAt(1, new Point2d(ox + width, oy), 0, 0, 0); poly.AddVertexAt(2, new Point2d(ox + width, oy + height), 0, 0, 0); poly.AddVertexAt(3, new Point2d(ox, oy + height), 0, 0, 0); poly.Closed = true; poly.ColorIndex = 7; ctx.Btr.AppendEntity(poly); ctx.Tr.AddNewlyCreatedDBObject(poly, true); // 尺寸1标注 var tol1Plus = bag.GetDoubleOrNull(KeyBoxSize1TolPlus); var tol1Minus = bag.GetDoubleOrNull(KeyBoxSize1TolMinus); var dim1Text = BuildDimensionText($"{width}", tol1Plus, tol1Minus); AddLinearDim(ctx, new Point3d(ox, oy, 0), new Point3d(ox + width, oy, 0), new Point3d(ctx.Center.X, oy - 20, 0), 0, dim1Text); // 尺寸2标注 if (size2.HasValue && size2.Value > 0) { var tol2Plus = bag.GetDoubleOrNull(KeyBoxSize2TolPlus); var tol2Minus = bag.GetDoubleOrNull(KeyBoxSize2TolMinus); var dim2Text = BuildDimensionText($"{height}", tol2Plus, tol2Minus); AddLinearDim(ctx, new Point3d(ox + width, oy, 0), new Point3d(ox + width, oy + height, 0), new Point3d(ox + width + 20, ctx.Center.Y, 0), 90, dim2Text); } // 尺寸3标注 if (depth > 0) { var tol3Plus = bag.GetDoubleOrNull(KeyBoxSize3TolPlus); var tol3Minus = bag.GetDoubleOrNull(KeyBoxSize3TolMinus); var dim3Text = BuildDimensionText($"深度:{depth}", tol3Plus, tol3Minus); try { var text = new DBText(); text.TextString = dim3Text; text.Position = new Point3d(ox + width + 10, oy + height + 10, 0); text.Height = 5; text.ColorIndex = 7; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { } } // 未注圆角(使用方体专用Key) var unspecifiedFillet = bag.GetDoubleOrNull(KeyBoxFilletRadiusMax); if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) { try { var text = new DBText(); text.TextString = $"未注圆角半径R≤{unspecifiedFillet.Value}"; text.Position = new Point3d(ox + width + 10, oy + height + 20, 0); text.Height = 5; text.ColorIndex = 7; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { } } // 零件尺寸 var size1Prime = bag.GetDoubleOrNull(KeyBoxSize1Prime); var size2Prime = bag.GetDoubleOrNull(KeyBoxSize2Prime); var size3Prime = bag.GetDoubleOrNull(KeyBoxSize3Prime); if (size1Prime.HasValue && size1Prime.Value > 0) { DrawBlockPartContour(ctx, ox, oy, width, height, size1Prime.Value, size2Prime ?? size1Prime.Value, size3Prime); } } private static void DrawShaftPartContour(DrawingContext ctx, double ox, double oy, double R, double L, double partDia, double partLen) { double offsetX = (L - partLen) / 2.0; double Rp = partDia / 2.0; var polyPart = new Polyline(); polyPart.AddVertexAt(0, new Point2d(ox + offsetX, oy - Rp), 0, 0, 0); polyPart.AddVertexAt(1, new Point2d(ox + offsetX + partLen, oy - Rp), 0, 0, 0); polyPart.AddVertexAt(2, new Point2d(ox + offsetX + partLen, oy + Rp), 0, 0, 0); polyPart.AddVertexAt(3, new Point2d(ox + offsetX, oy + Rp), 0, 0, 0); polyPart.Closed = true; polyPart.ColorIndex = 7; ctx.Btr.AppendEntity(polyPart); ctx.Tr.AddNewlyCreatedDBObject(polyPart, true); // 填充 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 = 0.8; hatch.PatternAngle = 0; hatch.Associative = false; hatch.ColorIndex = 7; var ids = new ObjectIdCollection(); ids.Add(polyPart.ObjectId); hatch.AppendLoop(HatchLoopTypes.External, ids); hatch.EvaluateHatch(true); } catch { } // 零件直径标注 AddLinearDim(ctx, new Point3d(ox + offsetX, oy + Rp, 0), new Point3d(ox + offsetX, oy - Rp, 0), new Point3d(ox + offsetX - 10, oy, 0), 90, $"%%c{partDia}"); // 零件长度标注 AddLinearDim(ctx, new Point3d(ox + offsetX, oy - Rp, 0), new Point3d(ox + offsetX + partLen, oy - Rp, 0), new Point3d(ox + offsetX + partLen / 2, oy - Rp - 10, 0), 0, $"{partLen}"); } #endregion #region 方形绘制 - 特征驱动 private static void DrawBlockFeatures(DrawingContext ctx) { var bag = ctx.Bag; // 使用方体专用参数 var size1 = bag.GetDoubleOrNull(KeyBoxSize1); var size2 = bag.GetDoubleOrNull(KeyBoxSize2); var size3 = bag.GetDoubleOrNull(KeyBoxSize3); if (!size1.HasValue || size1.Value <= 0) return; // 默认为正方形或使用size1 double width = size1.Value; double height = size2.HasValue && size2.Value > 0 ? size2.Value : size1.Value; double depth = size3.HasValue && size3.Value > 0 ? size3.Value : 0; double ox = ctx.Center.X - width / 2.0; double oy = ctx.Center.Y - height / 2.0; // 绘制正视图(矩形) var poly = new Polyline(); poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0); poly.AddVertexAt(1, new Point2d(ox + width, oy), 0, 0, 0); poly.AddVertexAt(2, new Point2d(ox + width, oy + height), 0, 0, 0); poly.AddVertexAt(3, new Point2d(ox, oy + height), 0, 0, 0); poly.Closed = true; poly.ColorIndex = 7; ctx.Btr.AppendEntity(poly); ctx.Tr.AddNewlyCreatedDBObject(poly, true); // 宽度标注 (BoxSize1) var tol1Plus = bag.GetDoubleOrNull(KeyBoxSize1TolPlus); var tol1Minus = bag.GetDoubleOrNull(KeyBoxSize1TolMinus); var dim1Text = BuildDimensionText($"{width}", tol1Plus, tol1Minus); AddLinearDim(ctx, new Point3d(ox, oy, 0), new Point3d(ox + width, oy, 0), new Point3d(ctx.Center.X, oy - 20, 0), 0, dim1Text); // 高度标注 (BoxSize2) if (size2.HasValue && size2.Value > 0) { var tol2Plus = bag.GetDoubleOrNull(KeyBoxSize2TolPlus); var tol2Minus = bag.GetDoubleOrNull(KeyBoxSize2TolMinus); var dim2Text = BuildDimensionText($"{height}", tol2Plus, tol2Minus); AddLinearDim(ctx, new Point3d(ox + width, oy, 0), new Point3d(ox + width, oy + height, 0), new Point3d(ox + width + 20, ctx.Center.Y, 0), 90, dim2Text); } // 深度标注 (BoxSize3) - 如果有的话,以文字形式标注 if (depth > 0) { var tol3Plus = bag.GetDoubleOrNull(KeyBoxSize3TolPlus); var tol3Minus = bag.GetDoubleOrNull(KeyBoxSize3TolMinus); var dim3Text = BuildDimensionText($"深度:{depth}", tol3Plus, tol3Minus); try { var text = new DBText(); text.TextString = dim3Text; text.Position = new Point3d(ox + width + 10, oy + height + 10, 0); text.Height = 5; text.ColorIndex = 7; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { } } // 未注圆角(使用方体专用Key) var unspecifiedFillet = bag.GetDoubleOrNull(KeyBoxFilletRadiusMax); if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) { try { var text = new DBText(); text.TextString = $"未注圆角半径R≤{unspecifiedFillet.Value}"; text.Position = new Point3d(ox + width + 10, oy + height + 20, 0); text.Height = 5; text.ColorIndex = 7; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { } } // 有圆头时,绘制两端半圆形圆头 if (ctx.HasRoundHead) { double R = height / 2.0; // 圆头半径 = 高度/2(示意性) double centerY = oy + height / 2.0; // 左端圆头(半圆) try { var arcLeft = new Arc(new Point3d(ox, centerY, 0), R, Math.PI / 2, Math.PI * 1.5); arcLeft.ColorIndex = 7; ctx.Btr.AppendEntity(arcLeft); ctx.Tr.AddNewlyCreatedDBObject(arcLeft, true); } catch { } // 右端圆头(半圆) try { var arcRight = new Arc(new Point3d(ox + width, centerY, 0), R, -Math.PI / 2, Math.PI / 2); arcRight.ColorIndex = 7; ctx.Btr.AppendEntity(arcRight); ctx.Tr.AddNewlyCreatedDBObject(arcRight, true); } catch { } } // 零件尺寸 var size1Prime = bag.GetDoubleOrNull(KeyBoxSize1Prime); var size2Prime = bag.GetDoubleOrNull(KeyBoxSize2Prime); var size3Prime = bag.GetDoubleOrNull(KeyBoxSize3Prime); if (size1Prime.HasValue && size1Prime.Value > 0) { DrawBlockPartContour(ctx, ox, oy, width, height, size1Prime.Value, size2Prime ?? size1Prime.Value, size3Prime); } } private static void DrawBlockPartContour(DrawingContext ctx, double ox, double oy, double forgingW, double forgingH, double partW, double partH, double? partD) { double offsetX = (forgingW - partW) / 2.0; double offsetY = (forgingH - partH) / 2.0; var polyPart = new Polyline(); polyPart.AddVertexAt(0, new Point2d(ox + offsetX, oy + offsetY), 0, 0, 0); polyPart.AddVertexAt(1, new Point2d(ox + offsetX + partW, oy + offsetY), 0, 0, 0); polyPart.AddVertexAt(2, new Point2d(ox + offsetX + partW, oy + offsetY + partH), 0, 0, 0); polyPart.AddVertexAt(3, new Point2d(ox + offsetX, oy + offsetY + partH), 0, 0, 0); polyPart.Closed = true; polyPart.ColorIndex = 7; ctx.Btr.AppendEntity(polyPart); ctx.Tr.AddNewlyCreatedDBObject(polyPart, true); // 填充 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 = 0.8; hatch.PatternAngle = 0; hatch.Associative = false; hatch.ColorIndex = 7; var ids = new ObjectIdCollection(); ids.Add(polyPart.ObjectId); hatch.AppendLoop(HatchLoopTypes.External, ids); hatch.EvaluateHatch(true); } catch { } // 零件尺寸1标注 AddLinearDim(ctx, new Point3d(ox + offsetX, oy + offsetY, 0), new Point3d(ox + offsetX + partW, oy + offsetY, 0), new Point3d(ox + offsetX + partW / 2, oy + offsetY - 10, 0), 0, $"{partW}"); // 零件尺寸2标注 AddLinearDim(ctx, new Point3d(ox + offsetX + partW, oy + offsetY, 0), new Point3d(ox + offsetX + partW, oy + offsetY + partH, 0), new Point3d(ox + offsetX + partW + 10, oy + offsetY + partH / 2, 0), 90, $"{partH}"); // 零件尺寸3标注(如果有) if (partD.HasValue && partD.Value > 0) { try { var text = new DBText(); text.TextString = $"深度:{partD.Value}"; text.Position = new Point3d(ox + offsetX + partW + 10, oy + offsetY + partH + 5, 0); text.Height = 4; text.ColorIndex = 7; ctx.Btr.AppendEntity(text); ctx.Tr.AddNewlyCreatedDBObject(text, true); } catch { } } } #endregion #region 辅助方法 private static string BuildDimensionText(string baseText, double? tolPlus, double? tolMinus) { if (!tolPlus.HasValue && !tolMinus.HasValue) { return baseText; } var result = baseText; // 公差格式: 基本尺寸 +上差/-下差 if (tolPlus.HasValue && tolMinus.HasValue) { var plusStr = tolPlus.Value >= 0 ? $"+{tolPlus.Value}" : $"{tolPlus.Value}"; var minusStr = tolMinus.Value >= 0 ? $"+{tolMinus.Value}" : $"{tolMinus.Value}"; result += $"({plusStr}/{minusStr})"; } else if (tolPlus.HasValue) { var plusStr = tolPlus.Value >= 0 ? $"+{tolPlus.Value}" : $"{tolPlus.Value}"; result += $"({plusStr})"; } else if (tolMinus.HasValue) { var minusStr = tolMinus.Value >= 0 ? $"+{tolMinus.Value}" : $"{tolMinus.Value}"; result += $"({minusStr})"; } return result; } private static void AddLinearDim(DrawingContext ctx, Point3d pt1, Point3d pt2, Point3d dimLinePt, double rotationDeg, string textOverride) { try { double rotRad = rotationDeg * Math.PI / 180.0; var dim = new RotatedDimension(rotRad, pt1, pt2, dimLinePt, textOverride, ctx.Db.Dimstyle); dim.ColorIndex = 4; ctx.Btr.AppendEntity(dim); ctx.Tr.AddNewlyCreatedDBObject(dim, true); } catch { // 忽略标注错误 } } private static void TryLoadLinetype(Database db, Transaction tr, string linetypeName) { try { var linetypeTbl = (LinetypeTable)tr.GetObject(db.LinetypeTableId, OpenMode.ForRead); if (!linetypeTbl.Has(linetypeName)) { try { db.LoadLineTypeFile(linetypeName, "acad.lin"); } catch { } } } catch { } } /// /// 对参数包中的尺寸参数应用缩放比例 /// private static ParamBag ScaleParamBag(ParamBag original, double scaleFactor) { if (original == null || scaleFactor <= 0 || scaleFactor >= 1.0) { return original; } var scaled = new ParamBag(); // 需要缩放的尺寸参数Key列表 var sizeKeys = new HashSet(StringComparer.OrdinalIgnoreCase) { // 环形参数 KeyOuterDiameter1, KeyInnerDiameter2, KeyHeight1, KeyOuterDiameter1Prime, KeyInnerDiameter2Prime, KeyHeight1Prime, KeyMinWallThickness, // 饼盘参数 KeyDiskDiameter, KeyDiskHeight, KeyDiskDiameterPrime, KeyDiskHeightPrime, // 轴杆参数 KeyDiameter, KeyLength, KeyDiameterPrime, KeyLengthPrime, // 方体参数 KeyBoxSize1, KeyBoxSize2, KeyBoxSize3, KeyBoxSize1Prime, KeyBoxSize2Prime, KeyBoxSize3Prime, // 圆角参数 KeyUnspecifiedFilletRadiusMax, KeyInnerRadiusMax, KeyDiskFilletRadiusMax, KeyShaftFilletRadiusMax, KeyBoxFilletRadiusMax, KeyBoxRoundHeadFilletRadiusMax }; // 公差参数也需要缩放 var toleranceKeys = new HashSet(StringComparer.OrdinalIgnoreCase) { KeyOuterDiameter1TolPlus, KeyOuterDiameter1TolMinus, KeyInnerDiameter2TolPlus, KeyInnerDiameter2TolMinus, KeyHeight1TolPlus, KeyHeight1TolMinus, KeyDiskDiameterTolPlus, KeyDiskDiameterTolMinus, KeyDiskHeightTolPlus, KeyDiskHeightTolMinus, KeyDiameterTolPlus, KeyDiameterTolMinus, KeyLengthTolPlus, KeyLengthTolMinus, KeyBoxSize1TolPlus, KeyBoxSize1TolMinus, KeyBoxSize2TolPlus, KeyBoxSize2TolMinus, KeyBoxSize3TolPlus, KeyBoxSize3TolMinus }; foreach (var key in original.GetKeys()) { var value = original.GetString(key); if (sizeKeys.Contains(key) || toleranceKeys.Contains(key)) { // 尝试解析为数值并缩放 if (double.TryParse(value, out var numValue)) { var scaledValue = numValue * scaleFactor; // 保留适当的小数位数 scaled.Set(key, scaledValue.ToString("F2")); } else { scaled.Set(key, value); } } else { // 非尺寸参数直接复制 scaled.Set(key, value); } } return scaled; } #endregion } }