cgma
CubitTransformMatrix.cpp
Go to the documentation of this file.
00001 //       Class: CubitTransformMatrix
00002 //
00003 // Description: A 4-Dimensional Matrix.  Essentially the same as
00004 //              a generic CubitMatrix, except that it has some
00005 //              extra 3D transformation functions.
00006 //
00007 //              All transformations are pre-multiplications,
00008 //              meaning that M*V will transform a point V
00009 //              in the same order transformations are applied to M.
00010 //
00011 //      Owner: Darryl Melander
00012 
00013 #include "CubitTransformMatrix.hpp"
00014 #include "CubitMessage.hpp"
00015 
00016 CubitTransformMatrix::CubitTransformMatrix() 
00017     : CubitMatrix(4)
00018 {
00019     // Just creates a 4x4 matrix set to identity
00020 }
00021 
00022 CubitTransformMatrix::CubitTransformMatrix(const CubitTransformMatrix& from)
00023     : CubitMatrix(from)
00024 {
00025     // Just copies it
00026 }
00027 
00028 
00029 CubitTransformMatrix::~CubitTransformMatrix()
00030 {
00031     // Just deletes it
00032 }
00033 
00034 
00035 
00036 CubitTransformMatrix& CubitTransformMatrix::translate(const CubitVector& v)
00037 {
00038   return translate(v.x(), v.y(), v.z());
00039 }
00040 
00041 
00042 CubitTransformMatrix& CubitTransformMatrix::translate (double x, double y, double z)
00043 {
00044   set (0, 3, get(0, 3) + x);
00045   set (1, 3, get(1, 3) + y);
00046   set (2, 3, get(2, 3) + z);
00047   
00048   return *this;
00049 }
00050 
00051 CubitTransformMatrix& CubitTransformMatrix::rotate(double degrees,
00052                                                    const CubitVector& vector)
00053 {
00054   double angle, ct, st;
00055     // Make a copy of vector so we don't have to change it
00056   CubitVector axis = vector;
00057   
00058     // Convert degrees to radians
00059   angle = -degrees * CUBIT_PI/180.0;
00060   
00061     // Take sin and cos
00062   ct = cos(angle);
00063   st = sin(angle);
00064   
00065     // Normalize the axis vector
00066   axis.normalize();
00067   
00068     // Make an identity matrix
00069   CubitTransformMatrix mat;
00070   
00071     // Setup some calculations that occur repeatedly
00072   double one_minus_cos = 1.0 - ct;
00073   double dx_ct = axis.x() * one_minus_cos;
00074   double dy_ct = axis.y() * one_minus_cos;
00075   double dz_ct = axis.z() * one_minus_cos;
00076   double dx_st = axis.x() * st;
00077   double dy_st = axis.y() * st;
00078   double dz_st = axis.z() * st;
00079   
00080     // Set the values in the matrix
00081   mat.set(0, 0,     ct + axis.x() * dx_ct);
00082   mat.set(1, 0, -dz_st + axis.x() * dy_ct);
00083   mat.set(2, 0,  dy_st + axis.x() * dz_ct);
00084   
00085   mat.set(0, 1,  dz_st + axis.y() * dx_ct);
00086   mat.set(1, 1,     ct + axis.y() * dy_ct);
00087   mat.set(2, 1, -dx_st + axis.y() * dz_ct);
00088   
00089   mat.set(0, 2, -dy_st + axis.z() * dx_ct);
00090   mat.set(1, 2,  dx_st + axis.z() * dy_ct);
00091   mat.set(2, 2,     ct + axis.z() * dz_ct);
00092   
00093     // Premultiply the matrix
00094   *this = mat * *this;
00095     // Return
00096   return *this;
00097 }
00098 
00099 CubitTransformMatrix& CubitTransformMatrix::rotate(double degrees, char axis)
00100 {
00101   if(axis != 'x' && axis != 'y' && axis != 'z')
00102     throw std::invalid_argument("Invalid Axis: must be X, Y, or Z");
00103   //assert (axis == 'x' || axis == 'y' || axis == 'z');
00104   
00105     // Convert to Radians, Get the sine and cosine
00106   double angle = degrees * CUBIT_PI/180.;
00107   double s, c;
00108   s = sin(angle);
00109   c = cos(angle);
00110   
00111     // Make an Identity matrix
00112   CubitTransformMatrix mat;
00113     // Place values in appropriate places
00114   switch (axis)
00115   {
00116     case 'x':
00117       mat.set(1, 1, c);
00118       mat.set(2, 2, c);
00119       mat.set(1, 2, -s);
00120       mat.set(2, 1, s);
00121       break;
00122     case 'y':
00123       mat.set(0, 0, c);
00124       mat.set(0, 2, s);
00125       mat.set(2, 0, -s);
00126       mat.set(2, 2, c);
00127       break;
00128     case 'z':
00129       mat.set(0, 0, c);
00130       mat.set(1, 0, s);
00131       mat.set(0, 1, -s);
00132       mat.set(1, 1, c);
00133       break;
00134   }
00135   
00136     // Perform Pre-Multiplication
00137   *this = mat * *this;
00138   
00139   return *this;
00140 }
00141 
00142 CubitTransformMatrix& CubitTransformMatrix::reflect(const CubitVector& vector)
00143 {
00144   double a, b, c, d;
00145   CubitVector axis = vector;
00146   axis.normalize();
00147 
00148   a = axis.x();
00149   b = axis.y();
00150   c = axis.z();
00151   
00152   d = sqrt(b*b + c*c);
00153   
00154     // Make an Identity matrix
00155   CubitTransformMatrix mat;
00156   if(d)
00157   {
00158       // Place values in appropriate places for negative rotate about x
00159     mat.set(1, 1, c/d);
00160     mat.set(1, 2, -b/d);
00161     mat.set(2, 1, b/d);
00162     mat.set(2, 2, c/d);
00163   
00164       // Perform Pre-Multiplication
00165     *this = mat * *this;
00166     mat.set_to_identity();
00167   }
00168   
00169     // Place values in appropriate places for negative rotate about y
00170   mat.set(0, 0, d);
00171   mat.set(0, 2, -a);
00172   mat.set(2, 0, a);
00173   mat.set(2, 2, d);
00174 
00175   
00176     // Perform Pre-Multiplication
00177   *this = mat * *this;
00178   mat.set_to_identity();
00179   
00180     // Place values in appropriate places for reflect across z
00181   mat.set(2, 2, -1);
00182 
00183   
00184     // Perform Pre-Multiplication
00185   *this = mat * *this;
00186   mat.set_to_identity();
00187   
00188     // Place values in appropriate places for rotate about y
00189   mat.set(0, 0, d);
00190   mat.set(0, 2, a);
00191   mat.set(2, 0, -a);
00192   mat.set(2, 2, d);
00193 
00194   
00195     // Perform Pre-Multiplication
00196   *this = mat * *this;
00197   mat.set_to_identity();
00198 
00199   if(d)
00200   {
00201       // Place values in appropriate places for rotate about x
00202     mat.set(1, 1, c/d);
00203     mat.set(1, 2, b/d);
00204     mat.set(2, 1, -b/d);
00205     mat.set(2, 2, c/d);
00206   
00207       // Perform Pre-Multiplication
00208     *this = mat * *this;
00209     mat.set_to_identity();
00210   }
00211     
00212   return *this;
00213 
00214 }
00215 
00216 CubitTransformMatrix& CubitTransformMatrix::rotate(double degrees,
00217                                      const CubitVector& axis_from,
00218                                      const CubitVector& axis_to)
00219 {
00220     // Translate so that axis_from is at origin
00221   translate (-axis_from); 
00222   
00223     // Rotate about specified axis
00224   rotate (degrees, axis_to - axis_from);
00225   
00226     // Translate back
00227   translate (axis_from);
00228   
00229   return *this;
00230 }
00231 
00232 CubitTransformMatrix& CubitTransformMatrix::scale_about_origin (const CubitVector& scale)
00233 {
00234   return scale_about_origin(scale.x(), scale.y(), scale.z());
00235 }
00236 
00237 CubitTransformMatrix& CubitTransformMatrix::scale_about_origin (double x, double y, double z)
00238 {
00239   CubitTransformMatrix mat;
00240   mat.set(0, 0, x);
00241   mat.set(1, 1, y);
00242   mat.set(2, 2, z);
00243   
00244     // Perform Pre-Multiplication
00245   *this = mat * *this;
00246   
00247   return *this;
00248 }
00249 
00250 CubitTransformMatrix& CubitTransformMatrix::scale_about_origin (double scale)
00251 {
00252   return scale_about_origin(scale, scale, scale);
00253 }
00254 
00255 CubitTransformMatrix& CubitTransformMatrix::inverse()
00256 {
00257   CubitMatrix matrix = *this;
00258   matrix = matrix.inverse();
00259   for( int ii = 0; ii < 4; ii++ )
00260   {
00261     for( int jj = 0; jj < 4; jj++ )
00262     {
00263       set( ii, jj, matrix.get(ii,jj) );
00264     }
00265   }
00266   return *this;
00267 }
00268 
00269 
00270   // Post-multiplication of a point (M*V)
00271 CubitVector CubitTransformMatrix::operator* (const CubitVector& point) const
00272 {
00273     // Make a sub-matrix, multiply the point by it.
00274   CubitVector vec = (this->sub_matrix(3, 3))*point;
00275     // Handle the fourth column here
00276   vec.x(vec.x() + get(0, 3));
00277   vec.y(vec.y() + get(1, 3));
00278   vec.z(vec.z() + get(2, 3));
00279   
00280   return vec;
00281 }
00282 
00283 
00284   // point * matrix
00285 CUBIT_UTIL_EXPORT
00286 CubitVector operator* (const CubitVector& point,
00287                        const CubitTransformMatrix& matrix)
00288 {
00289     // Make a 1x4 matrix, multiply matrix by it.
00290   CubitMatrix m1(1,4);
00291   m1.set(0, 0, point.x());
00292   m1.set(0, 1, point.y());
00293   m1.set(0, 2, point.z());
00294   m1.set(0, 3, 1);
00295   
00296     // Perform the multiplication
00297   m1 = m1 * matrix;
00298     // The result is a 1x4
00299   
00300     // Put the results into a vector (dividing by w), and return
00301   double w = m1.get(0,3);
00302   return CubitVector(m1.get(0,0)/w, m1.get(0,1)/w, m1.get(0,2)/w);
00303 }
00304 
00305 CubitTransformMatrix CubitTransformMatrix::operator*(
00306   const CubitTransformMatrix& matrix) const
00307 {
00308   CubitTransformMatrix rv;
00309   CubitMatrix temp(4);
00310   temp = CubitMatrix::operator*(matrix);
00311   for (int i = 0; i < 4; i++)
00312     for (int j = 0; j < 4; j++)
00313       rv.set(i, j, temp.get(i,j));
00314   return rv;
00315 }
00316 
00317 CubitMatrix CubitTransformMatrix::operator*(const CubitMatrix& matrix) const
00318 {
00319   return CubitMatrix::operator*(matrix);
00320 }
00321 
00322 CubitTransformMatrix CubitTransformMatrix::operator*(double val) const
00323 {
00324   CubitTransformMatrix rv;
00325   for (int i = 0; i < 4; i++)
00326     for (int j = 0; j < 4; j++)
00327       rv.set(i, j, this->get(i,j)*val);
00328   return rv;
00329 }
00330 
00331 void CubitTransformMatrix::print_me() const
00332 {
00333   PRINT_INFO("%8.4f  %8.4f  %8.4f  %8.4f\n",
00334     get(0,0), get(0,1), get(0,2), get(0,3));
00335   PRINT_INFO("%8.4f  %8.4f  %8.4f  %8.4f\n",
00336     get(1,0), get(1,1), get(1,2), get(1,3));
00337   PRINT_INFO("%8.4f  %8.4f  %8.4f  %8.4f\n",
00338     get(2,0), get(2,1), get(2,2), get(2,3));
00339   PRINT_INFO("%8.4f  %8.4f  %8.4f  %8.4f\n",
00340     get(3,0), get(3,1), get(3,2), get(3,3));
00341 }
00342 
00344 CubitVector CubitTransformMatrix::origin() const
00345 {
00346   return CubitVector(this->get(0,3), this->get(1,3), this->get(2,3));
00347 }
00348 
00350 CubitVector CubitTransformMatrix::x_axis() const
00351 {
00352   CubitMatrix tmp1(4,1);
00353   tmp1.set(0,0,1);
00354   tmp1.set(1,0,0);
00355   tmp1.set(2,0,0);
00356   tmp1.set(3,0,0);
00357   CubitMatrix tmp2 = (*this) * tmp1;
00358   return CubitVector(tmp2.get(0,0), tmp2.get(1,0), tmp2.get(2,0));
00359 }
00360 
00362 CubitVector CubitTransformMatrix::y_axis() const
00363 {
00364   CubitMatrix tmp1(4,1);
00365   tmp1.set(0,0,0);
00366   tmp1.set(1,0,1);
00367   tmp1.set(2,0,0);
00368   tmp1.set(3,0,0);
00369   CubitMatrix tmp2 = (*this) * tmp1;
00370   return CubitVector(tmp2.get(0,0), tmp2.get(1,0), tmp2.get(2,0));
00371 }
00372 
00374 CubitVector CubitTransformMatrix::z_axis() const
00375 {
00376   CubitMatrix tmp1(4,1);
00377   tmp1.set(0,0,0);
00378   tmp1.set(1,0,0);
00379   tmp1.set(2,0,1);
00380   tmp1.set(3,0,0);
00381   CubitMatrix tmp2 = (*this) * tmp1;
00382   return CubitVector(tmp2.get(0,0), tmp2.get(1,0), tmp2.get(2,0));
00383 }
00384 
00385 
00386 CubitTransformMatrix CubitTransformMatrix::construct_matrix(const CubitVector& origin,
00387                                              const CubitVector& x_axis,
00388                                              const CubitVector& y_axis)
00389 {
00390   CubitTransformMatrix mat;
00391   double angle = x_axis.interior_angle(CubitVector(1,0,0));
00392   CubitVector axis = angle == 180 ? CubitVector(0,1,0) : CubitVector(1,0,0) * x_axis;
00393   mat.rotate(angle, axis);
00394   CubitVector y = mat * CubitVector(0,1,0);
00395   angle = y_axis.interior_angle(y);
00396   axis = angle == 180 ? CubitVector(0,0,1) : y * y_axis;
00397   mat.rotate(angle, axis);
00398   mat.translate(origin);
00399   return mat;
00400 }
00401 
00402 void CubitTransformMatrix::get_rotation_axis_and_angle(CubitVector &rotation_axis, double &angle)
00403 {
00404     double cos_theta = (this->get(0,0) + this->get(1,1) + this->get(2,2) - 1) / 2;
00405 
00406     double x = 0;
00407     double y = 0;
00408     double z = 0; 
00409     
00410     if (fabs(cos_theta - 1) < .0001)
00411     {
00412         // theta is 1 or almost 1
00413         angle = 0;
00414         x = 0;
00415         y = 0;
00416         z = 1;
00417     }
00418     else if (fabs(cos_theta + 1) > .0001)
00419     {
00420         // theta is NOT -1 or almost -1
00421         angle = acos(cos_theta);
00422         angle =  (angle * 180.0) / CUBIT_PI; // convert to degrees
00423         double sin_theta = sqrt(1 - cos_theta * cos_theta);
00424         x = ( (this->get(2,1) - this->get(1,2)) / 2 ) / sin_theta;
00425         y = ( (this->get(0,2) - this->get(2,0)) / 2 ) / sin_theta;
00426         z = ( (this->get(1,0) - this->get(0,1)) / 2 ) / sin_theta;
00427     }
00428     else
00429     {
00430         angle = 180;
00431         if (this->get(0,0) >= this->get(1,1))
00432         {
00433 
00434             if (this->get(0,0) >= this->get(2,2)) 
00435             {
00436                 // 0,0 is maximal diagonal term
00437                 x = sqrt(this->get(0,0) - this->get(1,1) - this->get(2,2) + 1) / 2;
00438                 double half_inverse = 1 / (2 * x);
00439                 y = half_inverse * this->get(0,1);
00440                 z = half_inverse * this->get(0,2);
00441             } 
00442             else
00443             {
00444                 // 2,2 is maximal diagonal term
00445                 z = sqrt(this->get(2,2) - this->get(0,0) - this->get(1,1) + 1) / 2;
00446                 double half_inverse = 1 / (2 * z);
00447                 x = half_inverse * this->get(0,2);
00448                 y = half_inverse * this->get(1,2);
00449             }
00450         }
00451         else
00452         {
00453             if (this->get(1,1) >= this->get(2,2))
00454             {
00455                 // 1,1 is maximal diagonal term
00456                 y = sqrt(this->get(1,1) - this->get(0,0) - this->get(2,2) + 1) / 2;
00457                 double half_inverse = 1 / (2 * y);
00458                 x = half_inverse * this->get(0,1);
00459                 z = half_inverse * this->get(1,2);
00460             } 
00461             else
00462             {
00463                 // 2,2 is maximal diagonal term
00464                 z = sqrt(this->get(2,2) - this->get(0,0) - this->get(1,1) + 1) / 2;
00465                 double half_inverse = 1 / (2 * z);
00466                 x = half_inverse * this->get(0,2);
00467                 y = half_inverse * this->get(1,2);
00468             }
00469         }
00470 
00471     }
00472 
00473     rotation_axis.x(x);
00474     rotation_axis.y(y);
00475     rotation_axis.z(z);
00476 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines