一、引言
在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点)向落点作一橡筋拖曳线,该橡筋拖曳线随十字光标的移动而相应移动,显示出拖动过程(见图1);同样,当十字光标的中心点处在135°~150°之间时,则落点应在150°线上,并显示相应的橡筋拖曳线。该橡筋拖曳线并不是真正的线段, 只是用XOR墨水绘制的一个向量,当用XOR墨水重新绘制一遍该向量时,该向量将从屏幕上消失,这就是本程序实现光标拖动的原理。

落点落在某一捕捉角度线上时,还得落在捕捉长度L 的整数倍的点(称为捕捉点)上,还是针对图1,其垂点必然处于某两个捕捉点A与B之间,设A与B的中点为C,当D处于A与C之间时,落点应为A;当D处于C与B之间时,落点应为B (见图1)。其中:

-- --

OA = n XL OB = (n + 1) XL

n: 非负整数。

L: 捕捉长度。 此时,程序通过一定的操作将在屏幕的最上面的坐标提示行准确地显示落点相对基准点的偏移长度和偏移角度。用户可以滑动鼠标准确捕捉到目标点。

至此,已实现某些特定角度及长度的捕捉。为了满足在程序执行过程中能随时更改捕捉角度和捕捉长度的需要,本程序还增加了相应的模块;另外,本程序中嵌入了窗口放缩功能模块,通过点取下拉菜单中窗口及漫游子菜单,方便了各种作图的需要。

三、源程序清单

;; OS.LSP源程序

;;err(),出错处理子程序

(defun err ( msg)

(if (/= msg "Function cancelled")

(princ(strcat "\nError:" msg)) 打印错误内容

) for if

(setq *error* olderr)

(setvar "cmdecho" scmd)

(setvar "osmode" cosmode)

(setvar "coords" ccoords)

(princ "n\n\t --多谢使用角度捕捉2.0版,程序非正常结束--!\n")

(princ)

) for defun err

;; ant(),设定捕捉角度子程序

(defun ant ( / ang0 ang1 )

(setq ang0 (* an0 (/ 180 pi)) )

(princ (strcat "\n请输入捕捉角度:<" (rtos ang0) ">_"))

(INITGET 4)

(setq ang1 (getreal))

(if (not (null ang1))

(setq an0 (* ang1 (/ pi 180)))

)

(princ "\n F2/F3/F4/F5/ESC/Return /下一点:")

) for defun ant

;; leng(),设定捕捉长度距离子程序

(defun leng ( / leng0 leng1 )

(setq leng0 len0)

(princ (strcat "\n 请输入捕捉长度距离:<" (rtos leng0) ">_"))

(INITGET 4)

(setq leng1 (getreal))

(if (not (null leng1))

(setq len0 leng1 )

)

(princ "\n F2/F3/F4/F5/ESC/Return /下一点:")

) for defun lent

;; field(),判断十字光标所在区间,并投影到相应的捕捉角度线上

(defun field ( ps pe ang0 / ang1 n )

(setq ang1 (angle ps pe))

(setq n (fix (+ ( / ang1 ang0) 0.5)))

(setq ang2 (* ang0 n))

);for defun

;; endp(), 十字光标投影到相应的捕捉角度上后,以用户设定的长度

;; 捕捉计算落点

(defun endp ( ps pe ang0 / p1 p2 p3 p4 dis )

(setq p1 ps

p2 (polar ps ang0 1)

p3 pe

p4 (polar pe (+ ang0 (/ pi 2)) 1)

)

(setq pend (inters p1 p2 p3 p4 nil))

(setq dis (distance ps pe))

(if ( / = len0 0)

(setq dist (* (fix (+ (/ dis len0) 0.5)) len0))

else

(setq dist dis)

) for if

(setq pend (polar ps ang0 dist))

) for defun endp

;; drag(), 对上一次显示的拖曳线进行"或"操作,使其从屏幕上消失,

;; 并绘制下一次拖曳线

(defun drag ( pold1 pold2 pold3 / )

(if ( / = b2 4)

(progn

(grdraw pold1 pold2 -1 0)

(grdraw pold2 pold3 -1 0)

)

) for if

(grdraw pstart pend -1 0)

(grdraw pend pframe -1 0)

) for defun drag

;; coord(), 在屏幕的最上一行的坐标栏显示长度和角度

(defun coord ( / str leng1 leng0 ang0)

(setq ang0 (* ang2 (/ 180 pi)) )

(setq str (strcat (rtos dist) ">" (rtos ang0)))

(grtext -2 str)

) for defun coord

;; init(), 对程序进行初始化

(defun init ( / )

(setq scmd (getvar "cmdecho"));保留原命令回显方式

(setq ccoords (getvar "coords"));保留原坐标显示方式

(setq cosmode (getvar "osmode"))

(setq olderr *error* *error* err) 出错处理

(setvar "cmdecho" 0);不回显

(setvar "coords" 0) 不显示坐标

(setvar "osmode" 0 ) 取消捕捉

(setq b 0 b1 0 c '(0 0) )

(setq pstart (getpoint "\n 请输入直线第一点:"))

(if (or (null an0 ) (< an0 0) (not (numberp an0)))

(progn

(setq an0 (/ pi 6))

(ant)

)

) for if

(if (or (null len0 ) (< len0 0) (not (numberp len0)))

(progn

(setq len0 1)

(leng)

)

) for if

(if (null len0) (leng))

(princ "\n F2/F3/F4/F5/ESC/Return /下一点::")

(setq a (grread 2 nil))

(setq pframe (cadr a))

(field pstart pframe an0)

(endp pstart pframe ang2)

(grdraw pstart pend -1 0)

(grdraw pend pframe -1 0)

(setq plast pframe polde pend)

(setq b (car a))

) for defun init

, home(), 设置退出程序的控制变量

(defun home ( / )

(setq b 3)

(setq b1 1)

) for defun home

;; pull(), 接受用户输入控制子程序

(defun pull ( / )

(setq b1 0)

(while (/= b 3)

(progn

(setq a (grread 2 nil))

(coord)

(if (and (= b 2) (= b2 4)) (setq b 4))

(setq b2 b)

(setq b (car a))

(cond

((or (= b 5) (= b 12) );只移动十字光标时

(progn

(setq pframe (cadr a))

(field pstart pframe an0)

(endp pstart pframe ang2)

(if (>= (distance plast pframe) 0.1)

(progn

(drag pstart polde plast)

(setq plast pframe polde pend)

) for progn

) for if

) for progn

) for cond1

( (= b 3);用鼠标在屏幕上点取一点时

(progn

(setq pframe (cadr a))

(field pstart pframe an0)

(endp pstart pframe ang2)

(if (>= (distance plast pframe) 0.1)

(progn

(grdraw pstart polde -1 0)

(setq plast pframe polde pend)

) for progn

) for if

) for progn

) for cond1

((= b 2);键盘输入

(progn

(setq c1 (cadr a))

(cond ((= c1 138) (ant)) F2

((= c1 139) (leng)) F3

((= c1 140) F4

(progn

(setq b2 4)

(command"zoom" "0.7x")

)

) for (= c1 140)

((= c1 141) F5

(progn

(setq b2 4)

(command"zoom" "1.4x")

)

) for (= c1 141)

((= c1 13) (home))

((= c1 27) (home))

(T (princ "\n 未定义的键"))

) for cond

(princ "\n F2/F3/F4/F5/ESC/Return /下一点:")

);for progn

);for (cond (= b 2))

((= b 4);点取下拉菜单时

(progn

(setq c1 (cadr a))

(princ "\n")

(cond ((= c1 6005)

(progn

(command"zoom" "w")

(princ "\n 第一角点:")

(command pause)

(princ "\n 第二角点:")

(command pause)

)

) for (= c1 6005)

((= c1 6007)

(command"zoom" "p" ))

((= c1 6008)

(command"zoom" "a" ))

((= c1 6011)

(progn

(command"pan")

(princ "\n 第一参考点:")

(command pause)

(princ "\n 第二参考点:")

command pause)

)

) for (= c1 6011)

,else

(T (princ "\n 未定义的菜单"))

) for cond

(princ "\n F2/F3/F4/F5/ESC/Return /下一点:")

) FOR PROGN

) for (cond (= b 4))

(T (home) ) for else

) for cond

) for progn

) for while

) for defun pull

;; draw() , 绘制直线子程序

(defun draw ( / )

(while (/= b1 1)

(progn

(if (= b 3)

(progn

(command"line" pstart pend "")

(princ "\n F2/F3/F4/F5/ESC/Return /下一点:")

(setq b 0 b1 1)

(setq pstart pend)

);for progn

); for if

(pull)

) for progn

) for while

(grdraw pstart pend -1 0)

 (grdraw pend pframe -1 0)

) for defun draw

;;;;主程序

(defun c:os ( / b b1 b2 c pstart pend pframe plast ang2

dist scmd ccoords olderr cosmode )

,; an0 len0 are defined out program

(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)

) for defun os

四、程序的安装与使用

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菜单中的Zoom Window 、Zoom Previous、Zoom All等三个子项实现窗口放缩和Pan菜单实现屏幕漫游; 对于其他操作,用户均可按屏幕命令行的中文提示方便地进行操作。在非汉化AutoCAD 中运行本程序时,只需将程序中有关的中文提示行改成英文提示即可。 另外,由于不同的机型在AutoCAD环境下键盘返回码可能稍有区别,所以要求用户在应用本程序之前对自己的机器键盘返回码按如下方法作一次核实:

在AutoCAD命令状态下输入(grread)并回车,用户此时可按下F2或F3、F4、F5键:

第一步:Command:(grread)回车

第二步:按下F2键

此时,屏幕上回显刚输入的键值,比如对笔者使用的机器(AST PIII+4/66D)回显为:(2 1 36)。

其具体涵义为:第一个数字"2"表示刚才是键盘输入;第二个数字"136"表示本机器的"F2"键的返回码。

按上述步骤依次对FF4、F5键的返回码进行核实,笔者的机器该三键的返回码分别为137、138、139。

如果核实结果与上述结果不符(比如,对某些机型,上述四键的返回码分别为138、139、140、141),则应对程序中的相应语句作如下修改。

在"接受用户输入控制子程序"pull()中的键盘输入部分的下述语句作对应修改:

(cond ((=c1 136)(ant));F2--此处136改为用户的F2键返回码

((=c1 137)(leng);

F3--此处137改为用户的F3键返回码

((=c1 138);

F4--此处138改为用户的F4键返回码

((=c1 139);

F5--此处139改为用户的F5键返回码

最后,需要指出的是:用户自己的菜单文件ACAD.MNU可能增删过菜单项或AutoCAD R13中,会使Zoom Window、Zoom All、Zoom Previous、Pan在菜单中位置发生改变。这样,要求用户在应用本程序之前对自己的菜单项回码按如下方法作一次核实:

在AutoCAD命令状态下输入(grread)并回车,用户此时可点取下拉菜单View下的Zoom子菜单中的Window项,对于笔者的菜单其返回值为:(4 6005)。其具体涵义为:第一个数字"4"表示刚才是下拉菜单输入;第二个数字"6005"表示本菜单的Zoom Window菜单项的返回码。用户可按同样的方法找到菜单项Zoom All、Zoom Previous、Pan的返回码。并相应地改变"接受用户输入控制子程序"pull()中的"点取下拉菜单"部分的下述语句作对应修改:

(cond ((=c1 6005)--此处6005改为用户的Zoom Window菜单项返回码;

((=c1 6007)--此处6007改为用户的Zoom Previous菜单项返回码;

((=c1 6008)--此处6008改为用户的Zoom All菜单项返回码;

((=c1 6011)--此外6011改为用户的Pan菜单项返回码;

五、结语

应用本程序,可在制图过程中很方便地实现某些特定角度和长度的捕捉,简化了操作步骤和击键次数,根据目前的使用情况来看,画线时可提高作图速度4倍以上。至于AutoCAD内部提供的正交和网点捕捉只是本程序当捕捉角度为 90°时的一个特例。

将本程序的画线子模块 draw()中语句行

(command"line" pstart pend "")