LCOV - code coverage report
Current view: top level - src/moab - BVHTree.hpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 93 93 100.0 %
Date: 2020-12-16 07:07:30 Functions: 26 26 100.0 %
Branches: 76 130 58.5 %

           Branch data     Line data    Source code
       1                 :            : /**\file BVHTree.hpp
       2                 :            :  * \class moab::BVHTree
       3                 :            :  * \brief Bounding Volume Hierarchy (sorta like a tree), for sorting and searching entities
       4                 :            :  * spatially
       5                 :            :  */
       6                 :            : 
       7                 :            : #ifndef BVH_TREE_HPP
       8                 :            : #define BVH_TREE_HPP
       9                 :            : 
      10                 :            : #include "moab/Interface.hpp"
      11                 :            : #include "moab/CartVect.hpp"
      12                 :            : #include "moab/BoundBox.hpp"
      13                 :            : #include "moab/Tree.hpp"
      14                 :            : #include "moab/Range.hpp"
      15                 :            : #include "moab/CN.hpp"
      16                 :            : 
      17                 :            : #include <vector>
      18                 :            : #include <cfloat>
      19                 :            : #include <climits>
      20                 :            : #include <map>
      21                 :            : #include <set>
      22                 :            : #include <iostream>
      23                 :            : 
      24                 :            : #include "moab/win32_config.h"
      25                 :            : 
      26                 :            : namespace moab
      27                 :            : {
      28                 :            : 
      29                 :            : class ElemEvaluator;
      30                 :            : 
      31                 :            : class BVHTree : public Tree
      32                 :            : {
      33                 :            :   public:
      34                 :            :     BVHTree( Interface* impl );
      35                 :            : 
      36                 :          1 :     ~BVHTree()
      37                 :          1 :     {
      38                 :          1 :         reset_tree();
      39         [ -  + ]:          1 :     }
      40                 :            : 
      41                 :            :     /** \brief Destroy the tree maintained by this object, optionally checking we have the right
      42                 :            :      * root. \param root If non-NULL, check that this is the root, return failure if not
      43                 :            :      */
      44                 :            :     virtual ErrorCode reset_tree();
      45                 :            : 
      46                 :            :     virtual ErrorCode parse_options( FileOptions& opts );
      47                 :            : 
      48                 :            :     /** \brief Get bounding box for tree below tree_node, or entire tree
      49                 :            :      * If no tree has been built yet, returns +/- DBL_MAX for all dimensions.  Note for some tree
      50                 :            :      * types, boxes are not available for non-root nodes, and this function will return failure if
      51                 :            :      * non-root is passed in \param box The box for this tree \param tree_node If non-NULL, node for
      52                 :            :      * which box is requested, tree root if NULL \return Only returns error on fatal condition
      53                 :            :      */
      54                 :            :     virtual ErrorCode get_bounding_box( BoundBox& box, EntityHandle* tree_node = NULL ) const;
      55                 :            : 
      56                 :            :     /** Build the tree
      57                 :            :      * Build a tree with the entities input.  If a non-NULL tree_root_set pointer is input,
      58                 :            :      * use the pointed-to set as the root of this tree (*tree_root_set!=0) otherwise construct
      59                 :            :      * a new root set and pass its handle back in *tree_root_set.  Options vary by tree type;
      60                 :            :      * see Tree.hpp for common options; options specific to AdaptiveKDTree:
      61                 :            :      * SPLITS_PER_DIR: number of candidate splits considered per direction; default = 3
      62                 :            :      * CANDIDATE_PLANE_SET: method used to decide split planes; see CandidatePlaneSet enum (below)
      63                 :            :      *          for possible values; default = 1 (SUBDIVISION_SNAP)
      64                 :            :      * \param entities Entities with which to build the tree
      65                 :            :      * \param tree_root Root set for tree (see function description)
      66                 :            :      * \param opts Options for tree (see function description)
      67                 :            :      * \return Error is returned only on build failure
      68                 :            :      */
      69                 :            :     virtual ErrorCode build_tree( const Range& entities, EntityHandle* tree_root_set = NULL,
      70                 :            :                                   FileOptions* options = NULL );
      71                 :            : 
      72                 :            :     /** \brief Get leaf containing input position.
      73                 :            :      *
      74                 :            :      * Does not take into account global bounding box of tree.
      75                 :            :      * - Therefore there is always one leaf containing the point.
      76                 :            :      * - If caller wants to account for global bounding box, then
      77                 :            :      * caller can test against that box and not call this method
      78                 :            :      * at all if the point is outside the box, as there is no leaf
      79                 :            :      * containing the point in that case.
      80                 :            :      * \param point Point to be located in tree
      81                 :            :      * \param leaf_out Leaf containing point
      82                 :            :      * \param iter_tol Tolerance for convergence of point search
      83                 :            :      * \param inside_tol Tolerance for inside element calculation
      84                 :            :      * \param multiple_leaves Some tree types can have multiple leaves containing a point;
      85                 :            :      *          if non-NULL, this parameter is returned true if multiple leaves contain
      86                 :            :      *          the input point
      87                 :            :      * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
      88                 :            :      * \return Non-success returned only in case of failure; not-found indicated by leaf_out=0
      89                 :            :      */
      90                 :            :     virtual ErrorCode point_search( const double* point, EntityHandle& leaf_out, const double iter_tol = 1.0e-10,
      91                 :            :                                     const double inside_tol = 1.0e-6, bool* multiple_leaves = NULL,
      92                 :            :                                     EntityHandle* start_node = NULL, CartVect* params = NULL );
      93                 :            : 
      94                 :            :     /** \brief Find all leaves within a given distance from point
      95                 :            :      * If dists_out input non-NULL, also returns distances from each leaf; if
      96                 :            :      * point i is inside leaf, 0 is given as dists_out[i].
      97                 :            :      * If params_out is non-NULL and myEval is non-NULL, will evaluate individual entities
      98                 :            :      * in tree nodes and return containing entities in leaves_out.  In those cases, if params_out
      99                 :            :      * is also non-NULL, will return parameters in those elements in that vector.
     100                 :            :      * \param from_point Point to be located in tree
     101                 :            :      * \param distance Distance within which to query
     102                 :            :      * \param result_list Leaves within distance or containing point
     103                 :            :      * \param iter_tol Tolerance for convergence of point search
     104                 :            :      * \param inside_tol Tolerance for inside element calculation
     105                 :            :      * \param result_dists If non-NULL, will contain distsances to leaves
     106                 :            :      * \param result_params If non-NULL, will contain parameters of the point in the ents in
     107                 :            :      * leaves_out \param tree_root Start from this tree node (non-NULL) instead of tree root (NULL)
     108                 :            :      */
     109                 :            :     virtual ErrorCode distance_search( const double from_point[3], const double distance,
     110                 :            :                                        std::vector< EntityHandle >& result_list, const double iter_tol = 1.0e-10,
     111                 :            :                                        const double inside_tol = 1.0e-6, std::vector< double >* result_dists = NULL,
     112                 :            :                                        std::vector< CartVect >* result_params = NULL, EntityHandle* tree_root = NULL );
     113                 :            : 
     114                 :            :     //! print various things about this tree
     115                 :            :     virtual ErrorCode print();
     116                 :            : 
     117                 :            :   private:
     118                 :            :     // don't allow copy constructor, too complicated
     119                 :            :     BVHTree( const BVHTree& s );
     120                 :            : 
     121                 :      84678 :     class HandleData
     122                 :            :     {
     123                 :            :       public:
     124                 :        729 :         HandleData( EntityHandle h, const BoundBox& bx, const double dp ) : myHandle( h ), myBox( bx ), myDim( dp ) {}
     125                 :            :         HandleData() : myHandle( 0 ), myDim( -1 ) {}
     126                 :            :         EntityHandle myHandle;
     127                 :            :         BoundBox myBox;
     128                 :            :         double myDim;
     129                 :            :     };
     130                 :            :     typedef std::vector< HandleData > HandleDataVec;
     131                 :            : 
     132                 :       7144 :     class SplitData
     133                 :            :     {
     134                 :            :       public:
     135                 :        188 :         SplitData()
     136 [ +  - ][ +  - ]:        188 :             : dim( UINT_MAX ), nl( UINT_MAX ), nr( UINT_MAX ), split( DBL_MAX ), Lmax( -DBL_MAX ), Rmin( DBL_MAX )
     137                 :            :         {
     138                 :        188 :         }
     139                 :       3384 :         SplitData( const SplitData& f )
     140                 :            :             : dim( f.dim ), nl( f.nl ), nr( f.nr ), split( f.split ), Lmax( f.Lmax ), Rmin( f.Rmin ),
     141                 :       3384 :               boundingBox( f.boundingBox ), leftBox( f.leftBox ), rightBox( f.rightBox )
     142                 :            :         {
     143                 :       3384 :         }
     144                 :            :         unsigned int dim, nl, nr;
     145                 :            :         double split;
     146                 :            :         double Lmax, Rmin;
     147                 :            :         BoundBox boundingBox, leftBox, rightBox;
     148                 :        188 :         SplitData& operator=( const SplitData& f )
     149                 :            :         {
     150                 :        188 :             dim         = f.dim;
     151                 :        188 :             nl          = f.nl;
     152                 :        188 :             nr          = f.nr;
     153                 :        188 :             split       = f.split;
     154                 :        188 :             Lmax        = f.Lmax;
     155                 :        188 :             Rmin        = f.Rmin;
     156                 :        188 :             boundingBox = f.boundingBox;
     157                 :        188 :             leftBox     = f.leftBox;
     158                 :        188 :             rightBox    = f.rightBox;
     159                 :        188 :             return *this;
     160                 :            :         }
     161                 :            :     };  // SplitData
     162                 :            : 
     163                 :            :     class Split_comparator : public std::binary_function< SplitData, SplitData, bool >
     164                 :            :     {
     165                 :       3008 :         inline double objective( const SplitData& a ) const
     166                 :            :         {
     167                 :       3008 :             return a.Lmax * a.nl - a.Rmin * a.nr;
     168                 :            :         }
     169                 :            : 
     170                 :            :       public:
     171                 :       1504 :         bool operator()( const SplitData& a, const SplitData& b ) const
     172                 :            :         {
     173                 :       1504 :             return objective( a ) < objective( b );
     174                 :            :         }
     175                 :            :     };  // Split_comparator
     176                 :            : 
     177                 :            :     class HandleData_comparator : public std::binary_function< HandleData, HandleData, bool >
     178                 :            :     {
     179                 :            :       public:
     180                 :      46484 :         bool operator()( const HandleData& a, const HandleData& b )
     181                 :            :         {
     182 [ +  + ][ +  + ]:      46484 :             return a.myDim < b.myDim || ( a.myDim == b.myDim && a.myHandle < b.myHandle );
                 [ +  + ]
     183                 :            :         }
     184                 :            :     };  // Iterator_comparator
     185                 :            : 
     186                 :       6016 :     class Bucket
     187                 :            :     {
     188                 :            :       public:
     189                 :       1504 :         Bucket() : mySize( 0 ) {}
     190                 :       2256 :         Bucket( const Bucket& f ) : mySize( f.mySize ), boundingBox( f.boundingBox ) {}
     191                 :            :         Bucket( const unsigned int sz ) : mySize( sz ) {}
     192                 :            :         static unsigned int bucket_index( int num_splits, const BoundBox& box, const BoundBox& interval,
     193                 :            :                                           const unsigned int dim );
     194                 :            :         unsigned int mySize;
     195                 :            :         BoundBox boundingBox;
     196                 :            :         Bucket& operator=( const Bucket& f )
     197                 :            :         {
     198                 :            :             boundingBox = f.boundingBox;
     199                 :            :             mySize      = f.mySize;
     200                 :            :             return *this;
     201                 :            :         }
     202                 :            :     };  // Bucket
     203                 :            : 
     204                 :       3714 :     class Node
     205                 :            :     {
     206                 :            :       public:
     207                 :            :         HandleDataVec entities;
     208                 :            :         unsigned int dim, child;
     209                 :            :         double Lmax, Rmin;
     210                 :            :         BoundBox box;
     211         [ +  - ]:        377 :         Node() : dim( UINT_MAX ), child( UINT_MAX ), Lmax( -DBL_MAX ), Rmin( DBL_MAX ) {}
     212                 :            :         Node& operator=( const Node& f )
     213                 :            :         {
     214                 :            :             dim      = f.dim;
     215                 :            :             child    = f.child;
     216                 :            :             Lmax     = f.Lmax;
     217                 :            :             Rmin     = f.Rmin;
     218                 :            :             entities = f.entities;
     219                 :            :             return *this;
     220                 :            :         }
     221                 :            :     };  // Node
     222                 :            : 
     223                 :       1508 :     class TreeNode
     224                 :            :     {
     225                 :            :       public:
     226                 :            :         unsigned int dim, child;
     227                 :            :         double Lmax, Rmin;
     228                 :            :         BoundBox box;
     229                 :        377 :         TreeNode( int dm, int chld, double lmx, double rmn, BoundBox& bx )
     230                 :        377 :             : dim( dm ), child( chld ), Lmax( lmx ), Rmin( rmn ), box( bx )
     231                 :            :         {
     232                 :        377 :         }
     233                 :            :         TreeNode& operator=( const TreeNode& f )
     234                 :            :         {
     235                 :            :             dim   = f.dim;
     236                 :            :             child = f.child;
     237                 :            :             Lmax  = f.Lmax;
     238                 :            :             Rmin  = f.Rmin;
     239                 :            :             return *this;
     240                 :            :         }
     241                 :            :     };  // TreeNode
     242                 :            : 
     243                 :            :     void establish_buckets( HandleDataVec::const_iterator begin, HandleDataVec::const_iterator end,
     244                 :            :                             const BoundBox& interval, std::vector< std::vector< Bucket > >& buckets ) const;
     245                 :            : 
     246                 :            :     unsigned int set_interval( BoundBox& interval, std::vector< Bucket >::const_iterator begin,
     247                 :            :                                std::vector< Bucket >::const_iterator end ) const;
     248                 :            : 
     249                 :            :     void initialize_splits( std::vector< std::vector< SplitData > >& splits,
     250                 :            :                             const std::vector< std::vector< Bucket > >& buckets, const SplitData& data ) const;
     251                 :            : 
     252                 :            :     void order_elements( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const;
     253                 :            : 
     254                 :            :     void median_order( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const;
     255                 :            : 
     256                 :            :     void choose_best_split( const std::vector< std::vector< SplitData > >& splits, SplitData& data ) const;
     257                 :            : 
     258                 :            :     void find_split( HandleDataVec::iterator& begin, HandleDataVec::iterator& end, SplitData& data ) const;
     259                 :            : 
     260                 :            :     ErrorCode find_point( const std::vector< double >& point, const unsigned int& index, const double iter_tol,
     261                 :            :                           const double inside_tol, std::pair< EntityHandle, CartVect >& result );
     262                 :            : 
     263                 :            :     EntityHandle bruteforce_find( const double* point, const double iter_tol = 1.0e-10,
     264                 :            :                                   const double inside_tol = 1.0e-6 );
     265                 :            : 
     266                 :            :     int local_build_tree( std::vector< Node >& tree_nodes, HandleDataVec::iterator begin, HandleDataVec::iterator end,
     267                 :            :                           const int index, const BoundBox& box, const int depth = 0 );
     268                 :            : 
     269                 :            :     // builds up vector of HandleData, which caches elements' bounding boxes
     270                 :            :     ErrorCode construct_element_vec( std::vector< HandleData >& handle_data_vec, const Range& elements,
     271                 :            :                                      BoundBox& bounding_box );
     272                 :            : 
     273                 :            :     // convert the std::vector<Node> to myTree and a bunch of entity sets
     274                 :            :     ErrorCode convert_tree( std::vector< Node >& tree_nodes );
     275                 :            : 
     276                 :            :     // print tree nodes
     277                 :            :     ErrorCode print_nodes( std::vector< Node >& nodes );
     278                 :            : 
     279                 :            :     Range entityHandles;
     280                 :            :     std::vector< TreeNode > myTree;
     281                 :            :     int splitsPerDir;
     282                 :            :     EntityHandle startSetHandle;
     283                 :            :     static MOAB_EXPORT const char* treeName;
     284                 :            : };  // class Bvh_tree
     285                 :            : 
     286                 :      44052 : inline unsigned int BVHTree::Bucket::bucket_index( int num_splits, const BoundBox& box, const BoundBox& interval,
     287                 :            :                                                    const unsigned int dim )
     288                 :            : {
     289                 :            :     // see FastMemoryEfficientCellLocationinUnstructuredGridsForVisualization.pdf
     290                 :            :     // around page 9
     291                 :            : 
     292                 :            :     // Paper arithmetic is over-optimized.. this is safer.
     293                 :      44052 :     const double min    = interval.bMin[dim];
     294                 :      44052 :     const double length = ( interval.bMax[dim] - min ) / ( num_splits + 1 );
     295                 :      44052 :     const double center = ( ( box.bMax[dim] + box.bMin[dim] ) / 2.0 ) - min;
     296                 :            : #ifndef NDEBUG
     297                 :            : #ifdef BVH_SHOW_INDEX
     298                 :            :     std::cout << "[" << min << " , " << interval.max[dim] << " ]" << std::endl;
     299                 :            :     std::cout << "[" << box.bMin[dim] << " , " << box.bMax[dim] << " ]" << std::endl;
     300                 :            :     std::cout << "Length of bucket" << length << std::endl;
     301                 :            :     std::cout << "Center: " << ( box.bMax[dim] + box.bMin[dim] ) / 2.0 << std::endl;
     302                 :            :     std::cout << "Distance of center from min:  " << center << std::endl;
     303                 :            :     std::cout << "ratio: " << center / length << std::endl;
     304                 :            :     std::cout << "index: " << std::ceil( center / length ) - 1 << std::endl;
     305                 :            : #endif
     306                 :            : #endif
     307                 :      44052 :     unsigned int cl = std::ceil( center / length );
     308         [ +  - ]:      44052 :     return ( cl > 0 ? cl - 1 : 0 );
     309                 :            : }
     310                 :            : 
     311 [ +  - ][ +  - ]:          2 : inline BVHTree::BVHTree( Interface* impl ) : Tree( impl ), splitsPerDir( 3 ), startSetHandle( 0 )
     312                 :            : {
     313         [ +  - ]:          1 :     boxTagName = treeName;
     314                 :          1 : }
     315                 :            : 
     316                 :       3384 : inline unsigned int BVHTree::set_interval( BoundBox& interval, std::vector< Bucket >::const_iterator begin,
     317                 :            :                                            std::vector< Bucket >::const_iterator end ) const
     318                 :            : {
     319                 :       3384 :     bool first         = true;
     320                 :       3384 :     unsigned int count = 0;
     321 [ +  - ][ +  - ]:      10152 :     for( std::vector< Bucket >::const_iterator b = begin; b != end; ++b )
                 [ +  + ]
     322                 :            :     {
     323         [ +  - ]:       6768 :         const BoundBox& box = b->boundingBox;
     324         [ +  - ]:       6768 :         count += b->mySize;
     325 [ +  - ][ +  + ]:       6768 :         if( b->mySize != 0 )
     326                 :            :         {
     327         [ +  + ]:       4227 :             if( first )
     328                 :            :             {
     329         [ +  - ]:       2811 :                 interval = box;
     330                 :       2811 :                 first    = false;
     331                 :            :             }
     332                 :            :             else
     333         [ +  - ]:       4227 :                 interval.update( box );
     334                 :            :         }
     335                 :            :     }
     336                 :       3384 :     return count;
     337                 :            : }
     338                 :            : 
     339                 :         96 : inline void BVHTree::order_elements( HandleDataVec::iterator& begin, HandleDataVec::iterator& end,
     340                 :            :                                      SplitData& data ) const
     341                 :            : {
     342 [ +  - ][ +  - ]:       5160 :     for( HandleDataVec::iterator i = begin; i != end; ++i )
                 [ +  + ]
     343                 :            :     {
     344 [ +  - ][ +  - ]:       5064 :         const int index = Bucket::bucket_index( splitsPerDir, i->myBox, data.boundingBox, data.dim );
     345         [ +  - ]:       5064 :         i->myDim        = ( index <= data.split ) ? 0 : 1;
     346                 :            :     }
     347         [ +  - ]:         96 :     std::sort( begin, end, HandleData_comparator() );
     348                 :         96 : }
     349                 :            : 
     350                 :        188 : inline void BVHTree::choose_best_split( const std::vector< std::vector< SplitData > >& splits, SplitData& data ) const
     351                 :            : {
     352         [ +  - ]:        188 :     std::vector< SplitData > best_splits;
     353 [ +  - ][ +  - ]:        752 :     for( std::vector< std::vector< SplitData > >::const_iterator i = splits.begin(); i != splits.end(); ++i )
                 [ +  + ]
     354                 :            :     {
     355                 :            :         std::vector< SplitData >::const_iterator j =
     356 [ +  - ][ +  - ]:        564 :             std::min_element( ( *i ).begin(), ( *i ).end(), Split_comparator() );
                 [ +  - ]
     357 [ +  - ][ +  - ]:        564 :         best_splits.push_back( *j );
     358                 :            :     }
     359 [ +  - ][ +  - ]:        188 :     data = *std::min_element( best_splits.begin(), best_splits.end(), Split_comparator() );
                 [ +  - ]
     360                 :        188 : }
     361                 :            : 
     362                 :          1 : inline ErrorCode BVHTree::construct_element_vec( std::vector< HandleData >& handle_data_vec, const Range& elements,
     363                 :            :                                                  BoundBox& bounding_box )
     364                 :            : {
     365         [ +  - ]:          1 :     std::vector< double > coordinate( 3 * CN::MAX_NODES_PER_ELEMENT );
     366                 :            :     int num_conn;
     367                 :          1 :     ErrorCode rval = MB_SUCCESS;
     368         [ +  - ]:          2 :     std::vector< EntityHandle > storage;
     369 [ +  - ][ +  - ]:        730 :     for( Range::iterator i = elements.begin(); i != elements.end(); ++i )
         [ +  - ][ +  - ]
                 [ +  + ]
     370                 :            :     {
     371                 :            :         // TODO: not generic enough. Why dim != 3
     372                 :            :         // Commence un-necessary deep copying.
     373                 :            :         const EntityHandle* connect;
     374 [ +  - ][ +  - ]:        729 :         rval = mbImpl->get_connectivity( *i, connect, num_conn, false, &storage );
     375         [ -  + ]:        729 :         if( MB_SUCCESS != rval ) return rval;
     376 [ +  - ][ +  - ]:        729 :         rval = mbImpl->get_coords( connect, num_conn, &coordinate[0] );
     377         [ -  + ]:        729 :         if( MB_SUCCESS != rval ) return rval;
     378         [ +  - ]:        729 :         BoundBox box;
     379         [ +  + ]:       6561 :         for( int j = 0; j < num_conn; j++ )
     380 [ +  - ][ +  - ]:       5832 :             box.update( &coordinate[3 * j] );
     381 [ +  - ][ +  - ]:        729 :         if( i == elements.begin() )
                 [ +  + ]
     382         [ +  - ]:          1 :             bounding_box = box;
     383                 :            :         else
     384         [ +  - ]:        728 :             bounding_box.update( box );
     385 [ +  - ][ +  - ]:        729 :         handle_data_vec.push_back( HandleData( *i, box, 0.0 ) );
                 [ +  - ]
     386                 :        729 :     }
     387                 :            : 
     388                 :          2 :     return rval;
     389                 :            : }
     390                 :            : 
     391                 :          1 : inline ErrorCode BVHTree::reset_tree()
     392                 :            : {
     393                 :          1 :     return delete_tree_sets();
     394                 :            : }
     395                 :            : 
     396                 :            : }  // namespace moab
     397                 :            : 
     398                 :            : #endif  // BVH_TREE_HPP

Generated by: LCOV version 1.11