在 C# AutoCAD 二次开发中,合并两条首尾点重合的多段线,核心是获取并连接它们的顶点集合,然后创建一条新的多段线。关键在于精确判断重合点,并处理顶点顺序。
核心步骤与代码实现
- 获取两条多段线的顶点集合。
- 判断并找到重合的顶点(起点或终点)。
- 根据重合情况,重新排序并合并顶点列表。
- 使用合并后的顶点创建一条新的多段线,并(可选)删除原有多段线。
以下是完整的实现代码示例:
csharp
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;
public class PolylineMerge
{
[CommandMethod("MergePolylines")]
public void MergePolylines()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
try
{
// 1. 让用户选择两条多段线
PromptEntityOptions peo1 = new PromptEntityOptions("
选择第一条多段线: ");
peo1.SetRejectMessage("
请选择一条多段线。");
peo1.AddAllowedClass(typeof(Polyline), false);
PromptEntityResult per1 = ed.GetEntity(peo1);
if (per1.Status != PromptStatus.OK) return;
PromptEntityOptions peo2 = new PromptEntityOptions("
选择第二条多段线: ");
peo2.SetRejectMessage("
请选择一条多段线。");
peo2.AddAllowedClass(typeof(Polyline), false);
PromptEntityResult per2 = ed.GetEntity(peo2);
if (per2.Status != PromptStatus.OK) return;
Polyline pl1 = tr.GetObject(per1.ObjectId, OpenMode.ForRead) as Polyline;
Polyline pl2 = tr.GetObject(per2.ObjectId, OpenMode.ForRead) as Polyline;
if (pl1 == null || pl2 == null)
{
ed.WriteMessage("
错误:选中的对象不是多段线。");
return;
}
// 2. 获取顶点集合(Point2d)
List<Point2d> vertices1 = GetPolylineVertices(pl1);
List<Point2d> vertices2 = GetPolylineVertices(pl2);
// 3. 判断首尾点重合情况(使用容差判断)
double tolerance = 1e-6; // 容差值,可根据精度需求调整
bool start1ToStart2 = vertices1.First().IsEqualTo(vertices2.First(), tolerance);
bool start1ToEnd2 = vertices1.First().IsEqualTo(vertices2.Last(), tolerance);
bool end1ToStart2 = vertices1.Last().IsEqualTo(vertices2.First(), tolerance);
bool end1ToEnd2 = vertices1.Last().IsEqualTo(vertices2.Last(), tolerance);
List<Point2d> mergedVertices = new List<Point2d>();
// 4. 根据重合情况合并顶点
if (end1ToStart2) // 最常见情况:第一条的终点连接第二条的起点
{
mergedVertices.AddRange(vertices1);
mergedVertices.AddRange(vertices2.Skip(1)); // 跳过第二条的第一个顶点(已重合)
}
else if (end1ToEnd2) // 第一条终点连接第二条终点
{
mergedVertices.AddRange(vertices1);
mergedVertices.AddRange(vertices2.AsEnumerable().Reverse().Skip(1)); // 反转第二条并跳过原终点 }
else if (start1ToStart2) // 第一条起点连接第二条起点 {
mergedVertices.AddRange(vertices1.AsEnumerable().Reverse()); // 反转第一条
mergedVertices.AddRange(vertices2.Skip(1)); // 跳过第二条的第一个顶点
}
else if (start1ToEnd2) // 第一条起点连接第二条终点
{
mergedVertices.AddRange(vertices1);
mergedVertices.InsertRange(0, vertices2.Take(vertices2.Count - 1)); // 将第二条(除终点)插入到开头 }
else
{
ed.WriteMessage("
错误:两条多段线没有首尾点重合。");
return;
}
// 5. 创建新的多段线
Polyline newPl = new Polyline();
for (int i = 0; i < mergedVertices.Count; i++)
{
newPl.AddVertexAt(i, mergedVertices[i], 0, 0, 0);
}
// 6. 将新多段线添加到模型空间,并删除旧多段线(可选)
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(
SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
ObjectId newPlId = btr.AppendEntity(newPl);
tr.AddNewlyCreatedDBObject(newPl, true);
// 可选:删除原始多段线
pl1.UpgradeOpen();
pl1.Erase();
pl2.UpgradeOpen();
pl2.Erase();
tr.Commit();
ed.WriteMessage($"
成功合并多段线,新多段线顶点数:{mergedVertices.Count}");
}
catch (System.Exception ex)
{
ed.WriteMessage($"
合并过程中发生错误:{ex.Message}");
}
}
}
/// <summary>
/// 获取多段线的所有顶点(Point2d)
/// </summary>
private List<Point2d> GetPolylineVertices(Polyline pl)
{
List<Point2d> vertices = new List<Point2d>();
for (int i = 0; i < pl.NumberOfVertices; i++)
{
vertices.Add(pl.GetPoint2dAt(i));
}
return vertices;
}
}
关键要点与注意事项
| 要点 | 说明与代码示例 |
|---|---|
| 顶点重合判断 | 必须使用容差比较 (IsEqualTo 方法),因为浮点数计算存在精度问题。tolerance 值通常设为 ` |
1e-6或 |
|
| 1e-9`。 | |
| 顶点顺序处理 | 合并时需根据重合点(起点/终点)的不同组合,决定是否反转其中一条多段线的顶点顺序,以确保新多段线连续。 |
| 获取顶点 | 使用 Polyline.GetPoint2dAt(index) 方法获取二维顶点坐标。若需三维坐标,可使用 GetPoint3dAt。 |
| 容错处理 | 代码应检查两条多段线是否确实在首尾点重合,若不重合应给出明确提示并退出。 |
| 性能与扩展 | 当前方法适用于简单多段线。对于包含圆弧、样条曲线拟合或宽度信息的复杂多段线,合并逻辑需额外处理这些实体数据。 |
处理复杂情况(含圆弧段)的简化思路
如果多段线包含圆弧段,直接连接顶点会导致圆弧信息丢失。此时,更稳健的方法是:
- 使用
Polyline.Explode()方法 将每条多段线分解为直线和圆弧段 (DBObject集合)。 - 将分解得到的线段集合按原顺序合并到一个新的集合中。
- 使用
Polyline.JoinEntities()方法尝试将合并后的线段集合连接成一条新的多段线。
此方法能更好地保留原始几何特性,但实现更为复杂,需处理更多边界情况。