Merge pull request #4584 from sgiraudot/Property_maps-Add_example-GF

[Small Feature] Custom Property Map Example
This commit is contained in:
Sebastien Loriot 2020-04-07 08:20:40 +02:00 committed by GitHub
commit 7a2754b538
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 136 additions and 1 deletions

View File

@ -3,4 +3,4 @@
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - CGAL and Boost Property Maps" PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - CGAL and Boost Property Maps"
INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/property_map.h INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/property_map.h
EXCLUDE += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Dynamic_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}

View File

@ -6,6 +6,8 @@ namespace CGAL {
\anchor chapterProperty_map \anchor chapterProperty_map
\cgalAutoToc
\authors Andreas Fabri and Laurent Saboret \authors Andreas Fabri and Laurent Saboret
\section Property_mapA A Short Introduction to the Boost Property Maps Library \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. 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} \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 */ } /* namespace CGAL */

View File

@ -2,4 +2,5 @@
\example Point_set_processing_3/remove_outliers_example.cpp \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/read_write_xyz_point_set_example.cpp
\example Point_set_processing_3/average_spacing_example.cpp \example Point_set_processing_3/average_spacing_example.cpp
\example Property_map/custom_property_map.cpp
*/ */

View File

@ -32,4 +32,10 @@ endif()
create_single_source_cgal_program( "dynamic_properties.cpp" ) 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()

View File

@ -0,0 +1,112 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/jet_estimate_normals.h>
#include <CGAL/mst_orient_normals.h>
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<Point_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()
{
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];
// 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[3 *nb_points];
// we use a vector of indices to access arrays
std::vector<std::size_t> 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<CGAL::Sequential_tag>
(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;
return EXIT_SUCCESS;
}