更新标注样式,删除无用元素

This commit is contained in:
sladro 2025-12-23 17:34:17 +08:00
parent 3263461cec
commit 8f51b53f5b
5 changed files with 647 additions and 6 deletions

View File

@ -88,6 +88,22 @@ namespace CadParamPluging.Cad
var layerTbl = (LayerTable)_tr.GetObject(_db.LayerTableId, OpenMode.ForRead); var layerTbl = (LayerTable)_tr.GetObject(_db.LayerTableId, OpenMode.ForRead);
if (layerTbl.Has(layerName)) if (layerTbl.Has(layerName))
{ {
try
{
var layerId = layerTbl[layerName];
var existingLayer = (LayerTableRecord)_tr.GetObject(layerId, OpenMode.ForWrite);
if (existingLayer != null)
{
// Make sure the layer is visible in the template.
existingLayer.IsOff = false;
existingLayer.IsFrozen = false;
existingLayer.IsLocked = false;
}
}
catch
{
// ignore
}
return; return;
} }

View File

@ -230,7 +230,20 @@ namespace CadParamPluging.Cad
var db = ctx.Database; var db = ctx.Database;
var tr = ctx.Transaction; var tr = ctx.Transaction;
var btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
// 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 var context = new DrawingContext
{ {
@ -1527,13 +1540,38 @@ namespace CadParamPluging.Cad
private static void AddLinearDim(DrawingContext ctx, Point3d pt1, Point3d pt2, Point3d dimLinePt, private static void AddLinearDim(DrawingContext ctx, Point3d pt1, Point3d pt2, Point3d dimLinePt,
double rotationDeg, string textOverride) double rotationDeg, string textOverride)
{ {
try
{
var prevDb = HostApplicationServices.WorkingDatabase;
HostApplicationServices.WorkingDatabase = ctx.Db;
try try
{ {
double rotRad = rotationDeg * Math.PI / 180.0; 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); var dim = new RotatedDimension(rotRad, pt1, pt2, dimLinePt, textOverride, ctx.Db.Dimstyle);
try { dim.SetDatabaseDefaults(); } catch { }
try { dim.Normal = Vector3d.ZAxis; } catch { }
TryApplyDimSizeOverrides(dim);
ctx.Style?.Apply(dim, DrawingStyleManager.Role.Dimension); ctx.Style?.Apply(dim, DrawingStyleManager.Role.Dimension);
ctx.Btr.AppendEntity(dim); ctx.Btr.AppendEntity(dim);
ctx.Tr.AddNewlyCreatedDBObject(dim, true); 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 catch
{ {
@ -1541,6 +1579,55 @@ namespace CadParamPluging.Cad
} }
} }
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", 1.0);
}
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;
}
}
catch
{
// ignore
}
}
private static void TryLoadLinetype(Database db, Transaction tr, string linetypeName) private static void TryLoadLinetype(Database db, Transaction tr, string linetypeName)
{ {
try try

View File

@ -861,6 +861,10 @@ namespace CadParamPluging.Cad
public Extents3d? OriginalExtents { get; set; } public Extents3d? OriginalExtents { get; set; }
} }
private static readonly Regex DimensionPlaceholderRegex = new Regex(
@"(%%c|[Φφ∅Ø]|\\U\+03A6|\\U\+2205|\\U\+00D8)\s*\*",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary> /// <summary>
/// 删除模板中原有的图纸图形,保留右上角区域的内容(如粗糙度标注)。 /// 删除模板中原有的图纸图形,保留右上角区域的内容(如粗糙度标注)。
/// </summary> /// </summary>
@ -957,6 +961,439 @@ namespace CadParamPluging.Cad
return result; return result;
} }
/// <summary>
/// 删除模板中残留的“尺寸占位符”文本(例如 (Φ*)),避免与新生成的真实尺寸标注混淆。
/// </summary>
/// <remarks>
/// 仅清理文本类实体DBText/MText/块属性),不影响真正的 Dimension 实体。
/// </remarks>
public static int RemoveTemplateDimensionPlaceholderTexts(
CadContext ctx,
Extents3d? graphicExtents = null,
double topRightThreshold = 0.70,
bool scanBlockDefinitions = false)
{
if (ctx == null)
{
throw new ArgumentNullException(nameof(ctx));
}
var db = ctx.Database;
var tr = ctx.Transaction;
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
var ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
var allEntities = ms.Cast<ObjectId>()
.Select(id => tr.GetObject(id, OpenMode.ForRead, false) as Entity)
.Where(e => e != null)
.ToList();
var targetExtents = graphicExtents
?? ComputeWhiteFrameExtentsFromEntities(tr, allEntities)
?? ComputeLayoutExtents(allEntities);
var removed = 0;
foreach (ObjectId id in ms)
{
var ent = tr.GetObject(id, OpenMode.ForWrite, false) as Entity;
if (ent == null || ent.IsErased)
{
continue;
}
if (targetExtents.HasValue && IsInTopRightCorner(ent, targetExtents.Value, topRightThreshold))
{
continue;
}
if (!IsWithin(ent, targetExtents))
{
continue;
}
if (ent is DBText t)
{
if (LooksLikeDimensionPlaceholder(t.TextString))
{
ent.Erase(true);
removed++;
}
continue;
}
if (ent is MText mt)
{
var plain = SimplifyMText(mt.Contents);
if (LooksLikeDimensionPlaceholder(plain) || LooksLikeDimensionPlaceholder(mt.Contents))
{
ent.Erase(true);
removed++;
}
continue;
}
if (ent is BlockReference br)
{
removed += RemovePlaceholderAttributes(tr, br, targetExtents, topRightThreshold);
// Keep default behavior conservative: do not edit block definitions unless explicitly enabled.
if (scanBlockDefinitions && IsWithin(br, targetExtents))
{
removed += RemovePlaceholderTextsInBlockDefinition(tr, br.BlockTableRecord, new HashSet<ObjectId>());
}
}
}
return removed;
}
private static int RemovePlaceholderAttributes(Transaction tr, BlockReference br, Extents3d? targetExtents, double topRightThreshold)
{
if (tr == null || br == null)
{
return 0;
}
var removed = 0;
foreach (ObjectId attId in br.AttributeCollection)
{
var att = tr.GetObject(attId, OpenMode.ForWrite, false) as AttributeReference;
if (att == null || att.IsErased)
{
continue;
}
if (targetExtents.HasValue && IsInTopRightCorner(att, targetExtents.Value, topRightThreshold))
{
continue;
}
if (!IsWithin(att, targetExtents))
{
continue;
}
if (LooksLikeDimensionPlaceholder(att.TextString))
{
try
{
att.Erase(true);
removed++;
}
catch
{
// ignore
}
}
}
return removed;
}
private static int RemovePlaceholderTextsInBlockDefinition(Transaction tr, ObjectId blockId, HashSet<ObjectId> visited)
{
if (tr == null || blockId.IsNull)
{
return 0;
}
if (visited == null)
{
visited = new HashSet<ObjectId>();
}
if (visited.Contains(blockId))
{
return 0;
}
visited.Add(blockId);
var btr = tr.GetObject(blockId, OpenMode.ForWrite, false) as BlockTableRecord;
if (btr == null)
{
return 0;
}
var removed = 0;
foreach (ObjectId childId in btr)
{
var child = tr.GetObject(childId, OpenMode.ForWrite, false) as Entity;
if (child == null || child.IsErased)
{
continue;
}
if (child is DBText t)
{
if (LooksLikeDimensionPlaceholder(t.TextString))
{
child.Erase(true);
removed++;
}
continue;
}
if (child is MText mt)
{
var plain = SimplifyMText(mt.Contents);
if (LooksLikeDimensionPlaceholder(plain) || LooksLikeDimensionPlaceholder(mt.Contents))
{
child.Erase(true);
removed++;
}
continue;
}
if (child is BlockReference br)
{
removed += RemovePlaceholderAttributes(tr, br, null, 1.0);
removed += RemovePlaceholderTextsInBlockDefinition(tr, br.BlockTableRecord, visited);
}
}
return removed;
}
private static bool LooksLikeDimensionPlaceholder(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return false;
}
var s = (raw ?? string.Empty).Replace(" ", string.Empty).Replace(" ", string.Empty);
if (!s.Contains("*"))
{
return false;
}
// Typical placeholder examples: (Φ*), Φ*, %%c*, (\U+03A6*)
return DimensionPlaceholderRegex.IsMatch(s);
}
/// <summary>
/// 删除白色线框范围内上半部分的所有内容(用于清理模板残留的图形/占位符)。
/// 保留:右上角区域(如粗糙度标注)与下半部分(附注/表格)。
/// </summary>
/// <param name="keepBottomRatio">保留下半部比例0.5 表示保留下半部分)</param>
/// <param name="topRightThreshold">右上角保留阈值0.70表示X和Y都超过70%的位置</param>
public static int RemoveWhiteFrameUpperContent(CadContext ctx, double keepBottomRatio = 0.50, double topRightThreshold = 0.70)
{
if (ctx == null)
{
throw new ArgumentNullException(nameof(ctx));
}
keepBottomRatio = Math.Max(0.0, Math.Min(1.0, keepBottomRatio));
var db = ctx.Database;
var tr = ctx.Transaction;
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
var ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
var allEntities = ms.Cast<ObjectId>()
.Select(id => tr.GetObject(id, OpenMode.ForRead, false) as Entity)
.Where(e => e != null && !e.IsErased)
.ToList();
var whiteFrame = ComputeWhiteFrameExtentsFromEntities(tr, allEntities) ?? ComputeLayoutExtents(allEntities);
if (!whiteFrame.HasValue)
{
return 0;
}
var frame = whiteFrame.Value;
var height = frame.MaxPoint.Y - frame.MinPoint.Y;
if (height <= 0)
{
return 0;
}
var cutY = frame.MinPoint.Y + height * keepBottomRatio;
var removed = 0;
foreach (ObjectId id in ms)
{
var ent = tr.GetObject(id, OpenMode.ForWrite, false) as Entity;
if (ent == null || ent.IsErased)
{
continue;
}
// Keep white frame boundary itself.
if (IsWhiteFrameEntity(ent, frame, tr))
{
continue;
}
if (!IsWithin(ent, frame))
{
continue;
}
// Keep top-right corner content.
if (IsInTopRightCorner(ent, frame, topRightThreshold))
{
continue;
}
if (!TryGetEntityCenterY(ent, out var centerY))
{
continue;
}
// Keep bottom area (notes/table).
if (centerY < cutY)
{
continue;
}
try
{
ent.Erase(true);
removed++;
}
catch
{
// ignore
}
}
return removed;
}
private static bool TryGetEntityCenterY(Entity ent, out double centerY)
{
centerY = 0;
if (ent == null)
{
return false;
}
try
{
var ext = ent.GeometricExtents;
centerY = (ext.MinPoint.Y + ext.MaxPoint.Y) / 2.0;
return true;
}
catch
{
return false;
}
}
private static bool IsWithin(Entity ent, Extents3d frame)
{
if (ent == null)
{
return false;
}
try
{
var ext = ent.GeometricExtents;
return Intersects(ext, frame);
}
catch
{
return true;
}
}
private static bool IsWhiteFrameEntity(Entity ent, Extents3d frame, Transaction tr)
{
if (ent == null)
{
return false;
}
if (!(ent is Line) && !(ent is Polyline))
{
return false;
}
if (!IsWhiteColor(ent, tr))
{
return false;
}
try
{
var ext = ent.GeometricExtents;
var frameW = frame.MaxPoint.X - frame.MinPoint.X;
var frameH = frame.MaxPoint.Y - frame.MinPoint.Y;
var tol = Math.Max(frameW, frameH) * 0.01; // 1%
// On outer border lines.
var nearLeft = Math.Abs(ext.MinPoint.X - frame.MinPoint.X) < tol;
var nearRight = Math.Abs(ext.MaxPoint.X - frame.MaxPoint.X) < tol;
var nearBottom = Math.Abs(ext.MinPoint.Y - frame.MinPoint.Y) < tol;
var nearTop = Math.Abs(ext.MaxPoint.Y - frame.MaxPoint.Y) < tol;
// Rough heuristic: if it touches two sides or spans most of a side, treat as frame.
if ((nearLeft && nearBottom) || (nearLeft && nearTop) || (nearRight && nearBottom) || (nearRight && nearTop))
{
return true;
}
if (ent is Line)
{
var spansWidth = (ext.MaxPoint.X - ext.MinPoint.X) > frameW * 0.90;
var spansHeight = (ext.MaxPoint.Y - ext.MinPoint.Y) > frameH * 0.90;
if ((nearTop || nearBottom) && spansWidth)
{
return true;
}
if ((nearLeft || nearRight) && spansHeight)
{
return true;
}
}
if (ent is Polyline)
{
var spansWidth = (ext.MaxPoint.X - ext.MinPoint.X) > frameW * 0.90;
var spansHeight = (ext.MaxPoint.Y - ext.MinPoint.Y) > frameH * 0.90;
if (spansWidth && spansHeight)
{
return true;
}
}
}
catch
{
return false;
}
return false;
}
private static bool IsWithin(Entity ent, Extents3d? targetExtents)
{
if (ent == null)
{
return false;
}
if (!targetExtents.HasValue)
{
return true;
}
try
{
var ext = ent.GeometricExtents;
return Intersects(ext, targetExtents.Value);
}
catch
{
return true;
}
}
private static bool IsOuterFrameEntity(Entity ent, Extents3d? layoutExtents, Transaction tr = null) private static bool IsOuterFrameEntity(Entity ent, Extents3d? layoutExtents, Transaction tr = null)
{ {
if (ent == null || !layoutExtents.HasValue) if (ent == null || !layoutExtents.HasValue)

View File

@ -657,6 +657,16 @@ namespace CadParamPluging.UI
var removeResult = TemplateDrawingService.RemoveTemplateOriginalDrawing(ctx); var removeResult = TemplateDrawingService.RemoveTemplateOriginalDrawing(ctx);
AppendLog($"已删除原有图形: 红色外框={removeResult.OuterFrameErased}, CAXA图层={removeResult.CaxaLayerErased}, 标注={removeResult.DimensionLayerErased}, 保留右上角={removeResult.DimensionLayerKept}"); AppendLog($"已删除原有图形: 红色外框={removeResult.OuterFrameErased}, CAXA图层={removeResult.CaxaLayerErased}, 标注={removeResult.DimensionLayerErased}, 保留右上角={removeResult.DimensionLayerKept}");
// 删除白色线框内“上半部分”的所有内容(保留右上角与下半部分附注/表格)
var upperRemoved = TemplateDrawingService.RemoveWhiteFrameUpperContent(
ctx,
keepBottomRatio: 0.50,
topRightThreshold: 0.70);
if (upperRemoved > 0)
{
AppendLog($"已清理白框上半部内容: {upperRemoved} 处");
}
var scaleFactor = ParseScaleFactor(bag.GetString("DrawingScale")); var scaleFactor = ParseScaleFactor(bag.GetString("DrawingScale"));
// 根据模板参数绘制半剖视图,居中放置于原图纸位置 // 根据模板参数绘制半剖视图,居中放置于原图纸位置
@ -709,6 +719,8 @@ namespace CadParamPluging.UI
} }
ctx.Commit(); ctx.Commit();
try { doc.Editor.Regen(); } catch { }
} }
AppendLog("图纸生成完成。"); AppendLog("图纸生成完成。");

89
repro.cs Normal file
View File

@ -0,0 +1,89 @@
using System;
using System.Globalization;
public class Program
{
public static void Main()
{
double diameter = 100.5;
string res = FormatDimNumber(diameter);
Console.WriteLine($"Diameter 100.5 -> '{res}'");
diameter = 100;
res = FormatDimNumber(diameter);
Console.WriteLine($"Diameter 100 -> '{res}'");
diameter = 0;
res = FormatDimNumber(diameter);
Console.WriteLine($"Diameter 0 -> '{res}'");
// Test BuildDimensionText
string dimText = BuildDimensionText($"%%c{FormatDimNumber(100)}", 0.1, -0.1);
Console.WriteLine($"Text with tol: '{dimText}'");
dimText = BuildDimensionText($"%%c{FormatDimNumber(100)}", null, null);
Console.WriteLine($"Text no tol: '{dimText}'");
// Test ScaleParamBag logic (conceptually)
double scale = 0.5;
double val = 123.45;
string scaledStr = (val * scale).ToString("F2");
Console.WriteLine($"Scaled 123.45 * 0.5 -> '{scaledStr}'");
if (double.TryParse(scaledStr, NumberStyles.Float, CultureInfo.InvariantCulture, out var v))
{
Console.WriteLine($"Parsed back (Invariant): {v}");
}
else if (double.TryParse(scaledStr, NumberStyles.Float, CultureInfo.CurrentCulture, out v))
{
Console.WriteLine($"Parsed back (Current): {v}");
}
else
{
Console.WriteLine("Parse failed");
}
}
private static string FormatDimNumber(double value)
{
try
{
return value.ToString("0.###");
}
catch
{
return value.ToString();
}
}
private static string BuildDimensionText(string baseText, double? tolPlus, double? tolMinus)
{
if (!tolPlus.HasValue && !tolMinus.HasValue)
{
return baseText;
}
var result = baseText;
// 公差格式: 基本尺寸 +上差/-下差
if (tolPlus.HasValue && tolMinus.HasValue)
{
var plusStr = tolPlus.Value >= 0 ? $"+{tolPlus.Value}" : $"{tolPlus.Value}";
var minusStr = tolMinus.Value >= 0 ? $"+{tolMinus.Value}" : $"{tolMinus.Value}";
result += $"({plusStr}/{minusStr})";
}
else if (tolPlus.HasValue)
{
var plusStr = tolPlus.Value >= 0 ? $"+{tolPlus.Value}" : $"{tolPlus.Value}";
result += $"({plusStr})";
}
else if (tolMinus.HasValue)
{
var minusStr = tolMinus.Value >= 0 ? $"+{tolMinus.Value}" : $"{tolMinus.Value}";
result += $"({minusStr})";
}
return result;
}
}