AutoLisp学习笔记

【前言】
最近发现,做CAD二次开发的,要么是计算机相关专业的,没有CAD基础;要么是工程制图出身,不会编程。所以写了这篇博客,AutoLisp学习笔记,根据我的学习经验,旨在给没有基础的你指明学习的方向,让读者少走弯路。

AutoLISP语言是开发AutoCAD的主要工具,是LISP语言和AutoCAD有机结合的产物,在AutoCAD的发展及壮大过程中起到了重要的作用。CAD二次开发可以使用VB、LISP和C#语言,CAD均为各种方式开发了平台。之所以使用LISP,是因为经过多年的累积,已经有很多的基础代码,方便程序的开发。

掌握AutoLISP开发,需要准备如下知识:1、LISP语言 2.AutoCAD基础 3.AutoLISP函数 4.AutoLisp进阶。

一. LISP语言相关知识
跟我们学过的C++ Java语言有很大的不同,LISP语言是解释性语言,只有两个基本单位:原子(atom)和列表(List)。这里推荐如下两个博客,前者是一个常用的LISP语言的开发环境,后者是语法学习,配合使用快速学习。这样,半天的时间可以对LISP语言有初步的概念。递归是LISP的精髓,如果看懂链接博客中的所有示例,那么可以进行下一步了。

【Lisp语言: 在Windows下搭建CLisp环境】

http://blog.csdn.net/keyboardota/article/details/8237185

【Lisp入门】

http://www.cnblogs.com/suiqirui19872005/archive/2007/12/05/984517.html

二.AutoCAD基础
AutoCAD博大精深,对于我们这些开发人员,只需了解些基本操作和概念就足够了。个人认为如下几个概念比较重要,部分可以在AutoCAD术语帮助中找到。

1、命令。
CAD的操作几乎都可以用命令描述,如创建一个以原点为圆心,半径为100的圆,可用如下几种命令形式完成。CAD中不区分大小写。

(1)CAD命令
命令:circle/c

在命令栏里键入c,然后就可以用鼠标在绘图窗口中操作指定圆心和半径。

(2) AutoLisp命令
$ (setq center ‘(0 0 0))

  • $ (command “circle” center 100)
    1
    (注:_$ 是Visual Lisp控制台的前置符,启动Visual Lisp的CAD命令是VLIDE,在控制台和CAD命令栏均可使用AutoLisp命令及ActiveX方法。在CAD命令栏查看变量前面加感叹号!)
  • 学习过前面LISP语言后,应该可以理解setq,command命令其实是AutoLisp函数,即AutoCAD提供给开发人员的Lisp函数。前者为变量设置值,后者是AutoLisp与AutoCAD的接口,可以向AutoCAD命令行直接发送命令和参数。其中列表 ‘(0 0 0)和原子 100分别为圆心和半径的参数。如上命令括号不能省略,表示其为函数。

    (3)Active X方法
    $ (vl-load-com)

  • $ (setq acad_obj (vlax-get-acad-object))
    $ (setq acad_document (vla-get-activedocument acad_obj))
  • $ (setq m_space (vla-get-modelspace acad_document))
    _$ (vla-addcircle m_space (vlax-3d-point ‘(0 0 0)) 100)
    1
    Active X技术通过将AutoCAD的对象显示在外部使用户以各种编程的方式访问AutoCAD对象。Active X函数 (vla-) (vlax-)提供了访问对象的各种方法。这里只是引入,说明了CAD命令,AutoLisp命令和ActiveX方法均能对CAD进行操作。
  • 2、图层。
    一组具有一定逻辑关系的数据,类似于覆盖在图形上的透明硫酸纸。可以单独查看每个图层,也可以同时查看多个图层。与PS中图层的概念一样,一个绘图可由多个叠加的图层组成,不同的图元可以选择绘制在哪个图层上。通过layer命令(CAD命令)可以生成或者选择图层。

    3、选择集。
    顾名思义,选择集就是选择的集合,在绘图窗口中,点击鼠标左键拖动鼠标,所选择的图元构成选择集。在AutoLisp 中可以用 ssget 函数对选择进行处理和过滤,得到自己想要到集合。

    1. 图元对象属性及DXF组代码
      图元,顾名思义,就是CAD中最小的操作单位,如上面画的一个圆,还可以是插入的块。在CAD中,每个图元其实就是一个对象,它们具有各种属性,比如前面画的circle属性包括实体名,实体类型,辅助实体名,所在图层名,圆心坐标,半径等。这些属性都是用DXF组代码的形式写入的。组代码使用LISP语言的点对结构表示图元对象的属性,类似于C++中map结构。可用entget函数查看。

    $ (command “circle” ‘(10 286.611 50.8336 0.0) 100)

  • $ (setq ent1 (entlast))
    _$ (entget ent1)
    1
    其中,entlast函数返回最后的图元,上述返回结果如下:
    ((-1 . <图元名: 7ffff705c20>) ;实体名
    (0 . “CIRCLE”) ;实体类型
    (330 . <图元名: 7ffff7039f0>) ;辅助实体名
    (5 . “23A”) ;实体标号
    (100 . “AcDbEntity”) ;实体子类说明
    (67 . 0) ;空间类型说明
    (410 . “Model”) ;空间名
    (8 . “0”) ;图层名
    (100 . “AcDbCircle”) ;
    (10 286.611 50.8336 0.0) ;圆心坐标
    (100.000) ;半径
    (210 0.0 0.0 1.0)) ;3D延伸方向
    1
  • 更多关于DXF可参考AutoCAD的帮助。如果想得到该图元的圆心坐标,使用如下代码。

    _$ (cdr (assoc 10 (entget ent1)))
    (286.611 50.8336 0.0)
    1
    ※拓展:也可以用ActiveX的方法进行访问。
    $ (setq myobject (vlax-ename->vla-object (entlast)))

  • #<VLA- OBJECT IAcadCircle 0000000037be66f8>
  • $ (vlax-safearray->list (vlax-variant-value (vlax-get-property myobject 'center)))
    (286.611 50.8336 0.0)
    1
    这里涉及到ActiveX方法和函数,看不懂可先跳过,有概念即可。
    5. 块。
    表示结合起来以创建单一对象的一个或多个对象。常用于块定义或块参照。在块编辑窗口中可增加其属性,在AutoLisp中使用entnext遍历属性。
  • 6.AutoCAD的自定义配置
    AutoCAD强大的平台可以使用户自定义工作区间,包括菜单,面板,双击动作等等,还能定义新的命令,可以说,AutoCAD的灵活和个性化是软件的精髓,是AutoDesk公司屹立不倒的根基。

    敲击CAD命令:cui,或者【工具】->【自定义】->【界面】

    这里可以自定义用户界面,比如想添加一个查看图元属性的菜单选项,可以按如下步骤:

    (1)创建自定义命令 点击命令列表中的五角星,这里使用默认名称“命令1”

    (2)编辑自定义命令的宏,其中CC表示连按两下Esc,保证退出其他命令。键入命令:

    CC(entget (SSNAME (SSGET) 0))
    1
    (3)打开菜单栏,在文件菜单中,将命令列表的“命令1”拖动进去。点击确定退出。

    图表 1 CAD自定义界面

    (4)单击选中窗口中任一图元,然后再文件菜单中点击“命令1”,发现命令栏里返回图元的属性信息。

    7.AutoCAD支持文件配置
    类似于Java的环境配置,是程序寻找文件的目录列表。

    三.AutoLisp函数
    参考任一一本关于AutoLisp的书均可。推荐下《AutoCAD 2008 Visual LISP二次开发入门到精通》,现已绝版(⊙﹏⊙b汗)。AutoLisp函数是二次开发的基础,基本函数不多,是Lisp语言在AutoCAD环境下的扩展,容易掌握。

    四.Visual Lisp集成开发环境
    CAD命令栏键入 VLIDE 命令弹出VisualLisp开发环境,包括编译器,调试器和其他工具,提高编程效率。控制台窗口可以像AutoCAD命令行那样输入AutoLisp命令,还可以输入Visual LISP命令。

    五.AutoLisp进阶
    1.使用ActiveX对象
    我们可以把整个AutoCAD理解为一个对象的模型,包括样式设置对象,组织结构对象,图形显示对象,图元对象,AutoCAD本身也是一个对象。这些对象根据包含关系组成了层次结构,称为对象模型。既然为对象,那么就有属性值和方法。下面我们根据一个例子讲下ActiveX对象的使用方法。我们将使用三种方法完成。

    例:画直线,根据图元名称获得其对象,并得到直线的两个端点。并将直线向x轴负方向挪动1000。

    1.1 ActiveX对象属性的操作
    (1) 选择直线工具,在cad绘图窗口中绘制一条直线

    (2)打开Visual Lisp,在控制台窗口键入如下代码:

    $ (vl-load-com)

  • $ (setq line-object (vlax-ename->vla-object (entlast)))
    #<VLA-OBJECT IAcadLine 0000000030624d58>
    1
    若要用ActiveX访问指定的图形对象,则可以先找到对象的图元名,再将这个名称转化为VLA对象,之后就可以按照访问VLA对象的方法访问了。通过上面两行代码,我们就得到了刚刚画的直线的对象,并保存在变量line-object中。
  • 右键变量line-object,选择【检验】。弹出【检验】窗口,这里我们可以看到这个变量的多个属性。其中<StartPoint>和<EndPoint>便是线段的起点和终点。这里我们看到<EndPoint>值为#<variant 8197…>,这是一种ActiveX型的数据类型,术语“变体”。变体是应用在ActiveX对象操作中使用的数据类型,可以通过内置的函数与AutoCAD中的数据相互转化,下面我们将看到应用。双击<EndPoint>,弹出子窗口,我们可以看到该变体的值是一个元素类型为Double的#<safearray…>,Safearray(安全数组)也是一种ActiveX数据类型。双击safearray,弹出子窗口我们终于看到终点坐标(1007.6 3440.77 0.0)。
    

    图表 2 ActiveX对象检验

    接下来我们使用Lisp代码完成读取工作

    $ (setq endp (vla-get-endpoint line-object))

  • #<variant 8197 …>
  • $ (setq endp2 (vlax-variant-value endp))
    #<safearray…>
    _$ (setq endp3 (vlax-safearray->list endp2))
    (1007.6 3440.77 0.0)
    1
    其中vla-get-endpoint,vlax-variant-value,vlax-safearray->list是AutoLisp函数。同样如法炮制得到起点的坐标值:
  • _$(setq startp3 (vlax-safearray->list (vlax-variant-value (vla-get-startpoint (vlax-ename->vla-object (entlast))))))
    (234.156 3400.91 0.0)
    1
    接下来设置新的坐标

    $ (setq newEndP (list (- (nth 0 endp3) 1000) (nth 1 endp3) (nth 2 endp3)))

  • ( 7.6 3440.77 0.0)
  • $ (setq newStartP (list (- (nth 0 startp3) 1000) (nth 1 startp3) (nth 2 startp3)))
    (-765.844 3400.91 0.0)
    1
    接下来将新的坐标写入该对象,写入函数vla-put- 要求写入参数应当为变体类型,所以我们创建了两个安全数组,NewEndP2&NewStartP2。
  • $ (setq NewEndP2 (vlax-make-safearray vlax-vbDouble '(0 . 2)))

  • #<safearray…>
  • $ (vlax-safearray-fill NewEndP2 NewEndP)
    #<safearray…>
    $ (setq NewStartP2 (vlax-make-safearray vlax-vbDouble '
    ( 0 . 2)))
  • #<safearray…>
  • $ (vlax-safearray-fill NewStartP2 NewStartP)
    #<safearray…>
    $ (vla-put-startpoint line-object NewStartP2)
  • nil
  • $ (vla-put-endpoint line-object NewEndP2)
    Nil
    1
    同样地,我们可以不用ActiveX,而是采用AutoCAD 内部命令来完成上述工作。
  • _ ( s e t q e n t 1 ( e n t g e t ( e n t l a s t ) ) ) < / d i v > < / d i v > < / l i > < l i > < d i v c l a s s = " h l j s − l n − n u m b e r s " > < d i v c l a s s = " h l j s − l n − l i n e h l j s − l n − n " d a t a − l i n e − n u m b e r = " 2 " > < / d i v > < / d i v > < d i v c l a s s = " h l j s − l n − c o d e " > < d i v c l a s s = " h l j s − l n − l i n e " > < s p a n c l a s s = " h l j s − n u m b e r " > < s p a n c l a s s = " h l j s − n u m b e r " > < / s p a n > < / s p a n > (setq ent1 (entget (entlast)))</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-number"><span class="hljs-number">_</span></span> (setqent1(entget(entlast)))</div></div></li><li><divclass="hljslnnumbers"><divclass="hljslnlinehljslnn"datalinenumber="2"></div></div><divclass="hljslncode"><divclass="hljslnline"><spanclass="hljsnumber"><spanclass="hljsnumber"></span></span>(setq oldEndp (assoc 11 ent1)) ;终点坐标DXF组码值为11
    $ (setq oldStartp (assoc 10 ent1)) ;起点坐标DXF组码值为10

  • $ (setq newEndp (list 10 (- (nth 1 oldEndp) 1000) (nth 2 oldEndp) (nth 3 oldEndp)))
    $ (setq newStartp (list 10 (- (nth 1 oldStartp) 1000) (nth 2 oldStartp) (nth 3 oldStartp)))
  • $ (setq ENT1 (subst newEndp oldEndp ENT1))
    $ (setq ENT1 (subst newStartp oldStartp ENT1))
  • $ (entmod ENT1)
    1
    可能这时你就有疑问了,既然两种办法都可改变图元的属性,那还用ActiveX干嘛。其实相比于其他AutoCAD API环境,ActiveX接口技术速度快,效率高,随CAD安装,便于使用。另外ActiveX的对象交互技术使得CAD可与外界应用程序交互,拓宽了CAD开发的应用范围。
  • 1.2 ActiveX对象属性的操作
    Visual Lisp提供了Vlax-invoke-method函数来调用ActiveX的方法。使用的时候要注意将参数转化为ActiveX型,除非参数的默认分配类型(见将数据类型转换为ActiveX型)正好为所需的类型。对于上面的line-object,我们如何知道该对象所支持的ActiveX方法呢,下面提供个人经验。首先使用vlax-dump-object函数列出line-object所支持的方法。

    _$ (vlax-dump-object line-object t)
    ; IAcadLine: AutoCAD Line 接口
    ;特性值:
    ; Angle (RO) = 0.620333
    ; Application (RO) = #<VLA-OBJECT IAcadApplication 000000013f993318>
    ; Delta (RO) = (1361.03 972.338 0.0)
    ; Document (RO) = #<VLA-OBJECT IAcadDocument 000000002fb96bc8>
    ; EndPoint = (1458.44 1051.22 0.0)
    ; EntityTransparency = “ByLayer”
    ; Handle (RO) = “236”
    ; HasExtensionDictionary (RO) = 0
    ; Hyperlinks (RO) = #<VLA-OBJECT IAcadHyperlinks 0000000039a12ad8>
    ; Layer = “0”
    ; Length (RO) = 1672.68
    ; Linetype = “ByLayer”
    ; LinetypeScale = 1.0
    ; Lineweight = -1
    ; Material = “ByLayer”
    ; Normal = (0.0 0.0 1.0)
    ; ObjectID (RO) = 42
    ; ObjectID32 (RO) = 42
    ; ObjectName (RO) = “AcDbLine”
    ; OwnerID (RO) = 43
    ; OwnerID32 (RO) = 43
    ; PlotStyleName = “ByLayer”
    ; StartPoint = (97.4054 78.8798 0.0)
    ; Thickness = 0.0
    ; TrueColor = #<VLA-OBJECT IAcadAcCmColor 0000000039a12890>
    ; Visible = -1
    ;支持的方法:
    ; ArrayPolar (3)
    ; ArrayRectangular (6)
    ; Copy ()
    ; Delete ()
    ; GetBoundingBox (2)
    ; GetExtensionDictionary ()
    ; GetXData (3)
    ; Highlight (1)
    ; IntersectWith (2)
    ; Mirror (2)
    ; Mirror3D (3)
    ; Move (2)
    ; Offset (1)
    ; Rotate (2)
    ; Rotate3D (3)
    ; ScaleEntity (2)
    ; SetXData (2)
    ; TransformBy (1)
    ; Update ()
    1
    这里我们看到有个名字为Move的方法,猜想其可以完成图元的移动,是否如此呢,查看帮助中的“AutoCAD ActiveX and VBA references”部分,查找Move Method,确实是我们预想的那样。接下来我们使用这个函数同样完成将直线向x轴负方向挪动1000的工作。Move方法接受两个参数,Point1&Point2,分别表示移动向量的起点和终点。显然这里Point1&Point2的坐标分别为(0 , 0 , 0)和 (-1000 , 0 , 0)。参数类型要求为Variant (three-element array of doubles),我们先构造两个double类型的safearray,然后转化为变体(Variant )类型。(转化为变体类型这一步并非必须,因为safearray会被强制转化为Variant)最后作为实参代入函数,看能否同样完成前面的工作。

    图表 3 Move方法帮助

    $ (setq Point1 (vlax-make-safearray vlax-vbDouble '(0 . 2)))

  • #<safearray…>
  • $ (setq Point2 (vlax-make-safearray vlax-vbDouble '(0 . 2)))
    #<safearray…>
    $ (vlax-safearray-fill Point1 (list 0 0 0))
  • #<safearray…>
  • $ (vlax-safearray-fill Point2 (list -1000 0 0))
    #<safearray…>
    $ (setq Point1 (vlax-make-variant Point1)) ;;转换为变体类型,非必须
  • #<variant 8197 …>
  • $ (setq Point2 (vlax-make-variant Point2)) ;;非必须
    #<variant 8197 …>
    _$ (vlax-invoke-method line-object “Move” Point1 Point2)
    Nil
    1
    然后将窗口切换到AutoCAD绘图窗口,直线确实按照我们预想的一样,又往x轴负方向移动了1000单位。
  • 总结:对于某一ActiveX对象,使用vlax-dump-object函数可以列出该对象的属性值和适用的ActiveX方法。对属性值的操作,可以采用vla-get和vla-put为前缀的函数。ActiveX方法就比较复杂,若要查找相应的操作函数的使用方法,可以参考AutoCAD帮助中的“AutoCAD ActiveX and VBA references”部分。并应用vlax-invoke-method方法调用ActiveX对象的方法。CAD2013版本以后,VBA开发不再随软件安装,所以帮助部分也不容易找到了。http://entercad.ru/acadauto.en/ 网站可供参考使用。

    2.ActiveX对象交互
    在Visual Lisp环境中,也可以使用其他应用程序的ActiveX对象。笔者在开发的时候,遇到XML和CAD信息交互的问题,上网搜索,发现没有解析XML的LISP库,如果自己写XML解析,势必大大影响项目进展。终于在ActiveX对象中找到灵感,下载了一个XML的ActiveX控件,加载到自己的程序里完成项目开发。(见我的另一篇博客,AutoLisp中XML解析方案)

    转载【坠入海浪】的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值