# Matrix Transformation Functions

I have put together a library of subfunctions enabling the user to transform a VLA-Object or Vertex Point List using a Transformation Matrix.

Transformation Matrices may be used to apply a linear transformation, such as a rotation or translation, to a set of points encoding vertices of an object. Through the use of the Visual LISP vla-transformby function, these transformations may also be applied directly to a supplied VLA-Object.

The subfunctions included below allow the user to supply either a Vertex Point List or VLA-Object as the 'target' of the transformation and the relevant matrix will be applied to manipulate the target in the desired way.

## 2D Transformations

Select all
```;;------------------=={ Scale by Matrix }==-------------------;;
;;                                                            ;;
;;  Scales a VLA-Object or Point List using a                 ;;
;;  Transformation Matrix                                     ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target - VLA-Object or Point List to transform            ;;
;;  p1     - Base Point for Scaling Transformation            ;;
;;  scale  - Scale Factor by which to scale object            ;;
;;------------------------------------------------------------;;

(defun LM:ScaleByMatrix ( target p1 scale / m )

(LM:ApplyMatrixTransformation target
(setq m
(list
(list scale 0. 0.)
(list 0. scale 0.)
(list 0. 0. scale)
)
)
(mapcar '- p1 (mxv m p1))
)
)

;;----------------=={ Translate by Matrix }==-----------------;;
;;                                                            ;;
;;  Translates a VLA-Object or Point List using a             ;;
;;  Transformation Matrix                                     ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target - VLA-Object or Point List to transform            ;;
;;  p1, p2 - Points representing vector by which to translate ;;
;;------------------------------------------------------------;;

(defun LM:TranslateByMatrix ( target p1 p2 )

(LM:ApplyMatrixTransformation target
(list
(list 1. 0. 0.)
(list 0. 1. 0.)
(list 0. 0. 1.)
)
(mapcar '- p2 p1)
)
)

;;------------------=={ Rotate by Matrix }==------------------;;
;;                                                            ;;
;;  Rotates a VLA-Object or Point List using a                ;;
;;  Transformation Matrix                                     ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target - VLA-Object or Point List to transform            ;;
;;  p1     - Base Point for Rotation Transformation           ;;
;;  ang    - Angle through which to rotate object             ;;
;;------------------------------------------------------------;;

(defun LM:RotateByMatrix ( target p1 ang )

(LM:ApplyMatrixTransformation target
(setq m
(list
(list (cos ang) (- (sin ang)) 0.)
(list (sin ang)    (cos ang)  0.)
(list    0.           0.      1.)
)
)
(mapcar '- p1 (mxv m p1))
)
)

;;-----------------=={ Reflect by Matrix }==------------------;;
;;                                                            ;;
;;  Reflects a VLA-Object or Point List using a               ;;
;;  Transformation Matrix                                     ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target - VLA-Object or Point List to transform            ;;
;;  p1, p2 - Points representing vector in which to reflect   ;;
;;------------------------------------------------------------;;

(defun LM:ReflectByMatrix ( target p1 p2 )
(
(lambda ( a / m )
(LM:ApplyMatrixTransformation target
(setq m
(list
(list (cos a)    (sin a)  0.)
(list (sin a) (- (cos a)) 0.)
(list    0.         0.    1.)
)
)
(mapcar '- p1 (mxv m p1))
)
)
(* 2. (angle p1 p2))
)
)

;;-----------=={ Apply Matrix Transformation }==--------------;;
;;                                                            ;;
;;  Transforms a VLA-Object or Point List using a             ;;
;;  Transformation Matrix                                     ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target - VLA-Object or Point List to Transform            ;;
;;  matrix - 3x3 Matrix by which to Transform object          ;;
;;  vector - 3D translation vector                            ;;
;;------------------------------------------------------------;;

(defun LM:ApplyMatrixTransformation ( target matrix vector ) (vl-load-com)
(cond
( (eq 'VLA-OBJECT (type target))

(vla-TransformBy target
(vlax-tMatrix
(append (mapcar '(lambda ( x v ) (append x (list v))) matrix vector)
'((0. 0. 0. 1.))
)
)
)
)
( (listp target)

(mapcar
(function
(lambda ( point ) (mapcar '+ (mxv matrix point) vector))
)
target
)
)
)
)

;; Matrix x Vector - Vladimir Nesterovsky
;; Args: m - nxn matrix, v - vector in R^n

(defun mxv ( m v )
(mapcar '(lambda ( r ) (apply '+ (mapcar '* r v))) m)
)
```

## Test Functions

I have furthermore assembled a complete set of example functions to demonstrate how to call the above subfunctions with the correct arguments and moreover illustrate the effect of applying each transformation.

### Scaling Test Functions

Select all
```(defun c:scaleobject ( / e p s )
(if
(and
(setq e (car (entsel)))
(setq p (getpoint "\nBase Point: "))
(setq s (getdist  "\nScale: " p))
)
(LM:ScaleByMatrix (vlax-ename->vla-object e) (trans p 1 0) s)
)
(princ)
)

(defun c:scalelist ( / e p s )
(if
(and
(setq e (car (entsel)))
(eq "LWPOLYLINE" (cdr (assoc 0 (entget e))))
(setq p (getpoint "\nBase Point: "))
(setq s (getdist  "\nScale: " p))
)
(LWPolyline
(LM:ScaleByMatrix (Vertices e) (trans p 1 0) s) (cdr (assoc 70 (entget e)))
)
)
(princ)
)
```

### Translation Test Functions

Select all
```(defun c:translateobject ( / e p q )
(if
(and
(setq e (car (entsel)))
(setq p (getpoint "\nBase Point: "))
(setq q (getpoint "\nDisplacement: " p))
)
(LM:TranslateByMatrix (vlax-ename->vla-object e) (trans p 1 0) (trans q 1 0))
)
(princ)
)

(defun c:translatelist ( / e p q )
(if
(and
(setq e (car (entsel)))
(eq "LWPOLYLINE" (cdr (assoc 0 (entget e))))
(setq p (getpoint "\nBase Point: "))
(setq q (getpoint "\nDisplacement: " p))
)
(LWPolyline
(LM:TranslateByMatrix (Vertices e) (trans p 1 0) (trans q 1 0)) (cdr (assoc 70 (entget e)))
)
)
(princ)
)
```

### Rotation Test Functions

Select all
```(defun c:rotateobject ( / e p a )
(if
(and
(setq e (car (entsel)))
(setq p (getpoint "\nBase Point: "))
(setq a (getangle "\nRotation: " p))
)
(LM:RotateByMatrix (vlax-ename->vla-object e) (trans p 1 0) a)
)
(princ)
)

(defun c:rotatelist ( / e p a )
(if
(and
(setq e (car (entsel)))
(eq "LWPOLYLINE" (cdr (assoc 0 (entget e))))
(setq p (getpoint "\nBase Point: "))
(setq a (getangle "\nRotation: " p))
)
(LWPolyline
(LM:RotateByMatrix (Vertices e) (trans p 1 0) a) (cdr (assoc 70 (entget e)))
)
)
(princ)
)
```

### Reflection Test Functions

Select all
```(defun c:reflectobject ( / e p q )
(if
(and
(setq e (car (entsel)))
(setq p (getpoint "\nBase Point: "))
(setq q (getpoint "\nSecond Point of Reflection Vector: " p))
)
(LM:ReflectByMatrix (vlax-ename->vla-object e) (trans p 1 0) (trans q 1 0))
)
(princ)
)

(defun c:reflectlist ( / e p q )
(if
(and
(setq e (car (entsel)))
(eq "LWPOLYLINE" (cdr (assoc 0 (entget e))))
(setq p (getpoint "\nBase Point: "))
(setq q (getpoint "\nSecond Point of Reflection Vector: " p))
)
(LWPolyline
(LM:ReflectByMatrix (Vertices e) (trans p 1 0) (trans q 1 0)) (cdr (assoc 70 (entget e)))
)
)
(princ)
)
```

### Test Function Subfunctions

(The above functions require these to run)

Select all
```(defun LWPolyline ( l c )
(entmakex
(append
(list
(cons 0 "LWPOLYLINE")
(cons 100 "AcDbEntity")
(cons 100 "AcDbPolyline")
(cons 90 (length l))
(cons 70 c)
)
(mapcar '(lambda ( p ) (cons 10 p)) l)
)
)
)

(defun Vertices ( e )
(mapcar '(lambda ( x ) (append x (list 0.0)))
(mapcar 'cdr
(vl-remove-if-not '(lambda ( x ) (= 10 (car x))) (entget e))
)
)
)
```

## 3D Transformations

Select all
```;;----------------=={ 3D Rotate by Matrix }==-----------------;;
;;                                                            ;;
;;  Rotates a VLA-Object or Point List about a 3D axis using  ;;
;;  a Transformation matrix.                                  ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target - VLA-Object or Point List to Rotate               ;;
;;  p1,p2  - Two 3D points defining the axis of rotation      ;;
;;  ang    - Rotation Angle                                   ;;
;;------------------------------------------------------------;;

(defun LM:Rotate3D ( target p1 p2 ang / ux uy uz )

(mapcar 'set '(ux uy uz) (setq u (unit (mapcar '- p2 p1))))

(LM:ApplyMatrixTransformation target
(setq m
(m+m
(list
(list (cos ang) 0. 0.)
(list 0. (cos ang) 0.)
(list 0. 0. (cos ang))
)
(m+m
(mxs
(list
(list 0. (- uz) uy)
(list uz 0. (- ux))
(list (- uy) ux 0.)
)
(sin ang)
)
(mxs (mapcar '(lambda ( e ) (vxs u e)) u) (- 1. (cos ang)))
)
)
)
(mapcar '- p1 (mxv m p1))
)
)

;;----------------=={ 3D Reflect by Matrix }==----------------;;
;;                                                            ;;
;;  Reflects a VLA-Object or Point List in a plane using a    ;;
;;  Transformation matrix.                                    ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target   - VLA-Object or Point List to Reflect            ;;
;;  p1,p2,p3 - Three 3D points defining the reflection plane  ;;
;;------------------------------------------------------------;;

(defun LM:Reflect3D ( target p1 p2 p3 / m u ux uy uz )

(mapcar 'set '(ux uy uz) (setq u (unit (v^v (mapcar '- p2 p1) (mapcar '- p3 p1)))))

(LM:ApplyMatrixTransformation target
(setq m
(list
(list (- 1. (* 2. ux ux)) (* -2. uy ux) (* -2. ux uz))
(list (* -2. ux uy) (- 1. (* 2. uy uy)) (* -2. uy uz))
(list (* -2. ux uz) (* -2. uy uz) (- 1. (* 2. uz uz)))
)
)
(mapcar '- p1 (mxv m p1))
)
)

;;-----------=={ Apply Matrix Transformation }==--------------;;
;;                                                            ;;
;;  Transforms a VLA-Object or Point List using a             ;;
;;  Transformation Matrix                                     ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  target - VLA-Object or Point List to Transform            ;;
;;  matrix - 3x3 Matrix by which to Transform object          ;;
;;  vector - 3D translation vector                            ;;
;;------------------------------------------------------------;;

(defun LM:ApplyMatrixTransformation ( target matrix vector ) (vl-load-com)
(cond
( (eq 'VLA-OBJECT (type target))

(vla-TransformBy target
(vlax-tMatrix
(append (mapcar '(lambda ( x v ) (append x (list v))) matrix vector)
'((0. 0. 0. 1.))
)
)
)
)
( (listp target)

(mapcar
(function
(lambda ( point ) (mapcar '+ (mxv matrix point) vector))
)
target
)
)
)
)

;; Matrix x Vector - Vladimir Nesterovsky
;; Args: m - nxn matrix, v - vector in R^n

(defun mxv ( m v )
(mapcar '(lambda ( r ) (apply '+ (mapcar '* r v))) m)
)

;; Matrix x Scalar - Lee Mac
;; Args: m - nxn matrix, n - real scalar

(defun mxs ( m s )
(mapcar '(lambda ( r ) (mapcar '(lambda ( n ) (* n s)) r)) m)
)

;; Matrix + Matrix - Lee Mac
;; Args: m,n - nxn matrices

(defun m+m ( m n )
(mapcar '(lambda ( r s ) (mapcar '+ r s)) m n)
)

;; Vector Norm - Lee Mac
;; Args: v - vector in R^n

(defun norm ( v )
(sqrt (apply '+ (mapcar '* v v)))
)

;; Vector x Scalar - Lee Mac
;; Args: v - vector in R^n, s - real scalar

(defun vxs ( v s )
(mapcar '(lambda ( n ) (* n s)) v)
)

;; Unit Vector - Lee Mac
;; Args: v - vector in R^n

(defun unit ( v )
( (lambda ( n ) (if (equal 0.0 n 1e-14) nil (vxs v (/ 1.0 n)))) (norm v))
)

;; Vector Cross Product - Lee Mac
;; Args: u,v - vectors in R^3

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

## Test Functions

### Rotation Test Functions

Select all
```(defun c:rotateobject ( / e p q a )
(if
(and
(setq e (car (entsel)))
(setq p (getpoint "\nFirst Point of Rotation Axis: "))
(setq q (getpoint p "\nSecond Point of Rotation Axis: "))
(setq a (getangle "\nRotation: " p))
)
(LM:Rotate3D (vlax-ename->vla-object e) (trans p 1 0) (trans q 1 0) a)
)
(princ)
)

(defun c:rotatelist ( / l p q a )
(if
(and
(car (setq l (list (getpoint "\nSpecify First Point: "))))
(progn
(while (car (setq l (cons (getpoint "\nNext Point: ") l))))
(setq p (getpoint "\nFirst Point of Rotation Axis: "))
)
(setq q (getpoint p "\nSecond Point of Rotation Axis: "))
(setq a (getangle "\nRotation: " p))
)
(foreach p
(LM:Rotate3D
(mapcar '(lambda ( x ) (trans x 1 0)) (cdr l))
(trans p 1 0)
(trans q 1 0)
a
)
(entmakex (list (cons 0 "POINT") (cons 10 p)))
)
)
(princ)
)
```

### Reflection Test Functions

Select all
```(defun c:reflectobject ( / e p1 p2 p3 )
(if
(and
(setq e (car (entsel)))
(setq p1 (getpoint "\nFirst Point of Reflection Plane: "))
(setq p2 (getpoint "\nSecond Point of Reflection Plane: " p1))
(setq p3 (getpoint "\nThird Point of Reflection Plane: "  p1))
)
(LM:Reflect3D (vlax-ename->vla-object e) (trans p1 1 0) (trans p2 1 0) (trans p3 1 0))
)
(princ)
)

(defun c:reflectlist ( / l p1 p2 p3 )
(if
(and
(car (setq l (list (getpoint "\nSpecify First Point: "))))
(progn
(while (car (setq l (cons (getpoint "\nNext Point: ") l))))
(setq p1 (getpoint "\nFirst Point of Reflection Plane: "))
)
(setq p2 (getpoint "\nSecond Point of Reflection Plane: " p1))
(setq p3 (getpoint "\nThird Point of Reflection Plane: "  p1))
)
(foreach p
(LM:Reflect3D
(mapcar '(lambda ( x ) (trans x 1 0)) (cdr l))
(trans p1 1 0)
(trans p2 1 0)
(trans p3 1 0)
)
(entmakex (list (cons 0 "POINT") (cons 10 p)))
)
)
(princ)
)
```

textsize