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/data_structures.h>
00017
00018
#ifndef lint
00019
static char rcsid[] =
"$Header: /software/source//libraries/bicpl/Data_structures/build_bintree.c,v 1.12 2000/02/06 15:30:10 stever Exp $";
00020
#endif
00021
00022 #define NODE_VISIT_COST 0.02
00023 #define NET_CHANGE_THRESHOLD 0.0
00024
00025 typedef struct
00026
{
00027 bintree_node_struct **ptr_to_node;
00028 range_struct limits;
00029 }
leaf_queue_type;
00030
00031 typedef PRIORITY_QUEUE_STRUCT(
leaf_queue_type ) leaf_queue_struct;
00032
00033
00034
00035 private
void subdivide_bintree(
00036
bintree_struct_ptr bintree,
00037
int max_nodes,
00038
int n_objects,
00039
range_struct bound_vols[] );
00040 private
void split_node(
00041
range_struct bound_vols[],
00042
bintree_node_struct **ptr_to_node,
00043
range_struct *limits,
00044
int *n_nodes,
00045
range_struct *left_limits,
00046 Real *left_cost,
00047
range_struct *right_limits,
00048 Real *right_cost );
00049 private
void create_leaf_queue(
00050 leaf_queue_struct *leaf_queue );
00051 private
void delete_leaf_queue(
00052 leaf_queue_struct *leaf_queue );
00053 private BOOLEAN leaf_queue_empty(
00054 leaf_queue_struct *leaf_queue );
00055 private
void insert_in_leaf_queue(
00056 leaf_queue_struct *leaf_queue,
00057
bintree_node_struct **ptr_to_node,
00058 Real node_cost,
00059
range_struct *limits );
00060 private
void remove_from_leaf_queue(
00061 leaf_queue_struct *leaf_queue,
00062
bintree_node_struct ***ptr_to_node,
00063
range_struct *limits );
00064 private BOOLEAN node_tightly_bounds_object(
00065
range_struct *bound_vol,
00066
range_struct *limits );
00067 private
void recursive_efficiency_count(
00068
bintree_node_struct *node,
00069
range_struct *limits,
00070 Real *avg_nodes_visited,
00071 Real *avg_objects_visited );
00072 private Real node_visit_estimation(
00073
range_struct *limits );
00074
00075
00076
00077 #define FACTOR 1.0e-4
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 public
void create_object_bintree(
00095
int n_objects,
00096
range_struct bound_vols[],
00097
bintree_struct_ptr bintree,
00098
int max_nodes )
00099 {
00100
int i, c;
00101 Real avg_nodes, avg_objects, limits[N_DIMENSIONS][2], size;
00102
#ifdef DEBUG
00103
Real best_objects;
00104
#endif
00105
00106 for_less( i, 0, n_objects )
00107 {
00108 for_less( c, 0, N_DIMENSIONS )
00109 {
00110 size = (Real) bound_vols[i].limits[c][1] -
00111 (Real) bound_vols[i].limits[c][0];
00112 bound_vols[i].limits[c][0] -= (
float) (size *
FACTOR);
00113 bound_vols[i].limits[c][1] += (
float) (size *
FACTOR);
00114 }
00115
00116
if( i == 0 )
00117 {
00118 limits[X][0] = (Real) bound_vols[i].limits[X][0];
00119 limits[Y][0] = (Real) bound_vols[i].limits[Y][0];
00120 limits[Z][0] = (Real) bound_vols[i].limits[Z][0];
00121 limits[X][1] = (Real) bound_vols[i].limits[X][1];
00122 limits[Y][1] = (Real) bound_vols[i].limits[Y][1];
00123 limits[Z][1] = (Real) bound_vols[i].limits[Z][1];
00124 }
00125
else
00126 {
00127 for_less( c, 0, N_DIMENSIONS )
00128 {
00129
if( (Real) bound_vols[i].limits[c][0] < limits[c][0] )
00130 limits[c][0] = (Real) bound_vols[i].limits[c][0];
00131
if( (Real) bound_vols[i].limits[c][1] > limits[c][1] )
00132 limits[c][1] = (Real) bound_vols[i].limits[c][1];
00133 }
00134 }
00135 }
00136
00137
initialize_bintree( limits[X][0], limits[X][1],
00138 limits[Y][0], limits[Y][1],
00139 limits[Z][0], limits[Z][1], bintree );
00140
00141
subdivide_bintree( bintree, max_nodes, n_objects, bound_vols );
00142
00143
evaluate_bintree_efficiency( bintree, &avg_nodes, &avg_objects );
00144
00145
#ifdef DEBUG
00146
best_objects = 0.0;
00147 for_less( i, 0, n_objects )
00148 best_objects +=
node_visit_estimation( &bound_vols[i] );
00149 best_objects /=
node_visit_estimation( &bintree->range );
00150
00151 print(
"Est Nodes Visit: %g Est Objects Visit %g (Best possible: %g\n",
00152 avg_nodes, avg_objects, best_objects );
00153
00154
if( n_objects > 100 && avg_objects > (Real) n_objects * 0.1 )
00155 {
00156 print(
"Warning, bintree not efficient: n_objects = %d, ",
00157 n_objects );
00158 print(
"avg_nodes %g, avg_objects %g\n", avg_nodes, avg_objects );
00159 }
00160
#endif
00161
}
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 private void subdivide_bintree(
00181
bintree_struct_ptr bintree,
00182
int max_nodes,
00183
int n_objects,
00184
range_struct bound_vols[] )
00185 {
00186
bintree_node_struct **ptr_to_node;
00187
bintree_node_struct **ptr_to_left_child, **ptr_to_right_child;
00188 Real left_cost, right_cost;
00189
range_struct left_limits, right_limits;
00190 leaf_queue_struct leaf_queue;
00191
int n_nodes;
00192
int i, *object_list;
00193
range_struct limits;
00194 progress_struct progress;
00195
00196 ALLOC( object_list, n_objects );
00197 for_less( i, 0, n_objects )
00198 object_list[i] = i;
00199
00200 bintree->
root =
create_bintree_leaf( 0.0, n_objects, object_list );
00201
00202 FREE( object_list );
00203
00204
create_leaf_queue( &leaf_queue );
00205
00206
get_bintree_limits( bintree, &limits );
00207
00208
insert_in_leaf_queue( &leaf_queue, &bintree->
root, 1.0, &limits );
00209
00210 initialize_progress_report( &progress,
FALSE, max_nodes+2,
00211
"Creating bintree" );
00212
00213 n_nodes = 1;
00214
00215
while( n_nodes < max_nodes && !
leaf_queue_empty( &leaf_queue ) )
00216 {
00217
remove_from_leaf_queue( &leaf_queue, &ptr_to_node, &limits );
00218
00219
split_node( bound_vols, ptr_to_node, &limits, &n_nodes,
00220 &left_limits, &left_cost, &right_limits, &right_cost );
00221
00222
if(
get_bintree_left_child_ptr( *ptr_to_node, &ptr_to_left_child ) )
00223 {
00224
insert_in_leaf_queue( &leaf_queue, ptr_to_left_child, left_cost,
00225 &left_limits );
00226 }
00227
00228
if(
get_bintree_right_child_ptr( *ptr_to_node, &ptr_to_right_child ) )
00229 {
00230
insert_in_leaf_queue( &leaf_queue, ptr_to_right_child, right_cost,
00231 &right_limits );
00232 }
00233
00234 update_progress_report( &progress, n_nodes );
00235 }
00236
00237 terminate_progress_report( &progress );
00238
00239
delete_leaf_queue( &leaf_queue );
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 private void get_planes(
00263
int axis_index,
00264
int n_objects,
00265
int list[],
00266
range_struct bound_vols[],
00267 Real right_plane,
00268 Real *left_plane,
00269
int *n_left,
00270
int *n_overlap,
00271
int *n_right )
00272 {
00273
int i;
00274 Real left_side, right_side;
00275 BOOLEAN found;
00276
00277 found =
FALSE;
00278 *left_plane = (Real) bound_vols[list[0]].
limits[axis_index][0];
00279
00280 for_less( i, 0, n_objects )
00281 {
00282 left_side = (Real) bound_vols[list[i]].
limits[axis_index][0];
00283 right_side = (Real) bound_vols[list[i]].
limits[axis_index][1];
00284
if( left_side < right_plane &&
00285 (!found || right_side > *left_plane ) )
00286 {
00287 *left_plane = right_side;
00288 found =
TRUE;
00289 }
00290 }
00291
00292 *n_left = 0;
00293 *n_overlap = 0;
00294 *n_right = 0;
00295
00296 for_less( i, 0, n_objects )
00297 {
00298 left_side = (Real) bound_vols[list[i]].
limits[axis_index][0];
00299 right_side = (Real) bound_vols[list[i]].
limits[axis_index][1];
00300
if( left_side < right_plane )
00301 ++(*n_left);
00302
else if( !found || right_side > *left_plane )
00303 ++(*n_right);
00304
else
00305 ++(*n_overlap);
00306 }
00307 }
00308
00309 #define THRESHOLD 30
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 private Real
find_best_split_node_for_axis(
00330
int axis_index,
00331
int n_objects,
00332
int object_list[],
00333
range_struct bound_vols[],
00334
range_struct *limits,
00335 Real *best_left_plane,
00336 Real *best_right_plane )
00337 {
00338
int i, n_left, n_right, n_overlap, step;
00339 Real left_plane, right_plane;
00340
float save_plane;
00341 Real cost, best_cost, size_left, size_right;
00342
00343 best_cost = 0.0;
00344
00345
if( n_objects >
THRESHOLD )
00346 step = n_objects+1;
00347
else
00348 step = 1;
00349
00350
for( i = 0; i <= n_objects; i += step )
00351 {
00352
if( n_objects >
THRESHOLD )
00353 right_plane = ((Real) limits->
limits[axis_index][0] +
00354 (Real) limits->
limits[axis_index][1]) / 2.0;
00355
else if( i < n_objects )
00356 {
00357 right_plane = (Real) bound_vols[object_list[i]].
00358 limits[axis_index][0];
00359 }
00360
else
00361 right_plane = (Real) limits->
limits[axis_index][1];
00362
00363
get_planes( axis_index, n_objects, object_list, bound_vols,
00364 right_plane, &left_plane,
00365 &n_left, &n_overlap, &n_right );
00366
00367 save_plane = limits->
limits[axis_index][1];
00368 limits->
limits[axis_index][1] = (
float) left_plane;
00369 size_left =
node_visit_estimation( limits );
00370 limits->
limits[axis_index][1] = save_plane;
00371
00372 save_plane = limits->
limits[axis_index][0];
00373 limits->
limits[axis_index][0] = (
float) right_plane;
00374 size_right =
node_visit_estimation( limits );
00375 limits->
limits[axis_index][0] = save_plane;
00376
00377
if( size_left < size_right )
00378 n_left += n_overlap;
00379
else
00380 n_right += n_overlap;
00381
00382 cost = size_left * (Real) n_left + size_right * (Real) n_right;
00383
00384
if( i == 0 || cost < best_cost )
00385 {
00386 best_cost = cost;
00387 *best_right_plane = right_plane;
00388 *best_left_plane = left_plane;
00389 }
00390 }
00391
00392
return( best_cost );
00393 }
00394
00395 #define SWAP( a, b, type ) \
00396
{ \
00397
type _tmp; \
00398
_tmp = (a); \
00399
(a) = (b); \
00400
(b) = _tmp; \
00401
}
00402
00403
#ifdef DEBUG
00404
private void check_objects(
00405
range_struct *limits,
00406
int n_objects,
00407
int object_list[],
00408
range_struct bound_vols[] )
00409 {
00410
int i, c;
00411 for_less( i, 0, n_objects )
00412 for_less( c, 0, N_DIMENSIONS )
00413
if( bound_vols[object_list[i]].
limits[c][0] < limits->
limits[c][0]||
00414 bound_vols[object_list[i]].
limits[c][1] > limits->
limits[c][1] )
00415 handle_internal_error(
"check_objects" );
00416 }
00417
#endif
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 private void split_node(
00433
range_struct bound_vols[],
00434
bintree_node_struct **ptr_to_node,
00435
range_struct *limits,
00436
int *n_nodes,
00437
range_struct *left_limits,
00438 Real *left_cost,
00439
range_struct *right_limits,
00440 Real *right_cost )
00441 {
00442
int i, c, n_objects;
00443
int *object_list;
00444
int axis_index, top, bottom, start_dim, end_dim;
00445 BOOLEAN overlap_in_left, tightly_bounds;
00446 Real left_plane, right_plane, split_position;
00447 Real min_plane, max_plane, best, cost;
00448 Real test_left, test_right;
00449 Real node_cost, previous_cost, net_change;
00450
bintree_node_struct *left_child, *right_child;
00451
00452 n_objects =
get_bintree_leaf_objects( *ptr_to_node, &object_list );
00453
00454
if( n_objects == 0 )
00455
return;
00456
00457 tightly_bounds =
TRUE;
00458
00459 for_less( i, 0, n_objects )
00460 {
00461
if( !
node_tightly_bounds_object( &bound_vols[object_list[i]], limits ) )
00462 {
00463 tightly_bounds =
FALSE;
00464
break;
00465 }
00466 }
00467
00468
if( tightly_bounds )
00469
return;
00470
00471 best = 0.0;
00472
00473
if( n_objects >
THRESHOLD )
00474 {
00475 start_dim = 0;
00476 for_less( c, 0, N_DIMENSIONS )
00477 {
00478
if( limits->
limits[c][1] - limits->
limits[c][0] >
00479 limits->
limits[start_dim][1] - limits->
limits[start_dim][0] )
00480 {
00481 start_dim = c;
00482 }
00483 }
00484 end_dim = start_dim + 1;
00485 }
00486
else
00487 {
00488 start_dim = 0;
00489 end_dim = N_DIMENSIONS;
00490 }
00491
00492 for_less( c, start_dim, end_dim )
00493 {
00494 cost =
find_best_split_node_for_axis( c, n_objects, object_list,
00495 bound_vols, limits,
00496 &test_left, &test_right );
00497
00498
if( c == start_dim || cost < best )
00499 {
00500 best = cost;
00501 axis_index = c;
00502 left_plane = test_left;
00503 right_plane = test_right;
00504 }
00505 }
00506
00507 previous_cost = (Real) n_objects *
node_visit_estimation( limits );
00508 node_cost =
NODE_VISIT_COST *
node_visit_estimation( limits );
00509
00510 net_change = node_cost + cost - previous_cost;
00511
00512
if( net_change >=
NET_CHANGE_THRESHOLD )
00513
return;
00514
00515 min_plane = (Real) limits->
limits[axis_index][0];
00516 max_plane = (Real) limits->
limits[axis_index][1];
00517
00518
if( left_plane - min_plane < max_plane - right_plane )
00519 overlap_in_left =
TRUE;
00520
else
00521 overlap_in_left =
FALSE;
00522
00523 bottom = 0;
00524 top = n_objects - 1;
00525
00526
while( bottom <= top )
00527 {
00528
while( bottom < n_objects &&
00529 (Real) bound_vols[object_list[bottom]].
limits[axis_index][1] <=
00530 left_plane &&
00531 (overlap_in_left ||
00532 (Real) bound_vols[object_list[bottom]].
limits[axis_index][0] <
00533 right_plane) )
00534 ++bottom;
00535
while( top >= 0 &&
00536 (Real) bound_vols[object_list[top]].
limits[axis_index][0] >=
00537 right_plane &&
00538 (!overlap_in_left ||
00539 (Real) bound_vols[object_list[top]].
limits[axis_index][1] >
00540 left_plane) )
00541 --top;
00542
if( bottom < top )
00543 {
00544
SWAP( object_list[bottom], object_list[top],
int )
00545 }
00546 }
00547
00548
if( (bottom == 0 && right_plane == (Real) limits->
limits[axis_index][0]) ||
00549 (bottom == n_objects &&
00550 left_plane == (Real) limits->
limits[axis_index][1]) )
00551 {
00552
return;
00553 }
00554
00555
if( bottom > 0 )
00556 {
00557 *left_limits = *limits;
00558 left_limits->
limits[axis_index][1] = (
float) left_plane;
00559
00560 *left_cost = (Real) bottom *
node_visit_estimation( left_limits );
00561
00562 left_child =
create_bintree_leaf( left_plane, bottom, object_list );
00563
00564
#ifdef DEBUG
00565
check_objects( left_limits, bottom, object_list, bound_vols );
00566
#endif
00567
00568 ++(*n_nodes);
00569 }
00570
else
00571 left_child = (
bintree_node_struct *) NULL;
00572
00573
if( bottom < n_objects )
00574 {
00575 *right_limits = *limits;
00576 right_limits->
limits[axis_index][0] = (
float) right_plane;
00577
00578 *right_cost = (Real) (n_objects - bottom) *
00579
node_visit_estimation( right_limits );
00580
00581 right_child =
create_bintree_leaf( right_plane, n_objects - bottom,
00582 &object_list[bottom] );
00583
#ifdef DEBUG
00584
check_objects( right_limits, n_objects - bottom, &object_list[bottom],
00585 bound_vols );
00586
#endif
00587
++(*n_nodes);
00588 }
00589
else
00590 right_child = (
bintree_node_struct *) NULL;
00591
00592
if( left_child == (
bintree_node_struct *) NULL &&
00593 right_child == (
bintree_node_struct *) NULL )
00594 handle_internal_error(
"Split bintree node" );
00595
00596
00597
00598 split_position =
get_node_split_position( *ptr_to_node );
00599
delete_bintree_node( *ptr_to_node );
00600 *ptr_to_node =
create_bintree_internal_node( axis_index,
00601 split_position,
00602 left_child,
00603 right_child );
00604 }
00605
00606 private void create_leaf_queue(
00607 leaf_queue_struct *leaf_queue )
00608 {
00609
INITIALIZE_PRIORITY_QUEUE( *leaf_queue );
00610 }
00611
00612 private void delete_leaf_queue(
00613 leaf_queue_struct *leaf_queue )
00614 {
00615
DELETE_PRIORITY_QUEUE( *leaf_queue );
00616 }
00617
00618 private BOOLEAN
leaf_queue_empty(
00619 leaf_queue_struct *leaf_queue )
00620 {
00621
return(
IS_PRIORITY_QUEUE_EMPTY( *leaf_queue ) );
00622 }
00623
00624 private void insert_in_leaf_queue(
00625 leaf_queue_struct *leaf_queue,
00626
bintree_node_struct **ptr_to_node,
00627 Real node_cost,
00628
range_struct *limits )
00629 {
00630
leaf_queue_type entry;
00631
00632 entry.
ptr_to_node = ptr_to_node;
00633 entry.
limits = *limits;
00634
00635
INSERT_IN_PRIORITY_QUEUE( *leaf_queue, entry, node_cost );
00636 }
00637
00638 private void remove_from_leaf_queue(
00639 leaf_queue_struct *leaf_queue,
00640
bintree_node_struct ***ptr_to_node,
00641
range_struct *limits )
00642 {
00643
leaf_queue_type entry;
00644 Real node_cost;
00645
00646
REMOVE_FROM_PRIORITY_QUEUE( *leaf_queue, entry, node_cost );
00647
00648
if( node_cost < 0.0 )
00649 handle_internal_error(
"remove from leaf queue" );
00650
00651 *ptr_to_node = entry.
ptr_to_node;
00652 *limits = entry.
limits;
00653 }
00654
00655 private BOOLEAN
node_tightly_bounds_object(
00656
range_struct *bound_vol,
00657
range_struct *limits )
00658 {
00659
int l, c;
00660
00661 for_less( c, 0, N_DIMENSIONS )
00662 {
00663 for_less( l, 0, 2 )
00664 {
00665
if( bound_vol->
limits[c][l] != limits->
limits[c][l] )
00666 {
00667
return(
FALSE );
00668 }
00669 }
00670 }
00671
00672
return(
TRUE );
00673 }
00674
00675 public void evaluate_bintree_efficiency(
00676
bintree_struct_ptr bintree,
00677 Real *avg_nodes_visited,
00678 Real *avg_objects_visited )
00679 {
00680 Real n_visits_top_level;
00681
range_struct limits;
00682
00683 *avg_nodes_visited = 0.0;
00684 *avg_objects_visited = 0.0;
00685
00686 limits = bintree->
range;
00687
00688
recursive_efficiency_count( bintree->
root, &limits,
00689 avg_nodes_visited, avg_objects_visited );
00690
00691 n_visits_top_level =
node_visit_estimation( &bintree->
range );
00692
00693 *avg_nodes_visited /= n_visits_top_level;
00694 *avg_objects_visited /= n_visits_top_level;
00695 }
00696
00697 private void recursive_efficiency_count(
00698
bintree_node_struct *node,
00699
range_struct *limits,
00700 Real *avg_nodes_visited,
00701 Real *avg_objects_visited )
00702 {
00703
float save_limit;
00704 Real node_visit_estimate;
00705
bintree_node_struct *left_child, *right_child;
00706 Real left_limit, right_limit;
00707
int *object_list, axis_index;
00708
00709 node_visit_estimate =
node_visit_estimation( limits );
00710
00711 *avg_nodes_visited += node_visit_estimate;
00712
00713
if(
bintree_node_is_leaf( node ) )
00714 {
00715 *avg_objects_visited += node_visit_estimate *
00716 (Real)
get_bintree_leaf_objects( node, &object_list );
00717 }
00718
else
00719 {
00720 axis_index =
get_node_split_axis( node );
00721
00722
if(
get_bintree_left_child( node, &left_child ) )
00723 {
00724 left_limit =
get_node_split_position( left_child );
00725
00726 save_limit = limits->
limits[axis_index][1];
00727 limits->
limits[axis_index][1] = (
float) left_limit;
00728
00729
recursive_efficiency_count( left_child, limits,
00730 avg_nodes_visited,
00731 avg_objects_visited );
00732 limits->
limits[axis_index][1] = save_limit;
00733 }
00734
00735
if(
get_bintree_right_child( node, &right_child ) )
00736 {
00737 right_limit =
get_node_split_position( right_child );
00738
00739 save_limit = limits->
limits[axis_index][0];
00740 limits->
limits[axis_index][0] = (
float) right_limit;
00741
00742
recursive_efficiency_count( right_child, limits,
00743 avg_nodes_visited,
00744 avg_objects_visited );
00745 limits->
limits[axis_index][0] = save_limit;
00746 }
00747 }
00748 }
00749
00750 private Real
node_visit_estimation(
00751
range_struct *limits )
00752 {
00753
#ifdef VOLUME_EST
00754
return(
range_volume(limits) );
00755
#else
00756
return(
range_surface_area(limits) );
00757
#endif
00758
}