moab
|
00001 /* 00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating, 00003 * storing and accessing finite element mesh data. 00004 * 00005 * Copyright 2008 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Coroporation, the U.S. Government 00007 * retains certain rights in this software. 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 */ 00015 00021 #include "moab/BSPTree.hpp" 00022 #include "moab/GeomUtil.hpp" 00023 #include "moab/Range.hpp" 00024 #include "Internals.hpp" 00025 #include "moab/BSPTreePoly.hpp" 00026 00027 #include <assert.h> 00028 #include <string.h> 00029 #include <algorithm> 00030 #include <limits> 00031 00032 #if defined(_MSC_VER) || defined(__MINGW32__) 00033 # include <float.h> 00034 # define finite(A) _finite(A) 00035 #elif defined(HAVE_IEEEFP_H) 00036 # include <ieeefp.h> 00037 #endif 00038 00039 #define MB_BSP_TREE_DEFAULT_TAG_NAME "BSPTree" 00040 00041 namespace moab { 00042 00043 static void corners_from_box( const double box_min[3], 00044 const double box_max[3], 00045 double corners[8][3] ) 00046 { 00047 const double* ranges[] = { box_min, box_max }; 00048 for (int z = 0; z < 2; ++z) { 00049 corners[4*z ][0] = box_min[0]; 00050 corners[4*z ][1] = box_min[1]; 00051 corners[4*z ][2] = ranges[z][2]; 00052 00053 corners[4*z+1][0] = box_max[0]; 00054 corners[4*z+1][1] = box_min[1]; 00055 corners[4*z+1][2] = ranges[z][2]; 00056 00057 corners[4*z+2][0] = box_max[0]; 00058 corners[4*z+2][1] = box_max[1]; 00059 corners[4*z+2][2] = ranges[z][2]; 00060 00061 corners[4*z+3][0] = box_min[0]; 00062 corners[4*z+3][1] = box_max[1]; 00063 corners[4*z+3][2] = ranges[z][2]; 00064 } 00065 } 00066 00067 // assume box has planar sides 00068 // test if point is contained in box 00069 static bool point_in_box( const double corners[8][3], 00070 const double point[3] ) 00071 { 00072 const unsigned side_verts[6][3] = { { 0, 3, 1 }, 00073 { 4, 5, 7 }, 00074 { 0, 1, 4 }, 00075 { 1, 2, 5 }, 00076 { 2, 3, 6 }, 00077 { 3, 0, 7 } }; 00078 // If we assume planar sides, then the box is the intersection 00079 // of 6 half-spaces defined by the planes of the sides. 00080 const CartVect pt(point); 00081 for (unsigned s = 0; s < 6; ++s) { 00082 CartVect v0( corners[side_verts[s][0]] ); 00083 CartVect v1( corners[side_verts[s][1]] ); 00084 CartVect v2( corners[side_verts[s][2]] ); 00085 CartVect N = (v1 - v0) * (v2 - v0); 00086 if ((v0 - pt) % N < 0) 00087 return false; 00088 } 00089 return true; 00090 } 00091 00092 void BSPTree::Plane::set( const double pt1[3], const double pt2[3], const double pt3[3] ) 00093 { 00094 const double v1[] = { pt2[0] - pt1[0], pt2[1] - pt1[1], pt2[2] - pt1[2] }; 00095 const double v2[] = { pt3[0] - pt1[0], pt3[1] - pt1[1], pt3[2] - pt1[2] }; 00096 const double nrm[] = { v1[1]*v2[2] - v1[2]*v2[1], 00097 v1[2]*v2[0] - v1[0]*v2[2], 00098 v1[0]*v2[1] - v1[1]*v2[0] }; 00099 set( nrm, pt1 ); 00100 } 00101 00102 ErrorCode BSPTree::init_tags( const char* tagname ) 00103 { 00104 if (!tagname) 00105 tagname = MB_BSP_TREE_DEFAULT_TAG_NAME; 00106 00107 std::string rootname(tagname); 00108 rootname += "_box"; 00109 00110 ErrorCode rval = moab()->tag_get_handle( tagname, 4, MB_TYPE_DOUBLE, planeTag, MB_TAG_CREAT|MB_TAG_DENSE ); 00111 if (MB_SUCCESS != rval) 00112 planeTag = 0; 00113 else 00114 rval = moab()->tag_get_handle( rootname.c_str(), 24, MB_TYPE_DOUBLE, rootTag, MB_TAG_CREAT|MB_TAG_SPARSE ); 00115 if (MB_SUCCESS != rval) 00116 rootTag = 0; 00117 return rval; 00118 } 00119 00120 BSPTree::BSPTree( Interface* mb, 00121 const char* tagname, 00122 unsigned set_flags ) 00123 : mbInstance(mb), meshSetFlags(set_flags), cleanUpTrees(false) 00124 { init_tags( tagname ); } 00125 00126 BSPTree::BSPTree( Interface* mb, 00127 bool destroy_created_trees, 00128 const char* tagname, 00129 unsigned set_flags ) 00130 : mbInstance(mb), meshSetFlags(set_flags), cleanUpTrees(destroy_created_trees) 00131 { init_tags( tagname ); } 00132 00133 BSPTree::~BSPTree() 00134 { 00135 if (!cleanUpTrees) 00136 return; 00137 00138 while (!createdTrees.empty()) { 00139 EntityHandle tree = createdTrees.back(); 00140 // make sure this is a tree (rather than some other, stale handle) 00141 const void* data_ptr = 0; 00142 ErrorCode rval = moab()->tag_get_by_ptr( rootTag, &tree, 1, &data_ptr ); 00143 if (MB_SUCCESS == rval) 00144 rval = delete_tree( tree ); 00145 if (MB_SUCCESS != rval) 00146 createdTrees.pop_back(); 00147 } 00148 } 00149 00150 ErrorCode BSPTree::set_split_plane( EntityHandle node, const Plane& p ) 00151 { 00152 // check for unit-length normal 00153 const double lensqr = p.norm[0]*p.norm[0] 00154 + p.norm[1]*p.norm[1] 00155 + p.norm[2]*p.norm[2]; 00156 if (fabs(lensqr - 1.0) < std::numeric_limits<double>::epsilon()) 00157 return moab()->tag_set_data( planeTag, &node, 1, &p ); 00158 00159 const double inv_len = 1.0/sqrt(lensqr); 00160 Plane p2(p); 00161 p2.norm[0] *= inv_len; 00162 p2.norm[1] *= inv_len; 00163 p2.norm[2] *= inv_len; 00164 p2.coeff *= inv_len; 00165 00166 // check for zero-length normal 00167 if (!finite(p2.norm[0]+p2.norm[1]+p2.norm[2]+p2.coeff)) 00168 return MB_FAILURE; 00169 00170 // store plane 00171 return moab()->tag_set_data( planeTag, &node, 1, &p2 ); 00172 } 00173 00174 ErrorCode BSPTree::set_tree_box( EntityHandle root_handle, 00175 const double box_min[3], 00176 const double box_max[3] ) 00177 { 00178 double corners[8][3]; 00179 corners_from_box( box_min, box_max, corners ); 00180 return set_tree_box( root_handle, corners ); 00181 } 00182 00183 ErrorCode BSPTree::set_tree_box( EntityHandle root_handle, 00184 const double corners[8][3] ) 00185 { 00186 return moab()->tag_set_data( rootTag, &root_handle, 1, corners ); 00187 } 00188 00189 ErrorCode BSPTree::get_tree_box( EntityHandle root_handle, 00190 double corners[8][3] ) 00191 { 00192 return moab()->tag_get_data( rootTag, &root_handle, 1, corners ); 00193 } 00194 00195 ErrorCode BSPTree::get_tree_box( EntityHandle root_handle, 00196 double corners[24] ) 00197 { 00198 return moab()->tag_get_data( rootTag, &root_handle, 1, corners ); 00199 } 00200 00201 ErrorCode BSPTree::create_tree( EntityHandle& root_handle ) 00202 { 00203 const double min[3] = { -HUGE_VAL, -HUGE_VAL, -HUGE_VAL }; 00204 const double max[3] = { HUGE_VAL, HUGE_VAL, HUGE_VAL }; 00205 return create_tree( min, max, root_handle ); 00206 } 00207 00208 ErrorCode BSPTree::create_tree( const double corners[8][3], 00209 EntityHandle& root_handle ) 00210 { 00211 ErrorCode rval = moab()->create_meshset( meshSetFlags, root_handle ); 00212 if (MB_SUCCESS != rval) 00213 return rval; 00214 00215 rval = set_tree_box( root_handle, corners ); 00216 if (MB_SUCCESS != rval) { 00217 moab()->delete_entities( &root_handle, 1 ); 00218 root_handle = 0; 00219 return rval; 00220 } 00221 00222 createdTrees.push_back( root_handle ); 00223 return MB_SUCCESS; 00224 } 00225 00226 00227 ErrorCode BSPTree::create_tree( const double box_min[3], 00228 const double box_max[3], 00229 EntityHandle& root_handle ) 00230 { 00231 double corners[8][3]; 00232 corners_from_box( box_min, box_max, corners ); 00233 return create_tree( corners, root_handle ); 00234 } 00235 00236 ErrorCode BSPTree::delete_tree( EntityHandle root_handle ) 00237 { 00238 ErrorCode rval; 00239 00240 std::vector<EntityHandle> children, dead_sets, current_sets; 00241 current_sets.push_back( root_handle ); 00242 while (!current_sets.empty()) { 00243 EntityHandle set = current_sets.back(); 00244 current_sets.pop_back(); 00245 dead_sets.push_back( set ); 00246 rval = moab()->get_child_meshsets( set, children ); 00247 if (MB_SUCCESS != rval) 00248 return rval; 00249 std::copy( children.begin(), children.end(), std::back_inserter(current_sets) ); 00250 children.clear(); 00251 } 00252 00253 rval = moab()->tag_delete_data( rootTag, &root_handle, 1 ); 00254 if (MB_SUCCESS != rval) 00255 return rval; 00256 00257 createdTrees.erase( 00258 std::remove( createdTrees.begin(), createdTrees.end(), root_handle ), 00259 createdTrees.end() ); 00260 return moab()->delete_entities( &dead_sets[0], dead_sets.size() ); 00261 } 00262 00263 ErrorCode BSPTree::find_all_trees( Range& results ) 00264 { 00265 return moab()->get_entities_by_type_and_tag( 0, MBENTITYSET, 00266 &rootTag, 0, 1, 00267 results ); 00268 } 00269 00270 ErrorCode BSPTree::get_tree_iterator( EntityHandle root, 00271 BSPTreeIter& iter ) 00272 { 00273 ErrorCode rval = iter.initialize( this, root ); 00274 if (MB_SUCCESS != rval) 00275 return rval; 00276 return iter.step_to_first_leaf( BSPTreeIter::LEFT ); 00277 } 00278 00279 ErrorCode BSPTree::get_tree_end_iterator( EntityHandle root, 00280 BSPTreeIter& iter ) 00281 { 00282 ErrorCode rval = iter.initialize( this, root ); 00283 if (MB_SUCCESS != rval) 00284 return rval; 00285 return iter.step_to_first_leaf( BSPTreeIter::RIGHT ); 00286 } 00287 00288 ErrorCode BSPTree::split_leaf( BSPTreeIter& leaf, 00289 Plane plane, 00290 EntityHandle& left, 00291 EntityHandle& right ) 00292 { 00293 ErrorCode rval; 00294 00295 rval = moab()->create_meshset( meshSetFlags, left ); 00296 if (MB_SUCCESS != rval) 00297 return rval; 00298 00299 rval = moab()->create_meshset( meshSetFlags, right ); 00300 if (MB_SUCCESS != rval) { 00301 moab()->delete_entities( &left, 1 ); 00302 return rval; 00303 } 00304 00305 if (MB_SUCCESS != set_split_plane( leaf.handle(), plane ) || 00306 MB_SUCCESS != moab()->add_child_meshset( leaf.handle(), left ) || 00307 MB_SUCCESS != moab()->add_child_meshset( leaf.handle(), right) || 00308 MB_SUCCESS != leaf.step_to_first_leaf(BSPTreeIter::LEFT)) { 00309 EntityHandle children[] = { left, right }; 00310 moab()->delete_entities( children, 2 ); 00311 return MB_FAILURE; 00312 } 00313 00314 return MB_SUCCESS; 00315 } 00316 00317 ErrorCode BSPTree::split_leaf( BSPTreeIter& leaf, Plane plane ) 00318 { 00319 EntityHandle left, right; 00320 return split_leaf( leaf, plane, left, right ); 00321 } 00322 00323 ErrorCode BSPTree::split_leaf( BSPTreeIter& leaf, 00324 Plane plane, 00325 const Range& left_entities, 00326 const Range& right_entities ) 00327 { 00328 EntityHandle left, right, parent = leaf.handle(); 00329 ErrorCode rval = split_leaf( leaf, plane, left, right ); 00330 if (MB_SUCCESS != rval) 00331 return rval; 00332 00333 if (MB_SUCCESS == moab()->add_entities( left, left_entities ) && 00334 MB_SUCCESS == moab()->add_entities(right,right_entities ) && 00335 MB_SUCCESS == moab()->clear_meshset( &parent, 1 )) 00336 return MB_SUCCESS; 00337 00338 moab()->remove_child_meshset( parent, left ); 00339 moab()->remove_child_meshset( parent, right ); 00340 EntityHandle children[] = { left, right }; 00341 moab()->delete_entities( children, 2 ); 00342 return MB_FAILURE; 00343 } 00344 00345 ErrorCode BSPTree::split_leaf( BSPTreeIter& leaf, Plane plane, 00346 const std::vector<EntityHandle>& left_entities, 00347 const std::vector<EntityHandle>& right_entities ) 00348 { 00349 EntityHandle left, right, parent = leaf.handle(); 00350 ErrorCode rval = split_leaf( leaf, plane, left, right ); 00351 if (MB_SUCCESS != rval) 00352 return rval; 00353 00354 if (MB_SUCCESS == moab()->add_entities( left, &left_entities[0], left_entities.size() ) && 00355 MB_SUCCESS == moab()->add_entities(right,&right_entities[0],right_entities.size() ) && 00356 MB_SUCCESS == moab()->clear_meshset( &parent, 1 )) 00357 return MB_SUCCESS; 00358 00359 moab()->remove_child_meshset( parent, left ); 00360 moab()->remove_child_meshset( parent, right ); 00361 EntityHandle children[] = { left, right }; 00362 moab()->delete_entities( children, 2 ); 00363 return MB_FAILURE; 00364 } 00365 00366 ErrorCode BSPTree::merge_leaf( BSPTreeIter& iter ) 00367 { 00368 ErrorCode rval; 00369 if (iter.depth() == 1) // at root 00370 return MB_FAILURE; 00371 00372 // Move iter to parent 00373 iter.up(); 00374 00375 // Get sets to merge 00376 EntityHandle parent = iter.handle(); 00377 iter.childVect.clear(); 00378 rval = moab()->get_child_meshsets( parent, iter.childVect ); 00379 if (MB_SUCCESS != rval) 00380 return rval; 00381 00382 // Remove child links 00383 moab()->remove_child_meshset( parent, iter.childVect[0] ); 00384 moab()->remove_child_meshset( parent, iter.childVect[1] ); 00385 std::vector<EntityHandle> stack( iter.childVect ); 00386 00387 // Get all entities from children and put them in parent 00388 Range range; 00389 while (!stack.empty()) { 00390 EntityHandle h = stack.back(); 00391 stack.pop_back(); 00392 range.clear(); 00393 rval = moab()->get_entities_by_handle( h, range ); 00394 if (MB_SUCCESS != rval) 00395 return rval; 00396 rval = moab()->add_entities( parent, range ); 00397 if (MB_SUCCESS != rval) 00398 return rval; 00399 00400 iter.childVect.clear(); 00401 moab()->get_child_meshsets( h, iter.childVect ); 00402 if (!iter.childVect.empty()) { 00403 moab()->remove_child_meshset( h, iter.childVect[0] ); 00404 moab()->remove_child_meshset( h, iter.childVect[1] ); 00405 stack.push_back( iter.childVect[0] ); 00406 stack.push_back( iter.childVect[1] ); 00407 } 00408 00409 rval = moab()->delete_entities( &h, 1 ); 00410 if (MB_SUCCESS != rval) 00411 return rval; 00412 } 00413 00414 return MB_SUCCESS; 00415 } 00416 00417 00418 00419 ErrorCode BSPTreeIter::initialize( BSPTree* btool, 00420 EntityHandle root, 00421 const double* /*point*/ ) 00422 { 00423 treeTool = btool; 00424 mStack.clear(); 00425 mStack.push_back( root ); 00426 return MB_SUCCESS; 00427 } 00428 00429 00430 ErrorCode BSPTreeIter::step_to_first_leaf( Direction direction ) 00431 { 00432 ErrorCode rval; 00433 for (;;) { 00434 childVect.clear(); 00435 rval = tool()->moab()->get_child_meshsets( mStack.back(), childVect ); 00436 if (MB_SUCCESS != rval) 00437 return rval; 00438 if (childVect.empty()) // leaf 00439 break; 00440 00441 mStack.push_back( childVect[direction] ); 00442 } 00443 return MB_SUCCESS; 00444 } 00445 00446 ErrorCode BSPTreeIter::step( Direction direction ) 00447 { 00448 EntityHandle node, parent; 00449 ErrorCode rval; 00450 const Direction opposite = static_cast<Direction>(1-direction); 00451 00452 // If stack is empty, then either this iterator is uninitialized 00453 // or we reached the end of the iteration (and return 00454 // MB_ENTITY_NOT_FOUND) already. 00455 if (mStack.empty()) 00456 return MB_FAILURE; 00457 00458 // Pop the current node from the stack. 00459 // The stack should then contain the parent of the current node. 00460 // If the stack is empty after this pop, then we've reached the end. 00461 node = mStack.back(); 00462 mStack.pop_back(); 00463 00464 while(!mStack.empty()) { 00465 // Get data for parent entity 00466 parent = mStack.back(); 00467 childVect.clear(); 00468 rval = tool()->moab()->get_child_meshsets( parent, childVect ); 00469 if (MB_SUCCESS != rval) 00470 return rval; 00471 00472 // If we're at the left child 00473 if (childVect[opposite] == node) { 00474 // push right child on stack 00475 mStack.push_back( childVect[direction] ); 00476 // descend to left-most leaf of the right child 00477 return step_to_first_leaf(opposite); 00478 } 00479 00480 // The current node is the right child of the parent, 00481 // continue up the tree. 00482 assert( childVect[direction] == node ); 00483 node = parent; 00484 mStack.pop_back(); 00485 } 00486 00487 return MB_ENTITY_NOT_FOUND; 00488 } 00489 00490 ErrorCode BSPTreeIter::up() 00491 { 00492 if (mStack.size() < 2) 00493 return MB_ENTITY_NOT_FOUND; 00494 mStack.pop_back(); 00495 return MB_SUCCESS; 00496 } 00497 00498 ErrorCode BSPTreeIter::down( const BSPTree::Plane& /*plane*/, Direction dir ) 00499 { 00500 childVect.clear(); 00501 ErrorCode rval = tool()->moab()->get_child_meshsets( mStack.back(), childVect ); 00502 if (MB_SUCCESS != rval) 00503 return rval; 00504 if (childVect.empty()) 00505 return MB_ENTITY_NOT_FOUND; 00506 00507 mStack.push_back( childVect[dir] ); 00508 return MB_SUCCESS; 00509 } 00510 00511 ErrorCode BSPTreeIter::get_parent_split_plane( BSPTree::Plane& plane ) const 00512 { 00513 if (mStack.size() < 2) // at tree root 00514 return MB_ENTITY_NOT_FOUND; 00515 00516 EntityHandle parent = mStack[mStack.size()-2]; 00517 return tool()->get_split_plane( parent, plane ); 00518 } 00519 00520 double BSPTreeIter::volume() const 00521 { 00522 BSPTreePoly polyhedron; 00523 ErrorCode rval = calculate_polyhedron( polyhedron ); 00524 return MB_SUCCESS == rval ? polyhedron.volume() : -1.0; 00525 } 00526 00527 bool BSPTreeIter::is_sibling( const BSPTreeIter& other_leaf ) const 00528 { 00529 const size_t s = mStack.size(); 00530 return (s > 1) && (s == other_leaf.mStack.size()) && 00531 (other_leaf.mStack[s-2] == mStack[s-2]) && 00532 other_leaf.handle() != handle(); 00533 } 00534 00535 bool BSPTreeIter::is_sibling( EntityHandle other_leaf ) const 00536 { 00537 if (mStack.size() < 2 || other_leaf == handle()) 00538 return false; 00539 EntityHandle parent = mStack[mStack.size()-2]; 00540 childVect.clear(); 00541 ErrorCode rval = tool()->moab()->get_child_meshsets( parent, childVect ); 00542 if (MB_SUCCESS != rval || childVect.size() != 2) { 00543 assert(false); 00544 return false; 00545 } 00546 return childVect[0] == other_leaf || childVect[1] == other_leaf; 00547 } 00548 00549 bool BSPTreeIter::sibling_is_forward() const 00550 { 00551 if (mStack.size() < 2) // if root 00552 return false; 00553 EntityHandle parent = mStack[mStack.size()-2]; 00554 childVect.clear(); 00555 ErrorCode rval = tool()->moab()->get_child_meshsets( parent, childVect ); 00556 if (MB_SUCCESS != rval || childVect.size() != 2) { 00557 assert(false); 00558 return false; 00559 } 00560 return childVect[0] == handle(); 00561 } 00562 00563 ErrorCode BSPTreeIter::calculate_polyhedron( BSPTreePoly& poly_out ) const 00564 { 00565 ErrorCode rval; 00566 00567 assert( sizeof(CartVect) == 3*sizeof(double) ); 00568 CartVect corners[8]; 00569 rval = treeTool->get_tree_box( mStack.front(), corners[0].array() ); 00570 if (MB_SUCCESS != rval) 00571 return rval; 00572 00573 rval = poly_out.set( corners ); 00574 if (MB_SUCCESS != rval) 00575 return rval; 00576 00577 BSPTree::Plane plane; 00578 std::vector<EntityHandle>::const_iterator i = mStack.begin(); 00579 std::vector<EntityHandle>::const_iterator here = mStack.end() - 1; 00580 while (i != here) { 00581 rval = treeTool->get_split_plane( *i, plane ); 00582 if (MB_SUCCESS != rval) 00583 return rval; 00584 00585 childVect.clear(); 00586 rval = treeTool->moab()->get_child_meshsets( *i, childVect ); 00587 if (MB_SUCCESS != rval) 00588 return rval; 00589 if (childVect.size() != 2) 00590 return MB_FAILURE; 00591 00592 ++i; 00593 if (childVect[1] == *i) 00594 plane.flip(); 00595 00596 CartVect norm( plane.norm ); 00597 poly_out.cut_polyhedron( norm, plane.coeff ); 00598 } 00599 00600 return MB_SUCCESS; 00601 } 00602 00603 ErrorCode BSPTreeBoxIter::initialize( BSPTree* tool_ptr, 00604 EntityHandle root, 00605 const double* point ) 00606 { 00607 ErrorCode rval = BSPTreeIter::initialize( tool_ptr, root ); 00608 if (MB_SUCCESS != rval) 00609 return rval; 00610 00611 tool()->get_tree_box( root, leafCoords ); 00612 if (MB_SUCCESS != rval) 00613 return rval; 00614 00615 if (point && !point_in_box( leafCoords, point )) 00616 return MB_ENTITY_NOT_FOUND; 00617 00618 stackData.resize(1); 00619 return MB_SUCCESS; 00620 } 00621 00622 BSPTreeBoxIter::SideBits 00623 BSPTreeBoxIter::side_above_plane( const double hex_coords[8][3], 00624 const BSPTree::Plane& plane ) 00625 { 00626 unsigned result = 0; 00627 for (unsigned i = 0; i < 8u; ++i) 00628 result |= plane.above(hex_coords[i]) << i; 00629 return (BSPTreeBoxIter::SideBits)result; 00630 } 00631 00632 BSPTreeBoxIter::SideBits 00633 BSPTreeBoxIter::side_on_plane( const double hex_coords[8][3], 00634 const BSPTree::Plane& plane ) 00635 { 00636 unsigned result = 0; 00637 for (unsigned i = 0; i < 8u; ++i) { 00638 bool on = plane.distance(hex_coords[i]) <= BSPTree::epsilon(); 00639 result |= on << i; 00640 } 00641 return (BSPTreeBoxIter::SideBits)result; 00642 } 00643 00644 static inline void copy_coords( const double src[3], double dest[3] ) 00645 { 00646 dest[0] = src[0]; 00647 dest[1] = src[1]; 00648 dest[2] = src[2]; 00649 } 00650 00651 ErrorCode BSPTreeBoxIter::face_corners( const SideBits face, 00652 const double hex_corners[8][3], 00653 double face_corners[4][3] ) 00654 { 00655 switch (face) { 00656 case BSPTreeBoxIter::B0154: 00657 copy_coords( hex_corners[0], face_corners[0] ); 00658 copy_coords( hex_corners[1], face_corners[1] ); 00659 copy_coords( hex_corners[5], face_corners[2] ); 00660 copy_coords( hex_corners[4], face_corners[3] ); 00661 break; 00662 case BSPTreeBoxIter::B1265: 00663 copy_coords( hex_corners[1], face_corners[0] ); 00664 copy_coords( hex_corners[2], face_corners[1] ); 00665 copy_coords( hex_corners[6], face_corners[2] ); 00666 copy_coords( hex_corners[5], face_corners[3] ); 00667 break; 00668 case BSPTreeBoxIter::B2376: 00669 copy_coords( hex_corners[2], face_corners[0] ); 00670 copy_coords( hex_corners[3], face_corners[1] ); 00671 copy_coords( hex_corners[7], face_corners[2] ); 00672 copy_coords( hex_corners[6], face_corners[3] ); 00673 break; 00674 case BSPTreeBoxIter::B3047: 00675 copy_coords( hex_corners[3], face_corners[0] ); 00676 copy_coords( hex_corners[0], face_corners[1] ); 00677 copy_coords( hex_corners[4], face_corners[2] ); 00678 copy_coords( hex_corners[7], face_corners[3] ); 00679 break; 00680 case BSPTreeBoxIter::B3210: 00681 copy_coords( hex_corners[3], face_corners[0] ); 00682 copy_coords( hex_corners[2], face_corners[1] ); 00683 copy_coords( hex_corners[1], face_corners[2] ); 00684 copy_coords( hex_corners[0], face_corners[3] ); 00685 break; 00686 case BSPTreeBoxIter::B4567: 00687 copy_coords( hex_corners[4], face_corners[0] ); 00688 copy_coords( hex_corners[5], face_corners[1] ); 00689 copy_coords( hex_corners[6], face_corners[2] ); 00690 copy_coords( hex_corners[7], face_corners[3] ); 00691 break; 00692 default: 00693 return MB_FAILURE; // child is not a box 00694 } 00695 00696 return MB_SUCCESS; 00697 00698 } 00699 00707 static inline 00708 void plane_cut_edge( double old_coords_out[3], 00709 const double keep_end_coords[3], 00710 double cut_end_coords[3], 00711 const BSPTree::Plane& plane ) 00712 { 00713 const CartVect start( keep_end_coords ), end( cut_end_coords ); 00714 const CartVect norm( plane.norm ); 00715 CartVect xsect_point; 00716 00717 const CartVect m = end - start; 00718 const double t = -(norm % start + plane.coeff) / (norm % m); 00719 assert( t > 0.0 && t < 1.0 ); 00720 xsect_point = start + t * m; 00721 00722 end.get( old_coords_out ); 00723 xsect_point.get( cut_end_coords ); 00724 } 00725 00734 static ErrorCode plane_cut_box( double cut_face_out[4][3], 00735 double corners_inout[8][3], 00736 const BSPTree::Plane& plane ) 00737 { 00738 switch (BSPTreeBoxIter::side_above_plane( corners_inout, plane )) { 00739 case BSPTreeBoxIter::B0154: 00740 plane_cut_edge( cut_face_out[0], corners_inout[3], corners_inout[0], plane ); 00741 plane_cut_edge( cut_face_out[1], corners_inout[2], corners_inout[1], plane ); 00742 plane_cut_edge( cut_face_out[2], corners_inout[6], corners_inout[5], plane ); 00743 plane_cut_edge( cut_face_out[3], corners_inout[7], corners_inout[4], plane ); 00744 break; 00745 case BSPTreeBoxIter::B1265: 00746 plane_cut_edge( cut_face_out[0], corners_inout[0], corners_inout[1], plane ); 00747 plane_cut_edge( cut_face_out[1], corners_inout[3], corners_inout[2], plane ); 00748 plane_cut_edge( cut_face_out[2], corners_inout[7], corners_inout[6], plane ); 00749 plane_cut_edge( cut_face_out[3], corners_inout[4], corners_inout[5], plane ); 00750 break; 00751 case BSPTreeBoxIter::B2376: 00752 plane_cut_edge( cut_face_out[0], corners_inout[1], corners_inout[2], plane ); 00753 plane_cut_edge( cut_face_out[1], corners_inout[0], corners_inout[3], plane ); 00754 plane_cut_edge( cut_face_out[2], corners_inout[4], corners_inout[7], plane ); 00755 plane_cut_edge( cut_face_out[3], corners_inout[5], corners_inout[6], plane ); 00756 break; 00757 case BSPTreeBoxIter::B3047: 00758 plane_cut_edge( cut_face_out[0], corners_inout[2], corners_inout[3], plane ); 00759 plane_cut_edge( cut_face_out[1], corners_inout[1], corners_inout[0], plane ); 00760 plane_cut_edge( cut_face_out[2], corners_inout[5], corners_inout[4], plane ); 00761 plane_cut_edge( cut_face_out[3], corners_inout[6], corners_inout[7], plane ); 00762 break; 00763 case BSPTreeBoxIter::B3210: 00764 plane_cut_edge( cut_face_out[0], corners_inout[7], corners_inout[3], plane ); 00765 plane_cut_edge( cut_face_out[1], corners_inout[6], corners_inout[2], plane ); 00766 plane_cut_edge( cut_face_out[2], corners_inout[5], corners_inout[1], plane ); 00767 plane_cut_edge( cut_face_out[3], corners_inout[4], corners_inout[0], plane ); 00768 break; 00769 case BSPTreeBoxIter::B4567: 00770 plane_cut_edge( cut_face_out[0], corners_inout[0], corners_inout[4], plane ); 00771 plane_cut_edge( cut_face_out[1], corners_inout[1], corners_inout[5], plane ); 00772 plane_cut_edge( cut_face_out[2], corners_inout[2], corners_inout[6], plane ); 00773 plane_cut_edge( cut_face_out[3], corners_inout[3], corners_inout[7], plane ); 00774 break; 00775 default: 00776 return MB_FAILURE; // child is not a box 00777 } 00778 00779 return MB_SUCCESS; 00780 } 00781 00782 static inline 00783 void copy_coords( double dest[3], const double source[3] ) 00784 { 00785 dest[0] = source[0]; 00786 dest[1] = source[1]; 00787 dest[2] = source[2]; 00788 } 00789 00791 static inline 00792 ErrorCode plane_uncut_box( const double cut_face_in[4][3], 00793 double corners_inout[8][3], 00794 const BSPTree::Plane& plane ) 00795 { 00796 switch (BSPTreeBoxIter::side_on_plane( corners_inout, plane )) { 00797 case BSPTreeBoxIter::B0154: 00798 copy_coords( corners_inout[0], cut_face_in[0] ); 00799 copy_coords( corners_inout[1], cut_face_in[1] ); 00800 copy_coords( corners_inout[5], cut_face_in[2] ); 00801 copy_coords( corners_inout[4], cut_face_in[3] ); 00802 break; 00803 case BSPTreeBoxIter::B1265: 00804 copy_coords( corners_inout[1], cut_face_in[0] ); 00805 copy_coords( corners_inout[2], cut_face_in[1] ); 00806 copy_coords( corners_inout[6], cut_face_in[2] ); 00807 copy_coords( corners_inout[5], cut_face_in[3] ); 00808 break; 00809 case BSPTreeBoxIter::B2376: 00810 copy_coords( corners_inout[2], cut_face_in[0] ); 00811 copy_coords( corners_inout[3], cut_face_in[1] ); 00812 copy_coords( corners_inout[7], cut_face_in[2] ); 00813 copy_coords( corners_inout[6], cut_face_in[3] ); 00814 break; 00815 case BSPTreeBoxIter::B3047: 00816 copy_coords( corners_inout[3], cut_face_in[0] ); 00817 copy_coords( corners_inout[0], cut_face_in[1] ); 00818 copy_coords( corners_inout[4], cut_face_in[2] ); 00819 copy_coords( corners_inout[7], cut_face_in[3] ); 00820 break; 00821 case BSPTreeBoxIter::B3210: 00822 copy_coords( corners_inout[3], cut_face_in[0] ); 00823 copy_coords( corners_inout[2], cut_face_in[1] ); 00824 copy_coords( corners_inout[1], cut_face_in[2] ); 00825 copy_coords( corners_inout[0], cut_face_in[3] ); 00826 break; 00827 case BSPTreeBoxIter::B4567: 00828 copy_coords( corners_inout[4], cut_face_in[0] ); 00829 copy_coords( corners_inout[5], cut_face_in[1] ); 00830 copy_coords( corners_inout[6], cut_face_in[2] ); 00831 copy_coords( corners_inout[7], cut_face_in[3] ); 00832 break; 00833 default: 00834 return MB_FAILURE; // child is not a box 00835 } 00836 00837 return MB_SUCCESS; 00838 } 00839 00840 ErrorCode BSPTreeBoxIter::step_to_first_leaf( Direction direction ) 00841 { 00842 ErrorCode rval; 00843 BSPTree::Plane plane; 00844 Corners clipped_corners; 00845 00846 for (;;) { 00847 childVect.clear(); 00848 rval = tool()->moab()->get_child_meshsets( mStack.back(), childVect ); 00849 if (MB_SUCCESS != rval) 00850 return rval; 00851 if (childVect.empty()) // leaf 00852 break; 00853 00854 rval = tool()->get_split_plane( mStack.back(), plane ); 00855 if (MB_SUCCESS != rval) 00856 return rval; 00857 00858 if (direction == RIGHT) 00859 plane.flip(); 00860 rval = plane_cut_box( clipped_corners.coords, leafCoords, plane ); 00861 if (MB_SUCCESS != rval) 00862 return rval; 00863 mStack.push_back( childVect[direction] ); 00864 stackData.push_back( clipped_corners ); 00865 } 00866 return MB_SUCCESS; 00867 } 00868 00869 ErrorCode BSPTreeBoxIter::up() 00870 { 00871 ErrorCode rval; 00872 if (mStack.size() == 1) 00873 return MB_ENTITY_NOT_FOUND; 00874 00875 EntityHandle node = mStack.back(); 00876 Corners clipped_face = stackData.back(); 00877 mStack.pop_back(); 00878 stackData.pop_back(); 00879 00880 BSPTree::Plane plane; 00881 rval = tool()->get_split_plane( mStack.back(), plane ); 00882 if (MB_SUCCESS != rval) { 00883 mStack.push_back( node ); 00884 stackData.push_back( clipped_face ); 00885 return rval; 00886 } 00887 00888 rval = plane_uncut_box( clipped_face.coords, leafCoords, plane ); 00889 if (MB_SUCCESS != rval) { 00890 mStack.push_back( node ); 00891 stackData.push_back( clipped_face ); 00892 return rval; 00893 } 00894 00895 return MB_SUCCESS; 00896 } 00897 00898 ErrorCode BSPTreeBoxIter::down( const BSPTree::Plane& plane_ref, Direction direction ) 00899 { 00900 childVect.clear(); 00901 ErrorCode rval = tool()->moab()->get_child_meshsets( mStack.back(), childVect ); 00902 if (MB_SUCCESS != rval) 00903 return rval; 00904 if (childVect.empty()) 00905 return MB_ENTITY_NOT_FOUND; 00906 00907 BSPTree::Plane plane(plane_ref); 00908 if (direction == RIGHT) 00909 plane.flip(); 00910 00911 Corners clipped_face; 00912 rval = plane_cut_box( clipped_face.coords, leafCoords, plane ); 00913 if (MB_SUCCESS != rval) 00914 return rval; 00915 00916 mStack.push_back( childVect[direction] ); 00917 stackData.push_back( clipped_face ); 00918 return MB_SUCCESS; 00919 } 00920 00921 ErrorCode BSPTreeBoxIter::step( Direction direction ) 00922 { 00923 EntityHandle node, parent; 00924 Corners clipped_face; 00925 ErrorCode rval; 00926 BSPTree::Plane plane; 00927 const Direction opposite = static_cast<Direction>(1-direction); 00928 00929 // If stack is empty, then either this iterator is uninitialized 00930 // or we reached the end of the iteration (and return 00931 // MB_ENTITY_NOT_FOUND) already. 00932 if (mStack.empty()) 00933 return MB_FAILURE; 00934 00935 // Pop the current node from the stack. 00936 // The stack should then contain the parent of the current node. 00937 // If the stack is empty after this pop, then we've reached the end. 00938 node = mStack.back(); 00939 mStack.pop_back(); 00940 clipped_face = stackData.back(); 00941 stackData.pop_back(); 00942 00943 while(!mStack.empty()) { 00944 // Get data for parent entity 00945 parent = mStack.back(); 00946 childVect.clear(); 00947 rval = tool()->moab()->get_child_meshsets( parent, childVect ); 00948 if (MB_SUCCESS != rval) 00949 return rval; 00950 rval = tool()->get_split_plane( parent, plane ); 00951 if (MB_SUCCESS != rval) 00952 return rval; 00953 if (direction == LEFT) 00954 plane.flip(); 00955 00956 // If we're at the left child 00957 if (childVect[opposite] == node) { 00958 // change from box of left child to box of parent 00959 plane_uncut_box( clipped_face.coords, leafCoords, plane ); 00960 // change from box of parent to box of right child 00961 plane.flip(); 00962 plane_cut_box( clipped_face.coords, leafCoords, plane ); 00963 // push right child on stack 00964 mStack.push_back( childVect[direction] ); 00965 stackData.push_back( clipped_face ); 00966 // descend to left-most leaf of the right child 00967 return step_to_first_leaf(opposite); 00968 } 00969 00970 // The current node is the right child of the parent, 00971 // continue up the tree. 00972 assert( childVect[direction] == node ); 00973 plane.flip(); 00974 plane_uncut_box( clipped_face.coords, leafCoords, plane ); 00975 node = parent; 00976 clipped_face = stackData.back(); 00977 mStack.pop_back(); 00978 stackData.pop_back(); 00979 } 00980 00981 return MB_ENTITY_NOT_FOUND; 00982 } 00983 00984 ErrorCode BSPTreeBoxIter::get_box_corners( double coords[8][3] ) const 00985 { 00986 memcpy( coords, leafCoords, 24*sizeof(double) ); 00987 return MB_SUCCESS; 00988 } 00989 00990 // result = a - b 00991 static void subtr( double result[3], const double a[3], const double b[3] ) 00992 { 00993 result[0] = a[0] - b[0]; 00994 result[1] = a[1] - b[1]; 00995 result[2] = a[2] - b[2]; 00996 } 00997 00998 // result = a + b + c + d 00999 static void sum( double result[3], 01000 const double a[3], 01001 const double b[3], 01002 const double c[3], 01003 const double d[3] ) 01004 { 01005 result[0] = a[0] + b[0] + c[0] + d[0]; 01006 result[1] = a[1] + b[1] + c[1] + d[1]; 01007 result[2] = a[2] + b[2] + c[2] + d[2]; 01008 } 01009 01010 // result = a cross b 01011 static void cross( double result[3], const double a[3], const double b[3] ) 01012 { 01013 result[0] = a[1]*b[2] - a[2]*b[1]; 01014 result[1] = a[2]*b[0] - a[0]*b[2]; 01015 result[2] = a[0]*b[1] - a[1]*b[0]; 01016 } 01017 01018 static double dot( const double a[3], const double b[3] ) 01019 { 01020 return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; 01021 } 01022 01023 double BSPTreeBoxIter::volume() const 01024 { 01025 // have planar sides, so use mid-face tripple product 01026 double f1[3], f2[3], f3[3], f4[3], f5[3], f6[3]; 01027 sum( f1, leafCoords[0], leafCoords[1], leafCoords[4], leafCoords[5] ); 01028 sum( f2, leafCoords[1], leafCoords[2], leafCoords[5], leafCoords[6] ); 01029 sum( f3, leafCoords[2], leafCoords[3], leafCoords[6], leafCoords[7] ); 01030 sum( f4, leafCoords[0], leafCoords[3], leafCoords[4], leafCoords[7] ); 01031 sum( f5, leafCoords[0], leafCoords[1], leafCoords[2], leafCoords[3] ); 01032 sum( f6, leafCoords[4], leafCoords[5], leafCoords[6], leafCoords[7] ); 01033 double v13[3], v24[3], v65[3]; 01034 subtr( v13, f1, f3 ); 01035 subtr( v24, f2, f4 ); 01036 subtr( v65, f6, f5 ); 01037 double cr[3]; 01038 cross( cr, v13, v24 ); 01039 return (1./64) * dot( cr, v65 ); 01040 } 01041 01042 BSPTreeBoxIter::XSect 01043 BSPTreeBoxIter::splits( const BSPTree::Plane& plane ) const 01044 { 01045 // test each corner relative to the plane 01046 unsigned result = 0; 01047 for (unsigned i = 0; i < 8u; ++i) { 01048 double d = plane.signed_distance( leafCoords[i] ); 01049 // if corner is on plane, than intersection 01050 // will result in a degenerate hex 01051 if (fabs(d) < BSPTree::epsilon()) 01052 return NONHEX; 01053 // if mark vertices above plane 01054 if (d > 0.0) 01055 result |= 1<<i; 01056 } 01057 01058 switch (result) { 01059 // if all vertices or no vertices above plane, 01060 // then plane doesn't intersect 01061 case 0: 01062 case 0xFF: 01063 return MISS; 01064 01065 // if there are four vertices above the plane 01066 // and they compose a single face of the hex, 01067 // then the cut will result in two hexes 01068 case B0154: 01069 case B1265: 01070 case B2376: 01071 case B3047: 01072 case B3210: 01073 case B4567: 01074 return SPLIT; 01075 01076 // otherwise intersects, but split would not result 01077 // in two hexahedrons 01078 default: 01079 return NONHEX; 01080 } 01081 } 01082 01083 bool BSPTreeBoxIter::intersects( const BSPTree::Plane& plane ) const 01084 { 01085 // test each corner relative to the plane 01086 unsigned count = 0; 01087 for (unsigned i = 0; i < 8u; ++i) 01088 count += plane.above( leafCoords[i] ); 01089 return count > 0 && count < 8u; 01090 } 01091 01092 ErrorCode BSPTreeBoxIter::sibling_side( SideBits& side_out ) const 01093 { 01094 if (mStack.size() < 2) // at tree root 01095 return MB_ENTITY_NOT_FOUND; 01096 01097 EntityHandle parent = mStack[mStack.size()-2]; 01098 BSPTree::Plane plane; 01099 ErrorCode rval = tool()->get_split_plane( parent, plane ); 01100 if (MB_SUCCESS != rval) 01101 return MB_FAILURE; 01102 01103 side_out = side_on_plane( leafCoords, plane ); 01104 return MB_SUCCESS; 01105 } 01106 01107 ErrorCode BSPTreeBoxIter::get_neighbors( 01108 SideBits side, 01109 std::vector<BSPTreeBoxIter>& results, 01110 double epsilon ) const 01111 { 01112 EntityHandle tmp_handle; 01113 BSPTree::Plane plane; 01114 ErrorCode rval; 01115 int n; 01116 01117 Corners face; 01118 rval = face_corners( side, leafCoords, face.coords ); 01119 if (MB_SUCCESS != rval) 01120 return rval; 01121 01122 // Move up tree until we find the split that created the specified side. 01123 // Push the sibling at that level onto the iterator stack as 01124 // all neighbors will be rooted at that node. 01125 BSPTreeBoxIter iter( *this ); // temporary iterator (don't modifiy *this) 01126 for (;;) { 01127 tmp_handle = iter.handle(); 01128 01129 rval = iter.up(); 01130 if (MB_SUCCESS != rval) // reached root - no neighbors on that side 01131 return (rval == MB_ENTITY_NOT_FOUND) ? MB_SUCCESS : rval; 01132 01133 iter.childVect.clear(); 01134 rval = tool()->moab()->get_child_meshsets( iter.handle(), iter.childVect ); 01135 if (MB_SUCCESS!= rval) 01136 return rval; 01137 01138 rval = tool()->get_split_plane( iter.handle(), plane ); 01139 if (MB_SUCCESS != rval) 01140 return rval; 01141 SideBits s = side_above_plane( iter.leafCoords, plane ); 01142 01143 if (tmp_handle == iter.childVect[0] && s == side) { 01144 rval = iter.down( plane, RIGHT ); 01145 if (MB_SUCCESS != rval) 01146 return rval; 01147 break; 01148 } 01149 else if (tmp_handle == iter.childVect[1] && opposite_face(s) == side) { 01150 rval = iter.down( plane, LEFT ); 01151 if (MB_SUCCESS != rval) 01152 return rval; 01153 break; 01154 } 01155 } 01156 01157 // now move down tree, searching for adjacent boxes 01158 std::vector<BSPTreeBoxIter> list; 01159 // loop over all potential paths to neighbors (until list is empty) 01160 for (;;) { 01161 // follow a single path to a leaf, append any other potential 01162 // paths to neighbors to 'list' 01163 for (;;) { 01164 rval = tool()->moab()->num_child_meshsets( iter.handle(), &n ); 01165 if (MB_SUCCESS != rval) 01166 return rval; 01167 01168 // if leaf 01169 if (!n) { 01170 results.push_back( iter ); 01171 break; 01172 } 01173 01174 rval = tool()->get_split_plane( iter.handle(), plane ); 01175 if (MB_SUCCESS != rval) 01176 return rval; 01177 01178 bool some_above = false, some_below = false; 01179 for (int i = 0; i < 4; ++i) { 01180 double signed_d = plane.signed_distance( face.coords[i] ); 01181 if (signed_d > -epsilon) 01182 some_above = true; 01183 if (signed_d < epsilon) 01184 some_below = true; 01185 } 01186 01187 if (some_above && some_below) { 01188 list.push_back( iter ); 01189 list.back().down( plane, RIGHT ); 01190 iter.down( plane, LEFT ); 01191 } 01192 else if (some_above) { 01193 iter.down( plane, RIGHT ); 01194 } 01195 else if (some_below) { 01196 iter.down( plane, LEFT ); 01197 } 01198 else { 01199 // tolerance issue -- epsilon to small? 2D box? 01200 return MB_FAILURE; 01201 } 01202 } 01203 01204 if (list.empty()) 01205 break; 01206 01207 iter = list.back(); 01208 list.pop_back(); 01209 } 01210 01211 return MB_SUCCESS; 01212 } 01213 01214 ErrorCode BSPTreeBoxIter::calculate_polyhedron( BSPTreePoly& poly_out ) const 01215 { 01216 const CartVect* ptr = reinterpret_cast<const CartVect*>(leafCoords); 01217 return poly_out.set( ptr ); 01218 } 01219 01220 ErrorCode BSPTree::leaf_containing_point( EntityHandle tree_root, 01221 const double point[3], 01222 EntityHandle& leaf_out ) 01223 { 01224 std::vector<EntityHandle> children; 01225 Plane plane; 01226 EntityHandle node = tree_root; 01227 ErrorCode rval = moab()->get_child_meshsets( node, children ); 01228 if (MB_SUCCESS != rval) 01229 return rval; 01230 while (!children.empty()) { 01231 rval = get_split_plane( node, plane ); 01232 if (MB_SUCCESS != rval) 01233 return rval; 01234 01235 node = children[plane.above(point)]; 01236 children.clear(); 01237 rval = moab()->get_child_meshsets( node, children ); 01238 if (MB_SUCCESS != rval) 01239 return rval; 01240 } 01241 leaf_out = node; 01242 return MB_SUCCESS; 01243 } 01244 01245 ErrorCode BSPTree::leaf_containing_point( EntityHandle root, 01246 const double point[3], 01247 BSPTreeIter& iter ) 01248 { 01249 ErrorCode rval; 01250 01251 rval = iter.initialize( this, root, point ); 01252 if (MB_SUCCESS != rval) 01253 return rval; 01254 01255 for (;;) { 01256 iter.childVect.clear(); 01257 rval = moab()->get_child_meshsets( iter.handle(), iter.childVect ); 01258 if (MB_SUCCESS != rval || iter.childVect.empty()) 01259 return rval; 01260 01261 Plane plane; 01262 rval = get_split_plane( iter.handle(), plane ); 01263 if (MB_SUCCESS != rval) 01264 return rval; 01265 01266 rval = iter.down( plane, (BSPTreeIter::Direction)(plane.above( point )) ); 01267 if (MB_SUCCESS != rval) 01268 return rval; 01269 } 01270 } 01271 01272 01273 01274 template <typename PlaneIter> static inline 01275 bool ray_intersect_halfspaces( const CartVect& ray_pt, 01276 const CartVect& ray_dir, 01277 const PlaneIter& begin, 01278 const PlaneIter& end, 01279 double& t_enter, 01280 double& t_exit ) 01281 { 01282 const double epsilon = 1e-12; 01283 01284 // begin with inifinite ray 01285 t_enter = 0.0; 01286 t_exit = std::numeric_limits<double>::infinity(); 01287 01288 // cut ray such that we keep only the portion contained 01289 // in each halfspace 01290 for (PlaneIter i = begin; i != end; ++i) { 01291 CartVect norm( i->norm ); 01292 double coeff = i->coeff; 01293 double den = norm % ray_dir; 01294 if (fabs(den) < epsilon) { // ray is parallel to plane 01295 if (i->above( ray_pt.array() )) 01296 return false; // ray entirely outside half-space 01297 } 01298 else { 01299 double t_xsect = (-coeff - (norm % ray_pt)) / den; 01300 // keep portion of ray/segment below plane 01301 if (den > 0) { 01302 if (t_xsect < t_exit) 01303 t_exit = t_xsect; 01304 } 01305 else { 01306 if (t_xsect > t_enter) 01307 t_enter = t_xsect; 01308 } 01309 } 01310 } 01311 01312 return t_exit >= t_enter; 01313 } 01314 01315 class BoxPlaneIter { 01316 int faceNum; 01317 BSPTree::Plane facePlanes[6]; 01318 01319 public: 01320 BoxPlaneIter( const double coords[8][3] ); 01321 BoxPlaneIter( ) : faceNum(6) {} // initialize to 'end' 01322 const BSPTree::Plane* operator->() const 01323 { return facePlanes + faceNum; } 01324 bool operator==( const BoxPlaneIter& other ) const 01325 { return faceNum == other.faceNum; } 01326 bool operator!=( const BoxPlaneIter& other ) const 01327 { return faceNum != other.faceNum; } 01328 BoxPlaneIter& operator++() 01329 { ++faceNum; return *this; } 01330 }; 01331 01332 static const int box_face_corners[6][4] = { { 0, 1, 5, 4 }, 01333 { 1, 2, 6, 5 }, 01334 { 2, 3, 7, 6 }, 01335 { 3, 0, 4, 7 }, 01336 { 3, 2, 1, 0 }, 01337 { 4, 5, 6, 7 } }; 01338 01339 BoxPlaneIter::BoxPlaneIter( const double coords[8][3] ) 01340 : faceNum(0) 01341 { 01342 // NOTE: In the case of a BSP tree, all sides of the 01343 // leaf will planar. 01344 assert( sizeof(CartVect) == sizeof(coords[0]) ); 01345 const CartVect* corners = reinterpret_cast<const CartVect*>(coords); 01346 for (int i = 0; i < 6; ++i) { 01347 const int* indices = box_face_corners[i]; 01348 CartVect v1 = corners[indices[1]] - corners[indices[0]]; 01349 CartVect v2 = corners[indices[3]] - corners[indices[0]]; 01350 CartVect n = v1 * v2; 01351 facePlanes[i] = BSPTree::Plane( n.array(), -(n % corners[indices[2]]) ); 01352 } 01353 } 01354 01355 01356 bool BSPTreeBoxIter::intersect_ray( const double ray_point[3], 01357 const double ray_vect[3], 01358 double& t_enter, double& t_exit ) const 01359 { 01360 BoxPlaneIter iter( this->leafCoords ), end; 01361 return ray_intersect_halfspaces( CartVect(ray_point), 01362 CartVect(ray_vect), 01363 iter, end, 01364 t_enter, t_exit ); 01365 } 01366 01367 class BSPTreePlaneIter { 01368 BSPTree* toolPtr; 01369 const EntityHandle* const pathToRoot; 01370 int pathPos; 01371 BSPTree::Plane tmpPlane; 01372 std::vector<EntityHandle> tmpChildren; 01373 public: 01374 BSPTreePlaneIter( BSPTree* tool, const EntityHandle* path, int path_len ) 01375 : toolPtr(tool), pathToRoot(path), pathPos(path_len-1) 01376 { operator++(); } 01377 BSPTreePlaneIter() // initialize to 'end' 01378 : toolPtr(0), pathToRoot(0), pathPos(-1) {} 01379 01380 const BSPTree::Plane* operator->() const 01381 { return &tmpPlane; } 01382 bool operator==( const BSPTreePlaneIter& other ) const 01383 { return pathPos == other.pathPos; } 01384 bool operator!=( const BSPTreePlaneIter& other ) const 01385 { return pathPos != other.pathPos; } 01386 BSPTreePlaneIter& operator++(); 01387 }; 01388 01389 BSPTreePlaneIter& BSPTreePlaneIter::operator++() 01390 { 01391 if (--pathPos < 0) 01392 return *this; 01393 01394 EntityHandle prev = pathToRoot[pathPos+1]; 01395 EntityHandle curr = pathToRoot[pathPos]; 01396 01397 ErrorCode rval = toolPtr->get_split_plane( curr, tmpPlane ); 01398 if (MB_SUCCESS != rval) { 01399 assert(false); 01400 pathPos = 0; 01401 return *this; 01402 } 01403 01404 tmpChildren.clear(); 01405 rval = toolPtr->moab()->get_child_meshsets( curr, tmpChildren ); 01406 if (MB_SUCCESS != rval || tmpChildren.size() != 2) { 01407 assert(false); 01408 pathPos = 0; 01409 return *this; 01410 } 01411 01412 if (tmpChildren[1] == prev) 01413 tmpPlane.flip(); 01414 return *this; 01415 } 01416 01417 01418 bool BSPTreeIter::intersect_ray( const double ray_point[3], 01419 const double ray_vect[3], 01420 double& t_enter, double& t_exit ) const 01421 { 01422 // intersect with half-spaces defining tree 01423 BSPTreePlaneIter iter1( tool(), &mStack[0], mStack.size() ), end1; 01424 if (!ray_intersect_halfspaces( CartVect(ray_point), 01425 CartVect(ray_vect), 01426 iter1, end1, 01427 t_enter, t_exit )) 01428 return false; 01429 01430 01431 // itersect with box bounding entire tree 01432 double corners[8][3]; 01433 ErrorCode rval = tool()->get_tree_box( mStack.front(), corners ); 01434 if (MB_SUCCESS != rval) { 01435 assert(false); 01436 return false; 01437 } 01438 01439 BoxPlaneIter iter2( corners ), end2; 01440 double t2_enter, t2_exit; 01441 if (!ray_intersect_halfspaces( CartVect(ray_point), 01442 CartVect(ray_vect), 01443 iter2, end2, 01444 t2_enter, t2_exit )) 01445 return false; 01446 01447 // if intersect both box and halfspaces, check that 01448 // two intersections overlap 01449 if (t_enter < t2_enter) 01450 t_enter = t2_enter; 01451 if (t_exit > t2_exit) 01452 t_exit = t2_exit; 01453 return t_enter <= t_exit; 01454 } 01455 01456 } // namespace moab