Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
AdaptiveKDTree.hpp
Go to the documentation of this file.
00001 /**\file AdaptiveKDTree.hpp
00002  * \class moab::AdaptiveKDTree
00003  * \brief Adaptive KD tree, for sorting and searching entities spatially
00004  */
00005 
00006 #ifndef MOAB_ADAPTIVE_KD_TREE_HPP
00007 #define MOAB_ADAPTIVE_KD_TREE_HPP
00008 
00009 #include "moab/Types.hpp"
00010 #include "moab/Tree.hpp"
00011 
00012 #include <string>
00013 #include <vector>
00014 #include <cmath>
00015 
00016 namespace moab
00017 {
00018 
00019 class AdaptiveKDTreeIter;
00020 class Interface;
00021 class Range;
00022 
00023 class AdaptiveKDTree : public Tree
00024 {
00025   public:
00026     AdaptiveKDTree( Interface* iface );
00027 
00028     /** \brief Constructor (build the tree on construction)
00029      * Construct a tree object, and build the tree with entities input.  See comments
00030      * for build_tree() for detailed description of arguments.
00031      * \param iface MOAB instance
00032      * \param entities Entities to build tree around
00033      * \param tree_root Root set for tree (see function description)
00034      * \param opts Options for tree (see function description)
00035      */
00036     AdaptiveKDTree( Interface* iface,
00037                     const Range& entities,
00038                     EntityHandle* tree_root_set = NULL,
00039                     FileOptions* opts           = NULL );
00040 
00041     ~AdaptiveKDTree();
00042 
00043     /** \brief Parse options for tree creation
00044      * \param options Options passed in by application
00045      * \return Failure is returned if any options were passed in and not interpreted; could mean
00046      * inappropriate options for a particular tree type
00047      */
00048     ErrorCode parse_options( FileOptions& options );
00049 
00050     /** Build the tree
00051      * Build a tree with the entities input.  If a non-NULL tree_root_set pointer is input,
00052      * use the pointed-to set as the root of this tree (*tree_root_set!=0) otherwise construct
00053      * a new root set and pass its handle back in *tree_root_set.  Options vary by tree type;
00054      * see Tree.hpp for common options; options specific to AdaptiveKDTree:
00055      * SPLITS_PER_DIR: number of candidate splits considered per direction; default = 3
00056      * PLANE_SET: method used to decide split planes; see CandidatePlaneSet enum (below)
00057      *          for possible values; default = 1 (SUBDIVISION_SNAP)
00058      * \param entities Entities with which to build the tree
00059      * \param tree_root Root set for tree (see function description)
00060      * \param opts Options for tree (see function description)
00061      * \return Error is returned only on build failure
00062      */
00063     virtual ErrorCode build_tree( const Range& entities,
00064                                   EntityHandle* tree_root_set = NULL,
00065                                   FileOptions* options        = NULL );
00066 
00067     //! Reset the tree, optionally checking we have the right root
00068     virtual ErrorCode reset_tree();
00069 
00070     /** \brief Get leaf containing input position.
00071      *
00072      * Does not take into account global bounding box of tree.
00073      * - Therefore there is always one leaf containing the point.
00074      * - If caller wants to account for global bounding box, then
00075      * caller can test against that box and not call this method
00076      * at all if the point is outside the box, as there is no leaf
00077      * containing the point in that case.
00078      * \param point Point to be located in tree
00079      * \param leaf_out Leaf containing point
00080      * \param iter_tol Tolerance for convergence of point search
00081      * \param inside_tol Tolerance for inside element calculation
00082      * \param multiple_leaves Some tree types can have multiple leaves containing a point;
00083      *          if non-NULL, this parameter is returned true if multiple leaves contain
00084      *          the input point
00085      * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
00086      * \return Non-success returned only in case of failure; not-found indicated by leaf_out=0
00087      */
00088     virtual ErrorCode point_search( const double* point,
00089                                     EntityHandle& leaf_out,
00090                                     const double iter_tol    = 1.0e-10,
00091                                     const double inside_tol  = 1.0e-6,
00092                                     bool* multiple_leaves    = NULL,
00093                                     EntityHandle* start_node = NULL,
00094                                     CartVect* params         = NULL );
00095 
00096     /** \brief Get leaf containing input position.
00097      *
00098      * Does not take into account global bounding box of tree.
00099      * - Therefore there is always one leaf containing the point.
00100      * - If caller wants to account for global bounding box, then
00101      * caller can test against that box and not call this method
00102      * at all if the point is outside the box, as there is no leaf
00103      * containing the point in that case.
00104      * \param point Point to be located in tree
00105      * \param leaf_it Iterator to leaf containing point
00106      * \param iter_tol Tolerance for convergence of point search
00107      * \param inside_tol Tolerance for inside element calculation
00108      * \param multiple_leaves Some tree types can have multiple leaves containing a point;
00109      *          if non-NULL, this parameter is returned true if multiple leaves contain
00110      *          the input point
00111      * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
00112      * \return Non-success returned only in case of failure; not-found indicated by leaf_out=0
00113      */
00114     ErrorCode point_search( const double* point,
00115                             AdaptiveKDTreeIter& leaf_it,
00116                             const double iter_tol    = 1.0e-10,
00117                             const double inside_tol  = 1.0e-6,
00118                             bool* multiple_leaves    = NULL,
00119                             EntityHandle* start_node = NULL );
00120 
00121     /** \brief Find all leaves within a given distance from point
00122      * If dists_out input non-NULL, also returns distances from each leaf; if
00123      * point i is inside leaf, 0 is given as dists_out[i].
00124      * If params_out is non-NULL and myEval is non-NULL, will evaluate individual entities
00125      * in tree nodes and return containing entities in leaves_out.  In those cases, if params_out
00126      * is also non-NULL, will return parameters in those elements in that vector.
00127      * \param point Point to be located in tree
00128      * \param distance Distance within which to query
00129      * \param leaves_out Leaves within distance or containing point
00130      * \param iter_tol Tolerance for convergence of point search
00131      * \param inside_tol Tolerance for inside element calculation
00132      * \param dists_out If non-NULL, will contain distsances to leaves
00133      * \param params_out If non-NULL, will contain parameters of the point in the ents in leaves_out
00134      * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
00135      */
00136     virtual ErrorCode distance_search( const double* point,
00137                                        const double distance,
00138                                        std::vector< EntityHandle >& leaves_out,
00139                                        const double iter_tol               = 1.0e-10,
00140                                        const double inside_tol             = 1.0e-6,
00141                                        std::vector< double >* dists_out    = NULL,
00142                                        std::vector< CartVect >* params_out = NULL,
00143                                        EntityHandle* start_node            = NULL );
00144 
00145     ErrorCode get_info( EntityHandle root, double min[3], double max[3], unsigned int& dep );
00146 
00147     //! Enumeriate split plane directions
00148     enum Axis
00149     {
00150         X = 0,
00151         Y = 1,
00152         Z = 2
00153     };
00154 
00155     //! Split plane
00156     struct Plane
00157     {
00158         double coord;  //!< Location of plane as coordinate on normal axis
00159         int norm;      //!< The principal axis that is the normal of the plane;
00160 
00161         /** return true if point is below/to the left of the split plane */
00162         bool left_side( const double point[3] )
00163         {
00164             return point[norm] < coord;
00165         }
00166         /** return true if point is above/to the right of the split plane */
00167         bool right_side( const double point[3] )
00168         {
00169             return point[norm] > coord;
00170         }
00171         /** return distance from point to plane */
00172         double distance( const double point[3] ) const
00173         {
00174             return fabs( point[norm] - coord );
00175         }
00176     };
00177 
00178     //! Get split plane for tree node
00179     ErrorCode get_split_plane( EntityHandle node, Plane& plane );
00180 
00181     //! Set split plane for tree node
00182     ErrorCode set_split_plane( EntityHandle node, const Plane& plane );
00183 
00184     //! Get iterator for tree
00185     ErrorCode get_tree_iterator( EntityHandle tree_root, AdaptiveKDTreeIter& result );
00186 
00187     //! Get iterator at right-most ('last') leaf.
00188     ErrorCode get_last_iterator( EntityHandle tree_root, AdaptiveKDTreeIter& result );
00189 
00190     //! Get iterator for tree or subtree
00191     ErrorCode get_sub_tree_iterator( EntityHandle tree_root,
00192                                      const double box_min[3],
00193                                      const double box_max[3],
00194                                      AdaptiveKDTreeIter& result );
00195 
00196     //! Split leaf of tree
00197     //! Updates iterator location to point to first new leaf node.
00198     ErrorCode split_leaf( AdaptiveKDTreeIter& leaf, Plane plane );
00199 
00200     //! Split leaf of tree
00201     //! Updates iterator location to point to first new leaf node.
00202     ErrorCode split_leaf( AdaptiveKDTreeIter& leaf, Plane plane, EntityHandle& left_child, EntityHandle& right_child );
00203     //! Split leaf of tree
00204     //! Updates iterator location to point to first new leaf node.
00205     ErrorCode split_leaf( AdaptiveKDTreeIter& leaf,
00206                           Plane plane,
00207                           const Range& left_entities,
00208                           const Range& right_entities );
00209 
00210     //! Split leaf of tree
00211     //! Updates iterator location to point to first new leaf node.
00212     ErrorCode split_leaf( AdaptiveKDTreeIter& leaf,
00213                           Plane plane,
00214                           const std::vector< EntityHandle >& left_entities,
00215                           const std::vector< EntityHandle >& right_entities );
00216 
00217     //! Merge the leaf pointed to by the current iterator with it's
00218     //! sibling.  If the sibling is not a leaf, multiple merges may
00219     //! be done.
00220     ErrorCode merge_leaf( AdaptiveKDTreeIter& iter );
00221 
00222     //! Find triangle closest to input position.
00223     //!\param from_coords  The input position to test against
00224     //!\param closest_point_out  The closest point on the set of triangles in the tree
00225     //!\param triangle_out The triangle closest to the input position
00226     ErrorCode closest_triangle( EntityHandle tree_root,
00227                                 const double from_coords[3],
00228                                 double closest_point_out[3],
00229                                 EntityHandle& triangle_out );
00230 
00231     ErrorCode sphere_intersect_triangles( EntityHandle tree_root,
00232                                           const double center[3],
00233                                           double radius,
00234                                           std::vector< EntityHandle >& triangles );
00235 
00236     ErrorCode ray_intersect_triangles( EntityHandle tree_root,
00237                                        const double tolerance,
00238                                        const double ray_unit_dir[3],
00239                                        const double ray_base_pt[3],
00240                                        std::vector< EntityHandle >& triangles_out,
00241                                        std::vector< double >& distance_out,
00242                                        int result_count_limit = 0,
00243                                        double distance_limit  = -1.0 );
00244 
00245     ErrorCode compute_depth( EntityHandle root, unsigned int& min_depth, unsigned int& max_depth );
00246 
00247     //! methods for selecting candidate split planes
00248     enum CandidatePlaneSet
00249     {
00250         //! Candidiate planes at evenly spaced intervals
00251         SUBDIVISION = 0,
00252         //! Like SUBDIVISION, except snap to closest vertex coordinate
00253         SUBDIVISION_SNAP,  // = 1
00254                            //! Median vertex coodinate values
00255         VERTEX_MEDIAN,     // = 2
00256                            //! Random sampling of vertex coordinate values
00257         VERTEX_SAMPLE      // = 3
00258     };
00259 
00260     //! print various things about this tree
00261     virtual ErrorCode print();
00262 
00263   private:
00264     friend class AdaptiveKDTreeIter;
00265 
00266     ErrorCode init();
00267 
00268     /**\brief find a triangle near the input point */
00269     ErrorCode find_close_triangle( EntityHandle root,
00270                                    const double from_point[3],
00271                                    double pt[3],
00272                                    EntityHandle& triangle );
00273 
00274     ErrorCode make_tag( Interface* iface,
00275                         std::string name,
00276                         TagType storage,
00277                         DataType type,
00278                         int count,
00279                         void* default_val,
00280                         Tag& tag_handle,
00281                         std::vector< Tag >& created_tags );
00282 
00283     ErrorCode intersect_children_with_elems( const Range& elems,
00284                                              AdaptiveKDTree::Plane plane,
00285                                              double eps,
00286                                              CartVect box_min,
00287                                              CartVect box_max,
00288                                              Range& left_tris,
00289                                              Range& right_tris,
00290                                              Range& both_tris,
00291                                              double& metric_value );
00292 
00293     ErrorCode best_subdivision_snap_plane( int num_planes,
00294                                            const AdaptiveKDTreeIter& iter,
00295                                            Range& best_left,
00296                                            Range& best_right,
00297                                            Range& best_both,
00298                                            AdaptiveKDTree::Plane& best_plane,
00299                                            std::vector< double >& tmp_data,
00300                                            double eps );
00301 
00302     ErrorCode best_subdivision_plane( int num_planes,
00303                                       const AdaptiveKDTreeIter& iter,
00304                                       Range& best_left,
00305                                       Range& best_right,
00306                                       Range& best_both,
00307                                       AdaptiveKDTree::Plane& best_plane,
00308                                       double eps );
00309 
00310     ErrorCode best_vertex_median_plane( int num_planes,
00311                                         const AdaptiveKDTreeIter& iter,
00312                                         Range& best_left,
00313                                         Range& best_right,
00314                                         Range& best_both,
00315                                         AdaptiveKDTree::Plane& best_plane,
00316                                         std::vector< double >& coords,
00317                                         double eps );
00318 
00319     ErrorCode best_vertex_sample_plane( int num_planes,
00320                                         const AdaptiveKDTreeIter& iter,
00321                                         Range& best_left,
00322                                         Range& best_right,
00323                                         Range& best_both,
00324                                         AdaptiveKDTree::Plane& best_plane,
00325                                         std::vector< double >& coords,
00326                                         std::vector< EntityHandle >& indices,
00327                                         double eps );
00328 
00329     static const char* treeName;
00330 
00331     Tag planeTag, axisTag;
00332 
00333     unsigned splitsPerDir;
00334 
00335     CandidatePlaneSet planeSet;
00336 
00337     bool spherical;
00338     double radius;
00339 };
00340 
00341 //! Iterate over leaves of an adaptive kD-tree
00342 class AdaptiveKDTreeIter
00343 {
00344   public:
00345     enum Direction
00346     {
00347         LEFT  = 0,
00348         RIGHT = 1
00349     };
00350 
00351   private:
00352     struct StackObj
00353     {
00354         StackObj( EntityHandle e, double c ) : entity( e ), coord( c ) {}
00355         StackObj() : entity( 0 ), coord( 0.0 ) {}
00356         EntityHandle entity;  //!< handle for tree node
00357         double coord;         //!< box coordinate of parent
00358     };
00359 
00360     enum
00361     {
00362         BMIN = 0,
00363         BMAX = 1
00364     };  //!< indices into mBox and child list
00365 
00366     CartVect mBox[2];                               //!< min and max corners of bounding box
00367     AdaptiveKDTree* treeTool;                       //!< tool for tree
00368     std::vector< StackObj > mStack;                 //!< stack storing path through tree
00369     mutable std::vector< EntityHandle > childVect;  //!< temporary storage of child handles
00370 
00371     //! Descend tree to left most leaf from current position
00372     //! No-op if at leaf.
00373     ErrorCode step_to_first_leaf( Direction direction );
00374 
00375     friend class AdaptiveKDTree;
00376 
00377   public:
00378     AdaptiveKDTreeIter() : treeTool( 0 ), childVect( 2 ) {}
00379 
00380     ErrorCode initialize( AdaptiveKDTree* tool,
00381                           EntityHandle root,
00382                           const double box_min[3],
00383                           const double box_max[3],
00384                           Direction direction );
00385 
00386     AdaptiveKDTree* tool() const
00387     {
00388         return treeTool;
00389     }
00390 
00391     //! Get handle for current leaf
00392     EntityHandle handle() const
00393     {
00394         return mStack.back().entity;
00395     }
00396 
00397     //! Get min corner of axis-aligned box for current leaf
00398     const double* box_min() const
00399     {
00400         return mBox[BMIN].array();
00401     }
00402 
00403     //! Get max corner of axis-aligned box for current leaf
00404     const double* box_max() const
00405     {
00406         return mBox[BMAX].array();
00407     }
00408 
00409     double volume() const
00410     {
00411         return ( mBox[BMAX][0] - mBox[BMIN][0] ) * ( mBox[BMAX][1] - mBox[BMIN][1] ) *
00412                ( mBox[BMAX][2] - mBox[BMIN][2] );
00413     }
00414 
00415     //! test if a plane intersects the leaf box
00416     bool intersects( const AdaptiveKDTree::Plane& plane ) const
00417     {
00418         return mBox[BMIN][plane.norm] <= plane.coord && mBox[BMAX][plane.norm] >= plane.coord;
00419     }
00420 
00421     //! Get depth in tree. root is at depth of 1.
00422     unsigned depth() const
00423     {
00424         return mStack.size();
00425     }
00426 
00427     //! Advance the iterator either left or right in the tree
00428     //! Note:  stepping past the end of the tree will invalidate
00429     //!        the iterator.  It will *not* be work step the
00430     //!        other direction.
00431     ErrorCode step( Direction direction );
00432 
00433     //! Advance to next leaf
00434     //! Returns MB_ENTITY_NOT_FOUND if at end.
00435     //! Note: steping past the end of the tree will invalidate
00436     //!       the iterator. Calling back() will not work.
00437     ErrorCode step()
00438     {
00439         return step( RIGHT );
00440     }
00441 
00442     //! Move back to previous leaf
00443     //! Returns MB_ENTITY_NOT_FOUND if at beginning.
00444     //! Note: steping past the start of the tree will invalidate
00445     //!       the iterator. Calling step() will not work.
00446     ErrorCode back()
00447     {
00448         return step( LEFT );
00449     }
00450 
00451     //! Return the side of the box bounding this tree node
00452     //! that is shared with the immediately adjacent sibling
00453     //! (the tree node that shares a common parent node with
00454     //! this node in the binary tree.)
00455     //!
00456     //!\param axis_out The principal axis orthogonal to the side of the box
00457     //!\param neg_out  true if the side of the box is toward the decreasing
00458     //!                direction of the principal axis indicated by axis_out,
00459     //!                false if it is toward the increasing direction.
00460     //!\return MB_ENTITY_NOT FOUND if root node.
00461     //!        MB_FAILURE if internal error.
00462     //!        MB_SUCCESS otherwise.
00463     ErrorCode sibling_side( AdaptiveKDTree::Axis& axis_out, bool& neg_out ) const;
00464 
00465     //! Get adjacent leaf nodes on side indicated by norm and neg.
00466     //!
00467     //! E.g. if norm == X and neg == true, then get neighbor(s)
00468     //! adjacent to the side of the box contained in the plane
00469     //! with normal to the X axis and with the x coordinate equal
00470     //! to the minimum x of the bounding box.
00471     //!
00472     //! E.g. if norm == Y and neg == false, then get neighbor(s)
00473     //! adjacent to the side of the box with y = maximum y of bounding box.
00474     //!
00475     //!\param norm  Normal vector for box side (X, Y, or Z)
00476     //!\param neg   Which of two planes with norm (true->smaller coord,
00477     //!             false->larger coord)
00478     //!\param results List to which to append results.  This function does
00479     //!             *not* clear existing values in list.
00480     //!\param epsilon Tolerance on overlap.  A positive value E will
00481     //!              result in nodes that are separated by as much as E
00482     //!              to be considered touching.  A negative value -E will
00483     //!              cause leaves that do not overlap by at least E to be
00484     //!              considered non-overlapping.  Amongst other things,
00485     //!              this value can be used to control whether or not
00486     //!              leaves adjacent at only their edges or corners are
00487     //!              returned.
00488     ErrorCode get_neighbors( AdaptiveKDTree::Axis norm,
00489                              bool neg,
00490                              std::vector< AdaptiveKDTreeIter >& results,
00491                              double epsilon = 0.0 ) const;
00492 
00493     //! Get split plane that separates this node from its immediate sibling.
00494     ErrorCode get_parent_split_plane( AdaptiveKDTree::Plane& plane ) const;
00495 
00496     //! Return true if thos node and the passed node share the
00497     //! same immediate parent.
00498     bool is_sibling( const AdaptiveKDTreeIter& other_leaf ) const;
00499 
00500     //! Return true if thos node and the passed node share the
00501     //! same immediate parent.
00502     bool is_sibling( EntityHandle other_leaf ) const;
00503 
00504     //! Returns true if calling step() will advance to the
00505     //! immediate sibling of the current node.  Returns false
00506     //! if current node is root or back() will move to the
00507     //! immediate sibling.
00508     bool sibling_is_forward() const;
00509 
00510     //! Find range of overlap between ray and leaf.
00511     //!
00512     //!\param ray_point Coordinates of start point of ray
00513     //!\param ray_vect  Directionion vector for ray such that
00514     //!                 the ray is defined by r(t) = ray_point + t * ray_vect
00515     //!                 for t > 0.
00516     //!\param t_enter   Output: if return value is true, this value
00517     //!                 is the parameter location along the ray at which
00518     //!                 the ray entered the leaf.  If return value is false,
00519     //!                 then this value is undefined.
00520     //!\param t_exit    Output: if return value is true, this value
00521     //!                 is the parameter location along the ray at which
00522     //!                 the ray exited the leaf.  If return value is false,
00523     //!                 then this value is undefined.
00524     //!\return true if ray intersects leaf, false otherwise.
00525     bool intersect_ray( const double ray_point[3], const double ray_vect[3], double& t_enter, double& t_exit ) const;
00526 };
00527 
00528 inline ErrorCode AdaptiveKDTree::reset_tree()
00529 {
00530     return delete_tree_sets();
00531 }
00532 
00533 }  // namespace moab
00534 
00535 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines