本帖最后由 caoyin 于 2025-12-11 19:27 编辑
话题引自网友 xiaocainiao 的帖子,高手请绕行
http://bbs.mjtd.com/forum.php?mo ... 4232&extra=page%3D1
简单描述:
圆是块A的子图元,块A是块B的子图元,
块参照B是当前空间的对象,要求获取块参照A的插入点的UCS坐标并转换到当前空间。
为了把问题说清楚,我把上面的应用场景再稍加复杂化
圆是 块定义A的子图元, 块参照A是 块定义B的子图元, 块参照B是 块定义C的子图元
块参照C是当前空间的对象,要求获取 块参照A的插入点的 UCS坐标并转换到 当前空间坐标系。
1.nentselp函数可以获取最底层的对象。
(setq sel (nentselp "\n选择圆(多重套嵌块的子图元):"))
返回的四个元素:
1).圆的图元名
2).拾取点UCS
3).最底层对象变换到当前空间的4*4变换矩阵
4).父系块图元名列表( 块参照C图元名 块参照B图元名 块参照A图元名)
2.如果我们想把圆心的坐标转换到当前空间,使用nentselp返回的变换矩阵就可以了,因为圆心是最底层对象
3.我们现在要获得的 块参照A的的插入点,并转换到 当前空间坐标系,而 块参照A不是最底层的对象,因此nentselp提供的变换矩阵不配套。
4.获得变换矩阵:
(1)获得 块参照A到 块定义A的逆变换矩阵。
我们直接使用gile大神的 RevRefGeom 函数得到3*4变换矩阵(3*3矩阵+位移向量):
(setq mat1 (RevRefGeom (last (last sel))))
(2) 获得最底层对象变换到当前空间的4*4变换矩阵,
(setq mat2 (caddr sel));;此变换矩阵等价于gile大神的 RefGeom 函数(格式不同)
5.变换矩阵格式的处理
我们可以两次进行矩阵变换,也可以将矩阵合并进行一次变换。
但从第四步可以看出mat1是3*4变换矩阵,mat2是 AutoCAD标注格式的变换矩阵。
我们可以把mat1为4*4变换矩阵,或者把mat2转换成3*4变换矩阵
由于AutoCAD针对图形对象的矩阵变换使用的是4*4格式,我们遵循这个惯例把3*4矩阵转换为4*4矩阵。
(setq mat1 (apply 'LT:Tmatrix-3x4->4x4 mat1))
LT:Tmatrix-3x4->4x4是我自用函数,在后面分享
引用大神的矩阵相乘函数MxM,合并矩阵,得到我们最终需要的变换矩阵
(MxM mat1 mat2)
这里做一个总结,无论块的套嵌级别有多深,我们不需要获取每一层套嵌块的变换矩阵,因此上文的 块参照B可以不参与计算(计算已经在ACAD内部完成) 以上是为了把问题说明白,更直接的方法见三楼(无需两次使用矩阵) 6.全部转换过程
(defun C:TT (/ sel enx)
(setq sel (nentselp "\n选择圆(多重套嵌块的子图元): ")
enx (entget (last (last sel)))
)
;; M4xP函数是我自用的应用4*4矩阵变换函数,在后面分享
(M4xP
;;把块参照A的OCS插入点转换为UCS点(原帖帖主的要求,改成0即是WCS点)
(trans (cdr (assoc 10 enx)) (cdr (assoc 210 enx)) 1) ;;把两个变换矩阵合并
(MxM (apply 'LT:Tmatrix-3x4->4x4 (RevRefGeom (last (last sel))))
(caddr sel)
)
)
)
7.矩阵变换的相关配套函数
;;;先分享几个我自用的函数---------------------------------------------------
;; [功能] 将点应用3*3变换矩阵到向量(点的3x3仿射变换)
(defun M3xP (P M V) (mapcar '+ (MxV M P) V))
;; [功能] 将点应用4*4变换矩阵(点的4x4齐次变换)
;; 注意:以下函数返回的矩阵格式不同:
;; nentselp 返回的矩阵: 直接使用 (M4xP P Mat)
;; nentsel 返回的矩阵: 需要转置 (M4xP P (TRP Mat))
;; nentsel函数帮助说明:
;; nentsel是唯一一个使用这种类型矩阵的 AutoLISP 函数。(非标准的ACAD4*4矩阵格式)
(defun M4xP (P M / W)
(setq P (MxV M (append P '(1.0)))
W (last P)
)
(if (equal W 0.0 1E-10)
(setq W 1.0)
)
(mapcar '/ P (list W W W))
)
;; [功能] 将点按照指定的矩阵变换
;; [参数] PT - 点
;; MAT - 3x3矩阵或4x4矩阵
;; VET - 向量。该参数为真,MAT被认为是3x3矩阵;为nil,MAT则被认为是4x4矩阵。
(defun LT:PointTransformBy (P MAT VEC)
(if VEC
(M3xP P MAT VEC)
(M4xP P MAT)
)
)
;; [功能] 将3x4矩阵(3x3矩阵+向量)转换为4x4矩阵
;; (LT:Tmatrix-3x4->4x4 '( (1 0 0) (0 1 0) (0 0 1) (0 0 0)) nil)
;; (LT:Tmatrix-3x4->4x4 '(((1 0 0) (0 1 0) (0 0 1)) (0 0 0)) nil)
;; (LT:Tmatrix-3x4->4x4 '( (1 0 0) (0 1 0) (0 0 1)) '(0 0 0))
(defun LT:Tmatrix-3x4->4x4 (M V)
(cond
(V)
((setq V (last M))
(if (= (length M) 2)
(setq M (car M))
)
)
)
(append (mapcar '(lambda (A B) (append A (list B))) M V)
'((0.0 0.0 0.0 1.0))
)
)
;;;各路大神的的函数---------------------------------------------------
;; [功能] 向量点积
(defun VxV (V1 V2) (apply '+ (mapcar '* V1 V2)))
;; [功能] 向量数乘(向量x标量)
(defun VxS (V S) (mapcar '(lambda (N) (* N S)) V))
;; [功能] 应用变换矩阵到向量 --- Vladimir Nesterovsky
(defun MxV (M V) (mapcar '(lambda (R) (VxV R V)) M))
;; [功能] 矩阵相乘 --- Vladimir Nesterovsky
;; 在两个参数顺序不能错,顺序错了,结果也错了
(defun MxM (M Q) (mapcar (function (lambda (R) (MxV (TRP Q) R))) M))
;; [功能] 矩阵转置 --- Doug Wilson
(defun TRP (M) (apply 'mapcar (cons 'LIST M)))
;; [功能] 创建一个多维初始矩阵
;; [参数] N --- 矩阵维数
;; Identity Matrix - Lee Mac
;; Args: n - matrix dimension
(defun IMat (N / I J L M)
(repeat (setq I N)
(repeat (setq J N) (setq L (cons (if (= I J) 1.0 0.0) l) J (1- J)))
(setq M (cons L M) L nil I (1- I))
)
M
)
;; [功能] 返回矩阵的逆向矩阵
;; 使用高斯-若尔当消元法返回非奇异(可逆) nxn 矩阵的逆矩阵。
;; Matrix Inverse - gile & Lee Mac
;; Uses Gauss-Jordan Elimination to return the inverse of a non-singular nxn matrix.
;; Args: m - nxn matrix
(defun InvM (M / F C P R)
(defun F (P M)
(mapcar '(lambda (X) (mapcar '(lambda (A B) (- A (* (car X) B))) (cdr X) P)) M)
)
(setq M (mapcar 'append M (IMat (length M))))
(while M
(setq C (mapcar '(lambda (X) (abs (car X))) M))
(repeat (vl-position (apply 'MAX C) C)
(setq M (append (cdr M) (list (caR M))))
)
(if (equal 0. (caar M) 1E-14)
(setq M nil R nil)
(setq P (mapcar '(lambda ( x ) (/ (float X) (caar M))) (cdar M))
M (F P (cdr M))
R (cons P (F P R))
)
)
)
(reverse R)
)
;; [功能] 获取块定义到块参照的变换矩阵
;; RefGeom (gile)
;; Returns a list whose first item is a 3x3 transformation matrix and
;; second item the object insertion point in its parent (xref, block or space)
(defun RefGeom (ent / ang enx mat ocs)
(setq enx (entget ent)
ang (cdr (assoc 050 enx))
ocs (cdr (assoc 210 enx))
)
(list (setq mat (MxM (mapcar '(lambda (v) (trans v 0 ocs T))
'((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))
)
(MxM (list (list (cos ang) (- (sin ang)) 0.0)
(list (sin ang) (cos ang) 0.0)
'(0.0 0.0 1.0)
)
(list (list (cdr (assoc 41 enx)) 0.0 0.0)
(list 0.0 (cdr (assoc 42 enx)) 0.0)
(list 0.0 0.0 (cdr (assoc 43 enx)))
)
)
)
)
(mapcar '- (trans (cdr (assoc 10 enx)) ocs 0)
(MxV mat (cdr (assoc 10 (tblsearch "BLOCK" (cdr (assoc 2 enx))))))
)
)
)
;; [功能] 获取块参照到块定义的变换矩阵
;; RevRefGeom (gile)
;; The inverse of RefGeom
(defun RevRefGeom (ent / ang enx mat ocs)
(setq enx (entget ent)
ang (cdr (assoc 050 enx))
ocs (cdr (assoc 210 enx))
)
(list (setq mat (MxM (list (list (/ 1.0 (cdr (assoc 41 enx))) 0.0 0.0)
(list 0.0 (/ 1.0 (cdr (assoc 42 enx))) 0.0)
(list 0.0 0.0 (/ 1.0 (cdr (assoc 43 enx))))
)
(MxM (list (list (cos ang) (sin ang) 0.0)
(list (- (sin ang)) (cos ang) 0.0)
'(0.0 0.0 1.0)
)
(mapcar '(lambda (v) (trans v ocs 0 T))
'((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))
)
)
)
)
(mapcar '- (cdr (assoc 10 (tblsearch "BLOCK" (cdr (assoc 2 enx)))))
(MxV mat (trans (cdr (assoc 10 enx)) ocs 0))
)
)
)
|