Search code examples
vbagroupingautocadautolisp

VBA/AutoLisp - How to check if a block is grouped through code in AutoCAD


I am working with groups in AutoCAD and, due to copy pasting them from different drawings, they ungroup. In the possibility of me forgetting to regroup them, I want to create a code that, when I think I am finished with the drawing, can check if a list of blocks (every group has a block) is not inside a group.

As such, the idea is that it would run from a selection of blocks (ex: block1, block3, block7) and check if those particular blocks are grouped. If not, it would tell me which block is ungrouped.

As the tags suggest, either vba or autolisp is fine. I am fairly novice at this, any help would be fairly appreciated.

edit: knowing how I could get a block group name in vba would be great


Solution

  • Background

    A block definition may have many block references: the block definition is analogous to the blueprints for a building, with each block reference analogous to the construction of the building itself.

    As such, given only a list of block names, each block name may correspond to multiple block references, with some contained within groups, and others not.


    Methods

    You can therefore approach this task from two angles:

    • Iterate over all Groups defined within the drawing (either using the ActiveX Groups Collection, or the ACAD_GROUP dictionary contained within the Named Object Dictionary), and obtain the set of distinct block names corresponding to blocks contained within at least one Group.

    OR

    • Iterate over all Block References within the drawing and test whether the block reference has a link to a GROUP entity via an {ACAD_REACTORS} entry in the DXF data. Compile a list of block names corresponding to blocks which are either contained within at least one group, or not contained within any group.

    Given such a list, you can then easily test whether any of your block names are not present in the list.


    Sample Code

    Below is a function that will iterate over all Groups defined within the ACAD_GROUP dictionary of the Named Object Dictionary, and will return a list of the names of block references contained within one or more groups:

    (defun blocknamesfromgroups ( / blk dic enx grp rtn )
        (if (setq dic (cdr (assoc -1 (dictsearch (namedobjdict) "acad_group"))))
            (while (setq grp (dictnext dic (not grp)))
                (foreach itm grp
                    (if (and (= 340 (car itm)) (= "INSERT" (cdr (assoc 0 (setq enx (entget (cdr itm)))))))
                        (if (not (member (setq blk (cdr (assoc 2 enx))) rtn))
                            (setq rtn (cons blk rtn))
                        )
                    )
                )
            )
        )
        (reverse rtn)
    )
    

    Alternatively, the below function will iterate over all primary block references in the active drawing and will report the names of block references not contained within a group:

    (defun blocknamesnotgrouped ( / blk enx grp idx sel rtn )
        (if (setq sel (ssget "_X" '((0 . "INSERT"))))
            (repeat (setq idx (sslength sel))
                (setq idx (1- idx)
                      enx (entget (ssname sel idx))
                      blk (cdr (assoc 2 enx))
                )
                (if
                    (not
                        (or
                            (and
                                (setq enx  (member '(102 . "{ACAD_REACTORS") enx))
                                (setq grp  (cdr (assoc 330 enx)))
                                (= "GROUP" (cdr (assoc 0 (entget grp))))
                            )
                            (member blk rtn)
                        )
                    )
                    (setq rtn (cons blk rtn))
                )
            )
        )
        (reverse rtn)
    )