菜鸟科技网

Lisp如何调用CAD命令?

下面我将从基本用法、高级技巧、最佳实践和常见问题四个方面,详细讲解如何在LISP中调用CAD命令。

Lisp如何调用CAD命令?-图1
(图片来源网络,侵删)

基本用法:command 函数

command 函数是LISP与CAD进行交互式操作的主要桥梁,它的基本语法是:

(command "命令名" "选项" "点1" "点2" ... "回车")

工作原理:

  1. 参数类型command 函数的参数必须是字符串类型。
  2. 参数传递:LISP将字符串参数按顺序传递给CAD的命令行。
  3. 命令执行:CAD接收到这些参数后,就像你在命令行手动输入一样,依次执行命令的各个步骤。
  4. 回车键:当命令需要确认或结束一个输入步骤时,LISP需要传递一个空字符串 来模拟按回车键,这是最关键也最容易出错的地方。

简单示例:画一条直线

(defun c:DrawLine ()
  (command "._line" "0,0" "100,100" "") ; 画一条从(0,0)到(100,100)的直线
  (princ) ; 静默退出,防止返回函数名
)

代码解释:

  • (defun c:DrawLine ...): 定义一个名为 DrawLine 的LISP函数,c: 前缀使其成为一个可以直接在CAD命令行输入的命令。
  • (command "._line" "0,0" "100,100" ""):
    • "._line":调用 LINE 命令。_ 前缀可以确保调用的是英文版命令,这对于在不同语言版本的CAD中保持兼容性非常重要。
    • "0,0":指定直线的起点。
    • "100,100":指定直线的终点。
    • 模拟按回车,结束 LINE 命令。
  • (princ):这是一个好习惯,它返回 nil 并且在CAD命令行上不打印任何东西,使得调用该LISP命令后,命令行保持干净。

高级技巧与常用模式

在实际应用中,我们很少使用固定的坐标,而是需要动态获取数据,如用户输入、选择对象、获取系统变量等。

获取用户输入(点、距离、角度等)

使用 getpoint, getdist, getangle 等函数获取用户输入,然后传递给 command

Lisp如何调用CAD命令?-图2
(图片来源网络,侵删)

示例:让用户指定起点和终点画线

(defun c:DrawLine2 ()
  (setq p1 (getpoint "\n请指定起点: ")) ; 获取一个点
  (if p1 ; 如果用户确实指定了一个点
    (progn
      (setq p2 (getpoint p1 "\n请指定终点: ")) ; 获取第二个点,并显示橡皮筋线
      (command "._line" p1 p2 "") ; 使用变量画线
    )
  )
  (princ)
)

代码解释:

  • (getpoint ...): 暂停程序,等待用户在屏幕上拾取一个点或输入坐标。
  • (setq p1 ...): 将用户拾取的点存储到变量 p1 中。
  • (if p1 ...): 检查用户是否按了ESC键取消。p1nil,则 if 判断为假,跳过后续代码。
  • (getpoint p1 ...): 传递一个点作为基点,CAD会从该点出发显示一条橡皮筋线,帮助用户预览。
  • (progn ...): 当 if 的条件为真时,progn 会将其中的多个表达式作为一个整体来执行。

处理对象选择

使用 ssget 函数让用户选择对象,然后将选择集传递给需要对象的命令(如 ERASE, MOVE)。

示例:删除用户选择的对象

Lisp如何调用CAD命令?-图3
(图片来源网络,侵删)
(defun c:MyErase ()
  (setq sset (ssget '((0 . "CIRCLE,LINE")))) ; 选择所有圆和直线
  (if sset
    (command "._erase" sset "") ; 将选择集传递给ERASE命令
  )
  (princ)
)

代码解释:

  • (ssget ...): 暂停程序,让用户选择对象。
    • ssget:不带参数,让用户自由选择。
    • ssget '((0 . "CIRCLE,LINE")):使用过滤列表只选择图层为0且类型为圆或直线的对象。0 是DXF组码,代表对象类型。
  • (if sset ...): 检查用户是否选择了对象(即 sset 不为 nil)。
  • (command "._erase" sset ""): 将选择集 sset 作为 ERASE 命令的参数,然后按回车执行。

处理透明命令和嵌套命令

一些命令需要在其他命令执行过程中使用,ZOOM (缩放) 或 PAN (平移),这些被称为透明命令

在LISP中,调用透明命令需要在命令名前加一个单引号 。

示例:在画线过程中进行缩放

(defun c:DrawLineWithZoom ()
  (command "._line")
  (while (= 1 (getvar "CMDACTIVE")) ; 检查LINE命令是否仍在活动状态
    (if (= (car (grread)) 11) ; 如果用户在屏幕上移动鼠标
      (progn
        (command "._zoom" 'W) ; 调用透明命令 'ZOOM Window
        (princ "\n指定缩放窗口的第一个角点.")
        (command (cadr (grread))) ; 获取窗口的第一个角点
        (princ "\n指定缩放窗口的第二个角点.")
        (command (cadr (grread))) ; 获取窗口的第二个角点
        (command "") ; 结束ZOOM命令
      )
    )
  )
  (princ)
)

注意:这个例子比较复杂,展示了 grread 函数的用法,更常见的做法是直接使用 ZOOM 命令,或者在主命令开始前让用户先缩放视图。

使用系统变量

可以使用 setvargetvar 函数来读取和设置CAD的系统变量,这些变量会影响 command 的行为。

示例:临时关闭对象捕捉,画一条线,然后恢复

(defun c:DrawLineWithoutOsnap ()
  (setq old_osmode (getvar "OSMODE")) ; 保存当前的OSMODE值
  (setvar "OSMODE" 0) ; 关闭所有对象捕捉
  (command "._line" "0,0" "10,10" "") ; 现在画线不会捕捉到任何东西
  (setvar "OSMODE" old_osmode) ; 恢复原来的对象捕捉设置
  (princ)
)

最佳实践与注意事项

  1. 始终使用 princ 结束函数(princ) 是LISP函数的“礼仪”,可以防止在命令行打印不必要的返回值,保持界面整洁。
  2. 使用 _ 前缀:为了代码的国际化,请始终在命令前加上下划线 或 _,如 "_line"".line",这可以强制CAD使用英文命令,避免在不同语言版本的CAD中出错。
  3. 检查返回值:对于 getpoint, ssget, getvar 等函数,它们的返回值可能是 nil(当用户取消操作时),使用 ifwhen 来检查返回值,可以防止程序因 nil 值而出错。
  4. 避免过度依赖 command
    • 优点:简单直观,可以快速实现几乎所有手动能做的操作。
    • 缺点:速度相对较慢,与CAD的数据库交互不直接,程序运行时无法中断(除非按ESC),且无法获取命令执行后的详细信息(如创建的对象ID)。
  5. 替代方案:ActiveX/VLISP:对于更复杂、更高效的应用,建议使用 Visual LISP (VLISP) 的ActiveX功能,它可以直接操作CAD的数据库,速度更快,更稳定,功能更强大。

ActiveX示例(对比 command 画线)

;; 使用ActiveX/VLISP画线,效率更高,且能获得对象
(defun c:DrawLineWithActiveX ()
  (setq p1 (getpoint "\n起点: "))
  (setq p2 (getpoint p1 "\n终点: "))
  (if (and p1 p2)
    (vla-addLine
      (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object))) ; 获取当前文档的模型空间
      (vlax-3d-point p1) ; 将LISP点列表转换为ActiveX点
      (vlax-3d-point p2)
    )
  )
  (princ)
)

可以看到,ActiveX方式不依赖 command,而是直接在CAD内部创建几何对象,性能和可控性都更好。


常见问题

Q: 为什么我的LISP运行后,CAD命令行提示“未知命令”?

A: 最常见的原因是 command 函数中的参数不是字符串(command line "0,0" "10,10") 是错误的,line 必须写成 "line"

Q: 为什么我的LISP画完线后,命令行还卡在 LINE 命令?

A: 几乎可以肯定是你忘记在最后加一个空字符串 来模拟回车,检查你的 command 调用,确保它以

Q: 如何在LISP中调用带“/”选项的命令,如 CIRCLE2P (两点) 选项?

A: 将选项也作为字符串传递,并在选项和后续参数之间加一个空字符串 。

示例:使用 2P 选项画圆

(defun c:Circle2P ()
  (setq p1 (getpoint "\n指定圆直径的第一个端点: "))
  (setq p2 (getpoint p1 "\n指定圆直径的第二个端点: "))
  (if (and p1 p2)
    (command "._circle" "_2P" p1 p2 "") ; 注意 "_2P" 和 p1, p2 之间的 ""
  )
  (princ)
)

注意:对于带 _ 前缀的命令,其子选项通常也加 _,如 "_2P"

方法 优点 缺点 适用场景
command 函数 简单、直观,与手动操作模式一致 速度慢,无法中断,无法直接获取对象信息,依赖命令行状态 快速编写脚本、自动化重复性手动操作、学习LISP的入门方法
ActiveX/VLISP 速度快,稳定,可中断,能直接操作对象和数据,功能强大 语法相对复杂,需要理解对象模型 开发专业、高效、复杂的CAD应用程序和插件

对于初学者和大多数日常任务,熟练掌握 command 函数是必不可少的,当你需要更高级的功能时,再深入学习 ActiveX/VLISP。

分享:
扫描分享到社交APP
上一篇
下一篇