ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

python lisp语言Autocad二次开发经验分享----Autolisp

python lisp语言Autocad二次开发经验分享----Autolisp 和我的python帖子一样能用AI解决的能很容易查到资料的内容不多赘述1.圆弧半径标注与缩放ZOOMe(command zoom e)存在圆弧半径标注时一旦范围缩放必定包含圆心位置所以在半径很大圆心很远的时候整个缩放会往圆心的另一侧偏移。当然没有缩放需求用不到这里我是在切换到图纸空间后需要在视口中调整模型空间中内容的位置。关于后续如解决这个问题我的方案是直接将圆弧半径标注使用多重引线替代。;; 使用多重引线标注半径文字格式为 R数值 (defun ut_mleader_radius (arc_pt landing_pt r_val dim_text / mleader_text dir_angle ext_pt mleader_obj) ;; 消除后续零 (setvar dimzin 8) ;; 构造标注文字 (setq mleader_text (if (and dim_text (vl-string-search dim_text)) (vl-string-subst (strcat R (rtos r_val 2 3)) dim_text) (strcat R (rtos r_val 2 3)) ) ) ;; 沿arc_pt→landing_pt方向延伸作为引线落点 (setq dir_angle (angle arc_pt landing_pt)) (setq ext_pt (polar arc_pt dir_angle (if ut_mleader_ext_len ut_mleader_ext_len (/ a0 4)))) (command mleader arc_pt ext_pt mleader_text) ;; 应用 Underline_Leader 样式 (setq mleader_obj (vlax-ename-vla-object (entlast))) (vl-catch-all-apply vla-put-StyleName (list mleader_obj Underline_Leader)) )附上视口创建的lisp代码(defun create_simple_viewport (save_path / vp_center vp_width vp_height vp_ent vp_obj doc) ;; 创建视口然后设置比例 ;; 使用标准视口位置和大小 (setq vp_center (list 5 15)) ; A4图纸中心 (setq vp_width 250) ; 视口宽度 (setq vp_height 180) ; 视口高度 ;; 创建视口 (command mview vp_center (list ( (car vp_center) vp_width) ( (cadr vp_center) vp_height))) ;; 等待命令完成 (ut_wait_cmd) ;; 将视口对象移动到视口图层 (setq vp_ent (entlast)) (command change vp_ent p la 视口 ) ;; 获取文档对象和视口对象ActiveX (setq doc (vla-get-ActiveDocument (vlax-get-acad-object))) (setq vp_obj (vlax-ename-vla-object vp_ent)) ;; 使用 vl-catch-all-apply 激活视口防止 ActiveX 类型不匹配错误 (if (and doc vp_obj) (progn (vl-catch-all-apply vla-put-ActiveViewport (list doc vp_obj)) (vl-catch-all-apply vla-put-MSpace (list doc :vlax-true)) ) ) ;; 设置注释比例与视口自定义比例这里的变量可以自己定义。 (if (and vp_obj ut_vp_scale) (progn (setvar CANNOSCALE ut_scale) (vl-catch-all-apply vla-put-CustomScale (list vp_obj ut_vp_scale)) (vl-catch-all-apply vla-update (list vp_obj)) ) ) ;; 返回图纸空间使用 vl-catch-all-apply 防止错误 (if doc (vl-catch-all-apply vla-put-MSpace (list doc :vlax-false)) ) )可能大家不太理解注释性注释性的标注可以在视口中设置注释比例和视口比例假设视口比例1:1注释比例为1或者1:1则注释的文字大小箭头大小视口中的图形都和模型空间中相同设置视口比例2:1注释比例为2:1则注释性的文字大小箭头大小同上保持不变但视口中的图形大小扩大为两倍(setvar CANNOSCALE ut_scale) ;;这个是注释性标注对象的比例 (vl-catch-all-apply vla-put-CustomScale (list vp_obj ut_vp_scale)) ;;这里设置的是自定义视口比例上面的视口创建代码中并未使用到zoome原因如下MVIEW 创建视口时的缩放至范围视口是这么建的create_simple_viewport开头(command mview vp_center (list ( (car vp_center) vp_width) ( (cadr vp_center) vp_height)))AutoCAD 在新建一个图纸空间视口时默认会把该视口内的视图初始化为显示模型空间全部内容并居中相当于对视口内部做了一次zoom extents。所以时序是这样的① MVIEW 创建视口→ 视口视图中点被自动设为模型空间内容的中心→ 此时内容已经居中② vla-put-CustomScale ut_vp_scale→ 只改变缩放倍数但围绕①中已固定的视图中点缩放→ 中心点没变所以无论放大缩小都保持居中这种居中其实是一种隐式依赖如果模型空间里除了目标图形外还有别的实体残留辅助线、参考块等zoom extents会把它们也框进来中心就会跑偏。一旦内容中心 ≠ 视口视图中点这里就不会居中2.python和lisp联动的方式具体实现可以使用AI但我觉得这个思路有时候还是挺有用的。from pyautocad import Autocad # 连接到AutoCAD应用程序 acad Autocad() print(f正在控制: {acad.doc.Name}) # 1. 发送纯LISP代码 # 在AutoCAD中画一条从 (0,0) 到 (10,10) 的直线 lisp_code (command LINE 0,0 10,10 ) acad.SendCommand(f(progn {lisp_code})\n) # 用 progn 包裹确保执行 # 2. 加载并执行外部的 .lsp 文件 # 假设你的脚本是 C:/my_scripts/my_tool.lsp其中定义了一个 C:MYCOMMAND 命令 lisp_file_path rC:/my_scripts/my_tool.lsp # 加载文件 acad.SendCommand(f(load {lisp_file_path})\n) # 执行文件中定义的命令 (注意命令名要大写) acad.SendCommand(MYCOMMAND\n)from pyautocad import Autocad acad Autocad() # 1. 画一条线 (命令行输入: LINE 0,0 10,10 回车) acad.SendCommand(LINE 0,0 10,10 \n) # 2. 执行LISP函数 (比如获取当前图层名并弹窗显示) acad.SendCommand((alert (getvar CLAYER)) \n) # 3. 设置一个系统变量 (比如把十字光标大小设为50) acad.SendCommand(CURSORSIZE 50 \n)这种方式基本上就是直接向命令行发送简短的lisp代码段了。对于不想花大量时间和lisp纠缠并且希望主要使用python一种语言开发是很友好的。一些使用python效果不好的代码实现比如# 设置点样式 (PDMODE) 和点大小 (PDSIZE)[reference:0][reference:1][reference:2] acad.ActiveDocument.SetVariable(PDMODE, 35) acad.ActiveDocument.SetVariable(PDSIZE, 10) # 开启/关闭栅格显示 (GRIDMODE)[reference:3][reference:4] acad.ActiveDocument.SetVariable(GRIDMODE, 1) # 1为开启0为关闭这只是一个示例有些变量设置是生效的有些不生效我也没测试过。假设遇到不生效的情况这个时候可以使用from pyautocad import Autocad acad Autocad() doc acad.ActiveDocument # 1. 清空用户系统变量 USERS1设为空字符串 doc.SendCommand((setvar USERS1 )\n) # 2. 假设有一个字典 global_vars global_vars { my_int: 123, my_float: 3.14, my_str: Hello world, # 包含双引号 my_none: None, } # 3. 注入全局变量按类型生成 LISP 语句 for var_name, var_value in global_vars.items(): if var_value is None: doc.SendCommand(f(setq {var_name} nil)\n) elif isinstance(var_value, (int, float)): doc.SendCommand(f(setq {var_name} {var_value})\n) else: # 字符串转义双引号 escaped str(var_value).replace(, \\) doc.SendCommand(f(setq {var_name} {escaped})\n)3.关于SendCommand方法1.使用pyautocadfrom pyautocad import Autocad acad Autocad() acad.SendCommand((setvar USERS1 )\n) # ✅ 完全正确官方推荐简写pyautocad的Autocad对象本身就封装了SendCommand方法它内部会自动指向当前文档所以可以直接写。在某些需要明确指定文档的场景比如有多个打开的图纸我会写成doc.SendCommand。但如果用的是pyautocad且只操作当前文档直接用acad.SendCommand更简洁。2.直接使用win32com接口import win32com.client acad win32com.client.Dispatch(AutoCAD.Application) doc acad.ActiveDocument doc.SendCommand((setvar USERS1 )\n) # ✅ 必须用 doc.SendCommand # acad.SendCommand(...) # ❌ 这样写会报错AttributeError直接操作 COM 对象时acad是 Application应用程序对象它没有SendCommand方法必须通过当前文档ActiveDocument来发送4.为什么我会使用到lisp以及好不好用在稳定性和速度上确实远超python的com接口方法。但是对于我的电脑配置荣耀magicbook art14 U7-155H32G实测区别不大速度体感差距很小。在开发难度上python面向对象的编程设计毋庸置疑非常方便想实现代码模块化或者调用各种python库尤其是添加数值运算逻辑非常方便。lisp虽然也有vla方法提供面向对象实际使用非常麻烦数学运算更不用说了非常不符合日常习惯。我也是“人生苦短我用python”的信徒但现有项目是基于lisp开发的加上有AI协助所以大部分内容使用lisp完成。注意lisp如果想要模块化需要先在AutoCAD中加载所有所需模块文件才可以调用主函数运行。所以我把项目拆成了若干lisp文件模块之后就很少手动load或者appload加载了直接使用python一次性打包加载完成所有模块。综上我的建议是在电脑性能足够的时候大型项目复杂绘图逻辑直接使用python开发lisp适合作为小组件使用sendcommand发送或者使用python调用一些别人已开发的lisp脚本。
返回列表