Author Topic: Given a transformation matrix,How do I get its normal ,rotation angle and scale?  (Read 13429 times)

0 Members and 1 Guest are viewing this topic.

highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
Given a tranformation matrix,How do I get its normal ,rotation angle and scale?
for example , this is a transformation matrix, maybe  from  nentsel or other way:
((0.423113 0.901122 0.0946252) (0.0753338 -0.0864765 0.486669) (0.446731 -0.198788 -0.104474) (2002.55 741.736 157.945))

P.S.  maybe it 's a nonuniform matrix,so need to get the  x scalefactor, y scalefactor and z scalefactor.
« Last Edit: January 01, 2012, 09:47:48 PM by HighflyingBird »
I am a bilingualist,Chinese and Chinglish.

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
I would transform cube block positioned with its center at 0,0,0 and aligned to WCS, and see what are results after transformation... Query for block info X, Y, Z scale factors and as well its rotation around new normal vector and position translation vector (4th line of your matrix)...

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
To obtain angle between new vector normal and WCS normal, after transformation use this simple code :

Code: [Select]
(defun c:ang-normals ( / pt1 pt2 pt3 pt4 rad deg degs cmde )
(setq cmde (getvar 'cmdecho))
(setvar 'cmdecho 0)
(command "ucsicon" "off")
(command "ucs" "s" "lastucs")
(command "ucs" "w")
(print)
(setq pt1 '(0.0 0.0 1.0))
(setq pt2 '(0.0 0.0 0.0))
(setq pt3 (cdr (assoc 210 (entget (car (entsel "\nPick object to calculate angle between new vector of normal and WCS normal"))))))
(command "ucs" "3p" pt2 pt1 pt3)
(setq pt4 (trans pt3 0 1))
(setq rad (angle '(0 0) pt4))
(setq deg (cvunit rad "radians" "degrees"))
(setq degs (rtos deg))
(command "ucs" "r" "lastucs")
(command "ucs" "d" "lastucs")
(command "ucsicon" "on")
(print)
(prompt degs)
(setvar 'cmdecho cmde)
(princ)
)

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
Now I've checked, indeed it's non-uniform scale matrix, and it's impossible to do transformation on block vla-object... So try some other method... Here is what I used unsuccessfully :

Code: [Select]
(defun c:t ( / obj 3dmatrix )
(vl-load-com)
(setq obj (vlax-ename->vla-object (car (entsel "\nSelect object for transformation"))))
(vla-transformby obj
  (vlax-tmatrix (setq 3dmatrix
    (list '(0.423113 0.901122 0.0946252 0.0) '(0.0753338 -0.0864765 0.486669 0.0) '(0.446731 -0.198788 -0.104474 0.0) '(0.0 0.0 0.0 1.0)))
  )
)
(prompt "\nTransformation matrix applied to selected object : ")(princ "\n")(princ 3dmatrix)
(princ)
)

M.R.
« Last Edit: January 02, 2012, 03:02:20 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
By measuring vector distances, I obtained scale factors 1.0; 0.5; 0.5 or if you multiply by 2.0 => 2.0; 1.0; 1.0... So X scale factor is 2x larger than Y or Z scale factors... See attached *.dwg...

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
By measuring vector distances, I obtained scale factors 1.0; 0.5; 0.5 or if you multiply by 2.0 => 2.0; 1.0; 1.0... So X scale factor is 2x larger than Y or Z scale factors... See attached *.dwg...

M.R.
Excellent! It's a good way!
I am a bilingualist,Chinese and Chinglish.

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
transposed vectors - XYZ of transformed object
0.42311313 0.90112227 0.09462523
0.15066759 -0.17295294 0.97333784
0.89346212 -0.39757506 -0.20894858

vectors of 3dmatrix - uniform scale (X=1.0 Y=1.0 Z=1.0)
0.42311313 0.15066759 0.89346212
0.90112227 -0.17295294 -0.39757506
0.09462523 0.97333784 -0.20894858

Similar method applied on your 3dmatrix :

3dmatrix
0.42311313 0.90112227 0.09462523
0.07533379 -0.08647647 0.48666892
0.44673106 -0.19878753 -0.10447429

transposed vectors - XYZ
0.42311313 0.07533379 0.44673106
0.90112227 -0.08647647 -0.19878753
0.09462523 0.48666892 -0.10447429

But, because these X,Y,Z are not orthogonal (see my newly attached *.dwg), you probably didn't post data for 3dmatrix, but for X,Y,Z vectors; so
X:Y:Z = 1.0:0.5:0.5

vectors of - XYZ of transformed object
0.42311313 0.90112227 0.09462523
0.07533379 -0.08647647 0.48666892
0.44673106 -0.19878753 -0.10447429

so transposed 3dmatrix should be :
0.42311313 0.07533379 0.44673106
0.90112227 -0.08647647 -0.19878753
0.09462523 0.48666892 -0.10447429

But because matrix is non-uniformly scaled transformation, this also doesn't work :
Code: [Select]
(defun c:t ( / obj 3dmatrix )
(vl-load-com)
(setq obj (vlax-ename->vla-object (car (entsel "\nSelect object for transformation"))))
(vla-transformby obj
  (vlax-tmatrix (setq 3dmatrix
    (list '(0.42311313 0.07533379 0.44673106 0.0) '(0.90112227 -0.08647647 -0.19878753 0.0) '(0.09462523 0.48666892 -0.10447429 0.0) '(0.0 0.0 0.0 1.0)))
  )
)
(prompt "\nTransformation matrix applied to selected object : ")(princ "\n")(princ 3dmatrix)
(princ)
)

M.R.
I hope I explained well...
:)
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
ribarm,thank you very much.
I  learned a lot from your code and files.
I am a bilingualist,Chinese and Chinglish.

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Firstly, note that the matrix returned by nentsel differs from that returned by nentselp (it is the transpose matrix minus the bottom row):

nentselp
Code: [Select]
(
    (a b c x)
    (d e f y)
    (g h j z)
    (0 0 0 1)
)
[ (x y z 1) is the homogeneous translation vector; the last row (0 0 0 1) is merely to create a square matrix ]

nentsel
Code: [Select]
(
    (a d g)
    (b e h)
    (c f j)
    (x y z)
)

In the following, I shall focus on using the matrix returned by the nentselp function, so to convert the nentsel matrix to the nentselp matrix, you can use the following function:

Code: [Select]
(defun nentsel->nentselp ( m )
    (append (apply 'mapcar (cons 'list m)) '((0.0 0.0 0.0 1.0)))
)

We can focus solely on rotations in the WCS plane, since the OCS matrix can be tranformed to WCS using the Object Normal (DXF 210) - I believe we discussed this previously here.

For the WCS nentselp matrix we have:

Code: [Select]
(a b c x)
(d e f y)
(g h j z)
(0 0 0 1)

Here, for the WCS matrix, we have:

Code: [Select]
(a  b  c  x)       (Sx·cosθ  -Sy·sinθ  0   x)
(d  e  f  y)   =   (Sx·sinθ   Sy·cosθ  0   y)
(g  h  j  z)       (    0       0     Sz   z)
(0  0  0  1)       (    0       0      0   1)

Where (Sx Sy Sz) are the respective x,y,z scale factors, θ is the rotation angle about the origin in the WCS plane, and (x y z) is the translation vector.


Now:

Code: [Select]
Sx  =  ±sqrt(a² + d²)
Sy  =  ±sqrt(b² + e²)
Sz  =  j

 θ  =  atan(d/a)

To determine the sign of Sx and Sy we can use the sign of values a and e (since Cosine is an even function and is non-negative in the domain of the ArcTan function).


Using this information, we can construct an AutoLISP function to return a list of: ((Sx Sy Sz) θ (x y z)), given the matrix returned by nentselp (or nentsel converted), transformed relative to WCS:

Code: [Select]
;; Decompose Matrix  -  Lee Mac
;; Decomposes a 4x4 transformation matrix into a list of
;; ((Sx Sy Sz) <angle> (x y z))

(defun LM:Decompose ( mat )   
    (list
        (list
            (* (sign (caar mat))
               (sqrt (+ (* (caar mat) (caar mat)) (* (caadr mat) (caadr mat))))
            )
            (* (sign (cadadr mat))
               (sqrt (+ (* (cadar mat) (cadar mat)) (* (cadadr mat) (cadadr mat))))
            )
            (caddr (caddr mat))
        )
        (atan (caadr mat) (caar mat))
        (mapcar '+ (mapcar 'last mat) '(0 0 0))
    )
)
(defun sign ( a ) (if (minusp a) -1.0 1.0))

An example, for a block with X-Scale = 1.5, Y-Scale = 1.3, Z-Scale = 1.5 and Rotation = pi/6 (30 degs), we have the following matrix returned by nentselp (for some position in ModelSpace):

Code: [Select]
(
    (1.29904 -0.65 0.0 -67.0503)
    (0.75 1.12583 0.0 18.2337)
    (0.0 0.0 1.5 0.0)
    (0.0 0.0 0.0 1.0)
)

Using the above function:

Code: [Select]
(setq m
   '(
        (1.29904 -0.65 0.0 -67.0503)
        (0.75 1.12583 0.0 18.2337)
        (0.0 0.0 1.5 0.0)
        (0.0 0.0 0.0 1.0)
    )
)

_$ (LM:Decompose m)
((1.5 1.3 1.5) 0.523599 (-67.0503 18.2337 0.0))

_$ (/ pi 6)
0.523599

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
Here is my little experiment with transformation matrices. It is using my explanation of X, Y, Z vectors incorporated in matrix and inverse matrix by Lee Mac (thanks Lee for your subfunction)... All that combined with grread function... It has some visual problems, but with fast mouse moving it is less viewable... I designed it for plan view (top view)...

Code: [Select]
(vl-load-com)

;;--------------------=={ Inverse Matrix }==------------------;;
;;                                                            ;;
;;  Implements the Gauss-Jordan Elimination algorithm to      ;;
;;  inverse a non-singular nxn matrix.                        ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments: m - nxn Matrix                                 ;;
;;------------------------------------------------------------;;
;;  Returns:  Matrix inverse, or nil if matrix is singular    ;;
;;------------------------------------------------------------;;

(defun LM:InverseMatrix ( m / _identity _eliminate p r x )

  (defun _identity ( n / i j l m ) (setq i 1)
    (repeat n (setq j 0)
      (repeat n
        (setq l (cons (if (= i (setq j (1+ j))) 1. 0.) l))
      )
      (setq m (cons (reverse l) m) l nil i (1+ i))
    ) (reverse m)
  )

  (defun _eliminate ( m p )
    (mapcar
      (function
        (lambda ( x / d )
          (setq d (car x)) (mapcar (function (lambda ( a b ) (- a (* d b)))) (cdr x) p)
        )
      )
      m
    )
  )

  (setq m (mapcar 'append m (_identity (length m))))
  (while m
    (setq p (apply 'max (mapcar 'abs (mapcar 'car m))))
    (while (not (equal p (abs (caar m)) 1e-14))
      (setq m (append (cdr m) (list (car m))))
    )
    (if (equal 0.0 (caar m) 1e-14)
      (setq m nil)
      (setq p (/ 1. (caar m))
            p (mapcar (function (lambda ( x ) (* p x))) (cdar m))
            m (_eliminate (cdr m) p)
            r (cons p (_eliminate r p))
      )
    )
  )
  (reverse r)
)

(defun v^v ( u v )
  (list
    (- (* (cadr u) (caddr v)) (* (cadr v) (caddr u)))
    (- (* (car  v) (caddr u)) (* (car  u) (caddr v)))
    (- (* (car  u) (cadr  v)) (* (car  v) (cadr  u)))
  )
)

(defun unit ( v / dv )
  (setq dv (distance '(0.0 0.0 0.0) v))
  (mapcar '(lambda ( x ) (/ x dv)) v)
)

(defun c:objpreview ( / A D GR LOOP MATRIX MATRIXI OBJ PT RM VS VSMAXR VSMINR XDIR YDIR YDIRXY YDIRZ ZDIR )
  (setq obj (vlax-ename->vla-object (car (entsel "\nPick object to preview"))))
  (setq rm (getvar 'regenmode))
  (setvar 'regenmode 0)
  (setq vs (getvar 'viewsize))
  (setq vsmaxr (/ vs 2.0))
  (setq vsminr (/ vs 4.0))
  (setq loop T)
  (prompt "\nLeft click with mouse to exit")
  (while loop
    (setq gr (grread T 15 0))
    (setq pt (cadr gr))
    (setq d (distance '(0.0 0.0 0.0) pt))
    (if (<= vsminr d vsmaxr) (setq a (/ (* PI 2.0) (/ (- vsmaxr vsminr) (- vsmaxr d)))) (setq a 0.0))
    (setq xdir (unit pt))
    (setq ydirxy (polar '(0.0 0.0 0.0) (+ (angle '(0.0 0.0 0.0) pt) (/ PI 2.0)) (cos a)))
    (setq ydirz (sin a))
    (setq ydir (list (car ydirxy) (cadr ydirxy) ydirz))
    (setq zdir (unit (v^v xdir ydir)))
    (setq matrix (list (list (car xdir) (car ydir) (car zdir) 0.0) (list (cadr xdir) (cadr ydir) (cadr zdir) 0.0) (list (caddr xdir) (caddr ydir) (caddr zdir) 0.0) '(0.0 0.0 0.0 1.0)))
    (setq matrixi (LM:InverseMatrix matrix))
    (cond
    ((vla-transformby obj (vlax-tmatrix matrix))) ((progn (vla-put-visible obj -1) (vla-update obj)))
    ((vla-transformby obj (vlax-tmatrix matrixi))) ((progn (vla-put-visible obj 0) (vla-update obj)))
    )
    (if (eq (car gr) 3)
      (progn
        (vla-put-visible obj -1)
        (setq loop nil)
      )
    )
  )
  (setvar 'regenmode rm)
  (princ)
)

M.R. (Thanks once again Lee)
« Last Edit: September 24, 2021, 10:36:25 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

Jeff H

  • Needs a day job
  • Posts: 6150
Have you looked at the ArxDocs?
 
The attached PDF is only a portion of information given.
 

highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
Code: [Select]
Sx  =  ±sqrt(a² + d²)
Sy  =  ±sqrt(b² + e²)
Sz  =  j

 θ  =  atan(d/a)

Lee,you are a genius!This is exactly what I wanted.
For  most of 2d operations, it's enough.
Thank you very much.
I am a bilingualist,Chinese and Chinglish.

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Lee,you are a genius!This is exactly what I wanted.
For  most of 2d operations, it's enough.
Thank you very much.

Many thanks HighflyingBird, I enjoyed constructing the solution  :-)

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
Does anyone know how to improve my above posted code... It seems that after (vla-update obj), object is always shown even if previously was set (redraw objename 2)...  :-(

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3274
  • Marko Ribar, architect
I did what I could... Used (vla-put-visible obj 0) to turn it off and (vla-put-visible obj -1) to turn it on. Now it works better than with (redraw) variant... This is what I wanted. Updated code above...

Regards,
M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube