guangdonglbq 发表于 2020-6-24 09:59:47

一个AARDIO以COM方式做CAD二次开发的程序的加速运行方法

本帖最后由 guangdonglbq 于 2020-6-24 10:58 编辑

       AARDIO以COM方式做cad二次开发很方便,但因为是外部调用,软件之间的通信耗时比较多,在生成大量对象时,耗时大到让人难以接受。      实际上,在需要生成大量对象时,可以用程序生成lisp文件,然后调用cad加载、执行lisp文件:com主程序->生成lisp文件(文件里不要使用command/vl-cmdf)->cad里加载:(load 文件)。
   经测试,两个方法的速度之间,往往有几倍到几十倍的差别。 具体见下图。

    示例的aardio代码里,用到一个addline的lisp函数,需要单独写个addline的lsp函数到一个lisp文件里去并加载。
假设这个lisp文件是addline.lsp,代码是:
(defun AddLine (listStartPoint listEndPoint)
(entmake (list '(0 . "LINE")
                (cons 10 listStartPoint)
                (cons 11 listEndPoint)
          )
)
)

单独加载addline.lsp后,就可以在aardio里执行示例程序了。

jacenhe 发表于 2021-6-15 02:25:44

guangdonglbq 发表于 2021-6-13 21:58
这个功能应该是autocad 2020及其后的版本才有的,叫“安全级别”的相关项:可用op命令调出设置界面,在 ...

谢谢,设置了 SECURELOAD 确实可以成功加载。

我在 aardio 里添加了一个 com.cad 库,对 SendCommand 以及 load 文件的方法做了简单封装,使其支持 aardio 的模板语法,可以在 lisp 里嵌入 aardio 参数。一个例子:import com.cad;
var cad = com.cad();
cad.Visible = true;

cad.SendCommand(`
(setq c:hello nil)
(defun c:hello(/ name)
(set 'name (getstring "What's your name? "))
(set 'msg (strcat "Hello, " name <?= time(),"这是 aardio 对象" ?>))
(write-line msg))
hello`)
如果要用 load 函数加载,改用 cad.LoadLisp() 函数就可以了,同样支持模板语法。

jacenhe 发表于 2022-2-13 14:53:07

本帖最后由 jacenhe 于 2022-4-23 13:16 编辑

“COM 接口慢,甚至是调用 COM 接口的语言慢”—— 这个说法是不准确的。
COM 并不慢,只不过 AutoCAD 是进程外调用,相对进程内调用当然会有一点成本。
瞬间大量调用外部接口,这肯定会把微小的速度差异放大,但实际程序开发中一般没必要这样做,或者有其他方法避免。

跨进程调用在现代软件开发中其实很常用,不是非常夸张地密集调用对运行速度的影响一般可以忽略不计。
调用服务端 API 敢就更是跨过千山万水去调用了,相比进程间通信来说就更慢了,但这并不妨碍现代软件大量使用远程接口。

首先如果我们用 aardio 开发一个软件,至少图形界面这部分根本不需要与 AutoCAD 交互,也肯定存在大量不需要与 AutoCAD直接交互的功能函数。

通过 COM 接口也可以调用 AutoCAD 执行 LISP ,而且与 LISP 交互并不一定非要通过 COM 接口,也可以使用其他编程语言动态生成 LISP 代码然后再执行。通过 COM 接口也可以调用 AutoCAD 加载 .Net 编写的 DLL,我在 aardio 里就提供了一个例子,在 aardio 里直接编译 C# 代码生成 DLL 程序集,然后再通过 COM 接口cad.NetLoad() 加载 .Net 写的 DLL,再通过 cad.SendCommand() 就可以调用该 DLL。

http://www.mjtd.com/forum.php?mod=attachment&aid=MTE5NjIwfDQ2MGY4NTc2fDE2NTA2OTA4MDF8NzMyODIzM3wxODA3Mzk%3D&noupdate=yes

所以通过 COM 接口调用 AutoCAD 并不会丢失 LISP / .Net 的优势,而是在这个优势的基础上叠加了其他编程语言以及 COM 接口的优势。 我们使用任何一种技术,都是为了善用他的优势、扬长避短。




zzyong00 发表于 2020-6-25 17:35:03

支持一下!所有支持com的语言(包括vb6),应该都可以采用你的这种方法!

jacenhe 发表于 2021-6-11 01:47:42

感谢分享,看了一下源码,是先把LISP存到文件,再通过 load 命令加载。
但实际上 SendCommand 函数可以在 aardio 里直接执行 LISP,这样的好处是比较方便的动态生成 LISP(可以使用模板语法)

示例 aardio 代码:import com;
var cad = com.GetOrCreateObject("AUTOCAD.Application");
cad.Visible = true;

//注意最后一定要有空格令
cad.ActiveDocument.SendCommand(`
(defun c:hello(/ name)
(set 'name (getstring "What's your name? "))
(set 'msg (strcat "Hello, " name))
(write-line msg))
hello `)

guangdonglbq 发表于 2021-6-11 06:38:02

本帖最后由 guangdonglbq 于 2021-6-11 06:40 编辑

    感谢jacenhe专门做的开发示例。
   cad.ActiveDocument.SendCommand发送到cad的每一句代码,都会在命令行窗口提示一次,这个可能不是开发者希望看到的。用户也未必希望看到这个过程,因为执行代码多的时候,会比较烦人,也影响查看历史命令或执行undo操作。
    可以把生成和加载临时lsp文件的功能单独写成一个或2个函数,使用时,把需要执行的lsp代码定义给一个变量,再交给功能函数调用。这样的方案,对于开发也比较方便的。
   即写成这个形式:
loadLispCode=function(str){
...
}


var stringLisp = `
(defun c:hello(/ name)
(set 'name (getstring "What's your name? "))
(set 'msg (strcat "Hello, " name))
(write-line msg))
hello `;
loadLispCode ( stringLisp );

jacenhe 发表于 2021-6-11 10:45:20

guangdonglbq 发表于 2021-6-11 06:38
感谢jacenhe专门做的开发示例。
   cad.ActiveDocument.SendCommand发送到cad的每一句代码,都会在 ...

谢谢,你说的方法非常好,
另外查到可以用 (setvar "CMDECHO" 0) 关闭命令回显。
不过我试了一下,无论怎么设置 CMDECHO,用 cad.ActiveDocument.SendCommand() 执行函数都没有提示(代码执行成功了)
只有在 AutoCAD 里手敲命令才有提示。

我对 AutoCAD 不太了解,可能是用法错误。




guangdonglbq 发表于 2021-6-11 23:27:46

    我用cad.ActiveDocument.SendCommand时,无论CMDECHO是0还是1,所有发送给cad的命令和代码都会在命令行中显示。
    由于以com方式调用autocad是属于外部调用,软件间相互通信耗时较长,对程序总的运行时间影响很大。因此,com方式直接调用autocad适合用在对耗时不太敏感的情况,如与用户交互操作时、处理少量的对象时。
    对于有大量数据需要处理的情况,先生成lisp文件,再在autocad里用load语句加载运行的方式,可以让你所写的程序与autocad只有很少的通信次数,且把大量的处理操作变成autocad内的lisp代码执行,那样,整个程序的处理速度就取决于lisp代码质量,而com方式调用时的软件间相互通信的速度了。

jacenhe 发表于 2021-6-13 19:13:27

guangdonglbq 发表于 2021-6-11 23:27
我用cad.ActiveDocument.SendCommand时,无论CMDECHO是0还是1,所有发送给cad的命令和代码都会在命令行 ...

原来这个输入框是可以展开的,我看到的是单行的所以没注意到。
用文件中转的方法当然也不错 —— 我之前做批处理解析库就是这么弄的,只是用 AutoCAD 加载 LISP 文件会弹一个警告需要确认一下。

guangdonglbq 发表于 2021-6-13 21:58:56

本帖最后由 guangdonglbq 于 2021-6-14 00:14 编辑

    这个功能应该是autocad 2020及其后的版本才有的,叫“安全级别”的相关项:可用op命令调出设置界面,在“选项--系统--安全性--安全选项”中设置。
    要令高版本autocad加载lisp文件时不提示,方便比较简单,先判断cad是否存在SECURELOAD系统变量:判断(getvar "SECURELOAD")非nil即可。如果变量存在,临时调低安全性级别,把SECURELOAD 系统变量 设为 0,即可:(setvar "SECURELOAD"0)

guangdonglbq 发表于 2021-6-15 16:02:51


看了com.cad 库,厉害~~
页: [1] 2
查看完整版本: 一个AARDIO以COM方式做CAD二次开发的程序的加速运行方法