home *** CD-ROM | disk | FTP | other *** search
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
-
- #include "grtransform.hpp"
-
-
- // ---------- grBaseTransform --------- //
-
- grBaseTransform::grBaseTransform( void ) // DEFAULT CTOR -- IDENTITY
- //--------------------------------------
- {
- uint i, j;
- double * row;
-
- for( i = 0; i < 4; i++ ) {
- row = _storage + 4 * i;
- _rows[ i ] = row;
- for( j = 0; j < 4; j++ ) {
- row[ j ] = 0.0;
- }
- row[ i ] = 1.0;
- }
- }
-
- grBaseTransform::grBaseTransform( // COPY CTOR
- const grBaseTransform & o ) // -- transform to copy
- //-------------------------------
- {
- uint i;
-
- for( i = 0; i < 4; i++ ) {
- _rows[ i ] = _storage + 4 * i;
- }
- copy( o );
- }
-
- void grBaseTransform::copy( // COPY ANOTHER TRANSFORM
- const grBaseTransform & xfrm ) // -- transform to copy
- //--------------------------------
- {
- memcpy( _storage, xfrm._storage, sizeof( double ) * 16 );
- }
-
- grBaseTransform & grBaseTransform::operator =( // ASSIGNMENT OPERATOR
- const grBaseTransform & o ) // -- transform to copy
- //--------------------------------------------
- {
- copy( o );
- return *this;
- }
-
- grBaseTransform & grBaseTransform::operator *=( // LEFT MULTIPLY BY TRANSFORM
- const grBaseTransform & xfrm ) // -- transform to multiply by
- //---------------------------------------------
- {
- grBaseTransform product;
- uint i, j;
- double tmp;
- double * row1;
- double * row2;
-
- for( i = 0; i < 4; i++ ) {
- row1 = xfrm._rows[ i ];
- row2 = product._rows[ i ];
- for( j = 0; j < 4; j++ ) {
- tmp = row1[ 0 ] * _rows[ 0 ][ j ];
- tmp += row1[ 1 ] * _rows[ 1 ][ j ];
- tmp += row1[ 2 ] * _rows[ 2 ][ j ];
- tmp += row1[ 3 ] * _rows[ 3 ][ j ];
- row2[ j ] = tmp;
- }
- }
-
- copy( product );
-
- return *this;
- }
-
- grPoint3 & grBaseTransform::apply( // APPLY TO A POINT
- grPoint3 & point ) const // -- point to apply to
- //--------------------------------
- {
- uint i;
- double result[ 4 ];
- double * row;
- double tmp;
-
- for( i = 0; i < 4; i++ ) {
- row = _rows[ i ];
-
- tmp = row[ 0 ] * point._coords[ 0 ];
- tmp += row[ 1 ] * point._coords[ 1 ];
- tmp += row[ 2 ] * point._coords[ 2 ];
- tmp += row[ 3 ] * point._coords[ 3 ];
- result[ i ] = tmp;
- }
-
- /* copy result */
- memcpy( point._coords, result, sizeof( double ) * 4 );
-
- return point;
- }
-
- grVector & grBaseTransform::apply( // APPLY TO A VECTOR
- grVector & vec ) const // -- vector to apply to
- //--------------------------------
- {
- uint i;
- double result[ 4 ];
- double * row;
- double tmp;
-
- for( i = 0; i < 4; i++ ) {
- row = _rows[ i ];
-
- tmp = row[ 0 ] * vec._coords[ 0 ];
- tmp += row[ 1 ] * vec._coords[ 1 ];
- tmp += row[ 2 ] * vec._coords[ 2 ];
- tmp += row[ 3 ] * vec._coords[ 3 ];
- result[ i ] = tmp;
- }
-
- /* copy result */
- memcpy( vec._coords, result, sizeof( double ) * 4 );
-
- return vec;
- }
-
- void grBaseTransform::transpose( void ) // TAKE TRANSPOSE OF MATRIX
- //-------------------------------------
- {
- double tmp;
- uint i, j;
-
- for( i = 0; i < 4; i++ ) {
- for( j = i + 1; j < 4; j++ ) {
- tmp = _rows[ i ][ j ];
- _rows[ i ][ j ] = _rows[ j ][ i ];
- _rows[ j ][ i ] = tmp;
- }
- }
- }
-
- // ----------- grChangeBase ----------- //
-
- grChangeBase::grChangeBase( // CONSTRUCTOR
- const grPoint3 & origin, // -- origin of new coordinates
- const grVector & ux, // -- unit vector along new x
- const grVector & uy, // -- unit vector along new y
- const grVector & uz ) // -- unit vector along new z
- //--------------------------
- {
- grTranslate trans( grPoint3Origin - origin );
- grTransform rotate;
- uint i;
-
- #if 0
- grAssert( 1.0 - grEPSILON < ux.length() && ux.length() < 1.0 + grEPSILON );
- grAssert( 1.0 - grEPSILON < uy.length() && uy.length() < 1.0 + grEPSILON );
- grAssert( 1.0 - grEPSILON < uz.length() && uz.length() < 1.0 + grEPSILON );
-
- memcpy( rotate._rows[ 0 ], ux._coords, sizeof( double ) * 3 );
- memcpy( rotate._rows[ 1 ], uy._coords, sizeof( double ) * 3 );
- memcpy( rotate._rows[ 2 ], uz._coords, sizeof( double ) * 3 );
-
- copy( rotate );
- *this *= trans;
- #else
- memcpy( _rows[ 0 ], ux._coords, sizeof( double ) * 3 );
- memcpy( _rows[ 1 ], uy._coords, sizeof( double ) * 3 );
- memcpy( _rows[ 2 ], uz._coords, sizeof( double ) * 3 );
-
- for( i = 0; i < 3; i++ ) {
- _rows[ i ][ 3 ] = -origin._coords[ i ];
- }
- #endif
- }
-
- // ------------ grRotation ------------ //
-
- #if 1
- /*
- * Rotate with a general origin and general rotation axis.
- * - translate, rotate, rotate, rotate, rotate, rotate, translate
- * Hearn and Baker p. 416
- */
- grRotation::grRotation( // CONSTRUCTOR
- const grPoint3 & origin, // -- origin of rotation
- const grVector & direct, // -- second point for direction
- double amount ) // -- degrees counterclockwise
- //--------------------------
- {
- grVector axis( direct);
- grTranslate trn( grPoint3Origin - origin );
- grTranslate trn_inv( origin - grPoint3Origin );
- grTransform Rx;
- grTransform Ry;
- grTransform Rz;
- double d;
-
- axis.normalize();
- grAssert( dot( axis, axis ) > (1.0 - grEPSILON) );
-
- d = sqrt( axis.y() * axis.y() + axis.z() * axis.z() );
- if( d > grEPSILON ) {
- Rx._rows[ 1 ][ 1 ] = axis.z() / d;
- Rx._rows[ 1 ][ 2 ] = -1.0 * axis.y() / d;
- Rx._rows[ 2 ][ 1 ] = axis.y() / d;
- Rx._rows[ 2 ][ 2 ] = axis.z() / d;
- }
-
- Ry._rows[ 0 ][ 0 ] = d;
- Ry._rows[ 0 ][ 2 ] = -1.0 * axis.x();
- Ry._rows[ 2 ][ 0 ] = axis.x();
- Ry._rows[ 2 ][ 2 ] = d;
-
- Rz._rows[ 0 ][ 0 ] = cos( amount );
- Rz._rows[ 0 ][ 1 ] = -1.0 * sin( amount );
- Rz._rows[ 1 ][ 0 ] = sin( amount );
- Rz._rows[ 1 ][ 1 ] = cos( amount );
-
- *this *= trn;
- *this *= Rx;
- *this *= Ry;
- *this *= Rz;
-
- Rx.transpose();
- Ry.transpose();
-
- // NOTE: don't invert the Rz transform -- that does the work!
-
- *this *= Ry;
- *this *= Rx;
- *this *= trn_inv;
- }
- #else
- /*
- * Rotate with a general origin and general rotation axis
- * quaternion method, Hearn and Baker p. 420
- */
- grRotation::grRotation( // CONSTRUCTOR
- const grPoint3 & origin, // -- origin of rotation
- const grPoint3 & direct, // -- second point for direction
- double amount ) // -- degrees counterclockwise
- //--------------------------
- {
- grVector axis( direct - origin );
- grVector v;
- grTranslate trn( grPoint3Origin - origin );
- grTranslate trn_inv( origin - grPoint3Origin );
- grTransform R;
- double s;
- double a, b, c;
- double t_aa, t_ab, t_ac, t_sa;
- double t_bb, t_bc, t_sb;
- double t_cc, t_sc;
-
- axis.normalize();
- if( dot( axis, axis ) == 0 ) {
- grError( "grRotation: invalid axis" );
- }
-
- s = cos( amount / 2.0 );
- v = sin( amount / 2.0 ) * axis;
- a = v.x();
- b = v.y();
- c = v.z();
-
- t_aa = 2.0 * a * a;
- t_bb = 2.0 * b * b;
- t_cc = 2.0 * c * c;
-
- t_ab = 2.0 * a * b;
- t_ac = 2.0 * a * c;
- t_sa = 2.0 * s * a;
-
- t_bc = 2.0 * b * c;
- t_sb = 2.0 * s * b;
-
- t_sc = 2.0 * s * c;
-
- R._rows[ 0 ][ 0 ] = 1.0 - t_bb - t_cc;
- R._rows[ 0 ][ 1 ] = t_ab - t_sc;
- R._rows[ 0 ][ 2 ] = t_ac + t_sb;
-
- R._rows[ 1 ][ 0 ] = t_ab + t_sc;
- R._rows[ 1 ][ 1 ] = 1.0 - t_aa - t_cc;
- R._rows[ 1 ][ 2 ] = t_bc - t_sa;
-
- R._rows[ 2 ][ 0 ] = t_ac - t_sb;
- R._rows[ 2 ][ 1 ] = t_bc + t_sa;
- R._rows[ 2 ][ 2 ] = 1.0 - t_aa - t_bb;
-
- *this *= trn;
- *this *= R;
- *this *= trn_inv;
- }
- #endif
-
- /*
- * Trivial rotation about a coordinate axis, origin at (0,0,0)
- */
- grRotation::grRotation( // CONSTRUCTOR
- int axis, // -- coordinate axis
- double amount ) // -- radians counter-clockwise
- //---------------------
- {
- double c_theta; // -- cosine of amount
- double s_theta; // -- sine of amount
-
- c_theta = cos( amount );
- s_theta = sin( amount );
-
- switch( axis ) {
- case X:
- _rows[ 1 ][ 1 ] = c_theta;
- _rows[ 1 ][ 2 ] = -1.0 * s_theta;
- _rows[ 2 ][ 1 ] = s_theta;
- _rows[ 2 ][ 2 ] = c_theta;
- break;
- case Y:
- _rows[ 0 ][ 0 ] = c_theta;
- _rows[ 0 ][ 2 ] = s_theta;
- _rows[ 2 ][ 0 ] = -1.0 * s_theta;
- _rows[ 2 ][ 2 ] = c_theta;
- break;
- case Z:
- _rows[ 0 ][ 0 ] = c_theta;
- _rows[ 0 ][ 1 ] = -1.0 * s_theta;
- _rows[ 1 ][ 0 ] = s_theta;
- _rows[ 1 ][ 1 ] = c_theta;
- break;
- default:
- grError( "grRotation: invalid axis" );
- }
- }
-
- // -------------- grScale ------------- //
-
- /*
- * Scale with respect to the coordinate axes: (Hearn and Baker, p. 420)
- * [ sx 0.0 0.0 ( 1.0 - sx ) * xf 0.0 ]
- * [ 0.0 sy 0.0 ( 1.0 - sy ) * yf 0.0 ]
- * [ 0.0 0.0 sz ( 1.0 - sz ) * zf 0.0 ]
- * [ 0.0 0.0 0.0 0.0 1.0 ]
- */
- grScale::grScale( // CONSTRUCTOR
- const grPoint3 & origin, // -- scale origin
- double sx, double sy, double sz ) // -- scale parameters
- //--------------------------------
- {
- _rows[ 0 ][ 0 ] = sx;
- _rows[ 1 ][ 1 ] = sy;
- _rows[ 2 ][ 2 ] = sz;
-
- _rows[ 0 ][ 3 ] = (1.0 - sx) * origin.x();
- _rows[ 1 ][ 3 ] = (1.0 - sy) * origin.y();
- _rows[ 2 ][ 3 ] = (1.0 - sz) * origin.z();
- }
-
- /*
- * Scale in a general direction:
- * - translate scale origin to coordinate origin
- * - rotate scale direction to match z-axis
- * - scale along z-axis
- * - reverse rotation
- * - reverse translation
- */
- grScale::grScale( // CONSTRUCTOR
- const grPoint3 & origin, // -- origin of scale
- const grVector & direction, // -- direction of scale
- double amt ) // -- amount to scale by
- //-----------------------------
- {
- grVector axis( direction );
- grTranslate trn( grPoint3Origin - origin );
- grTranslate trn_inv( origin - grPoint3Origin );
- grTransform Rx;
- grTransform Ry;
- grPoint3 O( 0.0, 0.0, 0.0 );
- grScale scale( O, 1.0, 1.0, amt );
- double d;
-
- axis.normalize();
- grAssert( dot( axis, axis ) > (1.0 - grEPSILON) );
-
- d = sqrt( axis.y() * axis.y() + axis.z() * axis.z() );
- if( d > grEPSILON ) {
- Rx._rows[ 1 ][ 1 ] = axis.z() / d;
- Rx._rows[ 1 ][ 2 ] = -1.0 * axis.y() / d;
- Rx._rows[ 2 ][ 1 ] = axis.y() / d;
- Rx._rows[ 2 ][ 2 ] = axis.z() / d;
- }
-
- Ry._rows[ 0 ][ 0 ] = d;
- Ry._rows[ 0 ][ 2 ] = -1.0 * axis.x();
- Ry._rows[ 2 ][ 0 ] = axis.x();
- Ry._rows[ 2 ][ 2 ] = d;
-
- *this *= trn;
- *this *= Rx;
- *this *= Ry;
-
- *this *= scale;
-
- // invert Rx and Ry by transposing them
- Rx.transpose();
- Ry.transpose();
-
- // NOTE: don't invert the Rz transform -- that does the work!
-
- *this *= Ry;
- *this *= Rx;
- *this *= trn_inv;
- }
-
- // ------------ grTranslate ----------- //
-
- grTranslate::grTranslate( // PERFORM GENERAL TRANSLATION
- const grVector & translate ) // -- amount to translate by
- //------------------------------
- {
- uint i;
-
- for( i = 0; i < 3; i++ ) {
- _rows[ i ][ 3 ] = translate._coords[ i ];
- }
- }
-
- // ----------- grPerspective ---------- //
-
- /*
- * Perform the perspective projection.
- * Although this is based on the version in class,
- * it is transposed as I am using column vectors.
- */
-
- grPerspective::grPerspective( // CONSTRUCTOR
- double fovy, // -- field of view, in abs degrees
- double aspect, // -- aspect ratio(horz angle/vert)
- double n, // -- distance to near clipping
- double f ) // -- distance to far clipping
- //---------------------------
- {
- double ctan;
-
- ctan = 1.0 / tan( fovy / 2.0 );
-
- _rows[ 0 ][ 0 ] = ctan / aspect;
- _rows[ 1 ][ 1 ] = ctan;
-
- _rows[ 2 ][ 2 ] = (f + n) / (n - f);
- _rows[ 2 ][ 3 ] = 2 * f * n / (n - f); // transpose
- _rows[ 3 ][ 2 ] = -1.0; // transpose
- _rows[ 3 ][ 3 ] = 0.0;
- }
-
- // ------------- grShearXY ------------ //
-
- grShearXY::grShearXY( // CONSTRUCTOR
- double shx, // -- x parameter
- double shy ) // -- y parameter
- //-------------------
- {
- _rows[ 0 ][ 2 ] = shx;
- _rows[ 0 ][ 2 ] = shy;
- }
-
- // ------------ grTransform ----------- //
-
- /*
- * Change from one coordinate system to another
- * using unit x, y, z vectors of the target given in the source
- * Hearn and Baker p. 428
- */
- grTransform & grTransform::changeBase( // PERFORM CHANGE OF BASIS
- const grPoint3 & origin, // -- origin of new coordinates
- const grVector & ux, // -- unit vector along new x
- const grVector & uy, // -- unit vector along new y
- const grVector & uz ) // -- unit vector along new z
- //------------------------------------
- {
- grChangeBase cb( origin, ux, uy, uz );
-
- *this *= cb;
- return *this;
- }
-
- grTransform & grTransform::rotate( // PERFORM GENERAL ROTATION
- const grPoint3 & origin, // -- origin of rotation
- const grVector & axis, // -- axis of rotation
- double angle ) // -- degrees counter-clockwise
- //--------------------------------
- {
- grRotation rot( origin, axis, angle );
-
- *this *= rot;
- return *this;
- }
-
- grTransform & grTransform::rotate( // PERFORM TRIVIAL ROTATION
- int axis, // -- coordinate axis
- double amount ) // -- radians counter-clockwise
- //--------------------------------
- {
- grRotation rot( axis, amount );
-
- *this *= rot;
- return *this;
- }
-
- grTransform & grTransform::scale( // PERFORM SCALE RELATIVE TO COORD
- const grPoint3 & origin, // -- scale origin
- double sx, double sy, double sz ) // -- scale parameters
- //--------------------------------
- {
- grScale scale( origin, sx, sy, sz );
-
- *this *= scale;
- return *this;
- }
-
- grTransform & grTransform::scale( // CONSTRUCTOR
- const grPoint3 & origin, // -- origin of scale
- const grVector & direction, // -- direction of scale
- double amt ) // -- amount to scale by
- //-------------------------------
- {
- grScale scale( origin, direction, amt );
-
- *this *= scale;
- return *this;
- }
-
- grTransform & grTransform::translate( // PERFORM GENERAL TRANSLATION
- const grVector & translate ) // -- amount to translate by
- //-----------------------------------
- {
- grTranslate trans( translate );
-
- *this *= trans;
- return *this;
- }
-