00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
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
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
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
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
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
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
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
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
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
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
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
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
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
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
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
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
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
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
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
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
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
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( ¢re, 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 }