From d2c4be42267fac984307809b39062d4073f6d036 Mon Sep 17 00:00:00 2001 From: sladro Date: Wed, 21 Jan 2026 11:42:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E6=AF=9B=E6=96=99=E6=80=81-?= =?UTF-8?q?=E8=BD=A7=E5=88=B6-=E7=8E=AF=E5=BD=A2=E7=9A=84=E7=94=9F?= =?UTF-8?q?=E6=88=90=E9=80=BB=E8=BE=91=EF=BC=8C=E5=9C=86=E8=A7=92=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cad/FeatureDrivenDrawer.cs | 214 ++++++++++++++++++++++++++++++------- 1 file changed, 178 insertions(+), 36 deletions(-) diff --git a/Cad/FeatureDrivenDrawer.cs b/Cad/FeatureDrivenDrawer.cs index 009c426..dcd12cb 100644 --- a/Cad/FeatureDrivenDrawer.cs +++ b/Cad/FeatureDrivenDrawer.cs @@ -544,12 +544,14 @@ namespace CadParamPluging.Cad // === 特征1: 锻件外轮廓 === var unspecifiedFillet = bag.GetDoubleOrNull(KeyUnspecifiedFilletRadiusMax); - if (applyUnspecifiedFillet && unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) - { - DrawForgingOuterContourHalf(ctx, ox, oy, visualOuterR, H, unspecifiedFillet); - } - else + + // 判断是否有圆角 + bool hasUnspecifiedFillet = applyUnspecifiedFillet && unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0; + + if (!hasUnspecifiedFillet) { + // 只有在非圆角模式下才绘制单独的外轮廓 + // 在圆角模式下,整个实体轮廓由后面的 DrawRingSectionContourWithFillet 统一绘制 DrawForgingOuterContourHalf(ctx, ox, oy, visualOuterR, H, null); } @@ -562,7 +564,7 @@ namespace CadParamPluging.Cad // 传入 visualOuterR 用于画线,传入 outerDia 用于文本 DrawOuterDiameterDimensionHalf(ctx, ox, oy, visualOuterR, H, outerDia, outerTolPlus, outerTolMinus, outerDiaPrime); - // === 特征3: 内孔/内径 === + // === 特征3: 内孔/内径 === double? xInnerRight = null; if (innerDia.HasValue && innerDia.Value > 0 && innerDia.Value < outerDia) { @@ -572,39 +574,62 @@ namespace CadParamPluging.Cad var innerTolPlus = bag.GetDoubleOrNull(KeyInnerDiameter2TolPlus); var innerTolMinus = bag.GetDoubleOrNull(KeyInnerDiameter2TolMinus); - DrawInnerHoleHalf(ctx, ox, xInnerRight.Value, oy, H); - // 传入 raw innerDia for text - DrawInnerDiameterDimensionHalf(ctx, ox, xInnerRight.Value, oy, H, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime); + // 判断是否有圆角 (hasUnspecifiedFillet already declared above) + if (hasUnspecifiedFillet) + { + // 计算圆角半径逻辑,与 DrawRingSectionContourWithFillet 保持一致 + var sectionWidth = visualOuterR * 2.0; // Wait, section width is visualOuterR - visualInnerRight? No. + // Calculate visual width for section + var sWidth = (ox + visualOuterR) - (ox + visualInnerR); + var maxR = Math.Min(sWidth * 0.5, H * 0.5); + var rawR = unspecifiedFillet.Value; + var r = Math.Min(rawR, maxR); + double dimOffset = (r > 0.01) ? r : 0.0; - // === 特征4: 内径圆角 === - var innerRadiusMax = bag.GetDoubleOrNull(KeyInnerRadiusMax); - if (innerRadiusMax.HasValue && innerRadiusMax.Value > 0 && ctx.IsCenterPunched) - { - DrawInnerFilletsHalf(ctx, xInnerRight.Value, oy, H, innerRadiusMax.Value); - } - else if (applyUnspecifiedFillet && unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) - { - DrawInnerFilletsHalfInward(ctx, xInnerRight.Value, oy, H, unspecifiedFillet.Value); - } + // 新逻辑:如果启用了圆角,直接绘制一个闭合的圆角矩形作为实体轮廓 + // 替代原来分散的 外轮廓 + 内孔竖线 + 圆角 的画法,解决直角残留和不平滑问题 + DrawRingSectionContourWithFillet(ctx, xInnerRight.Value, ox + visualOuterR, oy, H, unspecifiedFillet.Value); + + // 补充:绘制连接中轴线到实体内边缘的上下两条横线(内孔顶底面) + DrawHoleHorizontalLines(ctx, ox, xInnerRight.Value, oy, H, unspecifiedFillet.Value); - // === 特征4.1: 剖面线 === - if (applyUnspecifiedFillet && unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) - { + // 标注依然需要 + // 用户反馈:下边的标注线在竖直方向上不要闭合(保持在底边水平),不要高于白色底部边框 + // 所以这里恢复 offset 为 0 + DrawInnerDiameterDimensionHalf(ctx, ox, xInnerRight.Value, oy, H, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime, 0.0); + + // 剖面填充 DrawRingSectionHatchWithFillet(ctx, xInnerRight.Value, ox + visualOuterR, oy, H, unspecifiedFillet.Value); } else { + // 原有逻辑:直角模式 + DrawInnerHoleHalf(ctx, ox, xInnerRight.Value, oy, H); + DrawInnerDiameterDimensionHalf(ctx, ox, xInnerRight.Value, oy, H, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime); + DrawRingSectionHatch(ctx, xInnerRight.Value, ox + visualOuterR, oy, H); + + // 剖面左侧竖线 + DrawSectionInnerBoundaryBold(ctx, xInnerRight.Value, oy, H); } - - // 剖面左侧竖线 - DrawSectionInnerBoundaryBold(ctx, xInnerRight.Value, oy, H); } // === 特征5: 高度标注 === var heightTolPlus = bag.GetDoubleOrNull(KeyHeight1TolPlus); var heightTolMinus = bag.GetDoubleOrNull(KeyHeight1TolMinus); - DrawHeightDimensionHalf(ctx, ox, oy, visualOuterR, H, heightTolPlus, heightTolMinus, heightPrime); + + // 计算高度标注的内缩进量(针对圆角闭合) + // 使标注界线的起点X坐标向内缩进 r,从而搭在圆角的切点上,而Y坐标保持不变(与锻件顶底对齐) + double heightDimIndentX = 0.0; + if (hasUnspecifiedFillet) + { + var sWidth = (ox + visualOuterR) - (ox + visualInnerR); + var maxR = Math.Min(sWidth * 0.5, H * 0.5); + var r = Math.Min(unspecifiedFillet.Value, maxR); + if (r > 0.01) heightDimIndentX = r; + } + + DrawHeightDimensionHalf(ctx, ox, oy, visualOuterR, H, heightTolPlus, heightTolMinus, heightPrime, heightDimIndentX); // === 特征6: 未注圆角 === if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0) @@ -616,7 +641,8 @@ namespace CadParamPluging.Cad var minWallThickness = bag.GetDoubleOrNull(KeyMinWallThickness); if (minWallThickness.HasValue && minWallThickness.Value > 0 && xInnerRight.HasValue) { - DrawMinWallThicknessNote(ctx, xInnerRight.Value, ox + visualOuterR, oy, minWallThickness.Value); + // 用户反馈:下边标注线不要偏移,恢复为0 + DrawMinWallThicknessNote(ctx, xInnerRight.Value, ox + visualOuterR, oy, minWallThickness.Value, 0.0); } // === 特征8: 零件轮廓(车加工态,右半边) === @@ -642,6 +668,8 @@ namespace CadParamPluging.Cad // 高度方向没有示意图扭曲,直接使用物理高度 var scaledHeightPrime = heightPrime.Value; + // 恢复绘制零件轮廓(无论是否有圆角) + // 用户确认剖面中需要显示零件生成部分,之前的屏蔽是误判 DrawPartContourHalf(ctx, ox, oy, H, scaledOuterDiaPrime, scaledInnerDiaPrime, scaledHeightPrime); } @@ -658,6 +686,112 @@ namespace CadParamPluging.Cad } + + /// + /// 轧制:绘制带圆角的实体闭合轮廓(圆角多段线) + /// 替代原来分散的外轮廓线和内孔边界线 + /// + private static void DrawRingSectionContourWithFillet(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); // 90度圆弧的凸度 + + // 逆时针绘制圆角矩形 + // 顺序:左下圆弧 -> 右下圆弧 -> 右上圆弧 -> 左上圆弧 + + // 下方边:从左下到右下 + // 起点 (xLeft + r, yBottom) -> 直线 -> (xRight - r, yBottom) -> 圆弧 -> (xRight, yBottom + r) + + var polyFillet = new Polyline(); + + // 1. 下边直线段起点 + polyFillet.AddVertexAt(0, new Point2d(xLeft + r, yBottom), 0, 0, 0); + + // 2. 右下角圆弧起点 + polyFillet.AddVertexAt(1, new Point2d(xRight - r, yBottom), bulge, 0, 0); + + // 3. 右边直线段起点 (圆弧终点) + polyFillet.AddVertexAt(2, new Point2d(xRight, yBottom + r), 0, 0, 0); + + // 4. 右上角圆弧起点 + polyFillet.AddVertexAt(3, new Point2d(xRight, yTop - r), bulge, 0, 0); + + // 5. 上边直线段起点 (圆弧终点) + polyFillet.AddVertexAt(4, new Point2d(xRight - r, yTop), 0, 0, 0); + + // 6. 左上角圆弧起点 + polyFillet.AddVertexAt(5, new Point2d(xLeft + r, yTop), bulge, 0, 0); + + // 7. 左边直线段起点 (圆弧终点) + polyFillet.AddVertexAt(6, new Point2d(xLeft, yTop - r), 0, 0, 0); + + // 8. 左下角圆弧起点 + 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 DrawHoleHorizontalLines(DrawingContext ctx, double xAxis, double xSectionLeft, double yBottom, double height, double filletR) + { + var yTop = yBottom + height; + + // 计算延伸量:为了与圆角闭合,横线需要延伸到圆角圆心的X坐标处 + // 或者简单点,让它延伸到 (xSectionLeft + r),即圆角的结束位置 + var width = 200.0; // dummy big enough width for calculation + var maxR = Math.Min(width * 0.5, height * 0.5); + var r = Math.Min(filletR, maxR); + + // 如果圆角很小,就不用延伸太远,但考虑到视觉闭合,应该延伸到 xSectionLeft 就够了? + // 不, 截图显示圆角导致内孔竖直边向内缩进,所以横线必须向右延伸穿过圆角区域,连接到实体。 + // 圆角起点的X坐标是 xSectionLeft,圆角终点的X坐标是 xSectionLeft + r + // 实际上,横线应该连接到圆角圆弧的切点?不,横线是顶面/底面,所以应该连接到 (xSectionLeft + r) + + double xTarget = xSectionLeft; + if (r > 0.01) + { + xTarget = xSectionLeft + r; + } + + // Bottom line + var line1 = new Line(new Point3d(xAxis, yBottom, 0), new Point3d(xTarget, yBottom, 0)); + ctx.Style?.Apply(line1, DrawingStyleManager.Role.OutlineBold); + ctx.Btr.AppendEntity(line1); + ctx.Tr.AddNewlyCreatedDBObject(line1, true); + + // Top line + var line2 = new Line(new Point3d(xAxis, yTop, 0), new Point3d(xTarget, yTop, 0)); + ctx.Style?.Apply(line2, DrawingStyleManager.Role.OutlineBold); + ctx.Btr.AppendEntity(line2); + ctx.Tr.AddNewlyCreatedDBObject(line2, true); + } + /// /// 自由锻工艺 - 画全图 /// @@ -937,7 +1071,7 @@ namespace CadParamPluging.Cad /// 轧制:内径标注(从对称轴到右边内孔,放到下方并与最小壁厚标注共线) /// private static void DrawInnerDiameterDimensionHalf(DrawingContext ctx, double oxAxis, double xInnerRight, double yBottom, double height, - double diameter, double? tolPlus, double? tolMinus, double? diameterPrime) + double diameter, double? tolPlus, double? tolMinus, double? diameterPrime, double offsetY = 0) { // Use OriginalBag for text display var diameterVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2) ?? diameter; @@ -965,8 +1099,8 @@ namespace CadParamPluging.Cad var dimLineY = yBottom - 10; AddLinearDim( ctx, - new Point3d(oxAxis, yBottom, 0), - new Point3d(xInnerRight, yBottom, 0), + new Point3d(oxAxis, yBottom, 0), // 对称轴点不需要偏移,因为它是中心线 + new Point3d(xInnerRight, yBottom + offsetY, 0), // 内孔点需要偏移以避开圆角空隙 new Point3d(oxAxis + innerRadius / 2, dimLineY, 0), 0, dimText, @@ -998,9 +1132,10 @@ namespace CadParamPluging.Cad /// /// 轧制:高度标注(在右侧) + /// indentX: 界线起点向内横向缩进量(配合圆角使用,使界线起于圆角切点) /// private static void DrawHeightDimensionHalf(DrawingContext ctx, double ox, double oy, double radius, - double height, double? tolPlus, double? tolMinus, double? heightPrime) + double height, double? tolPlus, double? tolMinus, double? heightPrime, double indentX = 0) { // Use OriginalBag for text display var heightVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1) ?? height; @@ -1022,10 +1157,17 @@ namespace CadParamPluging.Cad ? baseText + $"\\X({FormatDimNumber(heightPrimeVal.Value)})" : baseText; + // 界线起点: + // 下端: (ox + radius - indentX, oy) + // 上端: (ox + radius - indentX, oy + height) + // 这样保持了高度(Y)不变,和白色横线对齐,但X方向向内缩进搭在圆角顶点上 + + var xLine = ox + radius - indentX; + AddLinearDim( ctx, - new Point3d(ox + radius, oy, 0), - new Point3d(ox + radius, oy + height, 0), + new Point3d(xLine, oy, 0), + new Point3d(xLine, oy + height, 0), new Point3d(ox + radius + 20, oy + height / 2, 0), 90, dimText); @@ -1250,14 +1392,14 @@ namespace CadParamPluging.Cad } } - private static void DrawMinWallThicknessNote(DrawingContext ctx, double xInnerRight, double xOuterRight, double yBottom, double thickness) + private static void DrawMinWallThicknessNote(DrawingContext ctx, double xInnerRight, double xOuterRight, double yBottom, double thickness, double offsetY = 0) { var val = ctx.OriginalBag?.GetDoubleOrNull(KeyMinWallThickness) ?? thickness; var dimText = $"{FormatDimNumber(val)}min"; AddLinearDim( ctx, - new Point3d(xInnerRight, yBottom, 0), - new Point3d(xOuterRight, yBottom, 0), + new Point3d(xInnerRight, yBottom + offsetY, 0), + new Point3d(xOuterRight, yBottom + offsetY, 0), new Point3d((xInnerRight + xOuterRight) / 2, yBottom - 10, 0), 0, dimText);