明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
楼主: Gaudi

[讨论] 新手从零开始的第一份LISP程序全纪录

    [复制链接]
 楼主| 发表于 2024-4-27 10:52:25 | 显示全部楼层
本帖最后由 Gaudi 于 2024-4-28 21:33 编辑

大佬们,我这Lisp才会做第一个程序呢,就开始C#,是不是有点为时过早……


再说也比不过科班出身的啊

纯粹用来给自己画图减少点工作量。


第三篇  第一部分  经验总结



1 列表

列表格式是最常用的格式,它千变万化,能包含其他所有格式。

对于列表的操作也必须要掌握。

但是也不用畏难,万变不离其宗,掌握怎么定义列表,以及怎么取值,基本上就可以了。

除了前文中已经描述的car系列、assoc、nth、foreach函数,还有一个 cons 函数,这个就是用来创建点对数据的。
或者用来给已有列表新增数据。



2 DXF码表

图层线宽的DXF码是370,这个点卡了我几个小时。
370的数据格式是mm×100,这个点又卡了我几个小时。

最后在国外一个论坛里的13年前的回复找到答案了。


FXCK USELESS CHINESE INTERNET!

这也是我为什么想开这个贴的原因之一。

顺便问下大佬们,哪儿有最齐全的、带数据格式的DXF群码表?



3 asscos 函数

有朋友可能发现了,asscos 函数后面我用了一个 read 函数。
  1.   (setq prefixes '("新建" "利用" "拆除" "更换"))
  2.   (setq colors '((新建 . 60) (利用 . 4) (拆除 . 3) (更换 . 30)))
  3. (cons 62 (cdr (assoc (read prefix) colors)))

按道理讲应该是不需要的,字符串应该可以直接利用 assoc 读取,只有数字的时候才需要。
但就是报错。
希望有大佬解释下。
发表于 2024-4-27 13:16:48 | 显示全部楼层
DXF编程是CAD早期的编程技术,还是有一定的门槛。更低门槛其实应该直接考虑转VLA,学习、按照对象模型来处理。很多很复杂的结构,尤其是比较新的实体类型,如ARRAY,动态参数之类的,有些甚至根本没有DXF的修改方式,COM模型改更方便。COM里面属性、方法等也都是简单的一目了然的单词。

点评

谢谢大佬,我也发现了VLA其实更简单,但是跟我这种普通画图工的常规认知有点不太一样,所以一些能用原始写法的代码我还是保持了  发表于 2024-5-9 19:50
发表于 2024-4-27 13:18:14 | 显示全部楼层
Gaudi 发表于 2024-4-27 10:52
大佬们,我这Lisp才会做第一个程序呢,就开始C#,是不是有点为时过早……

'((新建 . 60) (利用 . 4) (拆除 . 3) (更换 . 30)))
改写成(list(cons 新建  60) (cons 利用  4) (cons 拆除  3) (cons 更换  30)))

点评

谢谢大佬,那我还是用read吧,这看着有点繁杂  发表于 2024-5-9 19:51
回复 支持 1 反对 0

使用道具 举报

发表于 2024-4-28 10:17:10 | 显示全部楼层
什么事情都要讲性价比,对于有主业的cad二开爱好者来说,lisp绝对是性价比最高的。
如果有精力,学一下c#也挺好,很多算法的实现、还有jig动态之类的,都是lisp做不到的。
发表于 2024-4-28 15:34:44 | 显示全部楼层
本帖最后由 crtrccrt 于 2024-4-28 15:37 编辑

不喜勿喷,不喜勿喷,不喜勿喷

AUTOLSP灵魂在于SET和EVAL
AUTOLSP精华在于APPLY和MAPCAR及FOREACH
VISUAL-LSP莫名其妙的Automation 错误,让人抓狂.
使用LSP,尽量不用command / command-s / vL-cmd

不喜勿喷,不喜勿喷,不喜勿喷

点评

可能还没涉及到一些复杂的需求,主要用命令行模式和我这种普通画图工的朴素认知相符,所以一些能用的我还是保留了  发表于 2024-5-9 19:52
 楼主| 发表于 2024-4-28 20:52:14 | 显示全部楼层
本帖最后由 Gaudi 于 2024-4-29 13:01 编辑

为了不打扰大佬们看帖的流畅性,再不能点评之前,我就先不回复各位大佬的回帖了,见谅见谅。


第三篇  第二部分  获取指定文件夹地址



来到了第二个子函数。

1 确定指定文件夹

这里要用到大量的VLA函数,依次有:
  1. (setq sh (vla-getInterfaceObject (vlax-get-acad-object) "Shell.Application"))

vla-getInterfaceObject:这是一个VLA函数,用于获取AutoCAD中当前活动的文档对象(ActiveX文档对象)的指定接口。它接受两个参数:当前的AutoCAD文档对象和要获取的接口名称。
vlax-get-acad-object:这也是一个VLAX函数,用于获取AutoCAD的顶级对象,即AutoCAD应用程序对象。这个对象是访问AutoCAD其他对象和服务的大门。
Shell.Application:这是Windows Shell的COM(组件对象模型)接口名称,通过这个接口可以访问和控制Windows Shell的功能,例如浏览文件系统、打开文件、执行程序等。
首先获取AutoCAD应用程序对象,然后通过这个对象获取Windows Shell的接口对象,并将其保存在变量sh中。这样,在AutoLisp中就可以使用这个对象来执行与Windows Shell相关的操作。

……看晕了吗?
我反正是晕了。

总归,这句魔法咒语的意思:
我要跟和cad软件开始交易了!

你要问我这句魔法咒语是怎么被我写出来的?
抄得。
下一题。

……为什么要获得这个接口,主要原因还是接下来这句代码。里面的函数需要有这么个参数:
  1. (setq folder (vlax-invoke-method sh 'BrowseForFolder 0 "选择块文件夹" 0))

vlax-invoke-method ,定义-调用-方法。它至少两个参数:要调用的ActiveX对象和方法名。

所以上文要用一系列的VLA函数,来传递CAD这个对象。
BrowseForFolder 是用来选择文件夹的函数,后面几个都是它的参数,比如是否允许选择、标题显示、默认啥的。

最后是
  1. (vlax-release-object sh)

这句魔法咒语的意思:
跟CAD软件的交易结束了!

说实话这三句代码,让我看懂没问题,但让我再写出来,或者换个方式,比如不是文件夹而是文件,那又得再磨叽会儿。

所以对于我们这种菜鸟来说,把它保存下来就行了……
会用第一!


2 获取文件夹地址

  1. (setq folderPath (vlax-get-property folder 'Path))

很煎蛋,文件夹都选好了,用 vlax-get-property 把 folder 的 path 属性传递了不就行了嘛。

最后再重申返回下文件夹地址。


3  添加默认地址

使用的时候发现每次都要选择实在是太烦了,明明文件夹每次都是一样的。
这时候需要增加一个默认地址的功能。

如果使用默认地址,就直接空格过去。

首先你得定义个默认地址吧?直接使用 setq。
然后你得显示下默认地址是啥,不然我怎么对不对。直接使用 princ。
然后就是进行选择,是否使用默认地址?使用就直接返回默认地址,不使用就再进入选择。用 if 语句判定下。
注意这里还不能跟前面获取桩号标注的时候一样,先选择 Y 或者 N,如果是 Y 或者空格,才进入。这里要用到 equal,来判定输入的是什么。

  1.   (setq defaultFolderPath "默认地址")
  2.   (princ (strcat "\n预设路径: " defaultFolderPath))
  3.   (initget 0 "Y N")
  4.   (setq userChoice (getkword "&使用预设路径(Y\n)? <Y>\n "))
  5.   (if (or (equal userChoice "Y") (equal userChoice nil))
  6.     defaultFolderPath
  7.     (progn
  8.       (XXX)
  9.     )
  10.   )
  11. )



 楼主| 发表于 2024-4-28 21:00:01 | 显示全部楼层
本帖最后由 Gaudi 于 2024-4-29 13:04 编辑

第三篇  第二部分  经验总结




1

工作不是考试,不需要你掌握每一条代码的来龙去脉。

有些自己新建比较困难的东西,就把别人写的轮子看懂了,直接使用就行了。

会修改就行。

图纸不都是这么来得,修修补补又三年。

2

VLA函数再一次印证了它又长又软的特点。

只要你知道有这么个函数,可以实现这个功能。

你就不再需要通过各种底层的代码去自己实现——因为定义VLA函数的大佬们已经把这些底层代码封装成一个个接近自然语言的VLA函数了。

所以学习VLA函数,最简单的办法,应该是对着帮助文件一个个看。

跟大佬们混个眼熟。

以后才能想起来——

大佬,上次你说能读取文件夹,这事你看好办不?



3

这里面有个坑,还是我后来才发现的。

从逻辑上看,直接使用 getkword 函数就行了。

没想到 autolisp 中还需要一个  initget 函数初始化……

initget 函数后面跟一个参数和一个列表,参数常用的就是 0 和 1,其中 0 代表可以空格返回 nil,1 代表不允许。

全是坑!
发表于 2024-4-28 21:15:12 | 显示全部楼层
厉害  天天记录!
 楼主| 发表于 2024-4-29 10:11:17 | 显示全部楼层
本帖最后由 Gaudi 于 2024-4-29 15:53 编辑

第三篇  第三部分  读取指定excel表数据



这部分很重要,因为它自身的耦合性很高,可以用到其他任何函数里面。

同时这部分的代码确实理解起来有点难度,所以我先把代码放出来,不太想去理解的朋友,可以直接用。

  1. (defun ReadExcelData ()
  2.   (setq defaultPath (getvar "DWGPREFIX"))
  3.   (setq selectedExcelFile (getfiled "选择外业数据" defaultPath "xlsx;xls" 0))
  4.   (setq application (vlax-get-or-create-object "Excel.Application"))
  5.   (setq workbooks (vlax-get-property application "WorkBooks"))
  6.   (setq workbook (vlax-invoke-method workbooks "Open" selectedExcelFile))
  7.   (setq sheets (vlax-get-property workbook "Sheets"))
  8.   (setq worksheet (vlax-get-property sheets "Item" "标志牌"))
  9.   (setq range (vlax-get-property worksheet "Range" "A2:E100"))
  10.   (setq variantValues (vlax-get-property range 'Value))
  11.   (setq listValues (vlax-safearray->list (vlax-variant-value variantValues)))
  12.   (vlax-invoke-method workbook "Close")
  13.   (vlax-invoke-method application "Quit")
  14.   (vlax-release-object application)
  15.   listValues
  16. )


整体分为以下板块:

A 定义默认路径
B 选择excel程序,建立联系
C 选择工作簿
D 选择工作表
E 选择单元格
F 读取数据
G 改变格式,传递数据
H 关闭工作表、关闭工作簿
I 断开联系
J 重申数据返还

今天有点忙,先放,有空了再解释。



1 思维理解

对于 cad 和 excel 数据交互来说,每一步都需要两个操作:选择、打开。

程序是很笨的嘛,所有操作都得写清楚高速它。

而对于一份 excel 数据来说,这样的步骤需要重复三次:工作簿、工作表、单元格。

理解完成。


2 工作簿

  1. (setq application (vlax-get-or-create-object "Excel.Application"))

vlax-get-or-create-object,定义 - 获取 - 或者 - 创建 - 对象。
理解起来其实很容易,就是创建或者获取一个 VLA 对象,这里定义具体为 excel。
  1. (setq workbooks (vlax-get-property application "WorkBooks"))

vlax-get-property,定义 - 获取 - 属性。
针对已经创建的 VLA 对象,获得其属性,属性定义具体为 workbooks ,工作簿。
将工作簿对象集合传递下去。

3 工作表
  1. (setq workbook (vlax-invoke-method workbooks "Open" selectedExcelFile))

vlax-invoke-method,熟悉的函数,上次是这么使用的:
  1. (setq folder (vlax-invoke-method sh 'BrowseForFolder 0 "选择块文件夹" 0))

上次是用来选择文件夹。
这次是用来在工作簿对象中,将选择的文件打开,将工作表对象集合传递个下一个参数。

  1. (setq worksheet (vlax-get-property sheets "Item" "标志牌"))

在所有的工作表对象集合中,选择特定的工作表,将工作表作为对象传递个下一个参数。

4 单元格
  1. (setq range (vlax-get-property worksheet "Range" "A2:E100"))

在特定的工作表中,选定特定的范围,将单元格范围传递给下一个参数。
  1. (setq variantValues (vlax-get-property range 'Value))

在特定的单元格中,选择参数 value,将数值传递给下个参数。


5


到这里理论上就结束了。


但是会报错。
因为到目前为止,所谓的“value”仍然是一个VLA对象。
所以需要一个函数,将这个 VLA 对象,转为 cad 可返回的参数。
  1. (setq listValues (vlax-safearray->list (vlax-variant-value variantValues)))

这里有两个函数,一个是vlax-variant-value,定义-变体-数值;一个是vlax-safearray->list,定义-安全数组 转为 列表。

这里面有两个很拗口的概念:变体和安全数组。
先不聊,能理解就理解,半理解就这么
总归这两个函数的意思就是,先将读取的变体数值转为安全数组,再将安全数组转为列表。


 楼主| 发表于 2024-4-29 16:10:57 | 显示全部楼层
本帖最后由 Gaudi 于 2024-4-29 16:30 编辑

第三篇  第三部分  经验总结



1

我们再把整个流程顺一下:
vlax-get-or-create-object "Excel.Application":告诉电脑,今晚把 excel 带来。

vlax-get-property application "WorkBooks":excel,把所有工作簿全都叫上来!
vlax-invoke-method workbooks "Open" selectedExcelFile:就点这个工作簿了,其他下去吧。

vlax-get-property workbook "Sheets":这个工作簿里,所有工作表全都上来!
vlax-get-property sheets "Item" "标志牌":就点这个工作表了,其他下去吧。

vlax-get-property worksheet "Range" "A2:E100":这个工作表里,把这些单元格全都叫上来!——其他下去!
vlax-get-property range 'Value:这些单元格都只穿属性,其他不要了。

(setq listValues (vlax-safearray->list (vlax-variant-value variantValues))):老板,属性都变成你喜欢的列表了,是不是让它们进来?——进来吧。

是不是容易理解了。



2

为什么其他都是用的 vlax-get-property,在工作簿集合中选择工作簿使用的是 vlax-invoke-method 呢?
vlax-get-property,定义-获取-属性。
vlax-invoke-method,定义-调用-方法。

前者是获取一个对象的属性,是静态的。
后者是调用一个对象的方法,是动态的。

open、close、quit,都是动作。


3 变体和安全数组

变体和安全数组是什么?
太掉书袋的东西我们不管,直接说我个人的理解。

变体,变的啥?
变的是数据类型。
不同的VLA对象,都有其特殊的数据。
它可以自动“变“成接收端语言所需的数据类型。

安全数组,安全的啥?
固定数据类型、固定数据个数,类似于PDF。

为什么要引入这两个概念?
首先COM平台程序太多,你得尽可能把所有信息能传递出去,这就需要变体。
但是电脑又太笨了,前文所说,数据类型不一样,有些地方就不认识了,所有又需要一个安全数据,来保证数据的类型和结构在传递过程中不会丢失或损坏。

CAD是lisp语言,它喜欢列表,那最后就转成列表咯。


4  

……啰里啰嗦,其实我自己是懒得去理解的。
直接用呗,还能咋地。



这里我有个小问题想请教各位大佬!
这段代码我在其他电脑上不能使用,提示实参过少。
CAD版本一样,EXCEL版本一样,文件地址一样,文件内容一样。
有win7也有win10。
我自己调试发现是
  1. (setq workbook (vlax-invoke-method workbooks "Open" selectedExcelFile))
未生效。

把它转成vlax-invoke函数以后这句可行,但仍然提示实参太少,调试发现又是
  1. (setq worksheet (vlax-get-property sheets "Item" "标志牌"))
未生效。

求助各位大佬!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-25 18:57 , Processed in 0.213918 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表