From 2e0de573dda5264c9128cbea6cec0d1f5c4b8273 Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Wed, 18 Mar 2020 15:45:05 +0100 Subject: [PATCH 1/5] Add custom property map example --- .../examples/Property_map/CMakeLists.txt | 6 + .../Property_map/custom_property_map.cpp | 117 ++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 Property_map/examples/Property_map/custom_property_map.cpp diff --git a/Property_map/examples/Property_map/CMakeLists.txt b/Property_map/examples/Property_map/CMakeLists.txt index 19f1e6fa5ed..b01994b8dba 100644 --- a/Property_map/examples/Property_map/CMakeLists.txt +++ b/Property_map/examples/Property_map/CMakeLists.txt @@ -32,4 +32,10 @@ endif() create_single_source_cgal_program( "dynamic_properties.cpp" ) +find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater) +if (EIGEN3_FOUND) + create_single_source_cgal_program( "custom_property_map.cpp" ) + CGAL_target_use_Eigen(custom_property_map) +endif() + diff --git a/Property_map/examples/Property_map/custom_property_map.cpp b/Property_map/examples/Property_map/custom_property_map.cpp new file mode 100644 index 00000000000..fc0f8fbc779 --- /dev/null +++ b/Property_map/examples/Property_map/custom_property_map.cpp @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = Kernel::Point_3; +using Vector_3 = Kernel::Vector_3; +using Generator = CGAL::Random_points_on_sphere_3; + +// Example of readable property map to get CGAL::Point_3 objects from +// 3 coordinate arrays +struct Custom_point_map +{ + using key_type = std::size_t; // The iterator's value type is an index + using value_type = Point_3; // The object manipulated by the algorithm is a Point_3 + using reference = Point_3; // The object does not exist in memory, so there's no reference + using category = boost::readable_property_map_tag; // The property map is only used for reading + + double *x, *y, *z; + + Custom_point_map (double* x = nullptr, double* y = nullptr, double* z = nullptr) + : x(x), y(y), z(z) { } + + // The get() function returns the object expected by the algorithm (here, Point_3) + friend Point_3 get (const Custom_point_map& map, std::size_t idx) + { + return Point_3 (map.x[idx], map.y[idx], map.z[idx]); + } +}; + +// Example of read-write property map to get CGAL::Vector_3 objects from +// a buffer array and put CGAL::Vector_3 values in this buffer +struct Custom_normal_map +{ + using key_type = std::size_t; // The iterator's value type is an index + using value_type = Vector_3; // The object manipulated by the algorithm is a Vector_3 + using reference = Vector_3; // The object does not exist in memory, so there's no reference + using category = boost::read_write_property_map_tag; // The property map is used both + // for reading and writing data + double *buffer; + + Custom_normal_map (double* buffer = nullptr) + : buffer (buffer) { } + + // The get() function returns the object expected by the algorithm (here, Vector_3) + friend Vector_3 get (const Custom_normal_map& map, std::size_t idx) + { + return Vector_3 (map.buffer[idx * 3 ], + map.buffer[idx * 3 + 1], + map.buffer[idx * 3 + 2]); + } + + // The put() function updated the user's data structure from the + // object handled by the algorithm (here Vector_3) + friend void put (const Custom_normal_map& map, std::size_t idx, const Vector_3& vector_3) + { + map.buffer[idx * 3 ] = vector_3.x(); + map.buffer[idx * 3 + 1] = vector_3.y(); + map.buffer[idx * 3 + 2] = vector_3.z(); + } +}; + + +int main() +{ + std::size_t nb_points = 1000; + + // in this example, points are stored as separate coordinate arrays + double* x = new double[nb_points]; + double* y = new double[nb_points]; + double* z = new double[nb_points]; + + // generate random points + Generator generator; + for (std::size_t i = 0; i < nb_points; ++ i) + { + Point_3 p = *(generator ++ ); + x[i] = p.x(); + y[i] = p.y(); + z[i] = p.z(); + } + + // normals are stored as a contiguous double array + double* normals = new double[3 * nb_points]; + + // we use a vector of indices to access arrays + std::vector indices; + indices.reserve (nb_points); + for (std::size_t i = 0; i < nb_points; ++ i) + indices.push_back(i); + + // estimate and orient normals using directly user's data structure + // instead of creating deep copies using Point_3 and Vector_3 + CGAL::jet_estimate_normals + (indices, 12, + CGAL::parameters::point_map (Custom_point_map(x,y,z)). + normal_map (Custom_normal_map(normals))); + + CGAL::mst_orient_normals + (indices, 12, + CGAL::parameters::point_map (Custom_point_map(x,y,z)). + normal_map (Custom_normal_map(normals))); + + // Display first 10 points+normals + for (std::size_t i = 0; i < 10; ++ i) + std::cerr << "Point(" << i << ") = " << x[i] << " " << y[i] << " " << z[i] + << "\tNormal(" << i << ") = " + << normals[3*i] << " " << normals[3*i+1] << " " << normals[3*i+2] << std::endl; + + delete[] x; + delete[] y; + delete[] z; + delete[] normals; + + return EXIT_SUCCESS; +} From 012fed5e44ae5a88793cfbba6c99bd1075dd8ae6 Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Wed, 18 Mar 2020 16:01:14 +0100 Subject: [PATCH 2/5] Update property maps manual --- Property_map/doc/Property_map/Doxyfile.in | 2 +- Property_map/doc/Property_map/Property_map.txt | 16 ++++++++++++++++ Property_map/doc/Property_map/examples.txt | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Property_map/doc/Property_map/Doxyfile.in b/Property_map/doc/Property_map/Doxyfile.in index 2167dbca4fe..a079ae055f4 100644 --- a/Property_map/doc/Property_map/Doxyfile.in +++ b/Property_map/doc/Property_map/Doxyfile.in @@ -3,4 +3,4 @@ PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - CGAL and Boost Property Maps" INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/property_map.h EXCLUDE += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Dynamic_property_map.h -EXAMPLE_PATH = ${CGAL_Point_set_processing_3_EXAMPLE_DIR} +EXAMPLE_PATH += ${CGAL_Point_set_processing_3_EXAMPLE_DIR} diff --git a/Property_map/doc/Property_map/Property_map.txt b/Property_map/doc/Property_map/Property_map.txt index e29a999cf10..06d78d76d2b 100644 --- a/Property_map/doc/Property_map/Property_map.txt +++ b/Property_map/doc/Property_map/Property_map.txt @@ -6,6 +6,8 @@ namespace CGAL { \anchor chapterProperty_map +\cgalAutoToc + \authors Andreas Fabri and Laurent Saboret \section Property_mapA A Short Introduction to the Boost Property Maps Library @@ -55,6 +57,20 @@ The following example reads a point set from an input file and writes it to a fi The following example reads a point set in the `xyz` format and computes the average spacing. %Index, position and color are stored in a tuple and accessed through property maps. \cgalExample{Point_set_processing_3/average_spacing_example.cpp} +\section Property_mapCustom Writing Custom Property Maps + +Property maps are especially useful when using predefined data +structures that are not part of the \cgal library: algorithms written +with property maps can be called on these data structures provided the +user writes the required property maps, without the need to create +deep copies of potentially large data into \cgal formats. + +The following example shows how to write a readable point map and a +read-write normal map to run \cgal normal estimation and orientation +algorithm on raw `double` arrays: +\cgalExample{Property_map/custom_property_map.cpp} + + */ } /* namespace CGAL */ diff --git a/Property_map/doc/Property_map/examples.txt b/Property_map/doc/Property_map/examples.txt index fe5b9e2f71c..30870650f01 100644 --- a/Property_map/doc/Property_map/examples.txt +++ b/Property_map/doc/Property_map/examples.txt @@ -2,4 +2,5 @@ \example Point_set_processing_3/remove_outliers_example.cpp \example Point_set_processing_3/read_write_xyz_point_set_example.cpp \example Point_set_processing_3/average_spacing_example.cpp +\example Property_map/custom_property_map.cpp */ From f7b72e6c0580049d5782a9ea66a8f10ac8a716a0 Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Thu, 19 Mar 2020 14:00:19 +0100 Subject: [PATCH 3/5] Remove new/delete --- .../Property_map/custom_property_map.cpp | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Property_map/examples/Property_map/custom_property_map.cpp b/Property_map/examples/Property_map/custom_property_map.cpp index fc0f8fbc779..dedd0d6dd02 100644 --- a/Property_map/examples/Property_map/custom_property_map.cpp +++ b/Property_map/examples/Property_map/custom_property_map.cpp @@ -3,6 +3,8 @@ #include #include +#define NB_POINTS 1000 + using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_3 = Kernel::Point_3; using Vector_3 = Kernel::Vector_3; @@ -64,16 +66,14 @@ struct Custom_normal_map int main() { - std::size_t nb_points = 1000; - // in this example, points are stored as separate coordinate arrays - double* x = new double[nb_points]; - double* y = new double[nb_points]; - double* z = new double[nb_points]; + double x[NB_POINTS]; + double y[NB_POINTS]; + double z[NB_POINTS]; // generate random points Generator generator; - for (std::size_t i = 0; i < nb_points; ++ i) + for (std::size_t i = 0; i < NB_POINTS; ++ i) { Point_3 p = *(generator ++ ); x[i] = p.x(); @@ -82,12 +82,12 @@ int main() } // normals are stored as a contiguous double array - double* normals = new double[3 * nb_points]; + double normals[3 *NB_POINTS]; // we use a vector of indices to access arrays std::vector indices; - indices.reserve (nb_points); - for (std::size_t i = 0; i < nb_points; ++ i) + indices.reserve (NB_POINTS); + for (std::size_t i = 0; i < NB_POINTS; ++ i) indices.push_back(i); // estimate and orient normals using directly user's data structure @@ -108,10 +108,5 @@ int main() << "\tNormal(" << i << ") = " << normals[3*i] << " " << normals[3*i+1] << " " << normals[3*i+2] << std::endl; - delete[] x; - delete[] y; - delete[] z; - delete[] normals; - return EXIT_SUCCESS; } From de8abc55560604434c09a8e6702a2ef6a2d8a94b Mon Sep 17 00:00:00 2001 From: Simon Giraudot Date: Thu, 19 Mar 2020 15:05:50 +0100 Subject: [PATCH 4/5] Do not use DEFINE --- .../Property_map/custom_property_map.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Property_map/examples/Property_map/custom_property_map.cpp b/Property_map/examples/Property_map/custom_property_map.cpp index dedd0d6dd02..22a923a200d 100644 --- a/Property_map/examples/Property_map/custom_property_map.cpp +++ b/Property_map/examples/Property_map/custom_property_map.cpp @@ -3,8 +3,6 @@ #include #include -#define NB_POINTS 1000 - using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_3 = Kernel::Point_3; using Vector_3 = Kernel::Vector_3; @@ -66,14 +64,16 @@ struct Custom_normal_map int main() { + constexpr std::size_t nb_points = 1000; + // in this example, points are stored as separate coordinate arrays - double x[NB_POINTS]; - double y[NB_POINTS]; - double z[NB_POINTS]; + double x[nb_points]; + double y[nb_points]; + double z[nb_points]; // generate random points Generator generator; - for (std::size_t i = 0; i < NB_POINTS; ++ i) + for (std::size_t i = 0; i < nb_points; ++ i) { Point_3 p = *(generator ++ ); x[i] = p.x(); @@ -82,12 +82,12 @@ int main() } // normals are stored as a contiguous double array - double normals[3 *NB_POINTS]; + double normals[3 *nb_points]; // we use a vector of indices to access arrays std::vector indices; - indices.reserve (NB_POINTS); - for (std::size_t i = 0; i < NB_POINTS; ++ i) + indices.reserve (nb_points); + for (std::size_t i = 0; i < nb_points; ++ i) indices.push_back(i); // estimate and orient normals using directly user's data structure From 20d2770d3a36029d44ce5fbce814395d60789078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 26 Mar 2020 19:39:09 +0100 Subject: [PATCH 5/5] extra run of the script to remove tabs and trailing whitespaces --- Property_map/doc/Property_map/Property_map.txt | 10 +++++----- Property_map/examples/Property_map/CMakeLists.txt | 4 ++-- .../examples/Property_map/custom_property_map.cpp | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Property_map/doc/Property_map/Property_map.txt b/Property_map/doc/Property_map/Property_map.txt index 06d78d76d2b..d2ecf66d1df 100644 --- a/Property_map/doc/Property_map/Property_map.txt +++ b/Property_map/doc/Property_map/Property_map.txt @@ -1,7 +1,7 @@ namespace CGAL { /*! -\mainpage User Manual +\mainpage User Manual \anchor Chapter_CGAL_and_Boost_Property_Maps \anchor chapterProperty_map @@ -27,15 +27,15 @@ Property maps in the Boost manuals: , Vector_3 >`, or as a `boost::tuple<..,Point_3, ..., Vector_3 >`. -This component provides property maps to support these cases: +This component provides property maps to support these cases: - `Identity_property_map` - `First_of_pair_property_map` and `Second_of_pair_property_map` @@ -71,6 +71,6 @@ algorithm on raw `double` arrays: \cgalExample{Property_map/custom_property_map.cpp} -*/ +*/ } /* namespace CGAL */ diff --git a/Property_map/examples/Property_map/CMakeLists.txt b/Property_map/examples/Property_map/CMakeLists.txt index b01994b8dba..d5717d3f5d2 100644 --- a/Property_map/examples/Property_map/CMakeLists.txt +++ b/Property_map/examples/Property_map/CMakeLists.txt @@ -9,7 +9,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() @@ -20,7 +20,7 @@ if ( NOT Boost_FOUND ) message(STATUS "This project requires the Boost library, and will not be compiled.") - return() + return() endif() diff --git a/Property_map/examples/Property_map/custom_property_map.cpp b/Property_map/examples/Property_map/custom_property_map.cpp index 22a923a200d..540bec3cd2d 100644 --- a/Property_map/examples/Property_map/custom_property_map.cpp +++ b/Property_map/examples/Property_map/custom_property_map.cpp @@ -16,7 +16,7 @@ struct Custom_point_map using value_type = Point_3; // The object manipulated by the algorithm is a Point_3 using reference = Point_3; // The object does not exist in memory, so there's no reference using category = boost::readable_property_map_tag; // The property map is only used for reading - + double *x, *y, *z; Custom_point_map (double* x = nullptr, double* y = nullptr, double* z = nullptr) @@ -65,7 +65,7 @@ struct Custom_normal_map int main() { constexpr std::size_t nb_points = 1000; - + // in this example, points are stored as separate coordinate arrays double x[nb_points]; double y[nb_points]; @@ -96,7 +96,7 @@ int main() (indices, 12, CGAL::parameters::point_map (Custom_point_map(x,y,z)). normal_map (Custom_normal_map(normals))); - + CGAL::mst_orient_normals (indices, 12, CGAL::parameters::point_map (Custom_point_map(x,y,z)). @@ -107,6 +107,6 @@ int main() std::cerr << "Point(" << i << ") = " << x[i] << " " << y[i] << " " << z[i] << "\tNormal(" << i << ") = " << normals[3*i] << " " << normals[3*i+1] << " " << normals[3*i+2] << std::endl; - + return EXIT_SUCCESS; }