AutoLisp从入门到放弃(十七):条件与循环的实战应用
1. 条件判断在AutoLisp中的实战应用记得我第一次用AutoLisp写自动化绘图脚本时if函数就像个严格的交通警察控制着程序执行的每个路口。这个看似简单的函数在实际工程中能玩出各种花样。比如在机械制图时我们经常需要根据不同的零件类型自动调整标注样式(defun C:SmartDimension (/ partType dimStyle) (setq partType (getstring \n请输入零件类型(轴/齿轮/法兰): )) (if ( (strcase partType) 轴) (setq dimStyle AXIS_DIM) (if ( (strcase partType) 齿轮) (setq dimStyle GEAR_DIM) (setq dimStyle FLANGE_DIM) ) ) (command -dimstyle r dimStyle) )这个例子展示了if的嵌套用法但实际项目中更复杂的逻辑判断会让人头晕。这时候就该progn上场了——它能把多个表达式打包成一个表达式。有次我写批量修改图层的脚本就深刻体会到它的价值(if (setq ss (ssget X ((8 . OLD_LAYER)))) (progn (command -layer m NEW_LAYER ) (command chprop ss la NEW_LAYER ) (princ (strcat 已转换 (itoa (sslength ss)) 个对象)) ) (princ 未找到需要修改的对象) )2. repeat函数的工程化应用repeat就像个精准的计数器特别适合处理已知次数的重复操作。在建筑图纸中我常用它来生成标准层平面(defun C:GenFloors (/ floorNum basePt height) (setq basePt (getpoint \n指定首层基点: ) height (getdist \n输入层高: ) floorNum (getint \n输入层数: )) (repeat floorNum (command -insert 标准层 basePt ) (setq basePt (list (car basePt) (cadr basePt) ( (caddr basePt) height))) ) )更实用的场景是批量生成坐标网格。有次做总图布置用repeat配合数学计算30行代码就解决了原本需要手动绘制2小时的工作(defun C:DrawGrid (/ cols rows colSpace rowSpace startPt) (setq cols (getint \n列数: ) rows (getint \n行数: ) colSpace (getdist \n列间距: ) rowSpace (getdist \n行间距: ) startPt (getpoint \n基准点: )) (repeat cols (setq tempPt startPt) (repeat rows (command point tempPt) (setq tempPt (list (car tempPt) ( (cadr tempPt) rowSpace))) ) (setq startPt (list ( (car startPt) colSpace) (cadr startPt))) ) )3. while循环处理不确定次数任务while就像个不知疲倦的质检员会一直工作到条件不满足为止。在处理用户输入验证时特别有用(defun C:GetValidNumber (/ userInput) (setq userInput (getint \n请输入1-100间的数字: )) (while (or ( userInput 1) ( userInput 100)) (setq userInput (getint \n输入无效! 请重新输入1-100间的数字: )) ) (princ (strcat 你输入的数字是: (itoa userInput))) )更高级的用法是配合选择集遍历对象。我曾经用while开发过智能标注工具(defun C:AutoDimLines (/ ss i ent) (if (setq ss (ssget ((0 . LINE)))) (progn (setq i 0) (while ( i (sslength ss)) (setq ent (ssname ss i)) (command dimlinear (cdr (assoc 10 (entget ent))) (cdr (assoc 11 (entget ent))) pause) (setq i (1 i)) ) ) ) )4. cond函数实现多条件分支cond就像个智能路由器可以优雅地处理复杂的条件分支。在开发图纸版本转换工具时我这样处理不同CAD版本兼容问题(defun C:ConvertVersion (/ ver) (setq ver (getstring \n目标版本(2004/2007/2010/2013/2018): )) (cond (( ver 2004) (command -saveas 2004 (getvar dwgname))) (( ver 2007) (command -saveas 2007 (getvar dwgname))) (( ver 2010) (command -saveas 2010 (getvar dwgname))) (( ver 2013) (command -saveas 2013 (getvar dwgname))) (( ver 2018) (command -saveas 2018 (getvar dwgname))) (T (princ \n不支持的版本号)) ) )在参数化设计方面cond更是大显身手。比如这个智能生成标准件的函数(defun C:GenFastener (/ type size pt) (setq type (getstring \n紧固件类型(螺栓/螺母/垫圈): ) size (getreal \n规格尺寸: ) pt (getpoint \n插入点: )) (cond (( (strcase type) 螺栓) (command -insert BOLT pt size size 0)) (( (strcase type) 螺母) (command -insert NUT pt size size 0)) (( (strcase type) 垫圈) (command -insert WASHER pt size size 0)) (T (princ \n未知的紧固件类型)) ) )5. 综合实战自动化图框生成系统结合前面所有知识点我们来看个完整的工程案例。这个系统能根据项目类型自动生成符合不同企业标准的图框(defun C:SmartTitleBlock (/ company projectType size pt) (setq company (getstring \n企业标准(A/B/C): ) projectType (getstring \n项目类型(建筑/机械/电气): ) size (getstring \n图幅(A0/A1/A2/A3): ) pt (getpoint \n图框基点: )) (cond ((and ( (strcase company) A) ( (strcase projectType) 建筑)) (command -insert A_ARCH pt size size 0) (AddArchAttributes)) ((and ( (strcase company) A) ( (strcase projectType) 机械)) (command -insert A_MECH pt size size 0) (AddMechAttributes)) ((and ( (strcase company) B) ( (strcase projectType) 电气)) (command -insert B_ELEC pt size size 0) (AddElecAttributes)) (T (command -insert STANDARD pt size size 0)) ) (if (and ( (strcase company) C) (or ( (strcase projectType) 建筑) ( (strcase projectType) 机械))) (progn (command -layer s TITLE_BLOCK ) (AddCustomAttributes) (princ \n已应用C公司特殊标准)) ) )这个例子展示了如何将条件判断和循环有机结合。AddXXXAttributes这些自定义函数内部可能会用到while遍历图块属性用repeat生成标准字段用if/cond处理不同情况。6. 调试技巧与性能优化写了这么多条件循环代码最头疼的就是调试。我总结了几条实用经验复杂条件判断时先用princ输出中间结果。比如(princ (strcat \n当前值: (itoa var)))循环体内设置安全计数器避免死循环(setq maxLoop 100 loopCnt 0) (while (and ( loopCnt maxLoop) (not done)) ... (setq loopCnt (1 loopCnt)) )多重嵌套时适当使用注释标记结束位置(if condition1 (progn ... (if condition2 ... ) ; end if condition2 ) ; end progn ) ; end if condition1性能方面要注意在遍历大量对象时尽量减少循环体内的图形操作。有次我优化一个批量修改程序把command调用移到循环外速度提升了20倍; 慢速版本 (repeat 1000 (command move ...) ) ; 优化版本 (command move) (repeat 1000 (command ...) ) (command )7. 高级应用动态条件判断AutoLisp的条件判断还能玩得更高级。比如实现模糊匹配(defun FuzzyMatch (pattern str / cnt) (setq cnt 0) (repeat (strlen pattern) (if (wcmatch str (strcat * (substr pattern (setq cnt (1 cnt)) 1) *)) (setq match T) ) ) match )再比如带缓存的智能判断系统(setq *judgeCache* nil) (defun SmartJudge (condition / cached) (setq cached (assoc condition *judgeCache*)) (cond (cached (cdr cached)) (T (setq result (ComplexCalculation condition)) (setq *judgeCache* (cons (cons condition result) *judgeCache*)) result) ) )这些技巧在我开发智能标注系统时发挥了巨大作用。一个典型的应用是根据图形上下文自动选择标注样式(defun ContextAwareDim (/ ent dimType) (setq ent (car (entsel))) (cond ((isBolt ent) (setq dimType BOLT_DIM)) ((isHole ent) (setq dimType HOLE_DIM)) ((isSlot ent) (setq dimType SLOT_DIM)) (T (setq dimType STANDARD_DIM)) ) (command -dimstyle r dimType) (command dimlinear ...) )8. 从工程角度思考条件循环设计经过多个项目的磨练我总结出几个AutoLisp条件循环的设计原则可读性优先宁可多写几行代码也要保证逻辑清晰。复杂的cond语句可以拆分为多个辅助函数。防御性编程所有用户输入和边界条件都要处理。比如(while (not (setq pt (getpoint \n指定位置: ))) (princ \n必须指定一个有效点!) )模块化设计将重复使用的条件判断封装成函数。比如这个判断选择集是否有效的函数(defun IsValidSS (ss) (and ss ( (type ss) PICKSET) ( (sslength ss) 0)) )性能考量在循环前预先收集所有必要数据避免在循环内重复查询。比如; 不推荐 (repeat 100 (setq len (getvar clayer)) ) ; 推荐 (setq len (getvar clayer)) (repeat 100 ... )错误处理使用条件判断预防潜在错误。比如文件操作前检查(if (findfile filename) (progn (setq f (open filename r)) ... ) (princ \n文件不存在!) )这些经验都是我在实际项目中踩坑后总结出来的。比如有次因为没处理空选择集的情况导致脚本在无人值守运行时崩溃差点延误项目交付。现在我的所有脚本都会包含完善的错误检查。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2523144.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!