2243 lines
94 KiB
C#
2243 lines
94 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Autodesk.AutoCAD.DatabaseServices;
|
||
using Autodesk.AutoCAD.Geometry;
|
||
using CadParamPluging.Common;
|
||
|
||
namespace CadParamPluging.Cad
|
||
{
|
||
/// <summary>
|
||
/// 特征驱动绘图引擎 - 根据参数存在性动态绘制图形
|
||
/// </summary>
|
||
public static class FeatureDrivenDrawer
|
||
{
|
||
#region 参数Key常量
|
||
|
||
// 环形参数
|
||
public const string KeyOuterDiameter1 = "OuterDiameter1";
|
||
public const string KeyOuterDiameter1TolPlus = "OuterDiameter1TolPlus";
|
||
public const string KeyOuterDiameter1TolMinus = "OuterDiameter1TolMinus";
|
||
public const string KeyInnerDiameter2 = "InnerDiameter2";
|
||
public const string KeyInnerDiameter2TolPlus = "InnerDiameter2TolPlus";
|
||
public const string KeyInnerDiameter2TolMinus = "InnerDiameter2TolMinus";
|
||
public const string KeyHeight1 = "Height1";
|
||
public const string KeyHeight1TolPlus = "Height1TolPlus";
|
||
public const string KeyHeight1TolMinus = "Height1TolMinus";
|
||
public const string KeyMinWallThickness = "MinWallThickness";
|
||
public const string KeyUnspecifiedFilletRadiusMax = "UnspecifiedFilletRadiusMax"; // 环形未注圆角
|
||
public const string KeyInnerRadiusMax = "InnerRadiusMax"; // 内径半径R≤(中心冲孔)
|
||
|
||
// 环形零件尺寸(车加工态)
|
||
public const string KeyOuterDiameter1Prime = "OuterDiameter1Prime";
|
||
public const string KeyInnerDiameter2Prime = "InnerDiameter2Prime";
|
||
public const string KeyHeight1Prime = "Height1Prime";
|
||
|
||
// 饼盘参数
|
||
public const string KeyDiskDiameter = "DiskDiameter";
|
||
public const string KeyDiskDiameterTolPlus = "DiskDiameterTolPlus";
|
||
public const string KeyDiskDiameterTolMinus = "DiskDiameterTolMinus";
|
||
public const string KeyDiskHeight = "DiskHeight";
|
||
public const string KeyDiskHeightTolPlus = "DiskHeightTolPlus";
|
||
public const string KeyDiskHeightTolMinus = "DiskHeightTolMinus";
|
||
public const string KeyDiskFilletRadiusMax = "DiskFilletRadiusMax"; // 饼盘未注圆角
|
||
public const string KeyDiskDiameterPrime = "DiskDiameterPrime"; // 饼盘零件直径
|
||
public const string KeyDiskHeightPrime = "DiskHeightPrime"; // 饼盘零件高度
|
||
|
||
// 轴杆参数(圆轴)
|
||
public const string KeyDiameter = "Diameter";
|
||
public const string KeyDiameterTolPlus = "DiameterTolPlus";
|
||
public const string KeyDiameterTolMinus = "DiameterTolMinus";
|
||
public const string KeyLength = "Length";
|
||
public const string KeyLengthTolPlus = "LengthTolPlus";
|
||
public const string KeyLengthTolMinus = "LengthTolMinus";
|
||
public const string KeyShaftFilletRadiusMax = "ShaftFilletRadiusMax"; // 轴杆未注圆角
|
||
public const string KeyDiameterPrime = "DiameterPrime"; // 轴杆零件直径
|
||
public const string KeyLengthPrime = "LengthPrime"; // 轴杆零件长度
|
||
|
||
// 方体参数
|
||
public const string KeyBoxSize1 = "BoxSize1";
|
||
public const string KeyBoxSize1TolPlus = "BoxSize1TolPlus";
|
||
public const string KeyBoxSize1TolMinus = "BoxSize1TolMinus";
|
||
public const string KeyBoxSize2 = "BoxSize2";
|
||
public const string KeyBoxSize2TolPlus = "BoxSize2TolPlus";
|
||
public const string KeyBoxSize2TolMinus = "BoxSize2TolMinus";
|
||
public const string KeyBoxSize3 = "BoxSize3";
|
||
public const string KeyBoxSize3TolPlus = "BoxSize3TolPlus";
|
||
public const string KeyBoxSize3TolMinus = "BoxSize3TolMinus";
|
||
public const string KeyBoxFilletRadiusMax = "BoxFilletRadiusMax"; // 方体未注圆角
|
||
public const string KeyBoxRoundHeadFilletRadiusMax = "BoxRoundHeadFilletRadiusMax"; // 方体圆头处圆角
|
||
public const string KeyBoxSize1Prime = "BoxSize1Prime"; // 方体零件尺寸1
|
||
public const string KeyBoxSize2Prime = "BoxSize2Prime"; // 方体零件尺寸2
|
||
public const string KeyBoxSize3Prime = "BoxSize3Prime"; // 方体零件尺寸3
|
||
|
||
#endregion
|
||
|
||
#region 绘图上下文
|
||
|
||
public class DrawingContext
|
||
{
|
||
public CadContext Ctx { get; set; }
|
||
public ParamBag Bag { get; set; }
|
||
public ParamBag OriginalBag { get; set; }
|
||
public Point3d Center { get; set; }
|
||
public string DeliveryStatus { get; set; }
|
||
public string StructuralFeature { get; set; }
|
||
public string SpecialCondition { get; set; }
|
||
public string ProcessMethod { get; set; }
|
||
|
||
internal DrawingStyleManager Style { get; set; }
|
||
|
||
public Database Db => Ctx?.Database;
|
||
public Transaction Tr => Ctx?.Transaction;
|
||
public BlockTableRecord Btr { get; set; }
|
||
|
||
public bool IsMachined => !string.IsNullOrWhiteSpace(DeliveryStatus)
|
||
&& DeliveryStatus.IndexOf("车加工", StringComparison.OrdinalIgnoreCase) >= 0;
|
||
|
||
public bool IsCenterPunched => !string.IsNullOrWhiteSpace(SpecialCondition)
|
||
&& SpecialCondition.IndexOf("中心冲孔", StringComparison.OrdinalIgnoreCase) >= 0;
|
||
|
||
public bool HasRoundHead => !string.IsNullOrWhiteSpace(SpecialCondition)
|
||
&& SpecialCondition.IndexOf("有圆头", StringComparison.OrdinalIgnoreCase) >= 0;
|
||
|
||
/// <summary>
|
||
/// 是否为轧制工艺(轧制时只画右半边图)
|
||
/// </summary>
|
||
public bool IsRolling => !string.IsNullOrWhiteSpace(ProcessMethod)
|
||
&& ProcessMethod.IndexOf("轧制", StringComparison.OrdinalIgnoreCase) >= 0;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 预期图形尺寸计算
|
||
|
||
/// <summary>
|
||
/// 预期图形尺寸
|
||
/// </summary>
|
||
public class ExpectedDrawingSize
|
||
{
|
||
public double Width { get; set; }
|
||
public double Height { get; set; }
|
||
public bool IsValid => Width > 0 && Height > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据参数计算预期绘制图形的尺寸(不包含标注,仅计算图形主体)
|
||
/// </summary>
|
||
public static ExpectedDrawingSize CalculateExpectedSize(ParamBag bag, string structuralFeature)
|
||
{
|
||
if (bag == null)
|
||
{
|
||
return new ExpectedDrawingSize();
|
||
}
|
||
|
||
if (IsRing(structuralFeature))
|
||
{
|
||
return CalculateRingSize(bag);
|
||
}
|
||
if (IsDisk(structuralFeature))
|
||
{
|
||
return CalculateDiskSize(bag);
|
||
}
|
||
if (IsShaft(structuralFeature))
|
||
{
|
||
return CalculateShaftSize(bag);
|
||
}
|
||
if (IsBlock(structuralFeature))
|
||
{
|
||
return CalculateBlockSize(bag);
|
||
}
|
||
|
||
return new ExpectedDrawingSize();
|
||
}
|
||
|
||
private static ExpectedDrawingSize CalculateRingSize(ParamBag bag)
|
||
{
|
||
var outerDia = bag.GetDoubleOrNull(KeyOuterDiameter1) ?? 0;
|
||
var height = bag.GetDoubleOrNull(KeyHeight1) ?? 0;
|
||
|
||
// 环形图形:宽度=外径(X方向),高度=高度参数(Y方向)
|
||
// 加上标注的额外空间(约40像素每侧)
|
||
var extraMargin = 40;
|
||
return new ExpectedDrawingSize
|
||
{
|
||
Width = outerDia + extraMargin * 2,
|
||
Height = height + extraMargin * 2
|
||
};
|
||
}
|
||
|
||
private static ExpectedDrawingSize CalculateDiskSize(ParamBag bag)
|
||
{
|
||
var diameter = bag.GetDoubleOrNull(KeyDiskDiameter) ?? 0;
|
||
var height = bag.GetDoubleOrNull(KeyDiskHeight) ?? 0;
|
||
|
||
var extraMargin = 40;
|
||
return new ExpectedDrawingSize
|
||
{
|
||
Width = diameter + extraMargin * 2,
|
||
Height = height + extraMargin * 2
|
||
};
|
||
}
|
||
|
||
private static ExpectedDrawingSize CalculateShaftSize(ParamBag bag)
|
||
{
|
||
var diameter = bag.GetDoubleOrNull(KeyDiameter) ?? 0;
|
||
var length = bag.GetDoubleOrNull(KeyLength) ?? 0;
|
||
|
||
var extraMargin = 40;
|
||
return new ExpectedDrawingSize
|
||
{
|
||
Width = length + extraMargin * 2,
|
||
Height = diameter + extraMargin * 2
|
||
};
|
||
}
|
||
|
||
private static ExpectedDrawingSize CalculateBlockSize(ParamBag bag)
|
||
{
|
||
var size1 = bag.GetDoubleOrNull(KeyBoxSize1) ?? 0;
|
||
var size2 = bag.GetDoubleOrNull(KeyBoxSize2) ?? size1;
|
||
|
||
var extraMargin = 40;
|
||
return new ExpectedDrawingSize
|
||
{
|
||
Width = size1 + extraMargin * 2,
|
||
Height = size2 + extraMargin * 2
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 主入口
|
||
|
||
/// <summary>
|
||
/// 绘制图形(带缩放支持)
|
||
/// </summary>
|
||
/// <param name="ctx">CAD上下文</param>
|
||
/// <param name="bag">参数包</param>
|
||
/// <param name="deliveryStatus">交付状态</param>
|
||
/// <param name="structuralFeature">结构特征</param>
|
||
/// <param name="specialCondition">特殊条件</param>
|
||
/// <param name="processMethod">工艺方法(轧制/自由锻)</param>
|
||
/// <param name="center">绘图中心点</param>
|
||
/// <param name="scaleFactor">缩放比例(1.0表示不缩放)</param>
|
||
public static void Draw(CadContext ctx, ParamBag bag, string deliveryStatus, string structuralFeature,
|
||
string specialCondition = null, string processMethod = null, Point3d? center = null, 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;
|
||
|
||
// Important: templates & cleanup operate on ModelSpace; draw there to avoid PaperSpace-related dimension issues.
|
||
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 DrawingContext
|
||
{
|
||
Ctx = ctx,
|
||
Bag = effectiveBag,
|
||
OriginalBag = bag,
|
||
Center = center ?? Point3d.Origin,
|
||
DeliveryStatus = deliveryStatus,
|
||
StructuralFeature = structuralFeature,
|
||
SpecialCondition = specialCondition,
|
||
ProcessMethod = processMethod,
|
||
Btr = btr,
|
||
Style = new DrawingStyleManager(db, tr)
|
||
};
|
||
|
||
// 根据结构特征分发到对应绘制器
|
||
if (IsRing(structuralFeature))
|
||
{
|
||
DrawRingFeatures(context);
|
||
}
|
||
else if (IsDisk(structuralFeature))
|
||
{
|
||
DrawDiskFeatures(context);
|
||
}
|
||
else if (IsShaft(structuralFeature))
|
||
{
|
||
DrawShaftFeatures(context);
|
||
}
|
||
else if (IsBlock(structuralFeature))
|
||
{
|
||
DrawBlockFeatures(context);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 结构特征判断
|
||
|
||
private static bool IsRing(string feature)
|
||
{
|
||
return !string.IsNullOrWhiteSpace(feature)
|
||
&& feature.IndexOf("环形", StringComparison.OrdinalIgnoreCase) >= 0;
|
||
}
|
||
|
||
private static bool IsDisk(string feature)
|
||
{
|
||
return !string.IsNullOrWhiteSpace(feature)
|
||
&& (feature.IndexOf("饼盘", StringComparison.OrdinalIgnoreCase) >= 0
|
||
|| feature.IndexOf("饼", StringComparison.OrdinalIgnoreCase) >= 0
|
||
|| feature.IndexOf("盘", StringComparison.OrdinalIgnoreCase) >= 0);
|
||
}
|
||
|
||
private static bool IsShaft(string feature)
|
||
{
|
||
return !string.IsNullOrWhiteSpace(feature)
|
||
&& (feature.IndexOf("轴杆", StringComparison.OrdinalIgnoreCase) >= 0
|
||
|| feature.IndexOf("轴", StringComparison.OrdinalIgnoreCase) >= 0
|
||
|| feature.IndexOf("杆", StringComparison.OrdinalIgnoreCase) >= 0);
|
||
}
|
||
|
||
private static bool IsBlock(string feature)
|
||
{
|
||
return !string.IsNullOrWhiteSpace(feature)
|
||
&& feature.IndexOf("方体", StringComparison.OrdinalIgnoreCase) >= 0;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 环形绘制 - 特征驱动
|
||
|
||
private static void DrawRingFeatures(DrawingContext ctx)
|
||
{
|
||
var bag = ctx.Bag;
|
||
|
||
// 必需参数检测
|
||
var outerDia = bag.GetDoubleOrNull(KeyOuterDiameter1);
|
||
var height = bag.GetDoubleOrNull(KeyHeight1);
|
||
|
||
if (!outerDia.HasValue || outerDia.Value <= 0)
|
||
{
|
||
return; // 缺少外径,无法绘制
|
||
}
|
||
|
||
if (!height.HasValue || height.Value <= 0)
|
||
{
|
||
return; // 缺少高度,无法绘制
|
||
}
|
||
|
||
// 判断是轧制还是自由锻
|
||
if (ctx.IsRolling)
|
||
{
|
||
// 轧制:只画右半边图
|
||
DrawRingFeaturesHalf(ctx, outerDia.Value, height.Value);
|
||
}
|
||
else
|
||
{
|
||
// 自由锻:画全图
|
||
DrawRingFeaturesFull(ctx, outerDia.Value, height.Value);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制工艺 - 只画右半边图
|
||
/// </summary>
|
||
private static void DrawRingFeaturesHalf(DrawingContext ctx, double outerDia, double height)
|
||
{
|
||
var bag = ctx.Bag;
|
||
double R = outerDia / 2.0; // 外半径
|
||
double H = height;
|
||
|
||
// 轧制时图形只画右半边,但要保持居中
|
||
// 半图宽度为R,要居中则起点为 Center.X - R/2
|
||
double ox = ctx.Center.X - R / 2.0; // 对称轴位置(左边界)
|
||
double oy = ctx.Center.Y - H / 2.0;
|
||
|
||
// 车加工态零件尺寸
|
||
double? outerDiaPrime = null;
|
||
double? innerDiaPrime = null;
|
||
double? heightPrime = null;
|
||
if (ctx.IsMachined)
|
||
{
|
||
outerDiaPrime = bag.GetDoubleOrNull(KeyOuterDiameter1Prime);
|
||
innerDiaPrime = bag.GetDoubleOrNull(KeyInnerDiameter2Prime);
|
||
heightPrime = bag.GetDoubleOrNull(KeyHeight1Prime);
|
||
}
|
||
|
||
// === 特征1: 锻件外轮廓(右半边,三条边:下、右、上,左边开口) ===
|
||
DrawForgingOuterContourHalf(ctx, ox, oy, R, H);
|
||
|
||
// === 特征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);
|
||
|
||
// === 特征3: 内孔/内径(如果有内径参数) ===
|
||
var innerDia = bag.GetDoubleOrNull(KeyInnerDiameter2);
|
||
double? xInnerRight = null;
|
||
if (innerDia.HasValue && innerDia.Value > 0 && innerDia.Value < outerDia)
|
||
{
|
||
double innerR = innerDia.Value / 2.0;
|
||
xInnerRight = ox + innerR;
|
||
|
||
var innerTolPlus = bag.GetDoubleOrNull(KeyInnerDiameter2TolPlus);
|
||
var innerTolMinus = bag.GetDoubleOrNull(KeyInnerDiameter2TolMinus);
|
||
|
||
// 只画右侧内孔线
|
||
DrawInnerHoleHalf(ctx, ox, xInnerRight.Value, oy, H);
|
||
DrawInnerDiameterDimensionHalf(ctx, ox, xInnerRight.Value, oy, H, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime);
|
||
|
||
// === 特征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);
|
||
|
||
// 剖面左侧竖线应为粗实线(剖切边界)
|
||
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);
|
||
|
||
// === 特征6: 未注圆角 ===
|
||
var unspecifiedFillet = bag.GetDoubleOrNull(KeyUnspecifiedFilletRadiusMax);
|
||
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
|
||
{
|
||
DrawUnspecifiedFilletNote(ctx, ox, oy, H, R, 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);
|
||
}
|
||
|
||
// === 特征8: 零件轮廓(车加工态,右半边) ===
|
||
if (ctx.IsMachined && outerDiaPrime.HasValue && outerDiaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0)
|
||
{
|
||
DrawPartContourHalf(ctx, ox, oy, H, outerDiaPrime.Value, innerDiaPrime, heightPrime.Value);
|
||
}
|
||
|
||
// === 特征9: 硬度符号 ===
|
||
TryDrawHardnessSymbol(ctx, ox + R, oy, H);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 自由锻工艺 - 画全图
|
||
/// </summary>
|
||
private static void DrawRingFeaturesFull(DrawingContext ctx, double outerDia, double height)
|
||
{
|
||
var bag = ctx.Bag;
|
||
double W = outerDia;
|
||
double H = height;
|
||
double ox = ctx.Center.X - W / 2.0;
|
||
double oy = ctx.Center.Y - H / 2.0;
|
||
|
||
// 车加工态零件尺寸(用于括号尺寸与零件轮廓)
|
||
double? outerDiaPrime = null;
|
||
double? innerDiaPrime = null;
|
||
double? heightPrime = null;
|
||
if (ctx.IsMachined)
|
||
{
|
||
outerDiaPrime = bag.GetDoubleOrNull(KeyOuterDiameter1Prime);
|
||
innerDiaPrime = bag.GetDoubleOrNull(KeyInnerDiameter2Prime);
|
||
heightPrime = bag.GetDoubleOrNull(KeyHeight1Prime);
|
||
}
|
||
|
||
// === 特征1: 锻件外轮廓(必绘) ===
|
||
DrawForgingOuterContour(ctx, ox, oy, W, H);
|
||
|
||
// === 特征1.1: 中心线 ===
|
||
DrawRingCenterline(ctx, ox, oy, W, H);
|
||
|
||
// === 特征2: 外径公差标注(如果有公差参数) ===
|
||
var outerTolPlus = bag.GetDoubleOrNull(KeyOuterDiameter1TolPlus);
|
||
var outerTolMinus = bag.GetDoubleOrNull(KeyOuterDiameter1TolMinus);
|
||
DrawOuterDiameterDimension(ctx, ox, oy, W, outerDia, outerTolPlus, outerTolMinus, outerDiaPrime);
|
||
|
||
// === 特征3: 内孔/内径(如果有内径参数) ===
|
||
var innerDia = bag.GetDoubleOrNull(KeyInnerDiameter2);
|
||
double? xInnerLeft = null;
|
||
double? xInnerRight = null;
|
||
if (innerDia.HasValue && innerDia.Value > 0 && innerDia.Value < W)
|
||
{
|
||
xInnerLeft = ctx.Center.X - innerDia.Value / 2.0;
|
||
xInnerRight = ctx.Center.X + innerDia.Value / 2.0;
|
||
|
||
var innerTolPlus = bag.GetDoubleOrNull(KeyInnerDiameter2TolPlus);
|
||
var innerTolMinus = bag.GetDoubleOrNull(KeyInnerDiameter2TolMinus);
|
||
|
||
DrawInnerHole(ctx, xInnerLeft.Value, xInnerRight.Value, oy, H);
|
||
DrawInnerDiameterDimension(ctx, xInnerLeft.Value, xInnerRight.Value, oy, innerDia.Value, innerTolPlus, innerTolMinus, innerDiaPrime);
|
||
|
||
// === 特征4: 内径圆角(如果有内径半径R参数,且是中心冲孔) ===
|
||
var innerRadiusMax = bag.GetDoubleOrNull(KeyInnerRadiusMax);
|
||
if (innerRadiusMax.HasValue && innerRadiusMax.Value > 0 && ctx.IsCenterPunched)
|
||
{
|
||
DrawInnerFillets(ctx, xInnerLeft.Value, xInnerRight.Value, oy, H, innerRadiusMax.Value);
|
||
}
|
||
|
||
// === 特征4.1: 剖面线(仅剖切端部区域) ===
|
||
DrawRingSectionHatch(ctx, xInnerRight.Value, ox + W, oy, H);
|
||
|
||
// 剖面左侧竖线应为粗实线(剖切边界)
|
||
DrawSectionInnerBoundaryBold(ctx, xInnerRight.Value, oy, H);
|
||
}
|
||
|
||
// === 特征5: 高度标注 ===
|
||
var heightTolPlus = bag.GetDoubleOrNull(KeyHeight1TolPlus);
|
||
var heightTolMinus = bag.GetDoubleOrNull(KeyHeight1TolMinus);
|
||
DrawHeightDimension(ctx, ox, oy, W, H, heightTolPlus, heightTolMinus, heightPrime);
|
||
|
||
// === 特征6: 未注圆角(如果有该参数) ===
|
||
var unspecifiedFillet = bag.GetDoubleOrNull(KeyUnspecifiedFilletRadiusMax);
|
||
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
|
||
{
|
||
// 复用现有位置逻辑:右上角
|
||
DrawUnspecifiedFilletNote(ctx, ox, oy, H, W, unspecifiedFillet.Value);
|
||
}
|
||
|
||
// === 特征7: 最小壁厚min标注(如果有该参数) ===
|
||
var minWallThickness = bag.GetDoubleOrNull(KeyMinWallThickness);
|
||
if (minWallThickness.HasValue && minWallThickness.Value > 0 && xInnerRight.HasValue)
|
||
{
|
||
DrawMinWallThicknessNote(ctx, xInnerRight.Value, ox + W, oy, minWallThickness.Value);
|
||
}
|
||
|
||
// === 特征8: 零件轮廓(车加工态,双点划线) ===
|
||
if (ctx.IsMachined && outerDiaPrime.HasValue && outerDiaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0)
|
||
{
|
||
DrawPartContour(ctx, ctx.Center, outerDiaPrime.Value, innerDiaPrime, heightPrime.Value);
|
||
}
|
||
|
||
// === 特征9: 硬度符号(有要求才画) ===
|
||
TryDrawHardnessSymbol(ctx, ox + W, oy, H);
|
||
}
|
||
|
||
private static void DrawSectionInnerBoundaryBold(DrawingContext ctx, double x, double yBottom, double height)
|
||
{
|
||
try
|
||
{
|
||
var line = new Line(new Point3d(x, yBottom, 0), new Point3d(x, yBottom + height, 0));
|
||
ctx.Style?.Apply(line, DrawingStyleManager.Role.OutlineBold);
|
||
ctx.Btr.AppendEntity(line);
|
||
ctx.Tr.AddNewlyCreatedDBObject(line, true);
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
private static void DrawForgingOuterContour(DrawingContext ctx, double ox, double oy, double width, double height)
|
||
{
|
||
var poly = new Polyline();
|
||
poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0);
|
||
poly.AddVertexAt(1, new Point2d(ox + width, oy), 0, 0, 0);
|
||
poly.AddVertexAt(2, new Point2d(ox + width, oy + height), 0, 0, 0);
|
||
poly.AddVertexAt(3, new Point2d(ox, oy + height), 0, 0, 0);
|
||
poly.Closed = true;
|
||
|
||
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold);
|
||
|
||
ctx.Btr.AppendEntity(poly);
|
||
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
|
||
}
|
||
|
||
private static void DrawRingCenterline(DrawingContext ctx, double ox, double oy, double width, double height)
|
||
{
|
||
var cy = oy + height / 2.0;
|
||
var line = new Line(new Point3d(ox - 10, cy, 0), new Point3d(ox + width + 10, cy, 0));
|
||
ctx.Style?.Apply(line, DrawingStyleManager.Role.Centerline);
|
||
ctx.Btr.AppendEntity(line);
|
||
ctx.Tr.AddNewlyCreatedDBObject(line, true);
|
||
}
|
||
|
||
#region 轧制专用绘图方法(只画右半边)
|
||
|
||
/// <summary>
|
||
/// 轧制:绘制右半边外轮廓(开口多段线)
|
||
/// </summary>
|
||
private static void DrawForgingOuterContourHalf(DrawingContext ctx, double ox, double oy, double radius, double height)
|
||
{
|
||
// 右半边轮廓:下边、右边、上边(左边开口)
|
||
var poly = new Polyline();
|
||
poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0); // 左下(对称轴下端)
|
||
poly.AddVertexAt(1, new Point2d(ox + radius, oy), 0, 0, 0); // 右下
|
||
poly.AddVertexAt(2, new Point2d(ox + radius, oy + height), 0, 0, 0); // 右上
|
||
poly.AddVertexAt(3, new Point2d(ox, oy + height), 0, 0, 0); // 左上(对称轴上端)
|
||
poly.Closed = false; // 不闭合,左边开口
|
||
|
||
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold);
|
||
ctx.Btr.AppendEntity(poly);
|
||
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制:绘制对称轴(垂直中心线)
|
||
/// </summary>
|
||
private static void DrawRingSymmetryAxis(DrawingContext ctx, double ox, double oy, double height)
|
||
{
|
||
const double extend = 5.0; // 中心线在轮廓上下各延长一点(与其它中心线的延长量保持一致)
|
||
const double frameMargin = 5.0; // 避免越过图框边界
|
||
|
||
var y0 = oy - extend;
|
||
var y1 = oy + height + extend;
|
||
|
||
// 若能检测到白色外框,则把中心线端点夹在图框内(留出少量安全边距)。
|
||
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
|
||
{
|
||
// ignore
|
||
}
|
||
|
||
// 极端情况下(图框过小/检测异常导致端点反转)退回到原始高度。
|
||
if (y1 <= y0)
|
||
{
|
||
y0 = oy;
|
||
y1 = oy + height;
|
||
}
|
||
|
||
var line = new Line(new Point3d(ox, y0, 0), new Point3d(ox, y1, 0));
|
||
ctx.Style?.Apply(line, DrawingStyleManager.Role.Centerline);
|
||
ctx.Btr.AppendEntity(line);
|
||
ctx.Tr.AddNewlyCreatedDBObject(line, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制:外径标注(从对称轴到右边,标注在图形下方偏内)
|
||
/// </summary>
|
||
private static void DrawOuterDiameterDimensionHalf(DrawingContext ctx, double ox, double oy, double radius, double height,
|
||
double diameter, double? tolPlus, double? tolMinus, double? diameterPrime)
|
||
{
|
||
// Use OriginalBag for text display to avoid scaled values
|
||
var diameterVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1) ?? diameter;
|
||
var diameterStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1);
|
||
var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1TolPlus) ?? tolPlus;
|
||
var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1TolMinus) ?? tolMinus;
|
||
var tolPlusStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1TolPlus);
|
||
var tolMinusStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1TolMinus);
|
||
|
||
var diameterPrimeVal = diameterPrime;
|
||
if (ctx.OriginalBag != null)
|
||
{
|
||
var p = ctx.OriginalBag.GetDoubleOrNull(KeyOuterDiameter1Prime);
|
||
if (p.HasValue) diameterPrimeVal = p.Value;
|
||
}
|
||
|
||
var baseText = BuildDimensionText($"%%c{FormatDimNumber(diameterVal, diameterStr)}", tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr);
|
||
var dimText = diameterPrimeVal.HasValue && diameterPrimeVal.Value > 0
|
||
? baseText + $"\\X(%%c{FormatDimNumber(diameterPrimeVal.Value)})"
|
||
: baseText;
|
||
|
||
// 标注放在图形底部稍下方
|
||
AddLinearDim(
|
||
ctx,
|
||
new Point3d(ox, oy, 0),
|
||
new Point3d(ox + radius, oy, 0),
|
||
new Point3d(ox + radius / 2, oy - 25, 0),
|
||
0,
|
||
dimText,
|
||
ApplyHalfSideDimStyle);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制:只画右侧内孔线
|
||
/// </summary>
|
||
private static void DrawInnerHoleHalf(DrawingContext ctx, double oxAxis, double xInnerRight, double yBottom, double height)
|
||
{
|
||
var yTop = yBottom + height;
|
||
|
||
// 只画右侧内孔竖线
|
||
var lineRight = new Line(new Point3d(xInnerRight, yBottom, 0), new Point3d(xInnerRight, yTop, 0));
|
||
ctx.Style?.Apply(lineRight, DrawingStyleManager.Role.Hidden);
|
||
ctx.Btr.AppendEntity(lineRight);
|
||
ctx.Tr.AddNewlyCreatedDBObject(lineRight, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制:内径标注(从对称轴到右边内孔,放到下方并与最小壁厚标注共线)
|
||
/// </summary>
|
||
private static void DrawInnerDiameterDimensionHalf(DrawingContext ctx, double oxAxis, double xInnerRight, double yBottom, double height,
|
||
double diameter, double? tolPlus, double? tolMinus, double? diameterPrime)
|
||
{
|
||
// Use OriginalBag for text display
|
||
var diameterVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2) ?? diameter;
|
||
var diameterStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2);
|
||
var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2TolPlus) ?? tolPlus;
|
||
var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2TolMinus) ?? tolMinus;
|
||
var tolPlusStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2TolPlus);
|
||
var tolMinusStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2TolMinus);
|
||
|
||
var diameterPrimeVal = diameterPrime;
|
||
if (ctx.OriginalBag != null)
|
||
{
|
||
var p = ctx.OriginalBag.GetDoubleOrNull(KeyInnerDiameter2Prime);
|
||
if (p.HasValue) diameterPrimeVal = p.Value;
|
||
}
|
||
|
||
var baseText = BuildDimensionText($"%%c{FormatDimNumber(diameterVal, diameterStr)}", tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr);
|
||
var dimText = diameterPrimeVal.HasValue && diameterPrimeVal.Value > 0
|
||
? baseText + $"\\X(%%c{FormatDimNumber(diameterPrimeVal.Value)})"
|
||
: baseText;
|
||
|
||
double innerRadius = xInnerRight - oxAxis;
|
||
|
||
// 放到下方,并与最小壁厚(30min)同一条水平尺寸线(yBottom - 10)
|
||
var dimLineY = yBottom - 10;
|
||
AddLinearDim(
|
||
ctx,
|
||
new Point3d(oxAxis, yBottom, 0),
|
||
new Point3d(xInnerRight, yBottom, 0),
|
||
new Point3d(oxAxis + innerRadius / 2, dimLineY, 0),
|
||
0,
|
||
dimText,
|
||
ApplyHalfSideDimStyle);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制:只画右侧内径圆角
|
||
/// </summary>
|
||
private static void DrawInnerFilletsHalf(DrawingContext ctx, double xInnerRight, double yBottom, double height, double filletR)
|
||
{
|
||
var yTop = yBottom + height;
|
||
|
||
// 只画右侧两个圆角
|
||
// 右上角
|
||
DrawFilletArc(ctx, xInnerRight - filletR, yTop - filletR, filletR, 0, Math.PI / 2);
|
||
// 右下角
|
||
DrawFilletArc(ctx, xInnerRight - filletR, yBottom + filletR, filletR, Math.PI * 1.5, Math.PI * 2);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制:高度标注(在右侧)
|
||
/// </summary>
|
||
private static void DrawHeightDimensionHalf(DrawingContext ctx, double ox, double oy, double radius,
|
||
double height, double? tolPlus, double? tolMinus, double? heightPrime)
|
||
{
|
||
// Use OriginalBag for text display
|
||
var heightVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1) ?? height;
|
||
var heightStr = ctx.OriginalBag?.GetString(KeyHeight1);
|
||
var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1TolPlus) ?? tolPlus;
|
||
var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1TolMinus) ?? tolMinus;
|
||
var tolPlusStr = ctx.OriginalBag?.GetString(KeyHeight1TolPlus);
|
||
var tolMinusStr = ctx.OriginalBag?.GetString(KeyHeight1TolMinus);
|
||
|
||
var heightPrimeVal = heightPrime;
|
||
if (ctx.OriginalBag != null)
|
||
{
|
||
var p = ctx.OriginalBag.GetDoubleOrNull(KeyHeight1Prime);
|
||
if (p.HasValue) heightPrimeVal = p.Value;
|
||
}
|
||
|
||
var baseText = BuildDimensionText(FormatDimNumber(heightVal, heightStr), tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr);
|
||
var dimText = heightPrimeVal.HasValue && heightPrimeVal.Value > 0
|
||
? baseText + $"\\X({FormatDimNumber(heightPrimeVal.Value)})"
|
||
: baseText;
|
||
|
||
AddLinearDim(
|
||
ctx,
|
||
new Point3d(ox + radius, oy, 0),
|
||
new Point3d(ox + radius, oy + height, 0),
|
||
new Point3d(ox + radius + 20, oy + height / 2, 0),
|
||
90,
|
||
dimText);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 轧制:零件轮廓(右半边)
|
||
/// </summary>
|
||
private static void DrawPartContourHalf(DrawingContext ctx, double ox, double oy, double forgingHeight,
|
||
double outerDiaPrime, double? innerDiaPrime, double heightPrime)
|
||
{
|
||
var Rp = outerDiaPrime / 2.0;
|
||
var h = heightPrime;
|
||
|
||
// 零件轮廓居中于锻件轮廓内
|
||
var offsetY = (forgingHeight - h) / 2.0;
|
||
var y0 = oy + offsetY;
|
||
|
||
// 右半边零件轮廓(开口)
|
||
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.Closed = false; // 不闭合
|
||
ctx.Style?.Apply(polyPart, DrawingStyleManager.Role.PartContour);
|
||
ctx.Btr.AppendEntity(polyPart);
|
||
ctx.Tr.AddNewlyCreatedDBObject(polyPart, true);
|
||
|
||
// 右侧内径轮廓
|
||
if (innerDiaPrime.HasValue && innerDiaPrime.Value > 0 && innerDiaPrime.Value < outerDiaPrime)
|
||
{
|
||
var xiR = ox + innerDiaPrime.Value / 2.0;
|
||
var yTop = y0 + h;
|
||
|
||
var lineInner = new Line(new Point3d(xiR, y0, 0), new Point3d(xiR, yTop, 0));
|
||
ctx.Style?.Apply(lineInner, DrawingStyleManager.Role.PartContour);
|
||
ctx.Btr.AppendEntity(lineInner);
|
||
ctx.Tr.AddNewlyCreatedDBObject(lineInner, true);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
private static void DrawInnerHole(DrawingContext ctx, double xInnerLeft, double xInnerRight, double yBottom, double height)
|
||
{
|
||
var yTop = yBottom + height;
|
||
|
||
var lineLeft = new Line(new Point3d(xInnerLeft, yBottom, 0), new Point3d(xInnerLeft, yTop, 0));
|
||
ctx.Style?.Apply(lineLeft, DrawingStyleManager.Role.Hidden);
|
||
ctx.Btr.AppendEntity(lineLeft);
|
||
ctx.Tr.AddNewlyCreatedDBObject(lineLeft, true);
|
||
|
||
var lineRight = new Line(new Point3d(xInnerRight, yBottom, 0), new Point3d(xInnerRight, yTop, 0));
|
||
ctx.Style?.Apply(lineRight, DrawingStyleManager.Role.Hidden);
|
||
ctx.Btr.AppendEntity(lineRight);
|
||
ctx.Tr.AddNewlyCreatedDBObject(lineRight, true);
|
||
}
|
||
|
||
private static void DrawInnerFillets(DrawingContext ctx, double xInnerLeft, double xInnerRight, double yBottom, double height, double filletR)
|
||
{
|
||
// 在内径四角绘制圆角示意
|
||
var yTop = yBottom + height;
|
||
|
||
// 左上角
|
||
DrawFilletArc(ctx, xInnerLeft + filletR, yTop - filletR, filletR, Math.PI / 2, Math.PI);
|
||
// 左下角
|
||
DrawFilletArc(ctx, xInnerLeft + filletR, yBottom + filletR, filletR, Math.PI, Math.PI * 1.5);
|
||
// 右上角
|
||
DrawFilletArc(ctx, xInnerRight - filletR, yTop - filletR, filletR, 0, Math.PI / 2);
|
||
// 右下角
|
||
DrawFilletArc(ctx, xInnerRight - filletR, yBottom + filletR, filletR, Math.PI * 1.5, Math.PI * 2);
|
||
}
|
||
|
||
private static void DrawFilletArc(DrawingContext ctx, double cx, double cy, double r, double startAngle, double endAngle)
|
||
{
|
||
try
|
||
{
|
||
var arc = new Arc(new Point3d(cx, cy, 0), r, startAngle, endAngle);
|
||
ctx.Style?.Apply(arc, DrawingStyleManager.Role.OutlineThin);
|
||
ctx.Btr.AppendEntity(arc);
|
||
ctx.Tr.AddNewlyCreatedDBObject(arc, true);
|
||
}
|
||
catch
|
||
{
|
||
// 忽略圆弧创建错误
|
||
}
|
||
}
|
||
|
||
private static void DrawOuterDiameterDimension(DrawingContext ctx, double ox, double oy, double width,
|
||
double diameter, double? tolPlus, double? tolMinus, double? diameterPrime)
|
||
{
|
||
// Use OriginalBag for text display to avoid scaled values
|
||
var diameterVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1) ?? diameter;
|
||
var diameterStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1);
|
||
var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1TolPlus) ?? tolPlus;
|
||
var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyOuterDiameter1TolMinus) ?? tolMinus;
|
||
var tolPlusStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1TolPlus);
|
||
var tolMinusStr = ctx.OriginalBag?.GetString(KeyOuterDiameter1TolMinus);
|
||
|
||
var diameterPrimeVal = diameterPrime;
|
||
if (ctx.OriginalBag != null)
|
||
{
|
||
var p = ctx.OriginalBag.GetDoubleOrNull(KeyOuterDiameter1Prime);
|
||
if (p.HasValue) diameterPrimeVal = p.Value;
|
||
}
|
||
|
||
var baseText = BuildDimensionText($"%%c{FormatDimNumber(diameterVal, diameterStr)}", tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr);
|
||
var dimText = diameterPrimeVal.HasValue && diameterPrimeVal.Value > 0
|
||
? baseText + $"\\X(%%c{FormatDimNumber(diameterPrimeVal.Value)})"
|
||
: baseText;
|
||
|
||
AddLinearDim(
|
||
ctx,
|
||
new Point3d(ox, oy, 0),
|
||
new Point3d(ox + width, oy, 0),
|
||
new Point3d(ox + width / 2, oy - 40, 0),
|
||
0,
|
||
dimText);
|
||
}
|
||
|
||
private static void DrawInnerDiameterDimension(DrawingContext ctx, double xInnerLeft, double xInnerRight, double yBottom,
|
||
double diameter, double? tolPlus, double? tolMinus, double? diameterPrime)
|
||
{
|
||
// Use OriginalBag for text display
|
||
var diameterVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2) ?? diameter;
|
||
var diameterStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2);
|
||
var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2TolPlus) ?? tolPlus;
|
||
var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyInnerDiameter2TolMinus) ?? tolMinus;
|
||
var tolPlusStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2TolPlus);
|
||
var tolMinusStr = ctx.OriginalBag?.GetString(KeyInnerDiameter2TolMinus);
|
||
|
||
var diameterPrimeVal = diameterPrime;
|
||
if (ctx.OriginalBag != null)
|
||
{
|
||
var p = ctx.OriginalBag.GetDoubleOrNull(KeyInnerDiameter2Prime);
|
||
if (p.HasValue) diameterPrimeVal = p.Value;
|
||
}
|
||
|
||
var baseText = BuildDimensionText($"%%c{FormatDimNumber(diameterVal, diameterStr)}", tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr);
|
||
var dimText = diameterPrimeVal.HasValue && diameterPrimeVal.Value > 0
|
||
? baseText + $"\\X(%%c{FormatDimNumber(diameterPrimeVal.Value)})"
|
||
: baseText;
|
||
|
||
AddLinearDim(
|
||
ctx,
|
||
new Point3d(xInnerLeft, yBottom, 0),
|
||
new Point3d(xInnerRight, yBottom, 0),
|
||
new Point3d((xInnerLeft + xInnerRight) / 2, yBottom - 25, 0),
|
||
0,
|
||
dimText);
|
||
}
|
||
|
||
private static void DrawHeightDimension(DrawingContext ctx, double ox, double oy, double width,
|
||
double height, double? tolPlus, double? tolMinus, double? heightPrime)
|
||
{
|
||
// Use OriginalBag for text display
|
||
var heightVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1) ?? height;
|
||
var heightStr = ctx.OriginalBag?.GetString(KeyHeight1);
|
||
var tolPlusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1TolPlus) ?? tolPlus;
|
||
var tolMinusVal = ctx.OriginalBag?.GetDoubleOrNull(KeyHeight1TolMinus) ?? tolMinus;
|
||
var tolPlusStr = ctx.OriginalBag?.GetString(KeyHeight1TolPlus);
|
||
var tolMinusStr = ctx.OriginalBag?.GetString(KeyHeight1TolMinus);
|
||
|
||
var heightPrimeVal = heightPrime;
|
||
if (ctx.OriginalBag != null)
|
||
{
|
||
var p = ctx.OriginalBag.GetDoubleOrNull(KeyHeight1Prime);
|
||
if (p.HasValue) heightPrimeVal = p.Value;
|
||
}
|
||
|
||
var baseText = BuildDimensionText(FormatDimNumber(heightVal, heightStr), tolPlusVal, tolMinusVal, tolPlusStr, tolMinusStr);
|
||
var dimText = heightPrimeVal.HasValue && heightPrimeVal.Value > 0
|
||
? baseText + $"\\X({FormatDimNumber(heightPrimeVal.Value)})"
|
||
: baseText;
|
||
|
||
AddLinearDim(
|
||
ctx,
|
||
new Point3d(ox + width, oy, 0),
|
||
new Point3d(ox + width, oy + height, 0),
|
||
new Point3d(ox + width + 20, oy + height / 2, 0),
|
||
90,
|
||
dimText);
|
||
}
|
||
|
||
private static void DrawUnspecifiedFilletNote(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)
|
||
{
|
||
// Check likely keys (could be Ring, Disk, Shaft, Box)
|
||
// We don't strictly know which one triggered this call without passing key,
|
||
// but we can check the context or just check all if they are mutually exclusive or consistent.
|
||
// Or better, just check the one that corresponds to current feature type.
|
||
|
||
double? original = null;
|
||
if (FeatureDrivenDrawer.IsRing(ctx.StructuralFeature))
|
||
original = ctx.OriginalBag.GetDoubleOrNull(KeyUnspecifiedFilletRadiusMax);
|
||
else if (FeatureDrivenDrawer.IsDisk(ctx.StructuralFeature))
|
||
original = ctx.OriginalBag.GetDoubleOrNull(KeyDiskFilletRadiusMax);
|
||
else if (FeatureDrivenDrawer.IsShaft(ctx.StructuralFeature))
|
||
original = ctx.OriginalBag.GetDoubleOrNull(KeyShaftFilletRadiusMax);
|
||
else if (FeatureDrivenDrawer.IsBlock(ctx.StructuralFeature))
|
||
original = ctx.OriginalBag.GetDoubleOrNull(KeyBoxFilletRadiusMax);
|
||
|
||
if (original.HasValue) val = original.Value;
|
||
}
|
||
|
||
var text = new DBText();
|
||
text.TextString = $"未注圆角半径R≤{val}";
|
||
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
|
||
{
|
||
// 忽略
|
||
}
|
||
}
|
||
|
||
private static void DrawMinWallThicknessNote(DrawingContext ctx, double xInnerRight, double xOuterRight, double yBottom, double thickness)
|
||
{
|
||
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 + xOuterRight) / 2, yBottom - 10, 0),
|
||
0,
|
||
dimText);
|
||
}
|
||
|
||
private static void DrawPartContour(DrawingContext ctx, Point3d center,
|
||
double outerDiaPrime, double? innerDiaPrime, double heightPrime)
|
||
{
|
||
var w = outerDiaPrime;
|
||
var h = heightPrime;
|
||
|
||
var x0 = center.X - w / 2.0;
|
||
var y0 = center.Y - h / 2.0;
|
||
|
||
var polyPart = new Polyline();
|
||
polyPart.AddVertexAt(0, new Point2d(x0, y0), 0, 0, 0);
|
||
polyPart.AddVertexAt(1, new Point2d(x0 + w, y0), 0, 0, 0);
|
||
polyPart.AddVertexAt(2, new Point2d(x0 + w, y0 + h), 0, 0, 0);
|
||
polyPart.AddVertexAt(3, new Point2d(x0, y0 + h), 0, 0, 0);
|
||
polyPart.Closed = true;
|
||
ctx.Style?.Apply(polyPart, DrawingStyleManager.Role.PartContour);
|
||
ctx.Btr.AppendEntity(polyPart);
|
||
ctx.Tr.AddNewlyCreatedDBObject(polyPart, true);
|
||
|
||
// 内径(车加工态)轮廓
|
||
if (innerDiaPrime.HasValue && innerDiaPrime.Value > 0 && innerDiaPrime.Value < w)
|
||
{
|
||
var xiL = center.X - innerDiaPrime.Value / 2.0;
|
||
var xiR = center.X + innerDiaPrime.Value / 2.0;
|
||
var yTop = y0 + h;
|
||
|
||
var l1 = new Line(new Point3d(xiL, y0, 0), new Point3d(xiL, yTop, 0));
|
||
ctx.Style?.Apply(l1, DrawingStyleManager.Role.PartContour);
|
||
ctx.Btr.AppendEntity(l1);
|
||
ctx.Tr.AddNewlyCreatedDBObject(l1, true);
|
||
|
||
var l2 = new Line(new Point3d(xiR, y0, 0), new Point3d(xiR, yTop, 0));
|
||
ctx.Style?.Apply(l2, DrawingStyleManager.Role.PartContour);
|
||
ctx.Btr.AppendEntity(l2);
|
||
ctx.Tr.AddNewlyCreatedDBObject(l2, true);
|
||
}
|
||
}
|
||
|
||
private static void DrawRingSectionHatch(DrawingContext ctx, double xInnerRight, double xOuterRight, double yBottom, double height)
|
||
{
|
||
if (xOuterRight <= xInnerRight)
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 临时边界(用于剖面填充),填充后删除边界
|
||
var boundary = new Polyline();
|
||
boundary.AddVertexAt(0, new Point2d(xInnerRight, yBottom), 0, 0, 0);
|
||
boundary.AddVertexAt(1, new Point2d(xOuterRight, yBottom), 0, 0, 0);
|
||
boundary.AddVertexAt(2, new Point2d(xOuterRight, yBottom + height), 0, 0, 0);
|
||
boundary.AddVertexAt(3, new Point2d(xInnerRight, yBottom + height), 0, 0, 0);
|
||
boundary.Closed = true;
|
||
ctx.Btr.AppendEntity(boundary);
|
||
ctx.Tr.AddNewlyCreatedDBObject(boundary, true);
|
||
|
||
var hatch = new Hatch();
|
||
hatch.SetDatabaseDefaults();
|
||
hatch.Normal = new Vector3d(0, 0, 1);
|
||
hatch.Elevation = 0.0;
|
||
|
||
ctx.Btr.AppendEntity(hatch);
|
||
ctx.Tr.AddNewlyCreatedDBObject(hatch, true);
|
||
|
||
hatch.SetHatchPattern(HatchPatternType.PreDefined, "ANSI31");
|
||
hatch.PatternScale = 10;
|
||
hatch.PatternAngle = 0;
|
||
hatch.Associative = false;
|
||
ctx.Style?.Apply(hatch, DrawingStyleManager.Role.Hatch);
|
||
|
||
var ids = new ObjectIdCollection();
|
||
ids.Add(boundary.ObjectId);
|
||
hatch.AppendLoop(HatchLoopTypes.External, ids);
|
||
hatch.EvaluateHatch(true);
|
||
|
||
try
|
||
{
|
||
boundary.Erase(true);
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
private static string FormatDimNumber(double value, string rawInput = null)
|
||
{
|
||
try
|
||
{
|
||
// If rawInput is provided and matches the value, use its precision
|
||
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;
|
||
}
|
||
// Format: 0.00... based on count
|
||
// If decimals is 0, format is "0" (integer)
|
||
if (decimals == 0) return value.ToString("0");
|
||
return value.ToString("0." + new string('0', decimals));
|
||
}
|
||
|
||
// Fallback: auto-detect from value (strip trailing zeros)
|
||
string str = value.ToString("0.##########");
|
||
int decimalIndex = str.IndexOf('.');
|
||
if (decimalIndex < 0)
|
||
{
|
||
return str; // Integer, no decimal
|
||
}
|
||
|
||
// Get number of digits after decimal
|
||
int autoDecimals = str.Length - decimalIndex - 1;
|
||
|
||
// Construct format string
|
||
if (autoDecimals == 0) return str;
|
||
|
||
string format = "0." + new string('0', autoDecimals);
|
||
return value.ToString(format);
|
||
}
|
||
catch
|
||
{
|
||
return value.ToString();
|
||
}
|
||
}
|
||
|
||
private static void TryDrawHardnessSymbol(DrawingContext ctx, double xRight, double yBottom, double height)
|
||
{
|
||
if (ctx == null || ctx.Bag == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var raw = ctx.Bag.GetString("Hardness");
|
||
if (string.IsNullOrWhiteSpace(raw))
|
||
{
|
||
return;
|
||
}
|
||
|
||
var upper = raw.Trim().ToUpperInvariant();
|
||
string symbol;
|
||
if (upper.Contains("HB"))
|
||
{
|
||
symbol = "HB";
|
||
}
|
||
else if (upper.Contains("HRC"))
|
||
{
|
||
symbol = "HRC";
|
||
}
|
||
else if (upper.Contains("HV"))
|
||
{
|
||
symbol = "HV";
|
||
}
|
||
else
|
||
{
|
||
symbol = ExtractLeadingLetters(upper);
|
||
if (string.IsNullOrWhiteSpace(symbol))
|
||
{
|
||
symbol = "HB";
|
||
}
|
||
}
|
||
|
||
try
|
||
{
|
||
var attach = new Point3d(xRight - 2, yBottom + height * 0.25, 0);
|
||
var circleCenter = new Point3d(xRight + 25, yBottom + height * 0.25, 0);
|
||
const double circleR = 6;
|
||
|
||
var leader = new Line(attach, new Point3d(circleCenter.X - circleR, circleCenter.Y, 0));
|
||
ctx.Style?.Apply(leader, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(leader);
|
||
ctx.Tr.AddNewlyCreatedDBObject(leader, true);
|
||
|
||
var circle = new Circle(circleCenter, new Vector3d(0, 0, 1), circleR);
|
||
ctx.Style?.Apply(circle, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(circle);
|
||
ctx.Tr.AddNewlyCreatedDBObject(circle, true);
|
||
|
||
var text = new DBText();
|
||
text.TextString = symbol;
|
||
text.Height = 3.5;
|
||
text.HorizontalMode = TextHorizontalMode.TextCenter;
|
||
text.VerticalMode = TextVerticalMode.TextVerticalMid;
|
||
text.AlignmentPoint = circleCenter;
|
||
text.Position = circleCenter;
|
||
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(text);
|
||
ctx.Tr.AddNewlyCreatedDBObject(text, true);
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
private static string ExtractLeadingLetters(string s)
|
||
{
|
||
if (string.IsNullOrEmpty(s))
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
var chars = new List<char>();
|
||
foreach (var c in s)
|
||
{
|
||
if (c >= 'A' && c <= 'Z')
|
||
{
|
||
chars.Add(c);
|
||
}
|
||
else
|
||
{
|
||
if (chars.Count > 0)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return chars.Count == 0 ? string.Empty : new string(chars.ToArray());
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 饼盘绘制 - 特征驱动
|
||
|
||
private static void DrawDiskFeatures(DrawingContext ctx)
|
||
{
|
||
var bag = ctx.Bag;
|
||
|
||
var diameter = bag.GetDoubleOrNull(KeyDiskDiameter);
|
||
var height = bag.GetDoubleOrNull(KeyDiskHeight);
|
||
|
||
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 poly = new Polyline();
|
||
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);
|
||
|
||
// 直径标注
|
||
var diaTolPlus = bag.GetDoubleOrNull(KeyDiskDiameterTolPlus);
|
||
var diaTolMinus = bag.GetDoubleOrNull(KeyDiskDiameterTolMinus);
|
||
var diameterStr = bag.GetString(KeyDiskDiameter);
|
||
var diaTolPlusStr = bag.GetString(KeyDiskDiameterTolPlus);
|
||
var diaTolMinusStr = bag.GetString(KeyDiskDiameterTolMinus);
|
||
|
||
var diaDimText = BuildDimensionText($"%%c{FormatDimNumber(diameter.Value, diameterStr)}", diaTolPlus, diaTolMinus, diaTolPlusStr, diaTolMinusStr);
|
||
AddLinearDim(ctx, new Point3d(ox, oy, 0), new Point3d(ox + diameter.Value, oy, 0),
|
||
new Point3d(ctx.Center.X, oy - 20, 0), 0, diaDimText);
|
||
|
||
// 高度标注
|
||
var htTolPlus = bag.GetDoubleOrNull(KeyDiskHeightTolPlus);
|
||
var htTolMinus = bag.GetDoubleOrNull(KeyDiskHeightTolMinus);
|
||
var heightStr = bag.GetString(KeyDiskHeight);
|
||
var htTolPlusStr = bag.GetString(KeyDiskHeightTolPlus);
|
||
var htTolMinusStr = bag.GetString(KeyDiskHeightTolMinus);
|
||
|
||
var htDimText = BuildDimensionText(FormatDimNumber(H, heightStr), htTolPlus, htTolMinus, htTolPlusStr, htTolMinusStr);
|
||
AddLinearDim(ctx, new Point3d(ox + diameter.Value, oy, 0), new Point3d(ox + diameter.Value, oy + H, 0),
|
||
new Point3d(ox + diameter.Value + 20, ctx.Center.Y, 0), 90, htDimText);
|
||
|
||
// 未注圆角(使用饼盘专用Key)
|
||
var unspecifiedFillet = bag.GetDoubleOrNull(KeyDiskFilletRadiusMax);
|
||
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
|
||
{
|
||
DrawUnspecifiedFilletNote(ctx, ox, oy + H, R, diameter.Value, unspecifiedFillet.Value);
|
||
}
|
||
|
||
// 零件尺寸(如果有)
|
||
var diaPrime = bag.GetDoubleOrNull(KeyDiskDiameterPrime);
|
||
var heightPrime = bag.GetDoubleOrNull(KeyDiskHeightPrime);
|
||
if (diaPrime.HasValue && diaPrime.Value > 0 && heightPrime.HasValue && heightPrime.Value > 0)
|
||
{
|
||
DrawDiskPartContour(ctx, ox, oy, diameter.Value, H, diaPrime.Value, heightPrime.Value);
|
||
}
|
||
}
|
||
|
||
private static void DrawDiskPartContour(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);
|
||
|
||
// 不再对零件轮廓整块填充剖面线
|
||
|
||
// 零件直径标注
|
||
AddLinearDim(ctx, new Point3d(ox + offsetX, oy + offsetY, 0),
|
||
new Point3d(ox + offsetX + partDia, oy + offsetY, 0),
|
||
new Point3d(ox + offsetX + partDia / 2, oy + offsetY - 10, 0), 0, $"%%c{partDia}");
|
||
|
||
// 零件高度标注
|
||
AddLinearDim(ctx, new Point3d(ox + offsetX + partDia, oy + offsetY, 0),
|
||
new Point3d(ox + offsetX + partDia, oy + offsetY + partH, 0),
|
||
new Point3d(ox + offsetX + partDia + 10, oy + offsetY + partH / 2, 0), 90, $"{partH}");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 轴杆绘制 - 特征驱动
|
||
|
||
private static void DrawShaftFeatures(DrawingContext ctx)
|
||
{
|
||
var bag = ctx.Bag;
|
||
|
||
// 圆轴使用Diameter/Length,方轴使用BoxSize1/2/3
|
||
var isSquareShaft = !string.IsNullOrWhiteSpace(ctx.SpecialCondition)
|
||
&& ctx.SpecialCondition.IndexOf("方轴", StringComparison.OrdinalIgnoreCase) >= 0;
|
||
|
||
if (isSquareShaft)
|
||
{
|
||
// 方轴使用方体参数绘制
|
||
DrawSquareShaftFeatures(ctx);
|
||
return;
|
||
}
|
||
|
||
// 圆轴绘制
|
||
var diameter = bag.GetDoubleOrNull(KeyDiameter);
|
||
var length = bag.GetDoubleOrNull(KeyLength);
|
||
|
||
if (!diameter.HasValue || diameter.Value <= 0) return;
|
||
if (!length.HasValue || length.Value <= 0) return;
|
||
|
||
double ox = ctx.Center.X - length.Value / 2.0;
|
||
double oy = ctx.Center.Y;
|
||
double R = diameter.Value / 2.0;
|
||
double L = length.Value;
|
||
|
||
TryLoadLinetype(ctx.Db, ctx.Tr, "CENTER");
|
||
|
||
// 绘制轴杆轮廓(侧视图为矩形)
|
||
var poly = new Polyline();
|
||
poly.AddVertexAt(0, new Point2d(ox, oy - R), 0, 0, 0);
|
||
poly.AddVertexAt(1, new Point2d(ox + L, oy - R), 0, 0, 0);
|
||
poly.AddVertexAt(2, new Point2d(ox + L, oy + R), 0, 0, 0);
|
||
poly.AddVertexAt(3, new Point2d(ox, oy + R), 0, 0, 0);
|
||
poly.Closed = true;
|
||
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold);
|
||
|
||
ctx.Btr.AppendEntity(poly);
|
||
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
|
||
|
||
// 中心线
|
||
var centerLine = new Line(new Point3d(ox - 10, oy, 0), new Point3d(ox + L + 10, oy, 0));
|
||
ctx.Style?.Apply(centerLine, DrawingStyleManager.Role.Centerline);
|
||
ctx.Btr.AppendEntity(centerLine);
|
||
ctx.Tr.AddNewlyCreatedDBObject(centerLine, true);
|
||
|
||
// 直径标注
|
||
var diaTolPlus = bag.GetDoubleOrNull(KeyDiameterTolPlus);
|
||
var diaTolMinus = bag.GetDoubleOrNull(KeyDiameterTolMinus);
|
||
var diameterStr = bag.GetString(KeyDiameter);
|
||
var diaTolPlusStr = bag.GetString(KeyDiameterTolPlus);
|
||
var diaTolMinusStr = bag.GetString(KeyDiameterTolMinus);
|
||
|
||
var diaDimText = BuildDimensionText($"%%c{FormatDimNumber(diameter.Value, diameterStr)}", diaTolPlus, diaTolMinus, diaTolPlusStr, diaTolMinusStr);
|
||
AddLinearDim(ctx, new Point3d(ox, oy + R, 0), new Point3d(ox, oy - R, 0),
|
||
new Point3d(ox - 20, oy, 0), 90, diaDimText);
|
||
|
||
// 长度标注
|
||
var lenTolPlus = bag.GetDoubleOrNull(KeyLengthTolPlus);
|
||
var lenTolMinus = bag.GetDoubleOrNull(KeyLengthTolMinus);
|
||
var lengthStr = bag.GetString(KeyLength);
|
||
var lenTolPlusStr = bag.GetString(KeyLengthTolPlus);
|
||
var lenTolMinusStr = bag.GetString(KeyLengthTolMinus);
|
||
|
||
var lenDimText = BuildDimensionText(FormatDimNumber(L, lengthStr), lenTolPlus, lenTolMinus, lenTolPlusStr, lenTolMinusStr);
|
||
AddLinearDim(ctx, new Point3d(ox, oy - R, 0), new Point3d(ox + L, oy - R, 0),
|
||
new Point3d(ctx.Center.X, oy - R - 20, 0), 0, lenDimText);
|
||
|
||
// 未注圆角(使用轴杆专用Key)
|
||
var unspecifiedFillet = bag.GetDoubleOrNull(KeyShaftFilletRadiusMax);
|
||
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
|
||
{
|
||
DrawUnspecifiedFilletNote(ctx, ox, oy, R, L, unspecifiedFillet.Value);
|
||
}
|
||
|
||
// 零件尺寸(如果有)
|
||
var diaPrime = bag.GetDoubleOrNull(KeyDiameterPrime);
|
||
var lenPrime = bag.GetDoubleOrNull(KeyLengthPrime);
|
||
if (diaPrime.HasValue && diaPrime.Value > 0 && lenPrime.HasValue && lenPrime.Value > 0)
|
||
{
|
||
DrawShaftPartContour(ctx, ox, oy, R, L, diaPrime.Value, lenPrime.Value);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 方轴绘制(使用方体参数)
|
||
/// </summary>
|
||
private static void DrawSquareShaftFeatures(DrawingContext ctx)
|
||
{
|
||
var bag = ctx.Bag;
|
||
|
||
var size1 = bag.GetDoubleOrNull(KeyBoxSize1);
|
||
var size2 = bag.GetDoubleOrNull(KeyBoxSize2);
|
||
var size3 = bag.GetDoubleOrNull(KeyBoxSize3);
|
||
|
||
if (!size1.HasValue || size1.Value <= 0) return;
|
||
|
||
double width = size1.Value;
|
||
double height = size2.HasValue && size2.Value > 0 ? size2.Value : size1.Value;
|
||
double depth = size3.HasValue && size3.Value > 0 ? size3.Value : 0;
|
||
|
||
double ox = ctx.Center.X - width / 2.0;
|
||
double oy = ctx.Center.Y - height / 2.0;
|
||
|
||
// 绘制正视图(矩形)
|
||
var poly = new Polyline();
|
||
poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0);
|
||
poly.AddVertexAt(1, new Point2d(ox + width, oy), 0, 0, 0);
|
||
poly.AddVertexAt(2, new Point2d(ox + width, oy + height), 0, 0, 0);
|
||
poly.AddVertexAt(3, new Point2d(ox, oy + height), 0, 0, 0);
|
||
poly.Closed = true;
|
||
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold);
|
||
|
||
ctx.Btr.AppendEntity(poly);
|
||
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
|
||
|
||
// 尺寸1标注
|
||
var tol1Plus = bag.GetDoubleOrNull(KeyBoxSize1TolPlus);
|
||
var tol1Minus = bag.GetDoubleOrNull(KeyBoxSize1TolMinus);
|
||
var dim1Text = BuildDimensionText($"{width}", tol1Plus, tol1Minus);
|
||
AddLinearDim(ctx, new Point3d(ox, oy, 0), new Point3d(ox + width, oy, 0),
|
||
new Point3d(ctx.Center.X, oy - 20, 0), 0, dim1Text);
|
||
|
||
// 尺寸2标注
|
||
if (size2.HasValue && size2.Value > 0)
|
||
{
|
||
var tol2Plus = bag.GetDoubleOrNull(KeyBoxSize2TolPlus);
|
||
var tol2Minus = bag.GetDoubleOrNull(KeyBoxSize2TolMinus);
|
||
var dim2Text = BuildDimensionText($"{height}", tol2Plus, tol2Minus);
|
||
AddLinearDim(ctx, new Point3d(ox + width, oy, 0), new Point3d(ox + width, oy + height, 0),
|
||
new Point3d(ox + width + 20, ctx.Center.Y, 0), 90, dim2Text);
|
||
}
|
||
|
||
// 尺寸3标注
|
||
if (depth > 0)
|
||
{
|
||
var tol3Plus = bag.GetDoubleOrNull(KeyBoxSize3TolPlus);
|
||
var tol3Minus = bag.GetDoubleOrNull(KeyBoxSize3TolMinus);
|
||
var dim3Text = BuildDimensionText($"深度:{depth}", tol3Plus, tol3Minus);
|
||
try
|
||
{
|
||
var text = new DBText();
|
||
text.TextString = dim3Text;
|
||
text.Position = new Point3d(ox + width + 10, oy + height + 10, 0);
|
||
text.Height = 5;
|
||
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(text);
|
||
ctx.Tr.AddNewlyCreatedDBObject(text, true);
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
// 未注圆角(使用方体专用Key)
|
||
var unspecifiedFillet = bag.GetDoubleOrNull(KeyBoxFilletRadiusMax);
|
||
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
|
||
{
|
||
try
|
||
{
|
||
var text = new DBText();
|
||
text.TextString = $"未注圆角半径R≤{unspecifiedFillet.Value}";
|
||
text.Position = new Point3d(ox + width + 10, oy + height + 20, 0);
|
||
text.Height = 5;
|
||
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(text);
|
||
ctx.Tr.AddNewlyCreatedDBObject(text, true);
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
// 零件尺寸
|
||
var size1Prime = bag.GetDoubleOrNull(KeyBoxSize1Prime);
|
||
var size2Prime = bag.GetDoubleOrNull(KeyBoxSize2Prime);
|
||
var size3Prime = bag.GetDoubleOrNull(KeyBoxSize3Prime);
|
||
if (size1Prime.HasValue && size1Prime.Value > 0)
|
||
{
|
||
DrawBlockPartContour(ctx, ox, oy, width, height,
|
||
size1Prime.Value, size2Prime ?? size1Prime.Value, size3Prime);
|
||
}
|
||
}
|
||
|
||
private static void DrawShaftPartContour(DrawingContext ctx, double ox, double oy,
|
||
double R, double L, double partDia, double partLen)
|
||
{
|
||
double offsetX = (L - partLen) / 2.0;
|
||
double Rp = partDia / 2.0;
|
||
|
||
var polyPart = new Polyline();
|
||
polyPart.AddVertexAt(0, new Point2d(ox + offsetX, oy - Rp), 0, 0, 0);
|
||
polyPart.AddVertexAt(1, new Point2d(ox + offsetX + partLen, oy - Rp), 0, 0, 0);
|
||
polyPart.AddVertexAt(2, new Point2d(ox + offsetX + partLen, oy + Rp), 0, 0, 0);
|
||
polyPart.AddVertexAt(3, new Point2d(ox + offsetX, oy + Rp), 0, 0, 0);
|
||
polyPart.Closed = true;
|
||
ctx.Style?.Apply(polyPart, DrawingStyleManager.Role.PartContour);
|
||
|
||
ctx.Btr.AppendEntity(polyPart);
|
||
ctx.Tr.AddNewlyCreatedDBObject(polyPart, true);
|
||
|
||
// 不再对零件轮廓整块填充剖面线
|
||
|
||
// 零件直径标注
|
||
AddLinearDim(ctx, new Point3d(ox + offsetX, oy + Rp, 0), new Point3d(ox + offsetX, oy - Rp, 0),
|
||
new Point3d(ox + offsetX - 10, oy, 0), 90, $"%%c{partDia}");
|
||
|
||
// 零件长度标注
|
||
AddLinearDim(ctx, new Point3d(ox + offsetX, oy - Rp, 0), new Point3d(ox + offsetX + partLen, oy - Rp, 0),
|
||
new Point3d(ox + offsetX + partLen / 2, oy - Rp - 10, 0), 0, $"{partLen}");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 方形绘制 - 特征驱动
|
||
|
||
private static void DrawBlockFeatures(DrawingContext ctx)
|
||
{
|
||
var bag = ctx.Bag;
|
||
|
||
// 使用方体专用参数
|
||
var size1 = bag.GetDoubleOrNull(KeyBoxSize1);
|
||
var size2 = bag.GetDoubleOrNull(KeyBoxSize2);
|
||
var size3 = bag.GetDoubleOrNull(KeyBoxSize3);
|
||
|
||
if (!size1.HasValue || size1.Value <= 0) return;
|
||
|
||
// 默认为正方形或使用size1
|
||
double width = size1.Value;
|
||
double height = size2.HasValue && size2.Value > 0 ? size2.Value : size1.Value;
|
||
double depth = size3.HasValue && size3.Value > 0 ? size3.Value : 0;
|
||
|
||
double ox = ctx.Center.X - width / 2.0;
|
||
double oy = ctx.Center.Y - height / 2.0;
|
||
|
||
// 绘制正视图(矩形)
|
||
var poly = new Polyline();
|
||
poly.AddVertexAt(0, new Point2d(ox, oy), 0, 0, 0);
|
||
poly.AddVertexAt(1, new Point2d(ox + width, oy), 0, 0, 0);
|
||
poly.AddVertexAt(2, new Point2d(ox + width, oy + height), 0, 0, 0);
|
||
poly.AddVertexAt(3, new Point2d(ox, oy + height), 0, 0, 0);
|
||
poly.Closed = true;
|
||
ctx.Style?.Apply(poly, DrawingStyleManager.Role.OutlineBold);
|
||
|
||
ctx.Btr.AppendEntity(poly);
|
||
ctx.Tr.AddNewlyCreatedDBObject(poly, true);
|
||
|
||
// 宽度标注 (BoxSize1)
|
||
var tol1Plus = bag.GetDoubleOrNull(KeyBoxSize1TolPlus);
|
||
var tol1Minus = bag.GetDoubleOrNull(KeyBoxSize1TolMinus);
|
||
var widthStr = bag.GetString(KeyBoxSize1);
|
||
var tol1PlusStr = bag.GetString(KeyBoxSize1TolPlus);
|
||
var tol1MinusStr = bag.GetString(KeyBoxSize1TolMinus);
|
||
|
||
var dim1Text = BuildDimensionText(FormatDimNumber(width, widthStr), tol1Plus, tol1Minus, tol1PlusStr, tol1MinusStr);
|
||
AddLinearDim(ctx, new Point3d(ox, oy, 0), new Point3d(ox + width, oy, 0),
|
||
new Point3d(ctx.Center.X, oy - 20, 0), 0, dim1Text);
|
||
|
||
// 高度标注 (BoxSize2)
|
||
if (size2.HasValue && size2.Value > 0)
|
||
{
|
||
var tol2Plus = bag.GetDoubleOrNull(KeyBoxSize2TolPlus);
|
||
var tol2Minus = bag.GetDoubleOrNull(KeyBoxSize2TolMinus);
|
||
var heightStr = bag.GetString(KeyBoxSize2);
|
||
var tol2PlusStr = bag.GetString(KeyBoxSize2TolPlus);
|
||
var tol2MinusStr = bag.GetString(KeyBoxSize2TolMinus);
|
||
|
||
var dim2Text = BuildDimensionText(FormatDimNumber(height, heightStr), tol2Plus, tol2Minus, tol2PlusStr, tol2MinusStr);
|
||
AddLinearDim(ctx, new Point3d(ox + width, oy, 0), new Point3d(ox + width, oy + height, 0),
|
||
new Point3d(ox + width + 20, ctx.Center.Y, 0), 90, dim2Text);
|
||
}
|
||
|
||
// 深度标注 (BoxSize3) - 如果有的话,以文字形式标注
|
||
if (depth > 0)
|
||
{
|
||
var tol3Plus = bag.GetDoubleOrNull(KeyBoxSize3TolPlus);
|
||
var tol3Minus = bag.GetDoubleOrNull(KeyBoxSize3TolMinus);
|
||
var depthStr = bag.GetString(KeyBoxSize3);
|
||
var tol3PlusStr = bag.GetString(KeyBoxSize3TolPlus);
|
||
var tol3MinusStr = bag.GetString(KeyBoxSize3TolMinus);
|
||
|
||
var dim3Text = BuildDimensionText($"深度:{FormatDimNumber(depth, depthStr)}", tol3Plus, tol3Minus, tol3PlusStr, tol3MinusStr);
|
||
try
|
||
{
|
||
var text = new DBText();
|
||
text.TextString = dim3Text;
|
||
text.Position = new Point3d(ox + width + 10, oy + height + 10, 0);
|
||
text.Height = 5;
|
||
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(text);
|
||
ctx.Tr.AddNewlyCreatedDBObject(text, true);
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
// 未注圆角(使用方体专用Key)
|
||
var unspecifiedFillet = bag.GetDoubleOrNull(KeyBoxFilletRadiusMax);
|
||
if (unspecifiedFillet.HasValue && unspecifiedFillet.Value > 0)
|
||
{
|
||
try
|
||
{
|
||
var text = new DBText();
|
||
text.TextString = $"未注圆角半径R≤{unspecifiedFillet.Value}";
|
||
text.Position = new Point3d(ox + width + 10, oy + height + 20, 0);
|
||
text.Height = 5;
|
||
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(text);
|
||
ctx.Tr.AddNewlyCreatedDBObject(text, true);
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
// 有圆头时,绘制两端半圆形圆头
|
||
if (ctx.HasRoundHead)
|
||
{
|
||
double R = height / 2.0; // 圆头半径 = 高度/2(示意性)
|
||
double centerY = oy + height / 2.0;
|
||
|
||
// 左端圆头(半圆)
|
||
try
|
||
{
|
||
var arcLeft = new Arc(new Point3d(ox, centerY, 0), R, Math.PI / 2, Math.PI * 1.5);
|
||
ctx.Style?.Apply(arcLeft, DrawingStyleManager.Role.OutlineBold);
|
||
ctx.Btr.AppendEntity(arcLeft);
|
||
ctx.Tr.AddNewlyCreatedDBObject(arcLeft, true);
|
||
}
|
||
catch { }
|
||
|
||
// 右端圆头(半圆)
|
||
try
|
||
{
|
||
var arcRight = new Arc(new Point3d(ox + width, centerY, 0), R, -Math.PI / 2, Math.PI / 2);
|
||
ctx.Style?.Apply(arcRight, DrawingStyleManager.Role.OutlineBold);
|
||
ctx.Btr.AppendEntity(arcRight);
|
||
ctx.Tr.AddNewlyCreatedDBObject(arcRight, true);
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
// 零件尺寸
|
||
var size1Prime = bag.GetDoubleOrNull(KeyBoxSize1Prime);
|
||
var size2Prime = bag.GetDoubleOrNull(KeyBoxSize2Prime);
|
||
var size3Prime = bag.GetDoubleOrNull(KeyBoxSize3Prime);
|
||
if (size1Prime.HasValue && size1Prime.Value > 0)
|
||
{
|
||
DrawBlockPartContour(ctx, ox, oy, width, height,
|
||
size1Prime.Value, size2Prime ?? size1Prime.Value, size3Prime);
|
||
}
|
||
}
|
||
|
||
private static void DrawBlockPartContour(DrawingContext ctx, double ox, double oy,
|
||
double forgingW, double forgingH, double partW, double partH, double? partD)
|
||
{
|
||
double offsetX = (forgingW - partW) / 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 + partW, oy + offsetY), 0, 0, 0);
|
||
polyPart.AddVertexAt(2, new Point2d(ox + offsetX + partW, 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);
|
||
|
||
// 不再对零件轮廓整块填充剖面线
|
||
|
||
// 零件尺寸1标注
|
||
AddLinearDim(ctx, new Point3d(ox + offsetX, oy + offsetY, 0),
|
||
new Point3d(ox + offsetX + partW, oy + offsetY, 0),
|
||
new Point3d(ox + offsetX + partW / 2, oy + offsetY - 10, 0), 0, $"{partW}");
|
||
|
||
// 零件尺寸2标注
|
||
AddLinearDim(ctx, new Point3d(ox + offsetX + partW, oy + offsetY, 0),
|
||
new Point3d(ox + offsetX + partW, oy + offsetY + partH, 0),
|
||
new Point3d(ox + offsetX + partW + 10, oy + offsetY + partH / 2, 0), 90, $"{partH}");
|
||
|
||
// 零件尺寸3标注(如果有)
|
||
if (partD.HasValue && partD.Value > 0)
|
||
{
|
||
try
|
||
{
|
||
var text = new DBText();
|
||
text.TextString = $"深度:{partD.Value}";
|
||
text.Position = new Point3d(ox + offsetX + partW + 10, oy + offsetY + partH + 5, 0);
|
||
text.Height = 4;
|
||
ctx.Style?.Apply(text, DrawingStyleManager.Role.Text);
|
||
ctx.Btr.AppendEntity(text);
|
||
ctx.Tr.AddNewlyCreatedDBObject(text, true);
|
||
}
|
||
catch { }
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 辅助方法
|
||
|
||
private static string BuildDimensionText(string baseText, double? tolPlus, double? tolMinus, string tolPlusStr = null, string tolMinusStr = null)
|
||
{
|
||
if (!tolPlus.HasValue && !tolMinus.HasValue)
|
||
{
|
||
return baseText;
|
||
}
|
||
|
||
// Check if symmetrical
|
||
// tolMinus is typically positive in parameter bag representing absolute deviation (e.g. 0.02 for -0.02)
|
||
// or negative. We check absolute values.
|
||
bool isSymmetrical = false;
|
||
if (tolPlus.HasValue && tolMinus.HasValue)
|
||
{
|
||
if (Math.Abs(Math.Abs(tolPlus.Value) - Math.Abs(tolMinus.Value)) < 0.000001)
|
||
{
|
||
// Also check if raw strings (if provided) imply different precision?
|
||
// E.g. +0.50 vs -0.5. Strictly speaking they are same value but different text.
|
||
// But for symmetrical display %%p0.50, we pick one precision (usually plus).
|
||
isSymmetrical = true;
|
||
}
|
||
}
|
||
|
||
// User requested Height scale 0.7 (70% of base text height)
|
||
// Symmetric tolerance: ±Value
|
||
if (isSymmetrical)
|
||
{
|
||
var val = Math.Abs(tolPlus.Value);
|
||
// Use tolPlusStr for precision if available
|
||
return $"{baseText}%%p{FormatDimNumber(val, tolPlusStr)}";
|
||
}
|
||
|
||
// Deviation tolerance: Stacked
|
||
// AutoCAD MText stack: \H...x;\S...^...; (Caret ^ for tolerance style stacking without bar)
|
||
// User requested Height scale 0.7 (70% of base text height)
|
||
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)
|
||
{
|
||
// Lower deviation is usually displayed as negative number.
|
||
double vm = tolMinus.Value;
|
||
|
||
// Use FormatDimNumber with raw string to respect input precision
|
||
string formattedVal = FormatDimNumber(Math.Abs(vm), tolMinusStr);
|
||
|
||
if (Math.Abs(vm) < 0.000001)
|
||
{
|
||
minusStr = formattedVal;
|
||
}
|
||
else
|
||
{
|
||
// Always display lower tolerance with negative sign
|
||
minusStr = $"-{formattedVal}";
|
||
}
|
||
}
|
||
|
||
// If we have both, stack them
|
||
if (tolPlus.HasValue && tolMinus.HasValue)
|
||
{
|
||
// Add a space between base text and tolerance stack to prevent crowding
|
||
return $"{baseText} {{\\H{tolScale}x;\\S{plusStr}^{minusStr};}}";
|
||
}
|
||
|
||
// If only one side is present
|
||
var single = tolPlus.HasValue ? plusStr : minusStr;
|
||
return $"{baseText} {{\\H{tolScale}x;{single}}}";
|
||
}
|
||
|
||
private static void ApplyHalfSideDimStyle(Dimension dim, DrawingContext ctx)
|
||
{
|
||
// 按需求修改半边标注样式:
|
||
// 尺寸线 1和2开 (默认即为开)
|
||
// 界线1关 (Dimse1 = true)
|
||
// 界线2开 (Dimse2 = false)
|
||
TrySetDimProp(dim, "Dimse1", true);
|
||
TrySetDimProp(dim, "Dimse2", false);
|
||
|
||
// 箭头1 无 (Dimblk1 = _NONE)
|
||
// 箭头2 实心闭合 (Dimblk2 = Default)
|
||
try
|
||
{
|
||
// 需要设置 Dimsah = true 才能分别设置箭头
|
||
TrySetDimProp(dim, "Dimsah", true);
|
||
|
||
// 尝试设置箭头1为 _NONE
|
||
var bt = (BlockTable)ctx.Tr.GetObject(ctx.Db.BlockTableId, OpenMode.ForRead);
|
||
if (bt.Has("_NONE"))
|
||
{
|
||
dim.Dimblk1 = bt["_NONE"];
|
||
}
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
private static void AddLinearDim(DrawingContext ctx, Point3d pt1, Point3d pt2, Point3d dimLinePt,
|
||
double rotationDeg, string textOverride, Action<Dimension, DrawingContext> customizer = null)
|
||
{
|
||
try
|
||
{
|
||
var prevDb = HostApplicationServices.WorkingDatabase;
|
||
HostApplicationServices.WorkingDatabase = ctx.Db;
|
||
try
|
||
{
|
||
double rotRad = rotationDeg * Math.PI / 180.0;
|
||
|
||
// Use current drawing's dimension style (template-controlled).
|
||
var dim = new RotatedDimension(rotRad, pt1, pt2, dimLinePt, textOverride, ctx.Db.Dimstyle);
|
||
try { dim.SetDatabaseDefaults(); } catch { }
|
||
|
||
// Re-apply text override because SetDatabaseDefaults might have cleared it
|
||
if (!string.IsNullOrEmpty(textOverride))
|
||
{
|
||
dim.DimensionText = textOverride;
|
||
}
|
||
|
||
try { dim.Normal = Vector3d.ZAxis; } catch { }
|
||
TryApplyDimSizeOverrides(dim);
|
||
TryApplyDimLayoutOverrides(dim, pt1, pt2, dimLinePt, rotRad);
|
||
|
||
customizer?.Invoke(dim, ctx);
|
||
|
||
ctx.Style?.Apply(dim, DrawingStyleManager.Role.Dimension);
|
||
ctx.Btr.AppendEntity(dim);
|
||
ctx.Tr.AddNewlyCreatedDBObject(dim, true);
|
||
|
||
// Ensure dimension graphics (including text) are computed and persisted in the DWG.
|
||
// Some CAD viewers may otherwise show '*' placeholders.
|
||
try
|
||
{
|
||
dim.RecomputeDimensionBlock(true);
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
HostApplicationServices.WorkingDatabase = prevDb;
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略标注错误
|
||
}
|
||
}
|
||
|
||
private static void TryApplyDimSizeOverrides(Dimension dim)
|
||
{
|
||
if (dim == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// Template dimstyle may have very small DIMTXT; apply per-dimension overrides to keep it readable.
|
||
// Values are in drawing units (typically mm).
|
||
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);
|
||
|
||
// Updated based on user request
|
||
TrySetDimProp(dim, "Dimtofl", true); // Draw dim line between ext lines
|
||
TrySetDimProp(dim, "Dimatfit", 3); // Text or Arrows (Best fit)
|
||
TrySetDimProp(dim, "Dimtad", 1); // Text Vertical: Above
|
||
}
|
||
|
||
private static void TryApplyDimLayoutOverrides(Dimension dim, Point3d pt1, Point3d pt2, Point3d dimLinePt, double rotRad)
|
||
{
|
||
if (dim == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 1) 文本与尺寸线平行(避免模板把文字强制水平)。
|
||
TrySetDimProp(dim, "Dimtih", false);
|
||
TrySetDimProp(dim, "Dimtoh", false);
|
||
|
||
// 2) 不抑制尺寸界线(修复半圆图左侧中心线位置“尺寸界线为空”的情况)。
|
||
TrySetDimProp(dim, "Dimse1", false);
|
||
TrySetDimProp(dim, "Dimse2", false);
|
||
|
||
// 3) 尺寸线位于尺寸(文字)上方:将文字整体移到尺寸线的“下方”(相对尺寸线法向的顺时针侧)。
|
||
// Modified: User requested "Above" style. Dimtad=1 handles this. Manual positioning removed.
|
||
/*
|
||
try
|
||
{
|
||
var dimtxt = TryGetDoubleProp(dim, "Dimtxt") ?? 3.5;
|
||
var dimgap = TryGetDoubleProp(dim, "Dimgap") ?? 1.0;
|
||
var offset = Math.Max(1.0, dimtxt + dimgap);
|
||
|
||
var v = new Vector3d(-Math.Sin(rotRad), Math.Cos(rotRad), 0); // 尺寸线法向(逆时针)
|
||
|
||
var q1 = ProjectToLineAlongNormal(pt1, dimLinePt, v);
|
||
var q2 = ProjectToLineAlongNormal(pt2, dimLinePt, v);
|
||
var mid = new Point3d((q1.X + q2.X) / 2.0, (q1.Y + q2.Y) / 2.0, 0);
|
||
|
||
var textPos = mid - v.MultiplyBy(offset);
|
||
TrySetDimProp(dim, "TextPosition", textPos);
|
||
TrySetDimProp(dim, "TextRotation", rotRad);
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
*/
|
||
}
|
||
|
||
private static Point3d ProjectToLineAlongNormal(Point3d p, Point3d linePoint, Vector3d normal)
|
||
{
|
||
// 线:通过 linePoint,方向与 normal 垂直(即 (x-linePoint)·normal = 0)
|
||
// 沿 normal 方向投影:q = p - normal * ((p-linePoint)·normal)
|
||
var d = (p - linePoint).DotProduct(normal);
|
||
return p - normal.MultiplyBy(d);
|
||
}
|
||
|
||
private static double? TryGetDoubleProp(object obj, string propName)
|
||
{
|
||
if (obj == null || string.IsNullOrWhiteSpace(propName))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
var prop = obj.GetType().GetProperty(propName);
|
||
if (prop == null || !prop.CanRead)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var v = prop.GetValue(obj, null);
|
||
if (v is double d) return d;
|
||
if (v is float f) return f;
|
||
if (v is int i) return i;
|
||
if (v is short s) return s;
|
||
return null;
|
||
}
|
||
catch
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
private static void TrySetDimProp(object obj, string propName, double value)
|
||
{
|
||
if (obj == null || string.IsNullOrWhiteSpace(propName))
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var prop = obj.GetType().GetProperty(propName);
|
||
if (prop == null || !prop.CanWrite)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(double))
|
||
{
|
||
prop.SetValue(obj, value, null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(float))
|
||
{
|
||
prop.SetValue(obj, (float)value, null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(int))
|
||
{
|
||
prop.SetValue(obj, (int)Math.Round(value), null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(short))
|
||
{
|
||
prop.SetValue(obj, (short)Math.Round(value), null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(bool))
|
||
{
|
||
prop.SetValue(obj, Math.Abs(value) > 0.000001, null);
|
||
return;
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
private static void TrySetDimProp(object obj, string propName, bool value)
|
||
{
|
||
if (obj == null || string.IsNullOrWhiteSpace(propName))
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var prop = obj.GetType().GetProperty(propName);
|
||
if (prop == null || !prop.CanWrite)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(bool))
|
||
{
|
||
prop.SetValue(obj, value, null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(short))
|
||
{
|
||
prop.SetValue(obj, (short)(value ? 1 : 0), null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(int))
|
||
{
|
||
prop.SetValue(obj, value ? 1 : 0, null);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
private static void TrySetDimProp(object obj, string propName, short value)
|
||
{
|
||
if (obj == null || string.IsNullOrWhiteSpace(propName))
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var prop = obj.GetType().GetProperty(propName);
|
||
if (prop == null || !prop.CanWrite)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(short))
|
||
{
|
||
prop.SetValue(obj, value, null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(int))
|
||
{
|
||
prop.SetValue(obj, (int)value, null);
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(double))
|
||
{
|
||
prop.SetValue(obj, (double)value, null);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
private static void TrySetDimProp(object obj, string propName, Point3d value)
|
||
{
|
||
if (obj == null || string.IsNullOrWhiteSpace(propName))
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var prop = obj.GetType().GetProperty(propName);
|
||
if (prop == null || !prop.CanWrite)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (prop.PropertyType == typeof(Point3d))
|
||
{
|
||
prop.SetValue(obj, value, null);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
private static void TryLoadLinetype(Database db, Transaction tr, string linetypeName)
|
||
{
|
||
try
|
||
{
|
||
var linetypeTbl = (LinetypeTable)tr.GetObject(db.LinetypeTableId, OpenMode.ForRead);
|
||
if (!linetypeTbl.Has(linetypeName))
|
||
{
|
||
try
|
||
{
|
||
db.LoadLineTypeFile(linetypeName, "acad.lin");
|
||
}
|
||
catch { }
|
||
}
|
||
}
|
||
catch { }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 对参数包中的尺寸参数应用缩放比例
|
||
/// </summary>
|
||
private static ParamBag ScaleParamBag(ParamBag original, double scaleFactor)
|
||
{
|
||
if (original == null || scaleFactor <= 0 || scaleFactor >= 1.0)
|
||
{
|
||
return original;
|
||
}
|
||
|
||
var scaled = new ParamBag();
|
||
|
||
// 需要缩放的尺寸参数Key列表
|
||
var sizeKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||
{
|
||
// 环形参数
|
||
KeyOuterDiameter1, KeyInnerDiameter2, KeyHeight1,
|
||
KeyOuterDiameter1Prime, KeyInnerDiameter2Prime, KeyHeight1Prime,
|
||
KeyMinWallThickness,
|
||
// 饼盘参数
|
||
KeyDiskDiameter, KeyDiskHeight,
|
||
KeyDiskDiameterPrime, KeyDiskHeightPrime,
|
||
// 轴杆参数
|
||
KeyDiameter, KeyLength,
|
||
KeyDiameterPrime, KeyLengthPrime,
|
||
// 方体参数
|
||
KeyBoxSize1, KeyBoxSize2, KeyBoxSize3,
|
||
KeyBoxSize1Prime, KeyBoxSize2Prime, KeyBoxSize3Prime,
|
||
// 圆角参数
|
||
KeyUnspecifiedFilletRadiusMax, KeyInnerRadiusMax,
|
||
KeyDiskFilletRadiusMax, KeyShaftFilletRadiusMax,
|
||
KeyBoxFilletRadiusMax, KeyBoxRoundHeadFilletRadiusMax
|
||
};
|
||
|
||
// 公差参数也需要缩放
|
||
var toleranceKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||
{
|
||
KeyOuterDiameter1TolPlus, KeyOuterDiameter1TolMinus,
|
||
KeyInnerDiameter2TolPlus, KeyInnerDiameter2TolMinus,
|
||
KeyHeight1TolPlus, KeyHeight1TolMinus,
|
||
KeyDiskDiameterTolPlus, KeyDiskDiameterTolMinus,
|
||
KeyDiskHeightTolPlus, KeyDiskHeightTolMinus,
|
||
KeyDiameterTolPlus, KeyDiameterTolMinus,
|
||
KeyLengthTolPlus, KeyLengthTolMinus,
|
||
KeyBoxSize1TolPlus, KeyBoxSize1TolMinus,
|
||
KeyBoxSize2TolPlus, KeyBoxSize2TolMinus,
|
||
KeyBoxSize3TolPlus, KeyBoxSize3TolMinus
|
||
};
|
||
|
||
foreach (var key in original.GetKeys())
|
||
{
|
||
var value = original.GetString(key);
|
||
|
||
if (sizeKeys.Contains(key) || toleranceKeys.Contains(key))
|
||
{
|
||
// 尝试解析为数值并缩放
|
||
if (double.TryParse(value, out var numValue))
|
||
{
|
||
var scaledValue = numValue * scaleFactor;
|
||
// 保留适当的小数位数
|
||
scaled.Set(key, scaledValue.ToString("F2"));
|
||
}
|
||
else
|
||
{
|
||
scaled.Set(key, value);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 非尺寸参数直接复制
|
||
scaled.Set(key, value);
|
||
}
|
||
}
|
||
|
||
return scaled;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|