using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using CadParamPluging.Common;
namespace CadParamPluging.Cad
{
public static class ShaftRawFreeForgeSquareShaftDrawer
{
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 = "轴杆",
SpecialCondition = "方轴",
ProcessMethod = "自由锻",
Btr = btr,
Style = new DrawingStyleManager(db, tr)
};
DrawCore(context);
}
private static void DrawCore(FeatureDrivenDrawer.DrawingContext ctx)
{
var bag = ctx.Bag;
var size1 = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize1);
var size2 = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize2);
var size3 = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize3);
var originalSize1 = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize1);
if (!size1.HasValue || size1.Value <= 0 || !size2.HasValue || size2.Value <= 0)
{
return;
}
double S1 = size1.Value;
double S2 = size2.Value;
double S3 = size3.HasValue && size3.Value > 0 ? size3.Value : 0;
double originalS1 = originalSize1.HasValue ? originalSize1.Value : S1;
double ox = ctx.Center.X - S1 / 2.0;
double oy = ctx.Center.Y - S2 / 2.0;
var filletRParam = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftFilletRadiusMax);
double filletR = filletRParam.HasValue && filletRParam.Value > 0 ? filletRParam.Value : 0;
double maxR = Math.Min(S1 / 2.0, S2 / 2.0);
if (filletR > maxR) filletR = maxR;
// 判断是否需要断线
bool needBreakLines = originalS1 > 150;
const double lineSpacing = 3.5;
// 1. Draw Main View - 如果需要断线,则绘制带缺口的轮廓
double xBreak = ox + S1 / 4.0;
// 1. Draw Main View - 如果需要断线,则绘制带缺口的轮廓
if (needBreakLines)
{
DrawRectWithBreak(ctx, ox, oy, S1, S2, filletR, xBreak, lineSpacing);
}
else
{
DrawRectWithFillets(ctx, ox, oy, S1, S2, filletR, DrawingStyleManager.Role.OutlineBold);
}
// 2. 绘制左右两端的弧线(向外凸出)
// 弧高设为 S2/5(尺寸2的1/5)
double arcHeight = S2 / 5.0;
DrawEndArcs(ctx, ox, oy, S1, S2, arcHeight);
// 3. 绘制中心线 (横向,在中间位置) - 已移除
// DrawHorizontalCenterLine(ctx, ctx.Center.Y, ox, ox + S1, needBreakLines, xBreak, lineSpacing);
// 4. Draw Break Lines if needed
if (needBreakLines)
{
DrawBreakLines(ctx, ox, oy, S1, S2);
}
// 3. Draw Section if S3 > 0
if (S3 > 0)
{
double sectionW = S3;
double sectionH = S2;
double sectionOx = ox + S1 * 2.0 / 3.0 - sectionW / 2.0; // 剖面位于右边1/3处
double sectionOy = oy;
double maxRSec = Math.Min(sectionW / 2.0, sectionH / 2.0);
double filletRSec = (filletR > maxRSec) ? maxRSec : filletR;
var sectionPoly = CreateRectPoly(sectionOx, sectionOy, sectionW, sectionH, filletRSec);
ctx.Style?.Apply(sectionPoly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(sectionPoly);
ctx.Tr.AddNewlyCreatedDBObject(sectionPoly, true);
CreateHatchForPolyline(ctx, sectionPoly);
}
// 4. Dimensions
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize1) ?? S1;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize1);
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize1TolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize1TolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize1TolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize1TolMinus);
var dimText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize1Prime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += @"\X(" + FeatureDrivenDrawer.FormatDimNumber(valPrime.Value) + ")";
}
double dimY = oy - 25;
double dimOriginY = oy + filletR;
FeatureDrivenDrawer.AddLinearDim(ctx, new Point3d(ox, dimOriginY, 0), new Point3d(ox + S1, dimOriginY, 0), new Point3d(ctx.Center.X, dimY, 0), 0, dimText);
}
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize2) ?? S2;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize2);
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize2TolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize2TolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize2TolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize2TolMinus);
var dimText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize2Prime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += @"\X(" + FeatureDrivenDrawer.FormatDimNumber(valPrime.Value) + ")";
}
double dimX = ox + S1 + 20;
double dimOriginX = ox + S1 - filletR;
FeatureDrivenDrawer.AddLinearDim(ctx, new Point3d(dimOriginX, oy, 0), new Point3d(dimOriginX, oy + S2, 0), new Point3d(dimX, ctx.Center.Y, 0), 90, dimText);
}
if (S3 > 0)
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize3) ?? S3;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize3);
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize3TolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize3TolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize3TolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeySquareShaftSize3TolMinus);
var dimText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize3Prime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += @"\X(" + FeatureDrivenDrawer.FormatDimNumber(valPrime.Value) + ")";
}
double dimY = oy + S2 + 20;
double sectionOx = ox + S1 * 2.0 / 3.0 - S3 / 2.0; // 标注位置对应剖面
double dimOriginY = oy + S2 - filletR;
FeatureDrivenDrawer.AddLinearDim(ctx, new Point3d(sectionOx, dimOriginY, 0), new Point3d(sectionOx + S3, dimOriginY, 0), new Point3d(ctx.Center.X, dimY, 0), 0, dimText);
}
var hardnessVal = bag.GetString(FeatureDrivenDrawer.KeyHardness);
if (!string.IsNullOrWhiteSpace(hardnessVal))
{
double xStart = (S3 > 0) ? ctx.Center.X : (ox + S1 / 2.0);
double yStart = oy;
FeatureDrivenDrawer.DrawHardnessSymbol(ctx, xStart, yStart);
}
var markingText = bag.GetString(FeatureDrivenDrawer.KeyMarkingContent);
if (!string.IsNullOrWhiteSpace(markingText))
{
double xTarget = (S3 > 0) ? ctx.Center.X : (ox + S1 / 2.0);
double yTarget = oy + S2;
FeatureDrivenDrawer.DrawSpecialHBLeaderToTop(ctx, xTarget, yTarget, markingText);
}
var s1Prime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize1Prime);
var s2Prime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeySquareShaftSize2Prime);
if (s1Prime.HasValue && s1Prime.Value > 0 && s2Prime.HasValue && s2Prime.Value > 0)
{
double pL = s1Prime.Value;
double pH = s2Prime.Value;
double pOx = ctx.Center.X - pL / 2.0;
double pOy = ctx.Center.Y - pH / 2.0;
if (needBreakLines)
{
// double xBreak = ox + S1 / 4.0; // variable is already declared in outer scope
DrawRectOutlineWithBreak(ctx, pOx, pOy, pL, pH, xBreak, lineSpacing, DrawingStyleManager.Role.PartContour);
}
else
{
DrawRectOutline(ctx, pOx, pOy, pL, pH, DrawingStyleManager.Role.PartContour);
}
}
}
///
/// 绘制断线(使用 BreakLine 样式:白色 PHANTOM 双点划线)
///
private static void DrawBreakLines(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double width, double height)
{
const double lineSpacing = 3.5;
const double extend = 5.0;
double xBreak = ox + width / 4.0;
double y0 = oy - extend;
double y1 = oy + height + extend;
var line1 = new Line(new Point3d(xBreak, y0, 0), new Point3d(xBreak, y1, 0));
ctx.Style?.Apply(line1, DrawingStyleManager.Role.BreakLine);
ctx.Btr.AppendEntity(line1);
ctx.Tr.AddNewlyCreatedDBObject(line1, true);
var line2 = new Line(new Point3d(xBreak + lineSpacing, y0, 0), new Point3d(xBreak + lineSpacing, y1, 0));
ctx.Style?.Apply(line2, DrawingStyleManager.Role.BreakLine);
ctx.Btr.AppendEntity(line2);
ctx.Tr.AddNewlyCreatedDBObject(line2, true);
}
///
/// 绘制带断口的矩形轮廓(在断线位置打断上下横线)
///
private static void DrawRectWithBreak(FeatureDrivenDrawer.DrawingContext ctx, double x, double y, double w, double h, double r, double xBreak, double breakWidth)
{
// 左边竖线
var leftLine = new Line(new Point3d(x, y, 0), new Point3d(x, y + h, 0));
ctx.Style?.Apply(leftLine, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(leftLine);
ctx.Tr.AddNewlyCreatedDBObject(leftLine, true);
// 右边竖线
var rightLine = new Line(new Point3d(x + w, y, 0), new Point3d(x + w, y + h, 0));
ctx.Style?.Apply(rightLine, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(rightLine);
ctx.Tr.AddNewlyCreatedDBObject(rightLine, true);
// 底边:断开 [xBreak, xBreak + breakWidth]
// 左段
var bottomLeft = new Line(new Point3d(x, y, 0), new Point3d(xBreak, y, 0));
ctx.Style?.Apply(bottomLeft, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(bottomLeft);
ctx.Tr.AddNewlyCreatedDBObject(bottomLeft, true);
// 右段
var bottomRight = new Line(new Point3d(xBreak + breakWidth, y, 0), new Point3d(x + w, y, 0));
ctx.Style?.Apply(bottomRight, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(bottomRight);
ctx.Tr.AddNewlyCreatedDBObject(bottomRight, true);
// 顶边:断开 [xBreak, xBreak + breakWidth]
// 左段
var topLeft = new Line(new Point3d(x, y + h, 0), new Point3d(xBreak, y + h, 0));
ctx.Style?.Apply(topLeft, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(topLeft);
ctx.Tr.AddNewlyCreatedDBObject(topLeft, true);
// 右段
var topRight = new Line(new Point3d(xBreak + breakWidth, y + h, 0), new Point3d(x + w, y + h, 0));
ctx.Style?.Apply(topRight, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(topRight);
ctx.Tr.AddNewlyCreatedDBObject(topRight, true);
}
private static void DrawRectWithFillets(FeatureDrivenDrawer.DrawingContext ctx, double x, double y, double w, double h, double r, DrawingStyleManager.Role role = DrawingStyleManager.Role.OutlineBold)
{
var poly = CreateRectPoly(x, y, w, h, r);
ctx.Style?.Apply(poly, role);
ctx.Btr.AppendEntity(poly);
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
}
private static Polyline CreateRectPoly(double x, double y, double w, double h, double r)
{
var poly = new Polyline();
if (r < 0.01)
{
poly.AddVertexAt(0, new Point2d(x, y), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(x + w, y), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(x + w, y + h), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(x, y + h), 0, 0, 0);
}
else
{
var bulge = Math.Tan(Math.PI / 8.0);
poly.AddVertexAt(0, new Point2d(x + r, y), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(x + w - r, y), bulge, 0, 0);
poly.AddVertexAt(2, new Point2d(x + w, y + r), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(x + w, y + h - r), bulge, 0, 0);
poly.AddVertexAt(4, new Point2d(x + w - r, y + h), 0, 0, 0);
poly.AddVertexAt(5, new Point2d(x + r, y + h), bulge, 0, 0);
poly.AddVertexAt(6, new Point2d(x, y + h - r), 0, 0, 0);
poly.AddVertexAt(7, new Point2d(x, y + r), bulge, 0, 0);
}
poly.Closed = true;
return poly;
}
private static void DrawRectOutline(FeatureDrivenDrawer.DrawingContext ctx, double x, double y, double w, double h, DrawingStyleManager.Role role)
{
var poly = new Polyline();
poly.AddVertexAt(0, new Point2d(x, y), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(x + w, y), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(x + w, y + h), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(x, y + h), 0, 0, 0);
poly.Closed = true;
ctx.Style?.Apply(poly, role);
ctx.Btr.AppendEntity(poly);
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
}
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
{
}
}
private static ParamBag ScaleParamBag(ParamBag original, double scaleFactor)
{
if (original == null) return null;
if (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("SquareShaftSize") || k.Contains("Radius") || k.Contains("Prime"))
{
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;
}
///
/// 绘制左右两端的弧线(向外凸出)
/// 使用Polyline的bulge(凸度)值绘制,确保端点精确对齐
///
private static void DrawEndArcs(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double W, double H, double arcHeight)
{
try
{
// 弧线端点:
// 左侧弧线:从(ox, oy+H)到(ox, oy),向左凸出arcHeight
// 右侧弧线:从(ox+W, oy)到(ox+W, oy+H),向右凸出arcHeight
double chordLength = H;
double sagitta = arcHeight;
// 计算凸度:bulge = 2 * 拱高 / 弦长
double bulge = (2.0 * sagitta) / chordLength;
// 左侧弧线:从(ox, oy+H)到(ox, oy),向左凸出(正凸度)
var leftArc = new Polyline();
leftArc.AddVertexAt(0, new Point2d(ox, oy + H), bulge, 0, 0);
leftArc.AddVertexAt(1, new Point2d(ox, oy), 0, 0, 0);
ctx.Style?.Apply(leftArc, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(leftArc);
ctx.Tr.AddNewlyCreatedDBObject(leftArc, true);
// 右侧弧线:从(ox+W, oy)到(ox+W, oy+H),向右凸出(正凸度)
var rightArc = new Polyline();
rightArc.AddVertexAt(0, new Point2d(ox + W, oy), bulge, 0, 0);
rightArc.AddVertexAt(1, new Point2d(ox + W, oy + H), 0, 0, 0);
ctx.Style?.Apply(rightArc, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(rightArc);
ctx.Tr.AddNewlyCreatedDBObject(rightArc, true);
}
catch
{
// ignore
}
}
///
/// 绘制带断口的零件轮廓(在断线位置打断上下横线)
/// 支持自定义 Role (通常为 PartContour)
///
private static void DrawRectOutlineWithBreak(FeatureDrivenDrawer.DrawingContext ctx, double x, double y, double w, double h, double xBreak, double breakWidth, DrawingStyleManager.Role role)
{
// 左边竖线
var leftLine = new Line(new Point3d(x, y, 0), new Point3d(x, y + h, 0));
ctx.Style?.Apply(leftLine, role);
ctx.Btr.AppendEntity(leftLine);
ctx.Tr.AddNewlyCreatedDBObject(leftLine, true);
// 右边竖线
var rightLine = new Line(new Point3d(x + w, y, 0), new Point3d(x + w, y + h, 0));
ctx.Style?.Apply(rightLine, role);
ctx.Btr.AppendEntity(rightLine);
ctx.Tr.AddNewlyCreatedDBObject(rightLine, true);
// 底边:断开 [xBreak, xBreak + breakWidth]
// 左段
if (xBreak > x)
{
var bottomLeft = new Line(new Point3d(x, y, 0), new Point3d(Math.Min(xBreak, x + w), y, 0));
ctx.Style?.Apply(bottomLeft, role);
ctx.Btr.AppendEntity(bottomLeft);
ctx.Tr.AddNewlyCreatedDBObject(bottomLeft, true);
}
// 右段
if (xBreak + breakWidth < x + w)
{
var bottomRight = new Line(new Point3d(Math.Max(xBreak + breakWidth, x), y, 0), new Point3d(x + w, y, 0));
ctx.Style?.Apply(bottomRight, role);
ctx.Btr.AppendEntity(bottomRight);
ctx.Tr.AddNewlyCreatedDBObject(bottomRight, true);
}
// 顶边:断开 [xBreak, xBreak + breakWidth]
// 左段
if (xBreak > x)
{
var topLeft = new Line(new Point3d(x, y + h, 0), new Point3d(Math.Min(xBreak, x + w), y + h, 0));
ctx.Style?.Apply(topLeft, role);
ctx.Btr.AppendEntity(topLeft);
ctx.Tr.AddNewlyCreatedDBObject(topLeft, true);
}
// 右段
if (xBreak + breakWidth < x + w)
{
var topRight = new Line(new Point3d(Math.Max(xBreak + breakWidth, x), y + h, 0), new Point3d(x + w, y + h, 0));
ctx.Style?.Apply(topRight, role);
ctx.Btr.AppendEntity(topRight);
ctx.Tr.AddNewlyCreatedDBObject(topRight, true);
}
}
}
}