feat: 新增 BlockRawFreeForgeRoundHeadDrawer 类,实现自由锻圆头毛坯的参数化绘图功能。

This commit is contained in:
sladro 2026-02-28 11:07:21 +08:00
parent ad9968f622
commit ad76f1bb32

View File

@ -135,34 +135,40 @@ namespace CadParamPluging.Cad
// 使用 sectionFilletR // 使用 sectionFilletR
DrawBoxSectionContourWithFillet(ctx, xSectionLeft, xSectionRight, oy, H, sectionFilletR); DrawBoxSectionContourWithFillet(ctx, xSectionLeft, xSectionRight, oy, H, sectionFilletR);
// Calculate effective head fillet R (clamped by side frame width) to ensure Outline matches SideFrame // Calculate effective head fillet R (clamped by side frame width)
double sideFrameWidth = xSectionLeft - xInnerLeft; double sideFrameWidth = xSectionLeft - xInnerLeft;
double maxR = Math.Min(sideFrameWidth * 0.5, H * 0.5); double maxR = Math.Min(sideFrameWidth * 0.5, H * 0.5);
double effectiveHeadR = Math.Min(headFilletR, maxR); double effectiveHeadR = Math.Min(headFilletR, maxR);
// 绘制左侧框线(连接左端圆弧和中间剖面框) double Rm = (H * H) / (8.0 * arcHeight) + arcHeight / 2.0;
// 左端: xInnerLeft (需处理左上下角的圆角 - 使用 headFilletR) double D_tangent = (Rm >= effectiveHeadR) ? Math.Sqrt(Math.Max(0, (Rm - effectiveHeadR) * (Rm - effectiveHeadR) - (H / 2.0 - effectiveHeadR) * (H / 2.0 - effectiveHeadR))) : (Rm - arcHeight);
// 右端: xSectionLeft (连接到中间框的直边)
// Note: Extend horizontally by sectionFilletR to achieve "Horizontal Closure" with the section fillet double xf_left = effectiveHeadR > 0 ? (xInnerLeft + Rm - arcHeight) - D_tangent : xInnerLeft;
DrawBoxSideFrame(ctx, xInnerLeft, xSectionLeft + sectionFilletR, oy, H, headFilletR, isLeft: true); double xf_right = effectiveHeadR > 0 ? (xInnerRight - Rm + arcHeight) + D_tangent : xInnerRight;
// 绘制右侧框线 double xc_left = xInnerLeft + Rm - arcHeight;
// 左端: xSectionRight (连接到中间框的直边) double fx_L_tang = effectiveHeadR > 0 ? xc_left + (Rm / (Rm - effectiveHeadR)) * (xf_left - xc_left) : xInnerLeft;
// 右端: xInnerRight (需处理右上下角的圆角 - 使用 headFilletR) double fy_L_tangBot = effectiveHeadR > 0 ? (oy + H / 2.0) + (Rm / (Rm - effectiveHeadR)) * ((oy + effectiveHeadR) - (oy + H / 2.0)) : oy;
// Note: Extend horizontally inwards by sectionFilletR
DrawBoxSideFrame(ctx, xSectionRight - sectionFilletR, xInnerRight, oy, H, headFilletR, isLeft: false);
// 1. 绘制完整锻件外轮廓(方体有圆头 - 白色,大圆弧) double xc_right = xInnerRight - Rm + arcHeight;
// 修正:圆弧弦线需向内缩进 effectiveHeadR (Clamped),以与锻件外侧圆角起点对齐 double fx_R_tang = effectiveHeadR > 0 ? xc_right + (Rm / (Rm - effectiveHeadR)) * (xf_right - xc_right) : xInnerRight;
// This ensures the Big Arc starts curving exactly where the Side Frame vertical edge ends. double fy_R_tangBot = effectiveHeadR > 0 ? (oy + H / 2.0) + (Rm / (Rm - effectiveHeadR)) * ((oy + effectiveHeadR) - (oy + H / 2.0)) : oy;
DrawBlockRoundHeadOutline(ctx, ox, oy, visualTotalW, H, arcHeight, effectiveHeadR);
// 绘制左侧框线(只画横向连接线)
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<=* // 绘制圆角的斜向标注如果存在圆角4-R<=*
if (effectiveHeadR > 0) if (effectiveHeadR > 0)
{ {
// 左上角 // 左上角
double yTop = oy + H; double yTop = oy + H;
double cxLeft = xInnerLeft + effectiveHeadR; double cxLeft = xf_left;
double cyLeft = yTop - effectiveHeadR; double cyLeft = yTop - effectiveHeadR;
DrawHeadFilletRadiusLeader(ctx, cxLeft, cyLeft, effectiveHeadR, true); DrawHeadFilletRadiusLeader(ctx, cxLeft, cyLeft, effectiveHeadR, true);
@ -228,13 +234,12 @@ namespace CadParamPluging.Cad
// 修正:标注需涵盖内框宽度 (矩形部分) // 修正:标注需涵盖内框宽度 (矩形部分)
// 修正:引线起点改为内框边界 (xInnerLeft/Right) 和高度底部上移圆角半径,确保闭合到白色线框 // 修正:引线起点改为内框边界 (xInnerLeft/Right) 和高度底部上移圆角半径,确保闭合到白色线框
// 使用 headFilletR 作为 Offset因为这是侧边框的倒角 // 修正:引线起点严格匹配倒角与圆弧相切处的极限点坐标 (fx_L_tang, fy_L_tangBot)
double dimOriginY = oy + headFilletR;
AddLinearDim( AddLinearDim(
ctx, ctx,
new Point3d(xInnerLeft, dimOriginY, 0), new Point3d(fx_L_tang, fy_L_tangBot, 0),
new Point3d(xInnerRight, dimOriginY, 0), new Point3d(fx_R_tang, fy_R_tangBot, 0),
new Point3d((xInnerLeft + xInnerRight) / 2, oy - 25, 0), new Point3d((fx_L_tang + fx_R_tang) / 2, oy - 25, 0),
0, 0,
dimText); dimText);
} }
@ -327,55 +332,146 @@ namespace CadParamPluging.Cad
} }
} }
private static void DrawBlockRoundHeadOutline(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double totalWidth, double height, double arcHeight, double innerFilletR) 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 try
{ {
double H = height; double H = height;
double r = innerFilletR; double r = innerFilletR;
double w = arcHeight;
// Calculate geometric bounds if (w < 0.1) return;
double xInnerLeft = ox + arcHeight;
double xInnerRight = ox + totalWidth - arcHeight;
// 修正:为了确保视觉上与圆角完全闭合,稍微向圆角区域延伸一点 (0.8 * r)
// 用户的需求是“再高一点和低一点”,这意味着需要一定的重叠量来消除缝隙
double overlapFactor = 0.8;
double yBottomStraight = oy + r * overlapFactor;
double yTopStraight = oy + H - r * overlapFactor;
double chordLength = yTopStraight - yBottomStraight;
if (chordLength < 0.1) return; // Should not happen for reasonable params
double sagitta = arcHeight; double Rm = (H * H) / (8.0 * w) + w / 2.0;
// Bulge calculation: bulge = 2 * sagitta / chord // Left side
// For a CCW arc, bulge is positive. double xInnerLeft = ox + w;
double bulge = (2.0 * sagitta) / chordLength; 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;
// Left Arc: From Top to Bottom, bulging Left (CCW)
// Start: (xInnerLeft, yTopStraight)
// End: (xInnerLeft, yBottomStraight)
// Path: 12 o'clock -> 9 o'clock -> 6 o'clock direction is CCW.
var leftPoly = new Polyline(); var leftPoly = new Polyline();
leftPoly.AddVertexAt(0, new Point2d(xInnerLeft, yTopStraight), bulge, 0, 0); if (r > 0.01)
leftPoly.AddVertexAt(1, new Point2d(xInnerLeft, yBottomStraight), 0, 0, 0); {
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.Style?.Apply(leftPoly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(leftPoly); ctx.Btr.AppendEntity(leftPoly);
ctx.Tr.AddNewlyCreatedDBObject(leftPoly, true); ctx.Tr.AddNewlyCreatedDBObject(leftPoly, true);
// Right Arc: From Bottom to Top, bulging Right (CCW) var leftClosureLine = new Line(new Point3d(fx_L_tangTop, fy_L_tangTop, 0), new Point3d(fx_L_tangBot, fy_L_tangBot, 0));
// Start: (xInnerRight, yBottomStraight) ctx.Style?.Apply(leftClosureLine, DrawingStyleManager.Role.OutlineBold);
// End: (xInnerRight, yTopStraight) ctx.Btr.AppendEntity(leftClosureLine);
// Path: 6 o'clock -> 3 o'clock -> 12 o'clock direction is CCW. 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(); var rightPoly = new Polyline();
rightPoly.AddVertexAt(0, new Point2d(xInnerRight, yBottomStraight), bulge, 0, 0); if (r > 0.01)
rightPoly.AddVertexAt(1, new Point2d(xInnerRight, yTopStraight), 0, 0, 0); {
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.Style?.Apply(rightPoly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(rightPoly); ctx.Btr.AppendEntity(rightPoly);
ctx.Tr.AddNewlyCreatedDBObject(rightPoly, true); 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 { } catch { }
} }
@ -429,50 +525,21 @@ namespace CadParamPluging.Cad
var width = Math.Abs(xEnd - xStart); var width = Math.Abs(xEnd - xStart);
if (width < 0.1) return; if (width < 0.1) return;
var maxR = Math.Min(width * 0.5, height * 0.5); var topPoly = new Polyline();
var r = Math.Min(filletR, maxR); topPoly.AddVertexAt(0, new Point2d(xStart, yTop), 0, 0, 0);
var bulge = -Math.Tan(Math.PI / 8.0); topPoly.AddVertexAt(1, new Point2d(xEnd, yTop), 0, 0, 0);
var poly = new Polyline();
if (isLeft) ctx.Style?.Apply(topPoly, DrawingStyleManager.Role.OutlineBold);
{ ctx.Btr.AppendEntity(topPoly);
poly.AddVertexAt(0, new Point2d(xEnd, yBottom), 0, 0, 0); ctx.Tr.AddNewlyCreatedDBObject(topPoly, true);
if (r > 0.01)
{
poly.AddVertexAt(1, new Point2d(xStart + r, yBottom), bulge, 0, 0);
poly.AddVertexAt(2, new Point2d(xStart, yBottom + r), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(xStart, yTop - r), bulge, 0, 0);
poly.AddVertexAt(4, new Point2d(xStart + r, yTop), 0, 0, 0);
poly.AddVertexAt(5, new Point2d(xEnd, yTop), 0, 0, 0);
}
poly.Closed = false;
}
else
{
poly.AddVertexAt(0, new Point2d(xStart, yTop), 0, 0, 0);
if (r > 0.01)
{
poly.AddVertexAt(1, new Point2d(xEnd - r, yTop), bulge, 0, 0);
poly.AddVertexAt(2, new Point2d(xEnd, yTop - r), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(xEnd, yBottom + r), bulge, 0, 0);
poly.AddVertexAt(4, new Point2d(xEnd - r, yBottom), 0, 0, 0);
poly.AddVertexAt(5, new Point2d(xStart, yBottom), 0, 0, 0);
}
else
{
poly.AddVertexAt(1, new Point2d(xEnd, yTop), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(xEnd, yBottom), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(xStart, yBottom), 0, 0, 0);
}
poly.Closed = false;
}
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold); var botPoly = new Polyline();
ctx.Btr.AppendEntity(poly); botPoly.AddVertexAt(0, new Point2d(xStart, yBottom), 0, 0, 0);
ctx.Tr.AddNewlyCreatedDBObject(poly, true); 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) private static void DrawRingSectionHatchWithFillet(FeatureDrivenDrawer.DrawingContext ctx, double xInnerRight, double xOuterRight, double yBottom, double height, double filletR)