C# CAD二次开发:合并首尾重合多段线

在 C# AutoCAD 二次开发中,合并两条首尾点重合的多段线,核心是获取并连接它们的顶点集合,然后创建一条新的多段线。关键在于精确判断重合点,并处理顶点顺序。

核心步骤与代码实现

  1. 获取两条多段线的顶点集合
  2. 判断并找到重合的顶点(起点或终点)。
  3. 根据重合情况,重新排序并合并顶点列表
  4. 使用合并后的顶点创建一条新的多段线,并(可选)删除原有多段线。

以下是完整的实现代码示例:

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
容错处理 代码应检查两条多段线是否确实在首尾点重合,若不重合应给出明确提示并退出。
性能与扩展 当前方法适用于简单多段线。对于包含圆弧、样条曲线拟合或宽度信息的复杂多段线,合并逻辑需额外处理这些实体数据。

处理复杂情况(含圆弧段)的简化思路

如果多段线包含圆弧段,直接连接顶点会导致圆弧信息丢失。此时,更稳健的方法是:

  1. 使用 Polyline.Explode() 方法 将每条多段线分解为直线和圆弧段 (DBObject 集合)。
  2. 将分解得到的线段集合按原顺序合并到一个新的集合中。
  3. 使用 Polyline.JoinEntities() 方法尝试将合并后的线段集合连接成一条新的多段线。

此方法能更好地保留原始几何特性,但实现更为复杂,需处理更多边界情况。


参考来源

相关推荐
波波0071 天前
C# 15 重磅新特性: 带标签 break 与 continue:重新定义嵌套循环控制流
服务器·前端·c#
wujian83111 天前
怎么用千问生成word文档:从「格式崩」到「一键过」,AI导出鸭打通最后半厘米
人工智能·ai·c#·word·豆包·deepseek·ai导出鸭
zlinear数据采集卡1 天前
D223上位机C#开发实战:从帧解析到波形显示的完整实现
开发语言·arm开发·嵌入式硬件·fpga开发·开源·c#
唐青枫1 天前
别把 ImmutableArray 当成只读 List:C#.NET 不可变数组深入详解
c#·.net
zlinear数据采集卡1 天前
D223 ADC数据处理流水线:从原始采样值到工程单位的完整转换链
开发语言·arm开发·嵌入式硬件·fpga开发·开源·c#
花落人散处1 天前
CDiskClean 开发历程 —— 文件清理_目录树解析实现方案参考
c#
离陌在学C#1 天前
C# 泛型:从基础到高级应用
开发语言·c#
Vertira1 天前
C# 与 OpencvSharp 编程[基础目录]
c#
格林威1 天前
多相机并行采图最佳实践:Task.WhenAll + 异常处理 + 资源释放
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·机器视觉