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

map_polygons.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/geom.h> 00017 #include <bicpl/trans.h> 00018 00019 #ifndef lint 00020 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Geometry/map_polygons.c,v 1.13 2000/02/06 15:30:15 stever Exp $"; 00021 #endif 00022 00023 /* ----------------------------- MNI Header ----------------------------------- 00024 @NAME : get_baricentric 00025 @INPUT : point 00026 p1 00027 p2 00028 p3 00029 @OUTPUT : 00030 @RETURNS : baricentric coordinate 00031 @DESCRIPTION: Returns the baricentric coordinate of the point within the 00032 triangle (p1,p2,p3), relative to the p3 point. 00033 @METHOD : 00034 @GLOBALS : 00035 @CALLS : 00036 @CREATED : 1993 David MacDonald 00037 @MODIFIED : 00038 ---------------------------------------------------------------------------- */ 00039 00040 private Real get_baricentric( 00041 Point *point, 00042 Point *p1, 00043 Point *p2, 00044 Point *p3 ) 00045 { 00046 Real weight; 00047 Vector hor, up, normal, vert, point_offset; 00048 00049 SUB_POINTS( point_offset, *point, *p1 ); 00050 SUB_POINTS( hor, *p2, *p1 ); 00051 SUB_POINTS( up, *p3, *p1 ); 00052 00053 CROSS_VECTORS( normal, hor, up ); 00054 CROSS_VECTORS( vert, normal, hor ); 00055 00056 weight = DOT_VECTORS( point_offset, vert ) / DOT_VECTORS( up, vert ); 00057 00058 return( weight ); 00059 } 00060 00061 /* ----------------------------- MNI Header ----------------------------------- 00062 @NAME : get_triangle_interpolation_weights 00063 @INPUT : point 00064 points 00065 @OUTPUT : weights 00066 @RETURNS : 00067 @DESCRIPTION: Computes the triangle interpolation weights, meaning the weights 00068 corresponding to each vertex. If the values at the vertex are 00069 v[0], v[1], v[2], they can be interpolated at point as 00070 value at point = v[0] * weights[0] + v[1] * weights[1] + 00071 v[2] * weights[2]. 00072 @METHOD : 00073 @GLOBALS : 00074 @CALLS : 00075 @CREATED : 1993 David MacDonald 00076 @MODIFIED : 00077 ---------------------------------------------------------------------------- */ 00078 00079 private void get_triangle_interpolation_weights( 00080 Point *point, 00081 Point points[], 00082 Real weights[] ) 00083 { 00084 weights[0] = get_baricentric( point, &points[1], &points[2], &points[0] ); 00085 weights[1] = get_baricentric( point, &points[2], &points[0], &points[1] ); 00086 weights[2] = get_baricentric( point, &points[0], &points[1], &points[2] ); 00087 } 00088 00089 /* ----------------------------- MNI Header ----------------------------------- 00090 @NAME : intersect_lines_2d 00091 @INPUT : p1 00092 p2 00093 q1 00094 q2 00095 @OUTPUT : intersect 00096 @RETURNS : TRUE if lines intersect 00097 @DESCRIPTION: Tests if two 2d lines intersect, i.e., are not parallel, and 00098 passes back the point of intersection. 00099 @METHOD : 00100 @GLOBALS : 00101 @CALLS : 00102 @CREATED : 1993 David MacDonald 00103 @MODIFIED : 00104 ---------------------------------------------------------------------------- */ 00105 00106 private BOOLEAN intersect_lines_2d( 00107 Real p1[], 00108 Real p2[], 00109 Real q1[], 00110 Real q2[], 00111 Real intersect[] ) 00112 { 00113 BOOLEAN intersects; 00114 Real t, bottom; 00115 Real dp[2], dq[2]; 00116 00117 dp[0] = p2[0] - p1[0]; 00118 dp[1] = p2[1] - p1[1]; 00119 dq[0] = q2[0] - q1[0]; 00120 dq[1] = q2[1] - q1[1]; 00121 00122 bottom = dp[0] * dq[1] - dp[1] * dq[0]; 00123 00124 if( bottom == 0.0 ) 00125 { 00126 intersects = FALSE; 00127 } 00128 else 00129 { 00130 t = (dq[0] * (p1[1] - q1[1]) + dq[1] * (q1[0] - p1[0])) / bottom; 00131 intersect[0] = p1[0] + t * (dp[0] - p1[0]); 00132 intersect[1] = p1[1] + t * (dp[1] - p1[1]); 00133 intersects = TRUE; 00134 } 00135 00136 return( intersects ); 00137 } 00138 00139 /* ----------------------------- MNI Header ----------------------------------- 00140 @NAME : get_two_d_coordinate 00141 @INPUT : p 00142 p1 00143 p2 00144 q1 00145 q2 00146 @OUTPUT : 00147 @RETURNS : two coordinate 00148 @DESCRIPTION: Returns a coordinate distance between 0 and 1 for a point in 00149 a quadrilateral, whose two opposite sides are p1--p2 and q1--q2. 00150 @METHOD : 00151 @GLOBALS : 00152 @CALLS : 00153 @CREATED : 1993 David MacDonald 00154 @MODIFIED : 00155 ---------------------------------------------------------------------------- */ 00156 00157 private Real get_two_d_coordinate( 00158 Point *p, 00159 Point *p1, 00160 Point *p2, 00161 Point *q1, 00162 Point *q2 ) 00163 { 00164 Real coords[4][2], coord[2], intersect[2]; 00165 Real intersect_point[2], len2, dx, dy, idx, idy, factor; 00166 Vector cross, offset, hor, vert, v1, v2; 00167 int i, j; 00168 Point points[4]; 00169 BOOLEAN found; 00170 00171 points[0] = *p1; 00172 points[1] = *p2; 00173 points[2] = *q2; 00174 points[3] = *q1; 00175 00176 found = FALSE; 00177 for_less( i, 0, 3 ) 00178 { 00179 SUB_POINTS( v1, points[i], points[0] ); 00180 for_less( j, i+1, 4 ) 00181 { 00182 SUB_POINTS( v2, points[j], points[0] ); 00183 CROSS_VECTORS( cross, v1, v2 ); 00184 if( !null_Vector(&cross) ) 00185 { 00186 found = TRUE; 00187 break; 00188 } 00189 } 00190 00191 if( found ) 00192 break; 00193 } 00194 00195 if( !found ) 00196 print_error( "get_two_d_coordinate: degenerate polygons\n" ); 00197 00198 create_two_orthogonal_vectors( &cross, &hor, &vert ); 00199 00200 for_less( i, 0, 4 ) 00201 { 00202 SUB_POINTS( offset, points[i], points[0] ); 00203 coords[i][0] = DOT_VECTORS( hor, offset ); 00204 coords[i][1] = DOT_VECTORS( vert, offset ); 00205 } 00206 00207 SUB_POINTS( offset, *p, points[0] ); 00208 coord[0] = DOT_VECTORS( hor, offset ); 00209 coord[1] = DOT_VECTORS( vert, offset ); 00210 00211 if( intersect_lines_2d( coords[0], coords[1], coords[3], coords[2], 00212 intersect ) ) 00213 { 00214 if( !intersect_lines_2d( intersect, coord, coords[0], coords[3], 00215 intersect_point ) ) 00216 return( 0.0 ); 00217 } 00218 else 00219 { 00220 intersect_point[0] = coord[0]; 00221 intersect_point[1] = coord[1]; 00222 } 00223 00224 dx = coords[3][0] - coords[0][0]; 00225 dy = coords[3][1] - coords[0][1]; 00226 00227 len2 = dx * dx + dy * dy; 00228 00229 idx = intersect_point[0] - coords[0][0]; 00230 idy = intersect_point[1] - coords[0][1]; 00231 00232 factor = (dx * idx + dy * idy) / len2; 00233 00234 return( factor ); 00235 } 00236 00237 /* ----------------------------- MNI Header ----------------------------------- 00238 @NAME : get_quadrilateral_interpolation_weights 00239 @INPUT : point 00240 points - 4 points 00241 @OUTPUT : weights 00242 @RETURNS : 00243 @DESCRIPTION: Gets the interpolation weights of the 4 quadrilateral vertices, 00244 by getting the equivalent u and v components on a unit square. 00245 @METHOD : 00246 @GLOBALS : 00247 @CALLS : 00248 @CREATED : 1993 David MacDonald 00249 @MODIFIED : 00250 ---------------------------------------------------------------------------- */ 00251 00252 private void get_quadrilateral_interpolation_weights( 00253 Point *point, 00254 Point points[], 00255 Real weights[] ) 00256 { 00257 Real u, v; 00258 00259 u = get_two_d_coordinate( point, 00260 &points[0], &points[3], &points[1], &points[2] ); 00261 v = get_two_d_coordinate( point, 00262 &points[0], &points[1], &points[3], &points[2] ); 00263 00264 weights[0] = (1.0 - u) * (1.0 - v); 00265 weights[1] = u * (1.0 - v); 00266 weights[2] = u * v; 00267 weights[3] = (1.0 - u) * v; 00268 } 00269 00270 /* ----------------------------- MNI Header ----------------------------------- 00271 @NAME : get_arbitrary_polygon_interpolation_weights 00272 @INPUT : point 00273 n_points 00274 @OUTPUT : weights 00275 @RETURNS : 00276 @DESCRIPTION: Computes the interpolation weights of each vertex of a polygon. 00277 @METHOD : 00278 @GLOBALS : 00279 @CALLS : 00280 @CREATED : 1993 David MacDonald 00281 @MODIFIED : 00282 ---------------------------------------------------------------------------- */ 00283 00284 private void get_arbitrary_polygon_interpolation_weights( 00285 Point *point, 00286 int n_points, 00287 Point points[], 00288 Real weights[] ) 00289 { 00290 int i, j; 00291 Real sum_weights, alpha, dist; 00292 00293 for_less( i, 0, n_points ) 00294 weights[i] = 0.0; 00295 00296 sum_weights = 0.0; 00297 00298 for_less( i, 0, n_points ) 00299 { 00300 dist = get_distance_to_line_segment( point, 00301 &points[i], &points[(i+1)%n_points], 00302 &alpha ); 00303 00304 if( dist == 0.0 ) 00305 { 00306 for_less( j, 0, n_points ) 00307 weights[j] = 0.0; 00308 weights[i] = 1.0 - alpha; 00309 weights[(i+1)%n_points] = alpha; 00310 sum_weights = 1.0; 00311 break; 00312 } 00313 00314 weights[i] += (1.0 - alpha) / dist; 00315 weights[(i+1)%n_points] += alpha / dist; 00316 00317 sum_weights += 1.0 / dist; 00318 } 00319 00320 for_less( i, 0, n_points ) 00321 weights[i] /= sum_weights; 00322 } 00323 00324 /* ----------------------------- MNI Header ----------------------------------- 00325 @NAME : get_polygon_interpolation_weights 00326 @INPUT : point 00327 n_points 00328 points 00329 @OUTPUT : weights 00330 @RETURNS : 00331 @DESCRIPTION: Computes the interpolation weights for the polygon vertices. 00332 @METHOD : 00333 @GLOBALS : 00334 @CALLS : 00335 @CREATED : 1993 David MacDonald 00336 @MODIFIED : 00337 ---------------------------------------------------------------------------- */ 00338 00339 public void get_polygon_interpolation_weights( 00340 Point *point, 00341 int n_points, 00342 Point points[], 00343 Real weights[] ) 00344 { 00345 if( n_points == 3 ) 00346 { 00347 get_triangle_interpolation_weights( point, points, weights ); 00348 } 00349 else if( n_points == 4 ) 00350 { 00351 get_quadrilateral_interpolation_weights( point, points, weights ); 00352 } 00353 else 00354 { 00355 get_arbitrary_polygon_interpolation_weights( point, n_points, 00356 points, weights ); 00357 } 00358 } 00359 00360 /* ----------------------------- MNI Header ----------------------------------- 00361 @NAME : map_point_between_polygons 00362 @INPUT : p1 - polygons struct 00363 poly_index - which polygon 00364 p1_point - a point in the polygon 00365 p2 - the destination polygons of same topology 00366 @OUTPUT : p2_point - the corresponding point in the second polygon 00367 @RETURNS : distance of p1_point from the polygons 00368 @DESCRIPTION: Given two polygons of the same topology and a point in the first 00369 polygon, finds the corresponding point in the second polygon. 00370 @METHOD : 00371 @GLOBALS : 00372 @CALLS : 00373 @CREATED : 1993 David MacDonald 00374 @MODIFIED : 00375 ---------------------------------------------------------------------------- */ 00376 00377 public void map_point_between_polygons( 00378 polygons_struct *p1, 00379 int poly_index, 00380 Point *p1_point, 00381 polygons_struct *p2, 00382 Point *p2_point ) 00383 { 00384 int i, size; 00385 Point poly1_points[MAX_POINTS_PER_POLYGON]; 00386 Point poly2_points[MAX_POINTS_PER_POLYGON]; 00387 Point scaled_point; 00388 Real weights[MAX_POINTS_PER_POLYGON]; 00389 00390 size = get_polygon_points( p1, poly_index, poly1_points ); 00391 00392 get_polygon_interpolation_weights( p1_point, size, poly1_points, weights ); 00393 00394 if( get_polygon_points( p2, poly_index, poly2_points ) != size ) 00395 handle_internal_error( "map_point_between_polygons" ); 00396 00397 fill_Point( *p2_point, 0.0, 0.0, 0.0 ); 00398 00399 for_less( i, 0, size ) 00400 { 00401 SCALE_POINT( scaled_point, poly2_points[i], weights[i] ); 00402 ADD_POINTS( *p2_point, *p2_point, scaled_point ); 00403 } 00404 } 00405 00406 /* ----------------------------- MNI Header ----------------------------------- 00407 @NAME : map_point_to_unit_sphere 00408 @INPUT : p 00409 point 00410 unit_sphere 00411 @OUTPUT : unit_sphere_point 00412 @RETURNS : distance of point from polygons 00413 @DESCRIPTION: Maps a point on a polygon to the unit sphere of the same topology. 00414 Returns the distance of the point from the polygons. Usually, 00415 we are mapping points on the polygon to points on the sphere, 00416 so the distance will be 0. However, we may want map points near 00417 the polygons, so we will return the distance so that the 00418 calling program may use the distance to determine if mapping this 00419 point makes sense. 00420 @METHOD : 00421 @GLOBALS : 00422 @CALLS : 00423 @CREATED : 1993 David MacDonald 00424 @MODIFIED : 00425 ---------------------------------------------------------------------------- */ 00426 00427 public Real map_point_to_unit_sphere( 00428 polygons_struct *p, 00429 Point *point, 00430 polygons_struct *unit_sphere, 00431 Point *unit_sphere_point ) 00432 { 00433 Real mag, dist; 00434 Point poly_point; 00435 Vector offset; 00436 int poly; 00437 00438 poly = find_closest_polygon_point( point, p, &poly_point ); 00439 00440 dist = distance_between_points( point, &poly_point ); 00441 00442 map_point_between_polygons( p, poly, &poly_point, unit_sphere, 00443 unit_sphere_point ); 00444 00445 CONVERT_POINT_TO_VECTOR( offset, *unit_sphere_point ); 00446 00447 mag = MAGNITUDE( offset ); 00448 00449 /*--- project it to the sphere */ 00450 00451 if( mag != 1.0 ) 00452 { 00453 SCALE_POINT( *unit_sphere_point, *unit_sphere_point, 1.0 / mag ); 00454 } 00455 00456 return( dist ); 00457 } 00458 00459 public void map_unit_sphere_to_point( 00460 polygons_struct *unit_sphere, 00461 Point *unit_sphere_point, 00462 polygons_struct *p, 00463 Point *point ) 00464 { 00465 Point poly_point; 00466 int poly; 00467 00468 poly = find_closest_polygon_point( unit_sphere_point, unit_sphere, 00469 &poly_point ); 00470 00471 map_point_between_polygons( unit_sphere, poly, &poly_point, p, 00472 point ); 00473 } 00474 00475 00476 /* ----------------------------- MNI Header ----------------------------------- 00477 @NAME : polygon_transform_point 00478 @INPUT : src_object 00479 dest_object 00480 src_point 00481 @OUTPUT : dest_point 00482 @RETURNS : 00483 @DESCRIPTION: Finds the point on the destination polygons corresponding to the 00484 src_point on the source polygons. 00485 @METHOD : 00486 @GLOBALS : 00487 @CALLS : 00488 @CREATED : 1993 David MacDonald 00489 @MODIFIED : 00490 ---------------------------------------------------------------------------- */ 00491 00492 private void polygon_transform_point( 00493 object_struct *src_object, 00494 object_struct *dest_object, 00495 Point *src_point, 00496 Point *dest_point ) 00497 { 00498 int obj_index; 00499 Point point; 00500 00501 (void) find_closest_point_on_object( src_point, src_object, &obj_index, 00502 &point ); 00503 00504 map_point_between_polygons( get_polygons_ptr(src_object), obj_index, 00505 &point, get_polygons_ptr(dest_object), 00506 dest_point ); 00507 } 00508 00509 /* ----------------------------- MNI Header ----------------------------------- 00510 @NAME : polygon_transform_points 00511 @INPUT : src_polygons 00512 dest_polygons 00513 n_points 00514 src_points 00515 @OUTPUT : dest_points 00516 @RETURNS : 00517 @DESCRIPTION: Maps each of the src_point to the dest_polygons. 00518 @METHOD : 00519 @GLOBALS : 00520 @CALLS : 00521 @CREATED : 1993 David MacDonald 00522 @MODIFIED : 00523 ---------------------------------------------------------------------------- */ 00524 00525 public void polygon_transform_points( 00526 polygons_struct *src_polygons, 00527 polygons_struct *dest_polygons, 00528 int n_points, 00529 Point src_points[], 00530 Point dest_points[] ) 00531 { 00532 int i; 00533 object_struct *src_object, *dest_object; 00534 00535 if( !polygons_are_same_topology( src_polygons, dest_polygons ) ) 00536 { 00537 print_error( 00538 "polygon_transform_points: polygons are not same topology.\n" ); 00539 return; 00540 } 00541 00542 src_object = create_object( POLYGONS ); 00543 *get_polygons_ptr(src_object) = *src_polygons; 00544 dest_object = create_object( POLYGONS ); 00545 *get_polygons_ptr(dest_object) = *dest_polygons; 00546 00547 for_less( i, 0, n_points ) 00548 { 00549 polygon_transform_point( src_object, dest_object, 00550 &src_points[i], &dest_points[i] ); 00551 } 00552 } 00553 00554 public void map_sphere_to_uv( 00555 Real x, 00556 Real y, 00557 Real z, 00558 Real *u, 00559 Real *v ) 00560 { 00561 Real angle_up, angle_around; 00562 00563 angle_up = acos( z ); 00564 00565 *v = 1.0 - angle_up / PI; 00566 00567 angle_around = compute_clockwise_rotation( x, -y ); 00568 00569 *u = angle_around / (2.0*PI); 00570 } 00571 00572 public void map_uv_to_sphere( 00573 Real u, 00574 Real v, 00575 Real *x, 00576 Real *y, 00577 Real *z ) 00578 { 00579 Real r; 00580 00581 *z = cos( (1.0 - v) * PI ); 00582 r = sin( (1.0 - v) * PI ); 00583 00584 *x = r * cos( u * 2.0 * PI ); 00585 *y = r * sin( u * 2.0 * PI ); 00586 }

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