mirror of https://github.com/CGAL/cgal
457 lines
23 KiB
Plaintext
457 lines
23 KiB
Plaintext
namespace CGAL {
|
|
|
|
/*!
|
|
|
|
\mainpage User Manual
|
|
\anchor Chapter_Fast_Intersection_and_Distance_Computation
|
|
\cgalAutoToc
|
|
|
|
\authors Pierre Alliez, Stephane Tayeb, and Camille Wormser
|
|
|
|
\section aabb_tree_introduction Introduction
|
|
|
|
The AABB tree component offers a static data structure and algorithms
|
|
to perform efficient intersection and distance queries against sets of
|
|
finite 2D or 3D geometric objects. The set of geometric objects stored in
|
|
the data structure can be queried for intersection detection,
|
|
intersection computation and distance. The intersection queries can be
|
|
of any type, provided that the corresponding intersection predicates
|
|
and constructors are implemented in the traits class. The distance
|
|
queries are limited to point queries. Examples of intersection queries
|
|
include line objects (rays, lines, segments) against sets of
|
|
triangles, or plane objects (planes, triangles) against sets of
|
|
segments. An example of a distance query consists of finding the
|
|
closest point from a point query to a set of triangles.
|
|
|
|
Note that this component is not suited to the problem of finding all
|
|
intersecting pairs of objects. We refer to the component
|
|
\ref chapterBoxIntersection "Intersecting Sequences of dD Iso-oriented Boxes"
|
|
which can find all intersecting pairs of iso-oriented boxes.
|
|
|
|
The AABB tree data structure takes as input an iterator range of
|
|
geometric data, which is then converted into primitives. From these
|
|
primitives a hierarchy of axis-aligned bounding boxes (AABBs) is
|
|
constructed and used to speed up intersection and distance queries.
|
|
Each primitive gives access to both one input geometric object
|
|
(so-called datum) and one reference id to this object. A typical
|
|
example primitive wraps a 3D triangle as datum and a face handle of a
|
|
polyhedral surface as id. Each intersection query can return the
|
|
intersection objects (e.g., 3D points or segments for ray queries) as
|
|
well as the id (here the face handle) of the intersected
|
|
primitives. Similarly, each distance query can return the closest
|
|
point from the point query as well as the id of the closest primitive.
|
|
|
|
\cgalFigureBegin{aabbtree_meca,anchor.png}
|
|
Left: surface triangle mesh of a mechanical part. Right: AABB tree constructed.
|
|
\cgalFigureEnd
|
|
|
|
\section aabb_tree_interface Interface
|
|
|
|
The main entry point to the component is the class `AABB_tree`
|
|
which represents a static AABB tree constructed from an iterator range
|
|
of geometric data. Once instantiated an AABB tree can be queried for
|
|
intersection and distance queries.
|
|
|
|
\b Intersections. Assume for example that the tree contains triangle
|
|
primitives. The tree can be queried for intersection against line
|
|
objects (rays, segments or line) in various ways. We distinguish
|
|
intersection *tests* which do not construct any intersection
|
|
objects, from *intersections* which construct the intersection
|
|
objects.
|
|
|
|
Tests:
|
|
|
|
- Function `AABB_tree::do_intersect()` tests if the input primitives are
|
|
intersected by the query. This function is fast as it involves only
|
|
predicates and stops after the first encountered intersection.
|
|
- Function `AABB_tree::number_of_intersected_primitives()` counts all
|
|
intersected primitives.
|
|
- Function `AABB_tree::all_intersected_primitives()` enumerates all intersected
|
|
primitives ids without constructing the corresponding intersection
|
|
objects.
|
|
- Function `AABB_tree::any_intersected_primitive()` returns the first
|
|
encountered intersecting primitive id (if any) without constructing
|
|
the corresponding intersection object, and stops after the first
|
|
encountered intersection. Note that the traversal order of the tree is
|
|
such that first herein does not refer to any particular ordering of
|
|
the intersections with respect to the query.
|
|
- Function `AABB_tree::first_intersected_primitive()` returns
|
|
the intersecting primitive id (if any) of the corresponding
|
|
intersection object that is closest to the source of the ray.
|
|
|
|
Constructions:
|
|
|
|
- Function `AABB_tree::all_intersections()` detects and constructs all
|
|
intersection objects with the input primitives.
|
|
- Function `AABB_tree::any_intersection()` detects and constructs the first
|
|
encountered intersection and constructs the corresponding object. This
|
|
function is fast as it stops after the first encountered intersection.
|
|
- Function `AABB_tree::first_intersection()` detects and constructs
|
|
the intersection object that is closest to the source of the ray.
|
|
|
|
|
|
\b Distance. An AABB tree computes the closest point from a
|
|
given point query to the input primitives through the function
|
|
`AABB_tree::closest_point()`. In addition, it can compute the id of the
|
|
closest primitive from a given point query through the function
|
|
`AABB_tree::closest_point_and_primitive()`, i.e., the id of the
|
|
primitive which realizes the minimum distance from the point
|
|
query. The AABB tree uses a secondary search structure to speed up the
|
|
distance queries. The construction of this secondary structure should
|
|
be requested by the user by a call to
|
|
`AABB_tree::accelerate_distance_queries()` before the first the distance
|
|
computation. This data structure is not generated by default because
|
|
it is used only for distance computations.
|
|
|
|
\warning Having degenerate primitives in the AABB-tree is not recommended as the underlying
|
|
predicates and constructions of the traits class might not be able to handle them.
|
|
For example if one is using `CGAL::AABB_traits` with a Kernel from \cgal,
|
|
having degenerate triangles or segments in the AABB-tree will results in an undefined
|
|
behavior or a crash.
|
|
|
|
\section aabb_tree_examples Examples
|
|
|
|
\subsection aabb_tree_examples_1 Tree of Triangles, for Intersection and Distance Queries
|
|
|
|
In the following example a set of 3D triangles is stored in a
|
|
list. The AABB primitive wraps a triangle as `datum` and an
|
|
iterator in the list as `id`. We compute the number of input
|
|
triangles intersected by a ray query, as well as the closest point and
|
|
the squared distance from a point query.
|
|
|
|
\cgalExample{AABB_tree/AABB_triangle_3_example.cpp}
|
|
|
|
\subsection aabb_tree_examples_2 Tree of Polyhedron Triangle Facets for Intersection Queries
|
|
|
|
In the following example the AABB primitive wraps a facet handle of a
|
|
triangle polyhedral surface as `id` and the corresponding 3D
|
|
triangle as geometric object. From a segment query we test the
|
|
intersections, then compute the number of intersections, compute the
|
|
first encountered intersection (generally a point), compute all
|
|
intersections (where each intersection is a pair of one \cgal object
|
|
and one primitive id - here a face handle) and compute all intersected
|
|
primitives. The latter involves only tests and no predicates and is
|
|
hence faster than computing all intersections. We also compute the
|
|
first encountered intersection with a plane query, which is generally
|
|
a segment. We finally compute the first intersection along a ray.
|
|
|
|
\cgalExample{AABB_tree/AABB_polyhedron_facet_intersection_example.cpp}
|
|
|
|
|
|
\subsection aabb_ray_shooting Ray Shooting
|
|
|
|
In the following example we load a closed polyhedral surface and perform a
|
|
ray shooting query from the centroid of each face, orthogonally to the face
|
|
towards the interior. As the centroid is computed with floating point
|
|
arithmetic the first face hit by the ray may be the face of the centroid.
|
|
The skip functor takes care of ignoring the face.
|
|
|
|
\cgalExample{AABB_tree/AABB_ray_shooting_example.cpp}
|
|
|
|
|
|
|
|
\subsection aabb_tree_examples_3 Tree of Polyhedron Triangle Facets for Distance Queries
|
|
|
|
In the following example the AABB primitive wraps a facet handle of a
|
|
triangle polyhedral surface as `id` and the corresponding 3D
|
|
triangle as geometric object. From a point query we compute the
|
|
squared distance, the closest point as well as the closest point and
|
|
primitive id. The latter returns a pair composed of a point and a face
|
|
handle.
|
|
|
|
\cgalExample{AABB_tree/AABB_polyhedron_facet_distance_example.cpp}
|
|
|
|
\subsection aabb_tree_examples_4 Tree of Segments for Intersection and Distance Queries
|
|
|
|
In the following example the segments are stored into a list, and the
|
|
AABB primitive wraps a segment as `datum` and an iterator in the
|
|
list as `id`. We compute the number of intersections with plane
|
|
and triangles queries, and the closest point from a point query.
|
|
\cgalExample{AABB_tree/AABB_segment_3_example.cpp}
|
|
|
|
\subsection aabb_tree_examples_8 Tree of Polyline and Polygon Segments for Intersection and Distance Queries
|
|
|
|
The following example uses segments given by a polyline and a polygon. The difference is that the polygon is closed. The `id` in this case is the iterator pointing to a `Point_2` in the polyline or the polygon. The datum, a `Segment_2`, is created on the fly from the points using the `id` as the source and the following `Point_2` as the target. We count the intersections with a `Segment_2` and the closest point and id from a point query.
|
|
\cgalExample{AABB_tree/AABB_polyline_segment_2_example.cpp}
|
|
|
|
\subsection aabb_tree_examples_5 Tree of Polyhedron Edge Segments for Intersection and Distance Queries
|
|
|
|
In the following example the AABB primitive wraps a halfedge handle as
|
|
`id` and generates a 3D segment on the fly, each time its method
|
|
`datum` is called. We compute the number of intersections with a
|
|
triangle query and the closest point from a point query.
|
|
\cgalExample{AABB_tree/AABB_polyhedron_edge_example.cpp}
|
|
|
|
\subsection aabb_tree_examples_6 Incremental Insertion of Primitives
|
|
|
|
The AABB tree is a static data structure, but it allows to insert
|
|
primitives, and will internally rebuild triggered by the first query,
|
|
or because the user calls the `AABB_tree::build()` method. The following
|
|
example illustrates this for two polyhedral surfaces.
|
|
|
|
\cgalExample{AABB_tree/AABB_insertion_example.cpp}
|
|
|
|
\subsection aabb_tree_examples_7 Trees of Custom Primitives
|
|
|
|
The AABB tree example folder contains three examples of trees
|
|
constructed with custom primitives. In \ref AABB_tree/AABB_custom_example.cpp "AABB_custom_example.cpp"
|
|
the primitive contains triangles which are defined by three pointers
|
|
to custom points. In \ref AABB_tree/AABB_custom_triangle_soup_example.cpp "AABB_custom_triangle_soup_example.cpp" all input
|
|
triangles are stored into a single array so as to form a triangle
|
|
soup. The primitive internally uses a `boost::iterator_adaptor` so as
|
|
to provide the three functions `AABBPrimitive::id()`, `AABBPrimitive::datum()`,
|
|
and `AABBPrimitive::reference_point()`) required by the primitive concept. In
|
|
\ref AABB_tree/AABB_custom_indexed_triangle_set_example.cpp "AABB_custom_indexed_triangle_set_example.cpp" the input is an indexed
|
|
triangle set stored through two arrays: one array of points and one
|
|
array of indices which refer to the point array. Here also the
|
|
primitive internally uses a `boost::iterator_adaptor`.
|
|
|
|
\section aabb_tree_perf Performances
|
|
|
|
We provide some performance numbers for the case where the AABB tree
|
|
contains a set of polyhedron triangle facets. We measure the tree
|
|
construction time, the memory occupancy and the number of queries per
|
|
second for a variety of intersection and distance queries. The machine
|
|
used is a PC running Windows XP64 with an Intel CPU Core2 Extreme
|
|
clocked at 3.06 GHz with 4GB of RAM. By default the kernel used is
|
|
`Simple_cartesian<double>` (the fastest in our experiments). The
|
|
program has been compiled with Visual C++ 2005 compiler with the O2
|
|
option which maximizes speed.
|
|
|
|
\subsection aabb_tree_perf_cons Construction
|
|
|
|
The surface triangle mesh chosen for benchmarking the tree
|
|
construction is the knot model (14,400 triangles) depicted by
|
|
\cgalFigureRef{figAABB-tree-bench}. We measure the tree construction time (both
|
|
AABB tree alone and AABB tree with internal KD-tree) for this model as
|
|
well as for three denser versions subdivided through the Loop
|
|
subdivision scheme which multiplies the number of triangles by four.
|
|
|
|
|
|
| Number of triangles | Construction (in ms) | Construction with internal KD-tree (in ms) |
|
|
| ----: | ----: | ----: |
|
|
14,400 | 156 | 157 |
|
|
57,600 | 328 | 328 |
|
|
230,400 | 1,141 | 1,437 |
|
|
921,600 | 4,813 | 5,953 |
|
|
|
|
\subsection aabb_tree_perf_mem Memory
|
|
|
|
When using the polyhedron triangle facet primitive (defined in
|
|
`AABB_face_graph_triangle_primitive.h`) the AABB tree occupies
|
|
approximately 61 bytes per primitive (without constructing the
|
|
internal KD-tree). It increases to approximately 150 bytes per
|
|
primitive when constructing the internal KD-tree with one reference
|
|
point per primitive (the default mode when calling the function
|
|
`AABB_tree::accelerate_distance_queries()`). Note that the polyhedron
|
|
facet primitive primitive stores only one facet handle as primitive id
|
|
and computes on the fly a 3D triangle from the facet handle stored
|
|
internally. When explicitly storing a 3D triangle in the primitive the
|
|
tree occupies approximately 140 bytes per primitive instead of 60
|
|
(without constructing the internal KD-tree).
|
|
|
|
The following table provides orders of memory occupancy in MBytes for
|
|
an increasing number of triangles. As the internal KD-tree used to
|
|
accelerate the distance queries dominates the memory occupancy, we
|
|
recommend to specify for large models a lower number of reference
|
|
point (evenly distributed) to construct the internal KD-tree through
|
|
the function `AABB_tree::accelerate_distance_queries()` which
|
|
takes an iterator range as input.
|
|
|
|
| Number of triangles | AABB tree (in MBytes) | AABB tree with internal KD-tree (in MBytes)|
|
|
| ----: | ----: | ----: |
|
|
18,400 | 1.10 | 2.76 |
|
|
102,400 | 6.33 | 14.73 |
|
|
1,022,400 | 59.56 | 151.31 |
|
|
1,822,400 | 108.34 | 291.84 |
|
|
|
|
|
|
\subsection aabb_tree_perf_inter Intersections
|
|
|
|
The following table measures the number of intersection queries per
|
|
second on the 14,400 triangle version of the knot mesh model for ray,
|
|
line, segment and plane queries. Each ray query is generated by
|
|
choosing a random source point within the mesh bounding box and a
|
|
random vector. A line or segment query is generated by choosing two
|
|
random points inside the bounding box. A plane query is generated by
|
|
picking a random point inside the bounding box and a random normal
|
|
vector. Note that a plane query generally intersects many triangles of
|
|
the input surface mesh. This explains the low performance numbers for
|
|
the intersection functions which enumerate all intersections.
|
|
|
|
|
|
| Function | Segment | Ray | Line | Plane |
|
|
| :---- | ----: | ----: | -: | -: |
|
|
| AABB_tree::do_intersect() | 187,868 | 185,649 | 206,096 | 377,969 |
|
|
| AABB_tree::any_intersected_primitive() | 190,684 | 190,027 | 208,941 | 360,337 |
|
|
| AABB_tree::any_intersection() | 147,468 | 143,230 | 148,235 | 229,336 |
|
|
| AABB_tree::number_of_intersected_primitives() | 64,389 | 52,943 | 54,559 | 7,906 |
|
|
| AABB_tree::all_intersected_primitives() | 65,553 | 54,838 | 53,183 | 5,693 |
|
|
| AABB_tree::all_intersections() | 46,507 | 38,471 | 36,374 | 2,644 |
|
|
|
|
|
|
Curve of \cgalFigureRef{figAABB-tree-bench} plots the number of queries per second
|
|
(here the `AABB_tree::all_intersections()` function with random segment
|
|
queries) against the number of input triangles for the knot triangle
|
|
surface mesh.
|
|
|
|
|
|
\cgalFigureBegin{figAABB-tree-bench,bench.png}
|
|
Number of queries per second against number of triangles for the knot model with 14K (shown), 57K, 230K and 921K triangles. We call the `all_intersections()` function with segment queries randomly chosen within the bounding box.
|
|
\cgalFigureEnd
|
|
|
|
The following table measures the number of `AABB_tree::all_intersections()`
|
|
queries per second against several kernels. We use the 14,400 triangle
|
|
version of the knot mesh model for random segment queries. Note how
|
|
the `Simple_cartesian` kernel is substantially faster than the
|
|
`Cartesian` kernel.
|
|
|
|
| Kernel | Queries/s (all_intersections() with segment queries)|
|
|
| :---- | ----: |
|
|
|`Simple_cartesian<double>` | 46,507 |
|
|
|`Simple_cartesian<float>` | 43,187 |
|
|
|`Cartesian<double>` | 5,335 |
|
|
|`Cartesian<float>` | 5,522 |
|
|
|`Exact_predicates_inexact_constructions_kernel` | 18,411 |
|
|
|
|
|
|
|
|
\subsection aabb_tree_perf_dist Distances
|
|
|
|
The surface triangle mesh chosen for benchmarking distances is again
|
|
the knot model in four increasing resolutions obtained through Loop
|
|
subdivision. In the following table we first measure the tree
|
|
construction time (which includes the construction of the internal
|
|
KD-tree data structure used to accelerate the distance queries by up
|
|
to one order of magnitude in our experiments). We then measure the
|
|
number of queries per second for the three types distance queries
|
|
(`AABB_tree::closest_point()`, `AABB_tree::squared_distance()` and
|
|
`AABB_tree::closest_point_and_primitive()`) from point queries randomly chosen
|
|
inside the bounding box.
|
|
|
|
| Nb triangles | Construction (ms) | Closest_point() | Squared_distance() | Closest_point_and_primitive() |
|
|
| ----: | ----: | ----: | ----: | -: |
|
|
| 14,400 | 157.000 | 45,132 | 45,626 | 45,770 |
|
|
| 57,600 | 328.000 | 21,589 | 21,312 | 21,137 |
|
|
| 230,400 | 1.437 | 11,063 | 10,962 | 11,086 |
|
|
| 921,600 | 5.953 | 5,636 | 5,722 | 5,703 |
|
|
|
|
\subsection aabb_tree_perf_summary Summary
|
|
|
|
The experiments described above are neither exhaustive nor conclusive
|
|
as we have chosen one specific case where the input primitives are the
|
|
facets of a triangle surface polyhedron. Nevertheless we now provide
|
|
some general observations and advises about how to put the AABB tree
|
|
to use with satisfactory performances. While the tree construction
|
|
times and memory occupancy do not fluctuate much in our experiments
|
|
depending on the input surface triangle mesh, the performance
|
|
expressed in number of queries varies greatly depending on a complex
|
|
combination of criteria: type of kernel, number of input primitives,
|
|
distribution of primitives in space, type of function queried, type of
|
|
query and location of query in space.
|
|
|
|
- %Kernel: The type of \cgal kernel turns out to dominate the final
|
|
execution times, the maximum performances being obtained with the
|
|
`Simple_cartesian` kernel parameterized with the double precision
|
|
number type. In applications where the intersection and distance
|
|
execution times are crucial it is possible to use this kernel for
|
|
the AABB tree in combination with a more robust kernel for the main
|
|
data structure.
|
|
|
|
- Primitives: Although the number of input primitives plays an obvious
|
|
role in the final performance, their distribution in space is at
|
|
least equally important in order to obtain a well-balanced AABB
|
|
tree. Ideally the primitives must be evenly distributed in space and
|
|
the long primitives spanning the bounding box of the tree root node
|
|
must be avoided as much as possible. It is often beneficial to split
|
|
these long primitives into smaller ones before constructing the
|
|
tree, e.g., through recursive longest edge bisection for triangle
|
|
surface meshes.
|
|
|
|
- Function: The type of function queried plays another important
|
|
role. Obviously the *exhaustive* functions, which list all
|
|
intersections, are slower than the ones stopping after the first
|
|
intersection. Within each of these functions the ones which call
|
|
only intersection tests (`AABB_tree::do_intersect()`,
|
|
`AABB_tree::number_of_intersected_primitives()`,
|
|
`AABB_tree::any_intersected_primitive()`, `AABB_tree::all_intersected_primitives()`) are
|
|
faster than the ones which explicitly construct the intersections
|
|
(`AABB_tree::any_intersection()` and `AABB_tree::all_intersections()`).
|
|
|
|
- Query: The type of query (e.g., line, ray, segment or plane used
|
|
above) plays another role, strongly correlated with the type of
|
|
function (exhaustive or not, and whether or not it constructs the
|
|
intersections). When all intersection constructions are needed, the
|
|
final execution times highly depend on the complexity of the general
|
|
intersection object. For example a plane query generally intersects
|
|
a surface triangle mesh into many segments while a segment query
|
|
generally intersects a surface triangle mesh into few
|
|
points. Finally, the location of the query in space also plays an
|
|
obvious role in the performances, especially for the distance
|
|
queries. Assuming the internal KD-tree constructed through the
|
|
function `AABB_tree::accelerate_distance_queries()`, it is preferable
|
|
to specify a query point already close to the surface triangle mesh
|
|
so that the query traverses only few AABBs of the tree. For a large
|
|
number of primitive data (greater than 2M faces in our experiments)
|
|
however we noticed that it is not necessary (and sometimes even
|
|
slower) to use all reference points when constructing the
|
|
KD-tree. In these cases we recommend to specify through the function
|
|
` AABB_tree::accelerate_distance_queries()` fewer reference
|
|
points (typically not more than 100K) evenly distributed over the
|
|
input primitives.
|
|
|
|
\section aabb_tree_impl Implementation Details
|
|
|
|
The AABB tree construction is initialized by computing the AABB of the
|
|
whole set of input primitives. All primitives are then sorted along
|
|
the longest coordinate axis of this box, and the primitives are
|
|
separated into two equal size sets. This procedure is applied
|
|
recursively until an AABB contains a single primitive. The tree is
|
|
leafless as presented in `OPCODE` \cgalCite{cgal:t-ocdl-05}\. An
|
|
intersection query traverses the tree by computing intersection tests
|
|
only with respect to the AABBs during traversal, and with respect to
|
|
the input primitives at the end of traversal (in the leafs of the
|
|
tree).
|
|
|
|
The reference id is not used internally but simply used by the AABB
|
|
tree to refer to the primitive in the results provided to the user. It
|
|
follows that, while in most cases each reference id corresponds to a
|
|
unique primitive, this is not a requirement of the component. This way
|
|
a user may use these reference ids as labels, each of them being
|
|
shared by several geometric objects.
|
|
|
|
A distance query between a query point `q` and the input primitives is
|
|
turned into a *ball* query centered at `q`. The ball traverses the
|
|
tree while recursively querying intersections with the AABBs, and
|
|
computes the closest point `p` from the query point to the input
|
|
primitives at the leafs of the tree. The ball radius is then shrunk to
|
|
the distance between `p` and `q` for all remaining recursive
|
|
traversals of the tree. Efficiency is achieved through setting the
|
|
initial ball radius to a small value still guaranteed to intersect the
|
|
input primitives. This is achieved by constructing an internal secondary data
|
|
structure which provides a good hint to the algorithm at the beginning
|
|
of the traversal (done by default).
|
|
Calling `AABB_tree::do_not_accelerate_distance_queries()` will disable
|
|
the construction and the usage of this internal secondary data structure.
|
|
|
|
\section aabb_tree_history Design and Implementation History
|
|
|
|
Camille Wormser and Pierre Alliez started working on a data structure
|
|
for efficient collision detection in 2007. The generic design for
|
|
implementing both intersection and distance queries, and for generic
|
|
queries and primitives was developed by Camille Wormser. In 2009,
|
|
Pierre Alliez, Stéphane Tayeb and Camille Wormser made the
|
|
implementation CGAL-compliant, with the help of Laurent Rineau for
|
|
optimizing the tree construction. Additionally, Andreas
|
|
Fabri, Jane Tournois, Mariette Yvinec and Sylvain Lefèbvre are
|
|
given thanks for helpful comments and discussions during that period.
|
|
Later, Sébastien Loriot contributed several improvements:
|
|
thread-safe queries, introduction of shared data stored in the traits
|
|
for lighter primitive types, ...
|
|
In 2024, the package was made compatible with 2D and 3D primitives by
|
|
Andreas Fabri, Sébastien Loriot, and Sven Oesau.
|
|
|
|
*/
|
|
|
|
}
|