moab
|
00001 00023 #include "AffineXform.hpp" 00024 #include "moab/Interface.hpp" 00025 #include <assert.h> 00026 00027 00028 namespace moab { 00029 00030 // Don't include tag-related stuff in test build because we don't 00031 // link to MOAB to test all other functionality. 00032 #ifndef TEST 00033 00034 const char* const AFFINE_XFORM_TAG_NAME = "AFFINE_TRANSFORM"; 00035 00036 ErrorCode AffineXform::get_tag( Tag& tag_out, 00037 Interface* interface, 00038 const char* tagname ) 00039 { 00040 assert( sizeof(AffineXform) == 12*sizeof(double) ); 00041 00042 if (!tagname) 00043 tagname = AFFINE_XFORM_TAG_NAME; 00044 00045 return interface->tag_get_handle( tagname, 00046 sizeof(AffineXform), 00047 MB_TYPE_DOUBLE, 00048 tag_out, 00049 MB_TAG_BYTES|MB_TAG_CREAT|MB_TAG_DENSE ); 00050 } 00051 00052 #endif //TEST 00053 00054 AffineXform AffineXform::rotation( const double* from_vec, const double* to_vec ) 00055 { 00056 CartVect from(from_vec); 00057 CartVect to(to_vec); 00058 CartVect a = from * to; 00059 double len = a.length(); 00060 00061 // If input vectors are not parallel (the normal case) 00062 if (len >= std::numeric_limits<double>::epsilon()) { 00063 from.normalize(); 00064 to.normalize(); 00065 return rotation( from % to, (from * to).length(), a/len ); 00066 } 00067 00068 // Vectors are parallel: 00069 // 00070 // If vectors are in same direction then rotation is identity (no transform) 00071 if (from % to >= 0.0) 00072 return AffineXform(); 00073 00074 // Parallel vectors in opposite directions: 00075 // 00076 // NOTE: This case is ill-defined. There are infinitely 00077 // many rotations that can align the two vectors. The angle 00078 // of rotation is 180 degrees, but the axis of rotation may 00079 // be any unit vector orthogonal to the input vectors. 00080 // 00081 from.normalize(); 00082 double lenxy = std::sqrt( from[0]*from[0] + from[1]*from[1] ); 00083 CartVect axis( -from[0]*from[2]/lenxy, 00084 -from[1]*from[2]/lenxy, 00085 lenxy ); 00086 return rotation( -1, 0, axis ); 00087 } 00088 00089 00090 } // namespace moab 00091 00092 00093 #ifdef TEST // ******************* Unit Test code *********************** 00094 00095 using namespace moab; 00096 00097 #include <iostream> 00098 #define ASSERT_VECTORS_EQUAL(A, B) assert_vectors_equal( (A), (B), #A, #B, __LINE__ ) 00099 #define ASSERT_DOUBLES_EQUAL(A, B) assert_doubles_equal( (A), (B), #A, #B, __LINE__ ) 00100 #define ASSERT(B) assert_bool( (B), #B, __LINE__ ) 00101 00102 const double TOL = 1e-6; 00103 00104 int error_count = 0; 00105 00106 void assert_vectors_equal( const double* a, const double* b, 00107 const char* sa, const char* sb, 00108 int lineno ) 00109 { 00110 if (fabs(a[0] - b[0]) > TOL || 00111 fabs(a[1] - b[1]) > TOL || 00112 fabs(a[2] - b[2]) > TOL) { 00113 std::cerr << "Assertion failed at line " << lineno << std::endl 00114 << "\t" << sa << " == " << sb << std::endl 00115 << "\t[" << a[0] << ", " << a[1] << ", " << a[2] << "] == [" 00116 << b[0] << ", " << b[1] << ", " << b[2] << "]" << std::endl; 00117 ++error_count; 00118 } 00119 } 00120 00121 void assert_vectors_equal( const CartVect& a, const CartVect& b, 00122 const char* sa, const char* sb, 00123 int lineno ) 00124 { 00125 assert_vectors_equal( a.array(), b.array(), sa, sb, lineno ); 00126 } 00127 00128 void assert_doubles_equal( double a, double b, const char* sa, const char* sb, int lineno ) 00129 { 00130 if (fabs(a - b) > TOL) { 00131 std::cerr << "Assertion failed at line " << lineno << std::endl 00132 << "\t" << sa << " == " << sb << std::endl 00133 << "\t" << a << " == " << b << std::endl; 00134 ++error_count; 00135 } 00136 } 00137 00138 void assert_bool( bool b, const char* sb, int lineno ) 00139 { 00140 if (!b) { 00141 std::cerr << "Assertion failed at line " << lineno << std::endl 00142 << "\t" << sb << std::endl; 00143 ++error_count; 00144 } 00145 } 00146 00147 00148 const CartVect point1( 0.0, 0.0, 0.0 ), point2( 3.5, 1000, -200 ); 00149 const CartVect vect1( 0.0, 0.0, -100.0 ), vect2( 1.0, 0.0, 1.0 ); 00150 00151 00152 void test_none() 00153 { 00154 // default xform should do nothing. 00155 CartVect output; 00156 AffineXform none; 00157 none.xform_point( point1.array(), output.array() ); 00158 ASSERT_VECTORS_EQUAL( output, point1 ); 00159 none.xform_point( point2.array(), output.array() ); 00160 ASSERT_VECTORS_EQUAL( output, point2 ); 00161 none.xform_vector( vect1.array(), output.array() ); 00162 ASSERT_VECTORS_EQUAL( output, vect1 ); 00163 none.xform_vector( vect2.array(), output.array() ); 00164 ASSERT_VECTORS_EQUAL( output, vect2 ); 00165 } 00166 00167 void test_translation() 00168 { 00169 CartVect offset( 1.0, 2.0, 3.0 ); 00170 CartVect output; 00171 00172 AffineXform move = AffineXform::translation( offset.array() ); 00173 00174 // test that points are moved by offset 00175 move.xform_point( point1.array(), output.array() ); 00176 ASSERT_VECTORS_EQUAL( output, point1 + offset ); 00177 move.xform_point( point2.array(), output.array() ); 00178 ASSERT_VECTORS_EQUAL( output, point2 + offset ); 00179 00180 // vectors should not be changed by a translation 00181 move.xform_vector( vect1.array(), output.array() ); 00182 ASSERT_VECTORS_EQUAL( output, vect1 ); 00183 move.xform_vector( vect2.array(), output.array() ); 00184 ASSERT_VECTORS_EQUAL( output, vect2 ); 00185 } 00186 00187 void test_rotation() 00188 { 00189 CartVect output; 00190 00191 // rotate 90 degress about Z axis 00192 00193 AffineXform rot = AffineXform::rotation( M_PI/2.0, CartVect(0,0,1).array() ); 00194 ASSERT_DOUBLES_EQUAL( rot.matrix().determinant(), 1.0 ); 00195 00196 rot.xform_point( point1.array(), output.array() ); 00197 ASSERT_VECTORS_EQUAL( output, point1 ); // origin not affected by transform 00198 00199 CartVect expectedz( -point2[1], point2[0], point2[2] ); // in first quadrant 00200 rot.xform_point( point2.array(), output.array() ); 00201 ASSERT_DOUBLES_EQUAL( output.length(), point2.length() ); 00202 ASSERT_VECTORS_EQUAL( output, expectedz ); 00203 00204 rot.xform_vector( vect1.array(), output.array() ); 00205 ASSERT_DOUBLES_EQUAL( output.length(), vect1.length() ); 00206 ASSERT_VECTORS_EQUAL( output, vect1 ); 00207 00208 rot.xform_vector( vect2.array(), output.array() ); 00209 ASSERT_DOUBLES_EQUAL( output.length(), vect2.length() ); 00210 ASSERT_VECTORS_EQUAL( output, CartVect( 0, 1, 1 ) ); 00211 00212 // rotate 90 degress about Y axis 00213 00214 rot = AffineXform::rotation( M_PI/2.0, CartVect(0,1,0).array() ); 00215 ASSERT_DOUBLES_EQUAL( rot.matrix().determinant(), 1.0 ); 00216 00217 rot.xform_point( point1.array(), output.array() ); 00218 ASSERT_VECTORS_EQUAL( output, point1 ); // origin not affected by transform 00219 00220 CartVect expectedy( point2[2], point2[1], -point2[0] ); // in second quadrant 00221 rot.xform_point( point2.array(), output.array() ); 00222 ASSERT_DOUBLES_EQUAL( output.length(), point2.length() ); 00223 ASSERT_VECTORS_EQUAL( output, expectedy ); 00224 00225 rot.xform_vector( vect1.array(), output.array() ); 00226 ASSERT_DOUBLES_EQUAL( output.length(), vect1.length() ); 00227 ASSERT_VECTORS_EQUAL( output, CartVect(-100,0,0) ); 00228 00229 rot.xform_vector( vect2.array(), output.array() ); 00230 ASSERT_DOUBLES_EQUAL( output.length(), vect2.length() ); 00231 ASSERT_VECTORS_EQUAL( output, CartVect( 1, 0, -1 ) ); 00232 00233 // rotate 90 degress about X axis 00234 00235 rot = AffineXform::rotation( M_PI/2.0, CartVect(1,0,0).array() ); 00236 ASSERT_DOUBLES_EQUAL( rot.matrix().determinant(), 1.0 ); 00237 00238 rot.xform_point( point1.array(), output.array() ); 00239 ASSERT_VECTORS_EQUAL( output, point1 ); // origin not affected by transform 00240 00241 CartVect expectedx( point2[0], -point2[2], point2[1] ); // in third quadrant 00242 rot.xform_point( point2.array(), output.array() ); 00243 ASSERT_DOUBLES_EQUAL( output.length(), point2.length() ); 00244 ASSERT_VECTORS_EQUAL( output, expectedx ); 00245 00246 rot.xform_vector( vect1.array(), output.array() ); 00247 ASSERT_DOUBLES_EQUAL( output.length(), vect1.length() ); 00248 ASSERT_VECTORS_EQUAL( output, CartVect(0,100,0) ); 00249 00250 rot.xform_vector( vect2.array(), output.array() ); 00251 ASSERT_DOUBLES_EQUAL( output.length(), vect2.length() ); 00252 ASSERT_VECTORS_EQUAL( output, CartVect( 1, -1, 0 ) ); 00253 00254 // rotate 180 degrees about vector in XY plane 00255 00256 rot = AffineXform::rotation( M_PI, CartVect( 1, 1, 0 ).array() ); 00257 ASSERT_DOUBLES_EQUAL( rot.matrix().determinant(), 1.0 ); 00258 00259 rot.xform_point( point1.array(), output.array() ); 00260 ASSERT_VECTORS_EQUAL( output, point1 ); // origin not affected by transform 00261 00262 rot.xform_point( point2.array(), output.array() ); 00263 ASSERT_DOUBLES_EQUAL( output.length(), point2.length() ); 00264 ASSERT_VECTORS_EQUAL( output, CartVect( point2[1], point2[0], -point2[2] ) ); 00265 00266 rot.xform_vector( vect1.array(), output.array() ); 00267 ASSERT_DOUBLES_EQUAL( output.length(), vect1.length() ); 00268 ASSERT_VECTORS_EQUAL( output, -vect1 ); // vector is in xy plane 00269 00270 rot.xform_vector( vect2.array(), output.array() ); 00271 ASSERT_DOUBLES_EQUAL( output.length(), vect2.length() ); 00272 ASSERT_VECTORS_EQUAL( output, CartVect( 0, 1, -1 ) ); 00273 } 00274 00275 void test_rotation_from_vec( ) 00276 { 00277 CartVect v1( 1, 1, 1 ); 00278 CartVect v2( 1, 0, 0 ); 00279 AffineXform rot = AffineXform::rotation( v1.array(), v2.array() ); 00280 CartVect result; 00281 rot.xform_vector( v1.array(), result.array() ); 00282 // vectors should be parallel, but not same length 00283 ASSERT_DOUBLES_EQUAL( result.length(), v1.length() ); 00284 result.normalize(); 00285 ASSERT_VECTORS_EQUAL( result, v2 ); 00286 00287 double v3[] = { -1, 0, 0 }; 00288 rot = AffineXform::rotation( v3, v2.array() ); 00289 rot.xform_vector( v3, result.array() ); 00290 ASSERT_VECTORS_EQUAL( result, v2 ); 00291 } 00292 00293 CartVect refl( const CartVect& vect, const CartVect& norm ) 00294 { 00295 CartVect n(norm); 00296 n.normalize(); 00297 double d = vect % n; 00298 return vect - 2 * d * n; 00299 } 00300 00301 void test_reflection() 00302 { 00303 CartVect output; 00304 00305 // reflect about XY plane 00306 AffineXform ref = AffineXform::reflection( CartVect( 0, 0, 1 ).array() ); 00307 ASSERT_DOUBLES_EQUAL( ref.matrix().determinant(), -1.0 ); 00308 ref.xform_point( point1.array(), output.array() ); 00309 ASSERT_VECTORS_EQUAL( output, point1 ); 00310 ref.xform_point( point2.array(), output.array() ); 00311 ASSERT_DOUBLES_EQUAL( output.length(), point2.length() ); 00312 ASSERT_VECTORS_EQUAL( output, CartVect(point2[0],point2[1],-point2[2]) ); 00313 ref.xform_vector( vect1.array(), output.array() ); 00314 ASSERT_DOUBLES_EQUAL( output.length(), vect1.length() ); 00315 ASSERT_VECTORS_EQUAL( output, -vect1 ); 00316 ref.xform_vector( vect2.array(), output.array() ); 00317 ASSERT_DOUBLES_EQUAL( output.length(), vect2.length() ); 00318 ASSERT_VECTORS_EQUAL( output, CartVect(1,0,-1) ); 00319 00320 // reflect about arbitrary palne 00321 CartVect norm( 3, 2, 1 ); 00322 ref = AffineXform::reflection( norm.array() ); 00323 ASSERT_DOUBLES_EQUAL( ref.matrix().determinant(), -1.0 ); 00324 ref.xform_point( point1.array(), output.array() ); 00325 ASSERT_VECTORS_EQUAL( output, point1 ); 00326 ref.xform_point( point2.array(), output.array() ); 00327 ASSERT_DOUBLES_EQUAL( output.length(), point2.length() ); 00328 ASSERT_VECTORS_EQUAL( output, refl(point2,norm) ); 00329 ref.xform_vector( vect1.array(), output.array() ); 00330 ASSERT_DOUBLES_EQUAL( output.length(), vect1.length() ); 00331 ASSERT_VECTORS_EQUAL( output, refl(vect1,norm) ); 00332 ref.xform_vector( vect2.array(), output.array() ); 00333 ASSERT_DOUBLES_EQUAL( output.length(), vect2.length() ); 00334 ASSERT_VECTORS_EQUAL( output, refl(vect2,norm) ); 00335 } 00336 00337 void test_scale() 00338 { 00339 CartVect output; 00340 00341 AffineXform scale = AffineXform::scale( 1.0 ); 00342 ASSERT(!scale.scale()); 00343 scale = AffineXform::scale( -1.0 ); 00344 ASSERT(!scale.scale()); 00345 00346 //scale in X only 00347 scale = AffineXform::scale( CartVect(2,1,1).array() ); 00348 ASSERT(scale.scale()); 00349 scale.xform_point( point1.array(), output.array() ); 00350 ASSERT_VECTORS_EQUAL( output, CartVect(2*point1[0],point1[1],point1[2]) ); 00351 scale.xform_point( point2.array(), output.array() ); 00352 ASSERT_VECTORS_EQUAL( output, CartVect(2*point2[0],point2[1],point2[2]) ); 00353 scale.xform_vector( vect1.array(), output.array() ); 00354 ASSERT_VECTORS_EQUAL( output, CartVect(2*vect1[0],vect1[1],vect1[2]) ); 00355 scale.xform_vector( vect2.array(), output.array() ); 00356 ASSERT_VECTORS_EQUAL( output, CartVect(2*vect2[0],vect2[1],vect2[2]) ); 00357 00358 // scale in all 00359 scale = AffineXform::scale( CartVect(0.5,0.5,0.5).array() ); 00360 ASSERT(scale.scale()); 00361 scale.xform_point( point1.array(), output.array() ); 00362 ASSERT_VECTORS_EQUAL( output, 0.5*point1 ); 00363 scale.xform_point( point2.array(), output.array() ); 00364 ASSERT_VECTORS_EQUAL( output, 0.5*point2 ); 00365 scale.xform_vector( vect1.array(), output.array() ); 00366 ASSERT_VECTORS_EQUAL( output, 0.5*vect1 ); 00367 scale.xform_vector( vect2.array(), output.array() ); 00368 ASSERT_VECTORS_EQUAL( output, 0.5*vect2 ); 00369 } 00370 00371 void test_scale_point() 00372 { 00373 const double point[] = {2,3,4}; 00374 const double f[] = { 0.2, 0.1, 0.3 }; 00375 double result[3]; 00376 AffineXform scale = AffineXform::scale( f, point ); 00377 scale.xform_point( point, result ); 00378 ASSERT_VECTORS_EQUAL( result, point ); 00379 00380 const double delta[3] = { 1, 0, 2 }; 00381 const double pt2[] = { point[0]+delta[0], 00382 point[1]+delta[1], 00383 point[2]+delta[2] }; 00384 scale = AffineXform::scale( f, point ); 00385 scale.xform_point( pt2, result ); 00386 00387 const double expected[] = { point[0] + f[0]*delta[0], 00388 point[1] + f[1]*delta[1], 00389 point[2] + f[2]*delta[2] }; 00390 ASSERT_VECTORS_EQUAL( result, expected ); 00391 } 00392 00393 void test_accumulate() 00394 { 00395 CartVect indiv, accum; 00396 00397 // build an group of transforms. make sure translation is somewhere in the middle 00398 AffineXform move, scal, rot1, rot2, refl; 00399 move = AffineXform::translation( CartVect( 5, -5, 1 ).array() ); 00400 scal = AffineXform::scale( CartVect( 1, 0.5, 2 ).array() ); 00401 rot1 = AffineXform::rotation( M_PI/3, CartVect( 0.5, 0.5, 1 ).array() ); 00402 rot2 = AffineXform::rotation( M_PI/4, CartVect( 1.0, 0.0, 0.0 ).array() ); 00403 refl = AffineXform::reflection( CartVect( -1, -1, 0 ).array() ); 00404 AffineXform accu; 00405 accu.accumulate( scal ); 00406 accu.accumulate( rot1 ); 00407 accu.accumulate( move ); 00408 accu.accumulate( refl ); 00409 accu.accumulate( rot2 ); 00410 00411 accu.xform_point( point1.array(), accum.array() ); 00412 scal.xform_point( point1.array(), indiv.array() ); 00413 rot1.xform_point( indiv.array() ); 00414 move.xform_point( indiv.array() ); 00415 refl.xform_point( indiv.array() ); 00416 rot2.xform_point( indiv.array() ); 00417 ASSERT_VECTORS_EQUAL( accum, indiv ); 00418 00419 accu.xform_point( point2.array(), accum.array() ); 00420 scal.xform_point( point2.array(), indiv.array() ); 00421 rot1.xform_point( indiv.array() ); 00422 move.xform_point( indiv.array() ); 00423 refl.xform_point( indiv.array() ); 00424 rot2.xform_point( indiv.array() ); 00425 ASSERT_VECTORS_EQUAL( accum, indiv ); 00426 00427 accu.xform_vector( vect1.array(), accum.array() ); 00428 scal.xform_vector( vect1.array(), indiv.array() ); 00429 rot1.xform_vector( indiv.array() ); 00430 move.xform_vector( indiv.array() ); 00431 refl.xform_vector( indiv.array() ); 00432 rot2.xform_vector( indiv.array() ); 00433 ASSERT_VECTORS_EQUAL( accum, indiv ); 00434 00435 accu.xform_vector( vect2.array(), accum.array() ); 00436 scal.xform_vector( vect2.array(), indiv.array() ); 00437 rot1.xform_vector( indiv.array() ); 00438 move.xform_vector( indiv.array() ); 00439 refl.xform_vector( indiv.array() ); 00440 rot2.xform_vector( indiv.array() ); 00441 ASSERT_VECTORS_EQUAL( accum, indiv ); 00442 } 00443 00444 void test_inversion() { 00445 CartVect result; 00446 00447 // build an group of transforms. make sure translation is somewhere in the middle 00448 AffineXform move, scal, rot1, rot2, refl; 00449 move = AffineXform::translation( CartVect( 5, -5, 1 ).array() ); 00450 scal = AffineXform::scale( CartVect( 1, 0.5, 2 ).array() ); 00451 rot1 = AffineXform::rotation( M_PI/3, CartVect( 0.5, 0.5, 1 ).array() ); 00452 rot2 = AffineXform::rotation( M_PI/4, CartVect( 1.0, 0.0, 0.0 ).array() ); 00453 refl = AffineXform::reflection( CartVect( -1, -1, 0 ).array() ); 00454 AffineXform acc; 00455 acc.accumulate( scal ); 00456 acc.accumulate( rot1 ); 00457 acc.accumulate( move ); 00458 acc.accumulate( refl ); 00459 acc.accumulate( rot2 ); 00460 00461 AffineXform inv = acc.inverse(); 00462 00463 acc.xform_point( point1.array(), result.array() ); 00464 inv.xform_point( result.array() ); 00465 ASSERT_VECTORS_EQUAL( point1, result ); 00466 00467 acc.xform_point( point2.array(), result.array() ); 00468 inv.xform_point( result.array() ); 00469 ASSERT_VECTORS_EQUAL( point2, result ); 00470 00471 acc.xform_vector( vect1.array(), result.array() ); 00472 inv.xform_vector( result.array() ); 00473 ASSERT_VECTORS_EQUAL( vect1, result ); 00474 00475 acc.xform_vector( vect2.array(), result.array() ); 00476 inv.xform_vector( result.array() ); 00477 ASSERT_VECTORS_EQUAL( vect2, result ); 00478 } 00479 00480 void test_is_reflection() 00481 { 00482 AffineXform refl1, refl2, scale; 00483 refl1 = AffineXform::reflection( CartVect( -1, -1, 0).array() ); 00484 refl2 = AffineXform::reflection( CartVect( 1, 0, 0).array() ); 00485 scale = AffineXform::scale( CartVect( -1, 1, 1 ).array() ); 00486 00487 ASSERT( refl1.reflection() ); 00488 ASSERT( refl2.reflection() ); 00489 ASSERT( scale.reflection() ); 00490 00491 AffineXform inv1, inv2, inv3; 00492 inv1 = refl1.inverse(); 00493 inv2 = refl2.inverse(); 00494 inv3 = scale.inverse(); 00495 00496 ASSERT( inv1.reflection() ); 00497 ASSERT( inv2.reflection() ); 00498 ASSERT( inv3.reflection() ); 00499 00500 refl1.accumulate( refl2 ); 00501 refl2.accumulate( scale ); 00502 ASSERT( ! refl1.reflection() ); 00503 ASSERT( ! refl2.reflection() ); 00504 00505 AffineXform rot, mov; 00506 rot = AffineXform::rotation( M_PI/4, CartVect(1,1,1).array() ); 00507 mov = AffineXform::translation( CartVect(-5,6,7).array() ); 00508 ASSERT( !rot.reflection() ); 00509 ASSERT( !mov.reflection() ); 00510 } 00511 00512 int main() 00513 { 00514 test_none(); 00515 test_translation(); 00516 test_rotation(); 00517 test_reflection(); 00518 test_rotation_from_vec(); 00519 test_scale(); 00520 test_scale_point(); 00521 test_accumulate(); 00522 test_inversion(); 00523 test_is_reflection(); 00524 return error_count; 00525 } 00526 00527 #endif // #ifdef TEST