mirror of https://github.com/CGAL/cgal
Make iDT the default and explain O() complexity
This commit is contained in:
parent
65e11086a9
commit
d749d3f003
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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" )
|
||||
|
|
|
|||
|
|
@ -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[])
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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" )
|
||||
|
|
|
|||
|
|
@ -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){
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue