找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 736|回复: 2

[LISP函数]:AutoCAD中特定角度及长度捕捉的实现方法

[复制链接]
发表于 2003-5-19 16:00:30 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、引言
??  在AutoCAD中的角度捕捉只有当正交状态打开时的直和水平方向,对于其他特殊角度无能为力;另外,其网点捕捉也是相对于X轴和Y轴,无法实现其他方向的特殊长度捕捉,给绘图带来极大的不方便。
??
??  在应用AutoCAD进行设计制图的操作中,LINE和POLYLINE是使用频率最高的两个命令,经常要遇到在某些特定角度上绘制特定长度的简单线或复合线的情况,因而实现这两个捕捉对提高AutoCAD作图效率很有实用价值。
??
??二、方法原理
??
??  所谓角度捕捉,是指当十字光标在某一角度α的一定范围内选取一点时,该点自动落在该α角度线上;当我们设定捕捉角度为α时,将会以基准点作为原点、自X轴正方向出发,将整个屏幕划分为[360/α]个区间,则NXα角度就是角度捕捉线,其中,0≤N≤[360/α],[360/α]表示不大于360/α的整数。
??
??  所谓长度捕捉,是在角度捕捉的基础上,在某一角度线上有一系列捕捉点,该系列点离基准点的距离为捕捉长度的正整数倍,当选取直线上的一点时,落点自动落到离其最近的捕捉点上。
??
??  实现特定角度和长度捕捉的关键点是:当十字光标(即十字交叉线)移动时,程序要随时跟踪其交叉点的位置,并将该位置与用户所设定的捕捉角度与长度对应起来,从而计算出在该角度上的落点。
??
??  以下举例说明该两个捕捉的实现过程:
??
??  假定捕捉角度为α=30°,捕捉长度为L。
??
??  当十字光标在任意的某一区间内移动时,比如在第5区间(120°~150°)内移动时,此时,落点只能在120°或150°线上(该线在图中并不直接显示),该两根角度线的中心线为135°。当十字光标的中心点处在120°~135°之间时,则落点应在120°线上,该落点的具体位置为由十字光标的中心点向120°线作垂线来获得,其交点D(称为垂点)即为落点,为直观起见,此时由基准点(此处为O点)向落点作一橡筋拖曳线,该橡筋拖曳线随十字光标的移动而相应移动,显示出拖动过程;同样,当十字光标的中心点处在135°~150°之间时,则落点应在150°线上,并显示相应的橡筋拖曳线。该橡筋拖曳线并不是真正的线段,只是用XOR墨水绘制的一个向量,当用XOR墨水重新绘制一遍该向量时,该向量将从屏幕上消失,这就是本程序实现光标拖动的原理。
??
??  落点落在某一捕捉角度线上时,还得落在捕捉长度L的整数倍的点(称为捕捉点)上,还是针对图1,其垂点必然处于某两个捕捉点A与B之间,设A与B的中点为C,当D处于A与C之间时,落点应为A;当D处于C与B之间时,落点应为B。其中:??
?? ----
??
?? OA=nXL;OB=(n+1)XL
??
?? n:非负整数。
??
?? L:捕捉长度。此时,程序通过一定的操作将在屏幕的最上面的坐标提示行准确地显示落点相对基准点的偏移长度和偏移角度。用户可以滑动鼠标准确捕捉到目标点。
??
??至此,已实现某些特定角度及长度的捕捉。为了满足在程序执行过程中能随时更改捕捉角度和捕捉长度的需要,本程序还增加了相应的模块;另外,本程序中嵌入了窗口放缩功能模块,通过点取下拉菜单中窗口及漫游子菜单,方便了各种作图的需要。
??
??三、源程序清单
??
?? ;;OS.LSP源程序
??
?? ;;err(),出错处理子程序
??
?? (defunerr(msg)
??
?? (if(/=msg\"Functioncancelled\")
??
?? (princ(strcat\"\\nError:\"msg));打印错误内容
??
?? );forif
??
?? (setq*error*olderr)
??
?? (setvar\"cmdecho\"scmd)
??
?? (setvar\"osmode\"cosmode)
??
?? (setvar\"coords\"ccoords)
??
?? (princ\"n\\n\\t--多谢使用角度捕捉2.0版,程序非正常结束--!\\n\")
??
?? (princ)
??
?? );fordefunerr
??
?? ;;ant(),设定捕捉角度子程序
??
?? (defunant(/ang0ang1)
??
?? (setqang0(*an0(/180pi)))
??
?? (princ(strcat\"\\n请输入捕捉角度:<\"(rtosang0)\">_\"))
??
?? (INITGET4)
??
?? (setqang1(getreal))
??
?? (if(not(nullang1))
??
?? (setqan0(*ang1(/pi180)))
??
?? )
??
?? (princ\"\\nF2/F3/F4/F5/ESC/Return/下一点:\")
??
?? );fordefunant
??
?? ;;leng(),设定捕捉长度距离子程序
??
?? (defunleng(/leng0leng1)
??
?? (setqleng0len0)
??
?? (princ(strcat\"\\n请输入捕捉长度距离:<\"(rtosleng0)\">_\"))
??
?? (INITGET4)
??
?? (setqleng1(getreal))
??
?? (if(not(nullleng1))
??
?? (setqlen0leng1)
??
?? )
??
?? (princ\"\\nF2/F3/F4/F5/ESC/Return/下一点:\")
??
?? );fordefunlent
??
?? ;;field(),判断十字光标所在区间,并投影到相应的捕捉角度线上
??
?? (defunfield(pspeang0/ang1n)
??
?? (setqang1(anglepspe))
??
?? (setqn(fix(+(/ang1ang0)0.5)))
??
?? (setqang2(*ang0n))
??
?? );fordefun
??
?? ;;endp(),十字光标投影到相应的捕捉角度上后,以用户设定的长度
??
?? ;;捕捉计算落点
??
?? (defunendp(pspeang0/p1p2p3p4dis)
??
?? (setqp1ps
??
?? p2(polarpsang01)
??
?? p3pe
??
?? p4(polarpe(+ang0(/pi2))1)
??
?? )
??
?? (setqpend(intersp1p2p3p4nil))
??
?? (setqdis(distancepspe))
??
?? (if(/=len00)
??
?? (setqdist(*(fix(+(/dislen0)0.5))len0))
??
?? ;else
??
?? (setqdistdis)
??
?? );forif
??
?? (setqpend(polarpsang0dist))
??
?? );fordefunendp
??
?? ;;drag(),对上一次显示的拖曳线进行\"或\"操作,使其从屏幕上消失,
??
?? ;;并绘制下一次拖曳线
??
?? (defundrag(pold1pold2pold3/)
??
?? (if(/=b24)
??
?? (progn
??
?? (grdrawpold1pold2-10)
??
?? (grdrawpold2pold3-10)
??
?? )
??
?? );forif
??
?? (grdrawpstartpend-10)
??
?? (grdrawpendpframe-10)
??
?? );fordefundrag
??
?? ;;coord(),在屏幕的最上一行的坐标栏显示长度和角度
??
?? (defuncoord(/strleng1leng0ang0)
??
?? (setqang0(*ang2(/180pi)))
??
?? (setqstr(strcat(rtosdist)\">\"(rtosang0)))
??
?? (grtext-2str)
??
?? );fordefuncoord
??
?? ;;init(),对程序进行初始化
??
?? (defuninit(/)
??
?? (setqscmd(getvar\"cmdecho\"));保留原命令回显方式
??
?? (setqccoords(getvar\"coords\"));保留原坐标显示方式
??
?? (setqcosmode(getvar\"osmode\"))
??
?? (setqolderr*error**error*err);出错处理
??
?? (setvar\"cmdecho\"0);不回显
??
?? (setvar\"coords\"0);不显示坐标
??
?? (setvar\"osmode\"0);取消捕捉
??
?? (setqb0b10c\'(00))
??
?? (setqpstart(getpoint\"\\n请输入直线第一点:\"))
??
?? (if(or(nullan0)(<an00)(not(numberpan0)))
??
?? (progn
??
?? (setqan0(/pi6))
??
?? (ant)
??
?? )
??
?? );forif
??
?? (if(or(nulllen0)(<len00)(not(numberplen0)))
??
?? (progn
??
?? (setqlen01)
??
?? (leng)
??
?? )
??
?? );forif
??
?? (if(nulllen0)(leng))
??
?? (princ\"\\nF2/F3/F4/F5/ESC/Return/下一点::\")
??
?? (setqa(grread2nil))
??
?? (setqpframe(cadra))
??
?? (fieldpstartpframean0)
??
?? (endppstartpframeang2)
??
?? (grdrawpstartpend-10)
??
?? (grdrawpendpframe-10)
??
?? (setqplastpframepoldepend)
??
?? (setqb(cara))
??
?? );fordefuninit
??
?? ;;home(),设置退出程序的控制变量
??
?? (defunhome(/)
??
?? (setqb3)
??
?? (setqb11)
??
?? );fordefunhome
??
?? ;;pull(),接受用户输入控制子程序
??
?? (defunpull(/)
??
?? (setqb10)
??
?? (while(/=b3)
??
?? (progn
??
?? (setqa(grread2nil))
??
?? (coord)
??
?? (if(and(=b2)(=b24))(setqb4))
??
?? (setqb2b)
??
?? (setqb(cara))
??
?? (cond
??
?? ((or(=b5)(=b12));只移动十字光标时
??
?? (progn
??
?? (setqpframe(cadra))
??
?? (fieldpstartpframean0)
??
?? (endppstartpframeang2)
??
?? (if(>=(distanceplastpframe)0.1)
??
?? (progn
??
?? (dragpstartpoldeplast)
??
?? (setqplastpframepoldepend)
??
?? );forprogn
??
?? );forif
??
?? );forprogn
??
?? );forcond1
??
?? ((=b3);用鼠标在屏幕上点取一点时
??
?? (progn
??
?? (setqpframe(cadra))
??
?? (fieldpstartpframean0)
??
?? (endppstartpframeang2)
??
?? (if(>=(distanceplastpframe)0.1)
??
?? (progn
??
?? (grdrawpstartpolde-10)
??
?? (setqplastpframepoldepend)
??
?? );forprogn
??
?? );forif
??
?? );forprogn
??
?? );forcond1
??
?? ((=b2);键盘输入
??
?? (progn
??
?? (setqc1(cadra))
??
?? (cond((=c1138)(ant));F2
??
?? ((=c1139)(leng));F3
??
?? ((=c1140);F4
??
?? (progn
??
?? (setqb24)
??
?? (command\"zoom\"\"0.7x\")
??
?? )
??
?? );for(=c1140)
??
?? ((=c1141);F5
??
?? (progn
??
?? (setqb24)
??
?? (command\"zoom\"\"1.4x\")
??
?? )
??
?? );for(=c1141)
??
?? ((=c113)(home))
??
?? ((=c127)(home))
??
?? (T(princ\"\\n未定义的键\"))
??
?? );forcond
??
?? (princ\"\\nF2/F3/F4/F5/ESC/Return/下一点:\")
??
?? );forprogn
??
?? );for(cond(=b2))
??
?? ((=b4);点取下拉菜单时
??
?? (progn
??
?? (setqc1(cadra))
??
?? (princ\"\\n\")
??
?? (cond((=c16005)
??
?? (progn
??
?? (command\"zoom\"\"w\")
??
?? (princ\"\\n第一角点:\")
??
?? (commandpause)
??
?? (princ\"\\n第二角点:\")
??
?? (commandpause)
??
?? )
??
?? );for(=c16005)
??
?? ((=c16007)
??
?? (command\"zoom\"\"p\"))
??
?? ((=c16008)
??
?? (command\"zoom\"\"a\"))
??
?? ((=c16011)
??
?? (progn
??
?? (command\"pan\")
??
?? (princ\"\\n第一参考点:\")
??
?? (commandpause)
??
?? (princ\"\\n第二参考点:\")
??
?? commandpause)
??
?? )
??
?? );for(=c16011)
??
?? ;;else
??
?? (T(princ\"\\n未定义的菜单\"))
??
?? );forcond
??
?? (princ\"\\nF2/F3/F4/F5/ESC/Return/下一点:\")
??
?? );FORPROGN
??
?? );for(cond(=b4))
??
?? (T(home));forelse
??
?? );forcond
??
?? );forprogn
??
?? );forwhile
??
?? );fordefunpull
??
?? ;;draw(),绘制直线子程序
??
?? (defundraw(/)
??
?? (while(/=b11)
??
?? (progn
??
?? (if(=b3)
??
?? (progn
??
?? (command\"line\"pstartpend\"\")
??
?? (princ\"\\nF2/F3/F4/F5/ESC/Return/下一点:\")
??
?? (setqb0b11)
??
?? (setqpstartpend)
??
?? );forprogn
??
?? );forif
??
?? (pull)
??
?? );forprogn
??
?? );forwhile
??
?? (grdrawpstartpend-10)
??
?? (grdrawpendpframe-10)
??
?? );fordefundraw
??
?? ;;;;主程序
??
?? (defunc:os(/bb1b2cpstartpendpframeplastang2
??
?? distscmdccoordsolderrcosmode)
??
?? ;;;an0len0aredefinedoutprogram
??
?? (init)
??
?? (draw)
??
?? (princ\"\\n\")
??
?? (command\"redraw\")
??
?? (setq*error*olderr)
??
?? (setvar\"cmdecho\"scmd)
??
?? (setvar\"osmode\"cosmode)
??
?? (setvar\"coords\"ccoords)
??
?? (princ\"\\n\\n\\t------角度捕捉2.0版------\\n\")
??
?? (princ\"\\n\\n\\t**宁波大学建筑设计研究院--程建华,1996**\\n\")
??
?? (princ)
??
?? );fordefunos
??
??四、程序的安装与使用
??
?? 1.程序的安装
??
??以下三种装载方式,用户任选一种即可:在AutoCAD环境下,将OS.LSP拷至当前目录,再执行(LOAD\"OS\")即可装载OS.LSP。也可先将OS.LSP拷至\\ACAD\\SUPPORT\\子目录下,再在\\ACAD\\SUPPORT\\ACADR12.LSP或ACADR13.LSP中加入下面一句语句实现启动AutoCAD时自动装载:
??
?? (AUTOLOAD\"OS\"\'(\"OS\"))
??
??也可将OS.LSP拷至\\ACAD\\SUPPORT\\子目录下,在\\ACAD\\SUPPORT\\\\子目录下的菜单文件ACAD.MNU中的合适位置加上下面的一句语句,即可直接在菜单中点取角度捕捉操作:
?? ??
?? [角度捕捉]^c^c(load\"c:/acad/support/os.lsp\")os
?? ??
?? 2.程序的使用
??
??在一幅图中第一次使用该程序时,需要用户输入捕捉角度和捕捉长度,第二次调用本程序时,程序可自动采用上一次最后设定的捕捉角度和长度作为默认值。然后,程序需要用户选择输入一点作为基准点,此时命令行提示:
??
?? F2/F3/F4/F5/ESC/Return/下一点:
??
?? 用户根据该提示可任选其中的一种操作,具体解释如下:
??
??①按F2键重新设定捕捉角度;
??
??②按F3键重新设定捕捉长度;
??
??③按F4键窗口缩小0.7倍;
??
??④按F5键窗口放大1.4倍;
??
??⑤按ESC键、回车键、鼠标右键均可结束操作,退出程序;
??
??⑥选取下一点,移动十字光标键,此时在屏幕的最上面的一行的坐标提示栏准确地显示出按用户设定的捕捉角度和长度所取得的落点相对于基准点的偏移角度和长度,滑动十字光标键直至用户寻找到所需要的下一点并按下鼠标左键,命令行重又出现上面的提示行,并进行下一轮循环;
??
??⑦另外,用户还可以点取View菜单下的Zoom菜单中的ZoomWindow、ZoomPrevious、ZoomAll等三个子项实现窗口放缩和Pan菜单实现屏幕漫游;对于其他操作,用户均可按屏幕命令行的中文提示方便地进行操作。在非汉化AutoCAD中运行本程序时,只需将程序中有关的中文提示行改成英文提示即可。另外,由于不同的机型在AutoCAD环境下键盘返回码可能稍有区别,所以要求用户在应用本程序之前对自己的机器键盘返回码按如下方法作一次核实:
??
??  在AutoCAD命令状态下输入(grread)并回车,用户此时可按下F2或F3、F4、F5键:
??
??第一步:Command:(grread)回车
??
??第二步:按下F2键
??
??  此时,屏幕上回显刚输入的键值,比如对笔者使用的机器(ASTPIII+4/66D)回显为:(2136)。
??
??  其具体涵义为:第一个数字\"2\"表示刚才是键盘输入;第二个数字\"136\"表示本机器的\"F2\"键的返回码。
??
??  按上述步骤依次对FF4、F5键的返回码进行核实,笔者的机器该三键的返回码分别为137、138、139。
??
??  如果核实结果与上述结果不符(比如,对某些机型,上述四键的返回码分别为138、139、140、141),则应对程序中的相应语句作如下修改。
??
??  在\"接受用户输入控制子程序\"pull()中的键盘输入部分的下述语句作对应修改:
??
?? (cond((=c1136)(ant));F2--此处136改为用户的F2键返回码
??
?? ((=c1137)(leng);
??
?? F3--此处137改为用户的F3键返回码
??
?? ((=c1138);
??
?? F4--此处138改为用户的F4键返回码
??
?? ((=c1139);
??
?? F5--此处139改为用户的F5键返回码
??
??  最后,需要指出的是:用户自己的菜单文件ACAD.MNU可能增删过菜单项或AutoCADR13中,会使ZoomWindow、ZoomAll、ZoomPrevious、Pan在菜单中位置发生改变。这样,要求用户在应用本程序之前对自己的菜单项回码按如下方法作一次核实:
??
??  在AutoCAD命令状态下输入(grread)并回车,用户此时可点取下拉菜单View下的Zoom子菜单中的Window项,对于笔者的菜单其返回值为:(46005)。其具体涵义为:第一个数字\"4\"表示刚才是下拉菜单输入;第二个数字\"6005\"表示本菜单的ZoomWindow菜单项的返回码。用户可按同样的方法找到菜单项ZoomAll、ZoomPrevious、Pan的返回码。并相应地改变\"接受用户输入控制子程序\"pull()中的\"点取下拉菜单\"部分的下述语句作对应修改:
??
?? (cond((=c16005)--此处6005改为用户的ZoomWindow菜单项返回码;
??
?? ((=c16007)--此处6007改为用户的ZoomPrevious菜单项返回码;
??
?? ((=c16008)--此处6008改为用户的ZoomAll菜单项返回码;
??
?? ((=c16011)--此外6011改为用户的Pan菜单项返回码;
??
??五、结语
??
??  应用本程序,可在制图过程中很方便地实现某些特定角度和长度的捕捉,简化了操作步骤和击键次数,根据目前的使用情况来看,画线时可提高作图速度4倍以上。至于AutoCAD内部提供的正交和网点捕捉只是本程序当捕捉角度为90°时的一个特例。
??
??  将本程序的画线子模块draw()中语句行
??
??  (command\"line\"pstartpend\"\") ??
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
发表于 2003-5-19 20:29:41 | 显示全部楼层
这贴斑竹怎么没有转移呀!!!!
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2003-5-20 09:55:00 | 显示全部楼层
极轴捕捉 好像能很好的完成这个功能啊。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2025-9-26 08:18 , Processed in 0.184540 second(s), 34 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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