凸包算法—— cad c#二次开发

发布于:2025-02-14 ⋅ 阅读:(145) ⋅ 点赞:(0)

 效果如下:

 代码如下:


using IfoxDemo;
//[assembly: CommandClass(typeof(IFoxDemo.凸包class))]//只允许此类快捷键命令
namespace IFoxDemo
{
    public class 凸包class
    {
        public static class 凸包助手
        {
            /// <summary>
            /// 计算点集的凸包并返回多段线
            /// </summary>
            /// <param name="pts">点集合</param>
            /// <returns>凸包多段线</returns>
            public static Polyline 计算凸包(List<Point2d> pts)
            {
                if (pts == null || pts.Count < 3)
                {
                    throw new ArgumentException("至少需要三个点来计算凸包。");
                }

                // 计算凸包点集
                List<Point2d> convexHullPoints = 筛选凸包点(pts);

                // 创建多段线
                Polyline convexHullPolyline = new Polyline();
                for (int i = 0; i < convexHullPoints.Count; i++)
                {
                    convexHullPolyline.AddVertexAt(i, convexHullPoints[i], 0, 0, 0);
                }

                // 闭合多段线
                convexHullPolyline.AddVertexAt(convexHullPoints.Count, convexHullPoints[0], 0, 0, 0);
                convexHullPolyline.Closed = true;

                return convexHullPolyline;
            }

            /// <summary>
            /// 使用 Andrew's monotone chain 算法计算凸包
            /// </summary>
            /// <param name="points">输入点集</param>
            /// <returns>凸包点集</returns>
            private static List<Point2d> 筛选凸包点(List<Point2d> points)
            {
                // 按 X 坐标排序,如果 X 相同则按 Y 排序
                points.Sort((a, b) => a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X));

                List<Point2d> hull = new List<Point2d>();

                // 构建下凸包
                foreach (var pt in points)
                {
                    while (hull.Count >= 2 && Cross(hull[hull.Count - 2], hull[hull.Count - 1], pt) <= 0)
                    {
                        hull.RemoveAt(hull.Count - 1);
                    }
                    hull.Add(pt);
                }

                // 构建上凸包
                int lowerHullCount = hull.Count + 1;
                for (int i = points.Count - 1; i >= 0; i--)
                {
                    var pt = points[i];
                    while (hull.Count >= lowerHullCount && Cross(hull[hull.Count - 2], hull[hull.Count - 1], pt) <= 0)
                    {
                        hull.RemoveAt(hull.Count - 1);
                    }
                    hull.Add(pt);
                }

                // 移除最后一个点,因为它是第一个点的重复
                hull.RemoveAt(hull.Count - 1);

                return hull;
            }

            /// <summary>
            /// 计算叉积
            /// </summary>
            /// <param name="O">起点</param>
            /// <param name="A">点 A</param>
            /// <param name="B">点 B</param>
            /// <returns>叉积值</returns>
            private static double Cross(Point2d O, Point2d A, Point2d B)
            {
                return (A.X - O.X) * (B.Y - O.Y) - (A.Y - O.Y) * (B.X - O.X);
            }
        }
        public class 凸包Demo类
        {
            [CommandMethod("tub")]
            public void 凸包Demo()
            {
                Document doc = Application.DocumentManager.MdiActiveDocument;
                Database db = doc.Database;
                Editor ed = doc.Editor;
                var pts = new List<DBPoint>();
                if  (! ed.GetEntities(out pts ,"") ) return;
                //List<Point2d> points = new List<Point2d>();
                //foreach (DBPoint p in pts)
                //{
                //    points.Add(new Point2d(p.Position.X,p.Position.Y));
                //}下面为lambda等效写法
                List<Point2d> points = pts.Select(p => new Point2d(p.Position.X, p.Position.Y)).ToList();
                #region
                 获取点集合(这里假设用户已经选择了一些点)
                //PromptPointOptions ppo = new PromptPointOptions("\n选择点: ");
                //ppo.AllowNone = false;
                //ppo.Keywords.Add("Done");

                //List<Point2d> points = new List<Point2d>();
                //while (true)
                //{
                //    PromptPointResult ppr = ed.GetPoint(ppo);
                //    if (ppr.Status == PromptStatus.Keyword && ppr.StringResult == "Done")
                //    {
                //        break;
                //    }
                //    points.Add(new Point2d(ppr.Value.X, ppr.Value.Y));
                //}

                //if (points.Count < 3)
                #endregion
                if (points.Count < 3)
                    {
                    ed.WriteMessage("\n至少需要三个点来计算凸包。");
                    return;
                }

                // 计算凸包
                Polyline pl = 凸包助手.计算凸包(points);

                // 将多段线添加到当前图形
                #region
                //using (Transaction tr = db.TransactionManager.StartTransaction())
                //{
                //    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                //    BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;

                //    btr.AppendEntity(convexHullPolyline);
                //    tr.AddNewlyCreatedDBObject(convexHullPolyline, true);

                //    tr.Commit();
                //}
                #endregion
                using var dbtrans = new DBTrans();
                dbtrans.CurrentSpace.AddEntity(pl);
                ed.WriteMessage("\n凸包多段线已创建。");
            }
        }
        public class 产生随机点
        {
            [CommandMethod("cssjd")]
            public void CreateRandomPoints()
            {
                Document doc = Application.DocumentManager.MdiActiveDocument;
                Database db = doc.Database;
                Editor ed = doc.Editor;

                // 提示用户输入点的数量
                PromptIntegerOptions pio = new PromptIntegerOptions("\n请输入要创建的点数量: ");
                pio.AllowNegative = false;
                pio.AllowZero = false;
                pio.DefaultValue = 10;

                PromptIntegerResult pir = ed.GetInteger(pio);
                if (pir.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("\n用户取消操作。");
                    return;
                }

                int pointCount = pir.Value;

                // 提示用户输入随机点的范围
                PromptPointOptions ppo = new PromptPointOptions("\n指定随机点的范围(左下角点): ");
                PromptPointResult ppr1 = ed.GetPoint(ppo);
                if (ppr1.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("\n用户取消操作。");
                    return;
                }

                ppo.Message = "\n指定随机点的范围(右上角点): ";
                PromptPointResult ppr2 = ed.GetPoint(ppo);
                if (ppr2.Status != PromptStatus.OK)
                {
                    ed.WriteMessage("\n用户取消操作。");
                    return;
                }

                Point3d lowerLeft = ppr1.Value;
                Point3d upperRight = ppr2.Value;

                // 创建随机点
                Random random = new Random();
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                    BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;

                    for (int i = 0; i < pointCount; i++)
                    {
                        double x = lowerLeft.X + (upperRight.X - lowerLeft.X) * random.NextDouble();
                        double y = lowerLeft.Y + (upperRight.Y - lowerLeft.Y) * random.NextDouble();

                        Point2d randomPoint2d = new Point2d(x, y);
                        Point3d randomPoint3d = new Point3d(randomPoint2d.X, randomPoint2d.Y, 0);

                        // 创建点实体
                        DBPoint dbPoint = new DBPoint(randomPoint3d);
                        btr.AppendEntity(dbPoint);
                        tr.AddNewlyCreatedDBObject(dbPoint, true);
                    }

                    tr.Commit();
                }

                ed.WriteMessage($"\n成功创建 {pointCount} 个随机点。");
            }
        }
    }
}

逆时针最小夹角

 cad 二次开发、插件代写↓↓↓


网站公告

今日签到

点亮在社区的每一天
去签到