Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
AdaptiveKDTree.hpp
Go to the documentation of this file.
1 /**\file AdaptiveKDTree.hpp
2  * \class moab::AdaptiveKDTree
3  * \brief Adaptive KD tree, for sorting and searching entities spatially
4  */
5 
6 #ifndef MOAB_ADAPTIVE_KD_TREE_HPP
7 #define MOAB_ADAPTIVE_KD_TREE_HPP
8 
9 #include "moab/Types.hpp"
10 #include "moab/Tree.hpp"
11 
12 #include <string>
13 #include <vector>
14 #include <cmath>
15 
16 namespace moab
17 {
18 
19 class AdaptiveKDTreeIter;
20 class Interface;
21 class Range;
22 
23 class AdaptiveKDTree : public Tree
24 {
25  public:
27 
28  /** \brief Constructor (build the tree on construction)
29  * Construct a tree object, and build the tree with entities input. See comments
30  * for build_tree() for detailed description of arguments.
31  * \param iface MOAB instance
32  * \param entities Entities to build tree around
33  * \param tree_root Root set for tree (see function description)
34  * \param opts Options for tree (see function description)
35  */
37  const Range& entities,
38  EntityHandle* tree_root_set = NULL,
39  FileOptions* opts = NULL );
40 
42 
43  /** \brief Parse options for tree creation
44  * \param options Options passed in by application
45  * \return Failure is returned if any options were passed in and not interpreted; could mean
46  * inappropriate options for a particular tree type
47  */
49 
50  /** Build the tree
51  * Build a tree with the entities input. If a non-NULL tree_root_set pointer is input,
52  * use the pointed-to set as the root of this tree (*tree_root_set!=0) otherwise construct
53  * a new root set and pass its handle back in *tree_root_set. Options vary by tree type;
54  * see Tree.hpp for common options; options specific to AdaptiveKDTree:
55  * SPLITS_PER_DIR: number of candidate splits considered per direction; default = 3
56  * PLANE_SET: method used to decide split planes; see CandidatePlaneSet enum (below)
57  * for possible values; default = 1 (SUBDIVISION_SNAP)
58  * \param entities Entities with which to build the tree
59  * \param tree_root Root set for tree (see function description)
60  * \param opts Options for tree (see function description)
61  * \return Error is returned only on build failure
62  */
63  virtual ErrorCode build_tree( const Range& entities,
64  EntityHandle* tree_root_set = NULL,
65  FileOptions* options = NULL );
66 
67  //! Reset the tree, optionally checking we have the right root
68  virtual ErrorCode reset_tree();
69 
70  /** \brief Get leaf containing input position.
71  *
72  * Does not take into account global bounding box of tree.
73  * - Therefore there is always one leaf containing the point.
74  * - If caller wants to account for global bounding box, then
75  * caller can test against that box and not call this method
76  * at all if the point is outside the box, as there is no leaf
77  * containing the point in that case.
78  * \param point Point to be located in tree
79  * \param leaf_out Leaf containing point
80  * \param iter_tol Tolerance for convergence of point search
81  * \param inside_tol Tolerance for inside element calculation
82  * \param multiple_leaves Some tree types can have multiple leaves containing a point;
83  * if non-NULL, this parameter is returned true if multiple leaves contain
84  * the input point
85  * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
86  * \return Non-success returned only in case of failure; not-found indicated by leaf_out=0
87  */
88  virtual ErrorCode point_search( const double* point,
89  EntityHandle& leaf_out,
90  const double iter_tol = 1.0e-10,
91  const double inside_tol = 1.0e-6,
92  bool* multiple_leaves = NULL,
93  EntityHandle* start_node = NULL,
94  CartVect* params = NULL );
95 
96  /** \brief Get leaf containing input position.
97  *
98  * Does not take into account global bounding box of tree.
99  * - Therefore there is always one leaf containing the point.
100  * - If caller wants to account for global bounding box, then
101  * caller can test against that box and not call this method
102  * at all if the point is outside the box, as there is no leaf
103  * containing the point in that case.
104  * \param point Point to be located in tree
105  * \param leaf_it Iterator to leaf containing point
106  * \param iter_tol Tolerance for convergence of point search
107  * \param inside_tol Tolerance for inside element calculation
108  * \param multiple_leaves Some tree types can have multiple leaves containing a point;
109  * if non-NULL, this parameter is returned true if multiple leaves contain
110  * the input point
111  * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
112  * \return Non-success returned only in case of failure; not-found indicated by leaf_out=0
113  */
114  ErrorCode point_search( const double* point,
115  AdaptiveKDTreeIter& leaf_it,
116  const double iter_tol = 1.0e-10,
117  const double inside_tol = 1.0e-6,
118  bool* multiple_leaves = NULL,
119  EntityHandle* start_node = NULL );
120 
121  /** \brief Find all leaves within a given distance from point
122  * If dists_out input non-NULL, also returns distances from each leaf; if
123  * point i is inside leaf, 0 is given as dists_out[i].
124  * If params_out is non-NULL and myEval is non-NULL, will evaluate individual entities
125  * in tree nodes and return containing entities in leaves_out. In those cases, if params_out
126  * is also non-NULL, will return parameters in those elements in that vector.
127  * \param point Point to be located in tree
128  * \param distance Distance within which to query
129  * \param leaves_out Leaves within distance or containing point
130  * \param iter_tol Tolerance for convergence of point search
131  * \param inside_tol Tolerance for inside element calculation
132  * \param dists_out If non-NULL, will contain distsances to leaves
133  * \param params_out If non-NULL, will contain parameters of the point in the ents in leaves_out
134  * \param start_node Start from this tree node (non-NULL) instead of tree root (NULL)
135  */
136  virtual ErrorCode distance_search( const double* point,
137  const double distance,
138  std::vector< EntityHandle >& leaves_out,
139  const double iter_tol = 1.0e-10,
140  const double inside_tol = 1.0e-6,
141  std::vector< double >* dists_out = NULL,
142  std::vector< CartVect >* params_out = NULL,
143  EntityHandle* start_node = NULL );
144 
145  ErrorCode get_info( EntityHandle root, double min[3], double max[3], unsigned int& dep );
146 
147  //! Enumeriate split plane directions
148  enum Axis
149  {
150  X = 0,
151  Y = 1,
152  Z = 2
153  };
154 
155  //! Split plane
156  struct Plane
157  {
158  double coord; //!< Location of plane as coordinate on normal axis
159  int norm; //!< The principal axis that is the normal of the plane;
160 
161  /** return true if point is below/to the left of the split plane */
162  bool left_side( const double point[3] )
163  {
164  return point[norm] < coord;
165  }
166  /** return true if point is above/to the right of the split plane */
167  bool right_side( const double point[3] )
168  {
169  return point[norm] > coord;
170  }
171  /** return distance from point to plane */
172  double distance( const double point[3] ) const
173  {
174  return fabs( point[norm] - coord );
175  }
176  };
177 
178  //! Get split plane for tree node
179  ErrorCode get_split_plane( EntityHandle node, Plane& plane );
180 
181  //! Set split plane for tree node
182  ErrorCode set_split_plane( EntityHandle node, const Plane& plane );
183 
184  //! Get iterator for tree
186 
187  //! Get iterator at right-most ('last') leaf.
189 
190  //! Get iterator for tree or subtree
192  const double box_min[3],
193  const double box_max[3],
194  AdaptiveKDTreeIter& result );
195 
196  //! Split leaf of tree
197  //! Updates iterator location to point to first new leaf node.
198  ErrorCode split_leaf( AdaptiveKDTreeIter& leaf, Plane plane );
199 
200  //! Split leaf of tree
201  //! Updates iterator location to point to first new leaf node.
202  ErrorCode split_leaf( AdaptiveKDTreeIter& leaf, Plane plane, EntityHandle& left_child, EntityHandle& right_child );
203  //! Split leaf of tree
204  //! Updates iterator location to point to first new leaf node.
206  Plane plane,
207  const Range& left_entities,
208  const Range& right_entities );
209 
210  //! Split leaf of tree
211  //! Updates iterator location to point to first new leaf node.
213  Plane plane,
214  const std::vector< EntityHandle >& left_entities,
215  const std::vector< EntityHandle >& right_entities );
216 
217  //! Merge the leaf pointed to by the current iterator with it's
218  //! sibling. If the sibling is not a leaf, multiple merges may
219  //! be done.
221 
222  //! Find triangle closest to input position.
223  //!\param from_coords The input position to test against
224  //!\param closest_point_out The closest point on the set of triangles in the tree
225  //!\param triangle_out The triangle closest to the input position
227  const double from_coords[3],
228  double closest_point_out[3],
229  EntityHandle& triangle_out );
230 
232  const double center[3],
233  double radius,
234  std::vector< EntityHandle >& triangles );
235 
237  const double tolerance,
238  const double ray_unit_dir[3],
239  const double ray_base_pt[3],
240  std::vector< EntityHandle >& triangles_out,
241  std::vector< double >& distance_out,
242  int result_count_limit = 0,
243  double distance_limit = -1.0 );
244 
245  ErrorCode compute_depth( EntityHandle root, unsigned int& min_depth, unsigned int& max_depth );
246 
247  //! methods for selecting candidate split planes
249  {
250  //! Candidiate planes at evenly spaced intervals
252  //! Like SUBDIVISION, except snap to closest vertex coordinate
254  //! Median vertex coodinate values
256  //! Random sampling of vertex coordinate values
257  VERTEX_SAMPLE // = 3
258  };
259 
260  //! print various things about this tree
261  virtual ErrorCode print();
262 
263  private:
264  friend class AdaptiveKDTreeIter;
265 
266  ErrorCode init();
267 
268  /**\brief find a triangle near the input point */
270  const double from_point[3],
271  double pt[3],
272  EntityHandle& triangle );
273 
275  std::string name,
276  TagType storage,
277  DataType type,
278  int count,
279  void* default_val,
280  Tag& tag_handle,
281  std::vector< Tag >& created_tags );
282 
284  AdaptiveKDTree::Plane plane,
285  double eps,
288  Range& left_tris,
289  Range& right_tris,
290  Range& both_tris,
291  double& metric_value );
292 
293  ErrorCode best_subdivision_snap_plane( int num_planes,
294  const AdaptiveKDTreeIter& iter,
295  Range& best_left,
296  Range& best_right,
297  Range& best_both,
298  AdaptiveKDTree::Plane& best_plane,
299  std::vector< double >& tmp_data,
300  double eps );
301 
302  ErrorCode best_subdivision_plane( int num_planes,
303  const AdaptiveKDTreeIter& iter,
304  Range& best_left,
305  Range& best_right,
306  Range& best_both,
307  AdaptiveKDTree::Plane& best_plane,
308  double eps );
309 
310  ErrorCode best_vertex_median_plane( int num_planes,
311  const AdaptiveKDTreeIter& iter,
312  Range& best_left,
313  Range& best_right,
314  Range& best_both,
315  AdaptiveKDTree::Plane& best_plane,
316  std::vector< double >& coords,
317  double eps );
318 
319  ErrorCode best_vertex_sample_plane( int num_planes,
320  const AdaptiveKDTreeIter& iter,
321  Range& best_left,
322  Range& best_right,
323  Range& best_both,
324  AdaptiveKDTree::Plane& best_plane,
325  std::vector< double >& coords,
326  std::vector< EntityHandle >& indices,
327  double eps );
328 
329  static const char* treeName;
330 
332 
333  unsigned splitsPerDir;
334 
336 
337  bool spherical;
338  double radius;
339 };
340 
341 //! Iterate over leaves of an adaptive kD-tree
343 {
344  public:
346  {
347  LEFT = 0,
348  RIGHT = 1
349  };
350 
351  private:
352  struct StackObj
353  {
354  StackObj( EntityHandle e, double c ) : entity( e ), coord( c ) {}
355  StackObj() : entity( 0 ), coord( 0.0 ) {}
356  EntityHandle entity; //!< handle for tree node
357  double coord; //!< box coordinate of parent
358  };
359 
360  enum
361  {
362  BMIN = 0,
363  BMAX = 1
364  }; //!< indices into mBox and child list
365 
366  CartVect mBox[2]; //!< min and max corners of bounding box
367  AdaptiveKDTree* treeTool; //!< tool for tree
368  std::vector< StackObj > mStack; //!< stack storing path through tree
369  mutable std::vector< EntityHandle > childVect; //!< temporary storage of child handles
370 
371  //! Descend tree to left most leaf from current position
372  //! No-op if at leaf.
374 
375  friend class AdaptiveKDTree;
376 
377  public:
379 
381  EntityHandle root,
382  const double box_min[3],
383  const double box_max[3],
384  Direction direction );
385 
387  {
388  return treeTool;
389  }
390 
391  //! Get handle for current leaf
393  {
394  return mStack.back().entity;
395  }
396 
397  //! Get min corner of axis-aligned box for current leaf
398  const double* box_min() const
399  {
400  return mBox[BMIN].array();
401  }
402 
403  //! Get max corner of axis-aligned box for current leaf
404  const double* box_max() const
405  {
406  return mBox[BMAX].array();
407  }
408 
409  double volume() const
410  {
411  return ( mBox[BMAX][0] - mBox[BMIN][0] ) * ( mBox[BMAX][1] - mBox[BMIN][1] ) *
412  ( mBox[BMAX][2] - mBox[BMIN][2] );
413  }
414 
415  //! test if a plane intersects the leaf box
416  bool intersects( const AdaptiveKDTree::Plane& plane ) const
417  {
418  return mBox[BMIN][plane.norm] <= plane.coord && mBox[BMAX][plane.norm] >= plane.coord;
419  }
420 
421  //! Get depth in tree. root is at depth of 1.
422  unsigned depth() const
423  {
424  return mStack.size();
425  }
426 
427  //! Advance the iterator either left or right in the tree
428  //! Note: stepping past the end of the tree will invalidate
429  //! the iterator. It will *not* be work step the
430  //! other direction.
431  ErrorCode step( Direction direction );
432 
433  //! Advance to next leaf
434  //! Returns MB_ENTITY_NOT_FOUND if at end.
435  //! Note: steping past the end of the tree will invalidate
436  //! the iterator. Calling back() will not work.
438  {
439  return step( RIGHT );
440  }
441 
442  //! Move back to previous leaf
443  //! Returns MB_ENTITY_NOT_FOUND if at beginning.
444  //! Note: steping past the start of the tree will invalidate
445  //! the iterator. Calling step() will not work.
447  {
448  return step( LEFT );
449  }
450 
451  //! Return the side of the box bounding this tree node
452  //! that is shared with the immediately adjacent sibling
453  //! (the tree node that shares a common parent node with
454  //! this node in the binary tree.)
455  //!
456  //!\param axis_out The principal axis orthogonal to the side of the box
457  //!\param neg_out true if the side of the box is toward the decreasing
458  //! direction of the principal axis indicated by axis_out,
459  //! false if it is toward the increasing direction.
460  //!\return MB_ENTITY_NOT FOUND if root node.
461  //! MB_FAILURE if internal error.
462  //! MB_SUCCESS otherwise.
463  ErrorCode sibling_side( AdaptiveKDTree::Axis& axis_out, bool& neg_out ) const;
464 
465  //! Get adjacent leaf nodes on side indicated by norm and neg.
466  //!
467  //! E.g. if norm == X and neg == true, then get neighbor(s)
468  //! adjacent to the side of the box contained in the plane
469  //! with normal to the X axis and with the x coordinate equal
470  //! to the minimum x of the bounding box.
471  //!
472  //! E.g. if norm == Y and neg == false, then get neighbor(s)
473  //! adjacent to the side of the box with y = maximum y of bounding box.
474  //!
475  //!\param norm Normal vector for box side (X, Y, or Z)
476  //!\param neg Which of two planes with norm (true->smaller coord,
477  //! false->larger coord)
478  //!\param results List to which to append results. This function does
479  //! *not* clear existing values in list.
480  //!\param epsilon Tolerance on overlap. A positive value E will
481  //! result in nodes that are separated by as much as E
482  //! to be considered touching. A negative value -E will
483  //! cause leaves that do not overlap by at least E to be
484  //! considered non-overlapping. Amongst other things,
485  //! this value can be used to control whether or not
486  //! leaves adjacent at only their edges or corners are
487  //! returned.
489  bool neg,
490  std::vector< AdaptiveKDTreeIter >& results,
491  double epsilon = 0.0 ) const;
492 
493  //! Get split plane that separates this node from its immediate sibling.
495 
496  //! Return true if thos node and the passed node share the
497  //! same immediate parent.
498  bool is_sibling( const AdaptiveKDTreeIter& other_leaf ) const;
499 
500  //! Return true if thos node and the passed node share the
501  //! same immediate parent.
502  bool is_sibling( EntityHandle other_leaf ) const;
503 
504  //! Returns true if calling step() will advance to the
505  //! immediate sibling of the current node. Returns false
506  //! if current node is root or back() will move to the
507  //! immediate sibling.
508  bool sibling_is_forward() const;
509 
510  //! Find range of overlap between ray and leaf.
511  //!
512  //!\param ray_point Coordinates of start point of ray
513  //!\param ray_vect Directionion vector for ray such that
514  //! the ray is defined by r(t) = ray_point + t * ray_vect
515  //! for t > 0.
516  //!\param t_enter Output: if return value is true, this value
517  //! is the parameter location along the ray at which
518  //! the ray entered the leaf. If return value is false,
519  //! then this value is undefined.
520  //!\param t_exit Output: if return value is true, this value
521  //! is the parameter location along the ray at which
522  //! the ray exited the leaf. If return value is false,
523  //! then this value is undefined.
524  //!\return true if ray intersects leaf, false otherwise.
525  bool intersect_ray( const double ray_point[3], const double ray_vect[3], double& t_enter, double& t_exit ) const;
526 };
527 
529 {
530  return delete_tree_sets();
531 }
532 
533 } // namespace moab
534 
535 #endif