首页 / 资讯中心 / 文章详情

AutoLISP函数分类手册:从数学运算到错误处理的系统复习指南

AutoLISP函数分类手册:从数学运算到错误处理的系统复习指南 ★ FEATURED ARTICLE
简介《LISP函数大全分类手册》是一份面向AutoLISP初学者与CAD二次开发者的函数速查资料以PDF形式系统梳理了AutoLISP编程中最常用的核心函数帮助读者在编写和调试LISP程序时快速定位语法与用途。资源包内含1个PDF文件压缩包约47KB体积轻巧便于随查随用。手册按功能划分为数学运算、检验与逻辑运算、转换运算、列表处理等模块逐条列出函数原型与返回值说明例如数学运算中的加减乘除、取整、最大公约数逻辑运算中的比较与位运算转换运算中的角度与字符串互转以及列表处理中的car、cdr、cons、mapcar等经典操作并延伸至字符串、文件、等待输入与几何运算等常用函数。目前已有765人学习下载适合需要系统掌握AutoLISP函数体系、提升CAD编程效率的开发者作为案头参考。1. 从一张函数地图说起AutoLISP 到底该怎么系统复习很多人第一次翻 AutoLISP 函数表都会有一种“每个都认识、连起来就不会写”的感觉。原因不复杂函数是按字母顺序或零散章节堆在一起的而实际写程序时你是按“我要算什么、我要取什么、我要改什么”来调函数的。这两套逻辑对不上背得再多也容易翻车。这份《LISP函数大全分类手册》的价值就在于它按功能把 AutoLISP 函数分成了十九个大类数学运算、检验与逻辑、转换运算、列表处理、字符串与文件、等待输入、几何运算、对象处理、选择集与符号表、查询与控制、判断与循环、函数定义与错误处理、显示打印、符号与表达式、加载卸载、内存管理、其他工具函数以及外部定义的 3D 和数据库函数。梳理下来会发现真正高频使用的其实集中在数学运算、列表处理、对象处理、选择集、判断循环这五块其余更像是按需查阅的“工具箱”。这份笔记适合两类人一类是正在系统学 AutoLISP、想建立完整知识地图的人另一类是写过一些脚本、但遇到报错就靠试错、想回头查漏补缺的人。下面按模块把重点、难点和易错点拆开讲。2. 数学、逻辑与转换三类基础函数的复习重点2.1 数学运算函数的参数陷阱数学函数看起来最没门槛但恰恰是参数类型和返回值类型最容易出问题的地方。手册里列出的二十来个函数可以按“输入输出类型”重新分组分组代表函数输入输出常见用途四则运算-*/数值整数或实数坐标计算、尺寸累加自增自减11-数值同类型循环计数取整取余fixremgcd数值整数索引、分页、对齐幂与对数expexptlogsqrt数值实数几何变换、缩放三角sincosatan弧度实数角度计算极值maxmin数值同类型边界判断常量pi无实数圆周计算重点在于sin、cos、atan接收的都是弧度不是角度。手册里明确写了“角度值为弧度”。如果你从用户输入拿到的是度数必须先转换。pi是常量不是函数写成(pi)会直接报错。/的除法行为也值得注意当所有参数都是整数时结果可能是整数截断。想要实数结果至少保证有一个参数是实数比如写成(/ 10.0 3)。;; 计算两点连线的角度弧度转度数 (setq p1 (getpoint \n输入第一点: )) (setq p2 (getpoint \n输入第二点: )) (setq ang (angle p1 p2)) ; angle 返回弧度 (setq deg (* ang (/ 180.0 pi))) ; 弧度转度数注意用 180.0 保证实数运算 (princ (strcat \n角度为: (rtos deg 2 2) 度))这段代码里(/ 180.0 pi)用实数 180.0 做被除数避免整数除法截断。rtos的第二个参数 2 表示十进制模式第三个参数 2 表示保留两位小数。2.2 逻辑比较和equal不是一回事检验与逻辑运算这一块最容易混的是、eq、equal三个比较函数。手册里写得很清楚但实际写代码时经常用错用于数值和字符串的相等比较不适用于列表。eq比较两个表达式是否“实际相同”适合判断两个符号是否指向同一个对象。equal比较两个表达式的“内容相同”可以带差量参数适合比较列表和带浮点误差的坐标。;; 比较两个点是否重合用 equal 带容差 (setq pt1 (1.0 2.0 0.0)) (setq pt2 (1.0001 2.0 0.0)) (if (equal pt1 pt2 0.001) (princ \n两点重合) (princ \n两点不重合))差量参数 0.001 表示允许的误差范围。如果直接用比较两个浮点坐标几乎永远返回 nil这是新手最常见的翻车点之一。and和or的短路特性也值得记and遇到第一个 nil 就停止求值or遇到第一个非 nil 就停止。这意味着你可以把开销大的判断放在后面把简单的守卫条件放在前面。2.3 转换函数字符串与数值之间的桥转换运算函数是连接用户输入和内部计算的桥梁。手册里列出的九个函数核心就是三组转换字符串转数值atof转实数、atoi转整数、distof按模式转实数、angtof角度字符串转实数数值转字符串itoa整数转字符串、rtos实数转字符串、angtos角度转字符串单位与坐标转换cvunit单位换算、trans坐标系转换rtos的模式参数容易记混模式 1 是科学计数法模式 2 是十进制模式 3 是工程单位模式 4 是建筑单位模式 5 是分数。精度参数控制小数位数。如果你不指定模式它会用系统变量LUNITS的当前值这在不同图纸环境下可能不一致所以建议显式指定。trans是几何编程里最容易被低估的函数。它负责在对象坐标系、世界坐标系和显示坐标系之间转换点。手册里写的参数是“点 原位置 新位置 [位移]”实际使用时原位置和新位置用整数代码表示比如 0 表示世界坐标系1 表示用户坐标系2 表示显示坐标系。注意cvunit依赖acad.nut文件里的单位定义如果单位名称拼写不对函数会返回 nil 而不是报错排查起来比较隐蔽。3. 列表处理AutoLISP 的核心竞争力3.1 取元素与构造列表car/cdr 家族列表处理是 LISP 的看家本领也是 AutoLISP 操作图形数据的主要方式。手册第四章列出的十六个函数可以按“取”和“造”两条线来梳理。取元素这条线核心是car、cadr、caddr、cdr、nth、last。手册特别标注了car通常用来求 X 坐标cadr求 Y 坐标caddr求 Z 坐标。这是因为 AutoLISP 里一个三维点就是三个元素的列表比如(1.0 2.0 3.0)。;; 从点列表中提取坐标 (setq pt (10.0 20.0 5.0)) (setq x (car pt)) ; 10.0 (setq y (cadr pt)) ; 20.0 (setq z (caddr pt)) ; 5.0 (setq rest (cdr pt)) ; (20.0 5.0)cdr返回的是去掉第一个元素后的列表不是第二个元素。想要第二个元素用cadr想要第 n 个用nth索引从 0 开始。nth的索引从 0 开始这一点和很多语言从 1 开始不同写循环时容易差一位。构造列表这条线核心是list、cons、append、reverse、subst。cons把新元素加到列表头部append把多个列表合并成一个subst替换列表中的旧项为新项。;; 构造和修改列表 (setq a (list 1 2 3)) ; (1 2 3) (setq b (cons 0 a)) ; (0 1 2 3) (setq c (append a (4 5))) ; (1 2 3 4 5) (setq d (reverse a)) ; (3 2 1) (setq e (subst 9 2 a)) ; (1 9 3)append的参数必须都是列表如果写成(append a 4)会报错。cons的第二个参数必须是列表第一个参数可以是任意元素。3.2 遍历与映射foreach 和 mapcar 的分工foreach和mapcar是列表遍历的两把利器但用法和返回结果不同。foreach用于“对每个元素做一件事”返回 nil适合执行副作用操作比如批量修改对象属性。mapcar用于“对每个元素做一次变换收集结果”返回一个新列表适合批量计算。;; foreach批量打印点坐标 (setq pts ((0 0) (1 1) (2 2))) (foreach p pts (princ (strcat \nX (rtos (car p) 2 1) Y (rtos (cadr p) 2 1)))) ;; mapcar批量计算距离 (setq base (0 0)) (setq dists (mapcar (lambda (p) (distance base p)) pts)) ;; dists 得到 (0.0 1.414 2.828)mapcar可以接受多个列表函数会依次取每个列表的对应元素。手册里写的“将列表1、列表2的元素配合函数求得新列表”就是这个意思。如果多个列表长度不一致mapcar会在最短列表耗尽时停止。assoc和member是查找类函数。assoc用于联合列表每个元素是键值对按关键元素查找member用于普通列表返回从匹配元素开始到末尾的子列表。;; assoc 查找联合列表 (setq info ((name . A) (age . 20) (city . X))) (setq name (cdr (assoc name info))) ; A ;; member 查找普通列表 (setq nums (1 2 3 4 5)) (setq found (member 3 nums)) ; (3 4 5)assoc返回的是键值对通常要用cdr取出值。member返回的是子列表不是单个元素。3.3 列表函数的易漏点梳理下来会发现列表处理有几个容易忽略的细节第一length返回的是顶层元素数量不递归计算嵌套列表。(length (1 (2 3) 4))返回 3不是 4。第二listp对 nil 返回 T因为 nil 在 LISP 里既是空列表也是假值。如果你要判断“非空列表”需要写成(and (listp x) x)。第三mapcar配合lambda时lambda的参数个数必须和列表个数匹配。多一个少一个都会报错。第四subst只替换顶层元素不深入嵌套列表。要替换嵌套结构里的元素需要配合递归或mapcar。4. 对象、选择集与几何和图纸打交道的函数4.1 对象处理entget 与 entmod 的配对使用对象处理函数是 AutoLISP 区别于普通 LISP 的关键。手册第八章列出的函数核心是“取对象信息”和“改对象信息”两条线。entget取出对象的信息列表entmod根据更新后的列表修改对象。这两个函数通常配对使用先用entget拿到信息用subst修改其中某一项再用entmod写回去。;; 修改一个圆对象的半径 (setq ent (car (entsel \n选择一个圆: ))) (setq data (entget ent)) (setq old (assoc 40 data)) ; 40 是半径组码 (setq new (cons 40 50.0)) ; 新半径 50.0 (setq data (subst new old data)) (entmod data) (entupd ent) ; 更新屏幕显示组码 40 代表半径这是 AutoLISP 对象数据里的约定。entmod修改数据后屏幕不一定立即刷新需要entupd强制更新。这是很多人改了数据却看不到变化的原因。entnext用于遍历图形数据库entlast取最后一个对象entsel让用户选择一个对象。entdel删除对象但如果对同一个对象再次调用entdel它会取消删除相当于“后悔药”。handent通过图码句柄查找对象这个句柄在图纸保存后仍然有效适合跨会话引用对象。4.2 选择集ssget 的过滤技巧选择集函数是批量操作的基础。手册第九章列出的函数核心是ssget取得选择集ssadd和ssdel增删元素ssname按索引取对象sslength取数量。ssget的过滤列表是最有技巧的部分。过滤列表用组码和值来筛选对象比如只选圆、只选特定图层、只选特定颜色。;; 选择所有半径大于 10 的圆 (setq ss (ssget X ((0 . CIRCLE) (40 . 10.0)))) ;; 注意过滤列表里的 40 是“大于等于”还是“等于”取决于具体写法 ;; 更精确的范围过滤需要配合条件运算符手册里写的(ssget X [过滤列表])中X 表示在整个图形数据库中搜索不需要用户交互。过滤列表的组码和entget返回的组码一致所以熟悉对象数据后过滤列表就很好写了。ssname的索引从 0 开始和nth一样。sslength返回选择集中的对象数量常用于循环边界。;; 遍历选择集并统计对象数量 (setq ss (ssget X ((0 . LINE)))) (setq n (sslength ss)) (setq i 0) (while ( i n) (setq ent (ssname ss i)) (setq data (entget ent)) ;; 处理每个线对象 (setq i (1 i))) (princ (strcat \n共找到 (itoa n) 条线))这段代码展示了选择集遍历的标准写法sslength取数量ssname按索引取对象while循环配合自增变量。注意1是函数不是运算符写成(1 i)而不是i。4.3 几何运算angle、distance、polar 的配合几何运算函数是写绘图程序的基础。手册第七章列出的六个函数核心是angle求角度、distance求距离、polar按极坐标求点、inters求交点、osnap按捕捉模式取点、textbox取文字边界。polar是最常用的构造点函数给定基点、弧度和距离返回新点。它和angle、distance配合可以实现很多几何计算。;; 在两点连线的延长线上取一点 (setq p1 (getpoint \n基点: )) (setq p2 (getpoint \n方向点: )) (setq ang (angle p1 p2)) (setq dist (distance p1 p2)) (setq p3 (polar p1 ang (* dist 2.0))) ; 延长一倍距离 (princ (strcat \n延长点: (rtos (car p3) 2 2) , (rtos (cadr p3) 2 2)))angle返回的是弧度polar接收的也是弧度两者可以直接配合。distance返回实数可以直接参与乘法。inters求两条线的交点第五个参数是模式nil 表示不延长非 nil 表示延长后求交。这个参数容易漏写导致本该相交的线因为线段不够长而返回 nil。osnap按捕捉模式取点模式字符串和 AutoCAD 的捕捉模式名称一致比如 MID 表示中点END 表示端点INT 表示交点。注意osnap返回的是世界坐标系下的点如果你在用户坐标系下工作可能需要用trans转换。5. 输入、判断与错误处理让程序跑得稳5.1 等待输入函数getxxx 家族等待输入函数是程序和用户交互的入口。手册第六章列出的十个函数核心是getpoint、getdist、getangle、getint、getreal、getstring、getkword、getcorner、getorient以及控制输入有效性的initget。这些函数的共同点是都可以带提示字符串都可以带基点参数部分函数都返回用户输入的值或 nil用户取消时。;; 带默认值和关键词的输入 (initget 1 Yes No) (setq ans (getkword \n是否继续? [Yes/No]: )) (if ( ans Yes) (princ \n继续执行) (princ \n已取消))initget的第一个参数是控制位1 表示禁止空输入用户直接回车无效2 表示禁止零值4 表示禁止负值。第二个参数是关键词列表用空格分隔。getkword只接受关键词列表中的输入其他输入会被拒绝并要求重新输入。getangle和getorient的区别在于getangle受系统变量ANGBASE和ANGDIR影响getorient不受影响始终以世界坐标系为基准。手册里特别标注了这一点写角度相关程序时要注意区分。getcorner需要一个基点参数返回矩形框的对角点。getpoint可以带基点参数用于相对坐标输入。5.2 判断与循环if、cond、while、repeat 的选择判断和循环是程序逻辑的骨架。手册第十一章列出的五个函数可以按“分支”和“循环”两类来记。分支类if用于两路分支cond用于多路分支。if的第三个参数else 分支是可选的省略时条件为假返回 nil。cond的每个子句是“测试表达式 结果表达式”的配对测试为真时执行对应结果。;; cond 多路分支示例 (setq score 85) (cond (( score 90) (princ \n优秀)) (( score 80) (princ \n良好)) (( score 70) (princ \n中等)) (t (princ \n需努力)))cond的最后一个子句用t作为测试表达式表示“以上都不满足时执行”相当于 default 分支。循环类while用于条件循环repeat用于固定次数循环。while先判断条件再执行条件为 nil 时退出。repeat直接指定次数次数必须是正整数。;; while 循环遍历列表 (setq lst (1 2 3 4 5)) (while lst (princ (strcat \n元素: (itoa (car lst)))) (setq lst (cdr lst))) ;; repeat 循环固定次数 (repeat 5 (princ \n执行五次))while循环里用cdr逐步缩短列表直到列表为空nil时退出。这是 LISP 里遍历列表的经典写法。progn用于把多个表达式组合成一个常用于if或cond的分支里需要执行多个表达式的情况。手册里写的“连接其内的表达式为一组”就是这个意思。5.3 函数定义与错误处理defun 和error函数定义是 AutoLISP 程序化的基础。手册第十二章列出的函数核心是defun定义函数、lambda定义匿名函数、apply应用函数、eval求值、*error*自定义错误处理。defun的标准形式是(defun 名称 (参数列表) 表达式...)。参数列表可以是局部变量用/分隔。局部变量在函数执行完毕后释放不会污染全局环境。;; 定义一个带局部变量的函数 (defun c:drawSquare ( / p1 p2 len) (setq p1 (getpoint \n输入左下角: )) (setq len (getdist p1 \n输入边长: )) (setq p2 (polar p1 0 len)) (command LINE p1 p2 ) (princ))c:前缀表示这个函数可以作为 AutoCAD 命令调用。/后面的p1、p2、len是局部变量不会留在全局环境里。command函数调用 AutoCAD 命令参数按命令提示顺序排列空字符串表示回车结束。*error*是自定义错误处理函数。当程序出错时AutoLISP 会调用*error*传入错误信息字符串。你可以重定义它来恢复环境、打印友好提示。;; 自定义错误处理 (defun myError (msg) (if (and msg (not (wcmatch msg *cancel*))) (princ (strcat \n出错: msg))) (setvar OSMODE 0) ; 恢复捕捉设置 (princ)) (setq oldError *error*) (setq *error* myError)这段代码保存了原有的错误处理函数替换成自定义版本。出错时恢复系统变量避免程序中断后环境被破坏。这是写健壮程序的好习惯。trace和untrace用于调试给函数设置追踪标记后调用时会打印参数和返回值。手册里写的“辅助检错”就是这个用途。6. 查漏补缺一份可执行的复习清单复习到这一步你已经有了完整的地图。接下来是怎么查漏补缺。我的做法是把函数按“使用频率”和“出错频率”两个维度重新过一遍重点看那些“高频且高错”的。第一遍过数学和转换函数。重点检查sin/cos/atan的弧度参数、/的整数截断、rtos的模式和精度参数、trans的坐标系代码。这些是写几何程序时最常翻车的地方。第二遍过列表处理函数。重点检查car/cadr/caddr的坐标对应、nth的 0 起始索引、mapcar的多列表长度匹配、subst的顶层替换限制。列表是 AutoLISP 的数据核心这里出错往往导致整个程序逻辑跑偏。第三遍过对象和选择集函数。重点检查entget/entmod的配对使用、entupd的刷新、ssget的过滤列表组码、ssname的索引范围。这部分是 AutoLISP 和图纸交互的关键组码记错一个数字结果就完全不对。第四遍过输入和错误处理。重点检查initget的控制位、getkword的关键词列表、*error*的恢复逻辑、command的参数顺序。这部分决定程序是“能用”还是“好用”。下面这张表可以作为快速自查的清单模块必查点常见错误数学运算弧度/角度、整数除法sin传度数、/截断逻辑比较/eq/equal区分用比较列表或浮点转换运算rtos模式、trans坐标系模式不指定、坐标系代码错列表处理索引起点、顶层替换nth从 1 开始、subst不递归对象处理组码、entupd组码记错、改完不刷新选择集过滤列表、索引范围组码不匹配、越界访问输入函数initget控制位忘记禁止空输入错误处理*error*恢复不恢复系统变量最后说一个习惯每次写完一段 AutoLISP 代码我都会强制走一遍“输入检查—类型检查—边界检查”三步。输入检查看getxxx是否可能返回 nil类型检查看car/cdr是否作用在列表上边界检查看nth/ssname的索引是否越界。这三步走完大部分低级错误都能提前拦住。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站