CadParamPluging/Cad/DiskRawFreeForgeDrawer.cs

480 lines
20 KiB
C#

using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using CadParamPluging.Common;
namespace CadParamPluging.Cad
{
public static class DiskRawFreeForgeDrawer
{
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 = "饼盘",
ProcessMethod = "自由锻",
Btr = btr,
Style = new DrawingStyleManager(db, tr)
};
DrawDiskFeatures(context);
}
private static void DrawDiskFeatures(FeatureDrivenDrawer.DrawingContext ctx)
{
var bag = ctx.Bag;
var diameter = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameter);
var height = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1);
if (!diameter.HasValue || diameter.Value <= 0) return;
if (!height.HasValue || height.Value <= 0) return;
double ox = ctx.Center.X - diameter.Value / 2.0;
double oy = ctx.Center.Y - height.Value / 2.0;
double R = diameter.Value / 2.0;
double H = height.Value;
// 获取未注圆角半径
var unspecifiedFillet = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyUnspecifiedFilletRadiusMax);
double r = unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0 ? unspecifiedFillet.Value : 0;
// 安全检查:圆角不能超过宽或高的一半
double maxR = Math.Min(diameter.Value * 0.5, H * 0.5);
r = Math.Min(r, maxR);
// 绘制饼盘轮廓(俯视图为圆,侧视图为矩形,根据 R 控制圆角弧度)
var poly = new Polyline();
if (r > 0.01)
{
var bulge = Math.Tan(Math.PI / 8.0);
double xLeft = ox;
double xRight = ox + diameter.Value;
double yBottom = oy;
double yTop = oy + H;
poly.AddVertexAt(0, new Point2d(xLeft + r, yBottom), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(xRight - r, yBottom), bulge, 0, 0);
poly.AddVertexAt(2, new Point2d(xRight, yBottom + r), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(xRight, yTop - r), bulge, 0, 0);
poly.AddVertexAt(4, new Point2d(xRight - r, yTop), 0, 0, 0);
poly.AddVertexAt(5, new Point2d(xLeft + r, yTop), bulge, 0, 0);
poly.AddVertexAt(6, new Point2d(xLeft, yTop - r), 0, 0, 0);
poly.AddVertexAt(7, new Point2d(xLeft, yBottom + r), bulge, 0, 0);
}
else
{
poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(ox + diameter.Value, oy), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(ox + diameter.Value, oy + H), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(ox, oy + H), 0, 0, 0);
}
poly.Closed = true;
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold);
ctx.Btr.AppendEntity(poly);
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
// 绘制中心线 (点划线)
const double extendLine = 5.0;
const double frameMargin = 5.0;
var y0 = oy - extendLine;
var y1 = oy + H + extendLine;
try
{
var frameExtents = TemplateDrawingService.ComputeWhiteFrameExtents(ctx?.Ctx);
if (frameExtents.HasValue)
{
var frame = frameExtents.Value;
y0 = Math.Max(y0, frame.MinPoint.Y + frameMargin);
y1 = Math.Min(y1, frame.MaxPoint.Y - frameMargin);
}
}
catch { }
if (y1 <= y0)
{
y0 = oy;
y1 = oy + H;
}
var centerLine = new Line(new Point3d(ctx.Center.X, y0, 0), new Point3d(ctx.Center.X, y1, 0));
ctx.Style?.Apply(centerLine, DrawingStyleManager.Role.Centerline);
ctx.Btr.AppendEntity(centerLine);
ctx.Tr.AddNewlyCreatedDBObject(centerLine, true);
var diaPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameterPrime);
var heightPrime = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1Prime);
// 直径标注
var diaTolPlus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameterTolPlus);
var diaTolMinus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyDiameterTolMinus);
var diameterStr = bag.GetString(FeatureDrivenDrawer.KeyDiameter);
var diaTolPlusStr = bag.GetString(FeatureDrivenDrawer.KeyDiameterTolPlus);
var diaTolMinusStr = bag.GetString(FeatureDrivenDrawer.KeyDiameterTolMinus);
var diaDimText = BuildDimensionText($"%%c{FormatDimNumber(diameter.Value, diameterStr)}", diaTolPlus, diaTolMinus, diaTolPlusStr, diaTolMinusStr);
if (diaPrime.HasValue && diaPrime.Value > 0)
{
diaDimText += $"\\X(%%c{FormatDimNumber(diaPrime.Value)})";
}
// 为避免标注界线悬空,根据 r 的存在小幅调整起点
AddLinearDim(ctx, new Point3d(ox, oy + r, 0), new Point3d(ox + diameter.Value, oy + r, 0),
new Point3d(ctx.Center.X, oy - 20, 0), 0, diaDimText);
// 高度标注
var htTolPlus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1TolPlus);
var htTolMinus = bag.GetDoubleOrNull(FeatureDrivenDrawer.KeyHeight1TolMinus);
var heightStr = bag.GetString(FeatureDrivenDrawer.KeyHeight1);
var htTolPlusStr = bag.GetString(FeatureDrivenDrawer.KeyHeight1TolPlus);
var htTolMinusStr = bag.GetString(FeatureDrivenDrawer.KeyHeight1TolMinus);
var htDimText = BuildDimensionText(FormatDimNumber(H, heightStr), htTolPlus, htTolMinus, htTolPlusStr, htTolMinusStr);
if (heightPrime.HasValue && heightPrime.Value > 0)
{
htDimText += $"\\X({FormatDimNumber(heightPrime.Value)})";
}
AddLinearDim(ctx, new Point3d(ox + diameter.Value - r, oy, 0), new Point3d(ox + diameter.Value - r, oy + H, 0),
new Point3d(ox + diameter.Value + 20, ctx.Center.Y, 0), 90, htDimText);
// 添加未注圆角文字标注
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
{
DrawUnspecifiedFilletNote(ctx, ox, oy + H, R, diameter.Value, unspecifiedFillet.Value);
}
// 零件轮廓(如果有)
if (diaPrime.HasValue && diaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0)
{
DrawDiskPartContour(ctx, ox, oy, diameter.Value, H, diaPrime.Value, heightPrime.Value);
}
// 标刻内容
var markingText = bag.GetString(FeatureDrivenDrawer.KeyMarkingContent);
if (!string.IsNullOrWhiteSpace(markingText))
{
double flatHalfWidth = (diameter.Value / 2.0) - r;
double offset = Math.Min(15.0, flatHalfWidth * 0.8);
double xTarget = ctx.Center.X - offset;
double yTarget = oy + H;
FeatureDrivenDrawer.DrawSpecialHBLeaderToTop(ctx, xTarget, yTarget, markingText);
}
// 硬度符号
var hardnessVal = bag.GetString(FeatureDrivenDrawer.KeyHardness);
if (!string.IsNullOrWhiteSpace(hardnessVal) && hardnessVal != "空")
{
double flatHalfWidth = (diameter.Value / 2.0) - r;
double offset = Math.Min(15.0, flatHalfWidth * 0.8);
double xHardness = ctx.Center.X + offset;
double yHardness = oy;
FeatureDrivenDrawer.DrawHardnessSymbol(ctx, xHardness, yHardness, hardnessVal);
}
}
private static void DrawDiskPartContour(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy,
double forgingDia, double forgingH, double partDia, double partH)
{
double offsetX = (forgingDia - partDia) / 2.0;
double offsetY = (forgingH - partH) / 2.0;
var polyPart = new Polyline();
polyPart.AddVertexAt(0, new Point2d(ox + offsetX, oy + offsetY), 0, 0, 0);
polyPart.AddVertexAt(1, new Point2d(ox + offsetX + partDia, oy + offsetY), 0, 0, 0);
polyPart.AddVertexAt(2, new Point2d(ox + offsetX + partDia, oy + offsetY + partH), 0, 0, 0);
polyPart.AddVertexAt(3, new Point2d(ox + offsetX, oy + offsetY + partH), 0, 0, 0);
polyPart.Closed = true;
ctx.Style?.Apply(polyPart, DrawingStyleManager.Role.PartContour);
ctx.Btr.AppendEntity(polyPart);
ctx.Tr.AddNewlyCreatedDBObject(polyPart, true);
}
private static void DrawUnspecifiedFilletNote(FeatureDrivenDrawer.DrawingContext ctx, double ox, double oy, double R, double height, double filletR)
{
try
{
// Try to get original value to avoid scaling
var val = filletR;
if (ctx.OriginalBag != null)
{
double? original = ctx.OriginalBag.GetDoubleOrNull(FeatureDrivenDrawer.KeyUnspecifiedFilletRadiusMax);
if (original.HasValue) val = original.Value;
}
var text = new DBText();
text.TextString = $"未注圆角半径R≤{val}";
// Position logic copied from FeatureDrivenDrawer (may need adjustment if generic logic was weird)
// In FeatureDrivenDrawer: text.Position = new Point3d(ox + height + 10, oy + R + 15, 0);
// ox, oy passed in were Top Left or similar?
// In DrawDiskFeatures: DrawUnspecifiedFilletNote(ctx, ox, oy + H, R, diameter.Value, unspecifiedFillet.Value);
// ox is Left X. oy+H is Top Y.
// R passed is Radius (Diameter/2). height passed is Diameter (Circle diameter?).
// Let's verify arguments in DrawDiskFeatures call:
// DrawUnspecifiedFilletNote(ctx, ox, oy + H, R, diameter.Value, unspecifiedFillet.Value);
// Arg3 (R) = R (Radius). Arg4 (height) = diameter.
// Inside DrawUnspecifiedFilletNote:
// Position = new Point3d(ox + height + 10, oy + R + 15, 0);
// ox + diameter + 10 -> Right of the drawing.
// oy + R + 15 -> Top Y + Radius + 15 -> Above the drawing?
text.Position = new Point3d(ox + height + 10, oy + R + 15, 0);
text.Height = 5;
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
ctx.Btr.AppendEntity(text);
ctx.Tr.AddNewlyCreatedDBObject(text, true);
}
catch
{
// ignore
}
}
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;
}
// --- Helper Methods Copied for Isolation ---
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 string FormatDimNumber(double value, string rawInput = null)
{
try
{
if (!string.IsNullOrWhiteSpace(rawInput) && double.TryParse(rawInput, out var d) && Math.Abs(d - value) < 0.000001)
{
int decIndex = rawInput.IndexOf('.');
int decimals = 0;
if (decIndex >= 0)
{
decimals = rawInput.Length - decIndex - 1;
}
if (decimals == 0) return value.ToString("0");
return value.ToString("0." + new string('0', decimals));
}
string str = value.ToString("0.##########");
int decimalIndex = str.IndexOf('.');
if (decimalIndex < 0)
{
return str;
}
int autoDecimals = str.Length - decimalIndex - 1;
if (autoDecimals == 0) return str;
string format = "0." + new string('0', autoDecimals);
return value.ToString(format);
}
catch
{
return value.ToString();
}
}
private static string BuildDimensionText(string baseText, double? tolPlus, double? tolMinus, string tolPlusStr = null, string tolMinusStr = null)
{
if (!tolPlus.HasValue && !tolMinus.HasValue)
{
return baseText;
}
bool isSymmetrical = false;
if (tolPlus.HasValue && tolMinus.HasValue)
{
if (Math.Abs(Math.Abs(tolPlus.Value) - Math.Abs(tolMinus.Value)) < 0.000001)
{
isSymmetrical = true;
}
}
if (isSymmetrical)
{
var val = Math.Abs(tolPlus.Value);
return $"{baseText}%%p{FormatDimNumber(val, tolPlusStr)}";
}
const double tolScale = 0.7;
var plusStr = string.Empty;
var minusStr = string.Empty;
if (tolPlus.HasValue)
{
plusStr = tolPlus.Value >= 0
? $"+{FormatDimNumber(tolPlus.Value, tolPlusStr)}"
: $"{FormatDimNumber(tolPlus.Value, tolPlusStr)}";
}
if (tolMinus.HasValue)
{
double vm = tolMinus.Value;
string formattedVal = FormatDimNumber(Math.Abs(vm), tolMinusStr);
if (Math.Abs(vm) < 0.000001)
{
minusStr = formattedVal;
}
else
{
minusStr = $"-{formattedVal}";
}
}
if (tolPlus.HasValue && tolMinus.HasValue)
{
return $"{baseText} {{\\H{tolScale}x;\\S{plusStr}^{minusStr};}}";
}
var single = tolPlus.HasValue ? plusStr : minusStr;
return $"{baseText} {{\\H{tolScale}x;{single}}}";
}
}
}