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() 方法尝试将合并后的线段集合连接成一条新的多段线。

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


参考来源

相关推荐
EIP低代码平台2 小时前
EIP低代码平台 - 应用管理 - 表单设计
低代码·c#·权限·工作流·netcore
czhc11400756632 小时前
726:zoffset
c#
向夏威夷 梦断明暄5 小时前
C# 弃元模式:从语法糖到性能利器的深度解析
服务器·数据库·c#
rick9777 小时前
C# × Python 互操不再难:DotNetPy 让两大生态真正融合
c#
ellis19707 小时前
C#/Unity清理非托管资源
unity·c#
吴可可12321 小时前
C#用OpenCVSharp提取轮廓生成CAD多段线
c#
玖玥拾1 天前
Unity 3D 笔记(十四)Unity/C# Socket 网络笔记3
服务器·网络·unity·c#
玖玥拾1 天前
Unity 3D 笔记(十七)Unity/C# Socket 网络笔记6
服务器·网络·unity·c#
geovindu1 天前
CSharp: Iterative Algorithms
开发语言·后端·算法·c#·.net·迭代算法