修改生成图纸逻辑

This commit is contained in:
sladro 2026-01-14 12:03:39 +08:00
parent 9774d8a0b9
commit f55b32e9fa
5 changed files with 211 additions and 53 deletions

View File

@ -2,6 +2,8 @@ using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using CadParamPluging.Common;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
namespace CadParamPluging.Cad
{
@ -56,6 +58,12 @@ namespace CadParamPluging.Cad
rb.Add(new TypedValue((int)DxfCode.Text, entry));
}
}
try
{
// Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage($"\n[CadParamPluging] Saving Params: Count={bag.Items.Count}\n");
}
catch {}
var xrec = new Xrecord();
xrec.Data = rb;
@ -117,6 +125,12 @@ namespace CadParamPluging.Cad
if (parts.Length == 2)
{
bag.Set(parts[0], parts[1]);
try
{
// Log Hardness read
}
catch {}
}
else if (parts.Length == 1)
{

View File

@ -157,12 +157,33 @@ namespace CadParamPluging.Cad
var outerDia = bag.GetDoubleOrNull(KeyOuterDiameter1) ?? 0;
var height = bag.GetDoubleOrNull(KeyHeight1) ?? 0;
// Check if schematic mode applies (Machined + Rolling)
// Need to fetch from bag as we don't have DrawingContext here
var deliveryStatus = bag.GetString("DeliveryStatus");
var processMethod = bag.GetString("ProcessMethod");
bool isMachined = !string.IsNullOrWhiteSpace(deliveryStatus) && deliveryStatus.Contains("车加工");
bool isRolling = !string.IsNullOrWhiteSpace(processMethod) && processMethod.Contains("轧制");
double activeWidth = outerDia;
double extraMargin = 40; // Default margin
if (isMachined && isRolling)
{
// In schematic mode, width is visually fixed to 2.0 * Height
activeWidth = height * 2.0;
// 对于示意图模式边距应按比例计算图形较大尺寸的50%上限100
// 避免小型示意图因边距过大导致"预期尺寸"虚高
var maxDim = Math.Max(activeWidth, height);
extraMargin = Math.Min(maxDim * 0.5, 100);
}
// 环形图形:宽度=外径X方向高度=高度参数Y方向
// 加上标注的额外空间约40像素每侧
var extraMargin = 40;
// 加上标注的额外空间
return new ExpectedDrawingSize
{
Width = outerDia + extraMargin * 2,
Width = activeWidth + extraMargin * 2,
Height = height + extraMargin * 2
};
}
@ -353,12 +374,72 @@ namespace CadParamPluging.Cad
private static void DrawRingFeaturesHalf(DrawingContext ctx, double outerDia, double height)
{
var bag = ctx.Bag;
double R = outerDia / 2.0; // 外半径
// --- 几何与视觉映射计算 ---
double H = height;
double physicalOuterR = outerDia / 2.0;
// 1. 确定视觉外半径 (L)
// 轧制+车加工:强制 L/H = 2
double visualOuterR = physicalOuterR;
if (ctx.IsMachined)
{
visualOuterR = H * 2.0;
}
// 2. 确定视觉内半径
var innerDia = bag.GetDoubleOrNull(KeyInnerDiameter2);
double physicalInnerR = 0;
double visualInnerR = 0;
if (innerDia.HasValue && innerDia.Value > 0 && innerDia.Value < outerDia)
{
physicalInnerR = innerDia.Value / 2.0;
if (ctx.IsMachined)
{
// 强制示意图模式:
// 按照用户提供的参考图 (L/H=2),右侧剖面区域和左侧内孔区域各占一半
// 即 Visual Inner Radius = Visual Outer Radius / 2.0
// 这样视觉上就是两个并排的正方形:左边是空的,右边是剖面
visualInnerR = visualOuterR * 0.5;
}
else
{
visualInnerR = physicalInnerR * (visualOuterR / physicalOuterR);
}
}
// 3. 定义半径映射函数 (非线性映射:孔区线性,壁厚区线性)
// r: 物理半径
double MapRadius(double r)
{
if (r <= 0) return 0;
// 如果没有内孔,直接线性映射
if (physicalInnerR <= 1e-6)
{
return r * (visualOuterR / physicalOuterR);
}
if (r <= physicalInnerR)
{
// 孔区映射
return r * (visualInnerR / physicalInnerR);
}
else
{
// 壁厚区映射
// V = Vir + (r - Pir) * (Vor - Vir) / (Por - Pir)
double wallScale = (visualOuterR - visualInnerR) / (physicalOuterR - physicalInnerR);
return visualInnerR + (r - physicalInnerR) * wallScale;
}
}
// --- 绘图坐标计算 ---
// 轧制时图形只画右半边,但要保持居中
// 半图宽度为R要居中则起点为 Center.X - R/2
double ox = ctx.Center.X - R / 2.0; // 对称轴位置(左边界)
double ox = ctx.Center.X - visualOuterR / 2.0; // 对称轴位置(视觉左边界)
double oy = ctx.Center.Y - H / 2.0;
// 车加工态零件尺寸
@ -372,77 +453,91 @@ namespace CadParamPluging.Cad
heightPrime = bag.GetDoubleOrNull(KeyHeight1Prime);
}
// === 特征1: 锻件外轮廓(右半边,三条边:下、右、上,左边开口) ===
DrawForgingOuterContourHalf(ctx, ox, oy, R, H);
// === 特征1: 锻件外轮廓 ===
DrawForgingOuterContourHalf(ctx, ox, oy, visualOuterR, H);
// === 特征1.1: 对称轴(垂直中心线) ===
// === 特征1.1: 对称轴 ===
DrawRingSymmetryAxis(ctx, ox, oy, H);
// === 特征2: 外径公差标注 ===
var outerTolPlus = bag.GetDoubleOrNull(KeyOuterDiameter1TolPlus);
var outerTolMinus = bag.GetDoubleOrNull(KeyOuterDiameter1TolMinus);
DrawOuterDiameterDimensionHalf(ctx, ox, oy, R, H, outerDia, outerTolPlus, outerTolMinus, outerDiaPrime);
// 传入 visualOuterR 用于画线,传入 outerDia 用于文本
DrawOuterDiameterDimensionHalf(ctx, ox, oy, visualOuterR, H, outerDia, outerTolPlus, outerTolMinus, outerDiaPrime);
// === 特征3: 内孔/内径(如果有内径参数) ===
var innerDia = bag.GetDoubleOrNull(KeyInnerDiameter2);
// === 特征3: 内孔/内径 ===
double? xInnerRight = null;
if (innerDia.HasValue && innerDia.Value > 0 && innerDia.Value < outerDia)
{
double innerR = innerDia.Value / 2.0;
xInnerRight = ox + innerR;
// 计算视觉上的内径右边界
xInnerRight = ox + visualInnerR;
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);
// === 特征4: 内径圆角(只画右侧) ===
// === 特征4: 内径圆角 ===
var innerRadiusMax = bag.GetDoubleOrNull(KeyInnerRadiusMax);
if (innerRadiusMax.HasValue && innerRadiusMax.Value > 0 && ctx.IsCenterPunched)
{
DrawInnerFilletsHalf(ctx, xInnerRight.Value, oy, H, innerRadiusMax.Value);
}
// === 特征4.1: 剖面线(右半边环形截面) ===
DrawRingSectionHatch(ctx, xInnerRight.Value, ox + R, oy, H);
// === 特征4.1: 剖面线 ===
DrawRingSectionHatch(ctx, xInnerRight.Value, ox + visualOuterR, oy, H);
// 剖面左侧竖线应为粗实线(剖切边界)
// 剖面左侧竖线
DrawSectionInnerBoundaryBold(ctx, xInnerRight.Value, oy, H);
}
// === 特征5: 高度标注 ===
var heightTolPlus = bag.GetDoubleOrNull(KeyHeight1TolPlus);
var heightTolMinus = bag.GetDoubleOrNull(KeyHeight1TolMinus);
DrawHeightDimensionHalf(ctx, ox, oy, R, H, heightTolPlus, heightTolMinus, heightPrime);
DrawHeightDimensionHalf(ctx, ox, oy, visualOuterR, H, heightTolPlus, heightTolMinus, heightPrime);
// === 特征6: 未注圆角 ===
var unspecifiedFillet = bag.GetDoubleOrNull(KeyUnspecifiedFilletRadiusMax);
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
{
DrawUnspecifiedFilletNote(ctx, ox, oy, H, R, unspecifiedFillet.Value);
DrawUnspecifiedFilletNote(ctx, ox, oy, H, visualOuterR, unspecifiedFillet.Value);
}
// === 特征7: 最小壁厚min标注 ===
var minWallThickness = bag.GetDoubleOrNull(KeyMinWallThickness);
if (minWallThickness.HasValue && minWallThickness.Value > 0 && xInnerRight.HasValue)
{
DrawMinWallThicknessNote(ctx, xInnerRight.Value, ox + R, oy, minWallThickness.Value);
DrawMinWallThicknessNote(ctx, xInnerRight.Value, ox + visualOuterR, oy, minWallThickness.Value);
}
// === 特征8: 零件轮廓(车加工态,右半边) ===
if (ctx.IsMachined && outerDiaPrime.HasValue && outerDiaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0)
{
DrawPartContourHalf(ctx, ox, oy, H, outerDiaPrime.Value, innerDiaPrime, heightPrime.Value);
// 零件轮廓(黄色部分)与锻件轮廓(白色部分)的间隙:
// 由于采用了强制比例和非线性映射,直接映射会导致间隙过大。
// 此处采用固定视觉间隙 (2.5个单位),确保零件框紧贴锻件框内部,符合示意图效果。
var visualGap = 2.5;
var scaledOuterDiaPrime = (visualOuterR - visualGap) * 2.0;
var scaledInnerDiaPrime = innerDiaPrime.HasValue
? (visualInnerR + visualGap) * 2.0
: (double?)null;
// 同时也修正高度方向的视觉间隙,使其上下也紧贴外框
var scaledHeightPrime = H - visualGap * 2.0;
DrawPartContourHalf(ctx, ox, oy, H, scaledOuterDiaPrime, scaledInnerDiaPrime, scaledHeightPrime);
}
// === 特征10: 轧制+车加工 特殊引线标注 (HB5936-13) ===
// 需满足: 车加工 + 轧制(本方法即为轧制) + 有内孔
if (ctx.IsMachined && innerDia.HasValue && innerDia.Value > 0)
{
// 指向锻件内孔右上角
DrawSpecialInnerHoleLeader(ctx, ox, oy, H, innerDia.Value);
// 指向锻件内孔右上角(白色线框)
var scaledInnerDia = visualInnerR * 2.0;
DrawSpecialInnerHoleLeader(ctx, ox, oy, H, scaledInnerDia);
}
// === 特征9: 硬度符号 ===
@ -607,7 +702,7 @@ namespace CadParamPluging.Cad
{
const double extend = 5.0; // 截断线在轮廓上下各延长一点
const double frameMargin = 5.0; // 避免越过图框边界
const double lineSpacing = 5.0; // 两根截断线间距5mm
const double lineSpacing = 3.0; // 两根截断线间距3mm
var y0 = oy - extend;
var y1 = oy + height + extend;
@ -797,18 +892,28 @@ namespace CadParamPluging.Cad
{
var Rp = outerDiaPrime / 2.0;
var h = heightPrime;
// 零件轮廓居中于锻件轮廓内
// 零件轮廓居中于锻件轮廓内 (垂直方向)
var offsetY = (forgingHeight - h) / 2.0;
var y0 = oy + offsetY;
// 绘制闭合方框(仅画外轮廓,不画内径线)
// 计算X方向的范围从零件内半径到零件外半径
// 如果没有内径,则默认从对称轴(ox)开始
double minX = ox;
if (innerDiaPrime.HasValue && innerDiaPrime.Value > 0)
{
minX = ox + innerDiaPrime.Value / 2.0;
}
double maxX = ox + Rp;
// 绘制闭合方框(对应截图中的黄色虚线框,即零件截面)
var polyPart = new Polyline();
polyPart.AddVertexAt(0, new Point2d(ox, y0), 0, 0, 0);
polyPart.AddVertexAt(1, new Point2d(ox + Rp, y0), 0, 0, 0);
polyPart.AddVertexAt(2, new Point2d(ox + Rp, y0 + h), 0, 0, 0);
polyPart.AddVertexAt(3, new Point2d(ox, y0 + h), 0, 0, 0);
polyPart.AddVertexAt(0, new Point2d(minX, y0), 0, 0, 0);
polyPart.AddVertexAt(1, new Point2d(maxX, y0), 0, 0, 0);
polyPart.AddVertexAt(2, new Point2d(maxX, y0 + h), 0, 0, 0);
polyPart.AddVertexAt(3, new Point2d(minX, y0 + h), 0, 0, 0);
polyPart.Closed = true; // 闭合方框
ctx.Style?.Apply(polyPart, DrawingStyleManager.Role.PartContour);
ctx.Btr.AppendEntity(polyPart);
ctx.Tr.AddNewlyCreatedDBObject(polyPart, true);

View File

@ -522,7 +522,7 @@ namespace CadParamPluging.Cad
var mt = new MText();
mt.Contents = ToMTextContents(renderedForCreation);
mt.Location = insertPoint;
mt.TextHeight = 3.5;
mt.TextHeight = 3.0;
mt.Attachment = AttachmentPoint.BottomLeft; // 关键:锚点在左下,文字向上延伸

View File

@ -6,6 +6,8 @@ using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using CadParamPluging.Common;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
namespace CadParamPluging.UI
{
@ -409,7 +411,7 @@ namespace CadParamPluging.UI
}
var lbl = new Label { AutoSize = true, Text = labelText, TextAlign = ContentAlignment.MiddleLeft, Padding = new Padding(0, 6, 8, 6) };
var ctrl = CreateControl(def);
var ctrl = CreateControl(def, controlKey);
ctrl.Width = 260;
if (!string.IsNullOrWhiteSpace(def.Hint))
@ -640,17 +642,28 @@ namespace CadParamPluging.UI
return bag;
}
private Control CreateControl(ParamDefinition def)
private Control CreateControl(ParamDefinition def, string valueKey)
{
var initialValue = def.DefaultValue;
// 优先使用传入的默认值 (loadedDefaults)
if (_loadedDefaults != null)
{
var val = _loadedDefaults.GetString(def.Key);
var val = _loadedDefaults.GetString(valueKey);
if (val != null) // only if key exists
{
initialValue = val;
if (valueKey.StartsWith("Hardness"))
{
// Logging removed
}
}
else
{
if (valueKey.StartsWith("Hardness"))
{
// Logging removed
}
}
}
// 确保不为 null
@ -694,7 +707,10 @@ namespace CadParamPluging.UI
{
cb.Items.AddRange(arr);
var idx = Array.FindIndex(arr, x => string.Equals(x, initialValue, StringComparison.OrdinalIgnoreCase));
cb.SelectedIndex = idx >= 0 ? idx : 0;
if (idx >= 0)
{
cb.SelectedIndex = idx;
}
}
if (!string.IsNullOrWhiteSpace(initialValue))
{
@ -771,6 +787,11 @@ namespace CadParamPluging.UI
}
bag.Set(key, value);
if (key.StartsWith("Hardness"))
{
// Logging removed
}
}
Result = bag;
@ -780,22 +801,25 @@ namespace CadParamPluging.UI
private static string ReadValue(Control ctrl, ParamDefinition def)
{
switch (def.Type)
if (ctrl is CheckBox chk)
{
case ParamValueType.Bool:
return (ctrl as CheckBox)?.Checked == true ? "true" : "false";
case ParamValueType.Enum:
return ((ctrl as ComboBox)?.Text ?? string.Empty).Trim();
case ParamValueType.Int:
case ParamValueType.Double:
if (ctrl is NumericUpDown num)
{
return num.Value.ToString(CultureInfo.InvariantCulture);
}
return string.Empty;
default:
return ((ctrl as TextBox)?.Text ?? string.Empty).Trim();
return chk.Checked ? "true" : "false";
}
if (ctrl is NumericUpDown num)
{
return num.Value.ToString(CultureInfo.InvariantCulture);
}
if (ctrl is ComboBox cb)
{
// Handles both Enum type and String type rendered as ComboBox
return (cb.Text ?? string.Empty).Trim();
}
if (ctrl is TextBox tb)
{
return (tb.Text ?? string.Empty).Trim();
}
return string.Empty;
}
}
}

View File

@ -339,6 +339,17 @@ namespace CadParamPluging.UI
var frameWidth = frame.MaxPoint.X - frame.MinPoint.X;
var frameHeight = frame.MaxPoint.Y - frame.MinPoint.Y;
// 确保 bag 中包含交付状态和工艺方法,以便 CalculateExpectedSize 正确判断示意图模式
// tplParams.ProjectType = 交付状态(如"车加工"tplParams.DrawingType = 工艺方法(如"轧制"
if (string.IsNullOrEmpty(bag.GetString("DeliveryStatus")))
{
bag.Set("DeliveryStatus", tplParams.ProjectType ?? string.Empty);
}
if (string.IsNullOrEmpty(bag.GetString("ProcessMethod")))
{
bag.Set("ProcessMethod", tplParams.DrawingType ?? string.Empty);
}
// 1. 获取预估图形尺寸 (不含标注的纯几何尺寸 + 预留边距)
var expectedSize = FeatureDrivenDrawer.CalculateExpectedSize(bag, tplParams.SheetSize);
@ -350,6 +361,10 @@ namespace CadParamPluging.UI
bool isOverflow = currentDrawW > frameWidth || currentDrawH > frameHeight;
bool isTooSmall = currentDrawW < frameWidth * 0.3 && currentDrawH < frameHeight * 0.3;
// 调试日志
AppendLog($"[尺寸检查] 白框尺寸: {frameWidth:F0}x{frameHeight:F0}, 预期图形(原始): {expectedSize.Width:F0}x{expectedSize.Height:F0}, 当前比例: 1:{(1/scaleFactor):F1}");
AppendLog($"[尺寸检查] 预期图形(缩放后): {currentDrawW:F0}x{currentDrawH:F0}, 超出={isOverflow}, 过小={isTooSmall}");
if (isOverflow || isTooSmall)
{
// 计算建议比例 (目标填充率 65%)
@ -485,7 +500,7 @@ namespace CadParamPluging.UI
bagToSave.Set("DrawingType", tplParams.DrawingType);
bagToSave.Set("SheetSize", tplParams.SheetSize);
bagToSave.Set("SpecialCondition", tplParams.Scale); // tplParams.Scale 对应 _cbScale (特殊条件)
DictionaryHelper.SaveParams(doc.Database, bagToSave);
AppendLog("参数已保存到图纸内部数据中。");
}