Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

transforms.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 McConnell Brain Imaging Centre, 00005 Montreal Neurological Institute, McGill University. 00006 Permission to use, copy, modify, and distribute this 00007 software and its documentation for any purpose and without 00008 fee is hereby granted, provided that the above copyright 00009 notice appear in all copies. The author and McGill University 00010 make no representations about the suitability of this 00011 software for any purpose. It is provided "as is" without 00012 express or implied warranty. 00013 ---------------------------------------------------------------------------- */ 00014 00015 #include <volume_io/internal_volume_io.h> 00016 #include <bicpl/trans.h> 00017 #include <bicpl/numerical.h> 00018 00019 #ifndef lint 00020 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Transforms/transforms.c,v 1.13 2000/02/06 15:30:51 stever Exp $"; 00021 #endif 00022 00023 /* ----------------------------- MNI Header ----------------------------------- 00024 @NAME : make_scale_transform 00025 @INPUT : sx 00026 sy 00027 sz 00028 @OUTPUT : transform 00029 @RETURNS : 00030 @DESCRIPTION: Assigns the transform a (possibly anisotropic) scaling transform. 00031 @METHOD : 00032 @GLOBALS : 00033 @CALLS : 00034 @CREATED : 1993 David MacDonald 00035 @MODIFIED : 00036 ---------------------------------------------------------------------------- */ 00037 00038 public void make_scale_transform( 00039 Real sx, 00040 Real sy, 00041 Real sz, 00042 Transform *transform ) 00043 { 00044 make_identity_transform( transform ); 00045 00046 Transform_elem( *transform, 0, 0 ) = sx; 00047 Transform_elem( *transform, 1, 1 ) = sy; 00048 Transform_elem( *transform, 2, 2 ) = sz; 00049 } 00050 00051 /* ----------------------------- MNI Header ----------------------------------- 00052 @NAME : set_transform_x_and_z_axes 00053 @INPUT : x_axis 00054 z_axis 00055 @OUTPUT : transform 00056 @RETURNS : 00057 @DESCRIPTION: Sets the transform to the orthogonal coordinate system defined 00058 by the x_axis and z_axis. To do this, the z axis is used as 00059 the z axis, and the cross product of the z_axis and the 00060 x_axis is used as the y_axis. Then, the x_axis is taken as 00061 the cross product of the y and z axes, as opposed to the 00062 one passed in to the function. In this way, as long as the 00063 passed in x_axis is not collinear with the z_axis, it need 00064 not be perpendicular to the z_axis. 00065 @METHOD : 00066 @GLOBALS : 00067 @CALLS : 00068 @CREATED : 1993 David MacDonald 00069 @MODIFIED : 00070 ---------------------------------------------------------------------------- */ 00071 00072 public void set_transform_x_and_z_axes( 00073 Transform *transform, 00074 Vector *x_axis, 00075 Vector *z_axis ) 00076 { 00077 Vector n_z, n_y, n_x; 00078 00079 NORMALIZE_VECTOR( n_z, *z_axis ); 00080 CROSS_VECTORS( n_y, n_z, *x_axis ); 00081 NORMALIZE_VECTOR( n_y, n_y ); 00082 CROSS_VECTORS( n_x, n_z, n_y ); 00083 NORMALIZE_VECTOR( n_x, n_x ); 00084 00085 set_transform_x_axis( transform, &n_x ); 00086 set_transform_y_axis( transform, &n_y ); 00087 set_transform_z_axis( transform, &n_z ); 00088 } 00089 00090 /* ----------------------------- MNI Header ----------------------------------- 00091 @NAME : make_translation_transform 00092 @INPUT : x_trans 00093 y_trans 00094 z_trans 00095 @OUTPUT : transform 00096 @RETURNS : 00097 @DESCRIPTION: Creates a translation transform. 00098 @METHOD : 00099 @GLOBALS : 00100 @CALLS : 00101 @CREATED : 1993 David MacDonald 00102 @MODIFIED : 00103 ---------------------------------------------------------------------------- */ 00104 00105 public void make_translation_transform( 00106 Real x_trans, 00107 Real y_trans, 00108 Real z_trans, 00109 Transform *transform ) 00110 { 00111 make_identity_transform( transform ); 00112 00113 Transform_elem( *transform, 0, 3 ) = x_trans; 00114 Transform_elem( *transform, 1, 3 ) = y_trans; 00115 Transform_elem( *transform, 2, 3 ) = z_trans; 00116 } 00117 00118 /* ----------------------------- MNI Header ----------------------------------- 00119 @NAME : make_origin_transform 00120 @INPUT : origin 00121 @OUTPUT : transform 00122 @RETURNS : 00123 @DESCRIPTION: Makes a transformation which has a different origin. 00124 @METHOD : 00125 @GLOBALS : 00126 @CALLS : 00127 @CREATED : 1993 David MacDonald 00128 @MODIFIED : 00129 ---------------------------------------------------------------------------- */ 00130 00131 public void make_origin_transform( 00132 Point *origin, 00133 Transform *transform ) 00134 { 00135 make_identity_transform( transform ); 00136 00137 Transform_elem( *transform, 0, 3 ) = (Transform_elem_type) Point_x(*origin); 00138 Transform_elem( *transform, 1, 3 ) = (Transform_elem_type) Point_y(*origin); 00139 Transform_elem( *transform, 2, 3 ) = (Transform_elem_type) Point_z(*origin); 00140 } 00141 00142 /* ----------------------------- MNI Header ----------------------------------- 00143 @NAME : make_rotation_transform 00144 @INPUT : radians 00145 axis 00146 @OUTPUT : transform 00147 @RETURNS : 00148 @DESCRIPTION: Makes a transform which rotates the specified number of radians 00149 around the given axis (X, Y, or Z). 00150 @METHOD : 00151 @GLOBALS : 00152 @CALLS : 00153 @CREATED : 1993 David MacDonald 00154 @MODIFIED : 00155 ---------------------------------------------------------------------------- */ 00156 00157 public void make_rotation_transform( 00158 Real radians, 00159 int axis, 00160 Transform *transform ) 00161 { 00162 int a1, a2; 00163 Real c, s; 00164 00165 a1 = (axis + 1) % N_DIMENSIONS; 00166 a2 = (axis + 2) % N_DIMENSIONS; 00167 00168 make_identity_transform( transform ); 00169 00170 c = cos( (double) radians ); 00171 s = sin( (double) radians ); 00172 00173 Transform_elem( *transform, a1, a1 ) = c; 00174 Transform_elem( *transform, a1, a2 ) = s; 00175 Transform_elem( *transform, a2, a1 ) = -s; 00176 Transform_elem( *transform, a2, a2 ) = c; 00177 } 00178 00179 /* ----------------------------- MNI Header ----------------------------------- 00180 @NAME : make_transform_relative_to_point 00181 @INPUT : point 00182 transform 00183 @OUTPUT : rel_transform 00184 @RETURNS : 00185 @DESCRIPTION: Creates a transform which is the specified transform performed 00186 relative to the given point. For instance to rotate around 00187 a point, one could pass the point, and a rotation transform 00188 created by make_rotation_transform(), 00189 and the resulting transform would perform rotation about that 00190 point. 00191 @METHOD : 00192 @GLOBALS : 00193 @CALLS : 00194 @CREATED : 1993 David MacDonald 00195 @MODIFIED : 00196 ---------------------------------------------------------------------------- */ 00197 00198 public void make_transform_relative_to_point( 00199 Point *point, 00200 Transform *transform, 00201 Transform *rel_transform ) 00202 { 00203 Transform to_origin, to_point; 00204 00205 make_translation_transform( (Real) Point_x(*point), (Real) Point_y(*point), 00206 (Real) Point_z(*point), &to_point ); 00207 00208 make_translation_transform( -(Real) Point_x(*point), 00209 -(Real) Point_y(*point), 00210 -(Real) Point_z(*point), &to_origin ); 00211 00212 concat_transforms( rel_transform, &to_origin, transform ); 00213 concat_transforms( rel_transform, rel_transform, &to_point ); 00214 } 00215 00216 /* ----------------------------- MNI Header ----------------------------------- 00217 @NAME : make_transform_in_coordinate_system 00218 @INPUT : origin 00219 x_axis 00220 y_axis 00221 z_axis 00222 transform 00223 @OUTPUT : rel_transform 00224 @RETURNS : 00225 @DESCRIPTION: Creates a transform which is the input transform relative to 00226 the specified coordinate system. For instance if the input 00227 transform is a scaling transform, then the resulting transform 00228 will scale points about the 'origin', in the directions of 00229 'x_axis', 'y_axis', and 'z_axis'. 00230 @METHOD : 00231 @GLOBALS : 00232 @CALLS : 00233 @CREATED : 1993 David MacDonald 00234 @MODIFIED : 00235 ---------------------------------------------------------------------------- */ 00236 00237 public void make_transform_in_coordinate_system( 00238 Point *origin, 00239 Vector *x_axis, 00240 Vector *y_axis, 00241 Vector *z_axis, 00242 Transform *transform, 00243 Transform *rel_transform ) 00244 { 00245 Transform to_bases, from_bases; 00246 00247 make_change_to_bases_transform( origin, x_axis, y_axis, z_axis, &to_bases ); 00248 make_change_from_bases_transform( origin, x_axis, y_axis, z_axis, 00249 &from_bases ); 00250 00251 concat_transforms( rel_transform, &from_bases, transform ); 00252 concat_transforms( rel_transform, rel_transform, &to_bases ); 00253 } 00254 00255 /* ----------------------------- MNI Header ----------------------------------- 00256 @NAME : make_rotation_about_axis 00257 @INPUT : axis 00258 angle 00259 @OUTPUT : transform 00260 @RETURNS : 00261 @DESCRIPTION: Creates a transform which corresponds to a rotation about an 00262 arbitrary vector. Code comes from Graphics Gems book. 00263 @METHOD : Graphics Gems, Page ?? 00264 @GLOBALS : 00265 @CALLS : 00266 @CREATED : 1993 David MacDonald 00267 @MODIFIED : 00268 ---------------------------------------------------------------------------- */ 00269 00270 public void make_rotation_about_axis( 00271 Vector *axis, 00272 Real angle, 00273 Transform *transform ) 00274 { 00275 Real c, s, t; 00276 Real txy, txz, tyz, sx, sy, sz; 00277 Real x, y, z; 00278 Vector unit_axis; 00279 00280 NORMALIZE_VECTOR( unit_axis, *axis ); 00281 00282 c = cos( (double) -angle ); 00283 s = sin( (double) -angle ); 00284 t = 1.0 - c; 00285 00286 x = (Real) Vector_x( unit_axis ); 00287 y = (Real) Vector_y( unit_axis ); 00288 z = (Real) Vector_z( unit_axis ); 00289 00290 txy = t * x * y; 00291 txz = t * x * z; 00292 tyz = t * y * z; 00293 00294 sx = s * x; 00295 sy = s * y; 00296 sz = s * z; 00297 00298 Transform_elem( *transform, 0, 0 ) = t * x * x + c; 00299 Transform_elem( *transform, 0, 1 ) = txy + sz; 00300 Transform_elem( *transform, 0, 2 ) = txz - sy; 00301 Transform_elem( *transform, 0, 3 ) = 0.0; 00302 00303 Transform_elem( *transform, 1, 0 ) = txy - sz; 00304 Transform_elem( *transform, 1, 1 ) = t * y * y + c; 00305 Transform_elem( *transform, 1, 2 ) = tyz + sx; 00306 Transform_elem( *transform, 1, 3 ) = 0.0; 00307 00308 Transform_elem( *transform, 2, 0 ) = txz + sy; 00309 Transform_elem( *transform, 2, 1 ) = tyz - sx; 00310 Transform_elem( *transform, 2, 2 ) = t * z * z + c; 00311 Transform_elem( *transform, 2, 3 ) = 0.0; 00312 00313 Transform_elem( *transform, 3, 0 ) = 0.0; 00314 Transform_elem( *transform, 3, 1 ) = 0.0; 00315 Transform_elem( *transform, 3, 2 ) = 0.0; 00316 Transform_elem( *transform, 3, 3 ) = 1.0; 00317 } 00318 00319 /* ----------------------------- MNI Header ----------------------------------- 00320 @NAME : convert_2d_transform_to_rotation_translation 00321 @INPUT : transform 00322 @OUTPUT : degrees_clockwise 00323 x_trans 00324 y_trans 00325 @RETURNS : 00326 @DESCRIPTION: Converts a 2d transform to a angle of rotation and origin 00327 of rotation. 00328 @METHOD : 00329 @GLOBALS : 00330 @CALLS : 00331 @CREATED : 1993 David MacDonald 00332 @MODIFIED : 00333 ---------------------------------------------------------------------------- */ 00334 00335 public void convert_2d_transform_to_rotation_translation( 00336 Transform *transform, 00337 Real *degrees_clockwise, 00338 Real *x_trans, 00339 Real *y_trans ) 00340 { 00341 Real x, y; 00342 00343 x = Transform_elem(*transform, X, X ); 00344 y = Transform_elem(*transform, Y, X ); 00345 00346 *degrees_clockwise = RAD_TO_DEG * compute_clockwise_rotation( x, y ); 00347 *x_trans = Transform_elem( *transform, X, 3 ); 00348 *y_trans = Transform_elem( *transform, Y, 3 ); 00349 } 00350 00351 /* ----------------------------- MNI Header ----------------------------------- 00352 @NAME : compute_clockwise_rotation 00353 @INPUT : x 00354 y 00355 @OUTPUT : 00356 @RETURNS : Radians 00357 @DESCRIPTION: Computes the clockwise angle of rotation required to rotate 00358 the x axis to the point (x,y). Will be value greater than or 00359 equal to 0 and less than two pi. 00360 @METHOD : 00361 @GLOBALS : 00362 @CALLS : 00363 @CREATED : 1993 David MacDonald 00364 @MODIFIED : 00365 ---------------------------------------------------------------------------- */ 00366 00367 public Real compute_clockwise_rotation( Real x, Real y ) 00368 { 00369 Real radians; 00370 00371 if( x == 0.0 ) 00372 { 00373 if( y < 0.0 ) 00374 return( PI / 2.0 ); 00375 else if( y > 0.0 ) 00376 return( 3.0 * PI / 2.0 ); 00377 else 00378 return( 0.0 ); 00379 } 00380 else if( y == 0.0 ) 00381 { 00382 if( x > 0.0 ) 00383 return( 0.0 ); 00384 else 00385 return( PI ); 00386 } 00387 else 00388 { 00389 radians = - (Real) atan2( (double) y, (double) x ); 00390 00391 if( radians < 0.0 ) 00392 radians += 2.0 * PI; 00393 00394 return( radians ); 00395 } 00396 } 00397 00398 public BOOLEAN is_transform_right_handed( 00399 Transform *transform ) 00400 { 00401 Real volume; 00402 Vector x_axis, y_axis, z_axis, offset; 00403 00404 get_transform_x_axis( transform, &x_axis ); 00405 get_transform_y_axis( transform, &y_axis ); 00406 get_transform_z_axis( transform, &z_axis ); 00407 00408 CROSS_VECTORS( offset, x_axis, y_axis ); 00409 volume = DOT_VECTORS( offset, z_axis ); 00410 00411 return( volume > 0.0 ); 00412 } 00413 00414 /* ----------------------------- MNI Header ----------------------------------- 00415 @NAME : make_identity_transform_2d 00416 @INPUT : transform 00417 @OUTPUT : 00418 @RETURNS : 00419 @DESCRIPTION: Fills in the 2d transform with the identity transform. 00420 @METHOD : 00421 @GLOBALS : 00422 @CALLS : 00423 @CREATED : 1993 David MacDonald 00424 @MODIFIED : 00425 ---------------------------------------------------------------------------- */ 00426 00427 public void make_identity_transform_2d( 00428 Transform_2d *transform ) 00429 { 00430 Transform_2d_elem( *transform, 0, 0 ) = 1.0; 00431 Transform_2d_elem( *transform, 0, 1 ) = 0.0; 00432 Transform_2d_elem( *transform, 0, 2 ) = 0.0; 00433 Transform_2d_elem( *transform, 1, 0 ) = 0.0; 00434 Transform_2d_elem( *transform, 1, 1 ) = 1.0; 00435 Transform_2d_elem( *transform, 1, 2 ) = 0.0; 00436 } 00437 00438 /* ----------------------------- MNI Header ----------------------------------- 00439 @NAME : get_inverse_transform_2d 00440 @INPUT : transform 00441 @OUTPUT : inverse 00442 @RETURNS : 00443 @DESCRIPTION: Passes back the inverse of the 2d transform. 00444 @METHOD : 00445 @GLOBALS : 00446 @CALLS : 00447 @CREATED : 1993 David MacDonald 00448 @MODIFIED : 00449 ---------------------------------------------------------------------------- */ 00450 00451 public void get_inverse_transform_2d( 00452 Transform_2d *transform, 00453 Transform_2d *inverse ) 00454 { 00455 Real determinant; 00456 00457 determinant = Transform_2d_elem(*transform,0,0) * 00458 Transform_2d_elem(*transform,1,1) - 00459 Transform_2d_elem(*transform,1,0) * 00460 Transform_2d_elem(*transform,0,1); 00461 00462 Transform_2d_elem(*inverse,0,0) = Transform_2d_elem(*transform,1,1) / 00463 determinant; 00464 Transform_2d_elem(*inverse,0,1) = -Transform_2d_elem(*transform,0,1) / 00465 determinant; 00466 Transform_2d_elem(*inverse,0,2) = (Transform_2d_elem(*transform,1,2) * 00467 Transform_2d_elem(*transform,0,1) - 00468 Transform_2d_elem(*transform,1,1) * 00469 Transform_2d_elem(*transform,0,2)) / 00470 determinant; 00471 00472 Transform_2d_elem(*inverse,1,0) = -Transform_2d_elem(*transform,1,0) / 00473 determinant; 00474 Transform_2d_elem(*inverse,1,1) = Transform_2d_elem(*transform,0,0) / 00475 determinant; 00476 Transform_2d_elem(*inverse,1,2) = (Transform_2d_elem(*transform,1,0) * 00477 Transform_2d_elem(*transform,0,2) - 00478 Transform_2d_elem(*transform,0,0) * 00479 Transform_2d_elem(*transform,1,2)) / 00480 determinant; 00481 } 00482 00483 /* ----------------------------- MNI Header ----------------------------------- 00484 @NAME : transform_point_2d 00485 @INPUT : transform 00486 x 00487 y 00488 @OUTPUT : x_trans 00489 y_trans 00490 @RETURNS : 00491 @DESCRIPTION: Transforms a 2d point by the specified transform. 00492 @METHOD : 00493 @GLOBALS : 00494 @CALLS : 00495 @CREATED : 1993 David MacDonald 00496 @MODIFIED : 00497 ---------------------------------------------------------------------------- */ 00498 00499 public void transform_point_2d( 00500 Transform_2d *transform, 00501 Real x, 00502 Real y, 00503 Real *x_trans, 00504 Real *y_trans ) 00505 { 00506 *x_trans = Transform_2d_elem(*transform,0,0) * x + 00507 Transform_2d_elem(*transform,0,1) * y + 00508 Transform_2d_elem(*transform,0,2); 00509 *y_trans = Transform_2d_elem(*transform,1,0) * x + 00510 Transform_2d_elem(*transform,1,1) * y + 00511 Transform_2d_elem(*transform,1,2); 00512 } 00513 00514 /* ----------------------------- MNI Header ----------------------------------- 00515 @NAME : get_least_squares_transform_2d 00516 @INPUT : n_points 00517 x 00518 y 00519 x_trans 00520 y_trans 00521 @OUTPUT : transform_2d 00522 @RETURNS : 00523 @DESCRIPTION: Computes the 2d transform that best transforms the points 00524 ( x[], y[] ) to ( x_trans[], y_trans[] ), using linear least 00525 squares. 00526 @METHOD : 00527 @GLOBALS : 00528 @CALLS : 00529 @CREATED : 1993 David MacDonald 00530 @MODIFIED : 00531 ---------------------------------------------------------------------------- */ 00532 00533 public void get_least_squares_transform_2d( 00534 int n_points, 00535 Real x[], 00536 Real y[], 00537 Real x_trans[], 00538 Real y_trans[], 00539 Transform_2d *transform_2d ) 00540 { 00541 int p; 00542 Real coefs[2+1]; 00543 Real **coords; 00544 00545 ALLOC2D( coords, n_points, 2 ); 00546 00547 for_less( p, 0, n_points ) 00548 { 00549 coords[p][X] = x[p]; 00550 coords[p][Y] = y[p]; 00551 } 00552 00553 least_squares( n_points, 2, coords, x_trans, coefs ); 00554 00555 Transform_2d_elem( *transform_2d, 0, 0 ) = coefs[1]; 00556 Transform_2d_elem( *transform_2d, 0, 1 ) = coefs[2]; 00557 Transform_2d_elem( *transform_2d, 0, 2 ) = coefs[0]; 00558 00559 least_squares( n_points, 2, coords, y_trans, coefs ); 00560 00561 Transform_2d_elem( *transform_2d, 1, 0 ) = coefs[1]; 00562 Transform_2d_elem( *transform_2d, 1, 1 ) = coefs[2]; 00563 Transform_2d_elem( *transform_2d, 1, 2 ) = coefs[0]; 00564 00565 FREE2D( coords ); 00566 }

Generated on Wed Jul 28 09:10:58 2004 for BICPL by doxygen 1.3.7