Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
82e8e4b
Initial version of bounded_error_hausdorff method.
msmathcomp May 21, 2019
04a05c0
Implemented distance computation from mesh_1 vertices to mesh_2 trian…
msmathcomp May 21, 2019
951e4a7
Implement first rough approximation.
msmathcomp May 21, 2019
9df0d3f
Fix initialization of global upper bound, include TODOs for further s…
msmathcomp May 21, 2019
c28f007
Add detailed comments on the code written so far and merge face proce…
msmathcomp Jun 6, 2019
a67fa38
Add traversal trait for Hausdorff-based AABB traversal on the first t…
msmathcomp Jun 9, 2019
04c84ef
Add second traversal trait for Hausdorff-based AABB traversal on the …
msmathcomp Jun 9, 2019
1400662
Fixed initialization of local Hausdorff bounds.
msmathcomp Jun 9, 2019
d93aa73
Pass tm2_tree instance to the traversal of tm1
msmathcomp Jun 18, 2019
a4112c4
Implement calling of TM2_tree traversal.
msmathcomp Jun 18, 2019
c76db1e
Finish traversal traits of tm1, i.e. finish implementation of Culling…
msmathcomp Jun 18, 2019
453ec15
Implement vertex (TM1) to triangle (TM2) distance in traversal proces…
msmathcomp Jun 19, 2019
6221ebe
Finish implementation of Culling on B (i.e. TM2) traversal.
msmathcomp Jun 21, 2019
48e159b
Store candidate triangles in a set to be processed later.
msmathcomp Jun 21, 2019
7ec6c4c
Correct implementation of Culling on second mesh.
msmathcomp Jun 22, 2019
2a52382
Implement a non-trivial toy example to test subdivision with. Intende…
msmathcomp Jun 24, 2019
68e9776
Implement subdivision of a triangle from the candidate set.
msmathcomp Jun 24, 2019
17b0003
Fix typo in vertex lookup.
msmathcomp Jun 24, 2019
3c73230
Finish first working prototype giving correct answer on the toy example.
msmathcomp Jun 24, 2019
d8b6e7d
Results of Code Review with Sebastien.
msmathcomp Jul 12, 2019
519d37d
Use Kernel method instead of computations by hand.
msmathcomp Jul 12, 2019
0332d9f
Enable reading of real meshes and perturbation of them for distance c…
msmathcomp Jul 12, 2019
e78cbff
Implement naive bounded Hausdoff computation by simple subdivision.
msmathcomp Jul 15, 2019
000604f
Comment naive comparison method.
msmathcomp Jul 15, 2019
3134025
Bugfix computation of upper bound, should not go below lower bound.
msmathcomp Jul 15, 2019
30b6c70
Add naive and optimized Hausdorff implementation to test file.
msmathcomp Jul 18, 2019
98e92a9
Introduce an additional stopping criterion to stop in degenerate case…
msmathcomp Jul 18, 2019
130dcbc
Bugfix entering nodes of TM2 when traversing it.
msmathcomp Jul 19, 2019
c91c780
Add timing to the example file and restore all tests in the test file.
msmathcomp Jul 19, 2019
156cac5
Implement benchmarking on both time and number of culled triangles.
msmathcomp Jul 20, 2019
680edc4
Modify triangle bounding box distance to have sharper bounds.
msmathcomp Jul 21, 2019
405cf12
Implement Priority Queue for the set of candidate triangles.
msmathcomp Jul 21, 2019
e7e724e
Include Benchmark examples in the Hausdorff examples file.
msmathcomp Aug 23, 2019
1e37c32
Write first lines of documentation to test linking and inclusion of e…
msmathcomp Aug 23, 2019
ba0a671
Clean up Code.
msmathcomp Aug 23, 2019
68f7fac
update doc to make links working
sloriot Aug 23, 2019
316cae0
Finalize documentation of bounded Hausdorff Distance computation and …
msmathcomp Aug 23, 2019
c5c6ef0
Improve text in documentation.
msmathcomp Aug 24, 2019
5f2069a
Document named parameters.
msmathcomp Aug 24, 2019
677908e
Fix NP usage
MaelRL Aug 30, 2019
6027b2d
Add Traits::intersection_with_priority()
afabri Sep 26, 2019
a4aa6a7
rework expression
sloriot Sep 26, 2019
3e5e721
plug do_intersect_with_priority
sloriot Sep 26, 2019
89094af
use do_intersect correctly as it is still needed
sloriot Sep 26, 2019
6e73f92
fix nb of primitives
sloriot Sep 27, 2019
16e0a47
Fix traversal order, add comment on benchmark results.
msmathcomp Oct 13, 2019
fed345c
Add notes from skype meeting.
msmathcomp Oct 13, 2019
2d4c254
Keep current global bounds in mind when traversing tm2.
msmathcomp Oct 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions AABB_tree/include/CGAL/AABB_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,22 @@ namespace CGAL {
}
}


template <class Query, class Traversal_traits>
void traversal_with_priority(const Query& query, Traversal_traits& traits) const
{
switch(size())
{
case 0:
break;
case 1:
traits.intersection(query, singleton_data());
break;
default: // if(size() >= 2)
root_node()->template traversal_with_priority<Traversal_traits,Query>(query, traits, m_primitives.size());
}
}

private:
typedef AABB_node<AABBTraits> Node;

Expand Down
66 changes: 66 additions & 0 deletions AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ class AABB_node
Traversal_traits& traits,
const std::size_t nb_primitives) const;

template<class Traversal_traits, class Query>
void traversal_with_priority(const Query& query,
Traversal_traits& traits,
const std::size_t nb_primitives) const;

private:
typedef AABBTraits AABB_traits;
typedef AABB_node<AABB_traits> Node;
Expand Down Expand Up @@ -201,6 +206,67 @@ AABB_node<Tr>::traversal(const Query& query,
}
}

template<typename Tr>
template<class Traversal_traits, class Query>
void
AABB_node<Tr>::traversal_with_priority(const Query& query,
Traversal_traits& traits,
const std::size_t nb_primitives) const
{
// Recursive traversal
switch(nb_primitives)
{
case 2:
traits.intersection(query, left_data());
if( traits.go_further() )
{
traits.intersection(query, right_data());
}
break;
case 3:
traits.intersection(query, left_data());
if( traits.go_further() && traits.do_intersect(query, right_child()) )
{
right_child().traversal_with_priority(query, traits, 2);
}
break;
default:
bool ileft, iright;
typename Traversal_traits::Priority pleft, pright;
std::tie(ileft,pleft) = traits.do_intersect_with_priority(query, left_child());
std::tie(iright,pright) = traits.do_intersect_with_priority(query, right_child());

if (ileft)
{
if (iright)
{
// Both children have to be inspected
if(pleft >= pright)
{
// Inspect left first, has higher priority
left_child().traversal_with_priority(query, traits, nb_primitives/2);
if( traits.go_further() ) //&& traits.do_intersect(query, right_child()) ) // TODO shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance)
right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2);
}
else
{
// Inspect right first, has higher priority
right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2);
if( traits.go_further() ) //&& traits.do_intersect(query, left_child()) ) // TODO shall we call again do_intersect? (Benchmarks show it slows down the Hausdorff Distance)
left_child().traversal_with_priority(query, traits, nb_primitives/2);
}
}
else
// Only the left child has to be inspected
left_child().traversal_with_priority(query, traits, nb_primitives/2);
}
else
if (iright)
// Only the right child has to be inspected
right_child().traversal_with_priority(query, traits, nb_primitives-nb_primitives/2);
}
}

} // end namespace CGAL

#endif // CGAL_AABB_NODE_H
11 changes: 11 additions & 0 deletions Documentation/doc/biblio/geom.bib
Original file line number Diff line number Diff line change
Expand Up @@ -152016,3 +152016,14 @@ @inproceedings{boissonnat2009Delaunay
HAL_ID = {inria-00412437},
HAL_VERSION = {v1},
}

@inproceedings{tang2009interactive,
title={Interactive Hausdorff distance computation for general polygonal models},
author={Tang, Min and Lee, Minkyoung and Kim, Young J},
booktitle={ACM Transactions on Graphics (TOG)},
volume={28},
number={3},
pages={74},
year={2009},
organization={ACM}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ and provides a list of the parameters that are used in this package.
- \link measure_grp `CGAL::Polygon_mesh_processing::centroid()` \endlink

\cgalCRPSection{Distance Functions}
- `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()`
- `CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance()`
- `CGAL::Polygon_mesh_processing::approximate_symmetric_Hausdorff_distance()`
- `CGAL::Polygon_mesh_processing::approximate_max_distance_to_point_set()`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -729,10 +729,12 @@ which enables to treat one or several connected components as a face graph.
\cgalExample{Polygon_mesh_processing/face_filtered_graph_example.cpp}


\section PMPDistance Approximate Hausdorff Distance
\section PMPDistance (Approximate) Hausdorff Distance

This package provides methods to compute (approximate) distances between meshes and point sets.

\subsection ApproxHD Approximate Hausdorff Distance

The function \link approximate_Hausdorff_distance() `approximate_Hausdorff_distance()`\endlink
computes an approximation of the Hausdorff distance from a mesh `tm1` to a mesh `tm2`. Given a
a sampling of `tm1`, it computes the distance to `tm2` of the farthest sample point to `tm2` \cgalCite{cignoni1998metro}.
Expand All @@ -757,12 +759,12 @@ computes an approximation of the Hausdorff distance from a mesh to a point set.
For each triangle, a lower and upper bound of the Hausdorff distance to the point set are computed.
Triangles are refined until the difference between the bounds is lower than a user-defined precision threshold.

\subsection AHDExample Approximate Hausdorff Distance Example
\subsubsection AHDExample Approximate Hausdorff Distance Example
In the following example, a mesh is isotropically remeshed and the approximate distance between the input and the output is computed.

\cgalExample{Polygon_mesh_processing/hausdorff_distance_remeshing_example.cpp}

\subsection PoissonDistanceExample Max Distance Between Point Set and Surface Example
\subsubsection PoissonDistanceExample Max Distance Between Point Set and Surface Example
In \ref Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp,
a triangulated surface mesh is constructed from a point set using the
\link PkgPoissonSurfaceReconstruction3 Poisson reconstruction algorithm \endlink,
Expand All @@ -771,6 +773,40 @@ with the following code:

\snippet Poisson_surface_reconstruction_3/poisson_reconstruction_example.cpp PMP_distance_snippet

\subsection BoundedHD Bounded Hausdorff Distance

The function `CGAL::Polygon_mesh_processing::bounded_error_Hausdorff_distance()`
computes an estimate of the Hausdorff distance of two triangle meshes which is
bounded by a user-given error bound. Given two meshes tm1 and tm2, it follows
the procedure given by \cgalCite{tang2009interactive}. Namely, an AABB tree is
built on tm1 and tm2 respectively. The tree on tm1 is used to iterate over all
triangles in tm1. Throughout the traversal, the procedure keeps track of a global
lower and upper bound on the Hausdorff distance respectively. For each triangle
t in tm1, by traversing the tree on tm2, it is estimated via the global bounds
whether t can still contribute to the actual Hausdorff distance. From this
process, a set of candidate triangles is selected.

The candidate triangles are subsequently subdivided and for each smaller
triangle, the tree on tm2 is traversed again. This is repeated until the
triangle is smaller than the user-given error bound, all vertices of the
triangle are projected onto the same triangle in tm2, or the triangle's upper
bound is lower than the global lower bound. After creation, the subdivided
triangles are added to the list of candidate triangles. Thereby, all candidate
triangles are processed until a triangle is found in which the Hausdorff
distance is realized or in which it is guaranteed to be realized within the
user-given error bound.

\subsubsection BHDExample Bounded Hausdorff Distance Example

In the following examples: (a) the distance of a tetrahedron to a remeshed
version of itself is computed, (b) the distance of two geometries is computed
which is realized strictly in the interior of a triangle of the first geometry,
(c) a perturbation of a user-given mesh is compared to the original user-given
mesh, (d) two user-given meshes are compared, where the second mesh is gradually
moved away from the first one.

\cgalExample{Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp}

\section PMPDetectFeatures Feature Detection

This package provides methods to detect some features of a polygon mesh.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
\example Polygon_mesh_processing/detect_features_example.cpp
\example Polygon_mesh_processing/manifoldness_repair_example.cpp
\example Polygon_mesh_processing/repair_polygon_soup_example.cpp
\example Polygon_mesh_processing/hausdorff_bounded_error_distance_example.cpp
*/
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ find_package( CGAL QUIET COMPONENTS )
if ( NOT CGAL_FOUND )

message(STATUS "This project requires the CGAL library, and will not be compiled.")
return()
return()

endif()

Expand All @@ -31,7 +31,7 @@ if ( NOT Boost_FOUND )

message(STATUS "This project requires the Boost library, and will not be compiled.")

return()
return()

endif()

Expand All @@ -55,8 +55,10 @@ find_package(Eigen3 3.2.0) #(requires 3.2.0 or greater)

find_package( TBB )
create_single_source_cgal_program( "hausdorff_distance_remeshing_example.cpp")
create_single_source_cgal_program( "hausdorff_bounded_error_distance_example.cpp")
if( TBB_FOUND )
CGAL_target_use_TBB(hausdorff_distance_remeshing_example)
CGAL_target_use_TBB(hausdorff_bounded_error_distance_example)
else()
message( STATUS "NOTICE: Intel TBB was not found. hausdorff_distance_example will use sequential code." )
endif()
Expand Down Expand Up @@ -118,6 +120,3 @@ target_link_libraries( stitch_borders_example_OM PRIVATE ${OPENMESH_LIBRARIES} )
create_single_source_cgal_program( "triangulate_faces_example_OM.cpp")
target_link_libraries( triangulate_faces_example_OM PRIVATE ${OPENMESH_LIBRARIES} )
endif(OpenMesh_FOUND)



Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#include <CGAL/Aff_transformation_3.h>
#include <CGAL/aff_transformation_tags.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Polygon_mesh_processing/distance.h>
#include <CGAL/Polygon_mesh_processing/remesh.h>
#include <CGAL/Polygon_mesh_processing/random_perturbation.h>
#include <CGAL/Polygon_mesh_processing/transform.h>
#include <CGAL/Real_timer.h>

#if defined(CGAL_LINKED_WITH_TBB)
#define TAG CGAL::Parallel_tag
#else
#define TAG CGAL::Sequential_tag
#endif

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_3 Point_3;
typedef K::Triangle_3 Triangle_3;
typedef K::Vector_3 Vector_3;
typedef CGAL::Surface_mesh<Point_3> Mesh;
typedef Mesh::Vertex_index Vertex_index;

namespace PMP = CGAL::Polygon_mesh_processing;

int main(int argc, char** argv)
{
// Objects to hold the meshes
Mesh tm1, tm2;

// Timer to measure the runtime of h-distance Distance_computation
CGAL::Real_timer time;

// Set an error bound
double error_bound = 0.0001;

// ----------------------------------------------------------------------------

// Easy Example of a tetrahedron and a remeshed version of itself

// Create the Tetrahedron
CGAL::make_tetrahedron(Point_3(.0,.0,.0),
Point_3(2,.0,.0),
Point_3(1,1,1),
Point_3(1,.0,2),
tm1);
// Copy it and remesh it
tm2=tm1;
PMP::isotropic_remeshing(tm2.faces(),.05, tm2);
// Compute the Hausdorff distance
time.reset();
time.start();
std::cout << "Approximated Hausdorff distance: "
<< PMP::bounded_error_Hausdorff_distance
<TAG>(tm1, tm2, error_bound)
<< std::endl;
time.stop();
std::cout << "Processing took " << time.time() << "s." << std::endl;

// ----------------------------------------------------------------------------

// Example with point realizing the Hausdorff distance strictly lying in the

// interior of a triangle
tm1 = Mesh();
tm1.add_vertex( Point_3(-1.,1.,1.) );
tm1.add_vertex( Point_3(0.,-1.,1.) );
tm1.add_vertex( Point_3(1.,1.,1.) );
tm1.add_face( tm1.vertices() );

tm2 = Mesh();
Vertex_index w0 = tm2.add_vertex( Point_3(-1.,1.,0.) );
Vertex_index w1 = tm2.add_vertex( Point_3(0.,-1.,0.) );
Vertex_index w2 = tm2.add_vertex( Point_3(1.,1.,0.) );
Vertex_index w3 = tm2.add_vertex( Point_3(0.,1.,-1.) );
Vertex_index w4 = tm2.add_vertex( Point_3(-0.5,0.,-1.) );
Vertex_index w5 = tm2.add_vertex( Point_3(0.5,0.,-1.) );
tm2.add_face( w0, w3, w4 );
tm2.add_face( w1, w4, w5 );
tm2.add_face( w2, w5, w3 );

// Compute the Hausdorff distance
time.reset();
time.start();
std::cout << "Approximated Hausdorff distance: "
<< PMP::bounded_error_Hausdorff_distance
<TAG>(tm1, tm2, error_bound)
<< std::endl;
time.stop();
std::cout << "Processing took " << time.time() << "s." << std::endl;

// ----------------------------------------------------------------------------

// Read a real meshes given by the user, perturb it slightly and compute the
// Hausdorff distance between the original mesh and its pertubation

std::ifstream input( argv[1] );
input >> tm1;
std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl;

// Copy the mesh and perturb it slightly
tm2 = tm1;
bool do_project = false;
PMP::random_perturbation( tm2.vertices(), tm2, 0.1, CGAL::parameters::do_project(do_project));
std::cout << "Perturbed the input mesh, now computing the Hausdorff distance." << std::endl;

// Compute the Hausdorff distance
time.reset();
time.start();
std::cout << "Approximated Hausdorff distance: "
<< PMP::bounded_error_Hausdorff_distance
<TAG>(tm1, tm2, error_bound)
<< std::endl;
time.stop();
std::cout << "Processing took " << time.time() << "s." << std::endl;

// ----------------------------------------------------------------------------

// Read two meshes given by the user, initially place them at their originally
// given position. Move the second mesh in 300 steps away from the first one.
// Print how the Hausdorff distance changes.

std::ifstream input1( argv[1] );
input1 >> tm1;
std::cout << "Read a mesh with " << tm1.number_of_faces() << " triangles." << std::endl;

std::ifstream input2( argv[2] );
input2 >> tm2;
std::cout << "Read a mesh with " << tm2.number_of_faces() << " triangles." << std::endl;

CGAL::Bbox_3 bb = PMP::bbox(tm2);
double dist = CGAL::approximate_sqrt( Vector_3(bb.xmax() - bb.xmin(), bb.ymax() - bb.ymin(), bb.zmax() - bb.zmin()).squared_length() );

for (int i=0; i<300; i++) {
PMP::transform(
CGAL::Aff_transformation_3<K> ( CGAL::Translation(), Vector_3( 0.01*dist, 0.01*dist, 0.01*dist ) ),
tm2
);
time.reset();
time.start();
std::cout << "Position: " << i << std::endl;
std::cout << "Approximated Hausdorff distance: "
<< PMP::bounded_error_Hausdorff_distance
<TAG>(tm1, tm2, error_bound)
<< std::endl;
time.stop();
std::cout << "Processing took " << time.time() << "s." << std::endl;
}
}
Loading