MOAB: Mesh Oriented datABase  (version 5.3.0)
BVHTree.hpp
Go to the documentation of this file.
00001 /**\file BVHTree.hpp
00002  * \class moab::BVHTree
00003  * \brief Bounding Volume Hierarchy (sorta like a tree), for sorting and searching entities
00004  * spatially
00005  */
00006 
00007 #ifndef BVH_TREE_HPP
00008 #define BVH_TREE_HPP
00009 
00010 #include "moab/Interface.hpp"
00011 #include "moab/CartVect.hpp"
00012 #include "moab/BoundBox.hpp"
00013 #include "moab/Tree.hpp"
00014 #include "moab/Range.hpp"
00015 #include "moab/CN.hpp"
00016 
00017 #include <vector>
00018 #include <cfloat>
00019 #include <climits>
00020 #include <map>
00021 #include <set>
00022 #include <iostream>
00023 
00024 #include "moab/win32_config.h"
00025 
00026 namespace moab
00027 {
00028 
00029 class ElemEvaluator;
00030 
00031 class BVHTree : public Tree
00032 {
00033   public:
00034     BVHTree( Interface* impl );
00035 
00036     ~BVHTree()
00037     {
00038         reset_tree();
00039     }
00040 
00041     /** \brief Destroy the tree maintained by this object, optionally checking we have the right
00042      * root. \param root If non-NULL, check that this is the root, return failure if not
00043      */
00044     virtual ErrorCode reset_tree();
00045 
00046     virtual ErrorCode parse_options( FileOptions& opts );
00047 
00048     /** \brief Get bounding box for tree below tree_node, or entire tree
00049      * If no tree has been built yet, returns +/- DBL_MAX for all dimensions.  Note for some tree
00050      * types, boxes are not available for non-root nodes, and this function will return failure if
00051      * non-root is passed in \param box The box for this tree \param tree_node If non-NULL, node for
00052      * which box is requested, tree root if NULL \return Only returns error on fatal condition
00053      */
00054     virtual ErrorCode get_bounding_box( BoundBox& box, EntityHandle* tree_node = NULL ) const;
00055 
00056     /** Build the tree
00057      * Build a tree with the entities input.  If a non-NULL tree_root_set pointer is input,
00058      * use the pointed-to set as the root of this tree (*tree_root_set!=0) otherwise construct
00059      * a new root set and pass its handle back in *tree_root_set.  Options vary by tree type;
00060      * see Tree.hpp for common options; options specific to AdaptiveKDTree:
00061      * SPLITS_PER_DIR: number of candidate splits considered per direction; default = 3
00062      * CANDIDATE_PLANE_SET: method used to decide split planes; see CandidatePlaneSet enum (below)
00063      *          for possible values; default = 1 (SUBDIVISION_SNAP)
00064      * \param entities Entities with which to build the tree
00065      * \param tree_root Root set for tree (see function description)
00066      * \param opts Options for tree (see function description)
00067      * \return Error is returned only on build failure
00068      */
00069     virtual ErrorCode build_tree( const Range& entities, EntityHandle* tree_root_set = NULL,
00070                                   FileOptions* options = NULL );
00071 
00072     /** \brief Get leaf containing input position.
00073      *
00074      * Does not take into account global bounding box of tree.
00075      * - Therefore there is always one leaf containing the point.
00076      * - If caller wants to account for global bounding box, then
00077      * caller can test against that box and not call this method
00078      * at all if the point is outside the box, as there is no leaf
00079      * containing the point in that case.
00080      * \param point Point to be located in tree
00081      * \param leaf_out Leaf containing point
00082      * \param iter_tol Tolerance for convergence of point search
00083      * \param inside_tol Tolerance for inside element calculation
00084      * \param multiple_leaves Some tree types can have multiple leaves containing a point;
00085      *          if non-NULL, this parameter is returned true if multiple leaves contain
00086      *          the input point
00087      * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
00088      * \return Non-success returned only in case of failure; not-found indicated by leaf_out=0
00089      */
00090     virtual ErrorCode point_search( const double* point, EntityHandle& leaf_out, const double iter_tol = 1.0e-10,
00091                                     const double inside_tol = 1.0e-6, bool* multiple_leaves = NULL,
00092                                     EntityHandle* start_node = NULL, CartVect* params = NULL );
00093 
00094     /** \brief Find all leaves within a given distance from point
00095      * If dists_out input non-NULL, also returns distances from each leaf; if
00096      * point i is inside leaf, 0 is given as dists_out[i].
00097      * If params_out is non-NULL and myEval is non-NULL, will evaluate individual entities
00098      * in tree nodes and return containing entities in leaves_out.  In those cases, if params_out
00099      * is also non-NULL, will return parameters in those elements in that vector.
00100      * \param from_point Point to be located in tree
00101      * \param distance Distance within which to query
00102      * \param result_list Leaves within distance or containing point
00103      * \param iter_tol Tolerance for convergence of point search
00104      * \param inside_tol Tolerance for inside element calculation
00105      * \param result_dists If non-NULL, will contain distsances to leaves
00106      * \param result_params If non-NULL, will contain parameters of the point in the ents in
00107      * leaves_out \param tree_root Start from this tree node (non-NULL) instead of tree root (NULL)
00108      */
00109     virtual ErrorCode distance_search( const double from_point[3], const double distance,
00110                                        std::vector< EntityHandle >& result_list, const double iter_tol = 1.0e-10,
00111                                        const double inside_tol = 1.0e-6, std::vector< double >* result_dists = NULL,
00112                                        std::vector< CartVect >* result_params = NULL, EntityHandle* tree_root = NULL );
00113 
00114     //! print various things about this tree
00115     virtual ErrorCode print();
00116 
00117   private:
00118     // don't allow copy constructor, too complicated
00119     BVHTree( const BVHTree& s );
00120 
00121     class HandleData
00122     {
00123       public:
00124         HandleData( EntityHandle h, const BoundBox& bx, const double dp ) : myHandle( h ), myBox( bx ), myDim( dp ) {}
00125         HandleData() : myHandle( 0 ), myDim( -1 ) {}
00126         EntityHandle myHandle;
00127         BoundBox myBox;
00128         double myDim;
00129     };
00130     typedef std::vector< HandleData > HandleDataVec;
00131 
00132     class SplitData
00133     {
00134       public:
00135         SplitData()
00136             : dim( UINT_MAX ), nl( UINT_MAX ), nr( UINT_MAX ), split( DBL_MAX ), Lmax( -DBL_MAX ), Rmin( DBL_MAX )
00137         {
00138         }
00139         SplitData( const SplitData& f )
00140             : dim( f.dim ), nl( f.nl ), nr( f.nr ), split( f.split ), Lmax( f.Lmax ), Rmin( f.Rmin ),
00141               boundingBox( f.boundingBox ), leftBox( f.leftBox ), rightBox( f.rightBox )
00142         {
00143         }
00144         unsigned int dim, nl, nr;
00145         double split;
00146         double Lmax, Rmin;
00147         BoundBox boundingBox, leftBox, rightBox;
00148         SplitData& operator=( const SplitData& f )
00149         {
00150             dim         = f.dim;
00151             nl          = f.nl;
00152             nr          = f.nr;
00153             split       = f.split;
00154             Lmax        = f.Lmax;
00155             Rmin        = f.Rmin;
00156             boundingBox = f.boundingBox;
00157             leftBox     = f.leftBox;
00158             rightBox    = f.rightBox;
00159             return *this;
00160         }
00161     };  // SplitData
00162 
00163     class Split_comparator
00164     {
00165         // deprecation of binary_function
00166         typedef SplitData first_argument_type;
00167         typedef SplitData second_argument_type;
00168         typedef bool result_type;
00169 
00170         inline double objective( const SplitData& a ) const
00171         {
00172             return a.Lmax * a.nl - a.Rmin * a.nr;
00173         }
00174 
00175       public:
00176         bool operator()( const SplitData& a, const SplitData& b ) const
00177         {
00178             return objective( a ) < objective( b );
00179         }
00180     };  // Split_comparator
00181 
00182     class HandleData_comparator
00183     {
00184       // deprecation of binary_function
00185       typedef HandleData first_argument_type;
00186       typedef HandleData second_argument_type;
00187       typedef bool result_type;
00188         
00189       public:
00190         bool operator()( const HandleData& a, const HandleData& b )
00191         {
00192             return a.myDim < b.myDim || ( a.myDim == b.myDim && a.myHandle < b.myHandle );
00193         }
00194     };  // Iterator_comparator
00195 
00196     class Bucket
00197     {
00198       public:
00199         Bucket() : mySize( 0 ) {}
00200         Bucket( const Bucket& f ) : mySize( f.mySize ), boundingBox( f.boundingBox ) {}
00201         Bucket( const unsigned int sz ) : mySize( sz ) {}
00202         static unsigned int bucket_index( int num_splits, const BoundBox& box, const BoundBox& interval,
00203                                           const unsigned int dim );
00204         unsigned int mySize;
00205         BoundBox boundingBox;
00206         Bucket& operator=( const Bucket& f )
00207         {
00208             boundingBox = f.boundingBox;
00209             mySize      = f.mySize;
00210             return *this;
00211         }
00212     };  // Bucket
00213 
00214     class Node
00215     {
00216       public:
00217         HandleDataVec entities;
00218         unsigned int dim, child;
00219         double Lmax, Rmin;
00220         BoundBox box;
00221         Node() : dim( UINT_MAX ), child( UINT_MAX ), Lmax( -DBL_MAX ), Rmin( DBL_MAX ) {}
00222         Node& operator=( const Node& f )
00223         {
00224             dim      = f.dim;
00225             child    = f.child;
00226             Lmax     = f.Lmax;
00227             Rmin     = f.Rmin;
00228             entities = f.entities;
00229             return *this;
00230         }
00231     };  // Node
00232 
00233     class TreeNode
00234     {
00235       public:
00236         unsigned int dim, child;
00237         double Lmax, Rmin;
00238         BoundBox box;
00239         TreeNode( int dm, int chld, double lmx, double rmn, BoundBox& bx )
00240             : dim( dm ), child( chld ), Lmax( lmx ), Rmin( rmn ), box( bx )
00241         {
00242         }
00243         TreeNode& operator=( const TreeNode& f )
00244         {
00245             dim   = f.dim;
00246             child = f.child;
00247             Lmax  = f.Lmax;
00248             Rmin  = f.Rmin;
00249             return *this;
00250         }
00251     };  // TreeNode
00252 
00253     void establish_buckets( HandleDataVec::const_iterator begin, HandleDataVec::const_iterator end,
00254                             const BoundBox& interval, std::vector< std::vector< Bucket > >& buckets ) const;
00255 
00256     unsigned int set_interval( BoundBox& interval, std::vector< Bucket >::const_iterator begin,
00257                                std::vector< Bucket >::const_iterator end ) const;
00258 
00259     void initialize_splits( std::vector< std::vector< SplitData > >& splits,
00260                             const std::vector< std::vector< Bucket > >& buckets, const SplitData& data ) const;
00261 
00262     void order_elements( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const;
00263 
00264     void median_order( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const;
00265 
00266     void choose_best_split( const std::vector< std::vector< SplitData > >& splits, SplitData& data ) const;
00267 
00268     void find_split( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const;
00269 
00270     ErrorCode find_point( const std::vector< double >& point, const unsigned int& index, const double iter_tol,
00271                           const double inside_tol, std::pair< EntityHandle, CartVect >& result );
00272 
00273     EntityHandle bruteforce_find( const double* point, const double iter_tol = 1.0e-10,
00274                                   const double inside_tol = 1.0e-6 );
00275 
00276     int local_build_tree( std::vector< Node >& tree_nodes, HandleDataVec::iterator begin, HandleDataVec::iterator end,
00277                           const int index, const BoundBox& box, const int depth = 0 );
00278 
00279     // builds up vector of HandleData, which caches elements' bounding boxes
00280     ErrorCode construct_element_vec( std::vector< HandleData >& handle_data_vec, const Range& elements,
00281                                      BoundBox& bounding_box );
00282 
00283     // convert the std::vector<Node> to myTree and a bunch of entity sets
00284     ErrorCode convert_tree( std::vector< Node >& tree_nodes );
00285 
00286     // print tree nodes
00287     ErrorCode print_nodes( std::vector< Node >& nodes );
00288 
00289     Range entityHandles;
00290     std::vector< TreeNode > myTree;
00291     int splitsPerDir;
00292     EntityHandle startSetHandle;
00293     static MOAB_EXPORT const char* treeName;
00294 };  // class Bvh_tree
00295 
00296 inline unsigned int BVHTree::Bucket::bucket_index( int num_splits, const BoundBox& box, const BoundBox& interval,
00297                                                    const unsigned int dim )
00298 {
00299     // see FastMemoryEfficientCellLocationinUnstructuredGridsForVisualization.pdf
00300     // around page 9
00301 
00302     // Paper arithmetic is over-optimized.. this is safer.
00303     const double min    = interval.bMin[dim];
00304     const double length = ( interval.bMax[dim] - min ) / ( num_splits + 1 );
00305     const double center = ( ( box.bMax[dim] + box.bMin[dim] ) / 2.0 ) - min;
00306 #ifndef NDEBUG
00307 #ifdef BVH_SHOW_INDEX
00308     std::cout << "[" << min << " , " << interval.max[dim] << " ]" << std::endl;
00309     std::cout << "[" << box.bMin[dim] << " , " << box.bMax[dim] << " ]" << std::endl;
00310     std::cout << "Length of bucket" << length << std::endl;
00311     std::cout << "Center: " << ( box.bMax[dim] + box.bMin[dim] ) / 2.0 << std::endl;
00312     std::cout << "Distance of center from min:  " << center << std::endl;
00313     std::cout << "ratio: " << center / length << std::endl;
00314     std::cout << "index: " << std::ceil( center / length ) - 1 << std::endl;
00315 #endif
00316 #endif
00317     unsigned int cl = std::ceil( center / length );
00318     return ( cl > 0 ? cl - 1 : 0 );
00319 }
00320 
00321 inline BVHTree::BVHTree( Interface* impl ) : Tree( impl ), splitsPerDir( 3 ), startSetHandle( 0 )
00322 {
00323     boxTagName = treeName;
00324 }
00325 
00326 inline unsigned int BVHTree::set_interval( BoundBox& interval, std::vector< Bucket >::const_iterator begin,
00327                                            std::vector< Bucket >::const_iterator end ) const
00328 {
00329     bool first         = true;
00330     unsigned int count = 0;
00331     for( std::vector< Bucket >::const_iterator b = begin; b != end; ++b )
00332     {
00333         const BoundBox& box = b->boundingBox;
00334         count += b->mySize;
00335         if( b->mySize != 0 )
00336         {
00337             if( first )
00338             {
00339                 interval = box;
00340                 first    = false;
00341             }
00342             else
00343                 interval.update( box );
00344         }
00345     }
00346     return count;
00347 }
00348 
00349 inline void BVHTree::order_elements( HandleDataVec::iterator& begin, HandleDataVec::iterator& end,
00350                                      SplitData& data ) const
00351 {
00352     for( HandleDataVec::iterator i = begin; i != end; ++i )
00353     {
00354         const int index = Bucket::bucket_index( splitsPerDir, i->myBox, data.boundingBox, data.dim );
00355         i->myDim        = ( index <= data.split ) ? 0 : 1;
00356     }
00357     std::sort( begin, end, HandleData_comparator() );
00358 }
00359 
00360 inline void BVHTree::choose_best_split( const std::vector< std::vector< SplitData > >& splits, SplitData& data ) const
00361 {
00362     std::vector< SplitData > best_splits;
00363     for( std::vector< std::vector< SplitData > >::const_iterator i = splits.begin(); i != splits.end(); ++i )
00364     {
00365         std::vector< SplitData >::const_iterator j =
00366             std::min_element( ( *i ).begin(), ( *i ).end(), Split_comparator() );
00367         best_splits.push_back( *j );
00368     }
00369     data = *std::min_element( best_splits.begin(), best_splits.end(), Split_comparator() );
00370 }
00371 
00372 inline ErrorCode BVHTree::construct_element_vec( std::vector< HandleData >& handle_data_vec, const Range& elements,
00373                                                  BoundBox& bounding_box )
00374 {
00375     std::vector< double > coordinate( 3 * CN::MAX_NODES_PER_ELEMENT );
00376     int num_conn;
00377     ErrorCode rval = MB_SUCCESS;
00378     std::vector< EntityHandle > storage;
00379     for( Range::iterator i = elements.begin(); i != elements.end(); ++i )
00380     {
00381         // TODO: not generic enough. Why dim != 3
00382         // Commence un-necessary deep copying.
00383         const EntityHandle* connect;
00384         rval = mbImpl->get_connectivity( *i, connect, num_conn, false, &storage );
00385         if( MB_SUCCESS != rval ) return rval;
00386         rval = mbImpl->get_coords( connect, num_conn, &coordinate[0] );
00387         if( MB_SUCCESS != rval ) return rval;
00388         BoundBox box;
00389         for( int j = 0; j < num_conn; j++ )
00390             box.update( &coordinate[3 * j] );
00391         if( i == elements.begin() )
00392             bounding_box = box;
00393         else
00394             bounding_box.update( box );
00395         handle_data_vec.push_back( HandleData( *i, box, 0.0 ) );
00396     }
00397 
00398     return rval;
00399 }
00400 
00401 inline ErrorCode BVHTree::reset_tree()
00402 {
00403     return delete_tree_sets();
00404 }
00405 
00406 }  // namespace moab
00407 
00408 #endif  // BVH_TREE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines