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

发布时间:2026/10/24 14:07:25
AutoLISP函数分类手册:从数学运算到错误处理的系统复习指南

简介:《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 数学运算函数的参数陷阱

数学函数看起来最没门槛,但恰恰是参数类型和返回值类型最容易出问题的地方。手册里列出的二十来个函数,可以按“输入输出类型”重新分组:

分组代表函数输入输出常见用途
四则运算+-*/数值整数或实数坐标计算、尺寸累加
自增自减1+1-数值同类型循环计数
取整取余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的索引是否越界。这三步走完,大部分低级错误都能提前拦住。希望帮到你。

本文还有配套的精品资源,点击获取