biVector forum

Generating a 4x4 Transformation Matrix from PGA3D

I’ve been connecting Ganga into the CAD software that I use. While it has worked marvelously for points and lines, I need to generate 4x4 transformation matrices in order to transform arbitrary geometry.

I remember mention somewhere in the documentation/resources or lecture of being able to generate a 4x4 matrix from PGA3D, but I haven’t been able to locate anything. For example, generating a transform matrix from a rotor.

Does anyone have any tips on how to achieve this using Ganga? I’m using the Python PGA3D from the code generator.


As I understand it, you just have to compute the images of the four basis vectors and concatenate them into the matrix.

I did something comparable some time ago as I was trying to implement a trackball :

I had a sandwich product \mathbf{x}\rightarrow\tilde{R}\mathbf{x}R, so I computed \tilde{R}\mathbf{i}R, \tilde{R}\mathbf{j}R and \tilde{R}\mathbf{k}R.

It should not be difficult anyway, but the case of the fourth vector, the one for the projective dimension, may depend on your representation convention or something.

1 Like

Hi 7Bridges,

The 4x4 point (tri-vectors) transformation matrix associated to the motor M can be constructed as follows :

  var a0=M.s,a1=M.e01,a2=M.e02,a3=M.e03,a4=M.e12,a5=-M.e31,a6=M.e23,a7=M.e0123;
  var _2a0=2*a0, _2a4=2*a4, _2a5=2*a5, a0a0=a0*a0, a4a4=a4*a4, a5a5=a5*a5, 
      a6a6=a6*a6, _2a6=2*a6, _2a0a4=_2a0*a4, _2a0a5=_2a0*a5, _2a0a6=_2a0*a6,
      _2a4a5=_2a4*a5, _2a4a6=_2a4*a6, _2a5a6=_2a5*a6;
  return [(a0a0+a4a4-a5a5-a6a6),(_2a4a5-_2a0a6),      (_2a0a5+_2a4a6),      0,
         (_2a4a5+_2a0a6),      (a0a0-a4a4+a5a5-a6a6),(_2a5a6-_2a0a4),      0,
         (_2a4a6-_2a0a5),      (_2a0a4+_2a5a6),      (a0a0-a4a4-a5a5+a6a6),0,



1 Like

It should be clear from the snippet but maybe worth mentioning that M is expressed in column major form (just in case :slight_smile:).


I finally had a chance to play with this again today and realized that somehow I had completely scrambled the order of the returned array (no idea how I screwed that up so badly). I also flipped the direction of my rotor (which explained the negative angle and some of the stupid changes I made to the transformation matrix).

Your code works perfectly enki. After applying a transpose (as kindly pointed out by ninepoints) I am getting a working transform. Here’s the proper version in Python, thank you all again!

# M[0],  M[5],  M[6],  M[7],  M[8],  M[9],  M[10],  M[15]
# S(1),   e01,   e02,   e03,   e12,   e31,    e23,  e0123
def TransformationMatrix3D(M):
    a0,a1,a2,a3,a4,a5,a6,a7 = M[0],M[5],M[6],M[7],M[9],M[10],M[8],M[15]
    _2a0 = 2 * a0
    _2a4 = 2 * a4
    _2a5 = 2 * a5
    a0a0 = a0 * a0
    a4a4 = a4 * a4
    a5a5 = a5 * a5
    a6a6 = a6 * a6
    _2a6 = 2 * a6
    _2a0a4 = _2a0 * a4
    _2a0a5 = _2a0 * a5
    _2a0a6 = _2a0 * a6
    _2a4a5 = _2a4 * a5
    _2a4a6 = _2a4 * a6
    _2a5a6 = _2a5 * a6
    return [
    (a0a0 + a4a4 - a5a5 - a6a6), (_2a4a5 + _2a0a6), (_2a4a6 - _2a0a5), ((_2a0 * a3) + (_2a4 * a7) - (_2a6 * a2) - (_2a5 * a1)),
    (_2a4a5 - _2a0a6),   (a0a0 - a4a4 + a5a5 - a6a6), (_2a0a4 + _2a5a6), ((_2a4 * a1) - (_2a0 * a2) - (_2a6 * a3) + (_2a5 * a7)),
    (_2a0a5 + _2a4a6),  (_2a5a6 - _2a0a4), (a0a0 - a4a4 - a5a5 + a6a6),((_2a0 * a1) + (_2a4 * a2) + (_2a5 * a3) + (_2a6 * a7)),   
    0, 0, 0, (a0a0 + a4a4 + a5a5 + a6a6)

In case anyone is interested in an SSE version with a modestly annotated derivation, earlier I wrote a motor -> matrix conversion routine here.

1 Like