乐筑天下

搜索
欢迎各位开发者和用户入驻本平台 尊重版权,从我做起,拒绝盗版,拒绝倒卖 签到、发布资源、邀请好友注册,可以获得银币 请注意保管好自己的密码,避免账户资金被盗
查看: 71|回复: 2

[编程交流] Alternate way(s) to determine

[复制链接]

2

主题

12

帖子

17

银币

初来乍到

Rank: 1

铜币
14
发表于 2022-7-5 15:49:08 | 显示全部楼层 |阅读模式
I am writing a lisp routine which processes user selected (via ssget) blocks and outputs various data (handle, insertion point, rotation, specific attribute values) to a CSV text file. It processes both top-level blocks and nested blocks to any level.
 
This lisp routine needs to run on both AutoCAD for Windows & AutoCAD for Mac, so that limits options a little (no vla-, vlax-, and vlr- functions) and also why I can't just use the data extraction tool.
 
For each unique block definition the code builds an association list with block name as the key and a list of enames for all sub-entities of type INSERT e.g.
 
( (Block Name #1 . (  ...)) (Block Name #2) ...)
 
Subsequent instances of the block then just process the sub-entities in the association list, rather than needing to iterate though the entire block definition again.
 
This whole process is done recursively to handle the nested blocks - relevant section of code below:
 
  1. ;; ... code to initialize output file/selection set etc;; iterate through blocks in selection set(repeat (setq Idx (sslength Sel));; get current entity from Sel, re-set BlkProcessed & Parents(setq    Blk (ssname Sel (setq Idx (1- Idx)))    BlkProcessed nil    Parents nil);;-------------------------------------------------------------------------;; ProcessBlk - Process block entity sub-routine;;                  Initial block added to NstLst as key value with;;                associated INSERT sub-entities, if found.;;                All duplicate blocks just process stored sub-entities.;;                Data for all blocks written as CSV line to output file;;              Sub-Routine to allow recursive calling;; Arguments: 2           ;;    Blk = Block Entity [as entity name];;    Parents = Parent Entities (parent grandparent...) [as list]           ;; Returns: nil           ;;-------------------------------------------------------------------------(defun ProcessBlk (Blk Parents / Item EntLst SubEnt BlkName EntData )    ;; get entity data & block name    (setq        EntData (entget Blk)        BlkName (cdr (assoc 2 EntData))    )        ;; add Blk to NstLst if not already a memeber    (if (not (Member BlkName (mapcar 'car NstLst)))        (Progn            ;; get 1st sub-entity from Block definition table & add to EntLst            (setq                SubEnt (cdr (assoc -2 (tblsearch "BLOCK" BlkName)))                EntLst (cons SubEnt EntLst)            )            ;; iterate remaning sub-entites & add to EntLst            (while                (setq SubEnt (entnext SubEnt))                (setq EntLst (cons SubEnt EntLst))            )            ;; filter EntLst add to NstLst w/BlkName as key            (setq                EntLst (vl-remove-if-not '(lambda(x) (= (cdr (assoc 0 (entget x))) "INSERT")) EntLst)                NstLst (cons (cons BlkName EntLst) NstLst)            )        )  ;; END progn            )  ;; END if    ;; write out CSV line data for Blk    (princ (BuildBlkInfo Blk EntData BlkName Parents) Dest)    ;; set BlkProcessed to T if currently nil    (if (not BlkProcessed) (setq BlkProcessed T))    ;; append current Blk to Parents    (setq Parents (cons Blk Parents))    ;; process all nested blocks associated w/BLkName in NstLst    (foreach Item (cdr (assoc BlkName NstLst))        (ProcessBlk Item Parents)    )) ;; END Defun;; Process top-level Blk, if not already processed(if (not BlkProcessed) (ProcessBlk Blk nil))   ) ;; END repeat   ;; ... code to close output file & provide feedback to user
 
Whilst this all works fine I have found a couple of specific blocks in my test drawings are taking a long time to process & subsequently slowing down the overall code execution. The 'problem' blocks are taking ±5sec to pre-process & add to NstLst, and whilst I'm only doing this once per unique block definition it still has quite an impact relative to the rest of the code execution.
 
Looking at these 'problem' blocks in more detail, they appear comprise of ±450 sub-entities, the vast majority of which are 3DSOLID entities.
 
Iterating through that many sub-entities does not appear to be the root-cause of slow-down, in fact if I bypass the vl-remove-if-not filtering of EntLst the pre-processing time is comparable to other 'non-problem' blocks in the drawing; however as soon I introduce entget everything slows down.
 
When I examine the returned data from entget I see that the association list has ±3200 items, the majority of which are encrypted model geometry.
 
I have tried various methods of determining the value of group code 0 in the returned list (assoc, nth, cdr, member) in the hope that it might affect how the list is processed and mean that not all 3200 items would need to be iterated through.
 
I have also tried performing the entget/type test as I'm iterating the sub-entities to determine if they get added to NstLst, rather than just adding all and then filtering at the end. Nothing I've tried has had any meaningful impact on the pre-processing time.
 
It seems to me that the actual act of performing the entget is what is slowing things down due to the size of the return data list. I tried performing entget 450 times on a 'regular' entity and had no slow down at all —which leads to my question(s):
 


  • Is there an alternate way to obtain the entity type without using entget, which would be faster?
  • Is it possible to do a 'partial entget' i.e. only get the first 2 items?
  • Would it be possible to create a filtered selection set i.e. like (ssget "X" '((0 . "INSERT"))) but only for block-specific sub-entities?

 
Ideally the solution would work on both AutoCAD for Mac & AutoCAD for Windows although I'm not adverse to having OS-specific sections of code to allow faster implementation for Windows users if there is an ActiveX or similar Windows-only function that will help here.
 
Thanks
回复

使用道具 举报

18

主题

1529

帖子

973

银币

中流砥柱

Rank: 25

铜币
649
发表于 2022-7-5 16:25:05 | 显示全部楼层
Use the getpropertyvalue function to check the objectname.
回复

使用道具 举报

2

主题

12

帖子

17

银币

初来乍到

Rank: 1

铜币
14
发表于 2022-7-5 16:53:29 | 显示全部楼层
Thanks Roy - that did the trick!
 
I swapped out the line...
 
EntLst (vl-remove-if-not '(lambda(x) (= (cdr (assoc 0 (entget x))) "INSERT")) EntLst)
 
for
 
EntLst (vl-remove-if-not '(lambda(x) (= "Block Reference" (getpropertyvalue x "LocalizedName"))) EntLst)
 
The previous run-time for my test drawing was ±13sec to process (1106) x blocks, 217 of which were nested. By swapping out the entget to getpropertyvalue the run time reduced to ±2sec.
 
Much simpler than I feared it would be, plus works on both AutoCAD for Windows & AutoCAD for Mac.
 
Really appreciate it.
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  • 微信公众平台

  • 扫描访问手机版

  • 点击图片下载手机App

QQ|关于我们|小黑屋|乐筑天下 繁体中文

GMT+8, 2025-3-14 13:06 , Processed in 2.624169 second(s), 58 queries .

© 2020-2025 乐筑天下

联系客服 关注微信 帮助中心 下载APP 返回顶部 返回列表