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

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);
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;
}

View File

@ -230,7 +230,20 @@ namespace CadParamPluging.Cad
var db = ctx.Database;
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
{
@ -1529,11 +1542,36 @@ namespace CadParamPluging.Cad
{
try
{
double rotRad = rotationDeg * Math.PI / 180.0;
var dim = new RotatedDimension(rotRad, pt1, pt2, dimLinePt, textOverride, ctx.Db.Dimstyle);
ctx.Style?.Apply(dim, DrawingStyleManager.Role.Dimension);
ctx.Btr.AppendEntity(dim);
ctx.Tr.AddNewlyCreatedDBObject(dim, true);
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 { }
try { dim.Normal = Vector3d.ZAxis; } catch { }
TryApplyDimSizeOverrides(dim);
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
{
@ -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)
{
try

View File

@ -861,6 +861,10 @@ namespace CadParamPluging.Cad
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>
@ -957,6 +961,439 @@ namespace CadParamPluging.Cad
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)
{
if (ent == null || !layoutExtents.HasValue)

View File

@ -657,6 +657,16 @@ namespace CadParamPluging.UI
var removeResult = TemplateDrawingService.RemoveTemplateOriginalDrawing(ctx);
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"));
// 根据模板参数绘制半剖视图,居中放置于原图纸位置
@ -709,6 +719,8 @@ namespace CadParamPluging.UI
}
ctx.Commit();
try { doc.Editor.Regen(); } catch { }
}
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;
}
}