cad.net 后台选择集

后台选择集

我把20210510日志贴到此处了,并且删除了日志(些许编辑):

需要1,cad自带的函数ssget如果进行矩形范围选择,那么需要设置屏幕范围可见,API上面提供了w选和c选.
需求2,后台开图没有ssget.

这个时候不妨制作一个自己的选择模式,不用可见:
遍历模型块表记录,图元采样点集,有一点在矩形中就是c选,全部在矩形中就是w选.

你可能认为cad的图元显示应该有一个图元二叉树,显示切换通过树快速拿到对应图元.
但是我都用可行性来说话,首先出库入库经过的管理器和那棵树没开放API,其次每次调用显示就会经过很多层设备IO,
所以这些都是导致了设置可见反而比较慢,
那么就测试一下看看数据,e大的22万级图元遍历也就0.024秒,看这个以偏概全的测试,所以要相信大力也能出奇迹!

说不定cad真就没有这颗树,因为桌子考虑问题的方式一般都是,可能不是最快的结果,但是这个demo最小,能跑就行,否则复杂度上去了就会有连锁反应...(谁要优化小数点后面的秒数呢,其实可以从一些开源cad看这方面的显示处理...
如果要认真处理这个问题,要测试不同量级,计算IO的消耗和遍历比较.
因为遍历可以一次就可以分析多个矩形范围,所以越是多个矩形,那么它效率越高,相反多个IO和多次从树中取果,也增耗时.
例如
10万图元,五个区域(内部要放固定数量的图元),切换ssget的c模式和w模式
30万级.
50万级.
100万级.

从Acad2018版起,ssget不再可见范围了,而是全图.(所以更是适用在后台)

因为本人很懒的关系,本例没有进行耗时操作测试,只是单纯想知道后台选择集怎么制作,所以就敲了以下的代码...
也没有进行w选和c选的区分...这个是c选...

代码

命令

public class 后台选择集
{
    [CommandMethod("Test_SsgetEntity")]
    public void Test_SsgetEntity()
    {
        Document doc = Application.DocumentManager.MdiActiveDocument;
        Editor ed = doc.Editor;
        Database db = doc.Database;//当前的数据库
        ed.WriteMessage("\n****{惊惊盒子}后台选择集:");

        // 获取当前空间块表记录
        List<ObjectId> ids = new();
        db.Action(tr =>
                  {
                      // 块表
                      var acBlkTbl = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                      // 当前空间的块表记录
                      var acBlkTblRec = tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord;
                      ids = acBlkTblRec.Toids();
                  }, false);
        //选择集矩形范围
        var pts = new List<Point3d>()
        {
            new Point3d(100, 100, 0),
            new Point3d(100, 1000, 0) ,
            new Point3d(1000, 1000, 0) ,
            new Point3d(1000, 100, 0) ,
        };
        var idList = new List<ObjectId>();
        db.Ssget(pts, ids, idList);
        db.Action(tr =>
                  {
                      foreach (var id in idList)
                      {
                          var ent = id.ToEntity(tr);
                          ent.UpgradeOpen();
                          ent.ColorIndex = 11;

                          if (ent is BlockReference brf)
                          {
                              ChangColorIndex(brf, tr);
                          }
                          ent.DowngradeOpen();
                      }
                  });
    }

    // 递归块改颜色..
    void ChangColorIndex(BlockReference brf, Transaction tr)
    {
        // 这里需要嵌套块处理了
        var btRec = tr.GetObject(brf.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
        foreach (var item in btRec)
        {
            var entItem = item.ToEntity(tr);
            if (entItem is BlockReference brfItem)
            {
                ChangColorIndex(brfItem, tr);//进入递归
            }
            entItem.UpgradeOpen();
            entItem.ColorIndex = 0;//随块
            entItem.DowngradeOpen();
            entItem.Dispose();
        }
    }
}

函数

namespace JoinBox
{
    public static partial class GetEnttityTool
    {
		/// <summary>
        /// 非可视范围选择集制作,增加矩形范围选择
        /// </summary>
        /// <param name="db">数据库</param>
        /// <param name="pts">多段线范围</param>
        /// <param name="idsInit">输入来筛选的ids,来自于当前空间</param>
        /// <param name="idsOut">输出筛选后的id</param>
        public static void Ssget(this Database db, IEnumerable<Point3d> pts, List<ObjectId> idsInit, List<ObjectId> idsOut)
        {
            var ss = new JoinBoxSsget(db, pts, idsInit);
            idsOut.AddRange(ss.IdsOut);
        }
    }
}

public class JoinBoxSsget
{
    Point3d[] PtsArr { get; set; }
    public List<ObjectId> IdsOut { get; private set; }

    /// <summary>
    /// 后台选择集
    /// </summary>
    /// <param name="db"></param>
    /// <param name="pts"></param>
    /// <param name="idsInit"></param>
    public JoinBoxSsget(Database db, IEnumerable<Point3d> pts, IEnumerable<ObjectId> idsInit)
    {
        if (pts.IsNull())
        {
            throw new ArgumentNullException("SsgetRectangleEntity点集范围为空");
        }
        if (idsInit.IsNull())
        {
            throw new ArgumentNullException("SsgetRectangleEntity图元集合为空");
        }
        PtsArr = pts.ToArray();
        IdsOut = new List<ObjectId>();

        db.Action(tr =>
                  {
                      foreach (var id in idsInit)
                      {
                          var ent = id.ToEntity(tr);
                          //这里还要处理 点  面域之类的............................................
                          if (ent is BlockReference brf)
                          {
                              // 嵌套块判断需要将边界坐标从块基点平移
                              var ptmove = new List<Point3d>();
                              foreach (var pt in PtsArr)
                              {
                                  ptmove.Add((pt - brf.Position).ToPoint3d());
                              }
                              var IdsOutBlock = new List<ObjectId>();
                              SetBlock(brf, tr, IdsOutBlock, ptmove.ToArray());//进入递归,要把块id输出,而不是内部图元id输出
                              if (IdsOutBlock.Count > 0)
                              {
                                  IdsOut.Add(brf.ObjectId);
                              }
                          }
                          else
                          {
                              SetEntity(ent, IdsOut, PtsArr);
                          }
                          ent.Dispose();
                      }
                  }, false);
    }

    /// <summary>
    /// 嵌套块用递归处理
    /// </summary>
    void SetBlock(BlockReference brf, Transaction tr, List<ObjectId> idsOut, Point3d[] ptsArr)
    {
        // 这里需要嵌套块处理了
        var btRec = tr.GetObject(brf.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
        foreach (var item in btRec)
        {
            var entItem = item.ToEntity(tr);
            if (entItem is BlockReference brfItem)
            {
                SetBlock(brfItem, tr, idsOut, ptsArr);//进入递归
            }
            else //如果不是块进入
            {
                SetEntity(entItem, idsOut, ptsArr);
                if (idsOut.Count > 0)//存在就表示这个块是选择集了
                {
                    return;
                }
            }
        }
    }

    /// <summary>
    /// 非块处理
    /// </summary>
    void SetEntity(Entity ent, List<ObjectId> idsOut, Point3d[] ptsArr)
    {
        //进行采样处理
        if (ent is Xline || ent is Ray)//参照线 射线(还没处理射线交点,开头处不一定和边界碰撞)
        {
            Pt2 xlPt1 = null;
            Pt2 xlPt2 = null;

            //利用反射获取
            var entType = ent.GetType();
            var entBasePoint = entType.GetProperty("BasePoint");//反射获取属性
            if (entBasePoint != null)
            {
                var obj = (Point3d)entBasePoint.GetValue(ent, null);
                xlPt1 = new Pt2(obj.ToArray());
            }
            var entSecondPoint = entType.GetProperty("SecondPoint");//反射获取属性
            if (entSecondPoint != null)
            {
                var obj = (Point3d)entSecondPoint.GetValue(ent, null);
                xlPt2 = new Pt2(obj.ToArray());
            }

            // 判断参照线与边界的交点,且交点落在边界上,则为选中
            for (int i = 0; i < ptsArr.Length - 1; i++)
            {
                // 求两条直线的交点,如果平衡则是null
                var jiaodian = JoinBoxCurrency.MathTool.GetIntersectionPoint(
                    xlPt1,
                    xlPt2,
                    new Pt2(ptsArr[i].ToArray()),
                    new Pt2(ptsArr[i + 1].ToArray()));
                if (jiaodian != null)
                {
                    // 在判断交点在选择集边线子段之间,用凸度0判断
                    var pt_jiaodian = new Point3d(jiaodian.X, jiaodian.Y, 0);
                    var bulge = MathTool.GetBulge(ptsArr[i], pt_jiaodian, ptsArr[i + 1]);
                    if (bulge == 0)
                    {
                        idsOut.Add(ent.ObjectId);
                        break;
                    }
                }
            }
        }
        else if (ent is Curve curve)
        {
            try
            {
                var cs = new CurveSample<Point3d>(curve, 300);
                bool flag = false;
                foreach (var item in cs.GetSamplePoints)
                {
                    if (item.IsPointInPL(ptsArr))
                    {
                        flag = true;
                        break;
                    }
                }
                if (flag)
                {
                    idsOut.Add(ent.ObjectId);
                }
            }
            catch (System.Exception e)
            {
                throw e;
            }
        }
    }
}

缺省函数链接

JoinBoxCurrency.MathTool.GetIntersectionPoint 数学篇 求两条直线的交点,说明过程

MathTool.GetBulge 数学篇 cad.net 向量+点乘+叉乘+矩阵+凸度

CurveSample 数学篇 cad.net 葛立恒凸包算法和面积最小包围盒

(完)

上一篇:Codeforces Round #769 (Div. 2) C D


下一篇:ik分词器支持标点符号,特殊字符分词(分词结果包含特殊字符)