opennurbs_xform.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 
00017 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00018 
00019 static void SwapRow( double matrix[4][4], int i0, int i1 )
00020 {
00021   double* p0;
00022   double* p1;
00023   double t;
00024   p0 = &matrix[i0][0];
00025   p1 = &matrix[i1][0];
00026   t = *p0; *p0++ = *p1; *p1++ = t;
00027   t = *p0; *p0++ = *p1; *p1++ = t;
00028   t = *p0; *p0++ = *p1; *p1++ = t;
00029   t = *p0; *p0   = *p1; *p1 = t;
00030 }
00031 
00032 static void SwapCol( double matrix[4][4], int j0, int j1 )
00033 {
00034   double* p0;
00035   double* p1;
00036   double t;
00037   p0 = &matrix[0][j0];
00038   p1 = &matrix[0][j1];
00039   t = *p0; *p0 = *p1; *p1 = t;
00040   p0 += 4; p1 += 4;
00041   t = *p0; *p0 = *p1; *p1 = t;
00042   p0 += 4; p1 += 4;
00043   t = *p0; *p0 = *p1; *p1 = t;
00044   p0 += 4; p1 += 4;
00045   t = *p0; *p0 = *p1; *p1 = t;
00046 }
00047 
00048 //static void ScaleRow( double matrix[4][4], double c, int i )
00049 //{
00050 //  double* p = &matrix[i][0];
00051 //  *p++ *= c;
00052 //  *p++ *= c;
00053 //  *p++ *= c;
00054 //  *p   *= c;
00055 //}
00056 //
00057 //static void InvScaleRow( double matrix[4][4], double c, int i )
00058 //{
00059 //  double* p = &matrix[i][0];
00060 //  *p++ /= c;
00061 //  *p++ /= c;
00062 //  *p++ /= c;
00063 //  *p   /= c;
00064 //}
00065 
00066 static void AddCxRow( double matrix[4][4], double c, int i0, int i1 )
00067 {
00068   const double* p0;
00069   double* p1;
00070   p0 = &matrix[i0][0];
00071   p1 = &matrix[i1][0];
00072   *p1++ += c* *p0++;
00073   *p1++ += c* *p0++;
00074   *p1++ += c* *p0++;
00075   *p1   += c* *p0;
00076 }
00077 
00078 /*
00079 static void AddCxCol( double matrix[4][4], double c, int j0, int j1 )
00080 {
00081   const double* p0;
00082   double* p1;
00083   p0 = &matrix[0][j0];
00084   p1 = &matrix[0][j1];
00085   *p1 += c* *p0;
00086   p0 += 4; p1 += 4;
00087   *p1 += c* *p0;
00088   p0 += 4; p1 += 4;
00089   *p1 += c* *p0;
00090   p0 += 4; p1 += 4;
00091   *p1 += c* *p0;
00092 }
00093 */
00094 
00095 static int Inv( const double* src, double dst[4][4], double* determinant, double* pivot )
00096 {
00097   // returns rank (0, 1, 2, 3, or 4), inverse, and smallest pivot
00098 
00099         double M[4][4], I[4][4], x, c, d;
00100         int i, j, ix, jx;
00101   int col[4] = {0,1,2,3};
00102   int swapcount = 0;
00103   int rank = 0;
00104 
00105   *pivot = 0.0;
00106   *determinant = 0.0;
00107 
00108   memset( I, 0, sizeof(I) );
00109   I[0][0] = I[1][1] = I[2][2] = I[3][3] = 1.0;
00110 
00111   memcpy( M, src, sizeof(M) );
00112 
00113   // some loops unrolled for speed
00114 
00115   ix = jx = 0;
00116         x = fabs(M[0][0]);
00117   for ( i = 0; i < 4; i++ ) for ( j = 0; j < 4; j++ ) {
00118     if ( fabs(M[i][j]) > x ) {
00119       ix = i;
00120       jx = j;
00121       x = fabs(M[i][j]);
00122     }
00123   }
00124   *pivot = x;
00125   if ( ix != 0 ) {
00126     SwapRow( M, 0, ix );
00127     SwapRow( I, 0, ix );
00128     swapcount++;
00129   }
00130   if ( jx != 0 ) {
00131     SwapCol( M, 0, jx );
00132     col[0] = jx;
00133     swapcount++;
00134   }
00135 
00136   if ( x > 0.0 ) {
00137     rank++;
00138 
00139     // 17 August 2011 Dale Lear
00140     //   The result is slightly more accurate when using division
00141     //   instead of multiplying by the inverse of M[0][0]. If there
00142     //   is any speed penalty at this point in history, the accuracy
00143     //   is more important than the additional clocks.
00144     //c = d = 1.0/M[0][0];
00145     //M[0][1] *= c; M[0][2] *= c; M[0][3] *= c;
00146     //ScaleRow( I, c, 0 );
00147     c = M[0][0];
00148     M[0][1] /= c; M[0][2] /= c; M[0][3] /= c;
00149     I[0][0] /= c; I[0][1] /= c; I[0][2] /= c; I[0][3] /= c;
00150     d = 1.0/c;
00151 
00152     x *=  ON_EPSILON;
00153 
00154           if (fabs(M[1][0]) > x) {
00155                   c = -M[1][0];
00156       M[1][1] += c*M[0][1]; M[1][2] += c*M[0][2]; M[1][3] += c*M[0][3];
00157       AddCxRow( I, c, 0, 1 );
00158           }
00159           if (fabs(M[2][0]) >  x) {
00160                   c = -M[2][0];
00161       M[2][1] += c*M[0][1]; M[2][2] += c*M[0][2]; M[2][3] += c*M[0][3];
00162       AddCxRow( I, c, 0, 2 );
00163           }
00164           if (fabs(M[3][0]) >  x) {
00165                   c = -M[3][0];
00166       M[3][1] += c*M[0][1]; M[3][2] += c*M[0][2]; M[3][3] += c*M[0][3];
00167       AddCxRow( I, c, 0, 3 );
00168           }
00169 
00170     ix = jx = 1;
00171           x = fabs(M[1][1]);
00172     for ( i = 1; i < 4; i++ ) for ( j = 1; j < 4; j++ ) {
00173       if ( fabs(M[i][j]) > x ) {
00174         ix = i;
00175         jx = j;
00176         x = fabs(M[i][j]);
00177       }
00178     }
00179     if ( x < *pivot )
00180       *pivot = x;
00181     if ( ix != 1 ) {
00182       SwapRow( M, 1, ix );
00183       SwapRow( I, 1, ix );
00184       swapcount++;
00185     }
00186     if ( jx != 1 ) {
00187       SwapCol( M, 1, jx );
00188       col[1] = jx;
00189       swapcount++;
00190     }
00191     if ( x > 0.0 ) {
00192       rank++;
00193 
00194       // 17 August 2011 Dale Lear
00195       //   The result is slightly more accurate when using division
00196       //   instead of multiplying by the inverse of M[1][1]. If there
00197       //   is any speed penalty at this point in history, the accuracy
00198       //   is more important than the additional clocks.
00199       //c = 1.0/M[1][1];
00200       //d *= c;
00201       //M[1][2] *= c; M[1][3] *= c;
00202       //ScaleRow( I, c, 1 );
00203       c = M[1][1];
00204       M[1][2] /= c; M[1][3] /= c;
00205       I[1][0] /= c; I[1][1] /= c; I[1][2] /= c; I[1][3] /= c;
00206       d /= c;
00207 
00208       x *= ON_EPSILON;
00209       if (fabs(M[0][1]) >  x) {
00210         c = -M[0][1];
00211         M[0][2] += c*M[1][2]; M[0][3] += c*M[1][3];
00212         AddCxRow( I, c, 1, 0 );
00213       }
00214       if (fabs(M[2][1]) >  x) {
00215         c = -M[2][1];
00216         M[2][2] += c*M[1][2]; M[2][3] += c*M[1][3];
00217         AddCxRow( I, c, 1, 2 );
00218       }
00219       if (fabs(M[3][1]) >  x) {
00220         c = -M[3][1];
00221         M[3][2] += c*M[1][2]; M[3][3] += c*M[1][3];
00222         AddCxRow( I, c, 1, 3 );
00223       }
00224 
00225       ix = jx = 2;
00226             x = fabs(M[2][2]);
00227       for ( i = 2; i < 4; i++ ) for ( j = 2; j < 4; j++ ) {
00228         if ( fabs(M[i][j]) > x ) {
00229           ix = i;
00230           jx = j;
00231           x = fabs(M[i][j]);
00232         }
00233       }
00234       if ( x < *pivot )
00235         *pivot = x;
00236       if ( ix != 2 ) {
00237         SwapRow( M, 2, ix );
00238         SwapRow( I, 2, ix );
00239         swapcount++;
00240       }
00241       if ( jx != 2 ) {
00242         SwapCol( M, 2, jx );
00243         col[2] = jx;
00244         swapcount++;
00245       }
00246       if ( x > 0.0 ) {
00247         rank++;
00248 
00249         // 17 August 2011 Dale Lear
00250         //   The result is slightly more accurate when using division
00251         //   instead of multiplying by the inverse of M[2][2]. If there
00252         //   is any speed penalty at this point in history, the accuracy
00253         //   is more important than the additional clocks.
00254         //c = 1.0/M[2][2];
00255         //d *= c;
00256         //M[2][3] *= c;
00257         //ScaleRow( I, c, 2 );
00258         c = M[2][2];
00259         M[2][3] /= c;
00260         I[2][0] /= c; I[2][1] /= c; I[2][2] /= c; I[2][3] /= c;
00261         d /= c;
00262 
00263         x *= ON_EPSILON;
00264         if (fabs(M[0][2]) >  x) {
00265           c = -M[0][2];
00266           M[0][3] += c*M[2][3];
00267           AddCxRow( I, c, 2, 0 );
00268         }
00269         if (fabs(M[1][2]) >  x) {
00270           c = -M[1][2];
00271           M[1][3] += c*M[2][3];
00272           AddCxRow( I, c, 2, 1 );
00273         }
00274         if (fabs(M[3][2]) >  x) {
00275           c = -M[3][2];
00276           M[3][3] += c*M[2][3];
00277           AddCxRow( I, c, 2, 3 );
00278         }
00279 
00280         x = fabs(M[3][3]);
00281         if ( x < *pivot )
00282           *pivot = x;
00283 
00284         if ( x > 0.0 ) {
00285           rank++;
00286 
00287           // 17 August 2011 Dale Lear
00288           //   The result is slightly more accurate when using division
00289           //   instead of multiplying by the inverse of M[3][3]. If there
00290           //   is any speed penalty at this point in history, the accuracy
00291           //   is more important than the additional clocks.
00292           //c = 1.0/M[3][3];
00293           //d *= c;
00294           //ScaleRow( I, c, 3 );
00295           c = M[3][3];
00296           I[3][0] /= c; I[3][1] /= c; I[3][2] /= c; I[3][3] /= c;
00297           d /= c;
00298 
00299           x *= ON_EPSILON;
00300           if (fabs(M[0][3]) >  x) {
00301             AddCxRow( I, -M[0][3], 3, 0 );
00302           }
00303           if (fabs(M[1][3]) >  x) {
00304             AddCxRow( I, -M[1][3], 3, 1 );
00305           }
00306           if (fabs(M[2][3]) >  x) {
00307             AddCxRow( I, -M[2][3], 3, 2 );
00308           }
00309 
00310           *determinant = (swapcount%2) ? -d : d;
00311         }
00312       }
00313     }
00314   }
00315 
00316   if ( col[3] != 3 )
00317     SwapRow( I, 3, col[3] );
00318   if ( col[2] != 2 )
00319     SwapRow( I, 2, col[2] );
00320   if ( col[1] != 1 )
00321     SwapRow( I, 1, col[1] );
00322   if ( col[0] != 0 )
00323     SwapRow( I, 0, col[0] );
00324 
00325   memcpy( dst, I, sizeof(I) );
00326         return rank;
00327 }
00328 
00330 //
00331 // ON_Xform constructors
00332 //
00333 
00334 ON_Xform::ON_Xform()
00335 {
00336   memset( m_xform, 0, sizeof(m_xform) );
00337   m_xform[3][3] = 1.0;
00338 }
00339 
00340 ON_Xform::ON_Xform( int d )
00341 {
00342   memset( m_xform, 0, sizeof(m_xform) );
00343   m_xform[0][0] = m_xform[1][1] = m_xform[2][2] = (double)d;
00344   m_xform[3][3] = 1.0;
00345 }
00346 
00347 ON_Xform::ON_Xform( double d )
00348 {
00349   memset( m_xform, 0, sizeof(m_xform) );
00350   m_xform[0][0] = m_xform[1][1] = m_xform[2][2] = d;
00351   m_xform[3][3] = 1.0;
00352 }
00353 
00354 #if defined(ON_COMPILER_MSC)
00355 ON_Xform::ON_Xform( double m[4][4] )
00356 {
00357   memcpy( &m_xform[0][0], &m[0][0], sizeof(m_xform) );
00358 }
00359 #endif
00360 
00361 ON_Xform::ON_Xform( const double m[4][4] )
00362 {
00363   memcpy( &m_xform[0][0], &m[0][0], sizeof(m_xform) );
00364 }
00365 
00366 #if defined(ON_COMPILER_MSC)
00367 ON_Xform::ON_Xform( float m[4][4] )
00368 {
00369   m_xform[0][0] = (double)m[0][0];
00370   m_xform[0][1] = (double)m[0][1];
00371   m_xform[0][2] = (double)m[0][2];
00372   m_xform[0][3] = (double)m[0][3];
00373 
00374   m_xform[1][0] = (double)m[1][0];
00375   m_xform[1][1] = (double)m[1][1];
00376   m_xform[1][2] = (double)m[1][2];
00377   m_xform[1][3] = (double)m[1][3];
00378 
00379   m_xform[2][0] = (double)m[2][0];
00380   m_xform[2][1] = (double)m[2][1];
00381   m_xform[2][2] = (double)m[2][2];
00382   m_xform[2][3] = (double)m[2][3];
00383 
00384   m_xform[3][0] = (double)m[3][0];
00385   m_xform[3][1] = (double)m[3][1];
00386   m_xform[3][2] = (double)m[3][2];
00387   m_xform[3][3] = (double)m[3][3];
00388 }
00389 #endif
00390 
00391 ON_Xform::ON_Xform( const float m[4][4] )
00392 {
00393   m_xform[0][0] = (double)m[0][0];
00394   m_xform[0][1] = (double)m[0][1];
00395   m_xform[0][2] = (double)m[0][2];
00396   m_xform[0][3] = (double)m[0][3];
00397 
00398   m_xform[1][0] = (double)m[1][0];
00399   m_xform[1][1] = (double)m[1][1];
00400   m_xform[1][2] = (double)m[1][2];
00401   m_xform[1][3] = (double)m[1][3];
00402 
00403   m_xform[2][0] = (double)m[2][0];
00404   m_xform[2][1] = (double)m[2][1];
00405   m_xform[2][2] = (double)m[2][2];
00406   m_xform[2][3] = (double)m[2][3];
00407 
00408   m_xform[3][0] = (double)m[3][0];
00409   m_xform[3][1] = (double)m[3][1];
00410   m_xform[3][2] = (double)m[3][2];
00411   m_xform[3][3] = (double)m[3][3];
00412 }
00413 
00414 ON_Xform::ON_Xform( const double* m )
00415 {
00416   memcpy( &m_xform[0][0], m, sizeof(m_xform) );
00417 }
00418 
00419 ON_Xform::ON_Xform( const float* m )
00420 {
00421   m_xform[0][0] = (double)m[0];
00422   m_xform[0][1] = (double)m[1];
00423   m_xform[0][2] = (double)m[2];
00424   m_xform[0][3] = (double)m[3];
00425 
00426   m_xform[1][0] = (double)m[4];
00427   m_xform[1][1] = (double)m[5];
00428   m_xform[1][2] = (double)m[6];
00429   m_xform[1][3] = (double)m[7];
00430 
00431   m_xform[2][0] = (double)m[8];
00432   m_xform[2][1] = (double)m[9];
00433   m_xform[2][2] = (double)m[10];
00434   m_xform[2][3] = (double)m[11];
00435 
00436   m_xform[3][0] = (double)m[12];
00437   m_xform[3][1] = (double)m[13];
00438   m_xform[3][2] = (double)m[14];
00439   m_xform[3][3] = (double)m[15];
00440 }
00441 
00442 ON_Xform::ON_Xform( const ON_3dPoint& P,
00443                                                                                                                  const ON_3dVector& X,
00444                                                                                                                  const ON_3dVector& Y,
00445                                                                                                                  const ON_3dVector& Z)
00446 {
00447   m_xform[0][0] = X[0];
00448   m_xform[1][0] = X[1];
00449   m_xform[2][0] = X[2];
00450   m_xform[3][0] = 0;
00451 
00452   m_xform[0][1] = Y[0];
00453   m_xform[1][1] = Y[1];
00454   m_xform[2][1] = Y[2];
00455   m_xform[3][1] = 0;
00456 
00457   m_xform[0][2] = Z[0];
00458   m_xform[1][2] = Z[1];
00459   m_xform[2][2] = Z[2];
00460   m_xform[3][2] = 0;
00461 
00462   m_xform[0][3] = P[0];
00463   m_xform[1][3] = P[1];
00464   m_xform[2][3] = P[2];
00465   m_xform[3][3] = 1;
00466 }
00467 
00468 ON_Xform::ON_Xform( const ON_Matrix& m )
00469 {
00470   *this = m;
00471 }
00472 
00474 //
00475 // ON_Xform operator[]
00476 //
00477 
00478 
00479 double* ON_Xform::operator[](int i)
00480 {
00481   return ( i >= 0 && i < 4 ) ? &m_xform[i][0] : NULL;
00482 }
00483 
00484 const double* ON_Xform::operator[](int i) const
00485 {
00486   return ( i >= 0 && i < 4 ) ? &m_xform[i][0] : NULL;
00487 }
00488 
00490 //
00491 // ON_Xform operator=
00492 //
00493 
00494 ON_Xform& ON_Xform::operator=( int d )
00495 {
00496   memset( m_xform, 0, sizeof(m_xform) );
00497   m_xform[0][0] = m_xform[1][1] = m_xform[2][2] = (double)d;
00498   m_xform[3][3] = 1.0;
00499   return *this;
00500 }
00501 
00502 ON_Xform& ON_Xform::operator=( float d )
00503 {
00504   memset( m_xform, 0, sizeof(m_xform) );
00505   m_xform[0][0] = m_xform[1][1] = m_xform[2][2] = (double)d;
00506   m_xform[3][3] = 1.0;
00507   return *this;
00508 }
00509 
00510 ON_Xform& ON_Xform::operator=( double d )
00511 {
00512   memset( m_xform, 0, sizeof(m_xform) );
00513   m_xform[0][0] = m_xform[1][1] = m_xform[2][2] = d;
00514   m_xform[3][3] = 1.0;
00515   return *this;
00516 }
00517   
00519 //
00520 // ON_Xform operator* operator- operator+
00521 //
00522 // All non-commutative operations have "this" as left hand side and
00523 // argument as right hand side.
00524 ON_Xform ON_Xform::operator*( const ON_Xform& rhs ) const
00525 {
00526   double m[4][4];
00527   const double* p = &rhs.m_xform[0][0];
00528 
00529   m[0][0] = m_xform[0][0]*p[0] + m_xform[0][1]*p[4] + m_xform[0][2]*p[ 8] + m_xform[0][3]*p[12];
00530   m[0][1] = m_xform[0][0]*p[1] + m_xform[0][1]*p[5] + m_xform[0][2]*p[ 9] + m_xform[0][3]*p[13];
00531   m[0][2] = m_xform[0][0]*p[2] + m_xform[0][1]*p[6] + m_xform[0][2]*p[10] + m_xform[0][3]*p[14];
00532   m[0][3] = m_xform[0][0]*p[3] + m_xform[0][1]*p[7] + m_xform[0][2]*p[11] + m_xform[0][3]*p[15];
00533 
00534   m[1][0] = m_xform[1][0]*p[0] + m_xform[1][1]*p[4] + m_xform[1][2]*p[ 8] + m_xform[1][3]*p[12];
00535   m[1][1] = m_xform[1][0]*p[1] + m_xform[1][1]*p[5] + m_xform[1][2]*p[ 9] + m_xform[1][3]*p[13];
00536   m[1][2] = m_xform[1][0]*p[2] + m_xform[1][1]*p[6] + m_xform[1][2]*p[10] + m_xform[1][3]*p[14];
00537   m[1][3] = m_xform[1][0]*p[3] + m_xform[1][1]*p[7] + m_xform[1][2]*p[11] + m_xform[1][3]*p[15];
00538 
00539   m[2][0] = m_xform[2][0]*p[0] + m_xform[2][1]*p[4] + m_xform[2][2]*p[ 8] + m_xform[2][3]*p[12];
00540   m[2][1] = m_xform[2][0]*p[1] + m_xform[2][1]*p[5] + m_xform[2][2]*p[ 9] + m_xform[2][3]*p[13];
00541   m[2][2] = m_xform[2][0]*p[2] + m_xform[2][1]*p[6] + m_xform[2][2]*p[10] + m_xform[2][3]*p[14];
00542   m[2][3] = m_xform[2][0]*p[3] + m_xform[2][1]*p[7] + m_xform[2][2]*p[11] + m_xform[2][3]*p[15];
00543 
00544   m[3][0] = m_xform[3][0]*p[0] + m_xform[3][1]*p[4] + m_xform[3][2]*p[ 8] + m_xform[3][3]*p[12];
00545   m[3][1] = m_xform[3][0]*p[1] + m_xform[3][1]*p[5] + m_xform[3][2]*p[ 9] + m_xform[3][3]*p[13];
00546   m[3][2] = m_xform[3][0]*p[2] + m_xform[3][1]*p[6] + m_xform[3][2]*p[10] + m_xform[3][3]*p[14];
00547   m[3][3] = m_xform[3][0]*p[3] + m_xform[3][1]*p[7] + m_xform[3][2]*p[11] + m_xform[3][3]*p[15];
00548 
00549   return ON_Xform(m);
00550 }
00551 
00552 ON_Xform ON_Xform::operator+( const ON_Xform& rhs ) const
00553 {
00554   double m[4][4];
00555   const double* p = &rhs.m_xform[0][0];
00556 
00557   m[0][0] = m_xform[0][0] + p[0];
00558   m[0][1] = m_xform[0][1] + p[1];
00559   m[0][2] = m_xform[0][2] + p[2];
00560   m[0][3] = m_xform[0][3] + p[3];
00561 
00562   m[1][0] = m_xform[1][0] + p[4];
00563   m[1][1] = m_xform[1][1] + p[5];
00564   m[1][2] = m_xform[1][2] + p[6];
00565   m[1][3] = m_xform[1][3] + p[7];
00566 
00567   m[2][0] = m_xform[2][0] + p[ 8];
00568   m[2][1] = m_xform[2][1] + p[ 9];
00569   m[2][2] = m_xform[2][2] + p[10];
00570   m[2][3] = m_xform[2][3] + p[11];
00571 
00572   m[3][0] = m_xform[3][0] + p[12];
00573   m[3][1] = m_xform[3][1] + p[13];
00574   m[3][2] = m_xform[3][2] + p[14];
00575   m[3][3] = m_xform[3][3] + p[15];
00576 
00577   return ON_Xform(m);
00578 }
00579 
00580 ON_Xform ON_Xform::operator-( const ON_Xform& rhs ) const
00581 {
00582   double m[4][4];
00583   const double* p = &rhs.m_xform[0][0];
00584 
00585   m[0][0] = m_xform[0][0] - p[0];
00586   m[0][1] = m_xform[0][1] - p[1];
00587   m[0][2] = m_xform[0][2] - p[2];
00588   m[0][3] = m_xform[0][3] - p[3];
00589 
00590   m[1][0] = m_xform[1][0] - p[4];
00591   m[1][1] = m_xform[1][1] - p[5];
00592   m[1][2] = m_xform[1][2] - p[6];
00593   m[1][3] = m_xform[1][3] - p[7];
00594 
00595   m[2][0] = m_xform[2][0] - p[ 8];
00596   m[2][1] = m_xform[2][1] - p[ 9];
00597   m[2][2] = m_xform[2][2] - p[10];
00598   m[2][3] = m_xform[2][3] - p[11];
00599 
00600   m[3][0] = m_xform[3][0] - p[12];
00601   m[3][1] = m_xform[3][1] - p[13];
00602   m[3][2] = m_xform[3][2] - p[14];
00603   m[3][3] = m_xform[3][3] - p[15];
00604 
00605   return ON_Xform(m);
00606 }
00607   
00609 //
00610 // ON_Xform
00611 //
00612 
00613 
00614 void ON_Xform::Zero()
00615 {
00616   memset( m_xform, 0, sizeof(m_xform) );
00617 }
00618 
00619 void ON_Xform::Identity()
00620 {
00621   memset( m_xform, 0, sizeof(m_xform) );
00622   m_xform[0][0] = m_xform[1][1] = m_xform[2][2] = m_xform[3][3] = 1.0;
00623 }
00624 
00625 void ON_Xform::Diagonal( double d )
00626 {
00627   memset( m_xform, 0, sizeof(m_xform) );
00628   m_xform[0][0] = m_xform[1][1] = m_xform[2][2] = d;
00629   m_xform[3][3] = 1.0;
00630 }
00631 
00632 void ON_Xform::Scale( double x, double y, double z )
00633 {
00634   memset( m_xform, 0, sizeof(m_xform) );
00635   m_xform[0][0] = x;
00636   m_xform[1][1] = y;
00637   m_xform[2][2] = z;
00638   m_xform[3][3] = 1.0;
00639 }
00640 
00641 void ON_Xform::Scale( const ON_3dVector& v )
00642 {
00643   memset( m_xform, 0, sizeof(m_xform) );
00644   m_xform[0][0] = v.x;
00645   m_xform[1][1] = v.y;
00646   m_xform[2][2] = v.z;
00647   m_xform[3][3] = 1.0;
00648 }
00649 
00650 void ON_Xform::Scale
00651   (
00652   ON_3dPoint fixed_point,
00653   double scale_factor
00654   )
00655 {
00656   if ( fixed_point.x == 0.0 && fixed_point.y == 0.0 && fixed_point.z == 0.0 )
00657   {
00658     Scale( scale_factor, scale_factor, scale_factor );
00659   }
00660   else
00661   {
00662     ON_Xform t0, t1, s;
00663     t0.Translation( ON_origin - fixed_point );
00664     s.Scale( scale_factor, scale_factor, scale_factor );
00665     t1.Translation( fixed_point - ON_origin );
00666     operator=(t1*s*t0);
00667   }
00668 }
00669 
00670 void ON_Xform::Scale
00671   (
00672   const ON_Plane& plane,
00673   double x_scale_factor,
00674   double y_scale_factor,
00675   double z_scale_factor
00676   )
00677 {
00678   Shear( plane, x_scale_factor*plane.xaxis, y_scale_factor*plane.yaxis, z_scale_factor*plane.zaxis );
00679 }
00680 
00681 void ON_Xform::Shear
00682   (
00683   const ON_Plane& plane,
00684   const ON_3dVector& x1,
00685   const ON_3dVector& y1,
00686   const ON_3dVector& z1
00687   )
00688 {
00689   ON_Xform t0, t1, s0(1), s1(1);
00690   t0.Translation( ON_origin - plane.origin );
00691   s0.m_xform[0][0] = plane.xaxis.x;
00692   s0.m_xform[0][1] = plane.xaxis.y;
00693   s0.m_xform[0][2] = plane.xaxis.z;
00694   s0.m_xform[1][0] = plane.yaxis.x;
00695   s0.m_xform[1][1] = plane.yaxis.y;
00696   s0.m_xform[1][2] = plane.yaxis.z;
00697   s0.m_xform[2][0] = plane.zaxis.x;
00698   s0.m_xform[2][1] = plane.zaxis.y;
00699   s0.m_xform[2][2] = plane.zaxis.z;
00700   s1.m_xform[0][0] = x1.x;
00701   s1.m_xform[1][0] = x1.y;
00702   s1.m_xform[2][0] = x1.z;
00703   s1.m_xform[0][1] = y1.x;
00704   s1.m_xform[1][1] = y1.y;
00705   s1.m_xform[2][1] = y1.z;
00706   s1.m_xform[0][2] = z1.x;
00707   s1.m_xform[1][2] = z1.y;
00708   s1.m_xform[2][2] = z1.z;
00709   t1.Translation( plane.origin - ON_origin );
00710   operator=(t1*s1*s0*t0);
00711 }
00712 
00713 void ON_Xform::Translation( double x, double y, double z )
00714 {
00715   Identity();
00716   m_xform[0][3] = x;
00717   m_xform[1][3] = y;
00718   m_xform[2][3] = z;
00719   m_xform[3][3] = 1.0;
00720 }
00721 
00722 void ON_Xform::Translation( const ON_3dVector& v )
00723 {
00724   Identity();
00725   m_xform[0][3] = v.x;
00726   m_xform[1][3] = v.y;
00727   m_xform[2][3] = v.z;
00728   m_xform[3][3] = 1.0;
00729 }
00730 
00731 void ON_Xform::PlanarProjection( const ON_Plane& plane )
00732 {
00733   int i, j;
00734   double x[3] = {plane.xaxis.x,plane.xaxis.y,plane.xaxis.z};
00735   double y[3] = {plane.yaxis.x,plane.yaxis.y,plane.yaxis.z};
00736   double p[3] = {plane.origin.x,plane.origin.y,plane.origin.z};
00737   double q[3];
00738   for ( i = 0; i < 3; i++ ) 
00739   {
00740     for ( j = 0; j < 3; j++ )
00741     {
00742       m_xform[i][j] = x[i]*x[j] + y[i]*y[j];
00743     }
00744     q[i] = m_xform[i][0]*p[0] + m_xform[i][1]*p[1] + m_xform[i][2]*p[2];
00745   }
00746   for ( i = 0; i < 3; i++ )
00747   {
00748     m_xform[3][i] = 0.0;
00749     m_xform[i][3] = p[i]-q[i];
00750   }
00751   m_xform[3][3] = 1.0;
00752 }
00753 
00755 //
00756 // ON_Xform
00757 //
00758 
00759 void ON_Xform::ActOnLeft(double x,double y,double z,double w,double v[4]) const
00760 {
00761   if ( v )
00762   {
00763     v[0] = m_xform[0][0]*x + m_xform[0][1]*y + m_xform[0][2]*z + m_xform[0][3]*w;
00764     v[1] = m_xform[1][0]*x + m_xform[1][1]*y + m_xform[1][2]*z + m_xform[1][3]*w;
00765     v[2] = m_xform[2][0]*x + m_xform[2][1]*y + m_xform[2][2]*z + m_xform[2][3]*w;
00766     v[3] = m_xform[3][0]*x + m_xform[3][1]*y + m_xform[3][2]*z + m_xform[3][3]*w;
00767   }
00768 }
00769 
00770 void ON_Xform::ActOnRight(double x,double y,double z,double w,double v[4]) const
00771 {
00772   if ( v )
00773   {
00774     v[0] = m_xform[0][0]*x + m_xform[1][0]*y + m_xform[2][0]*z + m_xform[3][0]*w;
00775     v[1] = m_xform[0][1]*x + m_xform[1][1]*y + m_xform[2][1]*z + m_xform[3][1]*w;
00776     v[2] = m_xform[0][2]*x + m_xform[1][2]*y + m_xform[2][2]*z + m_xform[3][2]*w;
00777     v[3] = m_xform[0][3]*x + m_xform[1][3]*y + m_xform[2][3]*z + m_xform[3][3]*w;
00778   }
00779 }
00780 
00781 ON_2dPoint ON_Xform::operator*( const ON_2dPoint& p ) const
00782 {
00783   const double x = p.x; // optimizer should put x,y in registers
00784   const double y = p.y;
00785   double xh[2], w;
00786   const double* m = &m_xform[0][0];
00787   xh[0] = m[ 0]*x + m[ 1]*y + m[ 3];
00788   xh[1] = m[ 4]*x + m[ 5]*y + m[ 7];
00789   w     = m[12]*x + m[13]*y + m[15];
00790   w = (w != 0.0) ? 1.0/w : 1.0;
00791   return ON_2dPoint( w*xh[0], w*xh[1] );
00792 }
00793 
00794 ON_3dPoint ON_Xform::operator*( const ON_3dPoint& p ) const
00795 {
00796   const double x = p.x; // optimizer should put x,y,z in registers
00797   const double y = p.y;
00798   const double z = p.z;
00799   double xh[3], w;
00800   const double* m = &m_xform[0][0];
00801   xh[0] = m[ 0]*x + m[ 1]*y + m[ 2]*z + m[ 3];
00802   xh[1] = m[ 4]*x + m[ 5]*y + m[ 6]*z + m[ 7];
00803   xh[2] = m[ 8]*x + m[ 9]*y + m[10]*z + m[11];
00804   w     = m[12]*x + m[13]*y + m[14]*z + m[15];
00805   w = (w != 0.0) ? 1.0/w : 1.0;
00806   return ON_3dPoint( w*xh[0], w*xh[1], w*xh[2] );
00807 }
00808 
00809 ON_4dPoint ON_Xform::operator*( const ON_4dPoint& h ) const
00810 {
00811   const double x = h.x; // optimizer should put x,y,z,w in registers
00812   const double y = h.y;
00813   const double z = h.z;
00814   const double w = h.w;
00815   double xh[4];
00816   const double* m = &m_xform[0][0];
00817   xh[0] = m[ 0]*x + m[ 1]*y + m[ 2]*z + m[ 3]*w;
00818   xh[1] = m[ 4]*x + m[ 5]*y + m[ 6]*z + m[ 7]*w;
00819   xh[2] = m[ 8]*x + m[ 9]*y + m[10]*z + m[11]*w;
00820   xh[3] = m[12]*x + m[13]*y + m[14]*z + m[15]*w;
00821   return ON_4dPoint( xh[0],xh[1],xh[2],xh[3] );
00822 }
00823 
00824 ON_2dVector ON_Xform::operator*( const ON_2dVector& v ) const
00825 {
00826   const double x = v.x; // optimizer should put x,y in registers
00827   const double y = v.y;
00828   double xh[2];
00829   const double* m = &m_xform[0][0];
00830   xh[0] = m[0]*x + m[1]*y;
00831   xh[1] = m[4]*x + m[5]*y;
00832   return ON_2dVector( xh[0],xh[1] );
00833 }
00834 
00835 ON_3dVector ON_Xform::operator*( const ON_3dVector& v ) const
00836 {
00837   const double x = v.x; // optimizer should put x,y,z in registers
00838   const double y = v.y;
00839   const double z = v.z;
00840   double xh[3];
00841   const double* m = &m_xform[0][0];
00842   xh[0] = m[0]*x + m[1]*y + m[ 2]*z;
00843   xh[1] = m[4]*x + m[5]*y + m[ 6]*z;
00844   xh[2] = m[8]*x + m[9]*y + m[10]*z;
00845   return ON_3dVector( xh[0],xh[1],xh[2] );
00846 }
00847 
00848 bool ON_Xform::IsValid() const
00849 {
00850   int i;
00851   const double* x = &m_xform[0][0];
00852   bool rc = true;
00853   for (i = 0; i < 16 && rc; i++)
00854   {
00855     rc = ON_IsValid(*x++);
00856   }
00857   return rc;
00858 }
00859 
00860 bool ON_Xform::IsIdentity( double zero_tolerance ) const
00861 {
00862   // The code below will return false if m_xform[][] contains
00863   // a nan value.
00864   const double* v = &m_xform[0][0];
00865   for ( int i = 0; i < 3; i++ )
00866   {
00867     if ( !(fabs(1.0 - *v++) <= zero_tolerance) )
00868       return false;
00869     if ( !(fabs(*v++) <= zero_tolerance) )
00870       return false;
00871     if ( !(fabs(*v++) <= zero_tolerance) )
00872       return false;
00873     if ( !(fabs(*v++) <= zero_tolerance) )
00874       return false;
00875     if ( !(fabs(*v++) <= zero_tolerance) )
00876       return false;
00877   }
00878   if ( !(fabs( 1.0 - *v ) <= zero_tolerance) )
00879     return false;
00880   return true;
00881 }
00882 
00883 bool ON_Xform::IsNotIdentity( double zero_tolerance ) const
00884 {
00885   // The code below will return false if m_xform[][] contains
00886   // a nan value.
00887   const double* v = &m_xform[0][0];
00888   for ( int i = 0; i < 3; i++ )
00889   {
00890     if ( fabs(1.0 - *v++) > zero_tolerance )
00891       return true;
00892     if ( fabs(*v++) > zero_tolerance )
00893       return true;
00894     if ( fabs(*v++) > zero_tolerance )
00895       return true;
00896     if ( fabs(*v++) > zero_tolerance )
00897       return true;
00898     if ( fabs(*v++) > zero_tolerance )
00899       return true;
00900   }
00901   if ( fabs( 1.0 - *v ) > zero_tolerance )
00902     return true;
00903 
00904   return false;
00905 }
00906 
00907 bool ON_Xform::IsTranslation( double zero_tolerance ) const
00908 {
00909   const double* v = &m_xform[0][0];
00910   if ( fabs(1.0 - *v++) > zero_tolerance )
00911     return false;
00912   if ( fabs(*v++) >  zero_tolerance )
00913     return false;
00914   if ( fabs(*v++) >  zero_tolerance )
00915     return false;
00916   v++;
00917   if ( fabs(*v++) >  zero_tolerance )
00918     return false;
00919   if ( fabs(1.0 - *v++) > zero_tolerance )
00920     return false;
00921   if ( fabs(*v++) >  zero_tolerance )
00922     return false;
00923   v++;
00924   if ( fabs(*v++) >  zero_tolerance )
00925     return false;
00926   if ( fabs(*v++) >  zero_tolerance )
00927     return false;
00928   if ( fabs(1.0 - *v++) > zero_tolerance )
00929     return false;
00930   v++;
00931   if ( fabs(*v++) >  zero_tolerance )
00932     return false;
00933   if ( fabs(*v++) >  zero_tolerance )
00934     return false;
00935   if ( fabs(*v++) >  zero_tolerance )
00936     return false;
00937   if ( fabs( 1.0 - *v ) > zero_tolerance )
00938     return false;
00939   return true;
00940 }
00941 
00942 
00943 int ON_Xform::Compare( const ON_Xform& other ) const
00944 {
00945   const double* a = &m_xform[0][0];
00946   const double* b = &other.m_xform[0][0];
00947   int i = 16;
00948   while(i--)
00949   {
00950     if ( *a < *b )
00951       return -1;
00952     if ( *a > *b )
00953       return 1;
00954     a++;
00955     b++;
00956   }
00957   return 0;
00958 }
00959 
00960 int ON_Xform::IsSimilarity() const
00961 {
00962   int rc = 0;
00963   if (    m_xform[3][0] != 0.0 
00964        || m_xform[3][1] != 0.0
00965        || m_xform[3][2] != 0.0
00966        || m_xform[3][3] != 1.0 )
00967   {
00968     rc = 0;
00969   }
00970   else
00971   {
00972     double tol = 1.0e-4;
00973     double dottol = 1.0e-3;
00974     double det = Determinant();
00975     if ( fabs(det) <= ON_SQRT_EPSILON )
00976     {
00977       // projection or worse
00978       rc = 0;
00979     }
00980     else
00981     {
00982       ON_3dVector X(m_xform[0][0],m_xform[1][0],m_xform[2][0]);
00983       ON_3dVector Y(m_xform[0][1],m_xform[1][1],m_xform[2][1]);
00984       ON_3dVector Z(m_xform[0][2],m_xform[1][2],m_xform[2][2]);
00985       double sx = X.Length();
00986       double sy = Y.Length();
00987       double sz = Z.Length();
00988       if (   sx == 0.0 || sy == 0.0 || sz == 0.0 
00989           || fabs(sx-sy) > tol || fabs(sy-sz) > tol || fabs(sz-sx) > tol )
00990       {
00991         // non-uniform scale or worse
00992         rc = 0;
00993       }
00994       else
00995       {
00996         double xy = (X*Y)/(sx*sy);
00997         double yz = (Y*Z)/(sy*sz);
00998         double zx = (Z*X)/(sz*sx);
00999         if ( fabs(xy) > dottol || fabs(yz) > dottol || fabs(zx) > dottol )
01000         {
01001           // shear or worse
01002           rc = 0;
01003         }
01004         else
01005         {
01006           rc = (det > 0.0) ? 1 : -1;
01007         }
01008       }
01009     }
01010   }
01011   return rc;
01012 }
01013 
01014 
01015 bool ON_Xform::IsZero() const
01016 {
01017   const double* v = &m_xform[0][0];
01018   for ( int i = 0; i < 15; i++ )
01019   {
01020     if ( *v++ != 0.0 )
01021       return false;
01022   }
01023   return true;
01024 }
01025 
01026 
01027 void ON_Xform::Transpose()
01028 {
01029   double t;
01030   t = m_xform[0][1]; m_xform[0][1] = m_xform[1][0]; m_xform[1][0] = t;
01031   t = m_xform[0][2]; m_xform[0][2] = m_xform[2][0]; m_xform[2][0] = t;
01032   t = m_xform[0][3]; m_xform[0][3] = m_xform[3][0]; m_xform[3][0] = t;
01033   t = m_xform[1][2]; m_xform[1][2] = m_xform[2][1]; m_xform[2][1] = t;
01034   t = m_xform[1][3]; m_xform[1][3] = m_xform[3][1]; m_xform[3][1] = t;
01035   t = m_xform[2][3]; m_xform[2][3] = m_xform[3][2]; m_xform[3][2] = t;
01036 }
01037 
01038 int ON_Xform::Rank( double* pivot ) const
01039 {
01040   double I[4][4], d = 0.0, p = 0.0;
01041   int r = Inv( &m_xform[0][0], I, &d, &p );
01042   if ( pivot )
01043     *pivot = p;
01044   return r;
01045 }
01046 
01047 double ON_Xform::Determinant( double* pivot ) const
01048 {
01049   double I[4][4], d = 0.0, p = 0.0;
01050   //int rank = 
01051   Inv( &m_xform[0][0], I, &d, &p );
01052   if ( pivot )
01053     *pivot = p;
01054   if (d != 0.0 )
01055     d = 1.0/d;
01056   return d;
01057 }
01058 
01059 bool ON_Xform::Invert( double* pivot )
01060 {
01061   double mrofx[4][4], d = 0.0, p = 0.0;
01062   int rank = Inv( &m_xform[0][0], mrofx, &d, &p );
01063   memcpy( m_xform, mrofx, sizeof(m_xform) );
01064   if ( pivot )
01065     *pivot = p;
01066   return (rank == 4) ? true : false;
01067 }
01068 
01069 ON_Xform ON_Xform::Inverse( double* pivot ) const
01070 {
01071   ON_Xform inv;
01072   double d = 0.0, p = 0.0;
01073   //int rank = 
01074   Inv( &m_xform[0][0], inv.m_xform, &d, &p );
01075   if ( pivot )
01076     *pivot = p;
01077   return inv;
01078 }
01079 
01080 double ON_Xform::GetSurfaceNormalXform( ON_Xform& N_xform ) const
01081 {
01082   // since were are transforming vectors, we don't need
01083   // the translation column or bottom row.
01084   memcpy(&N_xform.m_xform[0][0],&m_xform[0][0], 3*sizeof(N_xform.m_xform[0][0]) );
01085   N_xform.m_xform[0][3] = 0.0;
01086   memcpy(&N_xform.m_xform[1][0],&m_xform[1][0], 3*sizeof(N_xform.m_xform[0][0]) );
01087   N_xform.m_xform[1][3] = 0.0;
01088   memcpy(&N_xform.m_xform[2][0],&m_xform[2][0], 3*sizeof(N_xform.m_xform[0][0]) );
01089   N_xform.m_xform[2][3] = 0.0;
01090   N_xform.m_xform[3][0] = 0.0;
01091   N_xform.m_xform[3][1] = 0.0;
01092   N_xform.m_xform[3][2] = 0.0;
01093   N_xform.m_xform[3][3] = 1.0;
01094 
01095   double mrofx[4][4], d = 0.0, p = 0.0;
01096   double dtol = ON_SQRT_EPSILON*ON_SQRT_EPSILON*ON_SQRT_EPSILON;
01097   if ( 4 == Inv( &N_xform.m_xform[0][0], mrofx, &d, &p ) 
01098        && fabs(d) > dtol 
01099        && fabs(d)*dtol < 1.0
01100        && fabs(p) > ON_EPSILON*fabs(d)
01101      )
01102   {
01103     // Set N_xform = transpose of mrofx (only upper 3x3 matters)
01104     N_xform.m_xform[0][0] = mrofx[0][0];
01105     N_xform.m_xform[0][1] = mrofx[1][0]; 
01106     N_xform.m_xform[0][2] = mrofx[2][0];
01107 
01108     N_xform.m_xform[1][0] = mrofx[0][1];
01109     N_xform.m_xform[1][1] = mrofx[1][1];
01110     N_xform.m_xform[1][2] = mrofx[2][1];
01111 
01112     N_xform.m_xform[2][0] = mrofx[0][2];
01113     N_xform.m_xform[2][1] = mrofx[1][2];
01114     N_xform.m_xform[2][2] = mrofx[2][2];
01115   }
01116   else
01117   {
01118     d = 0.0;
01119   }
01120   return d;
01121 }
01122 
01123 double ON_Xform::GetMappingXforms( ON_Xform& P_xform, ON_Xform& N_xform ) const
01124 {
01125   double d = 0.0, p = 0.0;
01126   double dtol = ON_SQRT_EPSILON*ON_SQRT_EPSILON*ON_SQRT_EPSILON;
01127   if ( 4 == Inv( &m_xform[0][0], P_xform.m_xform, &d, &p ) 
01128        && fabs(d) > dtol 
01129        && fabs(d)*dtol < 1.0
01130        && fabs(p) > ON_EPSILON*fabs(d)
01131      )
01132   {
01133     // Set N_xform = transpose of this (only upper 3x3 matters)
01134     N_xform.m_xform[0][0] = m_xform[0][0];
01135     N_xform.m_xform[0][1] = m_xform[1][0]; 
01136     N_xform.m_xform[0][2] = m_xform[2][0];
01137     N_xform.m_xform[0][3] = 0.0;
01138 
01139     N_xform.m_xform[1][0] = m_xform[0][1];
01140     N_xform.m_xform[1][1] = m_xform[1][1];
01141     N_xform.m_xform[1][2] = m_xform[2][1];
01142     N_xform.m_xform[1][3] = 0.0;
01143 
01144     N_xform.m_xform[2][0] = m_xform[0][2];
01145     N_xform.m_xform[2][1] = m_xform[1][2];
01146     N_xform.m_xform[2][2] = m_xform[2][2];
01147     N_xform.m_xform[2][3] = 0.0;
01148 
01149     N_xform.m_xform[3][0] = 0.0;
01150     N_xform.m_xform[3][1] = 0.0;
01151     N_xform.m_xform[3][2] = 0.0;
01152     N_xform.m_xform[3][3] = 1.0;
01153   }
01154   else
01155   {
01156     P_xform.Identity();
01157     N_xform.Identity();
01158     d = 0.0;
01159   }
01160   return d;
01161 }
01162 
01163 
01164 void ON_Xform::Rotation( 
01165         double angle,
01166         ON_3dVector axis,  // 3d nonzero axis of rotation
01167         ON_3dPoint center  // 3d center of rotation
01168         )
01169 {
01170   Rotation( sin(angle), cos(angle), axis, center );
01171 }
01172 
01173 void ON_Xform::Rotation(
01174   ON_3dVector start_dir,
01175   ON_3dVector end_dir,
01176   ON_3dPoint rotation_center
01177   )
01178 {
01179   if ( fabs(start_dir.Length()-1.0) > ON_SQRT_EPSILON )
01180     start_dir.Unitize();
01181   if ( fabs(end_dir.Length()-1.0) > ON_SQRT_EPSILON )
01182     end_dir.Unitize();
01183   double cos_angle = start_dir*end_dir;
01184   ON_3dVector axis = ON_CrossProduct(start_dir,end_dir);
01185   double sin_angle = axis.Length();
01186   if ( 0.0 == sin_angle || !axis.Unitize() )
01187   {
01188     axis.PerpendicularTo(start_dir);
01189     axis.Unitize();
01190     sin_angle = 0.0;
01191     cos_angle = (cos_angle < 0.0) ? -1.0 : 1.0;
01192   }
01193   Rotation(sin_angle,cos_angle,axis,rotation_center);
01194 }
01195 
01196 void ON_Xform::Rotation(  
01197         double sin_angle,
01198         double cos_angle,
01199         ON_3dVector axis,
01200         ON_3dPoint center
01201         )
01202 {
01203   Identity();
01204 
01205   for(;;)
01206   {
01207     // 29 June 2005 Dale Lear
01208     //     Kill noise in input
01209     if ( fabs(sin_angle) >= 1.0-ON_SQRT_EPSILON && fabs(cos_angle) <= ON_SQRT_EPSILON )
01210     {
01211       cos_angle = 0.0;
01212       sin_angle = (sin_angle < 0.0) ? -1.0 : 1.0; 
01213       break;
01214     }
01215     
01216     if ( fabs(cos_angle) >= 1.0-ON_SQRT_EPSILON && fabs(sin_angle) <= ON_SQRT_EPSILON )
01217     {
01218       cos_angle = (cos_angle < 0.0) ? -1.0 : 1.0; 
01219       sin_angle = 0.0;
01220       break;
01221     }
01222     
01223     if ( fabs(cos_angle*cos_angle + sin_angle*sin_angle - 1.0) > ON_SQRT_EPSILON )
01224     {
01225       ON_2dVector cs(cos_angle,sin_angle);
01226       if ( cs.Unitize() )
01227       {
01228         cos_angle = cs.x;
01229         sin_angle = cs.y;
01230         // no break here
01231       }
01232       else
01233       {
01234         ON_ERROR("sin_angle and cos_angle are both zero.");
01235         cos_angle = 1.0;
01236         sin_angle = 0.0;
01237         break;
01238       }
01239     }
01240 
01241     if ( fabs(cos_angle) > 1.0-ON_EPSILON || fabs(sin_angle) < ON_EPSILON )
01242     {
01243       cos_angle = (cos_angle < 0.0) ? -1.0 : 1.0; 
01244       sin_angle = 0.0;
01245       break;
01246     }
01247 
01248     if ( fabs(sin_angle) > 1.0-ON_EPSILON || fabs(cos_angle) < ON_EPSILON )
01249     {
01250       cos_angle = 0.0;
01251       sin_angle = (sin_angle < 0.0) ? -1.0 : 1.0; 
01252       break;
01253     }
01254 
01255     break;
01256   }
01257 
01258   if (sin_angle != 0.0 || cos_angle != 1.0) 
01259   {
01260     const double one_minus_cos_angle = 1.0 - cos_angle;
01261     ON_3dVector a = axis;
01262     if ( fabs(a.LengthSquared() - 1.0) >  ON_EPSILON )
01263       a.Unitize();
01264 
01265     m_xform[0][0] = a.x*a.x*one_minus_cos_angle + cos_angle;
01266     m_xform[0][1] = a.x*a.y*one_minus_cos_angle - a.z*sin_angle;
01267     m_xform[0][2] = a.x*a.z*one_minus_cos_angle + a.y*sin_angle;
01268 
01269     m_xform[1][0] = a.y*a.x*one_minus_cos_angle + a.z*sin_angle;
01270     m_xform[1][1] = a.y*a.y*one_minus_cos_angle + cos_angle;
01271     m_xform[1][2] = a.y*a.z*one_minus_cos_angle - a.x*sin_angle;
01272 
01273     m_xform[2][0] = a.z*a.x*one_minus_cos_angle - a.y*sin_angle;
01274     m_xform[2][1] = a.z*a.y*one_minus_cos_angle + a.x*sin_angle;
01275     m_xform[2][2] = a.z*a.z*one_minus_cos_angle + cos_angle;
01276 
01277     if ( center.x != 0.0 || center.y != 0.0 || center.z != 0.0 ) {
01278       m_xform[0][3] = -((m_xform[0][0]-1.0)*center.x + m_xform[0][1]*center.y + m_xform[0][2]*center.z);
01279       m_xform[1][3] = -(m_xform[1][0]*center.x + (m_xform[1][1]-1.0)*center.y + m_xform[1][2]*center.z);
01280       m_xform[2][3] = -(m_xform[2][0]*center.x + m_xform[2][1]*center.y + (m_xform[2][2]-1.0)*center.z);
01281     }
01282 
01283     m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0;
01284     m_xform[3][3] = 1.0;
01285   }
01286 }
01287 
01288 
01289 void ON_Xform::Rotation(
01290   const ON_3dVector&  X0, // initial frame X (X,Y,Z = right handed orthonormal frame)
01291   const ON_3dVector&  Y0, // initial frame Y
01292   const ON_3dVector&  Z0, // initial frame Z
01293   const ON_3dVector&  X1, // final frame X (X,Y,Z = another right handed orthonormal frame)
01294   const ON_3dVector&  Y1, // final frame Y
01295   const ON_3dVector&  Z1  // final frame Z
01296   )
01297 {
01298   // transformation maps X0 to X1, Y0 to Y1, Z0 to Z1
01299 
01300   // F0 changes x0,y0,z0 to world X,Y,Z
01301   ON_Xform F0;
01302   F0[0][0] = X0.x; F0[0][1] = X0.y; F0[0][2] = X0.z;
01303   F0[1][0] = Y0.x; F0[1][1] = Y0.y; F0[1][2] = Y0.z;
01304   F0[2][0] = Z0.x; F0[2][1] = Z0.y; F0[2][2] = Z0.z;
01305   F0[3][3] = 1.0;
01306 
01307   // F1 changes world X,Y,Z to x1,y1,z1
01308   ON_Xform F1;
01309   F1[0][0] = X1.x; F1[0][1] = Y1.x; F1[0][2] = Z1.x;
01310   F1[1][0] = X1.y; F1[1][1] = Y1.y; F1[1][2] = Z1.y;
01311   F1[2][0] = X1.z; F1[2][1] = Y1.z; F1[2][2] = Z1.z;
01312   F1[3][3] = 1.0;
01313 
01314   *this = F1*F0;
01315 }
01316 
01317 void ON_Xform::Rotation( 
01318   const ON_Plane& plane0,
01319   const ON_Plane& plane1
01320   )
01321 {
01322   Rotation( 
01323     plane0.origin, plane0.xaxis, plane0.yaxis, plane0.zaxis,
01324     plane1.origin, plane1.xaxis, plane1.yaxis, plane1.zaxis
01325     );
01326 }
01327 
01328 
01329 void ON_Xform::Rotation(   // (not strictly a rotation)
01330                             // transformation maps P0 to P1, P0+X0 to P1+X1, ...
01331   const ON_3dPoint&   P0,  // initial frame center
01332   const ON_3dVector&  X0, // initial frame X
01333   const ON_3dVector&  Y0, // initial frame Y
01334   const ON_3dVector&  Z0, // initial frame Z
01335   const ON_3dPoint&   P1,  // final frame center
01336   const ON_3dVector&  X1, // final frame X
01337   const ON_3dVector&  Y1, // final frame Y
01338   const ON_3dVector&  Z1  // final frame Z
01339   )
01340 {
01341   // transformation maps P0 to P1, P0+X0 to P1+X1, ...
01342 
01343   // T0 translates point P0 to (0,0,0)
01344   ON_Xform T0;
01345   T0.Translation( -P0.x, -P0.y, -P0.z );
01346 
01347   ON_Xform R;
01348   R.Rotation(X0,Y0,Z0,X1,Y1,Z1);
01349 
01350   // T1 translates (0,0,0) to point o1
01351   ON_Xform T1;
01352   T1.Translation( P1 );
01353 
01354   *this = T1*R*T0;
01355 }
01356 
01357 void ON_Xform::Mirror(
01358   ON_3dPoint point_on_mirror_plane,
01359   ON_3dVector normal_to_mirror_plane
01360   )
01361 {
01362   ON_3dPoint P = point_on_mirror_plane;
01363   ON_3dVector N = normal_to_mirror_plane;
01364   N.Unitize();
01365   ON_3dVector V = (2.0*(N.x*P.x + N.y*P.y + N.z*P.z))*N;
01366   m_xform[0][0] = 1 - 2.0*N.x*N.x;
01367   m_xform[0][1] = -2.0*N.x*N.y;
01368   m_xform[0][2] = -2.0*N.x*N.z;
01369   m_xform[0][3] = V.x;
01370 
01371   m_xform[1][0] = -2.0*N.y*N.x;
01372   m_xform[1][1] = 1.0 -2.0*N.y*N.y;
01373   m_xform[1][2] = -2.0*N.y*N.z;
01374   m_xform[1][3] = V.y;
01375 
01376   m_xform[2][0] = -2.0*N.z*N.x;
01377   m_xform[2][1] = -2.0*N.z*N.y;
01378   m_xform[2][2] = 1.0 -2.0*N.z*N.z;
01379   m_xform[2][3] = V.z;
01380 
01381   m_xform[3][0] = 0.0;
01382   m_xform[3][1] = 0.0;
01383   m_xform[3][2] = 0.0;
01384   m_xform[3][3] = 1.0;
01385 }
01386 
01387 
01388 
01389 bool ON_Xform::ChangeBasis( 
01390   // General: If you have points defined with respect to planes, this
01391   //          computes the transformation to change coordinates from
01392   //          one plane to another.  The predefined world plane
01393   //          ON_world_plane can be used as an argument.
01394   // Details: If P = plane0.Evaluate( a0,b0,c0 ) and
01395   //          {a1,b1,c1} = ChangeBasis(plane0,plane1)*ON_3dPoint(a0,b0,c0),
01396   //          then P = plane1.Evaluate( a1, b1, c1 )
01397   //          
01398   const ON_Plane& plane0, // initial plane
01399   const ON_Plane& plane1  // final plane
01400   )
01401 {
01402   return ChangeBasis( 
01403     plane0.origin, plane0.xaxis, plane0.yaxis, plane0.zaxis,
01404     plane1.origin, plane1.xaxis, plane1.yaxis, plane1.zaxis
01405     );
01406 }
01407 
01408 
01409 bool ON_Xform::ChangeBasis(
01410   const ON_3dVector&  X0, // initial frame X (X,Y,Z = arbitrary basis)
01411   const ON_3dVector&  Y0, // initial frame Y
01412   const ON_3dVector&  Z0, // initial frame Z
01413   const ON_3dVector&  X1, // final frame X (X,Y,Z = arbitrary basis)
01414   const ON_3dVector&  Y1, // final frame Y
01415   const ON_3dVector&  Z1  // final frame Z
01416   )
01417 {
01418   // Q = a0*X0 + b0*Y0 + c0*Z0 = a1*X1 + b1*Y1 + c1*Z1
01419   // then this transform will map the point (a0,b0,c0) to (a1,b1,c1)
01420 
01421   Zero();
01422   m_xform[3][3] = 1.0;
01423   double a,b,c,d;
01424   a = X1*Y1;
01425   b = X1*Z1;
01426   c = Y1*Z1;
01427   double R[3][6] = {{X1*X1,      a,      b,       X1*X0, X1*Y0, X1*Z0},
01428                     {    a,  Y1*Y1,      c,       Y1*X0, Y1*Y0, Y1*Z0},
01429                     {    b,      c,  Z1*Z1,       Z1*X0, Z1*Y0, Z1*Z0}};
01430   //double R[3][6] = {{X1*X1,      a,      b,       X0*X1, X0*Y1, X0*Z1},
01431   //                  {    a,  Y1*Y1,      c,       Y0*X1, Y0*Y1, Y0*Z1},
01432   //                  {    b,      c,  Z1*Z1,       Z0*X1, Z0*Y1, Z0*Z1}};
01433 
01434   // row reduce R
01435   int i0 = (R[0][0] >= R[1][1]) ? 0 : 1;
01436   if ( R[2][2] > R[i0][i0] )
01437     i0 = 2;
01438   int i1 = (i0+1)%3;
01439   int i2 = (i1+1)%3;
01440   if ( R[i0][i0] == 0.0 )
01441     return false;
01442   d = 1.0/R[i0][i0];
01443   R[i0][0] *= d;
01444   R[i0][1] *= d;
01445   R[i0][2] *= d;
01446   R[i0][3] *= d;
01447   R[i0][4] *= d;
01448   R[i0][5] *= d;
01449   R[i0][i0] = 1.0;
01450   if ( R[i1][i0] != 0.0 ) {
01451     d = -R[i1][i0];
01452     R[i1][0] += d*R[i0][0];
01453     R[i1][1] += d*R[i0][1];
01454     R[i1][2] += d*R[i0][2];
01455     R[i1][3] += d*R[i0][3];
01456     R[i1][4] += d*R[i0][4];
01457     R[i1][5] += d*R[i0][5];
01458     R[i1][i0] = 0.0;
01459   }
01460   if ( R[i2][i0] != 0.0 ) {
01461     d = -R[i2][i0];
01462     R[i2][0] += d*R[i0][0];
01463     R[i2][1] += d*R[i0][1];
01464     R[i2][2] += d*R[i0][2];
01465     R[i2][3] += d*R[i0][3];
01466     R[i2][4] += d*R[i0][4];
01467     R[i2][5] += d*R[i0][5];
01468     R[i2][i0] = 0.0;
01469   }
01470 
01471   if ( fabs(R[i1][i1]) < fabs(R[i2][i2]) ) {
01472     int i = i1; i1 = i2; i2 = i;
01473   }
01474   if ( R[i1][i1] == 0.0 )
01475     return false;
01476   d = 1.0/R[i1][i1];
01477   R[i1][0] *= d;
01478   R[i1][1] *= d;
01479   R[i1][2] *= d;
01480   R[i1][3] *= d;
01481   R[i1][4] *= d;
01482   R[i1][5] *= d;
01483   R[i1][i1] = 1.0;
01484   if ( R[i0][i1] != 0.0 ) {
01485     d = -R[i0][i1];
01486     R[i0][0] += d*R[i1][0];
01487     R[i0][1] += d*R[i1][1];
01488     R[i0][2] += d*R[i1][2];
01489     R[i0][3] += d*R[i1][3];
01490     R[i0][4] += d*R[i1][4];
01491     R[i0][5] += d*R[i1][5];
01492     R[i0][i1] = 0.0;
01493   }
01494   if ( R[i2][i1] != 0.0 ) {
01495     d = -R[i2][i1];
01496     R[i2][0] += d*R[i1][0];
01497     R[i2][1] += d*R[i1][1];
01498     R[i2][2] += d*R[i1][2];
01499     R[i2][3] += d*R[i1][3];
01500     R[i2][4] += d*R[i1][4];
01501     R[i2][5] += d*R[i1][5];
01502     R[i2][i1] = 0.0;
01503   }
01504 
01505   if ( R[i2][i2] == 0.0 )
01506     return false;
01507   d = 1.0/R[i2][i2];
01508   R[i2][0] *= d;
01509   R[i2][1] *= d;
01510   R[i2][2] *= d;
01511   R[i2][3] *= d;
01512   R[i2][4] *= d;
01513   R[i2][5] *= d;
01514   R[i2][i2] = 1.0;
01515   if ( R[i0][i2] != 0.0 ) {
01516     d = -R[i0][i2];
01517     R[i0][0] += d*R[i2][0];
01518     R[i0][1] += d*R[i2][1];
01519     R[i0][2] += d*R[i2][2];
01520     R[i0][3] += d*R[i2][3];
01521     R[i0][4] += d*R[i2][4];
01522     R[i0][5] += d*R[i2][5];
01523     R[i0][i2] = 0.0;
01524   }
01525   if ( R[i1][i2] != 0.0 ) {
01526     d = -R[i1][i2];
01527     R[i1][0] += d*R[i2][0];
01528     R[i1][1] += d*R[i2][1];
01529     R[i1][2] += d*R[i2][2];
01530     R[i1][3] += d*R[i2][3];
01531     R[i1][4] += d*R[i2][4];
01532     R[i1][5] += d*R[i2][5];
01533     R[i1][i2] = 0.0;
01534   }
01535 
01536   m_xform[0][0] = R[0][3];
01537   m_xform[0][1] = R[0][4];
01538   m_xform[0][2] = R[0][5];
01539 
01540   m_xform[1][0] = R[1][3];
01541   m_xform[1][1] = R[1][4];
01542   m_xform[1][2] = R[1][5];
01543 
01544   m_xform[2][0] = R[2][3];
01545   m_xform[2][1] = R[2][4];
01546   m_xform[2][2] = R[2][5];
01547 
01548   return true;
01549 }
01550 
01551 bool ON_Xform::ChangeBasis(
01552   const ON_3dPoint&   P0,  // initial frame center
01553   const ON_3dVector&  X0, // initial frame X (X,Y,Z = arbitrary basis)
01554   const ON_3dVector&  Y0, // initial frame Y
01555   const ON_3dVector&  Z0, // initial frame Z
01556   const ON_3dPoint&   P1,  // final frame center
01557   const ON_3dVector&  X1, // final frame X (X,Y,Z = arbitrary basis)
01558   const ON_3dVector&  Y1, // final frame Y
01559   const ON_3dVector&  Z1  // final frame Z
01560   )
01561 {
01562   bool rc = false;
01563   // Q = P0 + a0*X0 + b0*Y0 + c0*Z0 = P1 + a1*X1 + b1*Y1 + c1*Z1
01564   // then this transform will map the point (a0,b0,c0) to (a1,b1,c1)
01565 
01566   ON_Xform F0(P0,X0,Y0,Z0);             // Frame 0
01567 
01568   // T1 translates by -P1
01569   ON_Xform T1;
01570   T1.Translation( -P1.x, -P1.y, -P1.z );
01571         
01572   ON_Xform CB;
01573   rc = CB.ChangeBasis(ON_xaxis, ON_yaxis, ON_zaxis,X1,Y1,Z1);
01574 
01575   *this = CB*T1*F0;
01576   return rc;
01577 }
01578 
01579 void ON_Xform::WorldToCamera( 
01580          const ON_3dPoint& cameraLocation,
01581          const ON_3dVector& cameraX,
01582          const ON_3dVector& cameraY,
01583          const ON_3dVector& cameraZ
01584          )
01585 {
01586   // see comments in tl2_xform.h for details.
01587   /* compute world to camera coordinate xform */
01588   m_xform[0][0] = cameraX.x; m_xform[0][1] = cameraX.y; m_xform[0][2] = cameraX.z;
01589   m_xform[0][3] = -(cameraX.x*cameraLocation.x + cameraX.y*cameraLocation.y + cameraX.z*cameraLocation.z);
01590   m_xform[1][0] = cameraY.x; m_xform[1][1] = cameraY.y; m_xform[1][2] = cameraY.z;
01591   m_xform[1][3] = -(cameraY.x*cameraLocation.x + cameraY.y*cameraLocation.y + cameraY.z*cameraLocation.z);
01592   m_xform[2][0] = cameraZ.x; m_xform[2][1] = cameraZ.y; m_xform[2][2] = cameraZ.z;
01593   m_xform[2][3] = -(cameraZ.x*cameraLocation.x + cameraZ.y*cameraLocation.y + cameraZ.z*cameraLocation.z);
01594   m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0; m_xform[3][3] = 1.0;
01595 }
01596   
01597 void ON_Xform::CameraToWorld(
01598          const ON_3dPoint& cameraLocation,
01599          const ON_3dVector& cameraX,
01600          const ON_3dVector& cameraY,
01601          const ON_3dVector& cameraZ
01602          )
01603 {
01604   // see comments in tl2_xform.h for details.
01605   /* compute camera to world coordinate m_xform */
01606   m_xform[0][0] = cameraX.x; m_xform[0][1] = cameraY.x; m_xform[0][2] = cameraZ.x; 
01607   m_xform[0][3] = cameraLocation.x;
01608   m_xform[1][0] = cameraX.y; m_xform[1][1] = cameraY.y; m_xform[1][2] = cameraZ.y; 
01609   m_xform[1][3] = cameraLocation.y;
01610   m_xform[2][0] = cameraX.z; m_xform[2][1] = cameraY.z; m_xform[2][2] = cameraZ.z; 
01611   m_xform[2][3] = cameraLocation.z;
01612   m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0; m_xform[3][3] = 1.0;
01613 }
01614 
01615 bool ON_Xform::CameraToClip(
01616       ON_BOOL32 bPerspective,
01617       double left,      double right,
01618       double bottom,    double top,
01619       double near_dist, double far_dist
01620       )
01621 {
01622   double dd;
01623 
01624   if ( left == right || bottom == top || near_dist == far_dist )
01625     return false;
01626 
01627   if ( !bPerspective ) {
01628     // parallel projection
01629     //d = 1.0/(left-right);
01630     //m_xform[0][0] = -2.0*d; m_xform[0][3] = (left+right)*d; m_xform[0][1] = m_xform[0][2] = 0.0;
01631     //d = 1.0/(bottom-top);
01632     //m_xform[1][1] = -2.0*d; m_xform[1][3] = (bottom+top)*d; m_xform[1][0] = m_xform[1][2] = 0.0;
01633     //d = 1.0/(far_dist-near_dist);
01634     //m_xform[2][2] = 2.0*d;  m_xform[2][3] = (far_dist+near_dist)*d;   m_xform[2][0] = m_xform[2][1] = 0.0;
01635     //m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0; m_xform[3][3] = 1.0;
01636 
01637     dd = (left-right);
01638     m_xform[0][0] = -2.0/dd; m_xform[0][3] = (left+right)/dd; m_xform[0][1] = m_xform[0][2] = 0.0;
01639     dd = (bottom-top);
01640     m_xform[1][1] = -2.0/dd; m_xform[1][3] = (bottom+top)/dd; m_xform[1][0] = m_xform[1][2] = 0.0;
01641     dd = (far_dist-near_dist);
01642     m_xform[2][2] = 2.0/dd;  m_xform[2][3] = (far_dist+near_dist)/dd;   m_xform[2][0] = m_xform[2][1] = 0.0;
01643     m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0; m_xform[3][3] = 1.0;
01644   }
01645   else 
01646   {
01647     // perspective projection
01648 
01649     //  2n/(r-l)     0        (r+l)/(r-l)     0
01650     //    0        2n/(t-b)   (t+b)/(t-b)     0
01651     //    0          0        (f+n)/(f-n)  2fn/(f-n)
01652     //    0          0            -1          0
01653     //
01654     // To get a linear map from camera z to clip z, apply the linear
01655     // fractional transformation that maps [-1,1] -> [-1,1]
01656     //
01657     //   f(s): s -> (a*s + b)/(a + bs),
01658     //
01659     //  where a = (n+f) and b = (f-n), to clip z.
01660     //
01661     // The inverse of f is g
01662     //
01663     //   g(t): t -> (a*t - b)/(a - b*t)
01664     //
01665     // to the z coordinate after applying this transformation
01666     //d = 1.0/(right-left);
01667     //m_xform[0][0] = 2.0*near_dist*d; 
01668     //m_xform[0][2] = (right+left)*d; 
01669     //m_xform[0][1] = m_xform[0][3] = 0.0;
01670 
01671     //d = 1.0/(top-bottom);
01672     //m_xform[1][1] = 2.0*near_dist*d; 
01673     //m_xform[1][2] = (top+bottom)*d; 
01674     //m_xform[1][0] = m_xform[1][3] = 0.0;
01675 
01676     //d = 1.0/(far_dist-near_dist);
01677     //m_xform[2][2] = (far_dist+near_dist)*d; 
01678     //m_xform[2][3] = 2.0*near_dist*far_dist*d; 
01679     //m_xform[2][0] = m_xform[2][1] = 0.0;
01680 
01681     dd = (right-left);
01682     m_xform[0][0] = 2.0*near_dist/dd; 
01683     m_xform[0][2] = (right+left)/dd; 
01684     m_xform[0][1] = m_xform[0][3] = 0.0;
01685 
01686     dd = (top-bottom);
01687     m_xform[1][1] = 2.0*near_dist/dd; 
01688     m_xform[1][2] = (top+bottom)/dd; 
01689     m_xform[1][0] = m_xform[1][3] = 0.0;
01690 
01691     dd = (far_dist-near_dist);
01692     m_xform[2][2] = (far_dist+near_dist)/dd; 
01693     m_xform[2][3] = 2.0*near_dist*far_dist/dd; 
01694     m_xform[2][0] = m_xform[2][1] = 0.0;
01695 
01696     m_xform[3][0] = m_xform[3][1] = m_xform[3][3] = 0.0; m_xform[3][2] = -1.0;
01697   }
01698   return true;
01699 }
01700 
01701 bool ON_Xform::ClipToCamera(
01702       ON_BOOL32 bPerspective,
01703       double left,      double right,
01704       double bottom,    double top,
01705       double near_dist, double far_dist
01706       )
01707 {
01708   // see comments in tl2_xform.h for details.
01709   double dd;
01710   if ( left == right || bottom == top || near_dist == far_dist )
01711     return false;
01712 
01713   if ( !bPerspective ) {
01714     // parallel projection
01715     m_xform[0][0] = 0.5*(right-left); m_xform[0][3] = 0.5*(right+left); m_xform[0][1] = m_xform[0][2] = 0.0;
01716     m_xform[1][1] = 0.5*(top-bottom); m_xform[1][3] = 0.5*(top+bottom); m_xform[1][0] = m_xform[1][2] = 0.0;
01717     m_xform[2][2] = 0.5*(far_dist-near_dist);   m_xform[2][3] = -0.5*(far_dist+near_dist);  m_xform[2][0] = m_xform[2][1] = 0.0;
01718     m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0; m_xform[3][3] = 1.0;
01719   }
01720   else {
01721     // perspective projection
01722     //  (r-l)/(2n)       0            0       (r+l)/(2n)
01723     //    0         (t-b)/(2n)        0       (t+b)/(2n)
01724     //    0              0            0           -1
01725     //    0              0       (f-n)/(2fn)  (f+n)/(2fn)
01726     //d = 0.5/near_dist;
01727     //m_xform[0][0] = d*(right-left); 
01728     //m_xform[0][3] = d*(right+left); 
01729     //m_xform[0][1] = m_xform[0][2] = 0.0;
01730 
01731     //m_xform[1][1] = d*(top-bottom); 
01732     //m_xform[1][3] = d*(top+bottom); 
01733     //m_xform[1][0] = m_xform[1][2] = 0.0;
01734 
01735     //m_xform[2][0] = m_xform[2][1] = m_xform[2][2] = 0.0; m_xform[2][3] = -1.0;
01736 
01737     //d /= far_dist;
01738     //m_xform[3][2] = d*(far_dist-near_dist); 
01739     //m_xform[3][3] = d*(far_dist+near_dist); 
01740     //m_xform[3][0] = m_xform[3][1] = 0.0;
01741 
01742     dd = 2.0*near_dist;
01743     m_xform[0][0] = (right-left)/dd; 
01744     m_xform[0][3] = (right+left)/dd; 
01745     m_xform[0][1] = m_xform[0][2] = 0.0;
01746 
01747     m_xform[1][1] = (top-bottom)/dd; 
01748     m_xform[1][3] = (top+bottom)/dd; 
01749     m_xform[1][0] = m_xform[1][2] = 0.0;
01750 
01751     m_xform[2][0] = m_xform[2][1] = m_xform[2][2] = 0.0; m_xform[2][3] = -1.0;
01752 
01753     dd *= far_dist;
01754     m_xform[3][2] = (far_dist-near_dist)/dd; 
01755     m_xform[3][3] = (far_dist+near_dist)/dd; 
01756     m_xform[3][0] = m_xform[3][1] = 0.0;
01757   }
01758 
01759   return true;
01760 }
01761 
01762 bool ON_Xform::ClipToScreen(
01763       double left,   double right,
01764       double bottom, double top,
01765       double near_z, double far_z
01766       )
01767 {
01768   // see comments in tl2_xform.h for details.
01769   if ( left == right || bottom == top )
01770     return false;
01771 
01772   m_xform[0][0] = 0.5*(right-left);
01773   m_xform[0][3] = 0.5*(right+left);
01774   m_xform[0][1] = m_xform[0][2] = 0.0;
01775 
01776   m_xform[1][1] = 0.5*(top-bottom);
01777   m_xform[1][3] = 0.5*(top+bottom);
01778   m_xform[1][0] = m_xform[1][2] = 0.0;
01779 
01780   if (far_z != near_z) {
01781     m_xform[2][2] = 0.5*(near_z-far_z);
01782     m_xform[2][3] = 0.5*(near_z+far_z);
01783   }
01784   else {
01785     m_xform[2][2] = 1.0;
01786     m_xform[2][3] = 0.0;
01787   }
01788   m_xform[2][0] = m_xform[2][1] = 0.0;
01789 
01790   m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0; 
01791   m_xform[3][3] = 1.0;
01792 
01793   return true;
01794 }
01795 
01796 bool ON_Xform::ScreenToClip(
01797       double left,   double right,
01798       double bottom, double top,
01799       double near_z, double far_z
01800       )
01801 {
01802   // see comments in tl2_xform.h for details.
01803   ON_Xform c2s;
01804   bool rc = c2s.ClipToScreen( left, right, bottom, top, near_z, far_z );
01805   if (rc) {
01806     m_xform[0][0] = 1.0/c2s[0][0]; m_xform[0][3] = -c2s[0][3]/c2s[0][0];
01807     m_xform[0][1] = m_xform[0][2] = 0.0;
01808 
01809     m_xform[1][1] = 1.0/c2s[1][1]; m_xform[1][3] = -c2s[1][3]/c2s[1][1];
01810     m_xform[1][0] = m_xform[1][2] = 0.0;
01811 
01812     m_xform[2][2] = 1.0/c2s[2][2]; m_xform[2][3] = -c2s[2][3]/c2s[2][2];
01813     m_xform[2][0] = m_xform[2][1] = 0.0;
01814 
01815     m_xform[3][0] = m_xform[3][1] = m_xform[3][2] = 0.0; 
01816     m_xform[3][3] = 1.0;
01817   }
01818   return rc;
01819 }
01820 
01821 
01822 int ON_Xform::ClipFlag4d( const double* point ) const
01823 {
01824   if ( !point )
01825     return 1|2|4|8|16|32;
01826   int clip = 0;
01827   double x = m_xform[0][0]*point[0] + m_xform[0][1]*point[1] + m_xform[0][2]*point[2] + m_xform[0][3]*point[3];
01828   double y = m_xform[1][0]*point[0] + m_xform[1][1]*point[1] + m_xform[1][2]*point[2] + m_xform[1][3]*point[3];
01829   double z = m_xform[2][0]*point[0] + m_xform[2][1]*point[1] + m_xform[2][2]*point[2] + m_xform[2][3]*point[3];
01830   double w = m_xform[3][0]*point[0] + m_xform[3][1]*point[1] + m_xform[3][2]*point[2] + m_xform[3][3]*point[3];
01831   if ( point[3] < 0.0 ) {
01832     x = -x; y = -y; z = -z; w = -w;
01833   }
01834   if ( x <= -w )
01835     clip |= 1;
01836   else if ( x >= w )
01837     clip |= 2;
01838   if ( y <= -w )
01839     clip |= 4;
01840   else if ( y >= w )
01841     clip |= 8;
01842   if ( z <= -w )
01843     clip |= 16;
01844   else if ( z >= w )
01845     clip |= 32;
01846   return clip;
01847 }
01848 
01849 int ON_Xform::ClipFlag3d( const double* point ) const
01850 {
01851   if ( !point )
01852     return 1|2|4|8|16|32;
01853   int clip = 0;
01854   const double x = m_xform[0][0]*point[0] + m_xform[0][1]*point[1] + m_xform[0][2]*point[2] + m_xform[0][3];
01855   const double y = m_xform[1][0]*point[0] + m_xform[1][1]*point[1] + m_xform[1][2]*point[2] + m_xform[1][3];
01856   const double z = m_xform[2][0]*point[0] + m_xform[2][1]*point[1] + m_xform[2][2]*point[2] + m_xform[2][3];
01857   const double w = m_xform[3][0]*point[0] + m_xform[3][1]*point[1] + m_xform[3][2]*point[2] + m_xform[3][3];
01858   if ( x <= -w )
01859     clip |= 1;
01860   else if ( x >= w )
01861     clip |= 2;
01862   if ( y <= -w )
01863     clip |= 4;
01864   else if ( y >= w )
01865     clip |= 8;
01866   if ( z <= -w )
01867     clip |= 16;
01868   else if ( z >= w )
01869     clip |= 32;
01870   return clip;
01871 }
01872 
01873 int ON_Xform::ClipFlag4d( int count, int stride, const double* point, 
01874                             ON_BOOL32 bTestZ ) const
01875 {
01876   int clip = 1|2|4|8;
01877   if ( bTestZ)
01878     clip |= (16|32);
01879   if ( point && ((count > 0 && stride >= 4) || count == 1) ) {
01880     for ( /*empty*/; clip && count--; point += stride ) {
01881       clip &= ClipFlag4d( point );
01882     }
01883   }
01884   return clip;
01885 }
01886 
01887 int ON_Xform::ClipFlag3d( int count, int stride, const double* point, 
01888                             ON_BOOL32 bTestZ ) const
01889 {
01890   int clip = 1|2|4|8;
01891   if ( bTestZ)
01892     clip |= (16|32);
01893   if ( point && ((count > 0 && stride >= 3) || count == 1) ) {
01894     for ( /*empty*/; clip && count--; point += stride ) {
01895       clip &= ClipFlag3d( point );
01896     }
01897   }
01898   return clip;
01899 }
01900 
01901 int ON_Xform::ClipFlag3dBox( const double* boxmin, const double* boxmax ) const
01902 {
01903   int clip = 1|2|4|8|16|32;
01904   double point[3];
01905   int i,j,k;
01906   if ( boxmin && boxmax ) {
01907     for (i=0;i<2;i++) {
01908       point[0] = (i)?boxmax[0]:boxmin[0];
01909       for (j=0;j<2;j++) {
01910         point[1] = (j)?boxmax[1]:boxmin[1];
01911         for (k=0;k<2;k++) {
01912           point[2] = (k)?boxmax[2]:boxmin[2];
01913           clip &= ClipFlag3d(point);
01914           if ( !clip )
01915             return 0;
01916         }
01917       }
01918     }
01919   }
01920   return clip;
01921 }
01922 
01923 ON_Xform& ON_Xform::operator=(const ON_Matrix& src)
01924 {
01925   int i,j;
01926   i = src.RowCount();
01927   const int maxi = (i>4)?4:i;
01928   j = src.ColCount();
01929   const int maxj = (j>4)?4:j;
01930   Identity();
01931   for ( i = 0; i < maxi; i++ ) for ( j = 0; j < maxj; j++ ) {
01932     m_xform[i][j] = src.m[i][j];
01933   }
01934   return *this;
01935 }
01936 
01937 bool ON_Xform::IntervalChange(
01938   int dir,
01939   ON_Interval old_interval,
01940   ON_Interval new_interval
01941   )
01942 {
01943   bool rc = false;
01944   Identity();
01945   if (   dir >= 0 
01946        && dir <= 3 
01947        && old_interval[0] != ON_UNSET_VALUE
01948        && old_interval[1] != ON_UNSET_VALUE
01949        && new_interval[0] != ON_UNSET_VALUE
01950        && new_interval[1] != ON_UNSET_VALUE
01951        && old_interval.Length() != 0.0
01952        )
01953   {
01954     rc = true;
01955     if ( new_interval != old_interval )
01956     {
01957       double s = new_interval.Length()/old_interval.Length();;
01958       double d = (new_interval[0]*old_interval[1] - new_interval[1]*old_interval[0])/old_interval.Length();
01959       m_xform[dir][dir] = s;
01960       m_xform[dir][3] = d;
01961     }
01962   }
01963   return rc;
01964 }


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:27:03