2025-12-23 21:37:02 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
using System.Windows.Forms.Integration;
|
|
|
|
|
|
|
|
|
|
|
|
using Autodesk.AutoCAD.ApplicationServices;
|
|
|
|
|
|
using Autodesk.AutoCAD.Colors;
|
|
|
|
|
|
using Autodesk.AutoCAD.DatabaseServices;
|
|
|
|
|
|
using Autodesk.AutoCAD.EditorInput;
|
|
|
|
|
|
using Autodesk.AutoCAD.Geometry;
|
|
|
|
|
|
using Autodesk.AutoCAD.Runtime;
|
|
|
|
|
|
using Autodesk.AutoCAD.Windows;
|
|
|
|
|
|
|
|
|
|
|
|
using Szmedi.CADkits;
|
|
|
|
|
|
|
|
|
|
|
|
using Application = Autodesk.AutoCAD.ApplicationServices.Application;
|
|
|
|
|
|
|
|
|
|
|
|
public class TerrainTools
|
|
|
|
|
|
{
|
|
|
|
|
|
private static PaletteSet ps;
|
|
|
|
|
|
public const string CheckLineLayer = "校对线";
|
2026-02-23 11:21:51 +08:00
|
|
|
|
|
2025-12-23 21:37:02 +08:00
|
|
|
|
[CommandMethod("MoveTerrainElevation")]
|
|
|
|
|
|
public void MoveTerrainElevation()
|
|
|
|
|
|
{
|
|
|
|
|
|
Document doc = Application.DocumentManager.MdiActiveDocument;
|
|
|
|
|
|
if (doc == null) return;
|
|
|
|
|
|
Database db = doc.Database;
|
|
|
|
|
|
Editor ed = doc.Editor;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// --- Phase 1: User Input ---
|
|
|
|
|
|
#region User Input Section
|
2026-02-23 11:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
string targetBlockName = null; // 仅当选中块时使用
|
|
|
|
|
|
string terrainLayerName;
|
|
|
|
|
|
|
|
|
|
|
|
// 定义处理模式: 0-块, 1-点, 2-多段线
|
|
|
|
|
|
int processingMode = 0;
|
|
|
|
|
|
string textLayerName;
|
|
|
|
|
|
double maxDistance = 5.0;
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 选择样例地形点(块 或 点)
|
|
|
|
|
|
using (Transaction tr = db.TransactionManager.StartTransaction())
|
|
|
|
|
|
{
|
|
|
|
|
|
PromptEntityOptions peoEnt = new PromptEntityOptions("\n请选择一个样例地形点 (块/点/多段线(起终点重合)): ");
|
|
|
|
|
|
peoEnt.SetRejectMessage("\n选择的对象无效。");
|
|
|
|
|
|
peoEnt.AddAllowedClass(typeof(BlockReference), true);
|
|
|
|
|
|
peoEnt.AddAllowedClass(typeof(DBPoint), true);
|
|
|
|
|
|
peoEnt.AddAllowedClass(typeof(Polyline), true);
|
|
|
|
|
|
|
|
|
|
|
|
PromptEntityResult perEnt = ed.GetEntity(peoEnt);
|
|
|
|
|
|
if (perEnt.Status != PromptStatus.OK) { ed.WriteMessage("\n操作已取消。"); return; }
|
|
|
|
|
|
|
|
|
|
|
|
Entity sampleEnt = (Entity)tr.GetObject(perEnt.ObjectId, OpenMode.ForRead);
|
|
|
|
|
|
terrainLayerName = sampleEnt.Layer;
|
|
|
|
|
|
|
|
|
|
|
|
if (sampleEnt is BlockReference sampleBlock)
|
|
|
|
|
|
{
|
|
|
|
|
|
processingMode = 0;
|
|
|
|
|
|
targetBlockName = sampleBlock.IsDynamicBlock ? ((BlockTableRecord)tr.GetObject(sampleBlock.DynamicBlockTableRecord, OpenMode.ForRead)).Name : sampleBlock.Name;
|
|
|
|
|
|
ed.WriteMessage($"\n已选择模式: [处理块]。块名: '{targetBlockName}', 图层: '{terrainLayerName}'");
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sampleEnt is DBPoint)
|
|
|
|
|
|
{
|
|
|
|
|
|
processingMode = 1;
|
|
|
|
|
|
ed.WriteMessage($"\n已选择模式: [处理点实体]。所在图层: '{terrainLayerName}'");
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sampleEnt is Polyline)
|
|
|
|
|
|
{
|
|
|
|
|
|
processingMode = 2;
|
|
|
|
|
|
ed.WriteMessage("\n模式: [多段线]");
|
|
|
|
|
|
}
|
|
|
|
|
|
tr.Commit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 选择样例文字
|
|
|
|
|
|
using (Transaction tr = db.TransactionManager.StartTransaction())
|
|
|
|
|
|
{
|
|
|
|
|
|
PromptEntityOptions peoText = new PromptEntityOptions("\n请选择一个样例标高文字 (用于确定图层): ");
|
|
|
|
|
|
peoText.SetRejectMessage("\n选择的不是 MText 或 DBText。");
|
|
|
|
|
|
peoText.AddAllowedClass(typeof(MText), true);
|
|
|
|
|
|
peoText.AddAllowedClass(typeof(DBText), true);
|
|
|
|
|
|
PromptEntityResult perText = ed.GetEntity(peoText);
|
|
|
|
|
|
if (perText.Status != PromptStatus.OK) { ed.WriteMessage("\n操作已取消。"); return; }
|
|
|
|
|
|
Entity sampleTextEnt = (Entity)tr.GetObject(perText.ObjectId, OpenMode.ForRead);
|
|
|
|
|
|
textLayerName = sampleTextEnt.Layer;
|
|
|
|
|
|
ed.WriteMessage($"\n已选择样例文字,所在图层: '{textLayerName}'");
|
|
|
|
|
|
tr.Commit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 输入距离
|
|
|
|
|
|
PromptDoubleOptions pdo = new PromptDoubleOptions($"\n请输入查找标高文字的最大距离(图形单位) <{maxDistance}>: ");
|
|
|
|
|
|
pdo.AllowNegative = false; pdo.AllowZero = false; pdo.AllowNone = true; pdo.DefaultValue = maxDistance;
|
|
|
|
|
|
PromptDoubleResult pdr = ed.GetDouble(pdo);
|
|
|
|
|
|
if (pdr.Status != PromptStatus.OK && pdr.Status != PromptStatus.None) { ed.WriteMessage("\n操作已取消。"); return; }
|
|
|
|
|
|
if (pdr.Status == PromptStatus.OK) maxDistance = pdr.Value;
|
|
|
|
|
|
|
2025-12-23 21:37:02 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
// --- Phase 2: Automatic Matching ---
|
2026-02-23 11:21:51 +08:00
|
|
|
|
List<TerrainEntityInfo> terrainEntities = new List<TerrainEntityInfo>();
|
2025-12-23 21:37:02 +08:00
|
|
|
|
int updatedCount = 0;
|
|
|
|
|
|
|
|
|
|
|
|
using (Transaction tr = db.TransactionManager.StartTransaction())
|
|
|
|
|
|
{
|
|
|
|
|
|
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
|
2026-02-23 11:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
// 根据模式采集
|
|
|
|
|
|
if (processingMode == 0)
|
|
|
|
|
|
terrainEntities = CollectBlocks(tr, btr, targetBlockName, terrainLayerName);
|
|
|
|
|
|
else if (processingMode == 1)
|
|
|
|
|
|
terrainEntities = CollectPoints(tr, btr, terrainLayerName);
|
|
|
|
|
|
else if (processingMode == 2)
|
|
|
|
|
|
terrainEntities = CollectPolylines(tr, btr, terrainLayerName);
|
|
|
|
|
|
var elevationTexts = CollectFilteredTexts(tr, btr, textLayerName);
|
|
|
|
|
|
|
2025-12-23 21:37:02 +08:00
|
|
|
|
if (elevationTexts.Count == 0) { ed.WriteMessage($"\n警告: 在图层 '{textLayerName}' 上未找到任何有效的标高文字。"); tr.Commit(); return; }
|
|
|
|
|
|
|
2026-02-23 11:21:51 +08:00
|
|
|
|
ed.WriteMessage($"\n正在使用贪婪匹配算法分析 {terrainEntities.Count} 个地形点...");
|
|
|
|
|
|
|
|
|
|
|
|
// 核心匹配算法不需要修改,因为它只依赖 ObjectId 和 Position,这在 TerrainEntityInfo 中都有
|
|
|
|
|
|
var validPairs = GetScoredValidPairs(terrainEntities, elevationTexts, maxDistance);
|
|
|
|
|
|
|
2025-12-23 21:37:02 +08:00
|
|
|
|
ed.WriteMessage($"\n分析完成。找到 {validPairs.Count} 个最优匹配对。");
|
|
|
|
|
|
|
|
|
|
|
|
if (validPairs.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
CreateLayerIfNotExists(db, tr, CheckLineLayer, 8);
|
|
|
|
|
|
ProgressMeter pm = new ProgressMeter();
|
|
|
|
|
|
pm.SetLimit(validPairs.Count);
|
2026-02-23 11:21:51 +08:00
|
|
|
|
pm.Start("正在更新已自动匹配的实体...");
|
|
|
|
|
|
|
2025-12-23 21:37:02 +08:00
|
|
|
|
var textDataMap = elevationTexts.ToDictionary(t => t.ObjectId, t => t);
|
2026-02-23 11:21:51 +08:00
|
|
|
|
|
2025-12-23 21:37:02 +08:00
|
|
|
|
foreach (var pair in validPairs)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (double.TryParse(textDataMap[pair.Value].TextContent, out double elevationZ))
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
// 更新位置逻辑:需要判断是块还是点
|
|
|
|
|
|
Entity ent = (Entity)tr.GetObject(pair.Key, OpenMode.ForWrite);
|
|
|
|
|
|
Point3d currentPos;
|
|
|
|
|
|
|
|
|
|
|
|
if (ent is BlockReference blk)
|
|
|
|
|
|
{
|
|
|
|
|
|
blk.Position = new Point3d(blk.Position.X, blk.Position.Y, elevationZ);
|
|
|
|
|
|
currentPos = blk.Position;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ent is DBPoint pt)
|
|
|
|
|
|
{
|
|
|
|
|
|
pt.Position = new Point3d(pt.Position.X, pt.Position.Y, elevationZ);
|
|
|
|
|
|
currentPos = pt.Position;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ent is Polyline pl)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 对于 2D 多段线,修改 Elevation 属性
|
|
|
|
|
|
pl.Elevation = elevationZ;
|
|
|
|
|
|
Extents3d ext = pl.GeometricExtents;
|
|
|
|
|
|
currentPos = ext.MinPoint + (ext.MaxPoint - ext.MinPoint) * 0.5;
|
|
|
|
|
|
//currentPos = pl.GetPoint3dAt(0); // 取第一个点作为连线起点
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Line line = new Line(currentPos, textDataMap[pair.Value].Position)
|
|
|
|
|
|
{
|
|
|
|
|
|
Layer = CheckLineLayer,
|
|
|
|
|
|
ColorIndex = 256
|
|
|
|
|
|
};
|
2025-12-23 21:37:02 +08:00
|
|
|
|
btr.AppendEntity(line);
|
|
|
|
|
|
tr.AddNewlyCreatedDBObject(line, true);
|
|
|
|
|
|
updatedCount++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
pm.Stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
tr.Commit();
|
2026-02-23 11:21:51 +08:00
|
|
|
|
ed.WriteMessage($"\n\n--- 自动处理报告 ---\n成功自动更新 {updatedCount} 个实体。\n{terrainEntities.Count - updatedCount} 个实体需要审核。");
|
2025-12-23 21:37:02 +08:00
|
|
|
|
|
2026-02-23 11:21:51 +08:00
|
|
|
|
if (terrainEntities.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ps == null) { ps = new PaletteSet("审核并校对高程点", new Guid("C4E61D33-3162-4889-A263-6A1D2C52D26C")); }
|
|
|
|
|
|
if (ps.Count > 0) { ps.Remove(0); }
|
|
|
|
|
|
|
|
|
|
|
|
// UI 控件初始化
|
|
|
|
|
|
var reviewControl = new ReviewAndMatchWindow(terrainEntities, validPairs, elevationTexts, CheckLineLayer, ps);
|
|
|
|
|
|
ElementHost host = new ElementHost { Dock = DockStyle.Fill, Child = reviewControl };
|
|
|
|
|
|
ps.Add("ReviewAndMatch", host);
|
|
|
|
|
|
ps.Visible = true;
|
|
|
|
|
|
}
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
2026-02-23 11:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (System.Exception ex) { ed.WriteMessage($"\n发生严重错误: {ex.Message}\n{ex.StackTrace}"); }
|
|
|
|
|
|
}
|
2026-02-23 11:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
// 匹配算法逻辑保持不变,只需签名中的 List 类型改为 TerrainEntityInfo
|
|
|
|
|
|
private Dictionary<ObjectId, ObjectId> GetScoredValidPairs(List<TerrainEntityInfo> entities, List<TextWithPosition> texts, double maxDist)
|
2025-12-23 21:37:02 +08:00
|
|
|
|
{
|
|
|
|
|
|
var textCompetition = new Dictionary<ObjectId, double>();
|
2026-02-23 11:21:51 +08:00
|
|
|
|
// ... (原逻辑不变,ent.Position 属性是一样的) ...
|
2025-12-23 21:37:02 +08:00
|
|
|
|
foreach (var text in texts)
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
var distancesToEnts = entities
|
2025-12-23 21:37:02 +08:00
|
|
|
|
.Select(b => new Point2d(b.Position.X, b.Position.Y).GetDistanceTo(new Point2d(text.Position.X, text.Position.Y)))
|
|
|
|
|
|
.OrderBy(d => d)
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
2026-02-23 11:21:51 +08:00
|
|
|
|
if (distancesToEnts.Count >= 2)
|
2025-12-23 21:37:02 +08:00
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
double d1 = distancesToEnts[0];
|
|
|
|
|
|
double d2 = distancesToEnts[1];
|
2025-12-23 21:37:02 +08:00
|
|
|
|
textCompetition[text.ObjectId] = (d2 > 0.001) ? (d1 / d2) : 1.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
textCompetition[text.ObjectId] = 0.0;
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-23 11:21:51 +08:00
|
|
|
|
var allPossiblePairs = new List<Tuple<ObjectId, ObjectId, double>>();
|
|
|
|
|
|
foreach (var ent in entities)
|
2025-12-23 21:37:02 +08:00
|
|
|
|
{
|
|
|
|
|
|
foreach (var text in texts)
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
double dist = new Point2d(ent.Position.X, ent.Position.Y)
|
2025-12-23 21:37:02 +08:00
|
|
|
|
.GetDistanceTo(new Point2d(text.Position.X, text.Position.Y));
|
|
|
|
|
|
|
|
|
|
|
|
if (dist <= maxDist)
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
double distanceScore = 1.0 / (dist + 0.001);
|
|
|
|
|
|
double uniquenessScore = 1.0 - textCompetition[text.ObjectId];
|
|
|
|
|
|
double finalScore = 0.7 * distanceScore + 0.3 * uniquenessScore * distanceScore;
|
|
|
|
|
|
allPossiblePairs.Add(new Tuple<ObjectId, ObjectId, double>(ent.ObjectId, text.ObjectId, finalScore));
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var sortedPairs = allPossiblePairs.OrderByDescending(p => p.Item3).ToList();
|
|
|
|
|
|
var validPairs = new Dictionary<ObjectId, ObjectId>();
|
2026-02-23 11:21:51 +08:00
|
|
|
|
var matchedEnts = new HashSet<ObjectId>();
|
2025-12-23 21:37:02 +08:00
|
|
|
|
var matchedTexts = new HashSet<ObjectId>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var pair in sortedPairs)
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
if (!matchedEnts.Contains(pair.Item1) && !matchedTexts.Contains(pair.Item2))
|
2025-12-23 21:37:02 +08:00
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
validPairs.Add(pair.Item1, pair.Item2);
|
|
|
|
|
|
matchedEnts.Add(pair.Item1);
|
|
|
|
|
|
matchedTexts.Add(pair.Item2);
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return validPairs;
|
|
|
|
|
|
}
|
2026-02-23 11:21:51 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 采集多段线方法 ---
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tr"></param>
|
|
|
|
|
|
/// <param name="btr"></param>
|
|
|
|
|
|
/// <param name="layerName"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private List<TerrainEntityInfo> CollectPolylines(Transaction tr, BlockTableRecord btr, string layerName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var list = new List<TerrainEntityInfo>();
|
|
|
|
|
|
foreach (ObjectId id in btr)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(Polyline))))
|
|
|
|
|
|
{
|
|
|
|
|
|
var pl = (Polyline)tr.GetObject(id, OpenMode.ForRead);
|
|
|
|
|
|
if (pl.Layer.Equals(layerName, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 【核心修改】:对于圆弧/圆形多段线,取其几何中心作为参考点
|
|
|
|
|
|
// 这样即使多段线是由两个半圆组成的,中心点也会准确落在圆心
|
|
|
|
|
|
Extents3d ext = pl.GeometricExtents;
|
|
|
|
|
|
Point3d center = ext.MinPoint + (ext.MaxPoint - ext.MinPoint) * 0.5;
|
|
|
|
|
|
|
|
|
|
|
|
// 将计算出的“圆心”存入 TerrainEntityInfo
|
|
|
|
|
|
list.Add(new TerrainEntityInfo(id, center));
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果某些特殊情况无法获取包围盒,则退而求其次取第一个点
|
|
|
|
|
|
list.Add(new TerrainEntityInfo(id, pl.GetPoint3dAt(0)));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// 采集点
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tr"></param>
|
|
|
|
|
|
/// <param name="btr"></param>
|
|
|
|
|
|
/// <param name="layerName"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private List<TerrainEntityInfo> CollectPoints(Transaction tr, BlockTableRecord btr, string layerName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var list = new List<TerrainEntityInfo>();
|
|
|
|
|
|
foreach (ObjectId id in btr)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(DBPoint))))
|
|
|
|
|
|
{
|
|
|
|
|
|
var pt = (DBPoint)tr.GetObject(id, OpenMode.ForRead);
|
|
|
|
|
|
if (pt.Layer.Equals(layerName, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
list.Add(new TerrainEntityInfo(id, pt.Position));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 修改:采集块实体 (返回类型变更为 TerrainEntityInfo)
|
|
|
|
|
|
private List<TerrainEntityInfo> CollectBlocks(Transaction tr, BlockTableRecord btr, string targetBlockName, string blockLayerName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var list = new List<TerrainEntityInfo>();
|
|
|
|
|
|
foreach (ObjectId id in btr)
|
|
|
|
|
|
if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(BlockReference))))
|
|
|
|
|
|
{
|
|
|
|
|
|
var br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
|
|
|
|
|
|
string name = br.IsDynamicBlock ? ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name : br.Name;
|
|
|
|
|
|
if (br.Layer.Equals(blockLayerName, StringComparison.OrdinalIgnoreCase) && name.Equals(targetBlockName, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
list.Add(new TerrainEntityInfo(id, br.Position));
|
|
|
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<TextWithPosition> CollectFilteredTexts(Transaction tr, BlockTableRecord btr, string textLayerName) { var list = new List<TextWithPosition>(); Regex rgx = new Regex(@"[\u4e00-\u9fa5]"); foreach (ObjectId id in btr) { if (id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(DBText))) || id.ObjectClass.IsDerivedFrom(RXObject.GetClass(typeof(MText)))) { var ent = (Entity)tr.GetObject(id, OpenMode.ForRead); if (ent.Layer.Equals(textLayerName, StringComparison.OrdinalIgnoreCase)) { string txt = (ent is MText mt) ? mt.Contents : ((DBText)ent).TextString; if (!string.IsNullOrWhiteSpace(txt) && !rgx.IsMatch(txt) && txt.Contains(".") && double.TryParse(txt, out _)) { try { Extents3d ext = ent.GeometricExtents; Point3d center = ext.MinPoint + (ext.MaxPoint - ext.MinPoint) * 0.5; list.Add(new TextWithPosition(id, center, txt)); } catch { } } } } } return list; }
|
|
|
|
|
|
private void CreateLayerIfNotExists(Database db, Transaction tr, string layerName, short colorIndex) { LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead); if (!lt.Has(layerName)) { lt.UpgradeOpen(); var ltr = new LayerTableRecord { Name = layerName, Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex) }; lt.Add(ltr); tr.AddNewlyCreatedDBObject(ltr, true); } }
|
|
|
|
|
|
|
|
|
|
|
|
// 清理功能保持不变
|
2025-12-23 21:37:02 +08:00
|
|
|
|
public static void CleanAllCheckLines()
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
// ... (与原代码一致,此处略) ...
|
|
|
|
|
|
// 请确保保留原 CleanAllCheckLines 实现
|
2025-12-23 21:37:02 +08:00
|
|
|
|
Document doc = Application.DocumentManager.MdiActiveDocument;
|
|
|
|
|
|
if (doc == null) return;
|
|
|
|
|
|
Database db = doc.Database;
|
|
|
|
|
|
Editor ed = doc.Editor;
|
|
|
|
|
|
int cleanedCount = 0;
|
|
|
|
|
|
using (doc.LockDocument())
|
|
|
|
|
|
using (Transaction tr = db.TransactionManager.StartTransaction())
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
|
2026-02-23 11:21:51 +08:00
|
|
|
|
if (!lt.Has(CheckLineLayer)) return;
|
2025-12-23 21:37:02 +08:00
|
|
|
|
LayerTableRecord layer = (LayerTableRecord)tr.GetObject(lt[CheckLineLayer], OpenMode.ForRead);
|
2026-02-23 11:21:51 +08:00
|
|
|
|
if (layer.IsLocked) { layer.UpgradeOpen(); layer.IsLocked = false; }
|
2025-12-23 21:37:02 +08:00
|
|
|
|
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
|
|
|
|
|
|
foreach (ObjectId id in btr)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (id.ObjectClass.DxfName.Equals("LINE", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
Line line = tr.GetObject(id, OpenMode.ForRead) as Line;
|
|
|
|
|
|
if (line != null && line.Layer.Equals(CheckLineLayer, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
{
|
2026-02-23 11:21:51 +08:00
|
|
|
|
line.UpgradeOpen(); line.Erase(); cleanedCount++;
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-02-23 11:21:51 +08:00
|
|
|
|
tr.Commit(); ed.WriteMessage($"\n已清理 {cleanedCount} 条校对线。"); ed.Regen();
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
2026-02-23 11:21:51 +08:00
|
|
|
|
catch { tr.Abort(); }
|
2025-12-23 21:37:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-02-23 11:21:51 +08:00
|
|
|
|
}
|