CadParamPluging/Cad/ShaftRawFreeForgeRoundShaftDrawer.cs

482 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using CadParamPluging.Common;
namespace CadParamPluging.Cad
{
public static class ShaftRawFreeForgeRoundShaftDrawer
{
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 dia = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameter);
var len = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyLength);
if (!dia.HasValue || dia.Value <= 0 || !len.HasValue || len.Value <= 0)
{
return;
}
// 逻辑要求:直径是宽度,长度是高度
double W = dia.Value;
double H = len.Value;
// 获取原始值用于判断断线(防止缩放干扰)
var originalDia = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameter);
double originalW = originalDia.HasValue ? originalDia.Value : W;
double ox = ctx.Center.X - W / 2.0;
double oy = ctx.Center.Y - H / 2.0;
var filletRParam = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyShaftFilletRadiusMax);
double filletR = filletRParam.HasValue && filletRParam.Value > 0 ? filletRParam.Value : 0;
double maxR = Math.Min(W / 2.0, H / 2.0);
if (filletR > maxR) filletR = maxR;
// 判断是否需要断线
bool needBreakLines = originalW > 150;
const double lineSpacing = 3.5;
// 1. 绘制主体轮廓 (矩形 + 圆角) - 保持原来的白色边框
double xBreak = ox + W / 4.0;
// 1. 绘制主体轮廓 (矩形 + 圆角) - 保持原来的白色边框
if (needBreakLines)
{
DrawRectWithBreak(ctx, ox, oy, W, H, filletR, xBreak, lineSpacing);
}
else
{
DrawRectWithFillets(ctx, ox, oy, W, H, filletR, DrawingStyleManager.Role.OutlineBold);
}
// 2. 绘制左右两端的弧线(向外凸出)
// 弧高设为 H/5高度的1/5确保弧高小于半弦长
double arcHeight = H / 5.0;
DrawEndArcs(ctx, ox, oy, W, H, arcHeight);
// 3. 绘制中心线 (横向,在中间位置)
DrawHorizontalCenterLine(ctx, ctx.Center.Y, ox, ox + W, needBreakLines, xBreak, lineSpacing);
// 4. 绘制断线 (如果需要)
if (needBreakLines)
{
DrawBreakLines(ctx, ox, oy, W, H);
}
// 3. 尺寸标注
// 3.1 直径标注 (底部)
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameter) ?? W;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyDiameter);
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameterTolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameterTolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyDiameterTolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyDiameterTolMinus);
// 直径加上 %%c 符号
var dimText = "%%c" + FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameterPrime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += @"\X(%%c" + FeatureDrivenDrawer.FormatDimNumber(valPrime.Value) + ")";
}
double dimY = oy - 25;
double dimOriginY = oy + filletR;
FeatureDrivenDrawer.AddLinearDim(ctx, new Point3d(ox, dimOriginY, 0), new Point3d(ox + W, dimOriginY, 0), new Point3d(ctx.Center.X, dimY, 0), 0, dimText);
}
// 3.2 长度标注 (右侧)
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyLength) ?? H;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyLength);
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyLengthTolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyLengthTolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyLengthTolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyLengthTolMinus);
var dimText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyLengthPrime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += @"\X(" + FeatureDrivenDrawer.FormatDimNumber(valPrime.Value) + ")";
}
double dimX = ox + W + 20;
double dimOriginX = ox + W - filletR;
FeatureDrivenDrawer.AddLinearDim(ctx, new Point3d(dimOriginX, oy, 0), new Point3d(dimOriginX, oy + H, 0), new Point3d(dimX, ctx.Center.Y, 0), 90, dimText);
}
// 4. 硬度和标刻
var hardnessVal = bag.GetString(FeatureDrivenDrawer.KeyHardness);
if (!string.IsNullOrWhiteSpace(hardnessVal))
{
// 硬度放在底部中心位置
double xStart = ctx.Center.X;
double yStart = oy;
FeatureDrivenDrawer.DrawHardnessSymbol(ctx, xStart, yStart);
}
var markingText = bag.GetString(FeatureDrivenDrawer.KeyMarkingContent);
if (!string.IsNullOrWhiteSpace(markingText))
{
// 标刻引线指向顶部中心
double xTarget = ctx.Center.X;
double yTarget = oy + H;
FeatureDrivenDrawer.DrawSpecialHBLeaderToTop(ctx, xTarget, yTarget, markingText);
}
// 5. 零件轮廓 (Prime)
// 逻辑要求:零件参数也遵循 直径=宽度,长度=高度
var diaPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameterPrime);
var lenPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyLengthPrime);
if (diaPrime.HasValue && diaPrime.Value > 0 && lenPrime.HasValue && lenPrime.Value > 0)
{
double pW = diaPrime.Value; // Diameter -> Width
double pH = lenPrime.Value; // Length -> Height
double pOx = ctx.Center.X - pW / 2.0;
double pOy = ctx.Center.Y - pH / 2.0;
if (needBreakLines)
{
// 使用与锻件相同的断线X坐标和间距
// double xBreak = ox + W / 4.0; // variable is already declared in outer scope
DrawRectOutlineWithBreak(ctx, pOx, pOy, pW, pH, xBreak, lineSpacing, DrawingStyleManager.Role.PartContour);
}
else
{
DrawRectOutline(ctx, pOx, pOy, pW, pH, DrawingStyleManager.Role.PartContour);
}
}
}
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);
}
/// <summary>
/// 绘制左右两端的弧线(向外凸出)
/// 使用Polyline的bulge凸度值绘制确保端点精确对齐
/// </summary>
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
// 计算凸度 bulge
// bulge = tan(theta/4),其中 theta 是圆弧对应的圆心角
// 或者使用 bulge = sagitta / (chordLength / 2) 的近似公式
// 更精确的公式bulge = 2 * sagitta / chordLength当弧线较小时
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
}
}
private static void DrawHorizontalCenterLine(FeatureDrivenDrawer.DrawingContext ctx, double centerY, double xLeft, double xRight, bool hasBreak = false, double xBreak = 0, double breakWidth = 0)
{
const double extend = 5.0;
if (!hasBreak)
{
var line = new Line(new Point3d(xLeft - extend, centerY, 0), new Point3d(xRight + extend, centerY, 0));
ctx.Style?.Apply(line, DrawingStyleManager.Role.Centerline);
ctx.Btr.AppendEntity(line);
ctx.Tr.AddNewlyCreatedDBObject(line, true);
}
else
{
// Left segment
var line1 = new Line(new Point3d(xLeft - extend, centerY, 0), new Point3d(xBreak, centerY, 0));
ctx.Style?.Apply(line1, DrawingStyleManager.Role.Centerline);
ctx.Btr.AppendEntity(line1);
ctx.Tr.AddNewlyCreatedDBObject(line1, true);
// Right segment
var line2 = new Line(new Point3d(xBreak + breakWidth, centerY, 0), new Point3d(xRight + extend, centerY, 0));
ctx.Style?.Apply(line2, DrawingStyleManager.Role.Centerline);
ctx.Btr.AppendEntity(line2);
ctx.Tr.AddNewlyCreatedDBObject(line2, true);
}
}
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("Diameter") || k.Contains("Length") || k.Contains("Radius") || k.Contains("Prime") || k.Contains("ShaftFillet"))
{
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;
}
/// <summary>
/// 绘制断线(使用 BreakLine 样式:白色 PHANTOM 双点划线)
/// </summary>
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);
}
/// <summary>
/// 绘制带断口的矩形轮廓(在断线位置打断上下横线)
/// </summary>
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);
}
/// <summary>
/// 绘制带断口的零件轮廓(在断线位置打断上下横线)
/// 支持自定义 Role (通常为 PartContour)
/// </summary>
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]
// 需要判断 xBreak 是否在当前矩形范围内
// 通常零件在锻件内部,且断线位置也会穿过零件
// 我们假设断线切断了矩形(如果 xBreak < x 或 xBreak > x+w应该做特殊处理这里暂不考虑极端情况
// 左段
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);
}
}
}
}