cad.net 根据块名获取所有插入块的id+GetNext块

说明

这个操作用来提供查找同名块,
见代码一共有两种方案,一种是遍历全图,一种是通过cad内部储存机制(大概是一个表结构)
遍历全图必然比cad预先提供的获取慢.
其中获取嵌套块的id,大家可以自己推导一下规律...

代码

c#

#if !HC2020
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
#else
using GrxCAD.DatabaseServices;
using GrxCAD.Runtime;
using GrxCAD.EditorInput;
using Acap = GrxCAD.ApplicationServices.Application;
#endif
using System;

namespace JoinBox
{
    public class GetBlockReferenceIds
    {    
        [CommandMethod("CmdTest_GetBlockReferenceIds")]
        public void CmdTest_GetBlockReferenceIds()
        {
            var dm = Acap.DocumentManager;
            var doc = dm.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            ed.WriteMessage("\n根据块名获取所有插入块图元名列表:");
            ed.WriteMessage("\n选择图元(儿子)");

            //定义选择集选项
            var pso = new PromptSelectionOptions
            {
                RejectObjectsOnLockedLayers = true, //选择锁定图层对象
                AllowDuplicates             = true, //允许重复选择
            };
            var ssPsr = ed.GetSelection(pso);
            if (ssPsr.Status != PromptStatus.OK)
                return;

            db.Action(tr => {
                foreach (var id in ssPsr.Value.GetObjectIds())
                {
                    if (!id.IsOk())
                        continue;
                    var ent = id.ToEntity(tr);
                    if (ent == null)
                        continue;
                    if (ent is BlockReference brf)
                    {
                        var btRec = tr.GetObject(brf.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;

                        /*
                         *  btRec.GetBlockReferenceIds(true不获取嵌套的最外层,用于旧图元修复一直为true就好)
                         *  必须是 BlockReference ,是模型空间就什么都获取不了
                         *  这个方法是用来寻找 BlockReference 块参照 在数据库中全部数量!
                         *
                         *  利用嵌套块,选择儿子,得到:
                         *
                         *  false参数++++++++++++++++++++++++++
                         *  块名:子;;;Handle是:1E3 (我)
                         *
                         *  块名:子;;;Handle是:1EA (我,一层嵌套)
                         *  块名:父;;;Handle是:1EB
                         *
                         *  块名:父;;;Handle是:1F2
                         *  块名:爷;;;Handle是:1F3
                         *
                         *  块名:爷;;;Handle是:1FC
                         *  块名:曾爷;;;Handle是:1FD
                         *
                         *  true参数++++++++++++++++++++++++++
                         *  块名:子;;;Handle是:1E3 (我)
                         *  块名:子;;;Handle是:1EA (我,一层嵌套)
                         */
                        //方案一:例如cad自带的树形图进行查询,比遍历块
                        var brfIds1 = btRec.GetBlockReferenceIds(false, true);
                        ed.WriteMessage("\nfalse参数++++++++++++++++++++++++++");
                        foreach (ObjectId item in brfIds1)
                        {
                            if (item.ToEntity(tr) is BlockReference brf2)
                                ed.WriteMessage($"\n块名:{brf2.Name};;;Handle是:{brf2.Handle}");
                        }

                        var brfIds2 = btRec.GetBlockReferenceIds(true, true);
                        ed.WriteMessage("\ntrue参数++++++++++++++++++++++++++");
                        foreach (ObjectId item in brfIds2)
                        {
                            if (item.ToEntity(tr) is BlockReference brf2)
                                ed.WriteMessage($"\n块名:{brf2.Name};;;Handle是:{brf2.Handle}");
                        }
                    }
                }
            });
            return;

            //方案二:遍历全图
            db.Action(tr => {
                var id = SymbolUtilityServices.GetBlockModelSpaceId(db);
                var modelSpace = tr.GetObject(id, OpenMode.ForRead) as BlockTableRecord;

                var insert = RXObject.GetClass(typeof(BlockReference)).DxfName;

                //遍历模型空间,获取同名动态块数量
                var blocks = modelSpace/*也可以直接用 整个块表 啊...*/
                .Cast<ObjectId>()
                //.Where(id => id.ObjectClass.DxfName == insert)
                .Where(id =>
                    id.GetDxfName(tr) == insert)//如果是块参照
                .Select(id =>
                    (BlockReference)tr.GetObject(id, OpenMode.ForRead))//打开定义
                .GroupBy(br =>
                    ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name);//获取真实的块名

                foreach (var group in blocks)
                    ed.WriteMessage($"\n{group.Key}: {group.Count()}");
            });
        }
    }
}

lisp

;;根据块名获取所有插入块图元名列表
(defun GetBlockReferenceIds (blkName / blkHeader dxf330 elist lst @sk_dxf) 
  (defun @sk_dxf (ent code) 
    (cdr (assoc code (entget ent)))
  )
  (if (setq blkHeader (tblobjname "block" blkname)) 
    (progn 
      (setq dxf330 (@sk_dxf blkHeader 330))
      (setq elist (entget dxf330))
      (while (setq a (car elist)) 
        (if (= (car a) 331) 
          (setq lst (cons (cdr a) lst))
        )
        (setq elist (cdr elist))
      )
      (reverse lst)
    )
  )
)

相关问题

0x01 getNext得到的entity怎么能获取它所在的块参照呢?

提示,ent.blockId和ent.blockName是块表记录

答案:不可能.
块内图元直接get的话,因为是块表记录着图元,不是储存在模型同级的.
也就是每次都拷贝一份出来,然后显示在模型(概念)

图元和图元之间没有从属关系,所以只有块表记录储存图元信息,因此不存在这样的操作...
要修改getNext的图元也会作用在块表记录上(全体参照).

如果图元和图元之间有从属关系,那么就会导致我修改这个图元所属,
便不需要打开另一个图元记录,造成权限溢出.
也会导致,不是块参照的图元拥有了另一个图元,造成歧义.

0x02 那么要怎么getNext到块内块上面呢?

而不是到entity.
getNext参数上面有这个选项.

(完)

posted @ 2022-03-13 22:55  惊惊  阅读(1282)  评论(0编辑  收藏  举报