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

polygon_sphere.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/numerical.h> 00018 00019 #ifndef lint 00020 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Geometry/polygon_sphere.c,v 1.16 2000/02/06 15:30:16 stever Exp $"; 00021 #endif 00022 00023 private int get_n_sphere_points( 00024 int n_up, 00025 int n_around ); 00026 private void get_sphere_point( 00027 Real up, 00028 Real around, 00029 Point *centre, 00030 Real x_size, 00031 Real y_size, 00032 Real z_size, 00033 Point *point ); 00034 private void get_subdivided_point( 00035 int up, 00036 int around, 00037 Point input_points[], 00038 int input_n_up, 00039 Point *point ); 00040 00041 /* ----------------------------- MNI Header ----------------------------------- 00042 @NAME : create_polygons_sphere 00043 @INPUT : centre 00044 x_size 00045 y_size 00046 z_size 00047 n_up 00048 n_around 00049 subdividing_flag 00050 @OUTPUT : polygons 00051 @RETURNS : 00052 @DESCRIPTION: Creates a tessellated sphere, using lines of latitude and 00053 longitude to create triangles around the poles, and quadrilaterals 00054 everywhere else. If subdividing_flag is true, then we are 00055 subdividing the polygons and are maintaining its sphere topology. 00056 @METHOD : 00057 @GLOBALS : 00058 @CALLS : 00059 @CREATED : 1993 David MacDonald 00060 @MODIFIED : 00061 ---------------------------------------------------------------------------- */ 00062 00063 public void create_polygons_sphere( 00064 Point *centre, 00065 Real x_size, 00066 Real y_size, 00067 Real z_size, 00068 int n_up, 00069 int n_around, 00070 BOOLEAN subdividing_flag, 00071 polygons_struct *polygons ) 00072 { 00073 int point_index, top_point_index, bottom_point_index; 00074 int point_index1, point_index2, point_index3, point_index4; 00075 int up, around, n_circum, next_around, n_indices, end, start, a; 00076 int n_around_top; 00077 Point *input_points; 00078 Colour save_colour; 00079 int input_n_up; 00080 Real up_pos, around_pos; 00081 00082 if( subdividing_flag ) 00083 { 00084 if( !get_tessellation_of_polygons_sphere( polygons, &input_n_up )) 00085 { 00086 print_error( "Not a sphere topology polygon.\n" ); 00087 return; 00088 } 00089 00090 n_up = 2 * input_n_up; 00091 n_around = 2 * n_up; 00092 00093 save_colour = polygons->colours[0]; 00094 00095 input_points = polygons->points; 00096 00097 /* so delete polygons frees a valid pointer */ 00098 00099 ALLOC( polygons->points, 1 ); 00100 00101 delete_polygons( polygons ); 00102 } 00103 00104 initialize_polygons( polygons, WHITE, (Surfprop *) NULL ); 00105 00106 if( subdividing_flag ) 00107 polygons->colours[0] = save_colour; 00108 00109 polygons->n_points = get_n_sphere_points( n_up, n_around ); 00110 00111 ALLOC( polygons->points, polygons->n_points ); 00112 ALLOC( polygons->normals, polygons->n_points ); 00113 00114 /* ------ build points ------ */ 00115 00116 for_less( up, 0, n_up+1 ) 00117 { 00118 up_pos = (Real) up / (Real) n_up; 00119 00120 if( up == 0 || up == n_up ) 00121 n_circum = 1; 00122 else 00123 n_circum = n_around; 00124 00125 for_less( around, 0, n_circum ) 00126 { 00127 around_pos = (Real) around / (Real) n_around; 00128 00129 point_index = get_sphere_point_index( up, around, n_up, n_around ); 00130 00131 if( subdividing_flag ) 00132 { 00133 get_subdivided_point( up, around, input_points, input_n_up, 00134 &polygons->points[point_index] ); 00135 } 00136 else 00137 { 00138 get_sphere_point( up_pos, around_pos, centre, x_size, y_size, 00139 z_size, &polygons->points[point_index] ); 00140 } 00141 } 00142 } 00143 00144 if( subdividing_flag ) 00145 FREE( input_points ); 00146 00147 n_indices = 0; 00148 00149 /* ------ build indices for top ------ */ 00150 00151 top_point_index = get_sphere_point_index( 0, 0, n_up, n_around ); 00152 00153 #ifdef N_AROUND_TOP 00154 n_around_top = N_AROUND_TOP; 00155 #else 00156 n_around_top = n_around; 00157 #endif 00158 00159 for_less( a, 0, n_around_top ) 00160 { 00161 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00162 top_point_index, DEFAULT_CHUNK_SIZE ); 00163 00164 start = n_around * a / n_around_top; 00165 end = n_around * (a+1) / n_around_top + 1; 00166 if( end > n_around + 1 ) 00167 end = n_around + 1; 00168 for_less( around, start, end ) 00169 { 00170 point_index = get_sphere_point_index( 1, around % n_around, 00171 n_up, n_around ); 00172 00173 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00174 point_index, DEFAULT_CHUNK_SIZE ); 00175 } 00176 00177 ADD_ELEMENT_TO_ARRAY( polygons->end_indices, polygons->n_items, 00178 n_indices, DEFAULT_CHUNK_SIZE ); 00179 } 00180 00181 /* ------ build indices for main part ------ */ 00182 00183 for_less( up, 1, n_up-1 ) 00184 { 00185 for_less( around, 0, n_around ) 00186 { 00187 next_around = (around + 1) % n_around; 00188 point_index1 = get_sphere_point_index( up, around, n_up, n_around ); 00189 point_index2 = get_sphere_point_index( up+1, around, n_up, n_around ); 00190 point_index3 = get_sphere_point_index( up+1, next_around, n_up, n_around ); 00191 point_index4 = get_sphere_point_index( up, next_around, n_up, n_around ); 00192 00193 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00194 point_index1, DEFAULT_CHUNK_SIZE ); 00195 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00196 point_index2, DEFAULT_CHUNK_SIZE ); 00197 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00198 point_index3, DEFAULT_CHUNK_SIZE ); 00199 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00200 point_index4, DEFAULT_CHUNK_SIZE ); 00201 00202 ADD_ELEMENT_TO_ARRAY( polygons->end_indices, polygons->n_items, 00203 n_indices, DEFAULT_CHUNK_SIZE ); 00204 } 00205 } 00206 00207 /* ------ build indices for bottom ------ */ 00208 00209 bottom_point_index = get_sphere_point_index( n_up, 0, n_up, n_around ); 00210 00211 for_less( a, 0, n_around_top ) 00212 { 00213 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00214 bottom_point_index, DEFAULT_CHUNK_SIZE ); 00215 00216 end = n_around * a / n_around_top; 00217 start = n_around * (a+1) / n_around_top; 00218 if( start > n_around ) 00219 start = n_around; 00220 for( around = start; around >= end; --around ) 00221 { 00222 point_index = get_sphere_point_index( n_up-1, around % n_around, 00223 n_up, n_around ); 00224 00225 ADD_ELEMENT_TO_ARRAY( polygons->indices, n_indices, 00226 point_index, DEFAULT_CHUNK_SIZE ); 00227 } 00228 00229 ADD_ELEMENT_TO_ARRAY( polygons->end_indices, polygons->n_items, 00230 n_indices, DEFAULT_CHUNK_SIZE ); 00231 } 00232 } 00233 00234 /* ----------------------------- MNI Header ----------------------------------- 00235 @NAME : get_sphere_point_index 00236 @INPUT : up 00237 around 00238 n_up 00239 n_around 00240 @OUTPUT : 00241 @RETURNS : index 00242 @DESCRIPTION: Computes the point index in the sphere tessellation, where 00243 up is in range 0 to n_up, and around is in the range of 0 00244 to n_around-1. up = 0 and up == n_up correspond to the 2 poles. 00245 @METHOD : 00246 @GLOBALS : 00247 @CALLS : 00248 @CREATED : 1993 David MacDonald 00249 @MODIFIED : 00250 ---------------------------------------------------------------------------- */ 00251 00252 public int get_sphere_point_index( 00253 int up, 00254 int around, 00255 int n_up, 00256 int n_around ) 00257 { 00258 int point_index; 00259 00260 if( up < 0 || up > n_up || around < 0 || around >= n_around ) 00261 { 00262 print_error( "up %d/%d around %d/%d\n", up, n_up, 00263 around, n_around ); 00264 handle_internal_error( "get_sphere_point_index" ); 00265 } 00266 00267 if( up == 0 ) 00268 { 00269 point_index = 0; 00270 } 00271 else if( up == n_up ) 00272 { 00273 point_index = 1; 00274 } 00275 else 00276 { 00277 point_index = 2 + IJ( up-1, around, n_around ); 00278 } 00279 00280 return( point_index ); 00281 } 00282 00283 /* ----------------------------- MNI Header ----------------------------------- 00284 @NAME : get_n_sphere_points 00285 @INPUT : n_up 00286 n_around 00287 @OUTPUT : 00288 @RETURNS : number of points 00289 @DESCRIPTION: 00290 @METHOD : 00291 @GLOBALS : 00292 @CALLS : 00293 @CREATED : 1993 David MacDonald 00294 @MODIFIED : 00295 ---------------------------------------------------------------------------- */ 00296 00297 private int get_n_sphere_points( 00298 int n_up, 00299 int n_around ) 00300 { 00301 return( 2 + (n_up-1) * n_around ); 00302 } 00303 00304 /* ----------------------------- MNI Header ----------------------------------- 00305 @NAME : get_sphere_point 00306 @INPUT : up : between 0 and 1 00307 around : between 0 and 1 00308 centre 00309 x_size 00310 y_size 00311 z_size 00312 @OUTPUT : point 00313 @RETURNS : 00314 @DESCRIPTION: Computes a point on a sphere. 00315 @METHOD : 00316 @GLOBALS : 00317 @CALLS : 00318 @CREATED : 1993 David MacDonald 00319 @MODIFIED : 00320 ---------------------------------------------------------------------------- */ 00321 00322 private void get_sphere_point( 00323 Real up, 00324 Real around, 00325 Point *centre, 00326 Real x_size, 00327 Real y_size, 00328 Real z_size, 00329 Point *point ) 00330 { 00331 Real dx, dy, dz; 00332 00333 dx = x_size * cos( (double) up * PI ); 00334 dy = y_size * sin( (double) up * PI ) * cos( (double) around * 2.0 *PI); 00335 dz = z_size * sin( (double) up * PI ) * sin( (double) around * 2.0 *PI); 00336 00337 fill_Point( *point, (Real) Point_x(*centre) + dx, 00338 (Real) Point_y(*centre) + dy, 00339 (Real) Point_z(*centre) + dz ); 00340 } 00341 00342 /* ----------------------------- MNI Header ----------------------------------- 00343 @NAME : get_subdivided_point 00344 @INPUT : up 00345 around 00346 input_points 00347 input_n_up 00348 @OUTPUT : point 00349 @RETURNS : 00350 @DESCRIPTION: Finds the point in the subdivided sphere topology. 00351 @METHOD : 00352 @GLOBALS : 00353 @CALLS : 00354 @CREATED : 1993 David MacDonald 00355 @MODIFIED : 00356 ---------------------------------------------------------------------------- */ 00357 00358 private void get_subdivided_point( 00359 int up, 00360 int around, 00361 Point input_points[], 00362 int input_n_up, 00363 Point *point ) 00364 { 00365 int input_up, input_around; 00366 BOOLEAN up_midpoint_flag, around_midpoint_flag; 00367 Point corner_below, corner_across, corner_below_across; 00368 00369 input_up = up / 2; 00370 up_midpoint_flag = (up & 1) == 1; 00371 input_around = around / 2; 00372 around_midpoint_flag = (around & 1) == 1; 00373 00374 *point = input_points[get_sphere_point_index( input_up, 00375 input_around, input_n_up, 2 * input_n_up )]; 00376 00377 if( up_midpoint_flag ) 00378 { 00379 corner_below = input_points[get_sphere_point_index( input_up+1, 00380 input_around, input_n_up, 2 * input_n_up )]; 00381 INTERPOLATE_POINTS( *point, *point, corner_below, 0.5 ); 00382 } 00383 00384 if( around_midpoint_flag ) 00385 { 00386 corner_across = input_points[get_sphere_point_index( input_up, 00387 (input_around + 1) % (2*input_n_up), input_n_up, 2*input_n_up )]; 00388 00389 if( up_midpoint_flag ) 00390 { 00391 corner_below_across = input_points[get_sphere_point_index( 00392 input_up+1, (input_around + 1) % (2*input_n_up), 00393 input_n_up, 2*input_n_up )]; 00394 INTERPOLATE_POINTS( corner_across, corner_across, 00395 corner_below_across, 0.5 ); 00396 } 00397 00398 INTERPOLATE_POINTS( *point, *point, corner_across, 0.5 ); 00399 } 00400 } 00401 00402 /* ----------------------------- MNI Header ----------------------------------- 00403 @NAME : is_this_sphere_topology 00404 @INPUT : polygons 00405 @OUTPUT : 00406 @RETURNS : TRUE or FALSE 00407 @DESCRIPTION: Returns true if the polygons are of sphere topology. 00408 @METHOD : 00409 @GLOBALS : 00410 @CALLS : 00411 @CREATED : 1993 David MacDonald 00412 @MODIFIED : 00413 ---------------------------------------------------------------------------- */ 00414 00415 public BOOLEAN is_this_sphere_topology( 00416 polygons_struct *polygons ) 00417 { 00418 int tess; 00419 00420 return( get_tessellation_of_polygons_sphere( polygons, &tess ) ); 00421 } 00422 00423 /* ----------------------------- MNI Header ----------------------------------- 00424 @NAME : get_tessellation_of_polygons_sphere 00425 @INPUT : polygons 00426 @OUTPUT : tess 00427 @RETURNS : TRUE or FALSE 00428 @DESCRIPTION: Determines if the polygons is of sphere topology and if so, 00429 what tessellation. 00430 @METHOD : 00431 @GLOBALS : 00432 @CALLS : 00433 @CREATED : 1993 David MacDonald 00434 @MODIFIED : 00435 ---------------------------------------------------------------------------- */ 00436 00437 public BOOLEAN get_tessellation_of_polygons_sphere( 00438 polygons_struct *polygons, 00439 int *tess ) 00440 { 00441 Real size; 00442 int int_size, n_around_top, n_triangles, i; 00443 BOOLEAN is_sphere; 00444 00445 is_sphere = FALSE; 00446 00447 if( polygons->n_items > 10 ) 00448 { 00449 #ifdef N_AROUND_TOP 00450 size = 1 + sqrt( (double) polygons->n_items / 2.0 + 1.0 - 00451 (double) N_AROUND_TOP ); 00452 n_around_top = N_AROUND_TOP; 00453 #else 00454 size = sqrt( (double) polygons->n_items / 2.0 ); 00455 n_around_top = 2 * ROUND( size ); 00456 #endif 00457 00458 if( IS_INT(size) ) 00459 { 00460 *tess = (int) size; 00461 00462 int_size = (int) size; 00463 while( (int_size & 1) == 0 ) 00464 { 00465 int_size >>= 1; 00466 } 00467 00468 is_sphere = (int_size == 1); 00469 } 00470 00471 if( is_sphere ) 00472 { 00473 n_triangles = 0; 00474 for_less( i, 0, polygons->n_items ) 00475 { 00476 if( GET_OBJECT_SIZE( *polygons, i ) == 3 ) 00477 ++n_triangles; 00478 } 00479 00480 if( n_triangles != 2 * n_around_top ) 00481 is_sphere = FALSE; 00482 } 00483 } 00484 00485 return( is_sphere ); 00486 } 00487 00488 /* ----------------------------- MNI Header ----------------------------------- 00489 @NAME : get_tessellation_with_n_points 00490 @INPUT : n_points 00491 @OUTPUT : 00492 @RETURNS : tess 00493 @DESCRIPTION: Given the number of points in the polygons, finds a sphere 00494 tessellation n_up that corresponds to this. 00495 @METHOD : 00496 @GLOBALS : 00497 @CALLS : 00498 @CREATED : 1993 David MacDonald 00499 @MODIFIED : 00500 ---------------------------------------------------------------------------- */ 00501 00502 public int get_tessellation_with_n_points( 00503 int n_points ) 00504 { 00505 Real a, b, c, s1, s2; 00506 int n_sol; 00507 00508 #ifdef N_AROUND_TOP 00509 a = 2.0; 00510 b = -6.0; 00511 c = 2.0 * (Real) N_AROUND_TOP + 2.0 - (Real) n_points; 00512 #else 00513 a = 2.0; 00514 b = -2.0; 00515 c = 2.0 - (Real) n_points; 00516 #endif 00517 00518 n_sol = solve_quadratic( a, b, c, &s1, &s2 ); 00519 00520 if( n_sol == 1 || (n_sol == 2 && s2 <= 0.0) ) 00521 { 00522 if( s1 > 0.0 ) 00523 return( ROUND( s1 ) ); 00524 } 00525 else if( n_sol == 2 ) 00526 return( ROUND( s2 ) ); 00527 00528 return( 0 ); 00529 } 00530 00531 /* ----------------------------- MNI Header ----------------------------------- 00532 @NAME : half_sample_sphere_tessellation 00533 @INPUT : polygons 00534 @OUTPUT : half 00535 @RETURNS : 00536 @DESCRIPTION: Half samples the sphere tessellation polygon, maintaining a 00537 sphere topology. 00538 @METHOD : 00539 @GLOBALS : 00540 @CALLS : 00541 @CREATED : 1993 David MacDonald 00542 @MODIFIED : 00543 ---------------------------------------------------------------------------- */ 00544 00545 public void half_sample_sphere_tessellation( 00546 polygons_struct *polygons, 00547 polygons_struct *half ) 00548 { 00549 static Point centre = { 0.0f, 0.0f, 0.0f }; 00550 int n_up, n_around, half_n_up, half_n_around; 00551 int up, around, n_circum, point_index, half_point_index; 00552 00553 if( get_tessellation_of_polygons_sphere( polygons, &n_up ) ) 00554 { 00555 n_around = 2 * n_up; 00556 half_n_up = n_up / 2; 00557 half_n_around = 2 * half_n_up; 00558 create_polygons_sphere( &centre, 1.0, 1.0, 1.0, half_n_up, 00559 half_n_around, FALSE, half ); 00560 00561 half->surfprop = polygons->surfprop; 00562 00563 if( polygons->colour_flag == ONE_COLOUR || 00564 polygons->colour_flag == PER_ITEM_COLOURS ) 00565 { 00566 half->colour_flag = ONE_COLOUR; 00567 half->colours[0] = polygons->colours[0]; 00568 } 00569 else 00570 { 00571 REALLOC( half->colours, half->n_points ); 00572 } 00573 00574 for_less( up, 0, half_n_up+1 ) 00575 { 00576 if( up == 0 || up == half_n_up ) 00577 n_circum = 1; 00578 else 00579 n_circum = half_n_around; 00580 00581 for_less( around, 0, n_circum ) 00582 { 00583 half_point_index = get_sphere_point_index( up, around, 00584 half_n_up, half_n_around ); 00585 point_index = get_sphere_point_index( 2 * up, 2 * around, 00586 n_up, n_around ); 00587 00588 half->points[half_point_index] = polygons->points[point_index]; 00589 00590 if( half->colour_flag == PER_VERTEX_COLOURS ) 00591 half->colours[half_point_index] = 00592 polygons->colours[point_index]; 00593 } 00594 } 00595 } 00596 }

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