非常无聊的多重插入匿名块(Anonymous Block)

最近有同事遇到了 AutoCAD 中的一种图块,不能用 explode 命令或 AutoCAD Express Tool 的 burst 命令进行分解。查看一下这种图块的属性,其图元是多重块插入(MINSERT),行、列数量均为 1,行、列间距均为 0。多重块插入(MINSERT)是不能用这两个命令分解的,如果我们找到了这个图块的块名,直接插入普通的块插入(INSERT),这个块插入就能够被分解。不过,使用这种多重块插入进行锁定防止分解的时候,操作者一般会使用匿名块(Anonymous Block),这样,这种图块就不能通过 insert 命令来插入到图形数据库中,从而能起到更好的锁定作用。这种技术其实挺无聊的,解锁的方法其实也非常简单,今天就来聊一聊这个问题。

多重插入匿名块锁定方法

我们可以使用 AutoLisp/VisualLisp 来完成这样的工作,下面列出这种方法的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
(defun c:lock(/ blockname ss sslst)
(vl-load-com)
(if (setq ss (ssget))
(progn
(setq blockname (rtos (getvar "CDATE") 2 8)
i 0
sslst '(((0 . "ENDBLK")))
)
(repeat (sslength ss)
(setq sslst (cons (entget (ssname ss i)) sslst))
(entdel (ssname ss i))
(setq i (1+ i))
)
(setq sslst (cons (list '(0 . "BLOCK") (cons 2 blockname) '(70 . 0) '(10 0.0 0.0 0.0)) sslst))
(mapcar 'entmake sslst)
(entmake
(list
'(0 . "INSERT")
(cons 2 blockname)
'(100 . "AcDbEntity")
'(8 . "0")
'(100 . "AcDbBlockReference")
(cons 10 '(0.0 0.0 0.0))
'(70 . 1)
'(71 . 1)
'(44 . 0.0)
'(45 . 0.0)
)
)
(vla-put-name
(vla-item
(vla-get-blocks
(vla-get-activedocument (vlax-get-acad-object))
)
(vla-get-name (vlax-ename->vla-object (entlast)))
)
"*U")
)
(princ "\n 未选中图元!")
)
(princ)
)

代码的主体 3~40 行是对选中图元情况作出一个判断分支,未选定图元的情况不需要赘述。在选定图元的情况下,9~13 行遍历所有选中图元,获取图元的组码列表,并将其加入到 sslst 表中,并删除图元。遍历之前,sslst 中先加入了 '((0 . "ENDBLK")) 作为图块定义的结束,遍历之后,sslst 中再加入图块定义开始的组码列表,其中块名使用由当前时间转换的一个字符串。对 sslst 中的每个表进行 entmake 后,就创建了一个图块定义。16~29 行的工作是在原位以多重块插入的形式重建这些图元。30~37 行的工作是修改了刚刚插入的图块的块定义,将其改为匿名块。至此,AutoCAD 中的这部分图元就以一个匿名块的形式存在,不能够用 explodeburst 命令分解,也不能通过 insert 命令插入在图形数据库中。

块解锁分解方法

除了使用多重插入匿名块的方法进行锁定外,图块(BLOCK)本身也有通过块分解性特性的设定来防止分解,这里我们将这两种情况一并考虑,解锁图块并分解的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
(defun c:unlock(/ ename ellst blkobj flag)
(vl-load-com)
(while (not (= (cdr (assoc 0 (setq ellst (entget (setq ename (car (entsel))))))) "INSERT"))
(princ "\n 选择的不是图块!")
)
(setq blkobj
(vla-item
(vla-get-blocks
(vla-get-activedocument (vlax-get-acad-object))
)
(vla-get-name (vlax-ename->vla-object ename))
)
)
(if (equal :vlax-false (vla-get-Explodable blkobj))
(progn
(vla-put-Explodable blkobj :vlax-true)
(setq flag T)
)
)
(if (and (= (cdr (assoc 70 ellst)) 1 ) (= (cdr (assoc 71 ellst)) 1 ))
(progn
(entdel ename)
(entmake
(setq ellst
(vl-remove-if
'(lambda(x)
(or
(= (car x) -1)
(= (car x) 70)
(= (car x) 71)
(= (car x) 44)
(= (car x) 45)
)
)
ellst
)
)
)
(setq ename (entlast))
)
)
(vl-cmdf "explode" ename)
(if flag (vla-put-Explodable blkobj :vlax-false))
(princ)
)

解锁是对单个图块的操作,3~5 行判断选择的图元是否为图块,直至选择到图块为止;6~13 行找到该图块块定义的 Vlaobject 对象;14~19 行判断该图块定义中是否设定了不允许分解,如果是,暂时性将其定义修改为允许分解;20~41 行通过块插入(INSERT)的组码 70、71 (行列数)为 1 来判断该块是否为锁定的多重块插入(这里逻辑不是非常严谨,主要是考虑如果是普通块插入,组码 70 一般为 0,如果确实是有需要的行列形式的多重块,行列数不会同时为 1),若是,则删除块插入,同时以同名重建一个普通的块插入(匿名块也可以通过这种方式插入),并获取这个新建图块插入的图元名。完成这一系列工作后,42 行代码采用 explode 命令分解图块。43 行则对之前可能发生的图块定义中可分解性的修改进行恢复。至此,解锁过程完成,所谓“不能分解”的图块均被分解了。

感谢拨冗阅读本文,若有些许收获,不妨捐赠以资鼓励。