1. 为什么需要解析DXF组码?
在CAD二次开发中,我们经常需要批量操作特定类型的图元。比如你想选中图纸中所有"轴线"图层上的红色虚线,传统做法是手动框选或者用快速选择工具。但遇到复杂图纸时,这种方法效率极低。
这时候就需要用到选择集过滤器。选择集过滤器的核心原理就是通过DXF组码来识别图元的各类属性。DXF组码就像是CAD图元的"身份证号码",每个数字对应不同的属性。比如组码8对应图层,组码62对应颜色。
但问题来了:不同图元的组码结构不一样,新手很难记住。比如直线的起点用组码10表示,而圆的圆心也是组码10。更麻烦的是,同一个属性在不同场景下可能用不同组码表示。这就是为什么我们需要系统性地学习DXF组码解析。
2. 获取直线图元的完整DXF数据
2.1 基础查询命令
先用最简单的LISP命令获取一条直线的完整DXF数据:
(setq en_data (entget (car (entsel))))执行这段代码后,在CAD中选择一条直线,你会得到类似这样的返回结果:
((-1 . <图元名: 7ef50cf0>) (0 . "LINE") (330 . <图元名: 7ef50cc0>) (5 . "2B4") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "轴线") (100 . "AcDbLine") (10 1250.0 3400.0 0.0) (11 3850.0 3400.0 0.0) (210 0.0 0.0 1.0))2.2 关键组码解析
让我们拆解这个返回结果:
(0 . "LINE"):图元类型,这里是直线(8 . "轴线"):图层名称(10 1250.0 3400.0 0.0):起点坐标(11 3850.0 3400.0 0.0):终点坐标(62 . 1):如果存在则表示颜色(红色)(6 . "DASHED"):如果存在则表示线型
特别注意,颜色和线型如果没有特别设置,可能不会出现在DXF数据中,这时CAD会使用图层的默认设置。
2.3 获取扩展数据
有时候我们需要获取图元的更多信息,可以加上'("*")参数:
(setq en_data (entget (car (entsel)) '("*")))这样能获取到包括扩展数据在内的完整信息,比如动态块的参数、自定义数据等。
3. 构建选择集过滤器
3.1 基础过滤器语法
选择集过滤器的基本结构是一个关联列表,每个子列表对应一个过滤条件。以选择"轴线"图层上的所有直线为例:
(setq filter '((0 . "LINE") (8 . "轴线"))) (ssget "X" filter)这段代码会在整个图纸范围内("X"模式)选择所有符合条件图元。
3.2 多条件组合
如果需要同时满足多个条件,直接在过滤器中添加更多组码即可。比如选择"轴线"图层且颜色为红色的直线:
(setq filter '((0 . "LINE") (8 . "轴线") (62 . 1)))但要注意,如果图元使用的是图层颜色(没有单独设置颜色),这个过滤器会漏选。更稳妥的做法是:
(setq filter '((0 . "LINE") (8 . "轴线"))) (setq ss (ssget "X" filter)) ;; 二次筛选颜色 (vl-remove-if-not '(lambda (x) (= (cdr (assoc 62 (entget x))) 1)) (vl-remove nil (mapcar 'cadr (ssnamex ss))))3.3 通配符的使用
CAD支持使用通配符进行模糊匹配。比如选择所有以"A-"开头的图层上的直线:
(setq filter '((0 . "LINE") (8 . "A-*")))常用的通配符包括:
*:匹配任意数量字符?:匹配单个字符#:匹配单个数字
4. 实战案例:批量修改直线属性
4.1 选择特定直线
假设我们需要选择"墙体"图层上所有长度大于3000的直线:
(setq filter '((0 . "LINE") (8 . "墙体"))) (setq ss (ssget "X" filter)) (setq long_lines (vl-remove-if-not '(lambda (ent) (setq data (entget ent) p1 (cdr (assoc 10 data)) p2 (cdr (assoc 11 data))) (> (distance p1 p2) 3000)) (vl-remove nil (mapcar 'cadr (ssnamex ss)))))4.2 批量修改属性
将选中的直线颜色改为蓝色(组码62=5),线型改为虚线:
(foreach ent long_lines (setq data (entget ent)) (setq data (subst (cons 62 5) (assoc 62 data) data)) (setq data (append data (list (cons 6 "DASHED")))) (entmod data))4.3 添加扩展数据
如果需要给这些直线添加自定义数据(比如标注为"待审核"):
(foreach ent long_lines (setq xdata '("MyApp" (1000 . "待审核"))) (regapp "MyApp") (entmod (append (entget ent) xdata)))5. 常见问题与优化技巧
5.1 性能优化
当图纸很大时,ssget可能会很慢。几个优化建议:
- 尽量缩小选择范围,不用
"X"而用窗口选择 - 分步过滤,先用宽泛条件初筛,再用LISP二次筛选
- 对固定条件的过滤器,可以预编译:
(defun compile-filter (filter) (list (cons -4 "<AND") (mapcar '(lambda (x) (list -4 (car x) (cdr x))) filter) (cons -4 "AND>"))) (setq my-filter (compile-filter '((0 . "LINE") (8 . "轴线"))))5.2 特殊组码处理
有些组码需要特别注意:
- 组码6(线型):如果值为"BYLAYER"可能不会出现在DXF数据中
- 组码62(颜色):值256表示随层,0表示随块
- 组码370(线宽):-1表示默认,-2表示随层,-3表示随块
5.3 错误处理
健壮的代码应该包含错误处理:
(defun safe-ssget (filter / ss) (if (not (vl-catch-all-error-p (setq ss (vl-catch-all-apply 'ssget (list "X" filter))))) ss (princ "\n选择集创建失败!")))6. 高级应用:动态过滤器
6.1 条件组合
使用逻辑运算符构建复杂条件:
;; 选择"轴线"或"辅助线"图层的直线 (setq filter '((0 . "LINE") (-4 . "<OR") (8 . "轴线") (8 . "辅助线") (-4 . "OR>")))6.2 关系测试
支持大小比较:
;; 选择长度在2000到3000之间的直线 (setq filter '((0 . "LINE") (-4 . "<AND") (-4 . ">=,>=,>=") (10 2000 2000 0) (-4 . "<=,<=,<=") (11 3000 3000 0) (-4 . "AND>")))6.3 自定义过滤函数
对于无法用标准组码表示的条件,可以结合vl-remove-if-not:
(defun filter-by-angle (ss min-angle max-angle / rad) (setq rad (/ pi 180)) (vl-remove-if-not '(lambda (ent) (setq data (entget ent) p1 (cdr (assoc 10 data)) p2 (cdr (assoc 11 data)) angle (angle p1 p2)) (and (>= angle (* min-angle rad)) (<= angle (* max-angle rad)))) (vl-remove nil (mapcar 'cadr (ssnamex ss)))))7. 实际项目经验分享
在最近的一个厂房设计项目中,我们需要统计所有设备定位线的总长度。这些直线分布在多个图层,名称格式为"设备-*"。通过组合使用通配符和二次筛选,我们写出了高效的统计代码:
(defun total-equipment-length (/ ss total) (setq filter '((0 . "LINE") (8 . "设备-*"))) (setq ss (ssget "X" filter)) (setq total 0.0) (foreach ent (vl-remove nil (mapcar 'cadr (ssnamex ss))) (setq data (entget ent) p1 (cdr (assoc 10 data)) p2 (cdr (assoc 11 data))) (setq total (+ total (distance p1 p2)))) (princ (strcat "\n设备定位线总长度: " (rtos total) "mm")))这个例子展示了如何将DXF组码解析应用到实际工程需求中。通过灵活组合各种过滤条件,可以解决CAD二次开发中的大部分批量操作问题。