Make iDT the default and explain O() complexity

This commit is contained in:
Andreas Fabri 2018-11-20 18:21:19 +01:00
parent 65e11086a9
commit d749d3f003
8 changed files with 35 additions and 82 deletions

View File

@ -26,7 +26,7 @@ on a fixed domain, since precomputation done for the first query can be re-used.
As a rule of thumb, the method works well on triangle meshes, which are
Delaunay, though in practice may also work fine for meshes that are far from
Delaunay. In order to ensure good behavior, one can optionally enable a
Delaunay. In order to ensure good behavior, we enable a
preprocessing step that constructs an <em>intrinsic Delaunay triangulation
(iDT)</em>; this triangulation will not change the input geometry, but
generally improves the quality of the solution. The cost of this preprocessing
@ -80,17 +80,15 @@ the distances with respect to these two sources.
\cgalExample{Heat_method_3/heat_method_surface_mesh.cpp}
\subsection HM_example_Intrinsic Using the Intrinsic Delaunay Triangulation
\subsection HM_example_Intrinsic Switching off the Intrinsic Delaunay Triangulation
The following example shows the heat method on a triangle mesh using the
intrinsic Delaunay triangulation (iDT) algorithm. The iDT
should be used when the input mesh has poor quality, or when results of
distance computation appear to be highly inaccurate. (Poor quality in this
case means that the input is far from Delaunay, though even in this case
one may still get good results without iDT, depending on the specific
geometry of the surface.)
The following example shows the heat method on a triangle mesh without using the
intrinsic Delaunay triangulation (iDT) algorithm, for example because by constrution
your meshes have a good quality (Poor quality in this case means that the input
is far from Delaunay, though even in this case one may still get good results without iDT,
depending on the specific geometry of the surface.)
\cgalExample{Heat_method_3/heat_method_surface_mesh_intrinsic.cpp}
\cgalExample{Heat_method_3/heat_method_surface_mesh_direct.cpp}
@ -216,15 +214,26 @@ The algorithm is as follows:
\section sec_HM_Performance Performance
The time complexity of the algorithm is determined primarily by the
choice of linear solver. In the current implementation, Cholesky
prefactorization is roughly \f$ O(N^1.5)\f$ and evaluation of distance is
roughly \f$ O(N)\f$, where \f$ N\f$ is the number of vertices in the triangulation.
The algorithm uses two \f$ N \times N\f$ matrices, both with the same pattern of
nonzeros as the graph Laplacian of the edge graph (roughly 7 nonzeros
per row/column). The cost of computation is independent of the size
of the source set. Primitive operations include sparse numerical
linear algebra (in double precision), and basic arithmetic operations
(including square roots).
We perform the benchmark on an Intel Core i7-7700HQ, 2.8HGz, and compiled with Visual Studio 2013.
<center>
Number of triangles | Initialization (sec) | Distance computation (sec) | Initialization iDT (sec) | Distance computation iDT (sec)
--------------------:| ----------- : | ---------------- : | ------------------: | --------------:
30,000 | 0.12 | 0.01 | 0.18 | 0.02
200,000 | 1.32 | 0.11 | 1.82 | 1.31
500,000 | 8.07 | 0.55 | 10.45 | 0.75
1,800,000 | 35.68 | 1.1 | 38.91 | 2.24
Number of triangles | Initialization iDT (sec) | Distance computation iDT (sec) | Initialization Direct (sec) | Distance computation Direct (sec)
--------------------:| ----------- : | ---------------- : | ------------------: | --------------:
30,000 | 0.18 | 0.02 | 0.12 | 0.01
200,000 | 1.82 | 1.31 | 1.32 | 0.11
500,000 | 10.45 | 0.75 | 8.07 | 0.55
1,800,000 | 38.91 | 2.24 | 35.68 | 1.1
</center>

View File

@ -2,5 +2,5 @@
\example Heat_method_3/heat_method.cpp
\example Heat_method_3/heat_method_polyhedron.cpp
\example Heat_method_3/heat_method_surface_mesh.cpp
\example Heat_method_3/heat_method_surface_mesh_intrinsic.cpp
\example Heat_method_3/heat_method_surface_mesh_direct.cpp
*/

View File

@ -56,4 +56,4 @@ include( CGAL_CreateSingleSourceCGALProgram )
create_single_source_cgal_program( "heat_method.cpp" )
create_single_source_cgal_program( "heat_method_polyhedron.cpp" )
create_single_source_cgal_program( "heat_method_surface_mesh.cpp" )
create_single_source_cgal_program( "heat_method_surface_mesh_intrinsic.cpp" )
create_single_source_cgal_program( "heat_method_surface_mesh_direct.cpp" )

View File

@ -14,7 +14,7 @@ typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
typedef Surface_mesh::Property_map<vertex_descriptor,double> Vertex_distance_map;
typedef CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<Surface_mesh, CGAL::Heat_method_3::Intrinsic_Delaunay> Heat_method_idt;
typedef CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<Surface_mesh, CGAL::Heat_method_3::Direct> Heat_method_idt;
int main(int argc, char* argv[])

View File

@ -948,7 +948,7 @@ public:
/// with `boost::graph_traits<TriangleMesh>::%vertex_descriptor` as key type and `double` as value type.
/// \tparam Mode either the tag `Direct` or `Intrinsic_Delaunay`, which determines if the geodesic distance
/// is computed directly on the mesh or if the intrinsic Delaunay triangulation is applied first.
/// The default is `Direct`.
/// The default is `Intrinsic_Delaunay`.
/// \warning The return type is `double` even when used with an exact kernel.
///
/// \sa CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3
@ -972,7 +972,7 @@ estimate_geodesic_distances(const TriangleMesh& tm,
VertexDistanceMap vdm,
typename boost::graph_traits<TriangleMesh>::vertex_descriptor source)
{
CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<TriangleMesh, Direct> hm(tm);
CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<TriangleMesh, Intrinsic_Delaunay> hm(tm);
hm.add_source(source);
hm.estimate_geodesic_distances(vdm);
}
@ -989,7 +989,7 @@ estimate_geodesic_distances(const TriangleMesh& tm,
/// \tparam VertexConstRange a model of the concept `ConstRange` with value type `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
/// \tparam Mode either the tag `Direct` or `Intrinsic_Delaunay`, which determines if the geodesic distance
/// is computed directly on the mesh or if the intrinsic Delaunay triangulation is applied first.
/// The default is `Direct`.
/// The default is `Intrinsic_Delaunay`.
/// \warning The return type is `double` even when used with an exact kernel.
/// \sa CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3
template <typename TriangleMesh, typename VertexDistanceMap, typename VertexConstRange, typename Mode>
@ -1020,7 +1020,7 @@ estimate_geodesic_distances(const TriangleMesh& tm,
typename boost::has_range_const_iterator<VertexConstRange>
>::type* = 0)
{
CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<TriangleMesh, Direct> hm(tm);
CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<TriangleMesh, Intrinsic_Delaunay> hm(tm);
hm.add_sources(sources);
hm.estimate_geodesic_distances(vdm);
}

View File

@ -53,4 +53,4 @@ include( CGAL_CreateSingleSourceCGALProgram )
create_single_source_cgal_program( "heat_method_concept.cpp" )
create_single_source_cgal_program( "heat_method_surface_mesh_test.cpp" )
create_single_source_cgal_program( "heat_method_surface_mesh_intrinsic_test.cpp" )
create_single_source_cgal_program( "heat_method_surface_mesh_direct_test.cpp" )

View File

@ -12,7 +12,7 @@ typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
typedef Surface_mesh::Property_map<vertex_descriptor,double> Vertex_distance_map;
typedef CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<Surface_mesh, CGAL::Heat_method_3::Intrinsic_Delaunay> Heat_method;
typedef CGAL::Heat_method_3::Surface_mesh_geodesic_distances_3<Surface_mesh, CGAL::Heat_method_3::Direct> Heat_method;
@ -100,7 +100,7 @@ int main(int argc, char* argv[])
assert(sdistance < CGAL_PI);
CGAL::Heat_method_3::estimate_geodesic_distances(sm, vertex_distance, source, CGAL::Heat_method_3::Intrinsic_Delaunay());
CGAL::Heat_method_3::estimate_geodesic_distances(sm, vertex_distance, source, CGAL::Heat_method_3::Direct());
sdistance = 0;
BOOST_FOREACH(vertex_descriptor vd , vertices(sm)){
if(get(vertex_distance,vd) > sdistance){

View File

@ -1,56 +0,0 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Heat_method_3/Heat_method_3.h>
#include <CGAL/Heat_method_3/Intrinsic_Delaunay_triangulation_3.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <iostream>
#include <cassert>
#include <string>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Point_2 Point_2;
typedef CGAL::Surface_mesh<Point> Surface_mesh;
typedef CGAL::Heat_method_3::Intrinsic_Delaunay_triangulation_3<Surface_mesh> Idt;
int validate(char* fname)
{
std::string s(fname);
std::string base = s.substr(0,s.length()-4);
Surface_mesh sm;
std::ifstream in(fname);
in >> sm;
if(!in || num_vertices(sm) == 0) {
std::cerr << "Problem loading the input data" << std::endl;
return 1;
}
Idt idt(sm);
boost::property_map<Idt,CGAL::vertex_point_t>::type vpm = get(CGAL::vertex_point_t(),idt);
std::cout.precision(17);
BOOST_FOREACH(boost::graph_traits<Idt>::face_descriptor fd, faces(idt)){
BOOST_FOREACH(boost::graph_traits<Idt>::vertex_descriptor vd, vertices_around_face(halfedge(fd,idt),idt)){
std::cout << get(vpm, vd) << std::endl;
}
}
std::cout << "done" << std::endl;
return 0;
}
int main(int argc, char*argv[])
{
int res = 0;
for(int i=1; i < argc; i++){
std::cout << "validate("<< argv[i] << ")"<< std::endl;
validate(argv[i]);
res++;
}
return res;
}