# Relative Rotation Calculations (Cardinal)

I am trying to build a rotation calculation that is relative to the plane the object exist in. In my situation I can consider all objects to be independent rigid bodies. To further simplify my issues for this scenario all rotations are locked to the cardinal directions, i.e. all angles are locked to multiples of 90°.

For my system currently I am representing my rotation in 3 parts [Rx,Ry,Rz], where R? is rotation on the X,Y and Z directions respectively.

Currently for objects who sit on the absolute plane, i.e. they have a rotation of [0,0,0], I rotate the objects by just adding or subtracting 90° to the plane I want to move them. Although I fear this may be an oversimplification.

For objects not sitting on the absolute plane, i.e. they do not have a rotation of [0,0,0], I am having an issue to calculate the rotation relative to the plane it is in. So if we take an object with the initial rotation of [0,90,0] and I wanted to rotate it [90,0,0] relative to itself I know this has the end result of rotating it by [0,0,90]. Although this is the step I am stuck with transforming the relative values to absolute ones so that I can calculate them.

I am assuming some sort of matrix calculations would be involved although through my research I cannot find any examples that is simplistic enough to follow. Also I cannot shake the feeling that since I am locked to the cardinal directions there should be a way to reduce and simplify the problem.

Please could you either point me in the right starting point or suggest the names of methods I could look into?

• I would suggest using matrix algebra to calculate the rotations. Euler angles are quite widely used, but you can also use just Direction Cosine Matrices. – Matti P. Jun 7 '18 at 13:01
• @MattiP. Would you happen to know a good link to teach the ideas at a fairly basic level, as most of the ones I can find are a bit more intermediate? – user898421 Jun 7 '18 at 13:14

See http://answers.google.com/answers/threadview/id/361441.html and also http://paulbourke.net/geometry/rotate/ as good starting points. (Bourke has lots of other good stuff, too.) Is this for programming (isn't it always:)? I used the above two pages (and several others, but the preceding contain all necessary info) to write the following C functions, based on quaternions,

/* ---
* Point and line datatype structs
* ---------------------------------- */
#define POINT struct point_struct       /* "typedef" for point_struct*/
#define LINE struct line_struct         /* "typedef" for line_struct*/
#define QUAT struct quaternion_struct   /* "typedef" for quaternion_struct */
POINT   { double x, y, z; } ;           /* 3d pts, 2d uses x,y components */
LINE    { POINT pt1, pt2; } ;           /* for vectors, pt1=tail, pt2=head */
QUAT    { double q0, q1, q2, q3; } ;    /* quat = q0 + q1*i + q2*j + q3*k */

/* ==========================================================================
* Function:    qrotate ( LINE axis, double theta )
* Purpose:     returns quaternion corresponding to rotation
*              through theta (**in radians**) around axis
* --------------------------------------------------------------------------
* Arguments:   axis (I)        LINE axis around which rotation by theta
*                              is to occur
*              theta (I)       double theta rotation **in radians**
* --------------------------------------------------------------------------
* Returns:     ( QUAT )        quaternion corresponding to rotation
*                              through theta around axis
* --------------------------------------------------------------------------
* Notes:     o Rotation direction determined by right-hand screw rule
*              (when subsequent qmultiply() is called with istranspose=0)
* ======================================================================= */
/* --- entry point --- */
QUAT    qrotate ( LINE axis, double theta ) {
/* --- allocations and declarations --- */
QUAT   q = { cos(0.5*theta), 0.,0.,0. } ; /* constructed quaternion */
double x = axis.pt2.x - axis.pt1.x,    /* length of x-component of axis */
y = axis.pt2.y - axis.pt1.y,    /* length of y-component of axis */
z = axis.pt2.z - axis.pt1.z;    /* length of z-component of axis */
double r = sqrt((x*x)+(y*y)+(z*z));    /* length of axis */
double qsin = sin(0.5*theta);          /* for q1,q2,q3 components */
/* --- construct quaternion and return it to caller */
if ( r >= 0.0000001 ) {                /* error check */
q.q1 = qsin*x/r;                     /* i-component */
q.q2 = qsin*y/r;                     /* j-component */
q.q3 = qsin*z/r; }                   /* k-component */
return ( q );
} /* --- end-of-function qrotate() --- */

/* ==========================================================================
* Function:    qmatrix ( QUAT q )
* Purpose:     returns 3x3 rotation matrix corresponding to quaternion q
*              ( can just be called as qmatrix(qrotate(axis,theta))
*                for rotation matrix around axis through theta )
* --------------------------------------------------------------------------
* Arguments:   q (I)           QUAT q for which a rotation matrix
*                              is to be constructed
* --------------------------------------------------------------------------
* Returns:     ( double * )    3x3 rotation matrix, stored row-wise
* --------------------------------------------------------------------------
* Notes:     o The matrix constructed from input q = q0+q1*i+q2*j+q3*k is:
*                    (q0²+q1²-q2²-q3²)    2(q1q2-q0q3)     2(q1q3+q0q2)
*                Q  =   2(q2q1+q0q3)   (q0²-q1²+q2²-q3²)   2(q2q3-q0q1)
*                       2(q3q1-q0q2)      2(q3q2+q0q1)  (q0²-q1²-q2²+q3²)
*            o The returned matrix is stored row-wise, i.e., explicitly
*                --------- first row ----------
*                qmatrix[0] = (q0²+q1²-q2²-q3²)
*                       [1] =    2(q1q2-q0q3)
*                       [2] =    2(q1q3+q0q2)
*                --------- second row ---------
*                       [3] =    2(q2q1+q0q3)
*                       [4] = (q0²-q1²+q2²-q3²)
*                       [5] =    2(q2q3-q0q1)
*                --------- third row ----------
*                       [6] =    2(q3q1-q0q2)
*                       [7] =    2(q3q2+q0q1)
*                       [8] = (q0²-q1²-q2²+q3²)
*            o qmatrix maintains a static buffer of 128 3x3 matrices
*              returned to the caller one at a time. So you may issue
*              128 qmatrix() calls and continue using all returned matrices.
*              The 129th call re-uses the memory used by the 1st call, etc.
* ======================================================================= */
/* --- entry point --- */
double  *qmatrix ( QUAT q ) {
/* --- allocations and declarations --- */
static double Qbuff[128][9];           /* up to 128 calls before wrap-around*/
static int    ibuff = (-1);            /* Qbuff[ibuff][] index 0<=ibuff<=63*/
double *Q = NULL;                      /* returned ptr Q=Qbuff[ibuff] */
double q0=q.q0, q1=q.q1, q2=q.q2, q3=q.q3; /* input quaternion components */
double q02=q0*q0, q12=q1*q1, q22=q2*q2, q32=q3*q3; /* components squared */
/* --- first maintain Qbuff[ibuff][] buffer --- */
if ( ++ibuff > 127 ) ibuff=0;          /* wrap Qbuff[ibuff][] index */
Q = Qbuff[ibuff];                      /* ptr to current 3x3 buffer */
/* --- just do the algebra described in the above comments --- */
Q[0] = (q02+q12-q22-q32);
Q[1] =  2.*(q1*q2-q0*q3);
Q[2] =  2.*(q1*q3+q0*q2);
Q[3] =  2.*(q2*q1+q0*q3);
Q[4] = (q02-q12+q22-q32);
Q[5] =  2.*(q2*q3-q0*q1);
Q[6] =  2.*(q3*q1-q0*q2);
Q[7] =  2.*(q3*q2+q0*q1);
Q[8] = (q02-q12-q22+q32);
/* --- return constructed quaternion to caller */
return ( Q );
} /* --- end-of-function qmatrix() --- */

/* ==========================================================================
* Function:    qmultiply ( double *Q, POINT u, int istranspose )
* Purpose:     returns Q*u (u a column vector) if istranspose=0,
*                   or u*Q (u a row vector)    if istranspose=1.
* --------------------------------------------------------------------------
* Arguments:   Q (I)           double *Q to rotation matrix returned
*                              by qmatrix (or by some similar construction)
*              u (I)           POINT u to column vector (or to row vector
*                              if istranspose=1) to be multiplied by Q
*                              (or to multiply Q if istranspose=1)
*              istranspose (I) int istranspose=0 to return Q*u (u a col vec),
*                              or  istranspose=1 to return u*Q (u a row vec)
* --------------------------------------------------------------------------
* Returns:     ( POINT )       Q*u (istranspose=0), or u*Q (istranspose=1)
* --------------------------------------------------------------------------
* Notes:     o Q assumed to be a 3x3 matrix stored row-wise
* ======================================================================= */
/* --- entry point --- */
POINT   qmultiply ( double *Q, POINT u, int istranspose ) {
/* --- allocations and declarations --- */
POINT  Qu = { 0.,0.,0. };              /* Q*u (or u*Q if istranspose=1) */
double x=u.x, y=u.y, z=u.z;            /* x(i),y(j),z(k)-components of u */
/* --- Q*u --- */
if ( !istranspose ) {
Qu.x = Q[0]*x + Q[1]*y + Q[2]*z;     /*  first row of Q * column vector u*/
Qu.y = Q[3]*x + Q[4]*y + Q[5]*z;     /* second row of Q * column vector u*/
Qu.z = Q[6]*x + Q[7]*y + Q[8]*z;     /*  third row of Q * column vector u*/
} /* --- end-of-if(!istranspose) --- */
/* --- u*Q --- */
if ( istranspose ) {
Qu.x = x*Q[0] + y*Q[3] + z*Q[6];     /* row vector u *  first column of Q*/
Qu.y = x*Q[1] + y*Q[4] + z*Q[7];     /* row vector u * second column of Q*/
Qu.z = x*Q[2] + y*Q[5] + z*Q[8];     /* row vector u *  third column of Q*/
} /* --- end-of-if(istranspose) --- */
/* --- return product to caller --- */
return ( Qu );
} /* --- end-of-function qmultiply() --- */

• Thanks for the above. I will be honest with you and say that for the complexity I will need to put this on hold and use a part of a plugin that I will hope to demise later. Although I would be looking to pick this up later and try to find a simplified method for the 90 Degree locked angles. Many thanks! Although if you have any suggestions of where to go with the simplified method I would appreciate them! – user898421 Jun 7 '18 at 14:45
• @user898421 If you just want to rotate about a coordinate axis, the very simple matrices given by en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations should do the trick, with $\theta=90^o$ even simpler. But if you're rotating about some arbitrary axis, then the simplification to $90^o$ won't really simplify the problem all that much. So I'd either use the simple wikipedia matrices if they're adequate for your purposes, or the completely general solution, which maybe you'll need for some future purpose, anyway (e.g., I used them for math.stackexchange.com/questions/2800146 ) – John Forkosh Jun 8 '18 at 3:21