using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
namespace OptimizedMergePlugin
{
public class Commands
{
[CommandMethod("MG", CommandFlags.Modal)]
public void MergeLines()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
try
{
// 获取选择集
PromptSelectionResult selResult = ed.GetSelection();
if (selResult.Status != PromptStatus.OK) return;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 按图层分组并收集所有线段
var layerGroups = new Dictionary<string, List<LineSegment>>();
CollectLineSegments(selResult, tr, layerGroups, ed);
// 处理每个图层
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
db.CurrentSpaceId, OpenMode.ForWrite);
int totalLayers = layerGroups.Count;
int currentLayer = 0;
foreach (var kvp in layerGroups)
{
currentLayer++;
ed.WriteMessage($"\n处理图层: {kvp.Key} ({currentLayer}/{totalLayers})");
// 使用空间索引加速处理
var spatialIndex = BuildSpatialIndex(kvp.Value);
// 打断重叠线段
List<LineSegment> brokenSegments = BreakSegmentsWithIndex(kvp.Value, spatialIndex, ed);
// 合并共线线段
List<Line> mergedLines = MergeSegments(brokenSegments);
// 添加新实体
foreach (Line newLine in mergedLines)
{
newLine.Layer = kvp.Key;
btr.AppendEntity(newLine);
tr.AddNewlyCreatedDBObject(newLine, true);
}
}
tr.Commit();
}
ed.WriteMessage("\n线段合并完成!");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\n错误: {ex.Message}");
}
}
// 公开的线段表示类
public class LineSegment
{
public Point3d Start { get; set; }
public Point3d End { get; set; }
public ObjectId OriginalId { get; set; } = ObjectId.Null;
public LineSegment(Point3d start, Point3d end)
{
Start = start;
End = end;
}
public Extents3d Extents => new Extents3d(Start, End);
}
// 收集所有线段
private void CollectLineSegments(PromptSelectionResult selResult, Transaction tr,
Dictionary<string, List<LineSegment>> layerGroups, Editor ed)
{
int totalObjects = selResult.Value.Count;
int processed = 0;
foreach (SelectedObject selObj in selResult.Value)
{
processed++;
// 每处理100个对象显示一次进度
if (processed % 100 == 0)
ed.WriteMessage($"\n已处理: {processed}/{totalObjects}");
Entity ent = tr.GetObject(selObj.ObjectId, OpenMode.ForRead) as Entity;
if (ent == null) continue;
string layer = ent.Layer;
if (!layerGroups.ContainsKey(layer))
layerGroups.Add(layer, new List<LineSegment>());
// 处理直线
if (ent is Line line)
{
layerGroups[layer].Add(new LineSegment(line.StartPoint, line.EndPoint)
{
OriginalId = line.ObjectId
});
}
// 处理多段线
else if (ent is Polyline pline)
{
for (int i = 0; i < pline.NumberOfVertices - 1; i++)
{
layerGroups[layer].Add(new LineSegment(
pline.GetPoint3dAt(i),
pline.GetPoint3dAt(i + 1)
));
}
}
}
}
// 构建空间索引
private SpatialIndex BuildSpatialIndex(List<LineSegment> segments)
{
SpatialIndex index = new SpatialIndex();
foreach (LineSegment seg in segments)
{
index.Add(seg.Extents, seg);
}
return index;
}
// 使用空间索引打断线段
private List<LineSegment> BreakSegmentsWithIndex(List<LineSegment> segments,
SpatialIndex index, Editor ed)
{
List<LineSegment> result = new List<LineSegment>();
HashSet<LineSegment> processed = new HashSet<LineSegment>();
int totalSegments = segments.Count;
int processedCount = 0;
foreach (LineSegment seg in segments)
{
processedCount++;
// 每处理100个线段显示一次进度
if (processedCount % 100 == 0)
ed.WriteMessage($"\n打断线段: {processedCount}/{totalSegments}");
if (processed.Contains(seg)) continue;
List<LineSegment> currentSegments = new List<LineSegment> { seg };
bool modified;
do
{
modified = false;
List<LineSegment> nextSegments = new List<LineSegment>();
foreach (LineSegment current in currentSegments)
{
// 使用空间索引查找可能相交的线段
var candidates = index.Search(current.Extents)
.Where(s => !processed.Contains(s) && s != current)
.ToList();
bool broken = false;
foreach (var candidate in candidates)
{
if (TryBreakSegment(current, candidate, out List<LineSegment> newSegments))
{
// 将打断后的线段加入待处理列表
nextSegments.AddRange(newSegments);
processed.Add(candidate);
broken = true;
break;
}
}
if (!broken)
{
nextSegments.Add(current);
}
else
{
modified = true;
}
}
currentSegments = nextSegments;
} while (modified);
result.AddRange(currentSegments);
processed.Add(seg);
}
return result;
}
// 尝试打断两条线段
private bool TryBreakSegment(LineSegment seg1, LineSegment seg2,
out List<LineSegment> result)
{
result = new List<LineSegment>();
Line line1 = new Line(seg1.Start, seg1.End);
Line line2 = new Line(seg2.Start, seg2.End);
Point3dCollection intersections = new Point3dCollection();
// 修复:使用 IntPtr.Zero 代替容差指针参数
line1.IntersectWith(line2, Intersect.OnBothOperands, intersections,
IntPtr.Zero, IntPtr.Zero); // 关键修改在这里
if (intersections.Count == 0) return false;
// 处理交点
List<Point3d> splitPoints = new List<Point3d>();
foreach (Point3d pt in intersections)
{
splitPoints.Add(pt);
}
// 按距离起点排序
splitPoints.Sort((a, b) =>
seg1.Start.DistanceTo(a).CompareTo(seg1.Start.DistanceTo(b)));
// 分割第一条线段
Point3d lastPoint = seg1.Start;
foreach (Point3d splitPoint in splitPoints)
{
result.Add(new LineSegment(lastPoint, splitPoint));
lastPoint = splitPoint;
}
result.Add(new LineSegment(lastPoint, seg1.End));
return true;
}
// 合并线段
private List<Line> MergeSegments(List<LineSegment> segments)
{
// 按起点排序
List<LineSegment> sortedSegments = segments
.OrderBy(s => s.Start.X)
.ThenBy(s => s.Start.Y)
.ThenBy(s => s.Start.Z)
.ToList();
List<Line> result = new List<Line>();
LineSegment current = null;
foreach (LineSegment seg in sortedSegments)
{
if (current == null)
{
current = seg;
continue;
}
// 检查是否共线且连接
if (AreSegmentsConnectable(current, seg))
{
// 扩展当前线段
current = new LineSegment(
PointMin(current.Start, seg.Start),
PointMax(current.End, seg.End)
);
}
else
{
// 添加完成合并的线段
result.Add(new Line(current.Start, current.End));
current = seg;
}
}
if (current != null)
{
result.Add(new Line(current.Start, current.End));
}
return result;
}
// 检查线段是否可连接
private bool AreSegmentsConnectable(LineSegment seg1, LineSegment seg2)
{
Vector3d dir1 = seg1.End - seg1.Start;
Vector3d dir2 = seg2.End - seg2.Start;
// 使用全局容差检查方向是否平行
bool isColinear = dir1.IsParallelTo(dir2, Tolerance.Global);
// 使用全局容差检查端点连接
bool isConnected = seg1.End.IsEqualTo(seg2.Start, Tolerance.Global) ||
seg1.Start.IsEqualTo(seg2.End, Tolerance.Global) ||
seg1.End.IsEqualTo(seg2.End, Tolerance.Global) ||
seg1.Start.IsEqualTo(seg2.Start, Tolerance.Global);
return isColinear && isConnected;
}
// 辅助方法:获取最小点
private Point3d PointMin(Point3d a, Point3d b)
{
return new Point3d(
Math.Min(a.X, b.X),
Math.Min(a.Y, b.Y),
Math.Min(a.Z, b.Z));
}
// 辅助方法:获取最大点
private Point3d PointMax(Point3d a, Point3d b)
{
return new Point3d(
Math.Max(a.X, b.X),
Math.Max(a.Y, b.Y),
Math.Max(a.Z, b.Z));
}
}
// 空间索引实现(公开类)
public class SpatialIndex
{
private List<Tuple<Extents3d, Commands.LineSegment>> _items =
new List<Tuple<Extents3d, Commands.LineSegment>>();
public void Add(Extents3d extents, Commands.LineSegment segment)
{
_items.Add(new Tuple<Extents3d, Commands.LineSegment>(extents, segment));
}
public IEnumerable<Commands.LineSegment> Search(Extents3d searchExtents)
{
// 简单实现:检查边界框重叠
return _items
.Where(item => item.Item1.MinPoint.X <= searchExtents.MaxPoint.X &&
item.Item1.MaxPoint.X >= searchExtents.MinPoint.X &&
item.Item1.MinPoint.Y <= searchExtents.MaxPoint.Y &&
item.Item1.MaxPoint.Y >= searchExtents.MinPoint.Y)
.Select(item => item.Item2);
}
}
}
还是删除不掉重叠线
最新发布