• autocad 二次开发 最小包围圆算法


     

    主要实现了在模型空间下的得到一个包围所有图元的最小圆,该算法的思路是这样:
    1.从点集中随机选出两个点作为直径对圆进行初始化。
    2.判断下一个点p是否在圆中,如果在则继续本步骤,如果不在则进行步骤3。
    3.使用p作为新圆的一个边界点,另一个边界点为距离p最远的圆上的点,使用这两个点作为直径构造新圆。
    4.继续步骤2,直到遍历完所有点。
    参考:https://blog.csdn.net/u010559586/article/details/90903896
    实现出来的效果如图所示:

    首先是获得所有的点,包括参照的点和普通实体的点,获取点之后得到的点集去重。如果是块参照要看它的Bounds属性是否有值,有值就取边界值,如果是普通实体就取Entity的Extends属性的边界点。还有如果是标注,就不计入点,因为标注的边界属性得出来的点不准确。我先得到BlockRecord的Bounds边界,然后继续把这个blockRecord遍历了一遍,得到实体。这样做,我是想把块参照也遍历进去,但是我不知道如何区分普通的实体所在的块和有名块,还有可能有匿名的块参照,我区分不了,,就重复遍历了,最后得到的点集去个重就行了。
    代码:

     public void GetAllPts()
            {
    
                using (var trans = Db.TransactionManager.StartTransaction())
                {
    
                    BlockTable blkTbl = (BlockTable)trans.GetObject(Db.BlockTableId, OpenMode.ForRead);
    
                    foreach (ObjectId oId in blkTbl)
                    {
    
                        var rec = trans.GetObject(oId, OpenMode.ForRead) as BlockTableRecord;
    
                        if (rec != null)
                        {
                            //块参照
                            if (rec.Bounds.HasValue)
                            {
                                var ptMin = rec.Bounds.Value.MinPoint;
                                var ptMax = rec.Bounds.Value.MaxPoint;
                                var radius = (ptMax - ptMin).Length / 2.0;
                                listPts.Add(new Point3d((ptMin.X + ptMax.X) / 2, (ptMin.Y + ptMax.Y) / 2, 0));
                                listRadius.Add(radius);
                            }
                            //实体
                            foreach (ObjectId entId in rec)
                            {
                                var ent = trans.GetObject(entId, OpenMode.ForRead) as Entity;
    
                                //在计算边界属性时,dimension的不准确,我就跳过了
                                if ((ent as Dimension) != null)
                                {
                                    continue;
                                }
    
                                if (ent != null)
                                {
                                    var ptMin = ent.GeometricExtents.MinPoint;
                                    var ptMax = ent.GeometricExtents.MaxPoint;
    
                                    var radius = (ptMax - ptMin).Length / 2.0;
    
                                    listPts.Add(new Point3d((ptMin.X + ptMax.X) / 2, (ptMin.Y + ptMax.Y) / 2, 0));
                                    listRadius.Add(radius);
                                }
                            }
                        }
                    }
                    listPts = listPts.Distinct<Point3d>().ToList();
                    trans.Commit();
                }
            }
    View Code

    得到点集之后,就可以写算法了,这里,我先得到第一个圆,如果模型空间上只有一个图元,我就已这个图元的中心做圆心,边界对角线的一半作为半径 构成一个圆返回;如果是只有两个图元,我就以这两个图元的中心点做直径,直径的中点做圆心构成一个圆返回;如果是3个或者3个以上,我就以点集的第一个点,和点集的中间点构成一个圆返回。代码如下:

     public Circle GetFirstCircle()
            {
                //如果只有一个图,就直接返回这个图元的边界圆
                if (listPts.Count == 1)
                {
                    Circle c = new Circle(listPts[0], Vector3d.ZAxis,  listRadius[0]);
                    return c;
                }
                else if (listPts.Count == 2)
                {
                    var ptMin = listPts[0];
                    var ptMax = listPts[1];
                    var radius = (ptMax - ptMin).Length / 2.0;
                    var ptCenter = new Point3d((ptMin.X + ptMax.X) / 2, (ptMin.Y + ptMax.Y) / 2, 0);
    
                    Circle c = new Circle(ptCenter, Vector3d.ZAxis, radius);
    
                    return c;
    
                }
                else
                {
                    var ptMin = listPts[0];
                    var ptMax = listPts[listPts.Count / 2];
                    var radius = (ptMax - ptMin).Length / 2.0;
                    var ptCenter = new Point3d((ptMin.X + ptMax.X) / 2, (ptMin.Y + ptMax.Y) / 2, 0);
    
                    Circle c = new Circle(ptCenter, Vector3d.ZAxis, radius);
    
                    listPts.Remove(ptMin);
                    listPts.Remove(ptMax);
    
                    return c;
                }
            }
    View Code

    最后是第二步和第三步的算法:

      Database Db = Application.DocumentManager.MdiActiveDocument.Database;
           //所有的点集
            List<Point3d> listPts = new List<Point3d>();
            List<double> listRadius = new List<double>();
    
            [CommandMethod("GetMinC")]
            public void GetCircle()
            {
                listPts.Clear();
                listRadius.Clear();
    
                GetAllPts();
                
                Circle minCircle = null;
                if (listPts.Count >= 3)
                {
                    Circle c= GetFirstCircle();
    
                    for (int i = 0; i < listPts.Count; i++)
                    {
                        var pt = listPts[i];
    
                        var len = c.Radius;
    
                        var cCen = c.Center;
    
                        var len2 = (pt - cCen).Length;
    
                        //如果pt在圆内,继续下一个点
                        if (len > len2)
                        {
                            continue;
                        }
                        else
                        {
                            //求圆心和pt点构成的直线和圆的交点,
                            //并求出pt点离圆最远的那个点pt1或者是Pt2,最后用这两个点构成一个新的圆,继续循环,直到所有的点遍历完
                            var line = new Line(pt, cCen);
    
                            Point3dCollection pt3Coll = new Point3dCollection();
    
                            c.IntersectWith(line, Intersect.ExtendBoth, pt3Coll, IntPtr.Zero, IntPtr.Zero);
    
                            var pt1 = pt3Coll[0];
                            var pt2 = pt3Coll[1];
    
                            var l1 = (pt1 - pt).Length;
                            var l2 = (pt2 - pt).Length;
    
                            if (l1 > l2)
                            {
                                var center = new Point3d((pt1.X + pt.X) / 2, (pt1.Y + pt.Y) / 2, 0);
    
                                c = new Circle(center, Vector3d.ZAxis, l1/2);
                            }
                            else
                            {
                                var center = new Point3d((pt2.X + pt.X) / 2, (pt2.Y + pt.Y) / 2, 0);
    
                                c = new Circle(center, Vector3d.ZAxis, l2 / 2);
                            }
                        }
                    }
                    minCircle = c;
                }
                else
                {
                    minCircle = GetFirstCircle();
                }
                if (minCircle != null)
                    //加入模型空间
                    minCircle.ToSpace();
                minCircle.Dispose();
            }
  • 相关阅读:
    高性能网络编程2----TCP消息的发送
    高性能网络编程1----accept建立连接
    Android之怎样使用ListView列表视图
    创建hive整合hbase的表总结
    最新版本号cocos2d&#173;2.0&#173;x&#173;2.0.2使用新资源载入策略!不再沿用-hd、-
    在NSUserDefaults中保存自己定义的对象
    Light oj 1138
    一个NHibernate的BUG
    hbase exporter importer 导出 导入
    Gulp帮你自己主动搞定coffee和scss的compile
  • 原文地址:https://www.cnblogs.com/HelloQLQ/p/12064009.html
Copyright © 2020-2023  润新知