Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "moab/BVHTree.hpp" 00002 #include "moab/Interface.hpp" 00003 #include "moab/ElemEvaluator.hpp" 00004 #include "moab/ReadUtilIface.hpp" 00005 #include "moab/CpuTimer.hpp" 00006 00007 namespace moab 00008 { 00009 const char* BVHTree::treeName = "BVHTree"; 00010 00011 ErrorCode BVHTree::build_tree( const Range& entities, EntityHandle* tree_root_set, FileOptions* options ) 00012 { 00013 ErrorCode rval; 00014 CpuTimer cp; 00015 00016 if( options ) 00017 { 00018 rval = parse_options( *options ); 00019 if( MB_SUCCESS != rval ) return rval; 00020 00021 if( !options->all_seen() ) return MB_FAILURE; 00022 } 00023 00024 // calculate bounding box of elements 00025 BoundBox box; 00026 rval = box.update( *moab(), entities ); 00027 if( MB_SUCCESS != rval ) return rval; 00028 00029 // create tree root 00030 EntityHandle tmp_root; 00031 if( !tree_root_set ) tree_root_set = &tmp_root; 00032 rval = create_root( box.bMin.array(), box.bMax.array(), *tree_root_set ); 00033 if( MB_SUCCESS != rval ) return rval; 00034 rval = mbImpl->add_entities( *tree_root_set, entities ); 00035 if( MB_SUCCESS != rval ) return rval; 00036 00037 // a fully balanced tree will have 2*_entities.size() 00038 // which is one doubling away.. 00039 std::vector< Node > tree_nodes; 00040 tree_nodes.reserve( entities.size() / maxPerLeaf ); 00041 std::vector< HandleData > handle_data_vec; 00042 rval = construct_element_vec( handle_data_vec, entities, boundBox ); 00043 if( MB_SUCCESS != rval ) return rval; 00044 00045 #ifndef NDEBUG 00046 for( std::vector< HandleData >::const_iterator i = handle_data_vec.begin(); i != handle_data_vec.end(); ++i ) 00047 { 00048 if( !boundBox.intersects_box( i->myBox, 0 ) ) 00049 { 00050 std::cerr << "BB:" << boundBox << "EB:" << i->myBox << std::endl; 00051 return MB_FAILURE; 00052 } 00053 } 00054 #endif 00055 // We only build nonempty trees 00056 if( !handle_data_vec.empty() ) 00057 { 00058 // initially all bits are set 00059 tree_nodes.push_back( Node() ); 00060 const int depth = local_build_tree( tree_nodes, handle_data_vec.begin(), handle_data_vec.end(), 0, boundBox ); 00061 #ifndef NDEBUG 00062 std::set< EntityHandle > entity_handles; 00063 for( std::vector< Node >::iterator n = tree_nodes.begin(); n != tree_nodes.end(); ++n ) 00064 { 00065 for( HandleDataVec::const_iterator j = n->entities.begin(); j != n->entities.end(); ++j ) 00066 { 00067 entity_handles.insert( j->myHandle ); 00068 } 00069 } 00070 if( entity_handles.size() != entities.size() ) 00071 { 00072 std::cout << "Entity Handle Size Mismatch!" << std::endl; 00073 } 00074 for( Range::iterator i = entities.begin(); i != entities.end(); ++i ) 00075 { 00076 if( entity_handles.find( *i ) == entity_handles.end() ) 00077 std::cout << "Tree is missing an entity! " << std::endl; 00078 } 00079 #endif 00080 treeDepth = std::max( depth, treeDepth ); 00081 } 00082 00083 // convert vector of Node's to entity sets and vector of TreeNode's 00084 rval = convert_tree( tree_nodes ); 00085 if( MB_SUCCESS != rval ) return rval; 00086 00087 treeStats.reset(); 00088 rval = treeStats.compute_stats( mbImpl, startSetHandle ); 00089 treeStats.initTime = cp.time_elapsed(); 00090 00091 return rval; 00092 } 00093 00094 ErrorCode BVHTree::convert_tree( std::vector< Node >& tree_nodes ) 00095 { 00096 // first construct the proper number of entity sets 00097 ReadUtilIface* read_util; 00098 ErrorCode rval = mbImpl->query_interface( read_util ); 00099 if( MB_SUCCESS != rval ) return rval; 00100 00101 { // isolate potentially-large std::vector so it gets deleted earlier 00102 std::vector< unsigned int > tmp_flags( tree_nodes.size(), meshsetFlags ); 00103 rval = read_util->create_entity_sets( tree_nodes.size(), &tmp_flags[0], 0, startSetHandle ); 00104 if( MB_SUCCESS != rval ) return rval; 00105 rval = mbImpl->release_interface( read_util ); 00106 if( MB_SUCCESS != rval ) return rval; 00107 } 00108 00109 // populate the sets and the TreeNode vector 00110 EntityHandle set_handle = startSetHandle; 00111 std::vector< Node >::iterator it; 00112 myTree.reserve( tree_nodes.size() ); 00113 for( it = tree_nodes.begin(); it != tree_nodes.end(); ++it, set_handle++ ) 00114 { 00115 if( it != tree_nodes.begin() && !it->entities.empty() ) 00116 { 00117 Range range; 00118 for( HandleDataVec::iterator hit = it->entities.begin(); hit != it->entities.end(); ++hit ) 00119 range.insert( hit->myHandle ); 00120 rval = mbImpl->add_entities( set_handle, range ); 00121 if( MB_SUCCESS != rval ) return rval; 00122 } 00123 myTree.push_back( TreeNode( it->dim, it->child, it->Lmax, it->Rmin, it->box ) ); 00124 00125 if( it->dim != 3 ) 00126 { 00127 rval = mbImpl->add_child_meshset( set_handle, startSetHandle + it->child ); 00128 if( MB_SUCCESS != rval ) return rval; 00129 rval = mbImpl->add_child_meshset( set_handle, startSetHandle + it->child + 1 ); 00130 if( MB_SUCCESS != rval ) return rval; 00131 } 00132 } 00133 00134 return MB_SUCCESS; 00135 } 00136 00137 ErrorCode BVHTree::parse_options( FileOptions& opts ) 00138 { 00139 ErrorCode rval = parse_common_options( opts ); 00140 if( MB_SUCCESS != rval ) return rval; 00141 00142 // SPLITS_PER_DIR: number of candidate splits considered per direction; default = 3 00143 int tmp_int; 00144 rval = opts.get_int_option( "SPLITS_PER_DIR", tmp_int ); 00145 if( MB_SUCCESS == rval ) splitsPerDir = tmp_int; 00146 00147 return MB_SUCCESS; 00148 } 00149 00150 void BVHTree::establish_buckets( HandleDataVec::const_iterator begin, 00151 HandleDataVec::const_iterator end, 00152 const BoundBox& interval, 00153 std::vector< std::vector< Bucket > >& buckets ) const 00154 { 00155 // put each element into its bucket 00156 for( HandleDataVec::const_iterator i = begin; i != end; ++i ) 00157 { 00158 const BoundBox& box = i->myBox; 00159 for( unsigned int dim = 0; dim < 3; ++dim ) 00160 { 00161 const unsigned int index = Bucket::bucket_index( splitsPerDir, box, interval, dim ); 00162 assert( index < buckets[dim].size() ); 00163 Bucket& bucket = buckets[dim][index]; 00164 if( bucket.mySize > 0 ) 00165 bucket.boundingBox.update( box ); 00166 else 00167 bucket.boundingBox = box; 00168 bucket.mySize++; 00169 } 00170 } 00171 00172 #ifndef NDEBUG 00173 BoundBox elt_union = begin->myBox; 00174 for( HandleDataVec::const_iterator i = begin; i != end; ++i ) 00175 { 00176 const BoundBox& box = i->myBox; 00177 elt_union.update( box ); 00178 for( unsigned int dim = 0; dim < 3; ++dim ) 00179 { 00180 const unsigned int index = Bucket::bucket_index( splitsPerDir, box, interval, dim ); 00181 Bucket& bucket = buckets[dim][index]; 00182 if( !bucket.boundingBox.intersects_box( box ) ) std::cerr << "Buckets not covering elements!" << std::endl; 00183 } 00184 } 00185 if( !elt_union.intersects_box( interval ) ) 00186 { 00187 std::cout << "element union: " << std::endl << elt_union; 00188 std::cout << "intervals: " << std::endl << interval; 00189 std::cout << "union of elts does not contain original box!" << std::endl; 00190 } 00191 if( !interval.intersects_box( elt_union ) ) 00192 { 00193 std::cout << "original box does not contain union of elts" << std::endl; 00194 std::cout << interval << std::endl << elt_union << std::endl; 00195 } 00196 for( unsigned int d = 0; d < 3; ++d ) 00197 { 00198 std::vector< unsigned int > nonempty; 00199 const std::vector< Bucket >& buckets_ = buckets[d]; 00200 unsigned int j = 0; 00201 for( std::vector< Bucket >::const_iterator i = buckets_.begin(); i != buckets_.end(); ++i, ++j ) 00202 { 00203 if( i->mySize > 0 ) 00204 { 00205 nonempty.push_back( j ); 00206 } 00207 } 00208 BoundBox test_box = buckets_[nonempty.front()].boundingBox; 00209 for( unsigned int i = 0; i < nonempty.size(); ++i ) 00210 test_box.update( buckets_[nonempty[i]].boundingBox ); 00211 00212 if( !test_box.intersects_box( interval ) ) 00213 std::cout << "union of buckets in dimension: " << d << "does not contain original box!" << std::endl; 00214 if( !interval.intersects_box( test_box ) ) 00215 { 00216 std::cout << "original box does " 00217 << "not contain union of buckets" 00218 << "in dimension: " << d << std::endl; 00219 std::cout << interval << std::endl << test_box << std::endl; 00220 } 00221 } 00222 #endif 00223 } 00224 00225 void BVHTree::initialize_splits( std::vector< std::vector< SplitData > >& splits, 00226 const std::vector< std::vector< Bucket > >& buckets, 00227 const SplitData& data ) const 00228 { 00229 for( unsigned int d = 0; d < 3; ++d ) 00230 { 00231 std::vector< SplitData >::iterator splits_begin = splits[d].begin(); 00232 std::vector< SplitData >::iterator splits_end = splits[d].end(); 00233 std::vector< Bucket >::const_iterator left_begin = buckets[d].begin(); 00234 std::vector< Bucket >::const_iterator _end = buckets[d].end(); 00235 std::vector< Bucket >::const_iterator left_end = buckets[d].begin() + 1; 00236 for( std::vector< SplitData >::iterator s = splits_begin; s != splits_end; ++s, ++left_end ) 00237 { 00238 s->nl = set_interval( s->leftBox, left_begin, left_end ); 00239 if( s->nl == 0 ) 00240 { 00241 s->leftBox = data.boundingBox; 00242 s->leftBox.bMax[d] = s->leftBox.bMin[d]; 00243 } 00244 s->nr = set_interval( s->rightBox, left_end, _end ); 00245 if( s->nr == 0 ) 00246 { 00247 s->rightBox = data.boundingBox; 00248 s->rightBox.bMin[d] = s->rightBox.bMax[d]; 00249 } 00250 s->Lmax = s->leftBox.bMax[d]; 00251 s->Rmin = s->rightBox.bMin[d]; 00252 s->split = std::distance( splits_begin, s ); 00253 s->dim = d; 00254 } 00255 #ifndef NDEBUG 00256 for( std::vector< SplitData >::iterator s = splits_begin; s != splits_end; ++s ) 00257 { 00258 BoundBox test_box = s->leftBox; 00259 test_box.update( s->rightBox ); 00260 if( !data.boundingBox.intersects_box( test_box ) ) 00261 { 00262 std::cout << "nr: " << s->nr << std::endl; 00263 std::cout << "Test box: " << std::endl << test_box; 00264 std::cout << "Left box: " << std::endl << s->leftBox; 00265 std::cout << "Right box: " << std::endl << s->rightBox; 00266 std::cout << "Interval: " << std::endl << data.boundingBox; 00267 std::cout << "Split boxes larger than bb" << std::endl; 00268 } 00269 if( !test_box.intersects_box( data.boundingBox ) ) 00270 { 00271 std::cout << "bb larger than union of split boxes" << std::endl; 00272 } 00273 } 00274 #endif 00275 } 00276 } 00277 00278 void BVHTree::median_order( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const 00279 { 00280 int dim = data.dim; 00281 for( HandleDataVec::iterator i = begin; i != end; ++i ) 00282 { 00283 i->myDim = 0.5 * ( i->myBox.bMin[dim], i->myBox.bMax[dim] ); 00284 } 00285 std::sort( begin, end, BVHTree::HandleData_comparator() ); 00286 const unsigned int total = std::distance( begin, end ); 00287 HandleDataVec::iterator middle = begin + ( total / 2 ); 00288 double middle_center = middle->myDim; 00289 middle_center += ( ++middle )->myDim; 00290 middle_center *= 0.5; 00291 data.split = middle_center; 00292 data.nl = std::distance( begin, middle ) + 1; 00293 data.nr = total - data.nl; 00294 ++middle; 00295 data.leftBox = begin->myBox; 00296 data.rightBox = middle->myBox; 00297 for( HandleDataVec::iterator i = begin; i != middle; ++i ) 00298 { 00299 i->myDim = 0; 00300 data.leftBox.update( i->myBox ); 00301 } 00302 for( HandleDataVec::iterator i = middle; i != end; ++i ) 00303 { 00304 i->myDim = 1; 00305 data.rightBox.update( i->myBox ); 00306 } 00307 data.Rmin = data.rightBox.bMin[data.dim]; 00308 data.Lmax = data.leftBox.bMax[data.dim]; 00309 #ifndef NDEBUG 00310 BoundBox test_box( data.rightBox ); 00311 if( !data.boundingBox.intersects_box( test_box ) ) 00312 { 00313 std::cerr << "MEDIAN: BB Does not contain splits" << std::endl; 00314 std::cerr << "test_box: " << test_box << std::endl; 00315 std::cerr << "data.boundingBox: " << data.boundingBox << std::endl; 00316 } 00317 #endif 00318 } 00319 00320 void BVHTree::find_split( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const 00321 { 00322 std::vector< std::vector< Bucket > > buckets( 3, std::vector< Bucket >( splitsPerDir + 1 ) ); 00323 std::vector< std::vector< SplitData > > splits( 3, std::vector< SplitData >( splitsPerDir, data ) ); 00324 00325 const BoundBox interval = data.boundingBox; 00326 establish_buckets( begin, end, interval, buckets ); 00327 initialize_splits( splits, buckets, data ); 00328 choose_best_split( splits, data ); 00329 const bool use_median = ( 0 == data.nl ) || ( data.nr == 0 ); 00330 if( !use_median ) 00331 order_elements( begin, end, data ); 00332 else 00333 median_order( begin, end, data ); 00334 00335 #ifndef NDEBUG 00336 bool seen_one = false, issue = false; 00337 bool first_left = true, first_right = true; 00338 unsigned int count_left = 0, count_right = 0; 00339 BoundBox left_box, right_box; 00340 for( HandleDataVec::iterator i = begin; i != end; ++i ) 00341 { 00342 int order = i->myDim; 00343 if( order != 0 && order != 1 ) 00344 { 00345 std::cerr << "Invalid order element !"; 00346 std::cerr << order << std::endl; 00347 std::exit( -1 ); 00348 } 00349 if( order == 1 ) 00350 { 00351 seen_one = 1; 00352 count_right++; 00353 if( first_right ) 00354 { 00355 right_box = i->myBox; 00356 first_right = false; 00357 } 00358 else 00359 { 00360 right_box.update( i->myBox ); 00361 } 00362 if( !right_box.intersects_box( i->myBox ) ) 00363 { 00364 if( !issue ) 00365 { 00366 std::cerr << "Bounding right box issue!" << std::endl; 00367 } 00368 issue = true; 00369 } 00370 } 00371 if( order == 0 ) 00372 { 00373 count_left++; 00374 if( first_left ) 00375 { 00376 left_box = i->myBox; 00377 first_left = false; 00378 } 00379 else 00380 { 00381 left_box.update( i->myBox ); 00382 } 00383 if( !data.leftBox.intersects_box( i->myBox ) ) 00384 { 00385 if( !issue ) 00386 { 00387 std::cerr << "Bounding left box issue!" << std::endl; 00388 } 00389 issue = true; 00390 } 00391 if( seen_one ) 00392 { 00393 std::cerr << "Invalid ordering!" << std::endl; 00394 std::cout << ( i - 1 )->myDim << order << std::endl; 00395 exit( -1 ); 00396 } 00397 } 00398 } 00399 if( !left_box.intersects_box( data.leftBox ) ) std::cout << "left elts do not contain left box" << std::endl; 00400 if( !data.leftBox.intersects_box( left_box ) ) std::cout << "left box does not contain left elts" << std::endl; 00401 if( !right_box.intersects_box( data.rightBox ) ) std::cout << "right elts do not contain right box" << std::endl; 00402 if( !data.rightBox.intersects_box( right_box ) ) std::cout << "right box do not contain right elts" << std::endl; 00403 00404 if( count_left != data.nl || count_right != data.nr ) 00405 { 00406 std::cerr << "counts are off!" << std::endl; 00407 std::cerr << "total: " << std::distance( begin, end ) << std::endl; 00408 std::cerr << "Dim: " << data.dim << std::endl; 00409 std::cerr << data.Lmax << " , " << data.Rmin << std::endl; 00410 std::cerr << "Right box: " << std::endl << data.rightBox << "Left box: " << std::endl << data.leftBox; 00411 std::cerr << "supposed to be: " << data.nl << " " << data.nr << std::endl; 00412 std::cerr << "accountant says: " << count_left << " " << count_right << std::endl; 00413 std::exit( -1 ); 00414 } 00415 #endif 00416 } 00417 00418 int BVHTree::local_build_tree( std::vector< Node >& tree_nodes, 00419 HandleDataVec::iterator begin, 00420 HandleDataVec::iterator end, 00421 const int index, 00422 const BoundBox& box, 00423 const int depth ) 00424 { 00425 #ifndef NDEBUG 00426 for( HandleDataVec::const_iterator i = begin; i != end; ++i ) 00427 { 00428 if( !box.intersects_box( i->myBox, 0 ) ) 00429 { 00430 std::cerr << "depth: " << depth << std::endl; 00431 std::cerr << "BB:" << box << "EB:" << i->myBox << std::endl; 00432 std::exit( -1 ); 00433 } 00434 } 00435 #endif 00436 00437 const unsigned int total_num_elements = std::distance( begin, end ); 00438 tree_nodes[index].box = box; 00439 00440 // logic for splitting conditions 00441 if( (int)total_num_elements > maxPerLeaf && depth < maxDepth ) 00442 { 00443 SplitData data; 00444 data.boundingBox = box; 00445 find_split( begin, end, data ); 00446 // assign data to node 00447 tree_nodes[index].Lmax = data.Lmax; 00448 tree_nodes[index].Rmin = data.Rmin; 00449 tree_nodes[index].dim = data.dim; 00450 tree_nodes[index].child = tree_nodes.size(); 00451 // insert left, right children; 00452 tree_nodes.push_back( Node() ); 00453 tree_nodes.push_back( Node() ); 00454 const int left_depth = 00455 local_build_tree( tree_nodes, begin, begin + data.nl, tree_nodes[index].child, data.leftBox, depth + 1 ); 00456 const int right_depth = 00457 local_build_tree( tree_nodes, begin + data.nl, end, tree_nodes[index].child + 1, data.rightBox, depth + 1 ); 00458 return std::max( left_depth, right_depth ); 00459 } 00460 00461 tree_nodes[index].dim = 3; 00462 std::copy( begin, end, std::back_inserter( tree_nodes[index].entities ) ); 00463 return depth; 00464 } 00465 00466 ErrorCode BVHTree::find_point( const std::vector< double >& point, 00467 const unsigned int& index, 00468 const double iter_tol, 00469 const double inside_tol, 00470 std::pair< EntityHandle, CartVect >& result ) 00471 { 00472 if( index == 0 ) treeStats.numTraversals++; 00473 const TreeNode& node = myTree[index]; 00474 treeStats.nodesVisited++; 00475 CartVect params; 00476 int is_inside; 00477 ErrorCode rval = MB_SUCCESS; 00478 if( node.dim == 3 ) 00479 { 00480 treeStats.leavesVisited++; 00481 Range entities; 00482 rval = mbImpl->get_entities_by_handle( startSetHandle + index, entities ); 00483 if( MB_SUCCESS != rval ) return rval; 00484 00485 for( Range::iterator i = entities.begin(); i != entities.end(); ++i ) 00486 { 00487 treeStats.traversalLeafObjectTests++; 00488 myEval->set_ent_handle( *i ); 00489 myEval->reverse_eval( &point[0], iter_tol, inside_tol, params.array(), &is_inside ); 00490 if( is_inside ) 00491 { 00492 result.first = *i; 00493 result.second = params; 00494 return MB_SUCCESS; 00495 } 00496 } 00497 result.first = 0; 00498 return MB_SUCCESS; 00499 } 00500 // the extra tol here considers the case where 00501 // 0 < Rmin - Lmax < 2tol 00502 std::vector< EntityHandle > children; 00503 rval = mbImpl->get_child_meshsets( startSetHandle + index, children ); 00504 if( MB_SUCCESS != rval || children.size() != 2 ) return rval; 00505 00506 if( ( node.Lmax + iter_tol ) < ( node.Rmin - iter_tol ) ) 00507 { 00508 if( point[node.dim] <= ( node.Lmax + iter_tol ) ) 00509 return find_point( point, children[0] - startSetHandle, iter_tol, inside_tol, result ); 00510 else if( point[node.dim] >= ( node.Rmin - iter_tol ) ) 00511 return find_point( point, children[1] - startSetHandle, iter_tol, inside_tol, result ); 00512 result = std::make_pair( 0, CartVect( &point[0] ) ); // point lies in empty space. 00513 return MB_SUCCESS; 00514 } 00515 00516 // Boxes overlap 00517 // left of Rmin, you must be on the left 00518 // we can't be sure about the boundaries since the boxes overlap 00519 // this was a typo in the paper which caused pain. 00520 if( point[node.dim] < ( node.Rmin - iter_tol ) ) 00521 return find_point( point, children[0] - startSetHandle, iter_tol, inside_tol, result ); 00522 // if you are on the right Lmax, you must be on the right 00523 else if( point[node.dim] > ( node.Lmax + iter_tol ) ) 00524 return find_point( point, children[1] - startSetHandle, iter_tol, inside_tol, result ); 00525 00526 /* pg5 of paper 00527 * However, instead of always traversing either subtree 00528 * first (e.g. left always before right), we first traverse 00529 * the subtree whose bounding plane has the larger distance to the 00530 * sought point. This results in less overall traversal, and the correct 00531 * cell is identified more quickly. 00532 */ 00533 // So far all testing confirms that this 'heuristic' is 00534 // significantly slower. 00535 // I conjecture this is because it gets improperly 00536 // branch predicted.. 00537 // bool dir = (point[ node.dim] - node.Rmin) <= 00538 // (node.Lmax - point[ node.dim]); 00539 find_point( point, children[0] - startSetHandle, iter_tol, inside_tol, result ); 00540 if( result.first == 0 ) 00541 { 00542 return find_point( point, children[1] - startSetHandle, iter_tol, inside_tol, result ); 00543 } 00544 return MB_SUCCESS; 00545 } 00546 00547 EntityHandle BVHTree::bruteforce_find( const double* point, const double iter_tol, const double inside_tol ) 00548 { 00549 treeStats.numTraversals++; 00550 CartVect params; 00551 for( unsigned int i = 0; i < myTree.size(); i++ ) 00552 { 00553 if( myTree[i].dim != 3 || !myTree[i].box.contains_point( point, iter_tol ) ) continue; 00554 if( myEval ) 00555 { 00556 EntityHandle entity = 0; 00557 treeStats.leavesVisited++; 00558 ErrorCode rval = myEval->find_containing_entity( startSetHandle + i, point, iter_tol, inside_tol, entity, 00559 params.array(), &treeStats.traversalLeafObjectTests ); 00560 if( entity ) 00561 return entity; 00562 else if( MB_SUCCESS != rval ) 00563 return 0; 00564 } 00565 else 00566 return startSetHandle + i; 00567 } 00568 return 0; 00569 } 00570 00571 ErrorCode BVHTree::get_bounding_box( BoundBox& box, EntityHandle* tree_node ) const 00572 { 00573 if( !tree_node || *tree_node == startSetHandle ) 00574 { 00575 box = boundBox; 00576 return MB_SUCCESS; 00577 } 00578 else if( ( tree_node && !startSetHandle ) || *tree_node < startSetHandle || 00579 *tree_node - startSetHandle > myTree.size() ) 00580 return MB_FAILURE; 00581 00582 box = myTree[*tree_node - startSetHandle].box; 00583 return MB_SUCCESS; 00584 } 00585 00586 ErrorCode BVHTree::point_search( const double* point, 00587 EntityHandle& leaf_out, 00588 const double iter_tol, 00589 const double inside_tol, 00590 bool* multiple_leaves, 00591 EntityHandle* start_node, 00592 CartVect* params ) 00593 { 00594 treeStats.numTraversals++; 00595 00596 EntityHandle this_set = ( start_node ? *start_node : startSetHandle ); 00597 // convoluted check because the root is different from startSetHandle 00598 if( this_set != myRoot && ( this_set < startSetHandle || this_set >= startSetHandle + myTree.size() ) ) 00599 return MB_FAILURE; 00600 else if( this_set == myRoot ) 00601 this_set = startSetHandle; 00602 00603 std::vector< EntityHandle > candidates, 00604 result_list; // list of subtrees to traverse, and results 00605 candidates.push_back( this_set - startSetHandle ); 00606 00607 BoundBox box; 00608 while( !candidates.empty() ) 00609 { 00610 EntityHandle ind = candidates.back(); 00611 treeStats.nodesVisited++; 00612 if( myTree[ind].dim == 3 ) treeStats.leavesVisited++; 00613 this_set = startSetHandle + ind; 00614 candidates.pop_back(); 00615 00616 // test box of this node 00617 ErrorCode rval = get_bounding_box( box, &this_set ); 00618 if( MB_SUCCESS != rval ) return rval; 00619 if( !box.contains_point( point, iter_tol ) ) continue; 00620 00621 // else if not a leaf, test children & put on list 00622 else if( myTree[ind].dim != 3 ) 00623 { 00624 candidates.push_back( myTree[ind].child ); 00625 candidates.push_back( myTree[ind].child + 1 ); 00626 continue; 00627 } 00628 else if( myTree[ind].dim == 3 && myEval && params ) 00629 { 00630 rval = myEval->find_containing_entity( startSetHandle + ind, point, iter_tol, inside_tol, leaf_out, 00631 params->array(), &treeStats.traversalLeafObjectTests ); 00632 if( leaf_out || MB_SUCCESS != rval ) return rval; 00633 } 00634 else 00635 { 00636 // leaf node within distance; return in list 00637 result_list.push_back( this_set ); 00638 } 00639 } 00640 00641 if( !result_list.empty() ) leaf_out = result_list[0]; 00642 if( multiple_leaves && result_list.size() > 1 ) *multiple_leaves = true; 00643 return MB_SUCCESS; 00644 } 00645 00646 ErrorCode BVHTree::distance_search( const double from_point[3], 00647 const double distance, 00648 std::vector< EntityHandle >& result_list, 00649 const double iter_tol, 00650 const double inside_tol, 00651 std::vector< double >* result_dists, 00652 std::vector< CartVect >* result_params, 00653 EntityHandle* tree_root ) 00654 { 00655 // non-NULL root should be in tree 00656 // convoluted check because the root is different from startSetHandle 00657 EntityHandle this_set = ( tree_root ? *tree_root : startSetHandle ); 00658 if( this_set != myRoot && ( this_set < startSetHandle || this_set >= startSetHandle + myTree.size() ) ) 00659 return MB_FAILURE; 00660 else if( this_set == myRoot ) 00661 this_set = startSetHandle; 00662 00663 treeStats.numTraversals++; 00664 00665 const double dist_sqr = distance * distance; 00666 const CartVect from( from_point ); 00667 std::vector< EntityHandle > candidates; // list of subtrees to traverse 00668 // pre-allocate space for default max tree depth 00669 candidates.reserve( maxDepth ); 00670 00671 // misc temporary values 00672 ErrorCode rval; 00673 BoundBox box; 00674 00675 candidates.push_back( this_set - startSetHandle ); 00676 00677 while( !candidates.empty() ) 00678 { 00679 00680 EntityHandle ind = candidates.back(); 00681 this_set = startSetHandle + ind; 00682 candidates.pop_back(); 00683 treeStats.nodesVisited++; 00684 if( myTree[ind].dim == 3 ) treeStats.leavesVisited++; 00685 00686 // test box of this node 00687 rval = get_bounding_box( box, &this_set ); 00688 if( MB_SUCCESS != rval ) return rval; 00689 double d_sqr = box.distance_squared( from_point ); 00690 00691 // if greater than cutoff, continue 00692 if( d_sqr > dist_sqr ) continue; 00693 00694 // else if not a leaf, test children & put on list 00695 else if( myTree[ind].dim != 3 ) 00696 { 00697 candidates.push_back( myTree[ind].child ); 00698 candidates.push_back( myTree[ind].child + 1 ); 00699 continue; 00700 } 00701 00702 if( myEval && result_params ) 00703 { 00704 EntityHandle ent; 00705 CartVect params; 00706 rval = myEval->find_containing_entity( startSetHandle + ind, from_point, iter_tol, inside_tol, ent, 00707 params.array(), &treeStats.traversalLeafObjectTests ); 00708 if( MB_SUCCESS != rval ) 00709 return rval; 00710 else if( ent ) 00711 { 00712 result_list.push_back( ent ); 00713 result_params->push_back( params ); 00714 if( result_dists ) result_dists->push_back( 0.0 ); 00715 } 00716 } 00717 else 00718 { 00719 // leaf node within distance; return in list 00720 result_list.push_back( this_set ); 00721 if( result_dists ) result_dists->push_back( sqrt( d_sqr ) ); 00722 } 00723 } 00724 00725 return MB_SUCCESS; 00726 } 00727 00728 ErrorCode BVHTree::print_nodes( std::vector< Node >& nodes ) 00729 { 00730 int i; 00731 std::vector< Node >::iterator it; 00732 for( it = nodes.begin(), i = 0; it != nodes.end(); ++it, i++ ) 00733 { 00734 std::cout << "Node " << i << ": dim = " << it->dim << ", child = " << it->child << ", Lmax/Rmin = " << it->Lmax 00735 << "/" << it->Rmin << ", box = " << it->box << std::endl; 00736 } 00737 return MB_SUCCESS; 00738 } 00739 00740 ErrorCode BVHTree::print() 00741 { 00742 int i; 00743 std::vector< TreeNode >::iterator it; 00744 for( it = myTree.begin(), i = 0; it != myTree.end(); ++it, i++ ) 00745 { 00746 std::cout << "Node " << i << ": dim = " << it->dim << ", child = " << it->child << ", Lmax/Rmin = " << it->Lmax 00747 << "/" << it->Rmin << ", box = " << it->box << std::endl; 00748 } 00749 return MB_SUCCESS; 00750 } 00751 00752 } // namespace moab