CadParamPluging/Cad/BlockRawFreeForgeRoundHeadDrawer.cs

919 lines
42 KiB
C#
Raw Permalink 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 BlockRawFreeForgeRoundHeadDrawer
{
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)
};
DrawBlockRawFreeForgeRoundHeadCore(context);
}
private static void DrawBlockRawFreeForgeRoundHeadCore(FeatureDrivenDrawer.DrawingContext ctx)
{
var bag = ctx.Bag;
// BoxSize1 (Width - 总长度)
// BoxSize2 (Height - 高度/直径)
var width = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize1);
var height = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize2);
if (!width.HasValue || width.Value <= 0 || !height.HasValue || height.Value <= 0)
{
return;
}
double H = height.Value;
double W = width.Value;
// 外轮廓圆弧:高度固定为 H/5
// 依据用户新需求 (2026-01-29): 黄色部分(圆弧高)是粉色部分(总高H)的1/5
double arcHeight = H / 5.0;
// 视觉比例:总宽度映射
double visualTotalW = H * 3.0; // 保持视觉宽高比约 3:1
// 绘图坐标计算 (保持居中)
double ox = ctx.Center.X - visualTotalW / 2.0; // 左边界 (圆弧最左端)
double oy = ctx.Center.Y - H / 2.0; // 底边
// 内框边界(从左圆弧弦线到右圆弧弦线)
// 注意ox 是圆弧顶点xInnerLeft 应该是弦线位置
double xInnerLeft = ox + arcHeight;
double xInnerRight = ox + visualTotalW - arcHeight;
double innerWidth = xInnerRight - xInnerLeft;
// 获取圆头处圆角半径 (BoxRoundHeadFilletRadiusMax) - 用于外侧圆角
// 依据用户需求:外侧圆角由“圆头处圆角半径”控制
var headFilletParam = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxRoundHeadFilletRadiusMax);
double headFilletR = headFilletParam.HasValue && headFilletParam.Value > 0
? headFilletParam.Value
: 0;
// 获取内框圆角参数:优先取 UnspecifiedFilletRadiusMax如果没有则取 BoxFilletRadiusMax - 用于内部剖面
var innerFilletParam = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyUnspecifiedFilletRadiusMax);
if (!innerFilletParam.HasValue || innerFilletParam.Value <= 0)
{
innerFilletParam = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxFilletRadiusMax);
}
double sectionFilletR = innerFilletParam.HasValue && innerFilletParam.Value > 0
? innerFilletParam.Value
: 0;
// 2. 绘制分段式内框(左、中、右三段)以支持中间剖面区域的独立圆角
// 中间区域(剖面)作为主体,如果设置了圆角,四个角都应为圆角
// 计算视觉上的剖面宽度
// 依据用户需求尺寸3 (BoxSize3) 对应剖面的宽
var size3 = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize3);
double visualSectionWidth;
if (size3.HasValue && size3.Value > 0)
{
// 按比例映射VisualW / PhysicalW
double scale = visualTotalW / W;
visualSectionWidth = size3.Value * scale;
// 限制最大宽度,防止出错
if (visualSectionWidth > innerWidth * 0.95)
{
visualSectionWidth = innerWidth * 0.95;
}
}
else
{
// 降级策略
visualSectionWidth = innerWidth / 3.0;
}
// 居中布置剖面
double sectionOffset = (innerWidth - visualSectionWidth) / 2.0;
double xSectionLeft = xInnerLeft + sectionOffset;
double xSectionRight = xSectionLeft + visualSectionWidth;
// 绘制中间剖面框(带圆角)
// 使用 sectionFilletR
DrawBoxSectionContourWithFillet(ctx, xSectionLeft, xSectionRight, oy, H, sectionFilletR);
// Calculate effective head fillet R (clamped by side frame width)
double sideFrameWidth = xSectionLeft - xInnerLeft;
double maxR = Math.Min(sideFrameWidth * 0.5, H * 0.5);
double effectiveHeadR = Math.Min(headFilletR, maxR);
double Rm = (H * H) / (8.0 * arcHeight) + arcHeight / 2.0;
double D_tangent = (Rm >= effectiveHeadR) ? Math.Sqrt(Math.Max(0, (Rm - effectiveHeadR) * (Rm - effectiveHeadR) - (H / 2.0 - effectiveHeadR) * (H / 2.0 - effectiveHeadR))) : (Rm - arcHeight);
double xf_left = effectiveHeadR > 0 ? (xInnerLeft + Rm - arcHeight) - D_tangent : xInnerLeft;
double xf_right = effectiveHeadR > 0 ? (xInnerRight - Rm + arcHeight) + D_tangent : xInnerRight;
double xc_left = xInnerLeft + Rm - arcHeight;
double fx_L_tang = effectiveHeadR > 0 ? xc_left + (Rm / (Rm - effectiveHeadR)) * (xf_left - xc_left) : xInnerLeft;
double fy_L_tangBot = effectiveHeadR > 0 ? (oy + H / 2.0) + (Rm / (Rm - effectiveHeadR)) * ((oy + effectiveHeadR) - (oy + H / 2.0)) : oy;
double xc_right = xInnerRight - Rm + arcHeight;
double fx_R_tang = effectiveHeadR > 0 ? xc_right + (Rm / (Rm - effectiveHeadR)) * (xf_right - xc_right) : xInnerRight;
double fy_R_tangBot = effectiveHeadR > 0 ? (oy + H / 2.0) + (Rm / (Rm - effectiveHeadR)) * ((oy + effectiveHeadR) - (oy + H / 2.0)) : oy;
// 绘制左侧框线(只画横向连接线)
DrawBoxSideFrame(ctx, xf_left, xSectionLeft + sectionFilletR, oy, H, 0, isLeft: true);
// 绘制右侧框线(只画横向连接线)
DrawBoxSideFrame(ctx, xSectionRight - sectionFilletR, xf_right, oy, H, 0, isLeft: false);
// 1. 绘制完整锻件外轮廓(方体有圆头 - 白色,大圆弧及外侧平滑过渡圆角)
DrawBlockRoundHeadOutline(ctx, ox, oy, visualTotalW, H, arcHeight, effectiveHeadR, xf_left, xf_right);
// 绘制圆角的斜向标注如果存在圆角4-R<=*
if (effectiveHeadR > 0)
{
// 左上角
double yTop = oy + H;
double cxLeft = xf_left;
double cyLeft = yTop - effectiveHeadR;
DrawHeadFilletRadiusLeader(ctx, cxLeft, cyLeft, effectiveHeadR, true);
// 根据需求,左右都标注了的话,只保留一个(左上角),去除右上角标注
// 右上角
// double cxRight = xInnerRight - effectiveHeadR;
// DrawHeadFilletRadiusLeader(ctx, cxRight, cyLeft, effectiveHeadR, false);
}
// 3. 剖面填充 - 只在中间区域
// 使用 sectionFilletR
if (sectionFilletR > 0.01)
{
DrawRingSectionHatchWithFillet(ctx, xSectionLeft, xSectionRight, oy, H, sectionFilletR);
}
else
{
DrawBlockSectionHatch(ctx, xSectionLeft, xSectionRight, oy, H);
}
// 5. 零件轮廓框(黄色双点划线矩形 - 在内框内,与锻件有一定间距)
var widthPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize1Prime);
var heightPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize2Prime);
if (widthPrime.HasValue && widthPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0)
{
double partH = heightPrime.Value;
double partW = widthPrime.Value;
// 计算零件在视觉上的宽度比例
double partWidthRatio = partW / W;
double visualPartW = innerWidth * partWidthRatio;
if (visualPartW > innerWidth) visualPartW = innerWidth * 0.9;
// 零件在锻件内居中
double partOffsetX = (innerWidth - visualPartW) / 2.0;
double partOffsetY = (H - partH) / 2.0;
double xPartLeft = xInnerLeft + partOffsetX;
double yPartBottom = oy + partOffsetY;
DrawBlockPartContour(ctx, xPartLeft, yPartBottom, visualPartW, partH);
}
// 6. 宽度标注 (BoxSize1) - 位于底部
// 标注从锻件最左端到最右端 (BoxSize1 对应 锻件总宽)
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize1) ?? W;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize1);
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize1TolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize1TolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize1TolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize1TolMinus);
var dimText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
// 添加零件尺寸 (Prime) 到下方,用括号包裹
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize1Prime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += $"\\X({FeatureDrivenDrawer.FormatDimNumber(valPrime.Value, null)})";
}
// 修正:标注需涵盖内框宽度 (矩形部分)
// 修正:引线起点改为内框边界 (xInnerLeft/Right) 和高度底部上移圆角半径,确保闭合到白色线框
// 修正:引线起点严格匹配倒角与圆弧相切处的极限点坐标 (fx_L_tang, fy_L_tangBot)
AddLinearDim(
ctx,
new Point3d(fx_L_tang, fy_L_tangBot, 0),
new Point3d(fx_R_tang, fy_R_tangBot, 0),
new Point3d((fx_L_tang + fx_R_tang) / 2, oy - 25, 0),
0,
dimText);
}
// 7. 高度标注 (BoxSize2) - 位于右侧
// 标注从锻件顶部到底部
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize2) ?? H;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize2);
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize2TolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize2TolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize2TolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize2TolMinus);
var dimText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
// 添加零件尺寸 (Prime) 到下方
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize2Prime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += $"\\X({FeatureDrivenDrawer.FormatDimNumber(valPrime.Value, null)})";
}
// 标注从圆弧最外侧开始(避免与圆弧轮廓线重叠)
double xOuterRight = ox + visualTotalW;
// 修正:标注界线起点应从圆弧顶端开始,往内缩进一个圆弧高度 arcHeight + headFilletR定位在弦线上
double xDimOrigin = xOuterRight - (arcHeight + headFilletR);
AddLinearDim(
ctx,
new Point3d(xDimOrigin, oy, 0),
new Point3d(xDimOrigin, oy + H, 0),
new Point3d(xOuterRight + 20, oy + H / 2, 0),
90,
dimText);
}
// 8. 中间矩形宽度标注 (BoxSize3) - 位于上方
// 对应剖面区域宽度
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize3) ?? 0;
var str = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize3);
// 只有当有值时才标注
if (val > 0)
{
var tolPlus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize3TolPlus);
var tolMinus = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize3TolMinus);
var tolPlusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize3TolPlus);
var tolMinusStr = ctx.OriginalBag?.GetString(FeatureDrivenDrawer.KeyBoxSize3TolMinus);
var dimText = FeatureDrivenDrawer.BuildDimensionText(FeatureDrivenDrawer.FormatDimNumber(val, str), tolPlus, tolMinus, tolPlusStr, tolMinusStr);
// 添加零件尺寸 (Prime) 到下方
var valPrime = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxSize3Prime);
if (valPrime.HasValue && valPrime.Value > 0)
{
dimText += $"\\X({FeatureDrivenDrawer.FormatDimNumber(valPrime.Value, null)})";
}
// 修正:引线向下延伸 sectionFilletR以接触直边
// sectionFilletR 是剖面处的圆角半径
double dimYStart = oy + H - sectionFilletR;
AddLinearDim(
ctx,
new Point3d(xSectionLeft, dimYStart, 0),
new Point3d(xSectionRight, dimYStart, 0),
new Point3d((xSectionLeft + xSectionRight) / 2, oy + H + 15, 0),
0,
dimText);
}
}
// 9. 硬度符号 - 从剖面右侧引出
var hardnessVal = bag.GetString(FeatureDrivenDrawer.KeyHardness);
if (!string.IsNullOrWhiteSpace(hardnessVal) && hardnessVal != "空")
{
double xStart = xSectionRight;
double yStart = oy + H * 0.25;
FeatureDrivenDrawer.DrawHardnessSymbol(ctx, xStart, yStart, hardnessVal);
}
// 10. 标刻内容引线 - 从剖面左侧引出
var markingText = bag.GetString(FeatureDrivenDrawer.KeyMarkingContent);
if (!string.IsNullOrWhiteSpace(markingText))
{
double xTarget = xSectionLeft;
double yTarget = oy + H * 0.75;
DrawSpecialHBLeaderToTop(ctx, xTarget, yTarget, markingText);
}
}
private static void DrawBlockRoundHeadOutline(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double totalWidth, double height, double arcHeight, double innerFilletR, double xf_left, double xf_right)
{
try
{
double H = height;
double r = innerFilletR;
double w = arcHeight;
if (w < 0.1) return;
double Rm = (H * H) / (8.0 * w) + w / 2.0;
// Left side
double xInnerLeft = ox + w;
double xc_left = xInnerLeft + Rm - w;
Point2d C_m_L = new Point2d(xc_left, oy + H / 2.0);
Point2d C_fTop_L = new Point2d(xf_left, oy + H - r);
Point2d C_fBot_L = new Point2d(xf_left, oy + r);
double fx_L_tangTop = r > 0 ? C_m_L.X + (Rm / (Rm - r)) * (C_fTop_L.X - C_m_L.X) : xInnerLeft;
double fy_L_tangTop = r > 0 ? C_m_L.Y + (Rm / (Rm - r)) * (C_fTop_L.Y - C_m_L.Y) : oy + H;
double fx_L_tangBot = r > 0 ? C_m_L.X + (Rm / (Rm - r)) * (C_fBot_L.X - C_m_L.X) : xInnerLeft;
double fy_L_tangBot = r > 0 ? C_m_L.Y + (Rm / (Rm - r)) * (C_fBot_L.Y - C_m_L.Y) : oy;
var leftPoly = new Polyline();
if (r > 0.01)
{
double angTop1 = Math.PI / 2.0;
double angTop2 = Math.Atan2(fy_L_tangTop - C_fTop_L.Y, fx_L_tangTop - C_fTop_L.X);
double diffTop = angTop2 - angTop1;
while (diffTop < 0) diffTop += Math.PI * 2;
while (diffTop >= Math.PI * 2) diffTop -= Math.PI * 2;
double bulgeTop = Math.Tan(diffTop / 4.0);
double angM1 = Math.Atan2(fy_L_tangTop - C_m_L.Y, fx_L_tangTop - C_m_L.X);
double angM2 = Math.Atan2(fy_L_tangBot - C_m_L.Y, fx_L_tangBot - C_m_L.X);
double diffM = angM2 - angM1;
while (diffM < 0) diffM += Math.PI * 2;
while (diffM >= Math.PI * 2) diffM -= Math.PI * 2;
double bulgeM = Math.Tan(diffM / 4.0);
double angBot1 = Math.Atan2(fy_L_tangBot - C_fBot_L.Y, fx_L_tangBot - C_fBot_L.X);
double angBot2 = -Math.PI / 2.0;
double diffBot = angBot2 - angBot1;
while (diffBot < 0) diffBot += Math.PI * 2;
while (diffBot >= Math.PI * 2) diffBot -= Math.PI * 2;
double bulgeBot = Math.Tan(diffBot / 4.0);
leftPoly.AddVertexAt(0, new Point2d(xf_left, oy + H), bulgeTop, 0, 0);
leftPoly.AddVertexAt(1, new Point2d(fx_L_tangTop, fy_L_tangTop), bulgeM, 0, 0);
leftPoly.AddVertexAt(2, new Point2d(fx_L_tangBot, fy_L_tangBot), bulgeBot, 0, 0);
leftPoly.AddVertexAt(3, new Point2d(xf_left, oy), 0, 0, 0);
}
else
{
double angM1 = Math.Atan2(oy + H - C_m_L.Y, xInnerLeft - C_m_L.X);
double angM2 = Math.Atan2(oy - C_m_L.Y, xInnerLeft - C_m_L.X);
double diffM = angM2 - angM1;
while (diffM < 0) diffM += Math.PI * 2;
while (diffM >= Math.PI * 2) diffM -= Math.PI * 2;
double bulgeM = Math.Tan(diffM / 4.0);
leftPoly.AddVertexAt(0, new Point2d(xInnerLeft, oy + H), bulgeM, 0, 0);
leftPoly.AddVertexAt(1, new Point2d(xInnerLeft, oy), 0, 0, 0);
}
ctx.Style?.Apply(leftPoly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(leftPoly);
ctx.Tr.AddNewlyCreatedDBObject(leftPoly, true);
var leftClosureLine = new Line(new Point3d(fx_L_tangTop, fy_L_tangTop, 0), new Point3d(fx_L_tangBot, fy_L_tangBot, 0));
ctx.Style?.Apply(leftClosureLine, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(leftClosureLine);
ctx.Tr.AddNewlyCreatedDBObject(leftClosureLine, true);
// Right side
double xInnerRight = ox + totalWidth - w;
double xc_right = xInnerRight - Rm + w;
Point2d C_m_R = new Point2d(xc_right, oy + H / 2.0);
Point2d C_fTop_R = new Point2d(xf_right, oy + H - r);
Point2d C_fBot_R = new Point2d(xf_right, oy + r);
double fx_R_tangTop = r > 0 ? C_m_R.X + (Rm / (Rm - r)) * (C_fTop_R.X - C_m_R.X) : xInnerRight;
double fy_R_tangTop = r > 0 ? C_m_R.Y + (Rm / (Rm - r)) * (C_fTop_R.Y - C_m_R.Y) : oy + H;
double fx_R_tangBot = r > 0 ? C_m_R.X + (Rm / (Rm - r)) * (C_fBot_R.X - C_m_R.X) : xInnerRight;
double fy_R_tangBot = r > 0 ? C_m_R.Y + (Rm / (Rm - r)) * (C_fBot_R.Y - C_m_R.Y) : oy;
var rightPoly = new Polyline();
if (r > 0.01)
{
double angBot1 = -Math.PI / 2.0;
double angBot2 = Math.Atan2(fy_R_tangBot - C_fBot_R.Y, fx_R_tangBot - C_fBot_R.X);
double diffBot = angBot2 - angBot1;
while (diffBot < 0) diffBot += Math.PI * 2;
while (diffBot >= Math.PI * 2) diffBot -= Math.PI * 2;
double bulgeBot = Math.Tan(diffBot / 4.0);
double angM1 = Math.Atan2(fy_R_tangBot - C_m_R.Y, fx_R_tangBot - C_m_R.X);
double angM2 = Math.Atan2(fy_R_tangTop - C_m_R.Y, fx_R_tangTop - C_m_R.X);
double diffM = angM2 - angM1;
while (diffM < 0) diffM += Math.PI * 2;
while (diffM >= Math.PI * 2) diffM -= Math.PI * 2;
double bulgeM = Math.Tan(diffM / 4.0);
double angTop1 = Math.Atan2(fy_R_tangTop - C_fTop_R.Y, fx_R_tangTop - C_fTop_R.X);
double angTop2 = Math.PI / 2.0;
double diffTop = angTop2 - angTop1;
while (diffTop < 0) diffTop += Math.PI * 2;
while (diffTop >= Math.PI * 2) diffTop -= Math.PI * 2;
double bulgeTop = Math.Tan(diffTop / 4.0);
rightPoly.AddVertexAt(0, new Point2d(xf_right, oy), bulgeBot, 0, 0);
rightPoly.AddVertexAt(1, new Point2d(fx_R_tangBot, fy_R_tangBot), bulgeM, 0, 0);
rightPoly.AddVertexAt(2, new Point2d(fx_R_tangTop, fy_R_tangTop), bulgeTop, 0, 0);
rightPoly.AddVertexAt(3, new Point2d(xf_right, oy + H), 0, 0, 0);
}
else
{
double angM1 = Math.Atan2(oy - C_m_R.Y, xInnerRight - C_m_R.X);
double angM2 = Math.Atan2(oy + H - C_m_R.Y, xInnerRight - C_m_R.X);
double diffM = angM2 - angM1;
while (diffM < 0) diffM += Math.PI * 2;
while (diffM >= Math.PI * 2) diffM -= Math.PI * 2;
double bulgeM = Math.Tan(diffM / 4.0);
rightPoly.AddVertexAt(0, new Point2d(xInnerRight, oy), bulgeM, 0, 0);
rightPoly.AddVertexAt(1, new Point2d(xInnerRight, oy + H), 0, 0, 0);
}
ctx.Style?.Apply(rightPoly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(rightPoly);
ctx.Tr.AddNewlyCreatedDBObject(rightPoly, true);
var rightClosureLine = new Line(new Point3d(fx_R_tangTop, fy_R_tangTop, 0), new Point3d(fx_R_tangBot, fy_R_tangBot, 0));
ctx.Style?.Apply(rightClosureLine, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(rightClosureLine);
ctx.Tr.AddNewlyCreatedDBObject(rightClosureLine, true);
}
catch { }
}
private static void DrawBoxSectionContourWithFillet(FeatureDrivenDrawer.DrawingContext ctx, double xLeft, double xRight, double yBottom, double height, double filletR)
{
var yTop = yBottom + height;
var width = xRight - xLeft;
var maxR = Math.Min(width * 0.5, height * 0.5);
var r = Math.Min(filletR, maxR);
if (r <= 0.01)
{
var poly = new Polyline();
poly.AddVertexAt(0, new Point2d(xLeft, yBottom), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(xRight, yBottom), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(xRight, yTop), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(xLeft, yTop), 0, 0, 0);
poly.Closed = true;
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(poly);
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
return;
}
var bulge = Math.Tan(Math.PI / 8.0);
var polyFillet = new Polyline();
polyFillet.AddVertexAt(0, new Point2d(xLeft + r, yBottom), 0, 0, 0);
polyFillet.AddVertexAt(1, new Point2d(xRight - r, yBottom), bulge, 0, 0);
polyFillet.AddVertexAt(2, new Point2d(xRight, yBottom + r), 0, 0, 0);
polyFillet.AddVertexAt(3, new Point2d(xRight, yTop - r), bulge, 0, 0);
polyFillet.AddVertexAt(4, new Point2d(xRight - r, yTop), 0, 0, 0);
polyFillet.AddVertexAt(5, new Point2d(xLeft + r, yTop), bulge, 0, 0);
polyFillet.AddVertexAt(6, new Point2d(xLeft, yTop - r), 0, 0, 0);
polyFillet.AddVertexAt(7, new Point2d(xLeft, yBottom + r), bulge, 0, 0);
polyFillet.Closed = true;
ctx.Style?.Apply(polyFillet, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(polyFillet);
ctx.Tr.AddNewlyCreatedDBObject(polyFillet, true);
}
private static void DrawBoxSideFrame(FeatureDrivenDrawer.DrawingContext ctx, double xStart, double xEnd, double yBottom, double height, double filletR, bool isLeft)
{
var yTop = yBottom + height;
var width = Math.Abs(xEnd - xStart);
if (width < 0.1) return;
var topPoly = new Polyline();
topPoly.AddVertexAt(0, new Point2d(xStart, yTop), 0, 0, 0);
topPoly.AddVertexAt(1, new Point2d(xEnd, yTop), 0, 0, 0);
ctx.Style?.Apply(topPoly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(topPoly);
ctx.Tr.AddNewlyCreatedDBObject(topPoly, true);
var botPoly = new Polyline();
botPoly.AddVertexAt(0, new Point2d(xStart, yBottom), 0, 0, 0);
botPoly.AddVertexAt(1, new Point2d(xEnd, yBottom), 0, 0, 0);
ctx.Style?.Apply(botPoly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(botPoly);
ctx.Tr.AddNewlyCreatedDBObject(botPoly, true);
}
private static void DrawRingSectionHatchWithFillet(FeatureDrivenDrawer.DrawingContext ctx, double xInnerRight, double xOuterRight, double yBottom, double height, double filletR)
{
if (xOuterRight <= xInnerRight)
{
return;
}
var availableWidth = xOuterRight - xInnerRight;
var maxR = Math.Min(availableWidth * 0.5, height * 0.5);
var r = Math.Min(filletR, maxR);
if (r <= 0.01)
{
DrawBlockSectionHatch(ctx, xInnerRight, xOuterRight, yBottom, height);
return;
}
try
{
var yTop = yBottom + height;
var bulge = Math.Tan(Math.PI / 8.0);
var boundary = new Polyline();
boundary.AddVertexAt(0, new Point2d(xInnerRight + r, yBottom), 0, 0, 0);
boundary.AddVertexAt(1, new Point2d(xOuterRight - r, yBottom), bulge, 0, 0);
boundary.AddVertexAt(2, new Point2d(xOuterRight, yBottom + r), 0, 0, 0);
boundary.AddVertexAt(3, new Point2d(xOuterRight, yTop - r), bulge, 0, 0);
boundary.AddVertexAt(4, new Point2d(xOuterRight - r, yTop), 0, 0, 0);
boundary.AddVertexAt(5, new Point2d(xInnerRight + r, yTop), bulge, 0, 0);
boundary.AddVertexAt(6, new Point2d(xInnerRight, yTop - r), 0, 0, 0);
boundary.AddVertexAt(7, new Point2d(xInnerRight, yBottom + r), bulge, 0, 0);
boundary.Closed = true;
ctx.Btr.AppendEntity(boundary);
ctx.Tr.AddNewlyCreatedDBObject(boundary, true);
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);
try
{
boundary.Erase(true);
}
catch { }
}
catch { }
}
private static void DrawBlockSectionHatch(FeatureDrivenDrawer.DrawingContext ctx, double xLeft, double xRight, double yBottom, double height)
{
if (xRight <= xLeft)
{
return;
}
try
{
var boundary = new Polyline();
boundary.AddVertexAt(0, new Point2d(xLeft, yBottom), 0, 0, 0);
boundary.AddVertexAt(1, new Point2d(xRight, yBottom), 0, 0, 0);
boundary.AddVertexAt(2, new Point2d(xRight, yBottom + height), 0, 0, 0);
boundary.AddVertexAt(3, new Point2d(xLeft, yBottom + height), 0, 0, 0);
boundary.Closed = true;
ctx.Btr.AppendEntity(boundary);
ctx.Tr.AddNewlyCreatedDBObject(boundary, true);
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);
try
{
boundary.Erase(true);
}
catch { }
}
catch { }
}
private static void DrawBlockPartContour(FeatureDrivenDrawer.DrawingContext ctx, double x, double y, double width, double height)
{
try
{
var poly = new Polyline();
poly.AddVertexAt(0, new Point2d(x, y), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(x + width, y), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(x + width, y + height), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(x, y + height), 0, 0, 0);
poly.Closed = true;
ctx.Style?.Apply(poly, DrawingStyleManager.Role.PartContour);
ctx.Btr.AppendEntity(poly);
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
}
catch { }
}
private static void DrawHeadFilletRadiusLeader(FeatureDrivenDrawer.DrawingContext ctx, double cx, double cy, double r, bool isLeftSection)
{
try
{
var val = ctx.OriginalBag?.GetDoubleOrNull(FeatureDrivenDrawer.KeyBoxRoundHeadFilletRadiusMax);
if (!val.HasValue || val.Value <= 0) return;
// 左上角向左上(135),右上角向右上(45)
double angleDeg = isLeftSection ? 135 : 45;
double angleRad = angleDeg * Math.PI / 180.0;
// 起点(外圆角,引线从圆弧表面引出)
double px = cx + r * Math.Cos(angleRad);
double py = cy + r * Math.Sin(angleRad);
// 终点
double ex = px + 25 * Math.Cos(angleRad);
double ey = py + 25 * Math.Sin(angleRad);
// 画直线
var line = new Line(new Point3d(px, py, 0), new Point3d(ex, ey, 0));
ctx.Style?.Apply(line, DrawingStyleManager.Role.Dimension);
line.ColorIndex = 4; // Cyan
ctx.Btr.AppendEntity(line);
ctx.Tr.AddNewlyCreatedDBObject(line, true);
// 绘制实心箭头
double arrowLength = 5.0; // 箭头长度,加长
double arrowWidth = 1.5; // 箭头宽度,加宽
double baseX = px + arrowLength * Math.Cos(angleRad);
double baseY = py + arrowLength * Math.Sin(angleRad);
double perpAngle = angleRad + Math.PI / 2;
double p1X = baseX + (arrowWidth / 2) * Math.Cos(perpAngle);
double p1Y = baseY + (arrowWidth / 2) * Math.Sin(perpAngle);
double p2X = baseX - (arrowWidth / 2) * Math.Cos(perpAngle);
double p2Y = baseY - (arrowWidth / 2) * Math.Sin(perpAngle);
var arrow = new Solid(new Point3d(px, py, 0), new Point3d(p1X, p1Y, 0), new Point3d(p2X, p2Y, 0));
arrow.ColorIndex = 4;
ctx.Btr.AppendEntity(arrow);
ctx.Tr.AddNewlyCreatedDBObject(arrow, true);
// 文字(与线对齐)
var textStr = $"4-R\\U+2264{val.Value}";
var text = new DBText();
text.TextString = textStr;
text.Height = 3.5;
text.ColorIndex = 4; // Cyan
// 倾斜文字角度
double textRotation = angleRad;
if (isLeftSection)
{
// 左侧角度是 135文字应该 -45度(减去180)保证从左向右读
textRotation = angleRad - Math.PI;
}
text.Rotation = textRotation;
// 对齐设置
text.HorizontalMode = TextHorizontalMode.TextCenter;
text.VerticalMode = TextVerticalMode.TextBottom;
// 计算文字放置点,紧贴在线端上方
double offsetX = 2.0 * Math.Cos(textRotation + Math.PI / 2);
double offsetY = 2.0 * Math.Sin(textRotation + Math.PI / 2);
var tp = new Point3d(ex + offsetX, ey + offsetY, 0);
text.AlignmentPoint = tp;
text.Position = tp;
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
text.ColorIndex = 4;
ctx.Btr.AppendEntity(text);
ctx.Tr.AddNewlyCreatedDBObject(text, true);
}
catch
{
// ignore
}
}
private static void DrawSpecialHBLeaderToTop(FeatureDrivenDrawer.DrawingContext ctx, double xTarget, double yTarget, string textContent)
{
try
{
var p1 = new Point3d(xTarget, yTarget, 0);
var p2 = new Point3d(xTarget - 10, yTarget + 10, 0);
double textLen = (string.IsNullOrEmpty(textContent) ? 10 : textContent.Length) * 2.5;
if (textLen < 20) textLen = 20;
var p3 = new Point3d(p2.X - textLen, p2.Y, 0);
var leader = new Leader();
leader.SetDatabaseDefaults();
leader.AppendVertex(p1);
leader.AppendVertex(p2);
leader.AppendVertex(p3);
leader.HasArrowHead = true;
leader.ColorIndex = 7; // 白色
leader.Layer = "0";
ctx.Btr.AppendEntity(leader);
ctx.Tr.AddNewlyCreatedDBObject(leader, true);
var text = new DBText();
text.TextString = textContent;
text.Height = 3.5;
text.ColorIndex = 7;
text.Layer = "0";
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 { }
}
private static void AddLinearDim(FeatureDrivenDrawer.DrawingContext ctx, Point3d pt1, Point3d pt2, Point3d dimLinePt,
double rotationDeg, string textOverride, Action<Dimension, FeatureDrivenDrawer.DrawingContext> 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", 2.5);
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;
}
}
}