公司动态
LISP实战:解析CAD图元DXF组码,精准构建选择集过滤器(以LINE为例)
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 批量修改属性将选中的直线颜色改为蓝色组码625线型改为虚线(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二次开发中的大部分批量操作问题。