moab
BSPTree.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines