home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-03-27 | 9.0 KB | 268 lines | [TEXT/KAHL] |
- //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- //| Rotations.cp
- //|
- //| This file contains code which implements n-dimensional rotations
- //|____________________________________________________________________________
-
-
- #include <math.h>
-
- //========================== Prototypes ============================\\
-
- double **CreateRotMatrix(long dim, double *angles);
- void BuildRotMatrix(long dim, double *angles, double **matrix_handle);
- void UpdateRotMatrix(long i, double old_value, double new_value, long dim,
- double **matrix_handle);
- void RotateVector(double *vector, double *rotated_vector, long dim, double *matrix);
-
-
- //============================= Constants ==============================\\
-
- #define Pi 3.14159265358979323846
-
-
- //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- //| Procedure CreateRotMatrix
- //|
- //| Purpose: this procedure creates an dim-dimensional rotation matrix
- //|
- //| Parameters: dim: the dimension of this rotation
- //| angles: a matrix containing the angles
- //| returns a handle to the rotation matrix
- //|__________________________________________________________________
-
- double **CreateRotMatrix(long dim, double *angles)
- {
-
- double **matrix_handle =
- (double **) NewHandleClear(sizeof(double)*dim*dim); // Allocate space for matrix
-
- BuildRotMatrix(dim, angles, matrix_handle);
-
- return matrix_handle; // return the matrix
-
- } //==== CreateRotMatrix() ====\\
-
-
-
- //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- //| Procedure BuildRotMatrix
- //|
- //| Purpose: this procedure fills in a dim-dimensional rotation matrix
- //|
- //| Parameters: dim: the dimension of this rotation
- //| angles: a matrix containing the angles
- //| matrix_handle: handle to the matrix to fill in
- //|__________________________________________________________________
-
- void BuildRotMatrix(long dim, double *angles, double **matrix_handle)
- {
-
- //
- // Here is the algorithm used to build the matrix from scratch. This algorith was
- // derived by examining correct rotation matrices up to size 7x7 (as derived by
- // Mathematica) and looking for patterns. The patterns were very obvious, but since
- // the analysis was not mathematical, this algorithm has not yet been formally PROVEN.
- // See Mathematica notebook RotMatrix Derivation.
- //
- // M[i,j] is the (i,j)th element of the rotation matrix, and rows and columns both
- // start at 0. s[i] and c[i] are the ith
- // element of the sines and cosines matrices, respectively. s[0] is defined to be 1.0
- // (important for proper execution of step 5).
- //
- // 1. prod = 1; loop c from dim-1 to 1 step -1 { M[0,c] = -prod*s[c-1]; prod *= c[c-1]; }
- // 2. M[0, 0] = prod;
- // 3. loop r from 1 to dim-1 { M[r, r] = c[r-1] }
- // 4. loop r from 1 to dim-2 { loop c from r+1 to dim-1 { M[r, c] = 0 } }
- // 5. loop c from 0 to dim-2 { if (c==0) then prod = 1 else prod = -s[c-1];
- // loop r from c+1 to dim-1 { M[r, c] = prod*s[r-1]; prod *= c[r-1] } }
- //
- // The matrix below is a sample 7x7 rotation matrix. The entries indicate which element
- // is generated by which step of the above algorithm. For instance, element (0,0) is 2,
- // indicating that the element in the 0th row and 0th column is generated by step 2 of
- // the algorithm.
- //
- // column = 0 column = dim-1
- // | |
- //
- // [ 2 1 1 1 1 1 1 ] row = 0
- // [ 5 3 4 4 4 4 4 ]
- // [ 5 5 3 4 4 4 4 ]
- // [ 5 5 5 3 4 4 4 ]
- // [ 5 5 5 5 3 4 4 ]
- // [ 5 5 5 5 5 3 4 ]
- // [ 5 5 5 5 5 0 3 ] row = dim-1
- //
-
- #define M(I, J) *((*matrix_handle) + (I)*dim + (J))
- #define ANGLE_OFFSET Pi/2000
-
- double prod = 1.0;
- long r, c;
- for (c = dim-1; c >= 1; c--) // STEP 1
- {
- M(0, c) = -prod*sin(angles[c-1] + ANGLE_OFFSET);
- prod *= cos(angles[c-1] + ANGLE_OFFSET);
- }
-
- M(0, 0) = prod; // STEP 2
-
- for (r = 1; r <= dim-1; r++) // STEP 3
- M(r, r) = cos(angles[r-1] + ANGLE_OFFSET);
-
- for (r = 1; r <= dim-2; r++) // STEP 4
- for (c = r+1; c <= dim-1; c++)
- M(r, c) = 0;
-
- for (c = 0; c <= dim-2; c++) // STEP 5
- {
- if (c == 0)
- prod = 1.0;
- else
- prod = -sin(angles[c-1] + ANGLE_OFFSET);
- for (r = c+1; r<= dim-1; r++)
- {
- M(r, c) = prod * sin(angles[r-1] + ANGLE_OFFSET);
- prod *= cos(angles[r-1] + ANGLE_OFFSET);
- }
- }
-
- } //==== BuildRotMatrix() ====\\
-
-
-
- //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- //| Procedure UpdateRotMatrix
- //|
- //| Purpose: this procedure updates the rotation matrix when one of the
- //| rotation angles has changed. Only those elements of the
- //| matrix which depend on that angle are updated.
- //|
- //| Parameters: i: the number of the angle which has changed
- //| old_value: the previous value of the angle
- //| new_value: the new value of the angle
- //| matrix_handle: handle to the matrix
- //|____________________________________________________________________
-
- void UpdateRotMatrix(long i, double old_value, double new_value, long dim,
- double **matrix_handle)
- {
-
- //
- // Here is the algorithm used to update the matrix after one angle had changed.
- // This algorith was derived by examining correct rotation matrices up to size 7x7
- // (as derived by Mathematica) and looking for patterns. The patterns were very
- // obvious, but since the analysis was not mathematical, this algorithm has not
- // yet been formally PROVEN. See Mathematica notebook RotMatrix Derivation.
- //
- // Each element of the matrix M is a product of sines and cosines if the angles.
- // No angle appears more than once in a product. It is therefore possible to
- // quickly update the matrix by multiplying the proper elements by crat and srat,
- // computed in steps 1 and 2, which cancel out the previous value of the sin or
- // cos, and multiply in the new value.
- //
- // M[i,j] is the (i,j)th element of the rotation matrix, and rows and columns both
- // start at 0. i is the angle number.
- //
- // 1. crat = cos(new_value)/cos(old_value)
- // 2. srat = sin(new_value)/cos(old_value)
- // 3. M[0, i+1] *= srat
- // 4. loop c from 0 to i { M[0, c] *= crat }
- // 5. M[i+1, i+1] = cos(new_value)
- // 6. loop r from i+2 to dim-1 { loop c from 0 to i { M[r, c] *= crat } }
- // 7. loop c from 0 to i { M[i+1, c] *= srat }
- // 8. loop r from i+2 to dim-1 { M[r, i+1] *= srat }
- //
- // The matrix below is a sample 7x7 rotation matrix, indicating how the matrix would be
- // altered when angle 2 was altered. The entries indicate which element
- // is changed by which step of the above algorithm. For instance, element (3,3) is 5,
- // indicating that the element in the 3rd row and 3rd column is altered by step 5 of
- // the algorithm. Elements which are 0 are not altered.
- //
- //
- // column = 0 column = dim-1
- // | |
- //
- // [ 4 4 4 3 0 0 0 ] row = 0
- // [ 0 0 0 0 0 0 0 ]
- // [ 0 0 0 0 0 0 0 ]
- // [ 7 7 7 5 0 0 0 ]
- // [ 6 6 6 8 0 0 0 ]
- // [ 6 6 6 8 0 0 0 ]
- // [ 6 6 6 8 0 0 0 ] row = dim-1
- //
-
-
- double crat = cos(new_value + ANGLE_OFFSET) / cos(old_value + ANGLE_OFFSET); // Step 1
- double srat = sin(new_value + ANGLE_OFFSET) / sin(old_value + ANGLE_OFFSET); // Step 2
- long c;
- long r;
-
- M(0, i+1) *= srat; // Step 3
-
- for (c = 0; c <= i; c++) // Step 4
- {
- M(0, c) *= crat;
- }
-
- M(i+1, i+1) = cos(new_value + ANGLE_OFFSET); // Step 5
-
- for (r = i+2; r <= dim-1; r++) // Step 6
- {
- for (c = 0; c <= i; c++)
- {
- M(r, c) *= crat;
- }
- }
-
- for (c = 0; c <= i; c++) // Step 7
- {
- M(i+1, c) *= srat;
- }
-
- for (r = i+2; r <= dim-1; r++) // Step 8
- {
- M(r, i+1) *= srat;
- }
-
- } //==== UpdateRotMatrix() ====\\
-
-
-
- //|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- //| Procedure RotateVector
- //|
- //| Purpose: this procedure rotates a vector by multiplying it by
- //| a rotation matrix.
- //|
- //| Parameters: vector: the vector to rotate
- //| rotated_vector: receives the rotated vector
- //| dim: dimension we're rotating in
- //| matrix: the rotation matrix
- //|____________________________________________________________________
-
- void RotateVector(double *vector, double *rotated_vector, long dim, double *matrix)
- {
- double *matrix_entry = matrix; // Start at first entry in matrix
- double *rot_coordinate = rotated_vector; // Start at first coordinate of rotated vect
-
- long row; // Multiply this vector by the rotation matrix
- for (row = 1; row <= dim; row++)
- {
- double *coordinate = vector; // Start at first coordinate of vector
-
- *rot_coordinate = 0; // Initialize sum to 0
-
- long column;
- for (column = 1; column <= dim; column++)
- {
- *rot_coordinate += (*matrix_entry) * (*coordinate);
- matrix_entry++;
- coordinate++;
- }
-
- rot_coordinate++;
-
- }
-
- } //==== RotateVector() ====\\