RINGMesh  Version 5.0.0
A programming library for geological model meshes
aabb.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2017, Association Scientifique pour la Geologie et ses
3  * Applications (ASGA). All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of ASGA nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ASGA BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * http://www.ring-team.org
28  *
29  * RING Project
30  * Ecole Nationale Superieure de Geologie - GeoRessources
31  * 2 Rue du Doyen Marcel Roubault - TSA 70605
32  * 54518 VANDOEUVRE-LES-NANCY
33  * FRANCE
34  */
35 
36 #pragma once
37 
38 #include <ringmesh/basic/box.h>
39 #include <ringmesh/basic/common.h>
40 
41 namespace RINGMesh
42 {
45  FORWARD_DECLARATION_DIMENSION_CLASS( SurfaceMeshBase );
47 } // namespace RINGMesh
48 
49 namespace RINGMesh
50 {
62  template < index_t DIMENSION >
63  class AABBTree
64  {
67 
68  public:
71  static const index_t ROOT_INDEX = 1;
72 
73  index_t nb_bboxes() const
74  {
75  return static_cast< index_t >( mapping_morton_.size() );
76  }
77 
99  template < typename EvalDistance >
100  std::tuple< index_t, vecn< DIMENSION >, double > closest_element_box(
101  const vecn< DIMENSION >& query, const EvalDistance& action ) const
102  {
103  index_t nearest_box = NO_ID;
104  vecn< DIMENSION > nearest_point;
105  double distance;
106  std::tie( nearest_box, nearest_point, distance ) =
108  closest_element_box_recursive< EvalDistance >( query, nearest_box,
109  nearest_point, distance, ROOT_INDEX, 0, nb_bboxes(), action );
110  ringmesh_assert( nearest_box != NO_ID );
111  return std::make_tuple( nearest_box, nearest_point, distance );
112  }
113  /*
114  * @brief Computes the intersections between a given
115  * box and the element boxes.
116  * @param[in] box the box to test
117  * @param[in] action The functor to run when an element box intersects
118  * \p box
119  * @tparam EvalIntersection this functor should have an operator()
120  * defined like this:
121  * void operator()( index_t cur_box ) ;
122  * where cur_box is the element box index
123  * (e.g. in the case of AABBTree2D, this index is a polygon index)
124  */
125  template < class EvalIntersection >
127  const Box< DIMENSION >& box, EvalIntersection& action ) const
128  {
129  bbox_intersect_recursive< EvalIntersection >(
130  box, ROOT_INDEX, 0, nb_bboxes(), action );
131  }
132  /*
133  * @brief Computes the self intersections of the element boxes.
134  * @param[in] action The functor to run when two boxes intersect
135  * @tparam EvalIntersection this functor should have an operator()
136  * defined like this:
137  * void operator()( index_t box1, index_t box2 ) ;
138  * where box1 and box2 are the element box indices
139  * (e.g. in the case of AABBTree2D, this index is a polygon index)
140  */
141  template < class EvalIntersection >
143  EvalIntersection& action ) const
144  {
145  self_intersect_recursive< EvalIntersection >( ROOT_INDEX, 0,
146  nb_bboxes(), ROOT_INDEX, 0, nb_bboxes(), action );
147  }
148 
149  protected:
150  AABBTree() = default;
151  virtual ~AABBTree() = default;
152 
159  void initialize_tree( const std::vector< Box< DIMENSION > >& bboxes );
160 
161  bool is_leaf( index_t box_begin, index_t box_end ) const
162  {
163  return box_begin + 1 == box_end;
164  }
165  void get_recursive_iterators( index_t node_index,
166  index_t box_begin,
167  index_t box_end,
168  index_t& middle_box,
169  index_t& child_left,
170  index_t& child_right ) const
171  {
172  middle_box = box_begin + ( box_end - box_begin ) / 2;
173  child_left = 2 * node_index;
174  child_right = 2 * node_index + 1;
175  }
176 
177  const Box< DIMENSION >& node( index_t i ) const
178  {
179  ringmesh_assert( i < tree_.size() );
180  return tree_[i];
181  }
182 
183  Box< DIMENSION >& node( index_t i )
184  {
185  ringmesh_assert( i < tree_.size() );
186  return tree_[i];
187  }
188 
189  private:
193  index_t max_node_index(
194  index_t node_index, index_t box_begin, index_t box_end );
199  const std::vector< Box< DIMENSION > >& bboxes,
200  index_t node_index,
201  index_t element_begin,
202  index_t element_end );
203 
207  template < typename ACTION >
209  index_t& nearest_box,
210  vecn< DIMENSION >& nearest_point,
211  double& distance,
212  index_t node_index,
213  index_t element_begin,
214  index_t element_end,
215  const ACTION& action ) const;
216 
217  template < class ACTION >
219  index_t node_index,
220  index_t element_begin,
221  index_t element_end,
222  ACTION& action ) const;
223 
224  template < class ACTION >
225  void self_intersect_recursive( index_t node_index1,
226  index_t element_begin1,
227  index_t element_end1,
228  index_t node_index2,
229  index_t element_begin2,
230  index_t element_end2,
231  ACTION& action ) const;
232 
241  std::tuple< index_t, vecn< DIMENSION >, double >
243  const vecn< DIMENSION >& query ) const;
250  const Box< DIMENSION >& box, index_t element_id ) const = 0;
251 
252  protected:
253  std::vector< Box< DIMENSION > > tree_{};
254  std::vector< index_t > mapping_morton_{};
255  };
256 
257  template < index_t DIMENSION >
258  class BoxAABBTree : public AABBTree< DIMENSION >
259  {
260  public:
261  explicit BoxAABBTree( const std::vector< Box< DIMENSION > >& boxes );
262 
263  private:
269  const Box< DIMENSION >& box, index_t element_id ) const override;
270  };
271 
273 
274  template < index_t DIMENSION >
275  class LineAABBTree : public AABBTree< DIMENSION >
276  {
277  public:
278  explicit LineAABBTree( const LineMesh< DIMENSION >& mesh );
279 
288  std::tuple< index_t, vecn< DIMENSION >, double > closest_edge(
289  const vecn< DIMENSION >& query ) const;
290 
291  private:
297  const Box< DIMENSION >& box, index_t element_id ) const override;
303  {
304  public:
305  explicit DistanceToEdge( const LineMesh< DIMENSION >& mesh )
306  : mesh_( mesh )
307  {
308  }
309 
310  std::tuple< double, vecn< DIMENSION > > operator()(
311  const vecn< DIMENSION >& query, index_t cur_box ) const;
312 
313  private:
315  };
316 
317  private:
319  };
320 
322 
323  template < index_t DIMENSION >
324  class SurfaceAABBTree : public AABBTree< DIMENSION >
325  {
326  public:
327  explicit SurfaceAABBTree( const SurfaceMeshBase< DIMENSION >& mesh );
328 
338  std::tuple< index_t, vecn< DIMENSION >, double > closest_triangle(
339  const vecn< DIMENSION >& query ) const;
340 
341  private:
347  const Box< DIMENSION >& box, index_t element_id ) const override;
353  {
354  public:
356  const SurfaceMeshBase< DIMENSION >& mesh )
357  : mesh_( mesh )
358  {
359  }
360 
361  std::tuple< double, vecn< DIMENSION > > operator()(
362  const vecn< DIMENSION >& query, index_t cur_box ) const;
363 
364  private:
366  };
367 
368  private:
370  };
371 
373 
374  template < index_t DIMENSION >
375  class VolumeAABBTree : public AABBTree< DIMENSION >
376  {
377  ringmesh_template_assert_3d( DIMENSION );
378 
379  public:
380  explicit VolumeAABBTree( const VolumeMesh< DIMENSION >& mesh );
381 
388  index_t containing_cell( const vecn< DIMENSION >& query ) const;
389 
390  private:
396  const Box< DIMENSION >& box, index_t element_id ) const override;
397  index_t containing_cell_recursive( const vecn< DIMENSION >& query,
398  index_t node_index,
399  index_t box_begin,
400  index_t box_end ) const;
401 
402  private:
404  };
405 
407 
408  template < index_t DIMENSION >
410  const vecn< DIMENSION >& p, const Box< DIMENSION >& B );
411 
412  template < index_t DIMENSION >
414  const vecn< DIMENSION >& p, const Box< DIMENSION >& B );
415 
416  template < index_t DIMENSION >
417  template < typename ACTION >
419  const vecn< DIMENSION >& query,
420  index_t& nearest_box,
421  vecn< DIMENSION >& nearest_point,
422  double& distance,
423  index_t node_index,
424  index_t box_begin,
425  index_t box_end,
426  const ACTION& action ) const
427  {
428  ringmesh_assert( node_index < tree_.size() );
429  ringmesh_assert( box_begin != box_end );
430 
431  // If node is a leaf: compute point-element distance
432  // and replace current if nearer
433  if( is_leaf( box_begin, box_end ) )
434  {
435  index_t cur_box = mapping_morton_[box_begin];
436  vecn< DIMENSION > cur_nearest_point;
437  double cur_distance;
438  std::tie( cur_distance, cur_nearest_point ) =
439  action( query, cur_box );
440  if( cur_distance < distance )
441  {
442  nearest_box = cur_box;
443  nearest_point = cur_nearest_point;
444  distance = cur_distance;
445  }
446  return;
447  }
448  index_t box_middle, child_left, child_right;
449  get_recursive_iterators( node_index, box_begin, box_end, box_middle,
450  child_left, child_right );
451 
452  double distance_left =
453  point_box_signed_distance( query, node( child_left ) );
454  double distance_right =
455  point_box_signed_distance( query, node( child_right ) );
456 
457  // Traverse the "nearest" child first, so that it has more chances
458  // to prune the traversal of the other child.
459  if( distance_left < distance_right )
460  {
461  if( distance_left < distance )
462  {
463  closest_element_box_recursive< ACTION >( query, nearest_box,
464  nearest_point, distance, child_left, box_begin, box_middle,
465  action );
466  }
467  if( distance_right < distance )
468  {
469  closest_element_box_recursive< ACTION >( query, nearest_box,
470  nearest_point, distance, child_right, box_middle, box_end,
471  action );
472  }
473  }
474  else
475  {
476  if( distance_right < distance )
477  {
478  closest_element_box_recursive< ACTION >( query, nearest_box,
479  nearest_point, distance, child_right, box_middle, box_end,
480  action );
481  }
482  if( distance_left < distance )
483  {
484  closest_element_box_recursive< ACTION >( query, nearest_box,
485  nearest_point, distance, child_left, box_begin, box_middle,
486  action );
487  }
488  }
489  }
490 
491  template < index_t DIMENSION >
492  template < typename ACTION >
494  const Box< DIMENSION >& box,
495  index_t node_index,
496  index_t element_begin,
497  index_t element_end,
498  ACTION& action ) const
499  {
500  ringmesh_assert( node_index < tree_.size() );
501  ringmesh_assert( element_begin != element_end );
502 
503  // Prune sub-tree that does not have intersection
504  if( !box.bboxes_overlap( node( node_index ) ) )
505  {
506  return;
507  }
508 
509  // Leaf case
510  if( is_leaf( element_begin, element_end ) )
511  {
512  // @todo Check if the box is not intersecting itself
513  index_t cur_box = mapping_morton_[element_begin];
514  action( cur_box );
515  return;
516  }
517 
518  index_t box_middle, child_left, child_right;
519  get_recursive_iterators( node_index, element_begin, element_end,
520  box_middle, child_left, child_right );
521 
522  bbox_intersect_recursive< ACTION >(
523  box, child_left, element_begin, box_middle, action );
524  bbox_intersect_recursive< ACTION >(
525  box, child_right, box_middle, element_end, action );
526  }
527 
528  template < index_t DIMENSION >
529  template < class ACTION >
531  index_t element_begin1,
532  index_t element_end1,
533  index_t node_index2,
534  index_t element_begin2,
535  index_t element_end2,
536  ACTION& action ) const
537  {
538  ringmesh_assert( element_end1 != element_begin1 );
539  ringmesh_assert( element_end2 != element_begin2 );
540 
541  // Since we are intersecting the AABBTree with *itself*,
542  // we can prune half of the cases by skipping the test
543  // whenever node2's polygon index interval is greated than
544  // node1's polygon index interval.
545  if( element_end2 <= element_begin1 )
546  {
547  return;
548  }
549 
550  // The acceleration is here:
551  if( !node( node_index1 ).bboxes_overlap( node( node_index2 ) ) )
552  {
553  return;
554  }
555 
556  // Simple case: leaf - leaf intersection.
557  if( is_leaf( element_begin1, element_end1 )
558  && is_leaf( element_begin2, element_end2 ) )
559  {
560  if( node_index1 == node_index2 )
561  {
562  return;
563  }
564  action( mapping_morton_[element_begin1],
565  mapping_morton_[element_begin2] );
566  return;
567  }
568 
569  // If node2 has more polygons than node1, then
570  // intersect node2's two children with node1
571  // else
572  // intersect node1's two children with node2
573  if( element_end2 - element_begin2 > element_end1 - element_begin1 )
574  {
575  index_t middle_box2, child_left2, child_right2;
576  get_recursive_iterators( node_index2, element_begin2, element_end2,
577  middle_box2, child_left2, child_right2 );
578  self_intersect_recursive< ACTION >( node_index1, element_begin1,
579  element_end1, child_left2, element_begin2, middle_box2,
580  action );
581  self_intersect_recursive< ACTION >( node_index1, element_begin1,
582  element_end1, child_right2, middle_box2, element_end2, action );
583  }
584  else
585  {
586  index_t middle_box1, child_left1, child_right1;
587  get_recursive_iterators( node_index1, element_begin1, element_end1,
588  middle_box1, child_left1, child_right1 );
589  self_intersect_recursive< ACTION >( child_left1, element_begin1,
590  middle_box1, node_index2, element_begin2, element_end2,
591  action );
592  self_intersect_recursive< ACTION >( child_right1, middle_box1,
593  element_end1, node_index2, element_begin2, element_end2,
594  action );
595  }
596  }
597 } // namespace RINGMesh
ringmesh_disable_copy_and_move(AABBTree)
AABB tree structure.
Definition: aabb.h:63
GEO::vecng< DIMENSION, double > vecn
Definition: types.h:74
const LineMesh< DIMENSION > & mesh_
Definition: aabb.h:314
void compute_bbox_element_bbox_intersections(const Box< DIMENSION > &box, EvalIntersection &action) const
Definition: aabb.h:126
double point_box_signed_distance(const vecn< DIMENSION > &p, const Box< DIMENSION > &B)
Definition: aabb.cpp:509
void get_recursive_iterators(index_t node_index, index_t box_begin, index_t box_end, index_t &middle_box, index_t &child_left, index_t &child_right) const
Definition: aabb.h:165
ringmesh_template_assert_2d_or_3d(DIMENSION)
std::vector< index_t > mapping_morton_
Definition: aabb.h:254
bool bboxes_overlap(const Box< DIMENSION > &B) const
Definition: box.h:92
Box< DIMENSION > & node(index_t i)
Definition: aabb.h:183
std::vector< Box< DIMENSION > > tree_
Definition: aabb.h:253
const LineMesh< DIMENSION > & mesh_
Definition: aabb.h:318
ALIAS_2D_AND_3D(Box)
#define ringmesh_template_assert_3d(type)
Definition: common.h:84
const SurfaceMeshBase< DIMENSION > & mesh_
Definition: aabb.h:369
DistanceToEdge(const LineMesh< DIMENSION > &mesh)
Definition: aabb.h:305
virtual vecn< DIMENSION > get_point_hint_from_box(const Box< DIMENSION > &box, index_t element_id) const =0
Gets an element point from its box.
std::tuple< index_t, vecn< DIMENSION >, double > get_nearest_element_box_hint(const vecn< DIMENSION > &query) const
Gets an hint of the result.
Definition: aabb.cpp:274
const SurfaceMeshBase< DIMENSION > & mesh_
Definition: aabb.h:365
void bbox_intersect_recursive(const Box< DIMENSION > &box, index_t node_index, index_t element_begin, index_t element_end, ACTION &action) const
Definition: aabb.h:493
double inner_point_box_distance(const vecn< DIMENSION > &p, const Box< DIMENSION > &B)
Definition: aabb.cpp:495
void initialize_tree_recursive(const std::vector< Box< DIMENSION > > &bboxes, index_t node_index, index_t element_begin, index_t element_end)
The recursive instruction used in initialize_tree()
Definition: aabb.cpp:246
void closest_element_box_recursive(const vecn< DIMENSION > &query, index_t &nearest_box, vecn< DIMENSION > &nearest_point, double &distance, index_t node_index, index_t element_begin, index_t element_end, const ACTION &action) const
The recursive instruction used in closest_element_box()
Definition: aabb.h:418
static const index_t ROOT_INDEX
Definition: aabb.h:71
const VolumeMesh< DIMENSION > & mesh_
Definition: aabb.h:403
index_t max_node_index(index_t node_index, index_t box_begin, index_t box_end)
Gets the number of nodes in the tree subset.
Definition: aabb.cpp:221
#define ringmesh_assert(x)
bool is_leaf(index_t box_begin, index_t box_end) const
Definition: aabb.h:161
DistanceToTriangle(const SurfaceMeshBase< DIMENSION > &mesh)
Definition: aabb.h:355
index_t nb_bboxes() const
Definition: aabb.h:73
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
void compute_self_element_bbox_intersections(EvalIntersection &action) const
Definition: aabb.h:142
void self_intersect_recursive(index_t node_index1, index_t element_begin1, index_t element_end1, index_t node_index2, index_t element_begin2, index_t element_end2, ACTION &action) const
Definition: aabb.h:530
void initialize_tree(const std::vector< Box< DIMENSION > > &bboxes)
Builds the tree.
Definition: aabb.cpp:211
FORWARD_DECLARATION_DIMENSION_CLASS(GeoModelMeshEntityAccess)
std::tuple< index_t, vecn< DIMENSION >, double > closest_element_box(const vecn< DIMENSION > &query, const EvalDistance &action) const
Gets the closest element box to a point.
Definition: aabb.h:100
virtual ~AABBTree()=default
const Box< DIMENSION > & node(index_t i) const
Definition: aabb.h:177