diff --git a/Cad/BlockRawFreeForgeRoundHeadDrawer.cs b/Cad/BlockRawFreeForgeRoundHeadDrawer.cs index d42303f..348cb19 100644 --- a/Cad/BlockRawFreeForgeRoundHeadDrawer.cs +++ b/Cad/BlockRawFreeForgeRoundHeadDrawer.cs @@ -135,34 +135,40 @@ namespace CadParamPluging.Cad // 使用 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 maxR = Math.Min(sideFrameWidth * 0.5, H * 0.5); double effectiveHeadR = Math.Min(headFilletR, maxR); - // 绘制左侧框线(连接左端圆弧和中间剖面框) - // 左端: xInnerLeft (需处理左上下角的圆角 - 使用 headFilletR) - // 右端: xSectionLeft (连接到中间框的直边) - // Note: Extend horizontally by sectionFilletR to achieve "Horizontal Closure" with the section fillet - DrawBoxSideFrame(ctx, xInnerLeft, xSectionLeft + sectionFilletR, oy, H, headFilletR, isLeft: true); + 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; - // 绘制右侧框线 - // 左端: xSectionRight (连接到中间框的直边) - // 右端: xInnerRight (需处理右上下角的圆角 - 使用 headFilletR) - // Note: Extend horizontally inwards by sectionFilletR - DrawBoxSideFrame(ctx, xSectionRight - sectionFilletR, xInnerRight, oy, H, headFilletR, isLeft: false); + 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; - // 1. 绘制完整锻件外轮廓(方体有圆头 - 白色,大圆弧) - // 修正:圆弧弦线需向内缩进 effectiveHeadR (Clamped),以与锻件外侧圆角起点对齐 - // This ensures the Big Arc starts curving exactly where the Side Frame vertical edge ends. - DrawBlockRoundHeadOutline(ctx, ox, oy, visualTotalW, H, arcHeight, effectiveHeadR); + 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 = xInnerLeft + effectiveHeadR; + double cxLeft = xf_left; double cyLeft = yTop - effectiveHeadR; DrawHeadFilletRadiusLeader(ctx, cxLeft, cyLeft, effectiveHeadR, true); @@ -228,13 +234,12 @@ namespace CadParamPluging.Cad // 修正:标注需涵盖内框宽度 (矩形部分) // 修正:引线起点改为内框边界 (xInnerLeft/Right) 和高度底部上移圆角半径,确保闭合到白色线框 - // 使用 headFilletR 作为 Offset,因为这是侧边框的倒角 - double dimOriginY = oy + headFilletR; + // 修正:引线起点严格匹配倒角与圆弧相切处的极限点坐标 (fx_L_tang, fy_L_tangBot) AddLinearDim( ctx, - new Point3d(xInnerLeft, dimOriginY, 0), - new Point3d(xInnerRight, dimOriginY, 0), - new Point3d((xInnerLeft + xInnerRight) / 2, oy - 25, 0), + 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); } @@ -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 { double H = height; double r = innerFilletR; - - // Calculate geometric bounds - 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 w = arcHeight; + if (w < 0.1) return; - double sagitta = arcHeight; - - // Bulge calculation: bulge = 2 * sagitta / chord - // For a CCW arc, bulge is positive. - double bulge = (2.0 * sagitta) / chordLength; + 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; - // 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(); - leftPoly.AddVertexAt(0, new Point2d(xInnerLeft, yTopStraight), bulge, 0, 0); - leftPoly.AddVertexAt(1, new Point2d(xInnerLeft, yBottomStraight), 0, 0, 0); - + 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); - // Right Arc: From Bottom to Top, bulging Right (CCW) - // Start: (xInnerRight, yBottomStraight) - // End: (xInnerRight, yTopStraight) - // Path: 6 o'clock -> 3 o'clock -> 12 o'clock direction is CCW. + 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(); - rightPoly.AddVertexAt(0, new Point2d(xInnerRight, yBottomStraight), bulge, 0, 0); - rightPoly.AddVertexAt(1, new Point2d(xInnerRight, yTopStraight), 0, 0, 0); + 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 { } } @@ -429,50 +525,21 @@ namespace CadParamPluging.Cad var width = Math.Abs(xEnd - xStart); if (width < 0.1) return; - var maxR = Math.Min(width * 0.5, height * 0.5); - var r = Math.Min(filletR, maxR); - var bulge = -Math.Tan(Math.PI / 8.0); - - var poly = new Polyline(); + var topPoly = new Polyline(); + topPoly.AddVertexAt(0, new Point2d(xStart, yTop), 0, 0, 0); + topPoly.AddVertexAt(1, new Point2d(xEnd, yTop), 0, 0, 0); - if (isLeft) - { - poly.AddVertexAt(0, new Point2d(xEnd, yBottom), 0, 0, 0); - - 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(topPoly, DrawingStyleManager.Role.OutlineBold); + ctx.Btr.AppendEntity(topPoly); + ctx.Tr.AddNewlyCreatedDBObject(topPoly, true); - ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold); - ctx.Btr.AppendEntity(poly); - ctx.Tr.AddNewlyCreatedDBObject(poly, 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)