diff --git a/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt b/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt
index 5d996b0ceed..90502e1bdf6 100644
--- a/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt
+++ b/Advancing_front_surface_reconstruction/doc/Advancing_front_surface_reconstruction/Advancing_front_surface_reconstruction.txt
@@ -47,6 +47,9 @@ not provide any guarantee on the topology of the surface.
We describe next the algorithm and provide examples.
+\note A \ref tuto_reconstruction "detailed tutorial on surface reconstruction"
+is provided with a guide to choose the most appropriate method along
+with pre- and post-processing.
\section AFSR_Definitions Definitions and the Algorithm
diff --git a/Documentation/doc/Documentation/Doxyfile.in b/Documentation/doc/Documentation/Doxyfile.in
index c4efea1bc5e..e90d8b66149 100644
--- a/Documentation/doc/Documentation/Doxyfile.in
+++ b/Documentation/doc/Documentation/Doxyfile.in
@@ -11,7 +11,8 @@ HTML_HEADER = ${CGAL_DOC_HEADER}
LAYOUT_FILE = ${CGAL_DOC_RESOURCE_DIR}/DoxygenLayout.xml
GENERATE_TAGFILE = ${CGAL_DOC_TAG_GEN_DIR}/Manual.tag
EXAMPLE_PATH = ${CGAL_Convex_hull_2_EXAMPLE_DIR} \
- ${CGAL_Kernel_23_EXAMPLE_DIR}
+ ${CGAL_Kernel_23_EXAMPLE_DIR} \
+ ${CGAL_Poisson_surface_reconstruction_3_EXAMPLE_DIR}
FILTER_PATTERNS = *.txt=${CMAKE_BINARY_DIR}/pkglist_filter
HTML_EXTRA_FILES += ${CGAL_DOC_RESOURCE_DIR}/hacks.js \
diff --git a/Documentation/doc/Documentation/Tutorials/Tutorial_reconstruction.txt b/Documentation/doc/Documentation/Tutorials/Tutorial_reconstruction.txt
new file mode 100644
index 00000000000..5601d6be977
--- /dev/null
+++ b/Documentation/doc/Documentation/Tutorials/Tutorial_reconstruction.txt
@@ -0,0 +1,294 @@
+namespace CGAL {
+/*!
+\example Poisson_surface_reconstruction_3/tutorial_example.cpp
+*/
+
+/*!
+
+\page tuto_reconstruction Surface Reconstruction from Point Clouds
+\cgalAutoToc
+
+\author Simon Giraudot
+
+Surface reconstruction from point clouds is a core topic in geometry
+processing \cgalCite{cgal:btsag-asosr-16}. It is an ill-posed problem:
+there is an infinite number of surfaces that approximate a single
+point cloud and a point cloud does not define a surface in
+itself. Thus additional assumptions and constraints must be defined by
+the user and reconstruction can be achieved in many different
+ways. This tutorials provides guidances on how to use the different
+algorithms of \cgal to effectively perform surface reconstruction.
+
+\section TutorialsReconstruction_algorithms Which algorithm should I use?
+
+\cgal offers three different algorithms for surface reconstruction:
+
+- \ref Chapter_Poisson_Surface_Reconstruction "Poisson Surface Reconstruction"
+- \ref Chapter_Advancing_Front_Surface_Reconstruction "Advancing Front Surface Reconstruction"
+- \ref Chapter_Scale_space_reconstruction "Scale Space Surface Reconstruction"
+
+
+Because reconstruction is an ill-posed problem, it must be regularized
+via prior knowledge. Differences in prior leads to different
+algorithms, and choosing one or the other of these methods is
+dependent on these priors. For example, Poisson always generates
+closed shapes (bounding a volume) and requires normals but does not
+interpolate input points (the output surface does not pass exactly
+through the input points). The following table lists different
+properties of the input and output to help the user choose the method
+best suited to each problem:
+
+
|
-2
+2
|
0.8
|
@@ -461,16 +466,16 @@ for the Bimba con Nastrino point set simplified to 100k points.
We measure the memory occupancy for the reconstruction of the full Bimba con Nastrino point
set (1.8 millions points) as well as for simplified versions.\n
-The Poisson implicit function computation has a memory peak when solving the Poisson linear
+The Poisson implicit function computation has a memory peak when solving the Poisson linear
system using the sparse linear solver.
|
|
-Number of points (x1000)
+Number of points (x1000)
|
-Memory occupancy (MBytes)
+Memory occupancy (MBytes)
|
|
@@ -509,19 +514,19 @@ Memory occupancy (MBytes)
\subsection SurfReconstPerfPSS Point Set Simplification
Due to the memory limitations described above, we recommend to simplify the point sets captured by laser scanners.\n
-We measure the reconstruction error for the Bimba con Nastrino point set (1.6M points) as well as for
-simplified versions. All reconstructions use the recommended contouring parameter
+We measure the reconstruction error for the Bimba con Nastrino point set (1.6M points) as well as for
+simplified versions. All reconstructions use the recommended contouring parameter
`approximation distance = 0.25 * the input point` set's average spacing.
-The reconstruction error is expressed as the average distance from input points to the reconstructed surface in mm
+The reconstruction error is expressed as the average distance from input points to the reconstructed surface in mm
(the Bimba con Nastrino statue is 324 mm tall).
|
|
-Number of points (x1000)
+Number of points (x1000)
|
-Reconstruction error (mm)
+Reconstruction error (mm)
|
|
|
@@ -530,7 +535,7 @@ Reconstruction error (mm)
0.27
|
|
-120
+120
|
0.15
|
@@ -570,10 +575,10 @@ as well as for simplified versions.
\section SurfReconstDesignHistory Design and Implementation History
-The initial implementation was essentially done by Laurent Saboret, guided by Pierre Alliez and Ga\"el Guennebaud.
+The initial implementation was essentially done by Laurent Saboret, guided by Pierre Alliez and Ga\"el Guennebaud.
For later releases of the package Andreas Fabri worked on performance improvements, and Laurent Rineau added the
two passes for dealing with holes.
-*/
+*/
} /* namespace CGAL */
diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt
index 85259f8bd2f..f2af58022ab 100644
--- a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt
+++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/CMakeLists.txt
@@ -31,11 +31,13 @@ if ( CGAL_FOUND )
CGAL_target_use_Eigen(poisson_reconstruction)
create_single_source_cgal_program( "poisson_reconstruction_function.cpp" )
CGAL_target_use_Eigen(poisson_reconstruction_function)
+ create_single_source_cgal_program( "tutorial_example.cpp" )
+ CGAL_target_use_Eigen(tutorial_example)
else()
message(STATUS "NOTICE: The examples need Eigen 3.1 (or greater) will not be compiled.")
endif()
-
+
else()
message(STATUS "NOTICE: This program requires the CGAL library, and will not be compiled.")
diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cmd b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cmd
new file mode 100644
index 00000000000..12b759aa160
--- /dev/null
+++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cmd
@@ -0,0 +1,3 @@
+data/kitten.xyz
+data/kitten.xyz 1
+data/kitten.xyz 2
diff --git a/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cpp b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cpp
new file mode 100644
index 00000000000..a51c9db41a0
--- /dev/null
+++ b/Poisson_surface_reconstruction_3/examples/Poisson_surface_reconstruction_3/tutorial_example.cpp
@@ -0,0 +1,223 @@
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+
+// types
+typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+typedef Kernel::FT FT;
+typedef Kernel::Point_3 Point_3;
+typedef Kernel::Vector_3 Vector_3;
+typedef Kernel::Sphere_3 Sphere_3;
+typedef CGAL::Point_set_3 Point_set;
+
+int main(int argc, char*argv[])
+{
+ ///////////////////////////////////////////////////////////////////
+ //! [Reading input]
+
+ Point_set points;
+
+ if (argc < 2)
+ {
+ std::cerr << "Usage: " << argv[0] << " [input.xyz/off/ply/las]" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ const char* input_file = argv[1];
+ std::ifstream stream (input_file, std::ios_base::binary);
+ if (!stream)
+ {
+ std::cerr << "Error: cannot read file " << input_file << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ stream >> points;
+
+ std::cout << "Read " << points.size () << " point(s)" << std::endl;
+ if (points.empty())
+ return EXIT_FAILURE;
+
+ //! [Reading input]
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //! [Outlier removal]
+
+ CGAL::remove_outliers (points,
+ 24, // Number of neighbors considered for evaluation
+ points.parameters().threshold_percent (5.0)); // Percentage of points to remove
+
+ std::cout << points.number_of_removed_points()
+ << " point(s) are outliers." << std::endl;
+
+ // Applying point set processing algorithm to a CGAL::Point_set_3
+ // object does not erase the points from memory but place them in
+ // the garbage of the object: memory can be freeed by the user.
+ points.collect_garbage();
+
+ //! [Outlier removal]
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //! [Simplification]
+
+ // Compute average spacing using neighborhood of 6 points
+ double spacing = CGAL::compute_average_spacing (points, 6);
+
+ // Simplify using a grid of size 2 * average spacing
+ CGAL::grid_simplify_point_set (points, 2. * spacing);
+
+ std::cout << points.number_of_removed_points()
+ << " point(s) removed after simplification." << std::endl;
+
+ points.collect_garbage();
+
+ //! [Simplification]
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //! [Smoothing]
+
+ CGAL::jet_smooth_point_set (points, 24);
+
+ //! [Smoothing]
+ ///////////////////////////////////////////////////////////////////
+
+ unsigned int reconstruction_choice
+ = (argc < 3 ? 0 : atoi(argv[2]));
+
+ if (reconstruction_choice == 0) // Poisson
+ {
+ ///////////////////////////////////////////////////////////////////
+ //! [Normal estimation]
+
+ CGAL::jet_estimate_normals
+ (points, 24); // Use 24 neighbors
+
+ // Orientation of normals, returns iterator to first unoriented point
+ typename Point_set::iterator unoriented_points_begin =
+ CGAL::mst_orient_normals(points, 24); // Use 24 neighbors
+
+ points.remove (unoriented_points_begin, points.end());
+
+ //! [Normal estimation]
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //! [Poisson reconstruction]
+
+ CGAL::Surface_mesh output_mesh;
+ CGAL::poisson_surface_reconstruction_delaunay
+ (points.begin(), points.end(),
+ points.point_map(), points.normal_map(),
+ output_mesh, spacing);
+
+ //! [Poisson reconstruction]
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //! [Output poisson]
+
+ std::ofstream f ("out.ply", std::ios_base::binary);
+ CGAL::set_binary_mode (f);
+ CGAL::write_ply (f, output_mesh);
+ f.close ();
+
+ //! [Output poisson]
+ ///////////////////////////////////////////////////////////////////
+ }
+ else if (reconstruction_choice == 1) // Advancing front
+ {
+ ///////////////////////////////////////////////////////////////////
+ //! [Advancing front reconstruction]
+
+ typedef std::array Facet; // Triple of indices
+
+ std::vector facets;
+
+ // The function is called using directly the points raw iterators
+ CGAL::advancing_front_surface_reconstruction(points.points().begin(),
+ points.points().end(),
+ std::back_inserter(facets));
+ std::cout << facets.size ()
+ << " facet(s) generated by reconstruction." << std::endl;
+
+ //! [Advancing front reconstruction]
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //! [Output advancing front]
+
+ // copy points for random access
+ std::vector vertices;
+ vertices.reserve (points.size());
+ std::copy (points.points().begin(), points.points().end(), std::back_inserter (vertices));
+
+ CGAL::Surface_mesh output_mesh;
+ CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh (vertices, facets, output_mesh);
+ std::ofstream f ("out.off");
+ f << output_mesh;
+ f.close ();
+
+ //! [Output advancing front]
+ ///////////////////////////////////////////////////////////////////
+ }
+ else if (reconstruction_choice == 2) // Scale space
+ {
+ ///////////////////////////////////////////////////////////////////
+ //! [Scale space reconstruction]
+
+ CGAL::Scale_space_surface_reconstruction_3 reconstruct
+ (points.points().begin(), points.points().end());
+
+ // Smooth using 4 iterations of Jet Smoothing
+ reconstruct.increase_scale (4, CGAL::Scale_space_reconstruction_3::Jet_smoother());
+ // Mesh with the Advancing Front mesher with a maximum facet length of 0.5
+ reconstruct.reconstruct_surface (CGAL::Scale_space_reconstruction_3::Advancing_front_mesher(0.5));
+
+ //! [Scale space reconstruction]
+ ///////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////
+ //! [Output scale space]
+
+ std::ofstream f ("out.off");
+ f << "OFF" << std::endl << points.size () << " "
+ << reconstruct.number_of_facets() << " 0" << std::endl;
+ for (Point_set::Index idx : points)
+ f << points.point (idx) << std::endl;
+ for (const auto& facet : CGAL::make_range (reconstruct.facets_begin(), reconstruct.facets_end()))
+ f << "3 "<< facet << std::endl;
+ f.close ();
+
+ //! [Output scale space]
+ ///////////////////////////////////////////////////////////////////
+ }
+ else // Handle error
+ {
+ std::cerr << "Error: invalid reconstruction id: " << reconstruction_choice << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt b/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt
index db6d7281b90..6b86b672c8f 100644
--- a/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt
+++ b/Scale_space_reconstruction_3/doc/Scale_space_reconstruction_3/Scale_space_reconstruction_3.txt
@@ -1,7 +1,7 @@
namespace CGAL {
/*!
-\mainpage User Manual
+\mainpage User Manual
\anchor Chapter_Scale_space_reconstruction
\anchor chapterScaleSpaceReconstruction3
\cgalAutoToc
@@ -17,6 +17,10 @@ Left: 5760 points on a synthetic knot data set. Right: reconstructed surface mes
A triangulated surface mesh is generated by first computing the point set at a coarse scale, then constructing a mesh of the point set at this scale, and finally reverting the points of the mesh back to their original scale.
+\note A \ref tuto_reconstruction "detailed tutorial on surface reconstruction"
+is provided with a guide to choose the most appropriate method along
+with pre- and post-processing.
+
\section ScaleSpaceReconstruction3secMethod Scale-Space
@@ -174,7 +178,7 @@ We have evaluated the scale-space surface reconstruction method on several data
\cgalFigureAnchor{chapterScaleSpaceReconstruction3figSettings}
-| Data set | Neighbors | Samples | Iterations |
+| Data set | Neighbors | Samples | Iterations |
| ----: | ----: | ----: | ----: |
Mushroom (s) | 10 | 200 | 2 |
Elephant (s) | 15 | 200 | 1 |
@@ -269,6 +273,6 @@ This last example shows how to use the alternative operators [Jet_smoother](@ref
This method was developed by Julie Digne et al. in 2011 \cgalCite{cgal:dmsl-ssmrp-11} and implemented by Thijs van Lankveld at Inria - Sophia Antipolis in 2014.
-*/
+*/
} /* namespace CGAL */
| |