马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
本帖最后由 Highflybird 于 2013-4-16 20:38 编辑
首先我们从国外Gile发表的一篇帖子谈起:
如果对本文不理解的,建议读者打开CAD在三维的UCS下用做一个三维图块来验证作者所说。 原文如下:
Hi,I'm going to try to answer CAB's request* in spite of my very poor English.First let's see about OCS.
Some 2D objects have their coordinates defined in the Object Coordinate System (lwpolyline, blocks, texts and so on ...), more, lwpolylines have an elevation data.For example, in a UCS (green on the picture) wich origin is (1.402 0.347 4.866) in WCS (white on the picture) and rotated around the 3 axis, a block is inserted in (0 0 0) with a rotation of 0.0 (orange).
Now, get the block reference DXF datas :get insertion point : (cdr (assoc 10 (entget ent))) -> (1.444 1.806 4.519) get rotation :
(cdr (assoc 50 (entget ent))) -> 0.39099
We can see insertion point coordinates are neither those in WCS (1.402 0.347 4.866) nor in UCS (0.0 0.0 0.0) and rotation is not 0.Because coordinates are defined in the OCS and rotation about X axis of OCS.The OCS is defined according to the extrusion direction (or Normal) and the Arbitrary Axis Algoriythm (see"Advanced DXF concepts" in the DXF section of the Developper's guide). For a routine to calculate X and Y axis of an OCS according to its Z vector you can see this message.
Let's have a new picture to see more about OCS (red):
So, the origin of all OCS are the same as WCS origin and all objects which have the same extrusion direction (210 DXF code or Normal property) have the same OCS.
To calculate the normal vector of a plane defined by 3 points, you can see Norm_3pts routine here.
Knowing that, it should be easier, I think, to to undrestand the use of the trans function in 3D and have
some helpfull code lines.
Following the example,to get the WCS coordinates of the block reference insertion point, a current way is to use its ename :
(trans (cdr (assoc 10 (entget ent))) ent 0)-> (1.402 0.347 4.866) which is the UCS origin coordinate in WCS.as well to get it in UCS :
(trans (cdr (assoc 10 (entget ent))) ent 1)
returns (4.440e-016 4.440e-016 8.881e-016)
which is very close to (0.0 0.0 0.0)
it's also possible to use the 210 DXF code :
(trans (cdr (assoc 10 (entget ent))) (cdr (assoc 210 (entget ent))) 0)
To create 2D objects on the UCS plane with (entmake ...) or (vla-add ...), another way must be used because ent don't already exists.So we have to calculate the normal vector of the UCS XY plane :
(setq ucszdir (trans '(0 0 1) 1 0 T))
ucszdir can be used as well as ent or (cdr (assoc 210 (entget ent))) in the above trans expressions.In a list to be used with entmake :
(cons 210 ucszdir)
ucszdir is also the Normal property to be used in (vla-put-Normal ...) expressions.
Now it seems to be OK for coordinates, but what's about rotation ?To get the angle between OCS X axis and UCS X axis :
(angle '(0 0 0) (trans (getvar ‘UCSXDIR) 0 ucszdir))
-> 0.39099 as the block rotation DXF data.
To finish, getting lwpolyline's elevation (samething for Z coordinates of block refs, texts ...)
To create a lwpolyline on the UCS plane with entmake or vla-add..., we have to specify its elevation always
using trans and ucszdir :
(caddr (trans '(0 0 0) 1 ucszdir))
-> 4.519 as the Z coordinate of the block insertion point (10 DXF code).
So, I hope this be helpfull and usefull for someones, it was quite difficult for me to explain all this in English, if some of you read French, they can find some more information in these topics : Trans, SCU, SCO et dxf en 3D, SCO et 3D.*Edit : I first wrote "demand", confusing the two meanings.
下面是我的翻译:
嗨,我将尝试回答CAB的请求,尽管我的英语很差。
让我们来看看OCS.
一些平面物体有它们自己的物体坐标系(OCS),譬如轻多段线,块参照,文本等等,另外多段线还有一个标高数据。
举例说:一个UCS(用户坐标系,图中绿色表示)它的原点在WCS(世界坐标系,图中白色表示)的坐标是(1.402 0.347 4.866),并且三个轴被旋转了。在UCS下插入一个图块(图中橙色部分)到点(0 0 0),旋转角度是0.
现在,我们来获取块参照的DXF数据:
得到插入点数据:
(cdr (assoc 10 (entget ent))) -> (1.444 1.806 4.519)
得到旋转角度:
(cdr (assoc 50 (entget ent))) -> 0.39099
我们可以看到插入点坐标既不是 WCS的 (1.402 0.347 4.866),也不是UCS的(0.0 0.0 0.0) ,而且旋转角度也不是0.为什么?
这是因为这些坐标是相对于OCS来说的,旋转角度也是相对OCS的X轴。
OCS是根据拉伸方向(或法线)和任意轴算法(参见CAD帮助:开发者文档—DXF参考—高级DXF议题—任意轴算法章节)来定义的。关于如何用程序对OCS中根据Z方向去计算X轴线和Y轴线,请看这个链接:http://www.theswamp.org/index.php?topic=12887.msg157305#msg157305
让我们来看一副新的图片去了解更多关于OCS(下图红色表示)的知识。
因而,所有的OCS的原点跟WCS的原点是相同的。
并且所有具有相同的拉伸方向(DXF组码的210代码值 或者Normal属性)的物体都具有相同的OCS.
为了计算一个三点确定的平面的法线矢量,你可以用Norm_3pts这个程序,参考下面链接:
http://www.theswamp.org/index.php?topic=11561.0
我认为,如果知道了这些,那去理解trans 函数在三维上的用法,就容易多了,对一些代码也很有用。
下面举例:
去获得块参照的插入点在WCS的坐标,一个通常的作法是用图元名:
(trans (cdr (assoc 10 (entget ent))) ent 0)
-> (1.402 0.347 4.866) ,这点正是UCS的原点在WCS的坐标,也是图块插入点在世界坐标系的坐标。同样我们也可获得插入点在UCS下的坐标:
(trans (cdr (assoc 10 (entget ent))) ent 1)
返回 (4.440e-016 4.440e-016 8.881e-016)很接近(0.0 0.0 0.0)。--译者注:这个是由于运算过程中的浮点误差产生的。它也可以用210 DXF组码来实现:
(trans (cdr (assoc 10 (entget ent))) (cdr (assoc 210 (entget ent))) 0)
用entmake …或者vla-add 在UCS平面上创建一个二维物体,必须要用到另外一个方法,因为这时候实体还不存在。所以我们必须计算UCS XY平面的法线矢量。
(setq ucszdir (trans '(0 0 1) 1 0 T))
在上述trans表达式中,UCSZdir (即UCS 的z方向) 跟ent 或者(cdr (assoc 210 (entget ent)))
一样的用法。--译者注:注意此处的 (trans ….T) 的T 。
(cons 210 ucszdir)
Ucszdir 同样也能通过(vla-put-Normal ...)去赋予一个物体的法线属性。
现在看来我们理解了坐标系统,但如何理解旋转角呢?
获得OCS的X轴线跟UCS X的轴线的夹角:
(angle '(0 0 0) (trans (getvar 'UCSXDIR) 0 ucszdir))-> 0.39099
便是块参照的DXF数据中的旋转角。
为完成它,需要获取轻多段线的标高(类似块参照,文本的Z坐标等)
用entmake 或者vla-add…去创建一个在UCS平面的轻多段线,我们必须为其指定标高,
(caddr (trans '(0 0 0) 1 ucszdir))-> 4.519作为块参照插入点的Z坐标(10 DXF组码)
至此,我希望此贴对你们有所帮助和借鉴。对我来说,用英语解说非常困难,如果你懂法语,你可以在如下链接找到这个主题的更多信息。
*编辑:我最初写的是“要求” 是弄混了这两者的含义。(要求和请求的区别)
--译者注:这两个链接已经失效。实际作者的英语是相当棒,比我强多了。所以本文如有翻译理解错误的请大家指正。
看完了此文,不知读者有何感受。如果你喜欢,请跟我继续深层次地理解CAD的坐标系统和trans的工作原理,以及它的一些有趣的用法。
CAD的坐标系统
CAD的坐标系统是什么,有哪些坐标系统,你如果到网上去搜索,或者百度的话,你将会得到一些错误的解答。
首先我们来看CAD的最常用的坐标系统:
一、世界坐标系 -- 即WCS,trans的代码为0.
世界坐标系即CAD内部处理时使用的三维坐标系 ,它为右手型,如下图所示:
它的定义的原点在左下角,
从计算机屏幕的角度来看,x轴正方向为屏幕从左向右,y轴正方向为屏幕从下向上,z轴正方向为屏幕从里向外。而进行旋转操作时需要指定的角度θ的方向则由右手法则来决定,即右手握拳,大拇指直向某个坐标轴的正方向,那么其余四指指向的方向即为该坐标轴上的θ角的正方向(即θ角增加的方向),在上图中用圆弧形箭头标出。
二、屏幕坐标系是一个二维的坐标系,有下图的两种,但是我们最常用的是左边的那种:原点在屏幕的最左上角,X正方向在是由原点从左至右,Y正方向是从上至下边。
理解这个,有助于你的DCL编程时候的对图像和图像按钮控件的设计。
三、用户坐标系 -- 即UCS,trans的代码为1.
顾名思义,用户是自己定义的坐标系,可以使用以下任意方法和其组合定义用户坐标系:
1. 通过定义新的坐标原点。
2. 三点法得到UCS。
3. 与现有对象或者当前观察方向对齐。
4. 绕当前X轴,Y轴线,或者Z轴或者任意轴旋转得到 UCS。
5. 恢复保存的 UCS。
等等。它也是右手型的坐标系统。设置好UCS后,当你打开了正交时,正交方向也平齐UCS。
如果当下是UCS时,可以通过系统变量UCSXDIR, UCSYDIR, UCSORG分别获得其X方向,Y方向和坐标原点在WCS的位置。
关于如何获得其变换矩阵可以参考我的帖子:
http://bbs.mjtd.com/thread-99926-1-1.html
WORLDUCS 系统变量指示当前UCS是否跟WCS 完全相同。如果为0则不同,否则相同。
四、对象坐标系 –即OCS,trans 的代码是图元名。
上面我已经谈了一些,再抄些来自CAD的开发帮助文件的段落:
要节省图形数据库(和 DXF 文件)的空间,可以按照图元自己的对象坐标系 (OCS) 来表示每个图元的相关点。在 OCS 中,描述图元在三维空间中的位置所需的唯一附加信息是描述 OCS 的 Z 轴和标高值的三维矢量。
对于给定的 Z 轴(或拉伸)方向,有无限个坐标系。这些坐标系是通过在三维空间中转换原点并围绕 Z 轴旋转 X 和 Y 轴而定义的。但对于同一个 Z 轴方向,只有一个 OCS。其特性如下:
1. 它的原点与 WCS 原点重合。
2. XY 平面中的 X 和 Y 轴的方向以任意但一致的方式计算。AutoCAD 使用任意轴算法(参见“任意轴算法”)执行此
计算。
对于某些图元,OCS 等同于 WCS,所有点(DXF 组 10-37)都用世界坐标表示。参见下表。
与图元类型关联的坐标系 | 图元 | 注意 | 三维图元,如直线、点、三维面、三维多段线、三维顶点、三维网格、三维网格顶点 | 这些图元不在特定平面上。所有点都用世界坐标表示。这些图元中,只有直线和点可以拉伸。它们的拉伸方向可以不同于世界 Z 轴 | 二维图元,如圆、圆弧、实面、宽线、文字、属性、属性定义、形、插入、二维多段线、二维顶点、优化多段线、图案填充、图像 | 这些图元本质上是平面。所有点都用对象坐标表示。这些图元可以拉伸。它们的拉伸方向可以不同于世界 Z 轴 | 标注 | 一些标注点用 WCS 表示,一些用 OCS 表示 | 视口 | 用世界坐标表示 | AutoCAD 为给定图元建立 OCS 后,OCS 将按如下方式工作:与图元一起存储的标高值表示沿 Z 轴移动 XY 平面(从 WCS 原点)多少距离可以使其和包含图元的平面重合。用户定义的标高值并不重要。
通过 UCS 输入的任何二维点将转换为相对于 UCS 移动和旋转的 OCS 中相应的二维点。
以下是该过程的几个结果:
1. 获得图元时,不一定会找到所用的 UCS。
2. 在给定的 UCS 中输入图元的 XY 坐标并执行 SAVEAS 后,可能无法识别 DXF 文件中的 XY 坐标。必须知道 AutoCAD 计算 X 和 Y 轴的方法才能使用这些值。
3. 与 DXF 文件的图元和输出一起存储的标高值是 UCS XY 平面和 OCS XY 平面之间 Z 坐标差别和绘制图元时用户指定的标高值总和。
五、显示坐标系 – 即DCS ,trans代码 2.
这个坐标系,是指当前视口的显示坐标系统,它是相当于把世界坐标系或者用户坐标系的投影到屏幕上,譬如,如果我们采用了轴测图观察图形,这时候把世界坐标或者用户坐标投影
到屏幕,我们就需要用到显示坐标系,它是由以下方面决定的:
1、 自观察点和原点与世界坐标系的X的夹角。
2、 自观察点和原点与世界坐标系的XY平面的夹角。
同样,你也可以从我这个帖子http://bbs.mjtd.com/thread-99926-1-1.html里面的关于轴测图的变换矩阵了解到其坐标系统。
坐标系统讲完了,进入下一个话题。
Trans函数的工作原理
Trans函数,对许多人来说,是一个比较难以理解的函数。
一言以蔽之,trans函数,就相当于矩阵变换,它把一个矢量或者一个点从一个坐标系统变换到另外一个坐标系统。
如果阅读了我前面写的,估计现在理解trans函数容易多了。
示例:
在下面的样例中,UCS 绕世界坐标系的 Z 轴旋转 90 度:
(trans '(1.0 2.0 3.0) 0 1) ->(2.0 -1.0 3.0)
意思就是:WCS的坐标(1.0 2.0 3.0),在UCS中是(2.0 -1.0 3.0)
(trans '(1.0 2.0 3.0) 1 0) ->(-2.0 1.0 3.0)
意思就是:UCS 的坐标(1.0 2.0 3.0),在WCS中是(-2.0 1.0 3.0)
剩下的,基本就可以理解了。这个地方要提醒一些新手:因为在UCS下,忘记对点进行转化,而造成最后画出来的图跑得很远。
如何区别点跟矢量,
(trans pt from to [disp])中disp如果存在且不为 nil,则将 pt 作为三维位移而不是三维点看待。这就是他们的区别。
譬如:(trans '(1.0 2.0 3.0) 0 1 T)
则将’(1.0 2.0 3.0)当做一个矢量,即三维位移看待,而不是三维点看待。
一些情况下与不加这个参数,它们的结果是相同的,而一些情况下则是不同的。
至于其它情况:明经通道翻译的那本Autolisp函数参考中trans的翻译说明已经够详细。
如果不懂,请单独提出。
Trans函数中如果第二个参数或者第三个参数是一个三维点或者矢量,该怎么理解其变换呢?例如
(trans ‘(1 2 3) 0 ‘(2 4 3))
将得到怎样的结果?
首先抄上开发帮助中"任意轴算法"的章节:
AutoCAD 内部使用任意轴算法为所有使用对象坐标的图元生成任意但一致的对象坐标系。
假定一个作为坐标系的 Z 轴的单位长度矢量,任意轴算法将为坐标系生成相应的 X 轴。Y 轴可以通过应用右手定则来确定。
可以使用该方法检查给定的 Z 轴(也称为普通矢量)。如果它距离正向或负向世界 Z 轴很近,可以用给定的 Z 轴跨越世界 Y 轴到达任意 X 轴。如果不是很近,可以用给定的 Z 轴跨越世界 Z 轴到达任意 X 轴。所选的边界应该既便于计算又能在不同计算机上使用。为此,可以通过安装一种"方形"环形封口来实现,环形封口的边界是 1/64,是用六位十进制分数和六位二进制分数精确指定的。
算法如下(假定所有矢量都在三维空间中并在世界坐标系中指定):
假定普通矢量为 N。
假定世界 Y 轴为 Wy,它总是位于点 (0,1,0)。
假定世界 Z 轴为 Wz,它总是位于点 (0,0,1)。
现在我们寻找任意 X 和 Y 轴以便与普通 N 匹配。它们将被称为 Ax 和 Ay。N 也可以按如下方式称为 Az(任意 Z 轴):
如果 (abs (Nx) < 1/64) 且 (abs (Ny) < 1/64) 则
Ax = Wy X N (其中"X"是叉积运算符)。
否则,
Ax = Wz X N。
将 Ax 缩放到单位长度。
获得 Ay 矢量的方法如下:
Ay = N X Ax。 将 Ay 缩放到单位长度。
由此可见,如果第二个或者第三个参数传递的是一个点或者矢量,那么CAD统一把这个参数当做一个矢量来看待,就像一个物体的拉伸方向一样。然后通过它的变换矩阵来转化。
下面我将用Gile的程序结合上面的段落来理解这个用法.
;;OCS的变换矩阵,或叫法线矢量的变换矩阵
(defun OcsMatrix (zdir / xdir)
(or (equal 1.0 (distance '(0 0 0) zdir) 1e-8)
(setq zdir (Normalize zdir)) ; 先把矢量单位化。
)
(if (and (< (abs (car zdir)) 0.015625) ; 如果(abs (Nx) < 1/64)
(< (abs (cadr zdir)) 0.015625) ; 且 (abs (Ny) < 1/64)
)
(setq xdir (Normalize (CrossProduct '(0 1 0) zdir))); Ax = Wy X N (叉积)
(setq xdir (Normalize (CrossProduct '(0 0 1) zdir)));否则 Ax = Wz X N。
)
(list xdir (Normalize (CrossProduct zdir xdir)) zdir) ;Y方向满足右手型坐标系统
)
;; CrossProduct;; Returns the cross product (vector) of two vectors
;; Arguments : two vectors
;; 两个矢量的叉积,参数两个矢量,返回值一个矢量.
(defun CrossProduct (v1 v2)
(list
(- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2)))
(- (* (caddr v1) (car v2)) (* (car v1) (caddr v2)))
(- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
)
)
;; Normalize;; Returns the single unit vector
;; Argument : a vector;; 把一个矢量单位化.
(defun Normalize (v)
( (lambda (l)
(if (/= 0 l)
(mapcar (function (lambda (x) (/ x l))) v)
)
)
(distance '(0 0 0) v)
)
)
;; Apply a transformation matrix to a vector by Vladimir Nesterovsky
(defun mxv (m v)
(mapcar (function (lambda (r) (apply '+ (mapcar '* r v)))) m)
)
我们来做下试验:
(mxv (OcsMatrix '(-1 2 1)) '(2 -3 1)) ->(-0.447214 2.37346 -2.85774)
(trans '(2 -3 1) 0 '(-1 2 1))->(-0.447214 2.37346 -2.85774)
可见我们用程序跟trans 函数得到了相同的结果。
这个就是trans函数的工作原理。
下面提及一下trans的一个妙用:
如下图:请求出点Pt (5 2) 到直线A B的距离。A点坐标(1 1),B点坐标(3 5)
(car (trans (mapcar '- '(5 2) '(1 1)) 0 (mapcar '- '(3 5) '(1 1))))
得出结果-3.1305 .负数表明这点在直线方向的下面。
是不是很简单?一句LISP搞定。
如何去理解呢,如果把AB轴方向矢量当成一个物体的法线矢量,那么,PT在这个坐标系统的投影,其X值就是距离。另外注意:此处的变换是三维变换,意味着如果我的坐标换成空间的,一样也能成立,请大家自行实验。
暂且到此,再次说明:如需转载,请标明作者和来源网站。
|