养成良好的AutoLISP书写习惯课案.docx
《养成良好的AutoLISP书写习惯课案.docx》由会员分享,可在线阅读,更多相关《养成良好的AutoLISP书写习惯课案.docx(24页珍藏版)》请在冰豆网上搜索。
养成良好的AutoLISP书写习惯课案
养成良好的AutoLISP书写习惯
众所周知,Lisp是一种表结构语言,括号必须成对出现,在调试时往往为遗漏了一个括号大费周折,所以,养成一个好的编程习惯是学好Lisp所必须的。
⑴选择一个较好的编辑器,这是一个基本条件,建议使用VisualLisp编辑器或Lisplink等专用编辑器,此类编辑器可以对函数突出显示。
⑵按Lisp(DCL)专有格式书写,并经常对程序进行“格式化”,及时发现语法错误,并有利于调试是查找错误。
⑶使用自定义函数,并辅助以适当得注释,在较大程序中按功能使用自定义函数可以使得程序条理化。
autolisp的入门教程+autolisp函数!
Lisp是一门历史悠久的语言,全名叫LIStProcessor,也就是“表处理语言”,它是由JohnMcCarthy于1958年就开始设计的一门语言。
和Lisp同时期甚至更晚出现的许多语言如Algo等如今大多已经消亡,又或者仅仅在一些特定的场合有一些微不足道的用途,到现在还广为人知的恐怕只剩下了Fortran和COBOL。
但唯独Lisp,不但没有随着时间而衰退,反倒是一次又一次的焕发出了青春,从Lisp分支出来的Scheme、ML等语言在很多场合的火爆程度甚至超过了许多老牌明星。
那么这颗常青树永葆青春的奥秘究竟在哪里呢?
如果你只接触过C/C++、Pascal这些“过程式语言”的话,Lisp可能会让你觉得十分不同寻常,首先吸引你眼球(或者说让你觉得混乱的)一定是Lisp程序中异常多的括号,当然从现在的角度来讲,这种设计的确对程序员不大友好,不过考虑到五六十年代的计算机处理能力,简化语言本身的设计在那时算得上是当务之急了。
Lisp的基本语法很简单,它甚至没有保留字(有些语言学家可能对这一点有异议,别怕,我听你们的),它只有两种基本的数据,仅有一种基本的语法结构就是表达式,而这些表达式同时也就是程序结构,但是正如规则最简单的围棋却有着最为复杂的变化一样,Lisp使用最基本的语言结构定义却可以完成其它语言难于实现的、最复杂的功能。
废话少说,现在我们就来看看Lisp语言中的基本元素。
Lisp的表达式是一个原子(atom)或表(list),原子(atom)是一个字母序列,如abc;表是由零个或多个表达式组成的序列,表达式之间用空格分隔开,放入一对括号中,如:
abc
()
(abcxyz)
(ab(c)d)
最后一个表是由四个元素构成的,其中第三个元素本身也是一个表。
正如算数表达式1+1有值2一样,Lisp中的表达式也有值,如果表达式e得出值v,我们说e返回v。
如果一个表达式是一个表,那么我们把表中的第一个元素叫做操作符,其余的元素叫做自变量。
正如欧几里德的几何世界中有五个公理一样,我们在这里给出Lisp世界中的7个公理(基本操作符):
(quotex)返回x,我们简记为'x
(atomx)当x是一个原子或者空表时返回原子t,否则返回空表()。
在Lisp中我们习惯用原子t表示真,而用空表()表示假。
>(atom'a)
t
>(atom'(abc))
()
>(atom'())
t
现在我们有了第一个需要求出自变量值的操作符,让我们来看看quote操作符的作用——通过引用(quote)一个表,我们避免它被求值。
一个未被引用的表达式作为自变量,atom将其视为代码,例如:
>(atom(atom'a))
t
反之一个被引用的表仅仅被视为表
>(atom'(atom'a))
()
引用看上去有些奇怪,因为你很难在其它语言中找到类似的概念,但正是这一特征构成了Lisp最为与众不同的特点——代码和数据使用相同的结构来表示,而我们用quote来区分它们。
(eqxy)当x和y的值相同或者同为空表时返回t,否则返回空表()
>(eq'a'a)
t
>(eq'a'b)
()
>(eq'()'())
t
例如:
我们有时想捕捉任意两点的中点,而不只是一条线上的中点,用系统自己的捕捉中点(它要有辅助线)就不行了,
我们可以参考“捕捉虚中点.lsp”程序来实现。
除程序中的语句要学外,动画中的自动找到所有的全局变量并把它们
改为局部变量的方法很有用!
动画中先画了一个六边形,再画一个圆与它内接,圆心就是捕捉虚中点!
AutoLisp概述
AutoLisp的数据类型,它有10种数据类型,常见的有五种:
整型 INT 实数型 REAL 符号型SYM
字符串STR 表 LISP
在AutoLisp中,最基本的数据类型称为符号表达式,也称为S-表达式,它是原子和点对的总称,点对通常表示为表。
原子是一个一般符号系列,有两种类型的原子,一种称为数子原子(简称“数”),AutoLIsp可处理整数和实数,其它不是“数”原子称为非数字原子,它包括符号原子(或称为文字原子)和串原子。
注意:
0.4不能写成.4 。
符号原子的大小写是等效的。
符号原子可以包含下列字符以外的任何可打印字符。
正反括号 用于定义表
句号 用于作点对
分号 用于注释的开始
‘ 用作QUOTE函数的简写
双引号 用作字符串常数的定界符
符号原子的长度没有限制,且所有的字符都是有意义的,但尽量不要超过6个字符。
约束是一对符号和值,当将一个值赋给符号时,就说符号被约束到那个值。
值(而不是符号)决定所代表信息的类型,故一个符号可以接受任何类型的值,其初始值为nil.
在AutoLisp中,有两个特殊的符号原子,即T和nil.
字符串的个数(不包括定界符)称为字符串的长度。
字符串可以是任意长度,它们的存储空间是动态分配的,但字符串常量的最大长度不超过100,长度为0字符串称为空串。
可以用“\nnn”的方式表示字符,其中nnn为八进制。
\e Esc \n 换行
\r 回车 \t 制表符(Tab节)
点对是由一个左括号,后接一个S-表达式和空格再接一个句点和空格和一个右括号。
表是指放在一对相匹配的左右括号中的元素有序集合。
表中的项称为表的元素,表中的元素可以是任意类型的S-表达式,序号0到n-1。
如果嵌套,0层,1层...
表的长度,顶层元素的个数。
只有nil是表(’())又是原子。
表有两种类型:
标准表,引用表。
引用表是在表的前面冠以引用符号(’或Quote)对该表不求值。
标准表:
第一个元素的值必须是一个合法的已经存在的AutoLisp函数定义,后跟调用该函数的参数。
AutoLisp采用”前缀表示法“即把运算符放在操作数之前,而不是中间,并把运算符(函数名)和操作数(调用函数的参数)用圆括号括起来,以表的方式表示。
一个完整的AutoLisp程序往往是由一系列按顺序排列的S-表达式组成的。
如:
(defun plus(xy)
(+(+xy)x))
(SetQa2.0)
(SetQb2.0)
(plusab)
一个S-表达式可以分多行写,一行也可以写多个表达式。
注释以分号开始,并在一行的末尾结束,AutoLisp的求值器忽略注释。
AutoLisp是一种求值型语言,求值程序第一次碰到一个求值代码块时,整个块被转换成压宿代码,如果程序中再次碰到那个块,只是简单的运行它。
求值过程:
1,整形,实数,字符串,文件指针,系统内部函数,以及两个特殊的符号原子,对它们求值就是它们本身。
2,符号原子是以当前的约束值作为它们的求值。
3,表是根据它的第一个元素的数据类型进行求值的。
(1)第一个元素的值为表,该表就假定为用户定义的函数 。
(2)如果表的第一个元素的求值结果为一个内部函数,则剩余元素作为参数传给该函数,并执行该函数的代码,由函数的类型确定是否对传给它的参数进行求值。
输入距离
Lisp语言中输入距离的函数为getdist,但我们有时需要输入负值,有时需要在输入距离的同时得到角度,使用getdist函数就显得无能为力,这时,我们可以灵活使用其它交互输入函数如getpoint、getcorner等,通过计算得到我们所需要的值。
例1是一段输入长度的同时得到默认角度的代码,使用getpoint函数。
************************************************
;;例1
(setq pt0 (getpoint"\n直线基点:
")
pt1 (getpointpt0"\n直线长度:
") ;长度及角度可用键盘或鼠标定位
dst (distancept0pt1) ;计算长度
ang (anglept0pt1) ;计算默认角度
ang1(getanglept0(strcat"\n直线方向<"(angtosang1)">:
"))
)
************************************************
例2是可以按阵列方式输入行列间距的代码,输入距离为正值,修改部分代码可输入负值,使用getcorner函数,同时使用initget的控制位128。
************************************************
;;例2
(defunlc_dist()
(initget128) ;允许任意输入
(setqdisr(getpoint"\n指定单位单元或输入行间距:
"))
(if(=(typedisr)'LIST) ;鼠标输入
(progn
(initget1)
(setqdis(getcornerdisr"\n指定对角点:
") ;鼠标输入对角
disc(abs(-(cardis)(cardisr))) ;正值行距
disr(abs(-(cadrdis)(cadrdisr))) ;正值列距
) ;计算行列间距
)
(if(=(typedisr)'STR) ;键盘输入行距
(if(setqdis(distofdisr)) ;判断输入的是否距离
(progn
(initget6)
(setqdisc(getdist"\n输入列间距:
")) ;输入列距
)
(progn ;键盘输入格式不符返回
(princ"\n需要正数值或两个二维角点。
")
(lc_dist)
)
)
(progn ;空输入返回
(princ"\n需要正数值或两个二维角点。
")
(lc_dist)
)
)
)
)
AutoCAD中特定角度及长度捕捉的实现方法
一、引言
在AutoCAD中的角度捕捉只有当正交状态打开时的直和水平方向,对于其他特殊角度无能为力;另外,其网点捕捉也是相对于X轴和Y轴,无法实现其他方向的特殊长度捕捉,给绘图带来极大的不方便。
在应用AutoCAD进行设计制图的操作中,LINE和POLYLINE是使用频率最高的两个命令,经常要遇到在某些特定角度上绘制特定长度的简单线或复合线的情况,因而实现这两个捕捉对提高AutoCAD作图效率很有实用价值。
二、方法原理
所谓角度捕捉,是指当十字光标在某一角度α的一定范围内选取一点时,该点自动落在该α角度线上;当我们设定捕捉角度为α时,将会以基准点作为原点、自X轴正方向出发,将整个屏幕划分为[360/α]个区间,则NXα角度就是角度捕捉线,其中,0≤N≤[360/α],[360/α]表示不大于360/α的整数。
所谓长度捕捉,是在角度捕捉的基础上,在某一角度线上有一系列捕捉点,该系列点离基准点的距离为捕捉长度的正整数倍,当选取直线上的一点时,落点自动落到离其最近的捕捉点上。
实现特定角度和长度捕捉的关键点是:
当十字光标(即十字交*线)移动时,程序要随时跟踪其交*点的位置,并将该位置与用户所设定的捕捉角度与长度对应起来,从而计算出在该角度上的落点。
以下举例说明该两个捕捉的实现过程:
假定捕捉角度为α=30°,捕捉长度为L。
当十字光标在任意的某一区间内移动时,比如在第5区间(120°~150°)内移动时,此时,落点只能在120°或150°线上(该线在图中并不直接显示),该两根角度线的中心线为135°。
当十字光标的中心点处在120°~135°之间时,则落点应在120°线上,该落点的具体位置为由十字光标的中心点向120°线作垂线来获得,其交点D(称为垂点)即为落点,为直观起见,此时由基准点(此处为O点)向落点作一橡筋拖曳线,该橡筋拖曳线随十字光标的移动而相应移动,显示出拖动过程(见图1);同样,当十字光标的中心点处在135°~150°之间时,则落点应在150°线上,并显示相应的橡筋拖曳线。
该橡筋拖曳线并不是真正的线段,只是用XOR墨水绘制的一个向量,当用XOR墨水重新绘制一遍该向量时,该向量将从屏幕上消失,这就是本程序实现光标拖动的原理。
落点落在某一捕捉角度线上时,还得落在捕捉长度L的整数倍的点(称为捕捉点)上,还是针对图1,其垂点必然处于某两个捕捉点A与B之间,设A与B的中点为C,当D处于A与C之间时,落点应为A;当D处于C与B之间时,落点应为B(见图1)。
其中:
----
OA=nXL;OB=(n+1)XL
n:
非负整数。
L:
捕捉长度。
此时,程序通过一定的操作将在屏幕的最上面的坐标提示行准确地显示落点相对基准点的偏移长度和偏移角度。
用户可以滑动鼠标准确捕捉到目标点。
至此,已实现某些特定角度及长度的捕捉。
为了满足在程序执行过程中能随时更改捕捉角度和捕捉长度的需要,本程序还增加了相应的模块;另外,本程序中嵌入了窗口放缩功能模块,通过点取下拉菜单中窗口及漫游子菜单,方便了各种作图的需要。
三、源程序清单
;;OS.LSP源程序
;;err(),出错处理子程序
(defunerr(msg)
(if(/=msg"Functioncancelled")
(princ(strcat"\nError:
"msg));打印错误内容
);forif
(setq*error*olderr)
(setvar"cmdecho"scmd)
(setvar"osmode"cosmode)
(setvar"coords"ccoords)
(princ"n\n\t--多谢使用角度捕捉2.0版,程序非正常结束--!
\n")
(princ)
);fordefunerr
;;ant(),设定捕捉角度子程序
(defunant(/ang0ang1)
(setqang0(*an0(/180pi)))
(princ(strcat"\n请输入捕捉角度:
<"(rtosang0)">_"))
(INITGET4)
(setqang1(getreal))
(if(not(nullang1))
(setqan0(*ang1(/pi180)))
)
(princ"\nF2/F3/F4/F5/ESC/Return/下一点:
")
);fordefunant
;;leng(),设定捕捉长度距离子程序
(defunleng(/leng0leng1)
(setqleng0len0)
(princ(strcat"\n请输入捕捉长度距离:
<"(rtosleng0)">_"))
(INITGET4)
(setqleng1(getreal))
(if(not(nullleng1))
(setqlen0leng1)
)
(princ"\nF2/F3/F4/F5/ESC/Return/下一点:
")
);fordefunlent
;;field(),判断十字光标所在区间,并投影到相应的捕捉角度线上
(defunfield(pspeang0/ang1n)
(setqang1(anglepspe))
(setqn(fix(+(/ang1ang0)0.5)))
(setqang2(*ang0n))
);fordefun
;;endp(),十字光标投影到相应的捕捉角度上后,以用户设定的长度
;;捕捉计算落点
(defunendp(pspeang0/p1p2p3p4dis)
(setqp1ps
p2(polarpsang01)
p3pe
p4(polarpe(+ang0(/pi2))1)
)
(setqpend(intersp1p2p3p4nil))
(setqdis(distancepspe))
(if(/=len00)
(setqdist(*(fix(+(/dislen0)0.5))len0))
;else
(setqdistdis)
);forif
(setqpend(polarpsang0dist))
);fordefunendp
;;drag(),对上一次显示的拖曳线进行"或"操作,使其从屏幕上消失,
;;并绘制下一次拖曳线
(defundrag(pold1pold2pold3/)
(if(/=b24)
(progn
(grdrawpold1pold2-10)
(grdrawpold2pold3-10)
)
);forif
(grdrawpstartpend-10)
(grdrawpendpframe-10)
);fordefundrag
;;coord(),在屏幕的最上一行的坐标栏显示长度和角度
(defuncoord(/strleng1leng0ang0)
(setqang0(*ang2(/180pi)))
(setqstr(strcat(rtosdist)">"(rtosang0)))
(grtext-2str)
);fordefuncoord
;;init(),对程序进行初始化
(defuninit(/)
(setqscmd(getvar"cmdecho"));保留原命令回显方式
(setqccoords(getvar"coords"));保留原坐标显示方式
(setqcosmode(getvar"osmode"))
(setqolderr*error**error*err);出错处理
(setvar"cmdecho"0);不回显
(setvar"coords"0);不显示坐标
(setvar"osmode"0);取消捕捉
(setqb0b10c'(00))
(setqpstart(getpoint"\n请输入直线第一点:
"))
(if(or(nullan0)( (progn
(setqan0(/pi6))
(ant)
)
);forif
(if(or(nulllen0)( (progn
(setqlen01)
(leng)
)
);forif
(if(nulllen0)(leng))
(princ"\nF2/F3/F4/F5/ESC/Return/下一点:
:
")
(setqa(grread2nil))
(setqpframe(cadra))
(fieldpstartpframean0)
(endppstartpframeang2)
(grdrawpstartpend-10)
(grdrawpendpframe-10)
(setqplastpframepoldepend)
(setqb(cara))
);for