Merge branch 'master' into Periodic_3_mesh_3-Feature-MBogdanov

This commit is contained in:
Laurent Rineau 2018-06-27 10:33:24 +02:00 committed by GitHub
commit 10a84aa34e
107 changed files with 2725 additions and 605 deletions

View File

@ -32,24 +32,36 @@
#include <CGAL/boost/graph/Euler_operations.h> #include <CGAL/boost/graph/Euler_operations.h>
#include <CGAL/boost/graph/helpers.h> #include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/named_function_params.h>
namespace CGAL { namespace CGAL {
/*! /*!
\ingroup PkgBGLIOFct \ingroup PkgBGLIOFct
writes the graph `g` in the OFF format. writes the graph `g` in the OFF format.
\cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` should be available in `FaceGraph`\cgalParamEnd
* \cgalNamedParamsEnd
\sa Overloads of this function for specific models of the concept `FaceGraph`. \sa Overloads of this function for specific models of the concept `FaceGraph`.
*/ */
template <typename FaceGraph> template <typename FaceGraph, typename NamedParameters>
bool write_off(std::ostream& os, bool write_off(std::ostream& os,
const FaceGraph& g) const FaceGraph& g,
const NamedParameters& np)
{ {
typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor; typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<FaceGraph>::vertices_size_type vertices_size_type; typedef typename boost::graph_traits<FaceGraph>::vertices_size_type vertices_size_type;
typedef typename boost::graph_traits<FaceGraph>::faces_size_type faces_size_type; typedef typename boost::graph_traits<FaceGraph>::faces_size_type faces_size_type;
typename boost::property_map<FaceGraph, CGAL::vertex_point_t>::const_type vpm = get(CGAL::vertex_point,g); typename Polygon_mesh_processing::GetVertexPointMap<FaceGraph, NamedParameters>::const_type
vpm = choose_param(get_param(np, internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, g));
vertices_size_type nv = static_cast<vertices_size_type>(std::distance(vertices(g).first, vertices(g).second)); vertices_size_type nv = static_cast<vertices_size_type>(std::distance(vertices(g).first, vertices(g).second));
faces_size_type nf = static_cast<faces_size_type>(std::distance(faces(g).first, faces(g).second)); faces_size_type nf = static_cast<faces_size_type>(std::distance(faces(g).first, faces(g).second));
@ -78,21 +90,45 @@ bool write_off(std::ostream& os,
\sa Overloads of this function for specific models of the concept `FaceGraph`. \sa Overloads of this function for specific models of the concept `FaceGraph`.
*/ */
template <typename FaceGraph, typename NamedParameters>
bool write_off(const char* fname,
const FaceGraph& g,
const NamedParameters& np)
{
std::ofstream out(fname);
if(out.good()){
return write_off(out,g, np);
}
return false;
}
template <typename FaceGraph, typename NamedParameters>
bool write_off(const std::string& fname,
const FaceGraph& g,
const NamedParameters& np)
{ return write_off(fname.c_str(), g, np); }
template <typename FaceGraph>
bool write_off(std::ostream& os,
const FaceGraph& g)
{
return write_off(os, g,
parameters::all_default());
}
template <typename FaceGraph> template <typename FaceGraph>
bool write_off(const char* fname, bool write_off(const char* fname,
const FaceGraph& g) const FaceGraph& g)
{ {
std::ofstream out(fname); return write_off(fname,g,
if(out.good()){ parameters::all_default());
return write_off(out,g);
}
return false;
} }
template <typename FaceGraph> template <typename FaceGraph>
bool write_off(const std::string& fname, bool write_off(const std::string& fname,
const FaceGraph& g) const FaceGraph& g)
{ return write_off(fname.c_str(), g); } { return write_off(fname, g,
parameters::all_default()); }
namespace internal { namespace read_off_tools { namespace internal { namespace read_off_tools {
@ -122,14 +158,21 @@ inline std::string next_non_comment(std::istream& is)
/*! /*!
\ingroup PkgBGLIOFct \ingroup PkgBGLIOFct
reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash, and lines with whitespace. reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash, and lines with whitespace.
\cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` should be available in `FaceGraph`\cgalParamEnd
* \cgalNamedParamsEnd
\sa Overloads of this function for specific models of the concept `FaceGraph`. \sa Overloads of this function for specific models of the concept `FaceGraph`.
\pre The data must represent a 2-manifold \pre The data must represent a 2-manifold
\attention The graph `g` is not cleared, and the data from the stream are added. \attention The graph `g` is not cleared, and the data from the stream are added.
*/ */
template <typename FaceGraph> template <typename FaceGraph, typename NamedParameters>
bool read_off(std::istream& is, bool read_off(std::istream& is,
FaceGraph& g) FaceGraph& g,
NamedParameters np)
{ {
using namespace internal::read_off_tools; using namespace internal::read_off_tools;
@ -137,9 +180,11 @@ bool read_off(std::istream& is,
typedef typename boost::graph_traits<FaceGraph>::vertices_size_type vertices_size_type; typedef typename boost::graph_traits<FaceGraph>::vertices_size_type vertices_size_type;
typedef typename boost::graph_traits<FaceGraph>::faces_size_type faces_size_type; typedef typename boost::graph_traits<FaceGraph>::faces_size_type faces_size_type;
typedef typename boost::property_map<FaceGraph, CGAL::vertex_point_t>::type Vpm; typedef typename Polygon_mesh_processing::GetVertexPointMap<FaceGraph, NamedParameters>::type Vpm;
typedef typename boost::property_traits<Vpm>::value_type Point_3; typedef typename boost::property_traits<Vpm>::value_type Point_3;
Vpm vpm = get(CGAL::vertex_point,g);
Vpm vpm = choose_param(get_param(np, internal_np::vertex_point),
get_property_map(CGAL::vertex_point, g));
vertices_size_type nv, nvf; vertices_size_type nv, nvf;
faces_size_type nf; faces_size_type nf;
int ignore; int ignore;
@ -182,6 +227,12 @@ bool read_off(std::istream& is,
return true; return true;
} }
template <typename FaceGraph>
bool read_off(std::istream& is,
FaceGraph& g)
{
return read_off(is, g, parameters::all_default());
}
/*! /*!
\ingroup PkgBGLIOFct \ingroup PkgBGLIOFct
@ -191,36 +242,52 @@ bool read_off(std::istream& is,
\attention The graph `g` is not cleared, and the data from the stream are added. \attention The graph `g` is not cleared, and the data from the stream are added.
*/ */
template <typename FaceGraph> template <typename FaceGraph, typename NamedParameters>
bool read_off(const char* fname, bool read_off(const char* fname,
FaceGraph& g) FaceGraph& g,
NamedParameters np)
{ {
std::ifstream in(fname); std::ifstream in(fname);
if(in.good()){ if(in.good()){
return read_off(in, g); return read_off(in, g, np);
} }
return false; return false;
} }
template <typename FaceGraph> template <typename FaceGraph>
bool read_off(const std::string& fname, bool read_off(const char* fname,
FaceGraph& g) FaceGraph& g)
{ return read_off(fname.c_str(), g); } {
return read_off(fname, g, parameters::all_default());
}
template <typename FaceGraph, typename NamedParameters>
bool read_off(const std::string& fname,
FaceGraph& g,
NamedParameters np)
{ return read_off(fname.c_str(), g, np); }
template <typename FaceGraph> template <typename FaceGraph>
bool read_off(const std::string& fname,
FaceGraph& g)
{ return read_off(fname, g, parameters::all_default()); }
template <typename FaceGraph, typename NamedParameters>
bool write_inp(std::ostream& os, bool write_inp(std::ostream& os,
const FaceGraph& g, const FaceGraph& g,
std::string name, std::string name,
std::string type) std::string type,
const NamedParameters& np)
{ {
typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor; typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
typedef typename boost::graph_traits<FaceGraph>::vertices_size_type vertices_size_type; typedef typename boost::graph_traits<FaceGraph>::vertices_size_type vertices_size_type;
typedef typename boost::property_map<FaceGraph, CGAL::vertex_point_t>::const_type VPM; typedef typename Polygon_mesh_processing::GetVertexPointMap<FaceGraph, NamedParameters>::const_type VPM;
typedef typename boost::property_traits<VPM>::value_type Point_3; typedef typename boost::property_traits<VPM>::value_type Point_3;
VPM vpm = get(CGAL::vertex_point,g); VPM vpm = choose_param(get_param(np, internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, g));
os << "*Part, name=" << name << "\n*Node\n"; os << "*Part, name=" << name << "\n*Node\n";
boost::container::flat_map<vertex_descriptor,vertices_size_type> reindex; boost::container::flat_map<vertex_descriptor,vertices_size_type> reindex;
@ -242,8 +309,15 @@ bool write_inp(std::ostream& os,
os << "*End Part"<< std::endl; os << "*End Part"<< std::endl;
return os.good(); return os.good();
} }
// conveniance overload
template <typename FaceGraph>
bool write_inp(std::ostream& os,
const FaceGraph& g,
std::string name,
std::string type)
{
return write_inp(os, g, name, type, parameters::all_default());
}
} // namespace CGAL } // namespace CGAL
#endif // CGAL_BOOST_GRAPH_IO_H #endif // CGAL_BOOST_GRAPH_IO_H

View File

@ -23,14 +23,6 @@
#include <CGAL/Kernel_traits.h> #include <CGAL/Kernel_traits.h>
#include <CGAL/Origin.h> #include <CGAL/Origin.h>
#include <CGAL/Default_diagonalize_traits.h>
#if defined(CGAL_EIGEN3_ENABLED)
#include <CGAL/Eigen_svd.h>
#elif defined(CGAL_LAPACK_ENABLED)
#include <CGAL/Lapack_svd.h>
#endif
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <CGAL/boost/graph/properties.h> #include <CGAL/boost/graph/properties.h>
@ -41,6 +33,15 @@
#include <boost/version.hpp> #include <boost/version.hpp>
namespace CGAL { namespace CGAL {
// forward declarations to avoid dependency to Solver_interface
template <typename FT, unsigned int dim>
class Default_diagonalize_traits;
class Eigen_svd;
class Lapack_svd;
//
//helper classes //helper classes
template<typename PolygonMesh, typename PropertyTag> template<typename PolygonMesh, typename PropertyTag>
class property_map_selector class property_map_selector

View File

@ -65,6 +65,7 @@ CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_u
CGAL_add_named_parameter(outward_orientation_t, outward_orientation, outward_orientation) CGAL_add_named_parameter(outward_orientation_t, outward_orientation, outward_orientation)
CGAL_add_named_parameter(overlap_test_t, overlap_test, do_overlap_test_of_bounded_sides) CGAL_add_named_parameter(overlap_test_t, overlap_test, do_overlap_test_of_bounded_sides)
CGAL_add_named_parameter(preserve_genus_t, preserve_genus, preserve_genus) CGAL_add_named_parameter(preserve_genus_t, preserve_genus, preserve_genus)
CGAL_add_named_parameter(apply_per_connected_component_t, apply_per_connected_component, apply_per_connected_component)
CGAL_add_named_parameter(projection_functor_t, projection_functor, projection_functor) CGAL_add_named_parameter(projection_functor_t, projection_functor, projection_functor)
// List of named parameters that we use in the package 'Surface Mesh Simplification' // List of named parameters that we use in the package 'Surface Mesh Simplification'
@ -85,6 +86,7 @@ CGAL_add_named_parameter(query_point_t, query_point_map, query_point_map)
CGAL_add_named_parameter(normal_t, normal_map, normal_map) CGAL_add_named_parameter(normal_t, normal_map, normal_map)
CGAL_add_named_parameter(diagonalize_traits_t, diagonalize_traits, diagonalize_traits) CGAL_add_named_parameter(diagonalize_traits_t, diagonalize_traits, diagonalize_traits)
CGAL_add_named_parameter(svd_traits_t, svd_traits, svd_traits) CGAL_add_named_parameter(svd_traits_t, svd_traits, svd_traits)
CGAL_add_named_parameter(callback_t, callback, callback)
CGAL_add_named_parameter(sharpness_angle_t, sharpness_angle, sharpness_angle) CGAL_add_named_parameter(sharpness_angle_t, sharpness_angle, sharpness_angle)
CGAL_add_named_parameter(edge_sensitivity_t, edge_sensitivity, edge_sensitivity) CGAL_add_named_parameter(edge_sensitivity_t, edge_sensitivity, edge_sensitivity)
CGAL_add_named_parameter(neighbor_radius_t, neighbor_radius, neighbor_radius) CGAL_add_named_parameter(neighbor_radius_t, neighbor_radius, neighbor_radius)

View File

@ -19,5 +19,4 @@ Number_types
Profiling_tools Profiling_tools
Property_map Property_map
STL_Extension STL_Extension
Solver_interface
Stream_support Stream_support

View File

@ -87,7 +87,8 @@ void test(const NamedParameters& np)
assert(get_param(np, CGAL::internal_np::weight_calculator).v == 39); assert(get_param(np, CGAL::internal_np::weight_calculator).v == 39);
assert(get_param(np, CGAL::internal_np::preserve_genus).v == 40); assert(get_param(np, CGAL::internal_np::preserve_genus).v == 40);
assert(get_param(np, CGAL::internal_np::verbosity_level).v == 41); assert(get_param(np, CGAL::internal_np::verbosity_level).v == 41);
assert(get_param(np, CGAL::internal_np::projection_functor).v == 42); assert(get_param(np, CGAL::internal_np::apply_per_connected_component).v == 42);
assert(get_param(np, CGAL::internal_np::projection_functor).v == 43);
// Test types // Test types
@ -153,7 +154,8 @@ void test(const NamedParameters& np)
check_same_type<39>(get_param(np, CGAL::internal_np::weight_calculator)); check_same_type<39>(get_param(np, CGAL::internal_np::weight_calculator));
check_same_type<40>(get_param(np, CGAL::internal_np::preserve_genus)); check_same_type<40>(get_param(np, CGAL::internal_np::preserve_genus));
check_same_type<41>(get_param(np, CGAL::internal_np::verbosity_level)); check_same_type<41>(get_param(np, CGAL::internal_np::verbosity_level));
check_same_type<42>(get_param(np, CGAL::internal_np::projection_functor)); check_same_type<42>(get_param(np, CGAL::internal_np::apply_per_connected_component));
check_same_type<43>(get_param(np, CGAL::internal_np::projection_functor));
} }
int main() int main()
@ -204,7 +206,8 @@ int main()
.weight_calculator(A<39>(39)) .weight_calculator(A<39>(39))
.preserve_genus(A<40>(40)) .preserve_genus(A<40>(40))
.verbosity_level(A<41>(41)) .verbosity_level(A<41>(41))
.projection_functor(A<42>(42)) .apply_per_connected_component(A<42>(42))
.projection_functor(A<43>(43))
); );
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -137,6 +137,8 @@ for display in Maplesoft's Maple.
\cgalExample{Approximate_min_ellipsoid_d/ellipsoid_for_maple.cpp} \cgalExample{Approximate_min_ellipsoid_d/ellipsoid_for_maple.cpp}
\note This class requires the \ref thirdpartyEigen library.
*/ */
template< typename Traits > template< typename Traits >
class Approximate_min_ellipsoid_d { class Approximate_min_ellipsoid_d {

View File

@ -13,6 +13,7 @@
\cgalPkgSummaryEnd \cgalPkgSummaryEnd
\cgalPkgShortInfoBegin \cgalPkgShortInfoBegin
\cgalPkgSince{1.1} \cgalPkgSince{1.1}
\cgalPkgDependsOn{\ref thirdpartyEigen}
\cgalPkgBib{cgal:fghhs-bv} \cgalPkgBib{cgal:fghhs-bv}
\cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgDemo{2D Bounding Volumes,bounding_volumes_2.zip} \cgalPkgDemo{2D Bounding Volumes,bounding_volumes_2.zip}

View File

@ -12,10 +12,18 @@ if ( CGAL_FOUND )
include_directories (BEFORE "../../include") include_directories (BEFORE "../../include")
# Use Eigen
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif()
# create a target per cppfile # create a target per cppfile
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach(cppfile ${cppfiles}) foreach(cppfile ${cppfiles})
if(NOT (${cppfile} STREQUAL "ellipsoid.cpp") OR EIGEN3_FOUND)
create_single_source_cgal_program( "${cppfile}" ) create_single_source_cgal_program( "${cppfile}" )
endif()
endforeach() endforeach()
else() else()

View File

@ -16,10 +16,18 @@ if ( CGAL_FOUND )
include_directories (BEFORE "../../include") include_directories (BEFORE "../../include")
# Use Eigen
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif()
# create a target per cppfile # create a target per cppfile
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach(cppfile ${cppfiles}) foreach(cppfile ${cppfiles})
if(NOT (${cppfile} STREQUAL "Approximate_min_ellipsoid_d.cpp") OR EIGEN3_FOUND)
create_single_source_cgal_program( "${cppfile}" ) create_single_source_cgal_program( "${cppfile}" )
endif()
endforeach() endforeach()
else() else()

View File

@ -25,6 +25,14 @@ find_package(CGAL QUIET COMPONENTS Core)
if ( CGAL_FOUND ) if ( CGAL_FOUND )
include( ${CGAL_USE_FILE} ) include( ${CGAL_USE_FILE} )
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
else()
message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.")
return()
endif()
find_package(IPE 6) find_package(IPE 6)
if ( IPE_FOUND ) if ( IPE_FOUND )

View File

@ -39,6 +39,16 @@ find_package(TBB QUIET)
find_package(OpenCV QUIET) find_package(OpenCV QUIET)
# Use Eigen
find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater)
if (NOT EIGEN3_FOUND)
message(STATUS "This project requires the Eigen library, and will not be compiled.")
return()
else()
include( ${EIGEN3_USE_FILE} )
endif()
# include for local directory # include for local directory
include_directories( BEFORE include ) include_directories( BEFORE include )

View File

@ -184,10 +184,9 @@ public:
algorithm. Possible values are `Parallel_tag` (default value is %CGAL algorithm. Possible values are `Parallel_tag` (default value is %CGAL
is linked with TBB) or `Sequential_tag` (default value otherwise). is linked with TBB) or `Sequential_tag` (default value otherwise).
\tparam DiagonalizeTraits model of `DiagonalizeTraits` used for \tparam DiagonalizeTraits model of `DiagonalizeTraits` used for
matrix diagonalization. It can be omitted: if Eigen 3 (or greater) matrix diagonalization. It can be omitted if Eigen 3 (or greater)
is available and `CGAL_EIGEN3_ENABLED` is defined then an overload is available and `CGAL_EIGEN3_ENABLED` is defined. In that case,
using `Eigen_diagonalize_traits` is provided. Otherwise, the an overload using `Eigen_diagonalize_traits` is provided.
internal implementation `Diagonalize_traits` is used.
\param input point range. \param input point range.
\param point_map property map to access the input points. \param point_map property map to access the input points.

View File

@ -87,10 +87,8 @@ namespace Classification {
is linked with TBB) or `Sequential_tag` (default value otherwise). is linked with TBB) or `Sequential_tag` (default value otherwise).
\tparam DiagonalizeTraits model of `DiagonalizeTraits` used for \tparam DiagonalizeTraits model of `DiagonalizeTraits` used for
matrix diagonalization. It can be omitted: if Eigen 3 (or greater) matrix diagonalization. It can be omitted: if Eigen 3 (or greater)
is available and `CGAL_EIGEN3_ENABLED` is defined then an overload is available and `CGAL_EIGEN3_ENABLED` is defined: in that case, an
using `Eigen_diagonalize_traits` is provided. Otherwise, the overload using `Eigen_diagonalize_traits` is provided.
internal implementation `Diagonalize_traits` is used.
*/ */
template <typename GeomTraits, template <typename GeomTraits,
typename PointRange, typename PointRange,

View File

@ -30,7 +30,6 @@
#include <CGAL/Search_traits_3.h> #include <CGAL/Search_traits_3.h>
#include <CGAL/Fuzzy_sphere.h> #include <CGAL/Fuzzy_sphere.h>
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/Default_diagonalize_traits.h>
#include <CGAL/centroid.h> #include <CGAL/centroid.h>
#include <CGAL/grid_simplify_point_set.h> #include <CGAL/grid_simplify_point_set.h>
#include <CGAL/squared_distance_3.h> #include <CGAL/squared_distance_3.h>

View File

@ -16,10 +16,20 @@ if ( CGAL_FOUND )
include_directories (BEFORE "../../include") include_directories (BEFORE "../../include")
# Use Eigen
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif()
# create a target per cppfile # create a target per cppfile
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach(cppfile ${cppfiles}) foreach(cppfile ${cppfiles})
if(NOT (${cppfile} STREQUAL "random_points_in_tetrahedral_mesh_3.cpp")
OR NOT (${cppfile} STREQUAL "random_points_on_tetrahedral_mesh_3.cpp")
OR EIGEN3_FOUND)
create_single_source_cgal_program( "${cppfile}" ) create_single_source_cgal_program( "${cppfile}" )
endif()
endforeach() endforeach()
else() else()

View File

@ -16,10 +16,18 @@ if ( CGAL_FOUND )
include_directories (BEFORE "../../include") include_directories (BEFORE "../../include")
# Use Eigen
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
endif()
# create a target per cppfile # create a target per cppfile
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach(cppfile ${cppfiles}) foreach(cppfile ${cppfiles})
if(NOT (${cppfile} STREQUAL "generic_random_test.cpp") OR EIGEN3_FOUND)
create_single_source_cgal_program( "${cppfile}" ) create_single_source_cgal_program( "${cppfile}" )
endif()
endforeach() endforeach()
else() else()

View File

@ -13,6 +13,14 @@ find_package(CGAL COMPONENTS Qt5 Core)
include(${CGAL_USE_FILE}) include(${CGAL_USE_FILE})
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
else()
message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.")
return()
endif()
find_package(Qt5 QUIET COMPONENTS Xml Script OpenGL Svg) find_package(Qt5 QUIET COMPONENTS Xml Script OpenGL Svg)
include_directories (BEFORE ../../include) include_directories (BEFORE ../../include)

View File

@ -1,7 +1,6 @@
Release History Release History
=============== ===============
Release 4.13 Release 4.13
------------ ------------
@ -66,8 +65,23 @@ Release date: September 2018
to reflect the real needs of the code (some types and operators were used to reflect the real needs of the code (some types and operators were used
in the code but did not appear in the concepts). in the code but did not appear in the concepts).
### Point Set Processing
- Added a callback mechanism for functions
`CGAL::bilateral_smooth_point_set()`,
`CGAL::compute_average_spacing()`,
`CGAL::grid_simplify_point_set()`,
`CGAL::hierarchy_simplify_point_set()`,
`CGAL::jet_estimate_normals()`, `CGAL::jet_smooth_point_set()`,
`CGAL::pca_estimate_normals()`, `CGAL::remove_outliers()` and
`CGAL::wlop_simplify_and_regularize_point_set()`.
### Polygon Mesh Processing ### Polygon Mesh Processing
- Added a new named parameter for stitching that allows to perform
this operation per connected component instead of globally
- Added a function, `CGAL::Polygon_mesh_processing::transform()`, to apply a transformation to a mesh. - Added a function, `CGAL::Polygon_mesh_processing::transform()`, to apply a transformation to a mesh.
- Constrained vertices are now guaranteed to be kept in the mesh after calling `isotropic_remeshing()` - Constrained vertices are now guaranteed to be kept in the mesh after calling `isotropic_remeshing()`
@ -116,6 +130,19 @@ Release date: September 2018
- Added the function `Mesh_domain_with_polyline_features_3::add_corner()`, which allows users - Added the function `Mesh_domain_with_polyline_features_3::add_corner()`, which allows users
to add a single corner (that is not incident to any polyline) to the mesh complex. to add a single corner (that is not incident to any polyline) to the mesh complex.
- **Breaking change**: `CGAL::lloyd_optimize_mesh_3` now depends on
the _Eigen_ library.
### Estimation of Local Differential Properties of Point-Sampled Surfaces Reference
- **Breaking change**: `CGAL::Monge_via_jet_fitting` now depends on
the _Eigen_ library.
### Bounding Volumes
- **Breaking change**: `CGAL::Approximate_min_ellipsoid_d` now
depends on the _Eigen_ library.
### CGAL and the Boost Graph Library (BGL) ### CGAL and the Boost Graph Library (BGL)
- Added a helper function, `CGAL::is_valid_polygon_mesh`, that checks the - Added a helper function, `CGAL::is_valid_polygon_mesh`, that checks the
@ -124,6 +151,13 @@ Release date: September 2018
- Improved the function `CGAL::Euler::collapse_edge` such that the target - Improved the function `CGAL::Euler::collapse_edge` such that the target
vertex of the collapsed edge is now always kept after the collapse. vertex of the collapsed edge is now always kept after the collapse.
### CGAL and Solvers
- **Breaking change**: `CGAL::Diagonalize_traits` is now deprecated
and shouldn't be used, `CGAL::Eigen_diagonalize_traits` (along
with the _Eigen_ library) should be used instead.
Release 4.12 Release 4.12
------------ ------------

View File

@ -195,9 +195,14 @@
#if defined(BOOST_NO_0X_HDR_UNORDERED_SET) || \ #if defined(BOOST_NO_0X_HDR_UNORDERED_SET) || \
defined(BOOST_NO_0X_HDR_UNORDERED_MAP) || \ defined(BOOST_NO_0X_HDR_UNORDERED_MAP) || \
defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) || \ defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) || \
defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) || \
(defined(_MSC_VER) && (_MSC_VER == 1800)) // std::unordered_set is very bad in MSVC2013
#define CGAL_CFG_NO_CPP0X_UNORDERED 1 #define CGAL_CFG_NO_CPP0X_UNORDERED 1
#endif #endif
#if defined( BOOST_NO_0X_HDR_THREAD) || \
defined( BOOST_NO_CXX11_HDR_THREAD)
#define CGAL_CFG_NO_STD_THREAD 1
#endif
#if defined(BOOST_NO_DECLTYPE) || \ #if defined(BOOST_NO_DECLTYPE) || \
defined(BOOST_NO_CXX11_DECLTYPE) || (BOOST_VERSION < 103600) defined(BOOST_NO_CXX11_DECLTYPE) || (BOOST_VERSION < 103600)
#define CGAL_CFG_NO_CPP0X_DECLTYPE 1 #define CGAL_CFG_NO_CPP0X_DECLTYPE 1

View File

@ -29,6 +29,7 @@ algebra algorithm required by the fitting method. The scalar type, `SvdTraits::
\sa `Eigen_svd` \sa `Eigen_svd`
\sa `Monge_form` \sa `Monge_form`
\note This class requires the \ref thirdpartyEigen library.
*/ */
template< typename DataKernel, typename LocalKernel, typename SvdTraits > template< typename DataKernel, typename LocalKernel, typename SvdTraits >
class Monge_via_jet_fitting { class Monge_via_jet_fitting {

View File

@ -13,7 +13,7 @@
\cgalPkgSummaryEnd \cgalPkgSummaryEnd
\cgalPkgShortInfoBegin \cgalPkgShortInfoBegin
\cgalPkgSince{3.3} \cgalPkgSince{3.3}
\cgalPkgDependsOn{\ref PkgSolverSummary} \cgalPkgDependsOn{\ref PkgSolverSummary and \ref thirdpartyEigen}
\cgalPkgBib{cgal:pc-eldp} \cgalPkgBib{cgal:pc-eldp}
\cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgDemo{Polyhedron demo,polyhedron_3.zip} \cgalPkgDemo{Polyhedron demo,polyhedron_3.zip}

View File

@ -33,9 +33,13 @@
bool read_mesh(Surface_mesh& mesh, const std::string& filename); bool read_mesh(Surface_mesh& mesh, const std::string& filename);
template<typename NamedParameters>
bool read_off(Surface_mesh& mesh, const std::string& filename, NamedParameters& np);
bool read_off(Surface_mesh& mesh, const std::string& filename); bool read_off(Surface_mesh& mesh, const std::string& filename);
bool write_mesh(const Surface_mesh& mesh, const std::string& filename); bool write_mesh(const Surface_mesh& mesh, const std::string& filename);
template<typename NamedParameters>
bool write_off(const Surface_mesh& mesh, const std::string& filename, const NamedParameters& np);
bool write_off(const Surface_mesh& mesh, const std::string& filename); bool write_off(const Surface_mesh& mesh, const std::string& filename);

View File

@ -24,7 +24,8 @@
#include "IO.h" #include "IO.h"
#include <stdio.h> #include <stdio.h>
#include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h>
//== IMPLEMENTATION =========================================================== //== IMPLEMENTATION ===========================================================
@ -39,12 +40,13 @@ template <typename T> void read(FILE* in, T& t)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename NamedParameters>
bool read_off_ascii(Surface_mesh& mesh, bool read_off_ascii(Surface_mesh& mesh,
FILE* in, FILE* in,
const bool has_normals, const bool has_normals,
const bool has_texcoords, const bool has_texcoords,
const bool has_colors) const bool has_colors,
NamedParameters& np)
{ {
char line[100], *lp; char line[100], *lp;
unsigned int i, j, items, idx, nc; unsigned int i, j, items, idx, nc;
@ -52,6 +54,9 @@ bool read_off_ascii(Surface_mesh& mesh,
Vec3f p, n, c; Vec3f p, n, c;
Vec2f t; Vec2f t;
Surface_mesh::Vertex v; Surface_mesh::Vertex v;
typename CGAL::Polygon_mesh_processing::GetVertexPointMap<Surface_mesh, NamedParameters>::const_type
vpm = choose_param(get_param(np, CGAL::boost::internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, mesh));
// properties // properties
@ -78,7 +83,8 @@ bool read_off_ascii(Surface_mesh& mesh,
// position // position
items = sscanf(lp, "%f %f %f%n", &p[0], &p[1], &p[2], &nc); items = sscanf(lp, "%f %f %f%n", &p[0], &p[1], &p[2], &nc);
assert(items==3); assert(items==3);
v = mesh.add_vertex((Point)p); Surface_mesh::Vertex v = mesh.add_vertex();
put(vpm, v, (Point)p);
lp += nc; lp += nc;
// normal // normal
@ -146,12 +152,13 @@ bool read_off_ascii(Surface_mesh& mesh,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<typename NamedParameters>
bool read_off_binary(Surface_mesh& mesh, bool read_off_binary(Surface_mesh& mesh,
FILE* in, FILE* in,
const bool has_normals, const bool has_normals,
const bool has_texcoords, const bool has_texcoords,
const bool has_colors) const bool has_colors,
NamedParameters& np)
{ {
unsigned int i, j, idx; unsigned int i, j, idx;
unsigned int nV, nF, nE; unsigned int nV, nF, nE;
@ -169,6 +176,9 @@ bool read_off_binary(Surface_mesh& mesh,
Surface_mesh::Vertex_property<Texture_coordinate> texcoords; Surface_mesh::Vertex_property<Texture_coordinate> texcoords;
if (has_normals) normals = mesh.vertex_property<Normal>("v:normal"); if (has_normals) normals = mesh.vertex_property<Normal>("v:normal");
if (has_texcoords) texcoords = mesh.vertex_property<Texture_coordinate>("v:texcoord"); if (has_texcoords) texcoords = mesh.vertex_property<Texture_coordinate>("v:texcoord");
typename CGAL::Polygon_mesh_processing::GetVertexPointMap<Surface_mesh, NamedParameters>::const_type
vpm = choose_param(get_param(np, CGAL::boost::internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, mesh));
// #Vertice, #Faces, #Edges // #Vertice, #Faces, #Edges
@ -184,7 +194,8 @@ bool read_off_binary(Surface_mesh& mesh,
{ {
// position // position
read(in, p); read(in, p);
v = mesh.add_vertex((Point)p); Surface_mesh::Vertex v = mesh.add_vertex();
put(vpm, v, (Point)p);
// normal // normal
if (has_normals) if (has_normals)
@ -224,8 +235,8 @@ bool read_off_binary(Surface_mesh& mesh,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<typename NamedParameters>
bool read_off(Surface_mesh& mesh, const std::string& filename) bool read_off(Surface_mesh& mesh, const std::string& filename, NamedParameters& np)
{ {
char line[100]; char line[100];
bool has_texcoords = false; bool has_texcoords = false;
@ -274,8 +285,8 @@ bool read_off(Surface_mesh& mesh, const std::string& filename)
// read as ASCII or binary // read as ASCII or binary
bool ok = (is_binary ? bool ok = (is_binary ?
read_off_binary(mesh, in, has_normals, has_texcoords, has_colors) : read_off_binary(mesh, in, has_normals, has_texcoords, has_colors, np) :
read_off_ascii(mesh, in, has_normals, has_texcoords, has_colors)); read_off_ascii(mesh, in, has_normals, has_texcoords, has_colors, np));
fclose(in); fclose(in);

View File

@ -100,6 +100,7 @@ lloyd_optimize_mesh_3(c3t3,
\sa `CGAL::perturb_mesh_3()` \sa `CGAL::perturb_mesh_3()`
\sa `CGAL::odt_optimize_mesh_3()` \sa `CGAL::odt_optimize_mesh_3()`
\note This function requires the \ref thirdpartyEigen library.
*/ */
template<typename C3T3, typename MD> template<typename C3T3, typename MD>

View File

@ -43,7 +43,7 @@
\cgalPkgSummaryEnd \cgalPkgSummaryEnd
\cgalPkgShortInfoBegin \cgalPkgShortInfoBegin
\cgalPkgSince{3.5} \cgalPkgSince{3.5}
\cgalPkgDependsOn{\ref PkgTriangulation3Summary} \cgalPkgDependsOn{\ref PkgTriangulation3Summary and \ref thirdpartyEigen}
\cgalPkgBib{cgal:rty-m3} \cgalPkgBib{cgal:rty-m3}
\cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgDemo{Polyhedron demo,polyhedron_3.zip} \cgalPkgDemo{Polyhedron demo,polyhedron_3.zip}

View File

@ -39,6 +39,15 @@ if ( CGAL_FOUND )
endif( LINK_WITH_TBB ) endif( LINK_WITH_TBB )
endif() endif()
# Use Eigen
find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater)
if (NOT EIGEN3_FOUND)
message(STATUS "This project requires the Eigen library, and will not be compiled.")
return()
else()
include( ${EIGEN3_USE_FILE} )
endif()
set(VTK_LIBS "") set(VTK_LIBS "")
find_package(VTK QUIET COMPONENTS vtkImagingGeneral vtkIOImage NO_MODULE) find_package(VTK QUIET COMPONENTS vtkImagingGeneral vtkIOImage NO_MODULE)
if(VTK_FOUND) if(VTK_FOUND)

View File

@ -57,6 +57,7 @@
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
# include <tbb/parallel_do.h> # include <tbb/parallel_do.h>
# include <tbb/mutex.h>
#endif #endif
#include <functional> #include <functional>

View File

@ -57,11 +57,7 @@
#endif #endif
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
# if TBB_IMPLEMENT_CPP0X # include <tbb/task_scheduler_init.h>
# include <tbb/compat/thread>
# else
# include <thread>
# endif
#endif #endif
#include <boost/format.hpp> #include <boost/format.hpp>

View File

@ -43,7 +43,6 @@
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
# include <tbb/task.h> # include <tbb/task.h>
# include <tbb/tbb.h>
#endif #endif
#include <string> #include <string>

View File

@ -31,7 +31,9 @@
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h> #include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
#include <CGAL/Meshes/Triangulation_mesher_level_traits_3.h> #include <CGAL/Meshes/Triangulation_mesher_level_traits_3.h>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <tbb/tbb.h> #include <tbb/enumerable_thread_specific.h>
#include <tbb/blocked_range.h>
#include <tbb/parallel_for.h>
#endif #endif
#include <CGAL/Meshes/Filtered_deque_container.h> #include <CGAL/Meshes/Filtered_deque_container.h>

View File

@ -34,7 +34,8 @@
#include <CGAL/Mesh_3/Mesher_level.h> #include <CGAL/Mesh_3/Mesher_level.h>
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h> #include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <tbb/tbb.h> #include <tbb/enumerable_thread_specific.h>
#include <tbb/parallel_do.h>
#endif #endif
#include <CGAL/Meshes/Filtered_deque_container.h> #include <CGAL/Meshes/Filtered_deque_container.h>

View File

@ -19,6 +19,15 @@ if ( CGAL_FOUND )
include_directories (BEFORE ../../include) include_directories (BEFORE ../../include)
include_directories (BEFORE ../../../AABB_tree/include) include_directories (BEFORE ../../../AABB_tree/include)
# Use Eigen
find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater)
if (NOT EIGEN3_FOUND)
message(STATUS "This project requires the Eigen library, and will not be compiled.")
return()
else()
include( ${EIGEN3_USE_FILE} )
endif()
create_single_source_cgal_program( "test_boost_has_xxx.cpp" ) create_single_source_cgal_program( "test_boost_has_xxx.cpp" )
create_single_source_cgal_program( "test_c3t3.cpp" ) create_single_source_cgal_program( "test_c3t3.cpp" )
create_single_source_cgal_program( "test_mesh_capsule_var_distance_bound.cpp" ) create_single_source_cgal_program( "test_mesh_capsule_var_distance_bound.cpp" )

View File

@ -10,6 +10,5 @@ Point_set_processing_3
Profiling_tools Profiling_tools
Property_map Property_map
STL_Extension STL_Extension
Solver_interface
Stream_support Stream_support
Surface_mesh Surface_mesh

View File

@ -49,7 +49,7 @@ No default value.
\cgalNPBegin{diagonalize_traits} \anchor PSP_diagonalize_traits \cgalNPBegin{diagonalize_traits} \anchor PSP_diagonalize_traits
is the solver used for diagonalizing covariance matrices.\n is the solver used for diagonalizing covariance matrices.\n
\b Type: a class model of `DiagonalizeTraits`.\n \b Type: a class model of `DiagonalizeTraits`.\n
\b Default: if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined, then `CGAL::Eigen_diagonalize_traits` is used. Otherwise, the fallback `CGAL::Diagonalize_traits` is used (note that it is significantly slower, so using Eigen is strongly advised).\n \b Default: `CGAL::Eigen_diagonalize_traits` if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined.\n
\cgalNPEnd \cgalNPEnd
\cgalNPBegin{svd_traits} \anchor PSP_svd_traits \cgalNPBegin{svd_traits} \anchor PSP_svd_traits
@ -58,6 +58,14 @@ No default value.
\b Default: if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined, then `CGAL::Eigen_svd` is used.\n \b Default: if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined, then `CGAL::Eigen_svd` is used.\n
\cgalNPEnd \cgalNPEnd
\cgalNPBegin{callback} \anchor PSP_callback
is a mechanism to get feedback on the advancement of the algorithm while it's running and to interrupt it if needed. It is called regularly when the algorithm is running: the current advancement (between 0. and 1.) is passed as parameter. If it returns `true`, then the algorithm continues its execution normally; if it returns `false`, the algorithm is stopped.\n
The callback will be copied and therefore needs to be lightweight.\n
Note that when a callback is run on a parallelized algorithm with `CGAL::Parallel_tag`, it is called asynchronously on a separate thread and shouldn't access or modify the variables that are parameters of the algorithm.\n
\b Type: `CGAL::cpp11::function<bool(double)>`.\n
\b Default: empty function.\n
\cgalNPEnd
\cgalNPBegin{query_point_map} \anchor PSP_query_point_map \cgalNPBegin{query_point_map} \anchor PSP_query_point_map
is the property map containing the points associated to the iterators of the point range `queries`.\n is the property map containing the points associated to the iterators of the point range `queries`.\n
\b Type: a class model of `ReadablePropertyMap` with \b Type: a class model of `ReadablePropertyMap` with

View File

@ -632,6 +632,26 @@ point set:
\cgalExample{Point_set_processing_3/structuring_example.cpp} \cgalExample{Point_set_processing_3/structuring_example.cpp}
\section Point_set_processing_3Callbacks Callbacks
Several functions of this package provide a callback mechanism that enables the user to track the progress of the algorithms and to interrupt them if needed. A callback, in this package, is an instance of `CGAL::cpp11::function<bool(double)>` that takes the advancement as a parameter (between 0. when the algorithm begins to 1. when the algorithm is completed) and that returns `true` if the algorithm should carry on, `false` otherwise. It is passed as a named parameter with an empty function as default.
Algorithms that support this mechanism are detailed in the [Reference Manual](@ref PkgPointSetProcessing), along with the effect that an early interruption has on the output.
\subsection Point_set_processing_3Example_callbacks Example
The following example defines a callback that displays the name of the current algorithm along with the progress (as a percentage) updated every \f$1/10th\f$ of a second. While the algorithm is running, the console output will typically look like this:
\code{.sh}
Computing average spacing: 100%
Grid simplification: 100%
Jet smoothing: 54%
\endcode
Thanks to the carriage return character `\r`, the lines are overwritten and the user sees the percentage increasing on each line.
\cgalExample{Point_set_processing_3/callback_example.cpp}
\section Point_set_processing_3ImplementationHistory Implementation History \section Point_set_processing_3ImplementationHistory Implementation History

View File

@ -17,4 +17,5 @@
\example Point_set_processing_3/edge_aware_upsample_point_set_example.cpp \example Point_set_processing_3/edge_aware_upsample_point_set_example.cpp
\example Point_set_processing_3/edges_example.cpp \example Point_set_processing_3/edges_example.cpp
\example Point_set_processing_3/structuring_example.cpp \example Point_set_processing_3/structuring_example.cpp
\example Point_set_processing_3/callback_example.cpp
*/ */

View File

@ -57,6 +57,7 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "wlop_simplify_and_regularize_point_set_example.cpp" ) create_single_source_cgal_program( "wlop_simplify_and_regularize_point_set_example.cpp" )
create_single_source_cgal_program( "edge_aware_upsample_point_set_example.cpp" ) create_single_source_cgal_program( "edge_aware_upsample_point_set_example.cpp" )
create_single_source_cgal_program( "structuring_example.cpp" ) create_single_source_cgal_program( "structuring_example.cpp" )
create_single_source_cgal_program( "callback_example.cpp" )
set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates) set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates)
create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" CXX_FEATURES ${needed_cxx_features} ) create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" CXX_FEATURES ${needed_cxx_features} )
@ -103,7 +104,8 @@ if ( CGAL_FOUND )
average_spacing_example average_spacing_example
normals_example normals_example
jet_smoothing_example jet_smoothing_example
normal_estimation) normal_estimation
callback_example)
if(TBB_FOUND AND TARGET ${target}) if(TBB_FOUND AND TARGET ${target})
CGAL_target_use_TBB(${target}) CGAL_target_use_TBB(${target})
endif() endif()

View File

@ -0,0 +1,95 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/Real_timer.h>
#include <CGAL/compute_average_spacing.h>
#include <CGAL/grid_simplify_point_set.h>
#include <CGAL/jet_smooth_point_set.h>
#include <vector>
#include <fstream>
// Types
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_3 Point;
typedef CGAL::Random_points_on_sphere_3<Point> Generator;
// Concurrency
#ifdef CGAL_LINKED_WITH_TBB
typedef CGAL::Parallel_tag Concurrency_tag;
#else
typedef CGAL::Sequential_tag Concurrency_tag;
#endif
// instance of CGAL::cpp11::function<bool(double)>
struct Progress_to_std_cerr_callback
{
mutable std::size_t nb;
CGAL::Real_timer timer;
double t_start;
mutable double t_latest;
const std::string name;
Progress_to_std_cerr_callback (const char* name)
: name (name)
{
timer.start();
t_start = timer.time();
t_latest = t_start;
}
bool operator()(double advancement) const
{
// Avoid calling time() at every single iteration, which could
// impact performances very badly
++ nb;
if (advancement != 1 && nb % 10000 != 0)
return true;
double t = timer.time();
if (advancement == 1 || (t - t_latest) > 0.1) // Update every 1/10th of second
{
std::cerr << "\r" // Return at the beginning of same line and overwrite
<< name << ": " << int(advancement * 100) << "%";
if (advancement == 1)
std::cerr << std::endl;
t_latest = t;
}
return true;
}
};
int main ()
{
// Generate 1000000 points on a sphere of radius 100.
std::vector<Point> points;
points.reserve (1000000);
Generator generator(100.);
CGAL::cpp11::copy_n (generator, 1000000, std::back_inserter(points));
// Compute average spacing
FT average_spacing = CGAL::compute_average_spacing<Concurrency_tag>
(points, 6,
CGAL::parameters::callback
(Progress_to_std_cerr_callback("Computing average spacing")));
// Simplify on a grid with a size of twice the average spacing
points.erase(CGAL::grid_simplify_point_set
(points, 2. * average_spacing,
CGAL::parameters::callback
(Progress_to_std_cerr_callback("Grid simplification"))),
points.end());
// Smooth simplified point set
CGAL::jet_smooth_point_set<Concurrency_tag>
(points, 6,
CGAL::parameters::callback
(Progress_to_std_cerr_callback("Jet smoothing")));
return EXIT_SUCCESS;
}

View File

@ -31,6 +31,7 @@
#include <CGAL/point_set_processing_assertions.h> #include <CGAL/point_set_processing_assertions.h>
#include <CGAL/Point_with_normal_3.h> #include <CGAL/Point_with_normal_3.h>
#include <CGAL/squared_distance_3.h> #include <CGAL/squared_distance_3.h>
#include <CGAL/function.h>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
@ -45,9 +46,11 @@
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/internal/Parallel_callback.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h> #include <tbb/scalable_allocator.h>
#include <tbb/atomic.h>
#endif // CGAL_LINKED_WITH_TBB #endif // CGAL_LINKED_WITH_TBB
// Default allocator: use TBB allocators if available // Default allocator: use TBB allocators if available
@ -300,18 +303,27 @@ class Compute_pwns_neighbors
const Tree & m_tree; const Tree & m_tree;
const Pwns & m_pwns; const Pwns & m_pwns;
Pwns_neighbors & m_pwns_neighbors; Pwns_neighbors & m_pwns_neighbors;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public: public:
Compute_pwns_neighbors(unsigned int k, const Tree &tree, Compute_pwns_neighbors(unsigned int k, const Tree &tree,
const Pwns &pwns, Pwns_neighbors &neighbors) const Pwns &pwns, Pwns_neighbors &neighbors,
: m_k(k), m_tree(tree), m_pwns(pwns), m_pwns_neighbors(neighbors) {} cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: m_k(k), m_tree(tree), m_pwns(pwns), m_pwns_neighbors(neighbors)
, advancement (advancement), interrupted (interrupted) {}
void operator() ( const tbb::blocked_range<size_t>& r ) const void operator() ( const tbb::blocked_range<size_t>& r ) const
{ {
for (size_t i = r.begin(); i!=r.end(); i++) for (size_t i = r.begin(); i!=r.end(); i++)
{ {
if (interrupted)
break;
m_pwns_neighbors[i] = bilateral_smooth_point_set_internal:: m_pwns_neighbors[i] = bilateral_smooth_point_set_internal::
compute_kdtree_neighbors<Kernel, Tree>(m_pwns[i], m_tree, m_k); compute_kdtree_neighbors<Kernel, Tree>(m_pwns[i], m_tree, m_k);
++ advancement;
} }
} }
}; };
@ -331,30 +343,37 @@ class Pwn_updater
Pwns* pwns; Pwns* pwns;
Pwns* update_pwns; Pwns* update_pwns;
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* pwns_neighbors; std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* pwns_neighbors;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public: public:
Pwn_updater(FT sharpness, Pwn_updater(FT sharpness,
FT r, FT r,
Pwns *in, Pwns *in,
Pwns *out, Pwns *out,
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* neighbors): std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* neighbors,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted):
sharpness_angle(sharpness), sharpness_angle(sharpness),
radius(r), radius(r),
pwns(in), pwns(in),
update_pwns(out), update_pwns(out),
pwns_neighbors(neighbors){} pwns_neighbors(neighbors),
advancement (advancement),
interrupted (interrupted) {}
void operator() ( const tbb::blocked_range<size_t>& r ) const void operator() ( const tbb::blocked_range<size_t>& r ) const
{ {
for (size_t i = r.begin(); i != r.end(); ++i) for (size_t i = r.begin(); i != r.end(); ++i)
{ {
if (interrupted)
break;
(*update_pwns)[i] = bilateral_smooth_point_set_internal:: (*update_pwns)[i] = bilateral_smooth_point_set_internal::
compute_denoise_projection<Kernel>((*pwns)[i], compute_denoise_projection<Kernel>((*pwns)[i],
(*pwns_neighbors)[i], (*pwns_neighbors)[i],
radius, radius,
sharpness_angle); sharpness_angle);
++ advancement;
} }
} }
}; };
@ -402,6 +421,13 @@ public:
\cgalParamBegin{normal_map} a model of `ReadWritePropertyMap` with value type \cgalParamBegin{normal_map} a model of `ReadWritePropertyMap` with value type
`geom_traits::Vector_3`.\cgalParamEnd `geom_traits::Vector_3`.\cgalParamEnd
\cgalParamBegin{sharpness_angle} controls the sharpness of the result.\cgalParamEnd \cgalParamBegin{sharpness_angle} controls the sharpness of the result.\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped, all points are left unchanged
and the function return `NaN`.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
@ -434,6 +460,8 @@ bilateral_smooth_point_set(
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
double sharpness_angle = choose_param(get_param(np, internal_np::sharpness_angle), 30.); double sharpness_angle = choose_param(get_param(np, internal_np::sharpness_angle), 30.);
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
CGAL_point_set_processing_precondition(points.begin() != points.end()); CGAL_point_set_processing_precondition(points.begin() != points.end());
CGAL_point_set_processing_precondition(k > 1); CGAL_point_set_processing_precondition(k > 1);
@ -513,8 +541,23 @@ bilateral_smooth_point_set(
#else #else
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value) if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
Compute_pwns_neighbors<Kernel, Tree> f(k, tree, pwns, pwns_neighbors); internal::Point_set_processing_3::Parallel_callback
parallel_callback (callback, 2 * nb_points);
Compute_pwns_neighbors<Kernel, Tree> f(k, tree, pwns, pwns_neighbors,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, nb_points), f); tbb::parallel_for(tbb::blocked_range<size_t>(0, nb_points), f);
bool interrupted = parallel_callback.interrupted();
// We interrupt by hand as counter only goes halfway and won't terminate by itself
parallel_callback.interrupted() = true;
parallel_callback.join();
// If interrupted during this step, nothing is computed, we return NaN
if (interrupted)
return std::numeric_limits<double>::quiet_NaN();
} }
else else
#endif #endif
@ -522,10 +565,13 @@ bilateral_smooth_point_set(
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
pwns_iter = pwns_neighbors.begin(); pwns_iter = pwns_neighbors.begin();
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end(); ++pwn_iter, ++pwns_iter) std::size_t nb = 0;
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end(); ++pwn_iter, ++pwns_iter, ++ nb)
{ {
*pwns_iter = bilateral_smooth_point_set_internal:: *pwns_iter = bilateral_smooth_point_set_internal::
compute_kdtree_neighbors<Kernel, Tree>(*pwn_iter, tree, k); compute_kdtree_neighbors<Kernel, Tree>(*pwn_iter, tree, k);
if (callback && !callback ((nb+1) / double(2. * nb_points)))
return std::numeric_limits<double>::quiet_NaN();
} }
} }
@ -545,24 +591,37 @@ bilateral_smooth_point_set(
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
if(boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value) if(boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
{ {
internal::Point_set_processing_3::Parallel_callback
parallel_callback (callback, 2 * nb_points, nb_points);
//tbb::task_scheduler_init init(4); //tbb::task_scheduler_init init(4);
tbb::blocked_range<size_t> block(0, nb_points); tbb::blocked_range<size_t> block(0, nb_points);
Pwn_updater<Kernel> pwn_updater(sharpness_angle, Pwn_updater<Kernel> pwn_updater(sharpness_angle,
guess_neighbor_radius, guess_neighbor_radius,
&pwns, &pwns,
&update_pwns, &update_pwns,
&pwns_neighbors); &pwns_neighbors,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(block, pwn_updater); tbb::parallel_for(block, pwn_updater);
parallel_callback.join();
// If interrupted during this step, nothing is computed, we return NaN
if (parallel_callback.interrupted())
return std::numeric_limits<double>::quiet_NaN();
} }
else else
#endif // CGAL_LINKED_WITH_TBB #endif // CGAL_LINKED_WITH_TBB
{ {
std::size_t nb = nb_points;
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::iterator typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::iterator
update_iter = update_pwns.begin(); update_iter = update_pwns.begin();
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
neighbor_iter = pwns_neighbors.begin(); neighbor_iter = pwns_neighbors.begin();
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end(); for(pwn_iter = pwns.begin(); pwn_iter != pwns.end();
++pwn_iter, ++update_iter, ++neighbor_iter) ++pwn_iter, ++update_iter, ++neighbor_iter, ++ nb)
{ {
*update_iter = bilateral_smooth_point_set_internal:: *update_iter = bilateral_smooth_point_set_internal::
compute_denoise_projection<Kernel> compute_denoise_projection<Kernel>
@ -570,6 +629,8 @@ bilateral_smooth_point_set(
*neighbor_iter, *neighbor_iter,
guess_neighbor_radius, guess_neighbor_radius,
sharpness_angle); sharpness_angle);
if (callback && !callback ((nb+1) / double(2. * nb_points)))
return std::numeric_limits<double>::quiet_NaN();
} }
} }
#ifdef CGAL_PSP3_VERBOSE #ifdef CGAL_PSP3_VERBOSE

View File

@ -31,6 +31,7 @@
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h> #include <CGAL/point_set_processing_assertions.h>
#include <CGAL/assertions.h> #include <CGAL/assertions.h>
#include <CGAL/function.h>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
@ -39,6 +40,7 @@
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/internal/Parallel_callback.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h> #include <tbb/scalable_allocator.h>
@ -109,17 +111,29 @@ compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point who
const unsigned int k; const unsigned int k;
const std::vector<Point>& input; const std::vector<Point>& input;
std::vector<FT>& output; std::vector<FT>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public: public:
Compute_average_spacings(Tree& tree, unsigned int k, std::vector<Point>& points, Compute_average_spacings(Tree& tree, unsigned int k, std::vector<Point>& points,
std::vector<FT>& output) std::vector<FT>& output,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: tree(tree), k (k), input (points), output (output) : tree(tree), k (k), input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ } { }
void operator()(const tbb::blocked_range<std::size_t>& r) const void operator()(const tbb::blocked_range<std::size_t>& r) const
{ {
for( std::size_t i = r.begin(); i != r.end(); ++i) for( std::size_t i = r.begin(); i != r.end(); ++i)
{
if (interrupted)
break;
output[i] = CGAL::internal::compute_average_spacing<Kernel,Tree>(input[i], tree, k); output[i] = CGAL::internal::compute_average_spacing<Kernel,Tree>(input[i], tree, k);
++ advancement;
}
} }
}; };
@ -153,6 +167,13 @@ compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point who
\cgalNamedParamsBegin \cgalNamedParamsBegin
\cgalParamBegin{point_map} a model of `ReadablePropertyMap` with value type `geom_traits::Point_3`. \cgalParamBegin{point_map} a model of `ReadablePropertyMap` with value type `geom_traits::Point_3`.
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped and the average spacing value
estimated on the processed subset is returned.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
@ -184,6 +205,8 @@ compute_average_spacing(
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap()); PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
// types for K nearest neighbors search structure // types for K nearest neighbors search structure
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
@ -209,6 +232,7 @@ compute_average_spacing(
// iterate over input points, compute and output normal // iterate over input points, compute and output normal
// vectors (already normalized) // vectors (already normalized)
FT sum_spacings = (FT)0.0; FT sum_spacings = (FT)0.0;
std::size_t nb = 0;
#ifndef CGAL_LINKED_WITH_TBB #ifndef CGAL_LINKED_WITH_TBB
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value), CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
@ -216,26 +240,43 @@ compute_average_spacing(
#else #else
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value) if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
std::vector<FT> spacings (kd_tree_points.size ()); internal::Point_set_processing_3::Parallel_callback
parallel_callback (callback, kd_tree_points.size());
std::vector<FT> spacings (kd_tree_points.size (), -1);
CGAL::internal::Compute_average_spacings<Kernel, Tree> CGAL::internal::Compute_average_spacings<Kernel, Tree>
f (tree, k, kd_tree_points, spacings); f (tree, k, kd_tree_points, spacings,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f); tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
for (unsigned int i = 0; i < spacings.size (); ++ i) for (unsigned int i = 0; i < spacings.size (); ++ i)
if (spacings[i] >= 0.)
{
sum_spacings += spacings[i]; sum_spacings += spacings[i];
++ nb;
}
parallel_callback.join();
} }
else else
#endif #endif
{ {
for(typename PointRange::const_iterator it = points.begin(); it != points.end(); it++) for(typename PointRange::const_iterator it = points.begin(); it != points.end(); it++, nb++)
{ {
sum_spacings += internal::compute_average_spacing<Kernel,Tree>( sum_spacings += internal::compute_average_spacing<Kernel,Tree>(
get(point_map,*it), get(point_map,*it),
tree,k); tree,k);
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
{
++ nb;
break;
}
} }
} }
// return average spacing // return average spacing
return sum_spacings / (FT)(kd_tree_points.size ()); return sum_spacings / (FT)(nb);
} }
/// \cond SKIP_IN_MANUAL /// \cond SKIP_IN_MANUAL

View File

@ -30,6 +30,7 @@
#include <CGAL/point_set_processing_assertions.h> #include <CGAL/point_set_processing_assertions.h>
#include <CGAL/unordered.h> #include <CGAL/unordered.h>
#include <CGAL/Iterator_range.h> #include <CGAL/Iterator_range.h>
#include <CGAL/function.h>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
@ -188,6 +189,13 @@ public:
\cgalNamedParamsBegin \cgalNamedParamsBegin
\cgalParamBegin{point_map} a model of `ReadWritePropertyMap` with value type `geom_traits::Point_3`. \cgalParamBegin{point_map} a model of `ReadWritePropertyMap` with value type `geom_traits::Point_3`.
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped and simplification stops with
no guarantee on the output.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
@ -204,6 +212,8 @@ grid_simplify_point_set(
typedef typename Point_set_processing_3::GetPointMap<PointRange, NamedParameters>::const_type PointMap; typedef typename Point_set_processing_3::GetPointMap<PointRange, NamedParameters>::const_type PointMap;
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap()); PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
// actual type of input points // actual type of input points
typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Enriched_point; typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Enriched_point;
@ -214,12 +224,15 @@ grid_simplify_point_set(
// points_to_keep[] will contain 1 point per cell; the others will be in points_to_remove[]. // points_to_keep[] will contain 1 point per cell; the others will be in points_to_remove[].
Epsilon_point_set_3<Enriched_point, PointMap> points_to_keep(epsilon, point_map); Epsilon_point_set_3<Enriched_point, PointMap> points_to_keep(epsilon, point_map);
std::deque<Enriched_point> points_to_remove; std::deque<Enriched_point> points_to_remove;
for (typename PointRange::iterator it = points.begin(); it != points.end(); it++) std::size_t nb = 0, nb_points = points.size();
for (typename PointRange::iterator it = points.begin(); it != points.end(); it++, ++ nb)
{ {
std::pair<typename Epsilon_point_set_3<Enriched_point, PointMap>::iterator,bool> result; std::pair<typename Epsilon_point_set_3<Enriched_point, PointMap>::iterator,bool> result;
result = points_to_keep.insert(*it); result = points_to_keep.insert(*it);
if (!result.second) // if not inserted if (!result.second) // if not inserted
points_to_remove.push_back(*it); points_to_remove.push_back(*it);
if (callback && !callback ((nb+1) / double(nb_points)))
break;
} }
// Replaces `[first, beyond)` range by the content of points_to_keep, then points_to_remove. // Replaces `[first, beyond)` range by the content of points_to_keep, then points_to_remove.

View File

@ -39,6 +39,7 @@
#include <CGAL/PCA_util.h> #include <CGAL/PCA_util.h>
#include <CGAL/squared_distance_3.h> #include <CGAL/squared_distance_3.h>
#include <CGAL/Iterator_range.h> #include <CGAL/Iterator_range.h>
#include <CGAL/function.h>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
@ -142,6 +143,13 @@ namespace CGAL {
if Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined then an overload if Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined then an overload
using `Eigen_diagonalize_traits` is provided. Otherwise, the internal implementation using `Eigen_diagonalize_traits` is provided. Otherwise, the internal implementation
`CGAL::Diagonalize_traits` is used.\cgalParamEnd `CGAL::Diagonalize_traits` is used.\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped and simplification stops with
no guarantee on the output.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
@ -167,6 +175,8 @@ namespace CGAL {
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap()); PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
unsigned int size = choose_param(get_param(np, internal_np::size), 10); unsigned int size = choose_param(get_param(np, internal_np::size), 10);
double var_max = choose_param(get_param(np, internal_np::maximum_variation), 1./3.); double var_max = choose_param(get_param(np, internal_np::maximum_variation), 1./3.);
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Input_type; typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Input_type;
@ -192,6 +202,8 @@ namespace CGAL {
std::list<Input_type> points_to_keep; std::list<Input_type> points_to_keep;
std::list<Input_type> points_to_remove; std::list<Input_type> points_to_remove;
std::size_t nb_done = 0;
while (!(clusters_stack.empty ())) while (!(clusters_stack.empty ()))
{ {
cluster_iterator current_cluster = clusters_stack.begin (); cluster_iterator current_cluster = clusters_stack.begin ();
@ -203,6 +215,7 @@ namespace CGAL {
points_to_keep.splice (points_to_keep.end (), current_cluster->first, points_to_keep.splice (points_to_keep.end (), current_cluster->first,
current_cluster->first.begin ()); current_cluster->first.begin ());
clusters_stack.pop_front (); clusters_stack.pop_front ();
++ nb_done;
continue; continue;
} }
@ -268,6 +281,7 @@ namespace CGAL {
cluster_iterator nonempty = (current_cluster->first.empty () cluster_iterator nonempty = (current_cluster->first.empty ()
? negative_side : current_cluster); ? negative_side : current_cluster);
nb_done += nonempty->first.size();
// Compute the centroid // Compute the centroid
nonempty->second = internal::hsps_centroid (nonempty->first.begin (), nonempty->second = internal::hsps_centroid (nonempty->first.begin (),
nonempty->first.end (), nonempty->first.end (),
@ -279,6 +293,7 @@ namespace CGAL {
point_map, point_map,
nonempty->second, nonempty->second,
Kernel ()); Kernel ());
clusters_stack.pop_front (); clusters_stack.pop_front ();
clusters_stack.pop_front (); clusters_stack.pop_front ();
} }
@ -311,6 +326,7 @@ namespace CGAL {
// and output point // and output point
else else
{ {
nb_done += current_cluster->first.size();
internal::hsc_terminate_cluster (current_cluster->first, internal::hsc_terminate_cluster (current_cluster->first,
points_to_keep, points_to_keep,
points_to_remove, points_to_remove,
@ -319,7 +335,14 @@ namespace CGAL {
Kernel ()); Kernel ());
clusters_stack.pop_front (); clusters_stack.pop_front ();
} }
if (callback && !callback (nb_done / double (points.size())))
break;
} }
if (callback)
callback (1.);
typename PointRange::iterator first_point_to_remove = typename PointRange::iterator first_point_to_remove =
std::copy (points_to_keep.begin(), points_to_keep.end(), points.begin()); std::copy (points_to_keep.begin(), points_to_keep.end(), points.begin());
std::copy (points_to_remove.begin(), points_to_remove.end(), first_point_to_remove); std::copy (points_to_remove.begin(), points_to_remove.end(), first_point_to_remove);

View File

@ -0,0 +1,117 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
// Author(s) : Simon Giraudot
#ifndef CGAL_INTERNAL_PSP_PARALLEL_CALLBACK_H
#define CGAL_INTERNAL_PSP_PARALLEL_CALLBACK_H
#include <CGAL/license/Point_set_processing_3.h>
#include <CGAL/function.h>
#include <CGAL/thread.h>
namespace CGAL {
namespace internal {
namespace Point_set_processing_3 {
class Parallel_callback
{
const cpp11::function<bool(double)>& m_callback;
cpp11::atomic<std::size_t>* m_advancement;
cpp11::atomic<bool>* m_interrupted;
std::size_t m_size;
bool m_creator;
cpp11::thread* m_thread;
// assignment operator shouldn't be used (m_callback is const ref)
Parallel_callback& operator= (const Parallel_callback&)
{
return *this;
}
public:
Parallel_callback (const cpp11::function<bool(double)>& callback,
std::size_t size,
std::size_t advancement = 0,
bool interrupted = false)
: m_callback (callback)
, m_advancement (new cpp11::atomic<std::size_t>())
, m_interrupted (new cpp11::atomic<bool>())
, m_size (size)
, m_creator (true)
, m_thread (NULL)
{
// cpp11::atomic only has default constructor, initialization done in two steps
*m_advancement = advancement;
*m_interrupted = interrupted;
if (m_callback)
m_thread = new cpp11::thread (*this);
}
Parallel_callback (const Parallel_callback& other)
: m_callback (other.m_callback)
, m_advancement (other.m_advancement)
, m_interrupted (other.m_interrupted)
, m_size (other.m_size)
, m_creator (false)
, m_thread (NULL)
{
}
~Parallel_callback ()
{
if (m_creator)
{
delete m_advancement;
delete m_interrupted;
}
if (m_thread != NULL)
delete m_thread;
}
cpp11::atomic<std::size_t>& advancement() { return *m_advancement; }
cpp11::atomic<bool>& interrupted() { return *m_interrupted; }
void join()
{
if (m_thread != NULL)
m_thread->join();
}
void operator()()
{
while (*m_advancement != m_size)
{
if (!m_callback (*m_advancement / double(m_size)))
*m_interrupted = true;
if (*m_interrupted)
return;
cpp11::sleep_for (0.00001);
}
m_callback (1.);
}
};
} // namespace Point_set_processing_3
} // namespace internal
} // namespace CGAL
#endif // CGAL_INTERNAL_PSP_PARALLEL_CALLBACK_H

View File

@ -32,6 +32,7 @@
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h> #include <CGAL/point_set_processing_assertions.h>
#include <CGAL/Memory_sizer.h> #include <CGAL/Memory_sizer.h>
#include <CGAL/function.h>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
@ -40,6 +41,7 @@
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/internal/Parallel_callback.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h> #include <tbb/scalable_allocator.h>
@ -125,17 +127,28 @@ jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
const unsigned int degree_fitting; const unsigned int degree_fitting;
const std::vector<Point>& input; const std::vector<Point>& input;
std::vector<Vector>& output; std::vector<Vector>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public: public:
Jet_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points, Jet_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points,
unsigned int degree_fitting, std::vector<Vector>& output) unsigned int degree_fitting, std::vector<Vector>& output,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: tree(tree), k (k), degree_fitting (degree_fitting), input (points), output (output) : tree(tree), k (k), degree_fitting (degree_fitting), input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ } { }
void operator()(const tbb::blocked_range<std::size_t>& r) const void operator()(const tbb::blocked_range<std::size_t>& r) const
{ {
for( std::size_t i = r.begin(); i != r.end(); ++i) for( std::size_t i = r.begin(); i != r.end(); ++i)
{
if (interrupted)
break;
output[i] = CGAL::internal::jet_estimate_normal<Kernel,SvdTraits>(input[i], tree, k, degree_fitting); output[i] = CGAL::internal::jet_estimate_normal<Kernel,SvdTraits>(input[i], tree, k, degree_fitting);
++ advancement;
}
} }
}; };
@ -179,6 +192,13 @@ jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
\cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If \cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If
\ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined, \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined,
then `CGAL::Eigen_svd` is used.\cgalParamEnd then `CGAL::Eigen_svd` is used.\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped and the remaining normals are
left unchanged.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
*/ */
@ -212,6 +232,8 @@ jet_estimate_normals(
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap()); PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap()); NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap());
unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2); unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2);
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
@ -254,27 +276,36 @@ jet_estimate_normals(
#else #else
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value) if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
std::vector<Vector> normals (kd_tree_points.size ()); internal::Point_set_processing_3::Parallel_callback
parallel_callback (callback, kd_tree_points.size());
std::vector<Vector> normals (kd_tree_points.size (),
CGAL::NULL_VECTOR);
CGAL::internal::Jet_estimate_normals<Kernel, SvdTraits, Tree> CGAL::internal::Jet_estimate_normals<Kernel, SvdTraits, Tree>
f (tree, k, kd_tree_points, degree_fitting, normals); f (tree, k, kd_tree_points, degree_fitting, normals,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f); tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
unsigned int i = 0; std::size_t i = 0;
for(it = points.begin(); it != points.end(); ++ it, ++ i) for(it = points.begin(); it != points.end(); ++ it, ++ i)
{ if (normals[i] != CGAL::NULL_VECTOR)
put (normal_map, *it, normals[i]); put (normal_map, *it, normals[i]);
}
parallel_callback.join();
} }
else else
#endif #endif
{ {
for(it = points.begin(); it != points.end(); it++) std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb)
{ {
Vector normal = internal::jet_estimate_normal<Kernel,SvdTraits,Tree>( Vector normal = internal::jet_estimate_normal<Kernel,SvdTraits,Tree>(
get(point_map,*it), get(point_map,*it),
tree, k, degree_fitting); tree, k, degree_fitting);
put(normal_map, *it, normal); // normal_map[it] = normal put(normal_map, *it, normal); // normal_map[it] = normal
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
break;
} }
} }

View File

@ -31,6 +31,7 @@
#include <CGAL/Monge_via_jet_fitting.h> #include <CGAL/Monge_via_jet_fitting.h>
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h> #include <CGAL/point_set_processing_assertions.h>
#include <CGAL/function.h>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
@ -39,6 +40,7 @@
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/internal/Parallel_callback.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h> #include <tbb/scalable_allocator.h>
@ -125,20 +127,31 @@ jet_smooth_point(
unsigned int degree_monge; unsigned int degree_monge;
const std::vector<Point>& input; const std::vector<Point>& input;
std::vector<Point>& output; std::vector<Point>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public: public:
Jet_smooth_pwns (Tree& tree, unsigned int k, std::vector<Point>& points, Jet_smooth_pwns (Tree& tree, unsigned int k, std::vector<Point>& points,
unsigned int degree_fitting, unsigned int degree_monge, std::vector<Point>& output) unsigned int degree_fitting, unsigned int degree_monge, std::vector<Point>& output,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: tree(tree), k (k), degree_fitting (degree_fitting), : tree(tree), k (k), degree_fitting (degree_fitting),
degree_monge (degree_monge), input (points), output (output) degree_monge (degree_monge), input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ } { }
void operator()(const tbb::blocked_range<std::size_t>& r) const void operator()(const tbb::blocked_range<std::size_t>& r) const
{ {
for( std::size_t i = r.begin(); i != r.end(); ++i) for( std::size_t i = r.begin(); i != r.end(); ++i)
{
if (interrupted)
break;
output[i] = CGAL::internal::jet_smooth_point<Kernel, SvdTraits>(input[i], tree, k, output[i] = CGAL::internal::jet_smooth_point<Kernel, SvdTraits>(input[i], tree, k,
degree_fitting, degree_fitting,
degree_monge); degree_monge);
++ advancement;
}
} }
}; };
@ -182,6 +195,13 @@ jet_smooth_point(
\cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If \cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If
\ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined, \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined,
then `CGAL::Eigen_svd` is used.\cgalParamEnd then `CGAL::Eigen_svd` is used.\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped and the remaining points are
left unchanged.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
@ -210,6 +230,8 @@ jet_smooth_point_set(
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap()); PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2); unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2);
unsigned int degree_monge = choose_param(get_param(np, internal_np::degree_monge), 2); unsigned int degree_monge = choose_param(get_param(np, internal_np::degree_monge), 2);
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
@ -244,27 +266,36 @@ jet_smooth_point_set(
#else #else
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value) if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
std::vector<Point> mutated_points (kd_tree_points.size ()); internal::Point_set_processing_3::Parallel_callback
parallel_callback (callback, kd_tree_points.size());
std::vector<Point> mutated_points (kd_tree_points.size (), CGAL::ORIGIN);
CGAL::internal::Jet_smooth_pwns<Kernel, SvdTraits, Tree> CGAL::internal::Jet_smooth_pwns<Kernel, SvdTraits, Tree>
f (tree, k, kd_tree_points, degree_fitting, degree_monge, f (tree, k, kd_tree_points, degree_fitting, degree_monge,
mutated_points); mutated_points,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f); tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
unsigned int i = 0; unsigned int i = 0;
for(it = points.begin(); it != points.end(); ++ it, ++ i) for(it = points.begin(); it != points.end(); ++ it, ++ i)
{ if (mutated_points[i] != CGAL::ORIGIN)
put(point_map, *it, mutated_points[i]); put(point_map, *it, mutated_points[i]);
} parallel_callback.join();
} }
else else
#endif #endif
{ {
for(it = points.begin(); it != points.end(); it++) std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb)
{ {
const typename boost::property_traits<PointMap>::reference p = get(point_map, *it); const typename boost::property_traits<PointMap>::reference p = get(point_map, *it);
put(point_map, *it , put(point_map, *it ,
internal::jet_smooth_point<Kernel, SvdTraits>( internal::jet_smooth_point<Kernel, SvdTraits>(
p,tree,k,degree_fitting,degree_monge) ); p,tree,k,degree_fitting,degree_monge) );
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
break;
} }
} }
} }

View File

@ -33,6 +33,7 @@
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h> #include <CGAL/point_set_processing_assertions.h>
#include <CGAL/Memory_sizer.h> #include <CGAL/Memory_sizer.h>
#include <CGAL/function.h>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
@ -41,6 +42,7 @@
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/internal/Parallel_callback.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h> #include <tbb/scalable_allocator.h>
@ -117,17 +119,28 @@ pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
const unsigned int k; const unsigned int k;
const std::vector<Point>& input; const std::vector<Point>& input;
std::vector<Vector>& output; std::vector<Vector>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public: public:
PCA_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points, PCA_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points,
std::vector<Vector>& output) std::vector<Vector>& output,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: tree(tree), k (k), input (points), output (output) : tree(tree), k (k), input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ } { }
void operator()(const tbb::blocked_range<std::size_t>& r) const void operator()(const tbb::blocked_range<std::size_t>& r) const
{ {
for( std::size_t i = r.begin(); i != r.end(); ++i) for( std::size_t i = r.begin(); i != r.end(); ++i)
{
if (interrupted)
break;
output[i] = CGAL::internal::pca_estimate_normal<Kernel,Tree>(input[i], tree, k); output[i] = CGAL::internal::pca_estimate_normal<Kernel,Tree>(input[i], tree, k);
++ advancement;
}
} }
}; };
@ -166,6 +179,13 @@ pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
\cgalParamBegin{normal_map} a model of `WritablePropertyMap` with value type \cgalParamBegin{normal_map} a model of `WritablePropertyMap` with value type
`geom_traits::Vector_3`.\cgalParamEnd `geom_traits::Vector_3`.\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped and the remaining normals are
left unchanged.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
*/ */
@ -193,6 +213,8 @@ pca_estimate_normals(
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap()); PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap()); NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap());
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
@ -235,20 +257,28 @@ pca_estimate_normals(
#else #else
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value) if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{ {
std::vector<Vector> normals (kd_tree_points.size ()); internal::Point_set_processing_3::Parallel_callback
parallel_callback (callback, kd_tree_points.size());
std::vector<Vector> normals (kd_tree_points.size (),
CGAL::NULL_VECTOR);
CGAL::internal::PCA_estimate_normals<Kernel, Tree> CGAL::internal::PCA_estimate_normals<Kernel, Tree>
f (tree, k, kd_tree_points, normals); f (tree, k, kd_tree_points, normals,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f); tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
unsigned int i = 0; unsigned int i = 0;
for(it = points.begin(); it != points.end(); ++ it, ++ i) for(it = points.begin(); it != points.end(); ++ it, ++ i)
{ if (normals[i] != CGAL::NULL_VECTOR)
put (normal_map, *it, normals[i]); put (normal_map, *it, normals[i]);
}
parallel_callback.join();
} }
else else
#endif #endif
{ {
for(it = points.begin(); it != points.end(); it++) std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb)
{ {
Vector normal = internal::pca_estimate_normal<Kernel,Tree>( Vector normal = internal::pca_estimate_normal<Kernel,Tree>(
get(point_map,*it), get(point_map,*it),
@ -256,6 +286,8 @@ pca_estimate_normals(
k); k);
put(normal_map, *it, normal); // normal_map[it] = normal put(normal_map, *it, normal); // normal_map[it] = normal
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
break;
} }
} }

View File

@ -29,6 +29,7 @@
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h> #include <CGAL/point_set_processing_assertions.h>
#include <CGAL/function.h>
#include <CGAL/boost/graph/named_function_params.h> #include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
@ -132,6 +133,13 @@ compute_avg_knn_sq_distance_3(
\cgalParamBegin{threshold_percent} maximum percentage of points to remove.\cgalParamEnd \cgalParamBegin{threshold_percent} maximum percentage of points to remove.\cgalParamEnd
\cgalParamBegin{threshold_distance} minimum distance for a point to be considered as outlier \cgalParamBegin{threshold_distance} minimum distance for a point to be considered as outlier
(distance here is the square root of the average squared distance to K nearest neighbors).\cgalParamEnd (distance here is the square root of the average squared distance to K nearest neighbors).\cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped, all points are left unchanged
and the function return `points.end()`.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
@ -163,6 +171,8 @@ remove_outliers(
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap()); PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
double threshold_percent = choose_param(get_param(np, internal_np::threshold_percent), 10.); double threshold_percent = choose_param(get_param(np, internal_np::threshold_percent), 10.);
double threshold_distance = choose_param(get_param(np, internal_np::threshold_distance), 0.); double threshold_distance = choose_param(get_param(np, internal_np::threshold_distance), 0.);
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
@ -198,12 +208,15 @@ remove_outliers(
// iterate over input points and add them to multimap sorted by distance to k // iterate over input points and add them to multimap sorted by distance to k
std::multimap<FT,Enriched_point> sorted_points; std::multimap<FT,Enriched_point> sorted_points;
for(it = points.begin(); it != points.end(); it++) std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb)
{ {
FT sq_distance = internal::compute_avg_knn_sq_distance_3<Kernel>( FT sq_distance = internal::compute_avg_knn_sq_distance_3<Kernel>(
get(point_map,*it), get(point_map,*it),
tree, k); tree, k);
sorted_points.insert( std::make_pair(sq_distance, *it) ); sorted_points.insert( std::make_pair(sq_distance, *it) );
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
return points.end();
} }
// Replaces [points.begin(), points.end()) range by the multimap content. // Replaces [points.begin(), points.end()) range by the multimap content.

View File

@ -42,8 +42,10 @@
#include <ctime> #include <ctime>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/internal/Parallel_callback.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#endif // CGAL_LINKED_WITH_TBB #endif // CGAL_LINKED_WITH_TBB
#include <CGAL/Simple_cartesian.h> #include <CGAL/Simple_cartesian.h>
@ -354,6 +356,8 @@ class Sample_point_updater
const typename Kernel::FT radius; const typename Kernel::FT radius;
const std::vector<typename Kernel::FT> &original_densities; const std::vector<typename Kernel::FT> &original_densities;
const std::vector<typename Kernel::FT> &sample_densities; const std::vector<typename Kernel::FT> &sample_densities;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public: public:
Sample_point_updater( Sample_point_updater(
@ -363,20 +367,25 @@ public:
const Tree &_sample_kd_tree, const Tree &_sample_kd_tree,
const typename Kernel::FT _radius, const typename Kernel::FT _radius,
const std::vector<typename Kernel::FT> &_original_densities, const std::vector<typename Kernel::FT> &_original_densities,
const std::vector<typename Kernel::FT> &_sample_densities): const std::vector<typename Kernel::FT> &_sample_densities,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted):
update_sample_points(out), update_sample_points(out),
sample_points(in), sample_points(in),
original_kd_tree(_original_kd_tree), original_kd_tree(_original_kd_tree),
sample_kd_tree(_sample_kd_tree), sample_kd_tree(_sample_kd_tree),
radius(_radius), radius(_radius),
original_densities(_original_densities), original_densities(_original_densities),
sample_densities(_sample_densities){} sample_densities(_sample_densities),
advancement (advancement),
interrupted (interrupted) {}
void operator() ( const tbb::blocked_range<size_t>& r ) const void operator() ( const tbb::blocked_range<size_t>& r ) const
{ {
for (size_t i = r.begin(); i != r.end(); ++i) for (size_t i = r.begin(); i != r.end(); ++i)
{ {
if (interrupted)
break;
update_sample_points[i] = simplify_and_regularize_internal:: update_sample_points[i] = simplify_and_regularize_internal::
compute_update_sample_point<Kernel, Tree, RandomAccessIterator>( compute_update_sample_point<Kernel, Tree, RandomAccessIterator>(
sample_points[i], sample_points[i],
@ -385,6 +394,7 @@ public:
radius, radius,
original_densities, original_densities,
sample_densities); sample_densities);
++ advancement;
} }
} }
}; };
@ -440,6 +450,13 @@ public:
value is 35. More iterations give a more regular result but increase the runtime.\cgalParamEnd value is 35. More iterations give a more regular result but increase the runtime.\cgalParamEnd
\cgalParamBegin{require_uniform_sampling} an optional preprocessing, which will give better result if the \cgalParamBegin{require_uniform_sampling} an optional preprocessing, which will give better result if the
distribution of the input points is highly non-uniform. The default value is `false`. \cgalParamEnd distribution of the input points is highly non-uniform. The default value is `false`. \cgalParamEnd
\cgalParamBegin{callback} an instance of
`cpp11::function<bool(double)>`. It is called regularly when the
algorithm is running: the current advancement (between 0. and
1.) is passed as parameter. If it returns `true`, then the
algorithm continues its execution normally; if it returns
`false`, the algorithm is stopped, no output points are
generated.\cgalParamEnd
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
\cgalNamedParamsEnd \cgalNamedParamsEnd
@ -466,6 +483,8 @@ wlop_simplify_and_regularize_point_set(
double radius = choose_param(get_param(np, internal_np::neighbor_radius), -1); double radius = choose_param(get_param(np, internal_np::neighbor_radius), -1);
unsigned int iter_number = choose_param(get_param(np, internal_np::number_of_iterations), 35); unsigned int iter_number = choose_param(get_param(np, internal_np::number_of_iterations), 35);
bool require_uniform_sampling = choose_param(get_param(np, internal_np::require_uniform_sampling), false); bool require_uniform_sampling = choose_param(get_param(np, internal_np::require_uniform_sampling), false);
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
cpp11::function<bool(double)>());
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
@ -589,6 +608,9 @@ wlop_simplify_and_regularize_point_set(
//parallel //parallel
if (boost::is_convertible<ConcurrencyTag, Parallel_tag>::value) if (boost::is_convertible<ConcurrencyTag, Parallel_tag>::value)
{ {
internal::Point_set_processing_3::Parallel_callback
parallel_callback (callback, iter_number * number_of_sample, iter_n * number_of_sample);
tbb::blocked_range<size_t> block(0, number_of_sample); tbb::blocked_range<size_t> block(0, number_of_sample);
Sample_point_updater<Kernel, Kd_Tree, typename PointRange::iterator> sample_updater( Sample_point_updater<Kernel, Kd_Tree, typename PointRange::iterator> sample_updater(
update_sample_points, update_sample_points,
@ -597,15 +619,28 @@ wlop_simplify_and_regularize_point_set(
sample_kd_tree, sample_kd_tree,
radius2, radius2,
original_density_weights, original_density_weights,
sample_density_weights); sample_density_weights,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(block, sample_updater); tbb::parallel_for(block, sample_updater);
bool interrupted = parallel_callback.interrupted();
// We interrupt by hand as counter only goes halfway and won't terminate by itself
parallel_callback.interrupted() = true;
parallel_callback.join();
// If interrupted during this step, nothing is computed, we return NaN
if (interrupted)
return output;
}else }else
#endif #endif
{ {
//sequential //sequential
std::size_t nb = iter_n * number_of_sample;
for (sample_iter = sample_points.begin(); for (sample_iter = sample_points.begin();
sample_iter != sample_points.end(); ++sample_iter, ++update_iter) sample_iter != sample_points.end(); ++sample_iter, ++update_iter, ++ nb)
{ {
*update_iter = simplify_and_regularize_internal:: *update_iter = simplify_and_regularize_internal::
compute_update_sample_point<Kernel, compute_update_sample_point<Kernel,
@ -617,6 +652,8 @@ wlop_simplify_and_regularize_point_set(
radius2, radius2,
original_density_weights, original_density_weights,
sample_density_weights); sample_density_weights);
if (callback && !callback ((nb+1) / double(iter_number * number_of_sample)))
return output;
} }
} }

View File

@ -23,12 +23,18 @@ if ( CGAL_FOUND )
include_directories (BEFORE "../../include") include_directories (BEFORE "../../include")
# Use Eigen
find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
create_single_source_cgal_program( "shape_detection_basic.cpp" ) create_single_source_cgal_program( "shape_detection_basic.cpp" )
create_single_source_cgal_program( "shape_detection_with_callback.cpp" ) create_single_source_cgal_program( "shape_detection_with_callback.cpp" )
create_single_source_cgal_program( "plane_regularization.cpp" )
endif()
create_single_source_cgal_program( "efficient_RANSAC_custom_shape.cpp" ) create_single_source_cgal_program( "efficient_RANSAC_custom_shape.cpp" )
create_single_source_cgal_program( "efficient_RANSAC_parameters.cpp" ) create_single_source_cgal_program( "efficient_RANSAC_parameters.cpp" )
create_single_source_cgal_program( "efficient_RANSAC_point_access.cpp" ) create_single_source_cgal_program( "efficient_RANSAC_point_access.cpp" )
create_single_source_cgal_program( "plane_regularization.cpp" )
else() else()

View File

@ -326,6 +326,12 @@ Parameter used in `isotropic_remeshing()` to specify an alternative vertex proje
<b>Default:</b> A function object projecting vertices on the input surface. <b>Default:</b> A function object projecting vertices on the input surface.
\cgalNPEnd \cgalNPEnd
\cgalNPBegin{apply_per_connected_component} \anchor PMP_apply_per_connected_component
Parameter used to indicate whether an algorithm should consider each connected component
of a mesh independently.\n
\b Type : `bool` \n
\b Default value is `false`
\cgalNPEnd
\cgalNPTableEnd \cgalNPTableEnd
*/ */

View File

@ -32,6 +32,7 @@
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h> #include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h> #include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/array.h> #include <CGAL/array.h>
#include <CGAL/Union_find.h> #include <CGAL/Union_find.h>
#include <CGAL/utility.h> #include <CGAL/utility.h>
@ -84,23 +85,21 @@ struct Less_for_halfedge
const VertexPointMap& vpmap; const VertexPointMap& vpmap;
}; };
template <typename PM, typename OutputIterator, typename LessHedge, typename VertexPointMap> //add a pair of border halfedges to be stitched.
OutputIterator //Specifies if they are manifold or not in the map.
collect_duplicated_stitchable_boundary_edges template<typename Halfedge,
(PM& pmesh, OutputIterator out, LessHedge less_hedge, const VertexPointMap& vpmap) typename Border_halfedge_map,
typename Halfedge_pair,
typename Manifold_halfedge_pair,
typename VPMAP,
typename Mesh>
void fill_pairs(const Halfedge& he,
Border_halfedge_map& border_halfedge_map,
Halfedge_pair& halfedge_pairs,
Manifold_halfedge_pair& manifold_halfedge_pairs,
VPMAP vpmap,
const Mesh& pmesh)
{ {
typedef typename boost::graph_traits<PM>::halfedge_descriptor halfedge_descriptor;
typedef std::map<halfedge_descriptor, std::pair<int, std::size_t>, LessHedge> Border_halfedge_map;
Border_halfedge_map border_halfedge_map(less_hedge);
std::vector< std::pair<halfedge_descriptor, halfedge_descriptor> > halfedge_pairs;
std::vector< bool > manifold_halfedge_pairs;
BOOST_FOREACH(halfedge_descriptor he, halfedges(pmesh))
{
if ( !CGAL::is_border(he, pmesh) )
continue;
typename Border_halfedge_map::iterator set_it; typename Border_halfedge_map::iterator set_it;
bool insertion_ok; bool insertion_ok;
CGAL::cpp11::tie(set_it, insertion_ok) CGAL::cpp11::tie(set_it, insertion_ok)
@ -120,10 +119,118 @@ collect_duplicated_stitchable_boundary_edges
} }
else else
if ( set_it->second.first > 2 ) if ( set_it->second.first > 2 )
{
manifold_halfedge_pairs[ set_it->second.second ] = false; manifold_halfedge_pairs[ set_it->second.second ] = false;
} }
} }
}
template<typename Mesh,
typename CCMap,
typename FIMap>
std::size_t num_component_wrapper(const Mesh& pmesh,
CCMap cc,
FIMap fim)
{
return CGAL::Polygon_mesh_processing::connected_components(pmesh, cc,
CGAL::Polygon_mesh_processing::parameters::face_index_map(fim));
}
//specialization if there is no default FIMap, create one
template<typename Mesh,
typename CCMap>
std::size_t num_component_wrapper(Mesh& pmesh,
CCMap cc,
boost::cgal_no_property::type)
{
boost::unordered_map<typename boost::graph_traits<Mesh>::face_descriptor, std::size_t> fim;
//init the map
std::size_t i=-1;
BOOST_FOREACH(typename boost::graph_traits<Mesh>::face_descriptor f, faces(pmesh))
fim[f]=++i;
return CGAL::Polygon_mesh_processing::connected_components(pmesh,
cc,
parameters::face_index_map(boost::make_assoc_property_map(fim)));
}
template <typename PM, typename OutputIterator, typename LessHedge, typename VertexPointMap
, class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
OutputIterator
collect_duplicated_stitchable_boundary_edges
(PM& pmesh, OutputIterator out, LessHedge less_hedge,
const VertexPointMap& vpmap, const CGAL_PMP_NP_CLASS& np)
{
typedef typename boost::graph_traits<PM>::halfedge_descriptor halfedge_descriptor;
typedef std::map<halfedge_descriptor, std::pair<int, std::size_t>, LessHedge> Border_halfedge_map;
Border_halfedge_map border_halfedge_map(less_hedge);
std::vector< std::pair<halfedge_descriptor, halfedge_descriptor> > halfedge_pairs;
std::vector< bool > manifold_halfedge_pairs;
typedef CGAL::dynamic_face_property_t<int> Face_property_tag;
typedef typename boost::property_map<PM, Face_property_tag>::type Face_cc_map;
Face_cc_map cc;
std::size_t num_component = 0;
std::vector<std::vector<halfedge_descriptor> > border_edges_per_cc;
bool per_cc = boost::choose_param(get_param(np, internal_np::apply_per_connected_component),
false);
if(per_cc)
{
cc = get(Face_property_tag(), pmesh);
typedef typename GetFaceIndexMap<PM, CGAL_PMP_NP_CLASS>::const_type FIMap;
FIMap fim = boost::choose_param(get_param(np, internal_np::face_index),
get_const_property_map(face_index, pmesh));
num_component = num_component_wrapper(pmesh, cc, fim);
border_edges_per_cc.resize(num_component);
}
BOOST_FOREACH(halfedge_descriptor he, halfedges(pmesh))
{
if ( !CGAL::is_border(he, pmesh) )
continue;
if(per_cc)
{
border_edges_per_cc[get(cc, face(opposite(he, pmesh), pmesh))].push_back(he);
}
else
{
fill_pairs(he, border_halfedge_map, halfedge_pairs,
manifold_halfedge_pairs, vpmap, pmesh);
}
}
if(per_cc)
{
for(std::size_t i = 0; i < num_component; ++i)
{
Border_halfedge_map border_halfedge_map_in_cc(less_hedge);
CGAL_assertion(halfedge_pairs.empty());
CGAL_assertion(manifold_halfedge_pairs.empty());
for(int j = 0; j < static_cast<int>(border_edges_per_cc[i].size()); ++j)
{
halfedge_descriptor he = border_edges_per_cc[i][j];
fill_pairs(he, border_halfedge_map_in_cc, halfedge_pairs,
manifold_halfedge_pairs, vpmap, pmesh);
}
// put in `out` only manifold edges from the set of edges to stitch.
// We choose not to allow only a pair out of the whole set to be stitched
// as we can produce inconsistent stitching along a sequence of non-manifold edges
std::size_t nb_pairs=halfedge_pairs.size();
for (std::size_t k=0; k<nb_pairs; ++k)
{
if( manifold_halfedge_pairs[k] )
{
*out++=halfedge_pairs[k];
}
}
halfedge_pairs.clear();
manifold_halfedge_pairs.clear();
}
}
else
{
// put in `out` only manifold edges from the set of edges to stitch. // put in `out` only manifold edges from the set of edges to stitch.
// We choose not to allow only a pair out of the whole set to be stitched // We choose not to allow only a pair out of the whole set to be stitched
// as we can produce inconsistent stitching along a sequence of non-manifold edges // as we can produce inconsistent stitching along a sequence of non-manifold edges
@ -133,6 +240,7 @@ collect_duplicated_stitchable_boundary_edges
if( manifold_halfedge_pairs[i] ) if( manifold_halfedge_pairs[i] )
*out++=halfedge_pairs[i]; *out++=halfedge_pairs[i];
} }
}
return out; return out;
} }
@ -503,9 +611,16 @@ void stitch_borders(PolygonMesh& pmesh,
/// \cgalNamedParamsBegin /// \cgalNamedParamsBegin
/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. /// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
/// If this parameter is omitted, an internal property map for /// If this parameter is omitted, an internal property map for
/// `CGAL::vertex_point_t` must be available in `PolygonMesh`\cgalParamEnd /// `CGAL::vertex_point_t` must be available in `PolygonMesh`.\cgalParamEnd
/// \cgalParamBegin{apply_per_connected_component}
/// specifies if the borders should only be stitched inside their own connected component.
/// In that case, a property map for `CGAL::face_index_t` should be either available as an internal property map
/// to `pmesh` or provided as the \ref pmp_namedparameters "Named Parameter" `face_index_map`. If this is not the case,
/// a default map will be created on the fly.
/// Default value is `false`.\cgalParamEnd
/// \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh` \cgalParamEnd
/// \cgalNamedParamsEnd /// \cgalNamedParamsEnd
///
template <typename PolygonMesh, class CGAL_PMP_NP_TEMPLATE_PARAMETERS> template <typename PolygonMesh, class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
void stitch_borders(PolygonMesh& pmesh, const CGAL_PMP_NP_CLASS& np) void stitch_borders(PolygonMesh& pmesh, const CGAL_PMP_NP_CLASS& np)
{ {
@ -522,7 +637,8 @@ void stitch_borders(PolygonMesh& pmesh, const CGAL_PMP_NP_CLASS& np)
internal::collect_duplicated_stitchable_boundary_edges(pmesh, internal::collect_duplicated_stitchable_boundary_edges(pmesh,
std::back_inserter(hedge_pairs_to_stitch), std::back_inserter(hedge_pairs_to_stitch),
internal::Less_for_halfedge<PolygonMesh, VPMap>(pmesh, vpm), vpm); internal::Less_for_halfedge<PolygonMesh, VPMap>(pmesh, vpm),
vpm, np);
stitch_borders(pmesh, hedge_pairs_to_stitch); stitch_borders(pmesh, hedge_pairs_to_stitch);
internal::stitch_boundary_cycle_2(pmesh); internal::stitch_boundary_cycle_2(pmesh);

View File

@ -0,0 +1,50 @@
OFF
20 28 0
-1 -1 -1
-1 1 -1
1 1 -1
1 -1 -1
-1 -1 1
-1 1 1
1 1 1
1 -1 1
1 2 -1
1 2 1
2 1 -1
2 2 -1
2 2 1
2 1 1
1 1 0
1 1 -1
1 1 1
1 1 0
1 1 0
1 1 0
3 0 1 3
3 3 1 2
3 0 4 1
3 1 4 5
3 3 2 14
3 3 14 7
3 7 14 6
3 4 0 3
3 7 4 3
3 6 4 7
3 6 5 4
3 1 17 2
3 1 5 17
3 5 6 17
3 15 8 10
3 10 8 11
3 15 18 8
3 8 18 9
3 18 16 9
3 10 11 13
3 13 11 12
3 16 19 13
3 13 19 10
3 10 19 15
3 12 16 13
3 12 9 16
3 8 9 12
3 11 8 12

View File

@ -2,9 +2,9 @@
#include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Polyhedron_3.h> #include <CGAL/Polyhedron_3.h>
#include <CGAL/Surface_mesh.h> #include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/stitch_borders.h> #include <CGAL/Polygon_mesh_processing/stitch_borders.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <set> #include <set>
@ -34,6 +34,29 @@ void test_polyhedron(const char* fname)
std::cout << "OK\n"; std::cout << "OK\n";
} }
template <typename K>
void test_polyhedron_cc(const char* fname)
{
typedef CGAL::Polyhedron_3<K> Polyhedron;
std::cout << "Testing Polyhedron_3 " << fname << "..." << std::flush;
std::ifstream input(fname);
Polyhedron poly;
if (!input || !(input >> poly)){
std::cerr << "Error: can not read file.";
return;
}
assert(poly.size_of_vertices() > 0);
CGAL::Polygon_mesh_processing::
stitch_borders(poly,
CGAL::Polygon_mesh_processing::parameters::apply_per_connected_component(true));
poly.normalize_border();
assert(poly.is_valid(false, 5));
std::cout << "OK\n";
}
void test_surface_mesh(const char* fname) void test_surface_mesh(const char* fname)
{ {
@ -57,6 +80,29 @@ void test_surface_mesh(const char* fname)
std::cout << "OK\n"; std::cout << "OK\n";
} }
void test_surface_mesh_cc(const char* fname)
{
typedef Epic K;
typedef K::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Mesh;
std::cout << "Testing Surface_mesh " << fname << "..." << std::flush;
std::ifstream input(fname);
Mesh m;
if (!input || !(input >> m)){
std::cerr << "Error: can not read file.";
return;
}
CGAL::Polygon_mesh_processing::stitch_borders(m,
CGAL::Polygon_mesh_processing::parameters::apply_per_connected_component(true));
//todo : add a validity test
assert(is_valid(m));
std::cout << "OK\n";
}
int main() int main()
{ {
test_polyhedron<Epec>("data_stitching/full_border.off"); test_polyhedron<Epec>("data_stitching/full_border.off");
@ -73,6 +119,7 @@ int main()
test_polyhedron<Epic>("data_stitching/two_patches.off"); test_polyhedron<Epic>("data_stitching/two_patches.off");
test_polyhedron<Epic>("data_stitching/non_manifold.off"); test_polyhedron<Epic>("data_stitching/non_manifold.off");
test_polyhedron<Epic>("data_stitching/non_manifold2.off"); test_polyhedron<Epic>("data_stitching/non_manifold2.off");
test_polyhedron_cc<Epic>("data_stitching/nm_cubes.off");
test_surface_mesh("data_stitching/full_border.off"); test_surface_mesh("data_stitching/full_border.off");
test_surface_mesh("data_stitching/full_border_quads.off"); test_surface_mesh("data_stitching/full_border_quads.off");
@ -84,7 +131,7 @@ int main()
test_surface_mesh("data_stitching/non_stitchable.off"); test_surface_mesh("data_stitching/non_stitchable.off");
test_surface_mesh("data_stitching/deg_border.off"); test_surface_mesh("data_stitching/deg_border.off");
test_surface_mesh("data_stitching/non_manifold.off"); test_surface_mesh("data_stitching/non_manifold.off");
test_surface_mesh("data_stitching/non_manifold2.off"); test_surface_mesh_cc("data_stitching/nm_cubes.off");
return 0; return 0;
} }

View File

@ -171,6 +171,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
add_library(demo_framework SHARED add_library(demo_framework SHARED
Scene.cpp Scene.cpp
Viewer.cpp Viewer.cpp
Three.cpp
${ViewerUI_FILES} ${ViewerUI_FILES}
${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES} ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES}
Viewer_interface_moc.cpp Viewer_interface_moc.cpp
@ -184,6 +185,11 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
target_link_libraries(demo_framework target_link_libraries(demo_framework
PUBLIC Qt5::OpenGL Qt5::Widgets Qt5::Gui Qt5::Script PUBLIC Qt5::OpenGL Qt5::Widgets Qt5::Gui Qt5::Script
) )
# Let's define `three_EXPORT` during the compilation of `demo_framework`,
# in addition of `demo_framework_EXPORT` (defined automatically by
# CMake). That is to deal with the visibility of symbols of
# `Three.h`/`Three.cpp`.
target_compile_definitions(demo_framework PRIVATE three_EXPORTS=1)
if(CGAL_HEADER_ONLY) if(CGAL_HEADER_ONLY)
target_compile_definitions(demo_framework PRIVATE -DCGAL_USE_Qt5_RESOURCES) target_compile_definitions(demo_framework PRIVATE -DCGAL_USE_Qt5_RESOURCES)
endif() endif()
@ -200,6 +206,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
add_library(scene_color_ramp SHARED Color_ramp.cpp) add_library(scene_color_ramp SHARED Color_ramp.cpp)
target_link_libraries(scene_color_ramp PRIVATE Qt5::Core) target_link_libraries(scene_color_ramp PRIVATE Qt5::Core)
add_library(scene_callback_signaler SHARED Callback_signaler.cpp)
target_link_libraries(scene_callback_signaler PRIVATE Qt5::Core)
add_library(point_dialog SHARED Show_point_dialog.cpp Show_point_dialog.ui ${Show_point_dialogUI_FILES}) add_library(point_dialog SHARED Show_point_dialog.cpp Show_point_dialog.ui ${Show_point_dialogUI_FILES})
target_link_libraries(point_dialog target_link_libraries(point_dialog
PUBLIC Qt5::OpenGL Qt5::Gui Qt5::Script Qt5::Widgets) PUBLIC Qt5::OpenGL Qt5::Gui Qt5::Script Qt5::Widgets)

View File

@ -0,0 +1,11 @@
#include "Callback_signaler.h"
Callback_signaler::Callback_signaler()
: is_canceled(false)
{
}
void Callback_signaler::emit_signal (int value) const
{
Q_EMIT progressChanged(value);
}

View File

@ -0,0 +1,39 @@
#ifndef CALLBACK_SIGNALER_H
#define CALLBACK_SIGNALER_H
#include <QObject>
#include <QtCore/qglobal.h>
#ifdef scene_callback_signaler_EXPORTS
# define SCENE_CALLBACK_SIGNALER_EXPORT Q_DECL_EXPORT
#else
# define SCENE_CALLBACK_SIGNALER_EXPORT Q_DECL_IMPORT
#endif
class SCENE_CALLBACK_SIGNALER_EXPORT Callback_signaler
: public QObject
{
Q_OBJECT
public:
bool is_canceled;
Callback_signaler();
void emit_signal (int value) const;
public Q_SLOTS:
void cancel()
{
is_canceled = true;
}
Q_SIGNALS:
void progressChanged(int) const;
};
#endif // CALLBACK_SIGNALER_H

View File

@ -36,6 +36,7 @@
#include <QStandardItem> #include <QStandardItem>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
#include <QTreeWidget> #include <QTreeWidget>
#include <QDockWidget>
#include <stdexcept> #include <stdexcept>
#ifdef QT_SCRIPT_LIB #ifdef QT_SCRIPT_LIB
# include <QScriptValue> # include <QScriptValue>
@ -44,6 +45,7 @@
# endif # endif
#endif #endif
#include <CGAL/Three/Three.h>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h> #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h> #include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
#include <CGAL/Three/Scene_item_with_properties.h> #include <CGAL/Three/Scene_item_with_properties.h>
@ -131,6 +133,7 @@ MainWindow::MainWindow(bool verbose, QWidget* parent)
ui = new Ui::MainWindow; ui = new Ui::MainWindow;
ui->setupUi(this); ui->setupUi(this);
menuBar()->setNativeMenuBar(false); menuBar()->setNativeMenuBar(false);
CGAL::Three::Three::s_mainwindow = this;
menu_map[ui->menuOperations->title()] = ui->menuOperations; menu_map[ui->menuOperations->title()] = ui->menuOperations;
this->verbose = verbose; this->verbose = verbose;
// remove the Load Script menu entry, when the demo has not been compiled with QT_SCRIPT_LIB // remove the Load Script menu entry, when the demo has not been compiled with QT_SCRIPT_LIB
@ -147,6 +150,8 @@ MainWindow::MainWindow(bool verbose, QWidget* parent)
scene = new Scene(this); scene = new Scene(this);
viewer->textRenderer()->setScene(scene); viewer->textRenderer()->setScene(scene);
viewer->setScene(scene); viewer->setScene(scene);
CGAL::Three::Three::s_scene = scene;
CGAL::Three::Three::s_connectable_scene = scene;
ui->actionMaxTextItemsDisplayed->setText(QString("Set Maximum Text Items Displayed : %1").arg(viewer->textRenderer()->getMax_textItems())); ui->actionMaxTextItemsDisplayed->setText(QString("Set Maximum Text Items Displayed : %1").arg(viewer->textRenderer()->getMax_textItems()));
{ {
QShortcut* shortcut = new QShortcut(QKeySequence(Qt::ALT+Qt::Key_Q), this); QShortcut* shortcut = new QShortcut(QKeySequence(Qt::ALT+Qt::Key_Q), this);
@ -305,7 +310,7 @@ MainWindow::MainWindow(bool verbose, QWidget* parent)
QDockWidget* dock = new QDockWidget(debug_widgets_names[i], this); QDockWidget* dock = new QDockWidget(debug_widgets_names[i], this);
dock->setObjectName(debug_widgets_names[i]); dock->setObjectName(debug_widgets_names[i]);
dock->setWidget(debugger->widget(debug_widgets[i])); dock->setWidget(debugger->widget(debug_widgets[i]));
this->addDockWidget(Qt::BottomDockWidgetArea, dock); this->QMainWindow::addDockWidget(Qt::BottomDockWidgetArea, dock);
dock->hide(); dock->hide();
} }
debugger->setAutoShowStandardWindow(false); debugger->setAutoShowStandardWindow(false);

View File

@ -5,6 +5,7 @@
#include <QtOpenGL/qgl.h> #include <QtOpenGL/qgl.h>
#include <CGAL/Qt/DemosMainWindow.h> #include <CGAL/Qt/DemosMainWindow.h>
#include <CGAL/Three/Three.h>
#include <QScriptEngine> #include <QScriptEngine>
#include <QScriptable> #include <QScriptable>
@ -48,6 +49,7 @@ namespace Ui {
class MAINWINDOW_EXPORT MainWindow : class MAINWINDOW_EXPORT MainWindow :
public CGAL::Qt::DemosMainWindow, public CGAL::Qt::DemosMainWindow,
public Messages_interface, public Messages_interface,
public CGAL::Three::Three,
protected QScriptable protected QScriptable
{ {
Q_OBJECT Q_OBJECT
@ -410,6 +412,7 @@ private:
//!Called when "Add new group" in the file menu is triggered. //!Called when "Add new group" in the file menu is triggered.
QAction* actionAddToGroup; QAction* actionAddToGroup;
QAction* actionResetDefaultLoaders; QAction* actionResetDefaultLoaders;
CGAL::Three::Three* three;
void print_message(QString message) { messages->information(message); } void print_message(QString message) { messages->information(message); }
Messages_interface* messages; Messages_interface* messages;

View File

@ -1,5 +1,6 @@
#include "Scene_polyhedron_selection_item.h" #include "Scene_polyhedron_selection_item.h"
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h> #include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
#include <CGAL/Three/Three.h>
#include <fstream> #include <fstream>
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_selection_io_plugin : class Polyhedron_demo_selection_io_plugin :
@ -19,7 +20,13 @@ public:
#endif #endif
bool canLoad() const { return true; } bool canLoad() const {
Scene_facegraph_item* sel_item = qobject_cast<Scene_facegraph_item*>(CGAL::Three::Three::scene()->item(
CGAL::Three::Three::scene()->mainSelectionIndex()));
if(sel_item)
return true;
return false;
}
CGAL::Three::Scene_item* load(QFileInfo fileinfo) { CGAL::Three::Scene_item* load(QFileInfo fileinfo) {
if(fileinfo.suffix().toLower() != "txt") return 0; if(fileinfo.suffix().toLower() != "txt") return 0;
// There will be no actual loading at this step. // There will be no actual loading at this step.

View File

@ -46,17 +46,23 @@ class Polyhedron_demo_polyhedron_stitching_plugin :
QAction* actionDetectBorders; QAction* actionDetectBorders;
QAction* actionStitchBorders; QAction* actionStitchBorders;
QAction* actionStitchByCC;
public: public:
QList<QAction*> actions() const { return QList<QAction*>() << actionDetectBorders << actionStitchBorders; } QList<QAction*> actions() const { return QList<QAction*>() << actionDetectBorders << actionStitchBorders << actionStitchByCC; }
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* /* m */) void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* /* m */)
{ {
scene = scene_interface; scene = scene_interface;
actionDetectBorders= new QAction(tr("Detect Boundaries"), mainWindow); actionDetectBorders= new QAction(tr("Detect Boundaries"), mainWindow);
actionStitchBorders= new QAction(tr("Stitch Duplicated Boundaries"), mainWindow);
actionDetectBorders->setObjectName("actionDetectBorders"); actionDetectBorders->setObjectName("actionDetectBorders");
actionDetectBorders->setProperty("subMenuName", "Polygon Mesh Processing");
actionStitchBorders= new QAction(tr("Stitch Duplicated Boundaries"), mainWindow);
actionStitchBorders->setObjectName("actionStitchBorders"); actionStitchBorders->setObjectName("actionStitchBorders");
actionStitchBorders->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionStitchBorders->setProperty("subMenuName", "Polygon Mesh Processing/Repair");
actionDetectBorders->setProperty("subMenuName", "Polygon Mesh Processing");
actionStitchByCC= new QAction(tr("Stitch Borders Per Connected Components"), mainWindow);
actionStitchByCC->setObjectName("actionStitchByCC");
actionStitchByCC->setProperty("subMenuName", "Polygon Mesh Processing/Repair");
autoConnectActions(); autoConnectActions();
} }
@ -76,9 +82,13 @@ public:
template <typename Item> template <typename Item>
void on_actionStitchBorders_triggered(Scene_interface::Item_id index); void on_actionStitchBorders_triggered(Scene_interface::Item_id index);
template <typename Item>
void on_actionStitchByCC_triggered(Scene_interface::Item_id index);
public Q_SLOTS: public Q_SLOTS:
void on_actionDetectBorders_triggered(); void on_actionDetectBorders_triggered();
void on_actionStitchBorders_triggered(); void on_actionStitchBorders_triggered();
void on_actionStitchByCC_triggered();
}; // end Polyhedron_demo_polyhedron_stitching_plugin }; // end Polyhedron_demo_polyhedron_stitching_plugin
@ -176,4 +186,27 @@ void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchBorders_trigger
on_actionStitchBorders_triggered<Scene_surface_mesh_item>(index); on_actionStitchBorders_triggered<Scene_surface_mesh_item>(index);
} }
} }
template <typename Item>
void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered(Scene_interface::Item_id index)
{
Item* item =
qobject_cast<Item*>(scene->item(index));
if(!item)
return;
CGAL::Polygon_mesh_processing::stitch_borders(*item->polyhedron(),
CGAL::Polygon_mesh_processing::parameters::apply_per_connected_component(true));
item->invalidateOpenGLBuffers();
scene->itemChanged(item);
}
void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered()
{
Q_FOREACH(int index, scene->selectionIndices()){
on_actionStitchByCC_triggered<Scene_polyhedron_item>(index);
on_actionStitchByCC_triggered<Scene_surface_mesh_item>(index);
}
}
#include "Polyhedron_stitching_plugin.moc" #include "Polyhedron_stitching_plugin.moc"

View File

@ -6,17 +6,17 @@ if(EIGEN3_FOUND)
qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui) qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui)
polyhedron_demo_plugin(point_set_normal_estimation_plugin Point_set_normal_estimation_plugin ${point_set_normal_estimationUI_FILES}) polyhedron_demo_plugin(point_set_normal_estimation_plugin Point_set_normal_estimation_plugin ${point_set_normal_estimationUI_FILES})
target_link_libraries(point_set_normal_estimation_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(point_set_normal_estimation_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
qt5_wrap_ui( features_detection_pluginUI_FILES Features_detection_plugin.ui) qt5_wrap_ui( features_detection_pluginUI_FILES Features_detection_plugin.ui)
polyhedron_demo_plugin(features_detection_plugin Features_detection_plugin ${features_detection_pluginUI_FILES}) polyhedron_demo_plugin(features_detection_plugin Features_detection_plugin ${features_detection_pluginUI_FILES})
target_link_libraries(features_detection_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(features_detection_plugin PUBLIC scene_points_with_normal_item)
polyhedron_demo_plugin(point_set_smoothing_plugin Point_set_smoothing_plugin) polyhedron_demo_plugin(point_set_smoothing_plugin Point_set_smoothing_plugin)
target_link_libraries(point_set_smoothing_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(point_set_smoothing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
polyhedron_demo_plugin(point_set_average_spacing_plugin Point_set_average_spacing_plugin) polyhedron_demo_plugin(point_set_average_spacing_plugin Point_set_average_spacing_plugin)
target_link_libraries(point_set_average_spacing_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(point_set_average_spacing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
else(EIGEN3_FOUND) else(EIGEN3_FOUND)
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Surface reconstruction plugin will not be available.") message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Surface reconstruction plugin will not be available.")
@ -29,11 +29,11 @@ endif()
qt5_wrap_ui(point_set_bilateral_smoothingUI_FILES Point_set_bilateral_smoothing_plugin.ui) qt5_wrap_ui(point_set_bilateral_smoothingUI_FILES Point_set_bilateral_smoothing_plugin.ui)
polyhedron_demo_plugin(point_set_bilateral_smoothing_plugin Point_set_bilateral_smoothing_plugin ${point_set_bilateral_smoothingUI_FILES}) polyhedron_demo_plugin(point_set_bilateral_smoothing_plugin Point_set_bilateral_smoothing_plugin ${point_set_bilateral_smoothingUI_FILES})
target_link_libraries(point_set_bilateral_smoothing_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(point_set_bilateral_smoothing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
qt5_wrap_ui( ps_outliers_removal_UI_FILES Point_set_outliers_removal_plugin.ui) qt5_wrap_ui( ps_outliers_removal_UI_FILES Point_set_outliers_removal_plugin.ui)
polyhedron_demo_plugin(point_set_outliers_removal_plugin Point_set_outliers_removal_plugin ${ps_outliers_removal_UI_FILES}) polyhedron_demo_plugin(point_set_outliers_removal_plugin Point_set_outliers_removal_plugin ${ps_outliers_removal_UI_FILES})
target_link_libraries(point_set_outliers_removal_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(point_set_outliers_removal_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
qt5_wrap_ui( point_set_selectionUI_FILES Point_set_selection_widget.ui) qt5_wrap_ui( point_set_selectionUI_FILES Point_set_selection_widget.ui)
polyhedron_demo_plugin(point_set_selection_plugin Point_set_selection_plugin ${point_set_selectionUI_FILES}) polyhedron_demo_plugin(point_set_selection_plugin Point_set_selection_plugin ${point_set_selectionUI_FILES})
@ -41,12 +41,11 @@ endif()
qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui) qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui)
polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES}) polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES})
target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_polyhedron_item scene_points_with_normal_item scene_polygon_soup_item) target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_polyhedron_item scene_points_with_normal_item scene_polygon_soup_item scene_callback_signaler)
qt5_wrap_ui(point_set_simplificationUI_FILES Point_set_simplification_plugin.ui) qt5_wrap_ui(point_set_simplificationUI_FILES Point_set_simplification_plugin.ui)
polyhedron_demo_plugin(point_set_simplification_plugin Point_set_simplification_plugin ${point_set_simplificationUI_FILES}) polyhedron_demo_plugin(point_set_simplification_plugin Point_set_simplification_plugin ${point_set_simplificationUI_FILES})
target_link_libraries(point_set_simplification_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(point_set_simplification_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
qt5_wrap_ui(point_set_upsamplingUI_FILES Point_set_upsampling_plugin.ui) qt5_wrap_ui(point_set_upsamplingUI_FILES Point_set_upsampling_plugin.ui)
polyhedron_demo_plugin(point_set_upsampling_plugin Point_set_upsampling_plugin ${point_set_upsamplingUI_FILES}) polyhedron_demo_plugin(point_set_upsampling_plugin Point_set_upsampling_plugin ${point_set_upsamplingUI_FILES})
@ -54,7 +53,7 @@ endif()
qt5_wrap_ui(point_set_wlopFILES Point_set_wlop_plugin.ui) qt5_wrap_ui(point_set_wlopFILES Point_set_wlop_plugin.ui)
polyhedron_demo_plugin(point_set_wlop_plugin Point_set_wlop_plugin ${point_set_wlopFILES}) polyhedron_demo_plugin(point_set_wlop_plugin Point_set_wlop_plugin ${point_set_wlopFILES})
target_link_libraries(point_set_wlop_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(point_set_wlop_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
polyhedron_demo_plugin(merge_point_sets_plugin Merge_point_sets_plugin) polyhedron_demo_plugin(merge_point_sets_plugin Merge_point_sets_plugin)
target_link_libraries(merge_point_sets_plugin PUBLIC scene_points_with_normal_item) target_link_libraries(merge_point_sets_plugin PUBLIC scene_points_with_normal_item)

View File

@ -1,10 +1,12 @@
//#undef CGAL_LINKED_WITH_TBB
#include "config.h" #include "config.h"
#include "Scene_points_with_normal_item.h" #include "Scene_points_with_normal_item.h"
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h> #include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h> #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/compute_average_spacing.h> #include <CGAL/compute_average_spacing.h>
#include <CGAL/Timer.h> #include <CGAL/Real_timer.h>
#include <CGAL/Memory_sizer.h> #include <CGAL/Memory_sizer.h>
#include <QObject> #include <QObject>
@ -14,6 +16,9 @@
#include <QtPlugin> #include <QtPlugin>
#include <QInputDialog> #include <QInputDialog>
#include <QMessageBox> #include <QMessageBox>
#include "run_with_qprogressdialog.h"
// Concurrency // Concurrency
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
typedef CGAL::Parallel_tag Concurrency_tag; typedef CGAL::Parallel_tag Concurrency_tag;
@ -21,6 +26,26 @@ typedef CGAL::Parallel_tag Concurrency_tag;
typedef CGAL::Sequential_tag Concurrency_tag; typedef CGAL::Sequential_tag Concurrency_tag;
#endif #endif
struct Compute_average_spacing_functor
: public Functor_with_signal_callback
{
Point_set* points;
const int nb_neighbors;
boost::shared_ptr<double> result;
Compute_average_spacing_functor (Point_set* points, const int nb_neighbors)
: points (points), nb_neighbors (nb_neighbors), result (new double(0)) { }
void operator()()
{
*result = CGAL::compute_average_spacing<Concurrency_tag>(
points->all_or_selection_if_not_empty(),
nb_neighbors,
points->parameters().
callback (*(this->callback())));
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_point_set_average_spacing_plugin : class Polyhedron_demo_point_set_average_spacing_plugin :
public QObject, public QObject,
@ -86,16 +111,16 @@ void Polyhedron_demo_point_set_average_spacing_plugin::on_actionAverageSpacing_t
if(!ok) if(!ok)
return; return;
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
QApplication::processEvents(); QApplication::processEvents();
CGAL::Timer task_timer; task_timer.start(); CGAL::Real_timer task_timer; task_timer.start();
std::cerr << "Average spacing (k=" << nb_neighbors <<")...\n"; std::cerr << "Average spacing (k=" << nb_neighbors <<")...\n";
// Computes average spacing // Computes average spacing
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>( Compute_average_spacing_functor functor (points, nb_neighbors);
points->all_or_selection_if_not_empty(), run_with_qprogressdialog (functor, "Computing average spacing...", mw);
nb_neighbors,
points->parameters()); double average_spacing = *functor.result;
// Print result // Print result
Kernel::Sphere_3 bsphere = points->bounding_sphere(); Kernel::Sphere_3 bsphere = points->bounding_sphere();
@ -113,6 +138,7 @@ void Polyhedron_demo_point_set_average_spacing_plugin::on_actionAverageSpacing_t
tr("Average Spacing = %1 = %2 * point set radius") tr("Average Spacing = %1 = %2 * point set radius")
.arg(average_spacing) .arg(average_spacing)
.arg(average_spacing/radius)); .arg(average_spacing/radius));
} }
} }

View File

@ -14,6 +14,10 @@
#include <QtPlugin> #include <QtPlugin>
#include <QMessageBox> #include <QMessageBox>
#include <sstream>
#include "run_with_qprogressdialog.h"
#include "ui_Point_set_bilateral_smoothing_plugin.h" #include "ui_Point_set_bilateral_smoothing_plugin.h"
// Concurrency // Concurrency
@ -23,6 +27,30 @@ typedef CGAL::Parallel_tag Concurrency_tag;
typedef CGAL::Sequential_tag Concurrency_tag; typedef CGAL::Sequential_tag Concurrency_tag;
#endif #endif
struct Bilateral_smoothing_functor
: public Functor_with_signal_callback
{
Point_set* points;
unsigned int neighborhood_size;
unsigned int sharpness_angle;
boost::shared_ptr<double> result;
Bilateral_smoothing_functor (Point_set* points,
unsigned int neighborhood_size,
unsigned int sharpness_angle)
: points (points), neighborhood_size (neighborhood_size)
, sharpness_angle (sharpness_angle), result (new double(0)) { }
void operator()()
{
*result = CGAL::bilateral_smooth_point_set<Concurrency_tag>
(points->all_or_selection_if_not_empty(),
neighborhood_size,
points->parameters().
sharpness_angle(sharpness_angle).
callback (*(this->callback())));
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_point_set_bilateral_smoothing_plugin : class Polyhedron_demo_point_set_bilateral_smoothing_plugin :
@ -103,22 +131,25 @@ void Polyhedron_demo_point_set_bilateral_smoothing_plugin::on_actionBilateralSmo
<< dialog.iterations () << " iteration(s), neighborhood size of " << dialog.iterations () << " iteration(s), neighborhood size of "
<< dialog.neighborhood_size () << " and sharpness angle of " << dialog.neighborhood_size () << " and sharpness angle of "
<< dialog.sharpness_angle () << "... "; << dialog.sharpness_angle () << "... ";
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
CGAL::Timer task_timer; task_timer.start(); CGAL::Timer task_timer; task_timer.start();
for (unsigned int i = 0; i < dialog.iterations (); ++i) for (unsigned int i = 0; i < dialog.iterations (); ++i)
{ {
/* double error = */ std::ostringstream oss;
CGAL::bilateral_smooth_point_set<Concurrency_tag> oss << "Bilateral smoothing (iteration " << i+1 << "/" << dialog.iterations() << ")";
(points->all_or_selection_if_not_empty(),
Bilateral_smoothing_functor functor (points,
dialog.neighborhood_size (), dialog.neighborhood_size (),
points->parameters(). dialog.sharpness_angle ());
sharpness_angle(dialog.sharpness_angle ())); run_with_qprogressdialog (functor, oss.str().c_str(), mw);
double error = *functor.result;
if (std::isnan(error)) // NaN return means algorithm was interrupted
break;
} }
std::size_t memory = CGAL::Memory_sizer().virtual_size(); std::size_t memory = CGAL::Memory_sizer().virtual_size();
std::cerr << task_timer.time() << " seconds, " std::cerr << task_timer.time() << " seconds, "
<< (memory>>20) << " Mb allocated)" << (memory>>20) << " Mb allocated)"

View File

@ -18,6 +18,8 @@
#include <QInputDialog> #include <QInputDialog>
#include <QMessageBox> #include <QMessageBox>
#include "run_with_qprogressdialog.h"
#include "ui_Point_set_normal_estimation_plugin.h" #include "ui_Point_set_normal_estimation_plugin.h"
#if BOOST_VERSION == 105700 #if BOOST_VERSION == 105700
@ -32,6 +34,49 @@ typedef CGAL::Parallel_tag Concurrency_tag;
#else #else
typedef CGAL::Sequential_tag Concurrency_tag; typedef CGAL::Sequential_tag Concurrency_tag;
#endif #endif
struct PCA_estimate_normals_functor
: public Functor_with_signal_callback
{
Point_set* points;
int neighborhood_size;
unsigned int sharpness_angle;
PCA_estimate_normals_functor (Point_set* points,
int neighborhood_size)
: points (points), neighborhood_size (neighborhood_size)
{ }
void operator()()
{
CGAL::pca_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
neighborhood_size,
points->parameters().
callback (*(this->callback())));
}
};
struct Jet_estimate_normals_functor
: public Functor_with_signal_callback
{
Point_set* points;
int neighborhood_size;
unsigned int sharpness_angle;
Jet_estimate_normals_functor (Point_set* points,
int neighborhood_size)
: points (points), neighborhood_size (neighborhood_size)
{ }
void operator()()
{
CGAL::jet_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
neighborhood_size,
points->parameters().
callback (*(this->callback())));
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_point_set_normal_estimation_plugin : class Polyhedron_demo_point_set_normal_estimation_plugin :
@ -49,6 +94,7 @@ public:
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) { void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
scene = scene_interface; scene = scene_interface;
mw = mainWindow;
actionNormalEstimation = new QAction(tr("Normal Estimation"), mainWindow); actionNormalEstimation = new QAction(tr("Normal Estimation"), mainWindow);
actionNormalEstimation->setObjectName("actionNormalEstimation"); actionNormalEstimation->setObjectName("actionNormalEstimation");
actionNormalEstimation->setProperty("subMenuName","Point Set Processing"); actionNormalEstimation->setProperty("subMenuName","Point Set Processing");
@ -160,7 +206,7 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
if(!dialog.exec()) if(!dialog.exec())
return; return;
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
QApplication::processEvents(); QApplication::processEvents();
// First point to delete // First point to delete
@ -175,9 +221,8 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
std::cerr << "Estimates normal direction by PCA (k=" << dialog.pca_neighbors() <<")...\n"; std::cerr << "Estimates normal direction by PCA (k=" << dialog.pca_neighbors() <<")...\n";
// Estimates normals direction. // Estimates normals direction.
CGAL::pca_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(), PCA_estimate_normals_functor functor (points, dialog.pca_neighbors());
dialog.pca_neighbors(), run_with_qprogressdialog (functor, "Estimating normals by PCA...", mw);
points->parameters());
std::size_t memory = CGAL::Memory_sizer().virtual_size(); std::size_t memory = CGAL::Memory_sizer().virtual_size();
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, " std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "
@ -190,9 +235,8 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
std::cerr << "Estimates normal direction by Jet Fitting (k=" << dialog.jet_neighbors() <<")...\n"; std::cerr << "Estimates normal direction by Jet Fitting (k=" << dialog.jet_neighbors() <<")...\n";
// Estimates normals direction. // Estimates normals direction.
CGAL::jet_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(), Jet_estimate_normals_functor functor (points, dialog.pca_neighbors());
dialog.jet_neighbors(), run_with_qprogressdialog (functor, "Estimating normals by jet fitting...", mw);
points->parameters());
std::size_t memory = CGAL::Memory_sizer().virtual_size(); std::size_t memory = CGAL::Memory_sizer().virtual_size();
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, " std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "

View File

@ -16,6 +16,39 @@
#include <QMessageBox> #include <QMessageBox>
#include "ui_Point_set_outliers_removal_plugin.h" #include "ui_Point_set_outliers_removal_plugin.h"
#include "run_with_qprogressdialog.h"
struct Outlier_removal_functor
: public Functor_with_signal_callback
{
Point_set* points;
int nb_neighbors;
double removed_percentage;
double distance_threshold;
boost::shared_ptr<Point_set::iterator> result;
Outlier_removal_functor (Point_set* points,
int nb_neighbors,
double removed_percentage,
double distance_threshold)
: points (points), nb_neighbors (nb_neighbors)
, removed_percentage (removed_percentage), distance_threshold (distance_threshold)
, result (new Point_set::iterator) { }
void operator()()
{
// Computes outliers
*result =
CGAL::remove_outliers(*points,
nb_neighbors,
points->parameters().
threshold_percent(removed_percentage).
threshold_distance(distance_threshold).
callback (*(this->callback())));
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_point_set_outliers_removal_plugin : class Polyhedron_demo_point_set_outliers_removal_plugin :
public QObject, public QObject,
@ -31,6 +64,7 @@ private:
public: public:
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) { void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
scene = scene_interface; scene = scene_interface;
mw = mainWindow;
actionOutlierRemoval = new QAction(tr("Outliers Selection"), mainWindow); actionOutlierRemoval = new QAction(tr("Outliers Selection"), mainWindow);
actionOutlierRemoval->setProperty("subMenuName","Point Set Processing"); actionOutlierRemoval->setProperty("subMenuName","Point Set Processing");
actionOutlierRemoval->setObjectName("actionOutlierRemoval"); actionOutlierRemoval->setObjectName("actionOutlierRemoval");
@ -87,24 +121,20 @@ void Polyhedron_demo_point_set_outliers_removal_plugin::on_actionOutlierRemoval_
const double distance_threshold = dialog.distance(); const double distance_threshold = dialog.distance();
const int nb_neighbors = dialog.nbNeighbors(); const int nb_neighbors = dialog.nbNeighbors();
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
CGAL::Timer task_timer; task_timer.start(); CGAL::Timer task_timer; task_timer.start();
std::cerr << "Select outliers (" << removed_percentage <<"% with distance threshold " std::cerr << "Select outliers (" << removed_percentage <<"% with distance threshold "
<< distance_threshold << ")...\n"; << distance_threshold << ")...\n";
// Computes outliers // Computes outliers
Point_set::iterator first_point_to_remove = Outlier_removal_functor functor (points, nb_neighbors, removed_percentage, distance_threshold);
CGAL::remove_outliers(*points, run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Selecting outliers...", mw);
nb_neighbors, Point_set::iterator first_point_to_remove = *functor.result;
points->parameters().
threshold_percent(removed_percentage).
threshold_distance(distance_threshold));
std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end()); std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());
std::size_t memory = CGAL::Memory_sizer().virtual_size(); std::size_t memory = CGAL::Memory_sizer().virtual_size();
std::cerr << "Simplification: " << nb_points_to_remove << " point(s) are selected (" std::cerr << "Outliers: " << nb_points_to_remove << " point(s) are selected ("
<< task_timer.time() << " seconds, " << task_timer.time() << " seconds, "
<< (memory>>20) << " Mb allocated)" << (memory>>20) << " Mb allocated)"
<< std::endl; << std::endl;

View File

@ -38,8 +38,27 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/function_output_iterator.hpp> #include <boost/function_output_iterator.hpp>
#include "run_with_qprogressdialog.h"
#include "ui_Point_set_shape_detection_plugin.h" #include "ui_Point_set_shape_detection_plugin.h"
template <typename Shape_detection>
struct Detect_shapes_functor
: public Functor_with_signal_callback
{
Shape_detection& shape_detection;
typename Shape_detection::Parameters& op;
Detect_shapes_functor (Shape_detection& shape_detection,
typename Shape_detection::Parameters& op)
: shape_detection (shape_detection), op (op)
{ }
void operator()()
{
shape_detection.detect(op, *(this->callback()));
}
};
struct build_from_pair struct build_from_pair
{ {
@ -55,93 +74,6 @@ struct build_from_pair
}; };
struct Progress_bar_callback
{
mutable int nb;
CGAL::Real_timer timer;
double t_start;
mutable double t_latest;
int bar_size;
mutable std::size_t string_size;
Progress_bar_callback() : nb(0), bar_size (30), string_size(0)
{
timer.start();
t_start = timer.time();
t_latest = t_start;
}
bool operator()(double advancement) const
{
// Avoid calling time() at every single iteration, which could
// impact performances very badly
++ nb;
if (advancement != 1 && nb % 1000 != 0)
return true;
// If the limit is reach, interrupt the algorithm
double t = timer.time();
if (advancement == 1 || (t - t_latest) > 1.)
{
std::ostringstream oss;
oss << "[";
int adv = int(advancement * bar_size);
for (int i = 0; i < adv; ++ i)
oss << "=";
if (adv != bar_size)
oss << ">";
for (int i = adv; i < bar_size; ++ i)
oss << " ";
oss << "] " << int(advancement * 100) << "% (";
display_time (oss, t);
oss << " elapsed, ";
display_time (oss, estimate_remaining(t, advancement));
oss << " remaining)";
std::string bar_string = oss.str();
std::cerr << "\r" << bar_string;
for (std::size_t i = bar_string.size(); i < string_size; ++ i)
std::cerr << " ";
string_size = (std::max) (string_size, bar_string.size());
if (advancement == 1)
std::cerr << std::endl;
t_latest = t;
}
return true;
}
void display_time (std::ostringstream& oss, double seconds) const
{
if (seconds > 3600.)
{
int hours = int(seconds / 3600.);
oss << hours << "h";
seconds -= hours * 3600.;
}
if (seconds > 60.)
{
int minutes = (int)(seconds / 60.);
oss << minutes << "min";
seconds -= minutes * 60.;
}
oss << int(seconds) << "sec";
}
double estimate_remaining (double seconds, double advancement) const
{
return ((1. - advancement) * (seconds - t_start) / advancement);
}
};
class Point_set_demo_point_set_shape_detection_dialog : public QDialog, private Ui::PointSetShapeDetectionDialog class Point_set_demo_point_set_shape_detection_dialog : public QDialog, private Ui::PointSetShapeDetectionDialog
{ {
Q_OBJECT Q_OBJECT
@ -303,7 +235,7 @@ private:
comments += "shape -1 no assigned shape\n"; comments += "shape -1 no assigned shape\n";
} }
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
Shape_detection shape_detection; Shape_detection shape_detection;
shape_detection.set_input(*points, points->point_map(), points->normal_map()); shape_detection.set_input(*points, points->point_map(), points->normal_map());
@ -340,8 +272,8 @@ private:
// The actual shape detection. // The actual shape detection.
CGAL::Real_timer t; CGAL::Real_timer t;
t.start(); t.start();
Progress_bar_callback callback; Detect_shapes_functor<Shape_detection> functor (shape_detection, op);
shape_detection.detect(op, callback); run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Detecting shapes...", mw);
t.stop(); t.stop();
std::cout << shape_detection.shapes().size() << " shapes found in " std::cout << shape_detection.shapes().size() << " shapes found in "

View File

@ -17,6 +17,8 @@
#include <QtPlugin> #include <QtPlugin>
#include <QMessageBox> #include <QMessageBox>
#include "run_with_qprogressdialog.h"
#include "ui_Point_set_simplification_plugin.h" #include "ui_Point_set_simplification_plugin.h"
// Concurrency // Concurrency
@ -26,6 +28,68 @@ typedef CGAL::Parallel_tag Concurrency_tag;
typedef CGAL::Sequential_tag Concurrency_tag; typedef CGAL::Sequential_tag Concurrency_tag;
#endif #endif
struct Compute_average_spacing_functor
: public Functor_with_signal_callback
{
Point_set* points;
const int nb_neighbors;
boost::shared_ptr<double> result;
Compute_average_spacing_functor (Point_set* points, const int nb_neighbors)
: points (points), nb_neighbors (nb_neighbors), result (new double(0)) { }
void operator()()
{
*result = CGAL::compute_average_spacing<Concurrency_tag>(
points->all_or_selection_if_not_empty(),
nb_neighbors,
points->parameters().
callback (*(this->callback())));
}
};
struct Grid_simplify_functor
: public Functor_with_signal_callback
{
Point_set* points;
double grid_size;
boost::shared_ptr<Point_set::iterator> result;
Grid_simplify_functor (Point_set* points, double grid_size)
: points (points), grid_size (grid_size), result (new Point_set::iterator) { }
void operator()()
{
*result = CGAL::grid_simplify_point_set(*points,
grid_size,
points->parameters().
callback (*(this->callback())));
}
};
struct Hierarchy_simplify_functor
: public Functor_with_signal_callback
{
Point_set* points;
unsigned int max_cluster_size;
double max_surface_variation;
boost::shared_ptr<Point_set::iterator> result;
Hierarchy_simplify_functor (Point_set* points,
double max_cluster_size,
double max_surface_variation)
: points (points), max_cluster_size (max_cluster_size)
, max_surface_variation (max_surface_variation), result (new Point_set::iterator) { }
void operator()()
{
*result = CGAL::hierarchy_simplify_point_set(*points,
points->parameters().
size(max_cluster_size).
maximum_variation(max_surface_variation).
callback (*(this->callback())));
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_point_set_simplification_plugin : class Polyhedron_demo_point_set_simplification_plugin :
@ -41,6 +105,7 @@ class Polyhedron_demo_point_set_simplification_plugin :
public: public:
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface,Messages_interface*) { void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface,Messages_interface*) {
scene = scene_interface; scene = scene_interface;
mw = mainWindow;
actionSimplify = new QAction(tr("Simplification Selection"), mainWindow); actionSimplify = new QAction(tr("Simplification Selection"), mainWindow);
actionSimplify->setProperty("subMenuName","Point Set Processing"); actionSimplify->setProperty("subMenuName","Point Set Processing");
@ -130,7 +195,7 @@ void Polyhedron_demo_point_set_simplification_plugin::on_actionSimplify_triggere
if(!dialog.exec()) if(!dialog.exec())
return; return;
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
CGAL::Timer task_timer; task_timer.start(); CGAL::Timer task_timer; task_timer.start();
@ -152,24 +217,30 @@ void Polyhedron_demo_point_set_simplification_plugin::on_actionSimplify_triggere
std::cerr << "Point set grid simplification (cell size = " << dialog.gridCellSize() <<" * average spacing)...\n"; std::cerr << "Point set grid simplification (cell size = " << dialog.gridCellSize() <<" * average spacing)...\n";
// Computes average spacing // Computes average spacing
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(*points, 6 /* knn = 1 ring */); Compute_average_spacing_functor functor_as (points, 6);
run_with_qprogressdialog (functor_as, "Simplification: computing average spacing...", mw);
double average_spacing = *functor_as.result;
Grid_simplify_functor functor (points, dialog.gridCellSize() * average_spacing);
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Grid simplyfing...", mw);
// Computes points to remove by Grid Clustering // Computes points to remove by Grid Clustering
first_point_to_remove = first_point_to_remove = *functor.result;
CGAL::grid_simplify_point_set(*points,
dialog.gridCellSize()*average_spacing);
} }
else else
{ {
std::cerr << "Point set hierarchy simplification (cluster size = " << dialog.maximumClusterSize() std::cerr << "Point set hierarchy simplification (cluster size = " << dialog.maximumClusterSize()
<< ", maximum variation = " << dialog.maximumSurfaceVariation() << ")...\n"; << ", maximum variation = " << dialog.maximumSurfaceVariation() << ")...\n";
// Computes points to remove by Grid Clustering // Computes points to remove by Hierarchy
first_point_to_remove = Hierarchy_simplify_functor functor (points, dialog.maximumClusterSize(),
CGAL::hierarchy_simplify_point_set(*points, dialog.maximumSurfaceVariation());
points->parameters(). run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Hierarchy simplyfing...", mw);
size(dialog.maximumClusterSize()).
maximum_variation(dialog.maximumSurfaceVariation())); first_point_to_remove = *functor.result;
} }
std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end()); std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());

View File

@ -12,6 +12,8 @@
#include <CGAL/jet_smooth_point_set.h> #include <CGAL/jet_smooth_point_set.h>
#include "run_with_qprogressdialog.h"
// Concurrency // Concurrency
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
typedef CGAL::Parallel_tag Concurrency_tag; typedef CGAL::Parallel_tag Concurrency_tag;
@ -19,6 +21,24 @@ typedef CGAL::Parallel_tag Concurrency_tag;
typedef CGAL::Sequential_tag Concurrency_tag; typedef CGAL::Sequential_tag Concurrency_tag;
#endif #endif
struct Jet_smoothing_functor
: public Functor_with_signal_callback
{
Point_set* points;
const int nb_neighbors;
Jet_smoothing_functor (Point_set* points, const int nb_neighbors)
: points (points), nb_neighbors (nb_neighbors) { }
void operator()()
{
CGAL::jet_smooth_point_set<Concurrency_tag>(points->all_or_selection_if_not_empty(),
nb_neighbors,
points->parameters().
callback (*(this->callback())));
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_point_set_smoothing_plugin : class Polyhedron_demo_point_set_smoothing_plugin :
public QObject, public QObject,
@ -79,17 +99,14 @@ void Polyhedron_demo_point_set_smoothing_plugin::on_actionJetSmoothing_triggered
&ok); &ok);
if(!ok) return; if(!ok) return;
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
QApplication::processEvents(); QApplication::processEvents();
CGAL::jet_smooth_point_set<Concurrency_tag>(points->all_or_selection_if_not_empty(),
nb_neighbors, Jet_smoothing_functor functor (points, nb_neighbors);
points->parameters()); run_with_qprogressdialog (functor, "Smoothing point set...", mw);
points->invalidate_bounds(); points->invalidate_bounds();
// calling jet_smooth_point_set breaks the normals
points->remove_normal_map();
// update scene // update scene
item->invalidateOpenGLBuffers(); item->invalidateOpenGLBuffers();
scene->itemChanged(index); scene->itemChanged(index);

View File

@ -15,6 +15,8 @@
#include <QtPlugin> #include <QtPlugin>
#include <QMessageBox> #include <QMessageBox>
#include "run_with_qprogressdialog.h"
#include "ui_Point_set_wlop_plugin.h" #include "ui_Point_set_wlop_plugin.h"
// Concurrency // Concurrency
@ -24,6 +26,53 @@ typedef CGAL::Parallel_tag Concurrency_tag;
typedef CGAL::Sequential_tag Concurrency_tag; typedef CGAL::Sequential_tag Concurrency_tag;
#endif #endif
struct Compute_average_spacing_functor
: public Functor_with_signal_callback
{
Point_set* points;
const int nb_neighbors;
boost::shared_ptr<double> result;
Compute_average_spacing_functor (Point_set* points, const int nb_neighbors)
: points (points), nb_neighbors (nb_neighbors), result (new double(0)) { }
void operator()()
{
*result = CGAL::compute_average_spacing<Concurrency_tag>(
points->all_or_selection_if_not_empty(),
nb_neighbors,
points->parameters().
callback (*(this->callback())));
}
};
struct Wlop_functor
: public Functor_with_signal_callback
{
Point_set* points;
double select_percentage;
double neighbor_radius;
Scene_points_with_normal_item* new_item;
Wlop_functor (Point_set* points, double select_percentage, double neighbor_radius,
Scene_points_with_normal_item* new_item)
: points (points), select_percentage (select_percentage)
, neighbor_radius (neighbor_radius), new_item (new_item)
{ }
void operator()()
{
CGAL::wlop_simplify_and_regularize_point_set<Concurrency_tag>
(points->all_or_selection_if_not_empty(),
new_item->point_set()->point_back_inserter(),
points->parameters().
select_percentage (select_percentage).
neighbor_radius (neighbor_radius).
callback (*(this->callback())));
}
};
using namespace CGAL::Three; using namespace CGAL::Three;
class Polyhedron_demo_point_set_wlop_plugin : class Polyhedron_demo_point_set_wlop_plugin :
public QObject, public QObject,
@ -38,6 +87,7 @@ class Polyhedron_demo_point_set_wlop_plugin :
public: public:
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) { void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
scene = scene_interface; scene = scene_interface;
mw = mainWindow;
actionSimplifyAndRegularize = new QAction(tr("WLOP Simplification and Regularization Selection"), mainWindow); actionSimplifyAndRegularize = new QAction(tr("WLOP Simplification and Regularization Selection"), mainWindow);
actionSimplifyAndRegularize->setProperty("subMenuName","Point Set Processing"); actionSimplifyAndRegularize->setProperty("subMenuName","Point Set Processing");
actionSimplifyAndRegularize->setObjectName("actionSimplifyAndRegularize"); actionSimplifyAndRegularize->setObjectName("actionSimplifyAndRegularize");
@ -89,7 +139,7 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
if(!dialog.exec()) if(!dialog.exec())
return; return;
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::BusyCursor);
CGAL::Timer task_timer; task_timer.start(); CGAL::Timer task_timer; task_timer.start();
@ -98,9 +148,9 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
<< dialog.neighborhoodRadius() <<" * average spacing)...\n"; << dialog.neighborhoodRadius() <<" * average spacing)...\n";
// Computes average spacing // Computes average spacing
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(points->all_or_selection_if_not_empty(), Compute_average_spacing_functor functor_as (points, 6);
6 /* knn = 1 ring */, run_with_qprogressdialog (functor_as, "WLOP: computing average spacing...", mw);
points->parameters()); double average_spacing = *functor_as.result;
Scene_points_with_normal_item* new_item Scene_points_with_normal_item* new_item
= new Scene_points_with_normal_item(); = new Scene_points_with_normal_item();
@ -109,12 +159,9 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
item->setVisible(false); item->setVisible(false);
scene->addItem(new_item); scene->addItem(new_item);
CGAL::wlop_simplify_and_regularize_point_set<Concurrency_tag> Wlop_functor functor (points, dialog.retainedPercentage(),
(points->all_or_selection_if_not_empty(), dialog.neighborhoodRadius() * average_spacing, new_item);
new_item->point_set()->point_back_inserter(), run_with_qprogressdialog (functor, "WLOP simplification and regularization...", mw);
points->parameters().
select_percentage (dialog.retainedPercentage()).
neighbor_radius (dialog.neighborhoodRadius()*average_spacing));
std::size_t memory = CGAL::Memory_sizer().virtual_size(); std::size_t memory = CGAL::Memory_sizer().virtual_size();
std::cerr << "Simplification and regularization: " std::cerr << "Simplification and regularization: "

View File

@ -22,7 +22,6 @@
#include <CGAL/Search_traits_3.h> #include <CGAL/Search_traits_3.h>
#include <CGAL/squared_distance_3.h> #include <CGAL/squared_distance_3.h>
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/Default_diagonalize_traits.h>
#include <CGAL/compute_average_spacing.h> #include <CGAL/compute_average_spacing.h>
#include <CGAL/grid_simplify_point_set.h> #include <CGAL/grid_simplify_point_set.h>
#include <CGAL/jet_smooth_point_set.h> #include <CGAL/jet_smooth_point_set.h>

View File

@ -0,0 +1,132 @@
#include <CGAL/Three/Three.h>
#include <QDockWidget>
#include <QMetaMethod>
#include <QAction>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
using namespace CGAL::Three;
QMainWindow* Three::s_mainwindow = NULL;
Scene_interface* Three::s_scene = NULL;
QObject* Three::s_connectable_scene = NULL;
Three* Three::s_three = NULL;
QMainWindow* Three::mainWindow()
{
return s_mainwindow;
}
Scene_interface* Three::scene()
{
return s_scene;
}
QObject* Three::connectableScene()
{
return s_connectable_scene;
}
Three* Three::messages()
{
return s_three;
}
Three::Three()
{
Three::s_three = this;
}
template<class SceneType>
SceneType* Three::getSelectedItem(){
Q_FOREACH(int item_id , scene()->selectionIndices())
{
SceneType* scene_item = qobject_cast<SceneType*>(scene()->item(item_id));
if(scene_item)
return scene_item;
}
return NULL;
}
void Three::addDockWidget(QDockWidget* dock_widget)
{
mainWindow()->addDockWidget(::Qt::LeftDockWidgetArea, dock_widget);
dock_widget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
QList<QDockWidget*> dockWidgets = mainWindow()->findChildren<QDockWidget*>();
int counter = 0;
Q_FOREACH(QDockWidget* dock, dockWidgets) {
if( mainWindow()->dockWidgetArea(dock) != ::Qt::LeftDockWidgetArea ||
dock == dock_widget )
{ continue; }
if(++counter > 1) {
mainWindow()->tabifyDockWidget(dock, dock_widget);
return;
}
}
}
void Three::autoConnectActions(Polyhedron_demo_plugin_interface *plugin)
{
QObject* thisObject = dynamic_cast<QObject*>(plugin);
if(!thisObject)
return;
const QMetaObject* metaObject = thisObject->metaObject();
QVector<QMetaMethod> methods;
QVector<QString> methodsNames;
QSet<QString> connected;
for(int i = metaObject->methodOffset();
i < metaObject->methodCount();
++i)
{
const int pos = QString(metaObject->method(i).methodSignature()).indexOf('(');
methodsNames << QString(metaObject->method(i).methodSignature()).left(pos);
methods << metaObject->method(i);
}
Q_FOREACH(QAction* action, plugin->actions())
{
bool success = false;
const QMetaObject* action_metaObject = action->metaObject();
for(int i = action_metaObject->methodOffset();
i < action_metaObject->methodCount(); ++i)
{
QMetaMethod action_method = action_metaObject->method(i);
if(action_method.methodType() == QMetaMethod::Signal)
{
const int pos = QString(action_method.methodSignature()).indexOf('(');
QString methodName = QString(action_method.methodSignature()).left(pos);
QString slotName =
QString("on_%1_%2").arg(action->objectName()).arg(methodName);
// qDebug() << thisObject->tr("Slot %1 (%2)...").arg(slotName).arg(i);
int index = methodsNames.indexOf(slotName);
if(index>=0 && !connected.contains(slotName))
{
const bool ok = QObject::connect(action,
qPrintable(QString("2%1").arg(QString(action_method.methodSignature()))),
thisObject,
qPrintable(QString("1%1").arg(QString(methods[index].methodSignature()))));
if(!ok)
{
qDebug() << thisObject->tr("Cannot connect method %1.%2 to slot %3!")
.arg(action->objectName())
.arg(QString(action_method.methodSignature()))
.arg(QString(methods[index].methodSignature()));
}
else {
success = true;
connected << slotName;
}
}
}
} // end for each method of action
if(!success)
qDebug("ERROR: Failed to autoconnect the action \"%s\"!",
action->objectName().toUtf8().data());
} // end foreach action of actions()
}

View File

@ -0,0 +1,111 @@
#ifndef PROGRESS_BAR_CALLBACK_H
#define PROGRESS_BAR_CALLBACK_H
#include <CGAL/Real_timer.h>
struct Progress_bar_callback
{
mutable std::size_t nb;
CGAL::Real_timer timer;
double t_start;
mutable double t_start_estimate;
mutable double t_latest;
int bar_size;
mutable std::size_t string_size;
Progress_bar_callback(const char* title = NULL,
void* = NULL) // Hack to have same constructor as Qt_progress_bar_callback
: nb(0), bar_size (30), string_size(0)
{
if (title != NULL)
std::cerr << title << std::endl;
timer.start();
t_start = timer.time();
t_start_estimate = 0.;
t_latest = t_start;
}
bool operator()(double advancement) const
{
// Avoid calling time() at every single iteration, which could
// impact performances very badly
++ nb;
if (advancement != 1 && nb % 1000 != 0)
return true;
// If the limit is reach, interrupt the algorithm
double t = timer.time();
if (advancement == 1 || (t - t_latest) > 1.)
{
if (advancement != 0. && t_start_estimate == 0.)
t_start_estimate = t_latest;
std::ostringstream oss;
oss << "[";
int adv = int(advancement * bar_size);
for (int i = 0; i < adv; ++ i)
oss << "=";
if (adv != bar_size)
oss << ">";
for (int i = adv; i < bar_size; ++ i)
oss << " ";
oss << "] " << int(advancement * 100) << "% (";
display_time (oss, t);
oss << " elapsed, ";
display_time (oss, estimate_remaining(t, advancement));
oss << " remaining)";
std::string bar_string = oss.str();
std::cerr << "\r" << bar_string;
for (std::size_t i = bar_string.size(); i < string_size; ++ i)
std::cerr << " ";
string_size = (std::max) (string_size, bar_string.size());
t_latest = t;
if (advancement == 1)
std::cerr << std::endl;
}
return true;
}
void display_time (std::ostringstream& oss, double seconds) const
{
if (seconds == std::numeric_limits<double>::infinity())
{
oss << "unknown";
return;
}
if (seconds > 3600.)
{
int hours = int(seconds / 3600.);
oss << hours << "h";
seconds -= hours * 3600.;
}
if (seconds > 60.)
{
int minutes = (int)(seconds / 60.);
oss << minutes << "min";
seconds -= minutes * 60.;
}
oss << int(seconds) << "sec";
}
double estimate_remaining (double seconds, double advancement) const
{
if (advancement == 0.)
return std::numeric_limits<double>::infinity();
return ((1. - advancement) * (seconds - t_start_estimate) / advancement);
}
};
#endif // PROGRESS_BAR_CALLBACK_H

View File

@ -0,0 +1,68 @@
#ifndef QT_PROGRESS_BAR_CALLBACK_H
#define QT_PROGRESS_BAR_CALLBACK_H
#include <CGAL/Real_timer.h>
#include <QProgressDialog>
#include <QApplication>
class Qt_progress_bar_callback
{
private:
CGAL::Real_timer timer;
double t_start;
mutable double t_latest;
mutable std::size_t nb;
QProgressDialog* dialog;
public:
Qt_progress_bar_callback()
{
}
Qt_progress_bar_callback(const char* title, QWidget* parent)
: dialog (new QProgressDialog (QString(title),
QString("Cancel"),
0, 100,
parent))
{
dialog->setMinimumDuration(0);
dialog->setWindowModality(Qt::WindowModal);
timer.start();
t_start = timer.time();
t_latest = t_start;
}
~Qt_progress_bar_callback()
{
}
bool operator() (double advancement) const
{
// Avoid calling time() at every single iteration, which could
// impact performances very badly
++ nb;
if (advancement != 1 && nb % 1000 != 0)
return true;
// If the limit is reach, interrupt the algorithm
double t = timer.time();
if (advancement == 1 || (t - t_latest) > 0.25)
{
dialog->setValue (int (100. * advancement));
t_latest = t;
if (dialog->wasCanceled())
return false;
}
return true;
}
};
#endif // QT_PROGRESS_BAR_CALLBACK_H

View File

@ -0,0 +1,142 @@
#ifndef RUN_WITH_QPROGRESSDIALOG_H
#define RUN_WITH_QPROGRESSDIALOG_H
#include <QProgressDialog>
#include <CGAL/Real_timer.h>
#include <CGAL/thread.h>
#include "Callback_signaler.h"
#ifdef CGAL_LINKED_WITH_TBB
typedef CGAL::Parallel_tag Concurrency_tag;
#else
typedef CGAL::Sequential_tag Concurrency_tag;
#endif
class Signal_callback
{
private:
CGAL::Real_timer timer;
double t_start;
mutable double t_latest;
mutable std::size_t nb;
public:
boost::shared_ptr<double> latest_adv;
boost::shared_ptr<bool> state;
boost::shared_ptr<Callback_signaler> signaler;
Signal_callback(bool)
: latest_adv (new double(0))
, state (new bool(true))
, signaler (new Callback_signaler())
{
timer.start();
t_start = timer.time();
t_latest = t_start;
}
~Signal_callback()
{
}
bool operator() (double advancement) const
{
if (!state)
return false;
*latest_adv = advancement;
// Avoid calling time() at every single iteration, which could
// impact performances very badly
++ nb;
if (advancement != 1 && nb % 1000 != 0)
return *state;
// If the limit is reach, interrupt the algorithm
double t = timer.time();
if (advancement == 1 || (t - t_latest) > 0.25)
{
signaler->emit_signal (int (100. * advancement));
t_latest = t;
if (signaler->is_canceled)
*state = false;
}
return *state;
}
};
class Functor_with_signal_callback
{
protected:
boost::shared_ptr<Signal_callback> m_callback;
public:
Signal_callback* callback() { return m_callback.get(); }
Functor_with_signal_callback()
: m_callback (new Signal_callback(true)) { }
virtual void operator()() = 0;
};
template <typename Functor>
void run_with_qprogressdialog (Functor& functor,
const char* title,
QWidget* mainWindow)
{
return run_with_qprogressdialog<Concurrency_tag> (functor, title, mainWindow);
}
template <typename ConcurrencyTag, typename Functor>
void run_with_qprogressdialog (Functor& functor,
const char* title,
QWidget* mainWindow)
{
mainWindow->setEnabled(false);
QProgressDialog progress (QString(title),
QString("Cancel"),
0, 100,
mainWindow);
progress.setMinimumDuration(0);
Signal_callback* signal_callback = functor.callback();
QEventLoop::connect (signal_callback->signaler.get(), SIGNAL(progressChanged(int)),
&progress, SLOT(setValue(int)));
QEventLoop::connect (&progress, SIGNAL(canceled()),
signal_callback->signaler.get(), SLOT(cancel()));
#ifdef CGAL_HAS_STD_THREADS
if (boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
{
CGAL::cpp11::thread thread (functor);
while (*signal_callback->latest_adv != 1. &&
*signal_callback->state)
{
CGAL::cpp11::sleep_for (0.1);
QApplication::processEvents ();
}
thread.join();
}
else
#endif // Sequential version
{
progress.setWindowModality(Qt::WindowModal);
functor();
}
mainWindow->setEnabled(true);
}
#endif // RUN_WITH_QPROGRESSDIALOG_H

View File

@ -28,6 +28,8 @@
#include <CGAL/Polyhedron_3.h> #include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/print_OFF.h> #include <CGAL/IO/print_OFF.h>
#include <CGAL/IO/scan_OFF.h> #include <CGAL/IO/scan_OFF.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/named_function_params.h>
#include <iostream> #include <iostream>
namespace CGAL { namespace CGAL {
@ -36,16 +38,54 @@ namespace CGAL {
template < class Traits, template < class Traits,
class Items, class Items,
template < class T, class I, class A> template < class T, class I, class A>
class HDS, class Alloc> class HDS, class Alloc, class NamedParameters>
bool bool
write_off( std::ostream& out, const Polyhedron_3<Traits,Items,HDS,Alloc>& P){ write_off( std::ostream& out, const Polyhedron_3<Traits,Items,HDS,Alloc>& P, const NamedParameters& np){
// writes P to `out' in PRETTY, ASCII or BINARY format // writes P to `out' in PRETTY, ASCII or BINARY format
// as the stream indicates. // as the stream indicates.
File_header_OFF header( is_binary( out), ! is_pretty( out), false); File_header_OFF header( is_binary( out), ! is_pretty( out), false);
CGAL::print_polyhedron_with_header_OFF( out, P, header); typename CGAL::Polygon_mesh_processing::GetVertexPointMap<Polyhedron_3<Traits,Items,HDS,Alloc>, NamedParameters>::const_type
vpm = choose_param(get_param(np, internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, P));
CGAL::print_polyhedron_with_header_OFF( out, P, header, vpm);
return out.good(); return out.good();
} }
template < class Traits,
class Items,
template < class T, class I, class A>
class HDS, class Alloc>
bool
write_off( std::ostream& out, const Polyhedron_3<Traits,Items,HDS,Alloc>& P){
return write_off(out, P, parameters::all_default());
}
template < class Traits,
class Items,
template < class T, class I, class A>
class HDS, class Alloc,
class NamedParameters>
bool
read_off(std::istream& in,
Polyhedron_3<Traits,Items,HDS,Alloc>& P,
NamedParameters np) {
// reads a polyhedron from `in' and appends it to P.
typedef typename CGAL::Polygon_mesh_processing::GetVertexPointMap<Polyhedron_3<Traits,Items,HDS,Alloc>, NamedParameters>::type Vpm;
Vpm vpm = choose_param(get_param(np, internal_np::vertex_point),
get_property_map(CGAL::vertex_point, P));
CGAL::scan_OFF( in, P);
if(!boost::is_default_param(get_param(np, internal_np::vertex_point)))
{
typedef typename boost::graph_traits<Polyhedron_3<Traits,Items,HDS,Alloc> >::vertex_descriptor Vertex;
typename property_map_selector<Polyhedron_3<Traits,Items,HDS,Alloc>, boost::vertex_point_t>::type
def_vpm = get_property_map(CGAL::vertex_point, P);
BOOST_FOREACH(Vertex v, vertices(P))
{
put(vpm, v, get(def_vpm, v));
}
}
return in.good();
}
template < class Traits, template < class Traits,
class Items, class Items,
@ -53,13 +93,11 @@ template < class Traits,
class HDS, class Alloc> class HDS, class Alloc>
bool bool
read_off(std::istream& in, read_off(std::istream& in,
Polyhedron_3<Traits,Items,HDS,Alloc>& P) { Polyhedron_3<Traits,Items,HDS,Alloc>& P)
// reads a polyhedron from `in' and appends it to P. {
CGAL::scan_OFF( in, P); return read_off(in, P, parameters::all_default());
return in.good();
} }
template < class Traits, template < class Traits,
class Items, class Items,
template < class T, class I, class A> template < class T, class I, class A>

View File

@ -15,221 +15,335 @@
// $Id$ // $Id$
// SPDX-License-Identifier: LGPL-3.0+ // SPDX-License-Identifier: LGPL-3.0+
// //
// Author(s) : Andreas Fabri // Author(s) : Andreas Fabri,
// Mael Rouxel-Labbé
#ifndef CGAL_IO_STL_READER_H #ifndef CGAL_IO_STL_READER_H
#define CGAL_IO_STL_READER_H #define CGAL_IO_STL_READER_H
#include <CGAL/array.h> #include <CGAL/array.h>
#include <CGAL/IO/io.h>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <vector>
#include <map>
#include <iostream>
#include <string>
#include <cctype> #include <cctype>
#include <iostream>
#include <map>
#include <string>
#include <vector>
namespace CGAL { namespace CGAL {
bool bool read_ASCII_facet(std::istream& input,
read_STL( std::istream& input, std::vector<cpp11::array<double,3> >& points,
std::vector<cpp11::array<int,3> >& facets,
int& index,
std::map<cpp11::array<double, 3>, int >& index_map,
bool verbose = false)
{
// Here, we have already read the word 'facet' and are looking to read till 'endfacet'
std::string s;
std::string vertex("vertex"),
endfacet("endfacet");
int count = 0;
cpp11::array<double, 3> p;
cpp11::array<int, 3> ijk;
while(input >> s)
{
if(s == endfacet)
{
if(count != 3)
{
if(verbose)
std::cerr << "Error: only triangulated surfaces are supported" << std::endl;
return false;
}
facets.push_back(ijk);
return true;
}
else if(s == vertex)
{
if(count >= 3)
{
if(verbose)
std::cerr << "Error: only triangulated surfaces are supported" << std::endl;
return false;
}
if(!(input >> iformat(p[0]) >> iformat(p[1]) >> iformat(p[2])))
{
if(verbose)
std::cerr << "Error while reading point coordinates (premature end of file)" << std::endl;
return false;
}
else
{
std::map<cpp11::array<double, 3>, int>::iterator iti=
index_map.insert(std::make_pair(p, -1)).first;
if(iti->second == -1)
{
ijk[count] = index;
iti->second = index++;
points.push_back(p);
}
else
{
ijk[count] = iti->second;
}
}
++count;
}
}
if(verbose)
std::cerr << "Error while reading facet (premature end of file)" << std::endl;
return false;
}
bool parse_ASCII_STL(std::istream& input,
std::vector<cpp11::array<double,3> >& points, std::vector<cpp11::array<double,3> >& points,
std::vector<cpp11::array<int,3> >& facets, std::vector<cpp11::array<int,3> >& facets,
bool verbose = false) bool verbose = false)
{ {
bool is_binary_file = false; if(verbose)
std::cout << "Parsing ASCII file..." << std::endl;
if(!input.good())
return true;
// Here, we have already read the word 'solid'
std::string s, solid("solid"), facet("facet");
std::map<cpp11::array<double,3>, int> pmap;
int index = 0; int index = 0;
cpp11::array<int,3> ijk; std::map<cpp11::array<double, 3>, int> index_map;
cpp11::array<double,3> p;
char line[80]; std::string s;
int i = 0, ni = 0; std::string facet("facet"),
endsolid("endsolid");
// read the 5 first characters to check if the first word is "solid" while(input >> s)
boost::uint8_t c; {
for(; i < 5; i++){ if(s == facet)
{
if(!read_ASCII_facet(input, points, facets, index, index_map, verbose))
return false;
}
else if(s == endsolid)
{
return true;
}
}
if(verbose)
std::cerr << "Error while parsing ASCII file" << std::endl;
return false;
}
bool parse_binary_STL(std::istream& input,
std::vector<cpp11::array<double,3> >& points,
std::vector<cpp11::array<int,3> >& facets,
bool verbose = false)
{
if(verbose)
std::cout << "Parsing binary file..." << std::endl;
// Start from the beginning again to simplify things
input.clear();
input.seekg(0, std::ios::beg);
if(!input.good())
return true;
// Discard the first 80 chars (unused header)
int pos = 0;
char c;
if(verbose)
std::cout << "header: ";
while(pos < 80)
{
input.read(reinterpret_cast<char*>(&c), sizeof(c)); input.read(reinterpret_cast<char*>(&c), sizeof(c));
line[i]=c; if(!input.good())
break;
if(verbose)
std::cout << c;
++pos;
} }
s = std::string(line,5); if(verbose)
if(s == solid){ std::cout << std::endl;
// we found the keyword "solid" which is supposed to indicate the file is Ascii
// But it might still be binary, so we have to find out if it is followed
// by an (optional) name and then the keyword "facet"
// When we find "facet" we conclude that it is really Ascii
// first skip whitespaces after solid if(pos != 80)
do { return true; // empty file
input.read(reinterpret_cast<char*>(&c), sizeof(c));
line[i++]=c;
}while(isspace(c) && ( i < 80));
if(i==80){
is_binary_file = true;
goto done;
}
// now c is not whitespace
ni = i-1; // here starts either the name or the keyword "facet"
do {
input.read(reinterpret_cast<char*>(&c), sizeof(c));
line[i++]=c;
}while(! isspace(c) && ( i < 80));
s = std::string(line+ni, (i-1) - ni);
# ifdef CGAL_DEBUG_BINARY_HEADER
std::cout << "|" << s << "|" << std::endl;
# endif
if(s == facet){
goto done;
} else if(i == 80){
// the entire header is a name
is_binary_file = true;
goto done;
}
// we continue to read what comes after the name int index = 0;
std::map<cpp11::array<double, 3>, int> index_map;
// now c is whitespace, skip other whitespaces
do {
input.read(reinterpret_cast<char*>(&c), sizeof(c));
line[i++]=c;
}while(isspace(c) && ( i < 80));
if(i==80){
is_binary_file = true;
goto done;
}
// now c is not whitespace
ni = i-1; // here starts either "facet", or it is really binary
do {
input.read(reinterpret_cast<char*>(&c), sizeof(c));
line[i++]=c;
}while(! isspace(c) && ( i < 80));
s = std::string(line+ni, (i-1) - ni);
# ifdef CGAL_DEBUG_BINARY_HEADER
std::cout << "|" << s << "|" << std::endl;
# endif
if(s == facet){
goto done;
} else {
for(; i < 80; i++){
input.read(reinterpret_cast<char*>(&c), sizeof(c));
}
is_binary_file = true;
goto done;
}
}else{
// we read the other 75 characters of the header
for(; i < 80; i++){
input.read(reinterpret_cast<char*>(&c), sizeof(c));
}
is_binary_file = true;
}
done:
if(is_binary_file){
boost::uint32_t N32; boost::uint32_t N32;
input.read(reinterpret_cast<char*>(&N32), sizeof(N32)); if(!(input.read(reinterpret_cast<char*>(&N32), sizeof(N32))))
{
if(verbose)
std::cerr << "Error while reading number of facets" << std::endl;
return false;
}
unsigned int N = N32; unsigned int N = N32;
if(verbose)
std::cout << N << " facets to read" << std::endl;
for(unsigned int i=0; i < N; i++){ for(unsigned int i=0; i<N; ++i)
{
float normal[3]; float normal[3];
input.read(reinterpret_cast<char*>(&normal[0]), sizeof(normal[0])); if(!(input.read(reinterpret_cast<char*>(&normal[0]), sizeof(normal[0]))) ||
input.read(reinterpret_cast<char*>(&normal[1]), sizeof(normal[1])); !(input.read(reinterpret_cast<char*>(&normal[1]), sizeof(normal[1]))) ||
input.read(reinterpret_cast<char*>(&normal[2]), sizeof(normal[2])); !(input.read(reinterpret_cast<char*>(&normal[2]), sizeof(normal[2]))))
{
if(verbose)
std::cerr << "Error while reading normal coordinates (premature end of file)" << std::endl;
for(int j=0; j < 3; j++){ return false;
}
cpp11::array<int, 3> ijk;
for(int j=0; j<3; ++j)
{
float x,y,z; float x,y,z;
input.read(reinterpret_cast<char*>(&x), sizeof(x)); if(!(input.read(reinterpret_cast<char*>(&x), sizeof(x))) ||
input.read(reinterpret_cast<char*>(&y), sizeof(y)); !(input.read(reinterpret_cast<char*>(&y), sizeof(y))) ||
input.read(reinterpret_cast<char*>(&z), sizeof(z)); !(input.read(reinterpret_cast<char*>(&z), sizeof(z))))
{
if(verbose)
std::cerr << "Error while reading vertex coordinates (premature end of file)" << std::endl;
return false;
}
cpp11::array<double, 3> p;
p[0] = x; p[1] = y; p[2] = z; p[0] = x; p[1] = y; p[2] = z;
std::map<cpp11::array<double, 3>, int>::iterator iti = std::map<cpp11::array<double, 3>, int>::iterator iti =
pmap.insert(std::make_pair(p,-1)).first; index_map.insert(std::make_pair(p, -1)).first;
if(iti->second==-1){
if(iti->second == -1)
{
ijk[j] = index; ijk[j] = index;
iti->second = index++; iti->second = index++;
points.push_back(p); points.push_back(p);
} else { }
else
{
ijk[j] = iti->second; ijk[j] = iti->second;
} }
} }
if((ijk[0] != ijk[1]) &&
(ijk[0] != ijk[2]) &&
(ijk[1] != ijk[2])){
facets.push_back(ijk); facets.push_back(ijk);
}else{
if(verbose){ // Read so-called attribute byte count and ignore it
std::cerr << "ignore degenerate face" << std::endl;
}
}
char c; char c;
input.read(reinterpret_cast<char*>(&c), sizeof(c)); if(!(input.read(reinterpret_cast<char*>(&c), sizeof(c))) ||
input.read(reinterpret_cast<char*>(&c), sizeof(c)); !(input.read(reinterpret_cast<char*>(&c), sizeof(c))))
} {
return true; if(verbose)
} else { std::cerr << "Error while reading attribute byte count (premature end of file)" << std::endl;
// It is an Ascii file but the first occurence of "facet" has already be parsed
bool first_facet = true;
std::string outer("outer"),
loop("loop"),
vertex("vertex"),
endloop("endloop"),
endsolid("endsolid");
s = facet;
while(first_facet || (input >> s)){
first_facet = false;
if(s == endsolid){
//std::cerr << "found endsolid" << std::endl;
} else if(s == facet){
//std::cerr << "found facet" << std::endl;
std::getline(input, s); // ignore the normal
input >> s;
if(s != outer){
if (verbose)
std::cerr << "Expect 'outer' and got " << s << std::endl;
return false;
}
input >> s;
if(s != loop){
if (verbose)
std::cerr << "Expect 'loop' and got " << s << std::endl;
return false;
}
int count = 0;
do {
input >> s;
if(s == vertex){
// std::cerr << "found vertex" << std::endl;
if(count < 3){
input >> p[0] >> p[1] >> p[2];
std::map<cpp11::array<double,3>, int>::iterator iti=
pmap.insert(std::make_pair(p,-1)).first;
if(iti->second==-1){
ijk[count] = index;
iti->second = index++;
points.push_back(p);
} else {
ijk[count] = iti->second;
}
++count;
} else {
if (verbose)
std::cerr << "We can only read triangulated surfaces" << std::endl;
return false; return false;
} }
} }
}while(s != endloop);
facets.push_back(ijk);
}
}
return true; return true;
} }
bool read_STL(std::istream& input,
std::vector<cpp11::array<double,3> >& points,
std::vector<cpp11::array<int,3> >& facets,
bool verbose = false)
{
int pos = 0;
// Ignore all initial whitespace
char c;
while(input.read(reinterpret_cast<char*>(&c), sizeof(c)))
{
if(!isspace(c))
{
input.unget(); // move back to the first interesting char
break;
} }
++pos;
}
if(!input.good()) // reached the end
return true;
// If we have gone beyond 80 characters and have not read anything yet,
// then this must be an ASCII file.
if(pos > 80)
return parse_ASCII_STL(input, points, facets, verbose);
// We are within the first 80 characters, both ASCII and binary are possible
// Read the 5 first characters to check if the first word is "solid"
std::string s, solid("solid");
char word[5];
if(input.read(reinterpret_cast<char*>(&word[0]), sizeof(c)) &&
input.read(reinterpret_cast<char*>(&word[1]), sizeof(c)) &&
input.read(reinterpret_cast<char*>(&word[2]), sizeof(c)) &&
input.read(reinterpret_cast<char*>(&word[3]), sizeof(c)) &&
input.read(reinterpret_cast<char*>(&word[4]), sizeof(c)))
{
s = std::string(word, 5);
pos += 5;
}
else
return true; // empty file
// If the first word is not 'solid', the file must be binary
if(s != solid)
{
if(parse_binary_STL(input, points, facets, verbose))
{
return true;
}
else
{
// If we failed to read it as a binary, try as ASCII just in case...
// The file does not start with 'solid' anyway, so it's fine to reset it.
input.clear();
input.seekg(0, std::ios::beg);
return parse_ASCII_STL(input, points, facets, verbose);
}
}
// Now, we have found the keyword "solid" which is supposed to indicate that the file is ASCII
if(parse_ASCII_STL(input, points, facets, verbose))
{
// correctly read the input as an ASCII file
return true;
}
else // Failed to read the ASCII file
{
// It might have actually have been a binary file... ?
return parse_binary_STL(input, points, facets, verbose);
}
}
} // namespace CGAL } // namespace CGAL
#endif // CGAL_IO_STL_READER_H #endif // CGAL_IO_STL_READER_H

View File

@ -24,6 +24,10 @@
#include <CGAL/license/Polyhedron.h> #include <CGAL/license/Polyhedron.h>
#include <CGAL/boost/graph/named_function_params.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/property_map.h>
#include <boost/graph/graph_traits.hpp>
#include <CGAL/basic.h> #include <CGAL/basic.h>
#include <CGAL/Inverse_index.h> #include <CGAL/Inverse_index.h>
@ -31,11 +35,12 @@
namespace CGAL { namespace CGAL {
template <class Polyhedron, class Writer> template <class Polyhedron, class Writer, class Vpm>
void void
generic_print_polyhedron( std::ostream& out, generic_print_polyhedron( std::ostream& out,
const Polyhedron& P, const Polyhedron& P,
Writer& writer) { Writer& writer,
const Vpm& vpm ) {
// writes P to `out' in the format provided by `writer'. // writes P to `out' in the format provided by `writer'.
typedef typename Polyhedron::Vertex_const_iterator VCI; typedef typename Polyhedron::Vertex_const_iterator VCI;
typedef typename Polyhedron::Facet_const_iterator FCI; typedef typename Polyhedron::Facet_const_iterator FCI;
@ -45,10 +50,10 @@ generic_print_polyhedron( std::ostream& out,
P.size_of_vertices(), P.size_of_vertices(),
P.size_of_halfedges(), P.size_of_halfedges(),
P.size_of_facets()); P.size_of_facets());
for( VCI vi = P.vertices_begin(); vi != P.vertices_end(); ++vi) { BOOST_FOREACH(typename boost::graph_traits<Polyhedron>::vertex_descriptor vi, vertices(P)) {
writer.write_vertex( ::CGAL::to_double( vi->point().x()), writer.write_vertex( ::CGAL::to_double( get(vpm, vi).x()),
::CGAL::to_double( vi->point().y()), ::CGAL::to_double( get(vpm, vi).y()),
::CGAL::to_double( vi->point().z())); ::CGAL::to_double( get(vpm, vi).z()));
} }
typedef Inverse_index< VCI> Index; typedef Inverse_index< VCI> Index;
Index index( P.vertices_begin(), P.vertices_end()); Index index( P.vertices_begin(), P.vertices_end());
@ -69,6 +74,15 @@ generic_print_polyhedron( std::ostream& out,
writer.write_footer(); writer.write_footer();
} }
template <class Polyhedron, class Writer>
void
generic_print_polyhedron( std::ostream& out,
const Polyhedron& P,
Writer& writer)
{
generic_print_polyhedron(out, P, writer,
get(CGAL::vertex_point, P));
}
} //namespace CGAL } //namespace CGAL
#endif // CGAL_IO_GENERIC_PRINT_POLYHEDRON_H // #endif // CGAL_IO_GENERIC_PRINT_POLYHEDRON_H //
// EOF // // EOF //

View File

@ -33,16 +33,24 @@
namespace CGAL { namespace CGAL {
template <class Polyhedron> template <class Polyhedron, class Vpm>
void print_polyhedron_with_header_OFF( std::ostream& out, void print_polyhedron_with_header_OFF( std::ostream& out,
const Polyhedron& P, const Polyhedron& P,
const File_header_OFF& header) { const File_header_OFF& header,
const Vpm& vpm) {
File_writer_OFF writer( header); File_writer_OFF writer( header);
writer.header().set_polyhedral_surface( true); writer.header().set_polyhedral_surface( true);
writer.header().set_halfedges( P.size_of_halfedges()); writer.header().set_halfedges( P.size_of_halfedges());
generic_print_polyhedron( out, P, writer); generic_print_polyhedron( out, P, writer, vpm);
} }
template <class Polyhedron>
void print_polyhedron_with_header_OFF( std::ostream& out,
const Polyhedron& P,
const File_header_OFF& header)
{
print_polyhedron_with_header_OFF(out, P, header, get(CGAL::vertex_point, P));
}
template <class Polyhedron> template <class Polyhedron>
void print_polyhedron_OFF( std::ostream& out, void print_polyhedron_OFF( std::ostream& out,

View File

@ -1,3 +1,4 @@
solid cube_corner solid cube_corner
facet normal 0.0 -1.0 0.0 facet normal 0.0 -1.0 0.0
outer loop outer loop
@ -7,6 +8,7 @@ solid cube_corner
endloop endloop
endfacet endfacet
facet normal 0.0 0.0 -1.0 facet normal 0.0 0.0 -1.0
outer loop outer loop
vertex 0.0 0.0 0.0 vertex 0.0 0.0 0.0
vertex 0.0 1.0 0.0 vertex 0.0 1.0 0.0
@ -28,4 +30,3 @@ solid cube_corner
endloop endloop
endfacet endfacet
endsolid endsolid

View File

@ -33,8 +33,6 @@ void read(const char* fname, std::size_t v, std::size_t f)
for(std::size_t i=0; i < faces.size(); i++){ for(std::size_t i=0; i < faces.size(); i++){
std::cout << "3 " << faces[i][0] << " " << faces[i][1] << " " << faces[i][2] << std::endl; std::cout << "3 " << faces[i][0] << " " << faces[i][1] << " " << faces[i][2] << std::endl;
} }
} }
@ -43,7 +41,6 @@ int main()
read("data/cube.stl", 8, 12); read("data/cube.stl", 8, 12);
read("data/triangle.stl", 3, 1); read("data/triangle.stl", 3, 1);
read("data/ascii-tetrahedron.stl", 4, 4); read("data/ascii-tetrahedron.stl", 4, 4);
read("data/binary-tetrahedron-nice-header.stl", 4, 4); read("data/binary-tetrahedron-nice-header.stl", 4, 4);
read("data/binary-tetrahedron-non-standard-header-1.stl", 4, 4); read("data/binary-tetrahedron-non-standard-header-1.stl", 4, 4);
@ -51,5 +48,6 @@ int main()
read("data/binary-tetrahedron-non-standard-header-3.stl", 4, 4); read("data/binary-tetrahedron-non-standard-header-3.stl", 4, 4);
read("data/binary-tetrahedron-non-standard-header-4.stl", 4, 4); read("data/binary-tetrahedron-non-standard-header-4.stl", 4, 4);
read("data/binary-tetrahedron-non-standard-header-5.stl", 4, 4); read("data/binary-tetrahedron-non-standard-header-5.stl", 4, 4);
return 0; return 0;
} }

View File

@ -20,6 +20,14 @@ include_directories( ./ )
find_package(CGAL COMPONENTS Qt5) find_package(CGAL COMPONENTS Qt5)
include( ${CGAL_USE_FILE} ) include( ${CGAL_USE_FILE} )
find_package(Eigen3 3.1.0) #(requires 3.1.0 or greater)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
else()
message(STATUS "NOTICE: This project requires the Eigen library, and will not be compiled.")
return()
endif()
# Find Qt5 itself # Find Qt5 itself
find_package(Qt5 QUIET COMPONENTS Xml Script OpenGL) find_package(Qt5 QUIET COMPONENTS Xml Script OpenGL)

View File

@ -13,7 +13,7 @@ The tag `tag` identifies the dimension to be considered from the objects. For po
The class `K` is the kernel in which the value type of the `InputIterator` is defined. It can be omitted and deduced automatically from the value type. The class `K` is the kernel in which the value type of the `InputIterator` is defined. It can be omitted and deduced automatically from the value type.
The class `DiagonalizeTraits_` is a model of `DiagonalizeTraits`. It can be omitted: if Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined then an overload using `Eigen_diagonalize_traits` is provided. Otherwise, the internal implementation `Diagonalize_traits` is used. The class `DiagonalizeTraits_` is a model of `DiagonalizeTraits`. It can be omitted if Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined: in that case, an overload using `Eigen_diagonalize_traits` is provided.
\cgalHeading{Requirements} \cgalHeading{Requirements}

View File

@ -65,10 +65,9 @@ value type of `InputIterator` is defined. It can be omitted and deduced
automatically from the value type. automatically from the value type.
The class `DiagonalizeTraits_` is a model of `DiagonalizeTraits`. It The class `DiagonalizeTraits_` is a model of `DiagonalizeTraits`. It
can be omitted: if Eigen 3 (or greater) is available and can be omitted if Eigen 3 (or greater) is available and
`CGAL_EIGEN3_ENABLED` is defined then an overload using `CGAL_EIGEN3_ENABLED` is defined: in that case, an overload using
`Eigen_diagonalize_traits` is provided. Otherwise, the internal `Eigen_diagonalize_traits` is provided.
implementation `Diagonalize_traits` is used.
\note This function is significantly faster when using \note This function is significantly faster when using
`Eigen_diagonalize_traits` and it is strongly advised to use this `Eigen_diagonalize_traits` and it is strongly advised to use this

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// Example program for the linear_least_square_fitting function on a set of circles in 2D // Example program for the linear_least_square_fitting function on a set of circles in 2D
#include <CGAL/Cartesian.h> #include <CGAL/Cartesian.h>

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// Example program for the linear_least_square_fitting function on set of cuboids in 3D // Example program for the linear_least_square_fitting function on set of cuboids in 3D
#include <CGAL/Cartesian.h> #include <CGAL/Cartesian.h>
#include <CGAL/linear_least_squares_fitting_3.h> #include <CGAL/linear_least_squares_fitting_3.h>

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// test for the linear_least_square_fitting() functions. // test for the linear_least_square_fitting() functions.
#include <CGAL/Cartesian.h> #include <CGAL/Cartesian.h>
#include <CGAL/algorithm.h> #include <CGAL/algorithm.h>

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// test for the linear_least_square_fitting() functions. // test for the linear_least_square_fitting() functions.

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// test for the linear_least_square_fitting() functions. // test for the linear_least_square_fitting() functions.

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// test for the linear_least_square_fitting() functions. // test for the linear_least_square_fitting() functions.

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// test for the linear_least_square_fitting() functions. // test for the linear_least_square_fitting() functions.

View File

@ -1,5 +1,7 @@
// Example program for the linear_least_square_fitting function // Example program for the linear_least_square_fitting function
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
#include <CGAL/Cartesian.h> #include <CGAL/Cartesian.h>
#include <CGAL/linear_least_squares_fitting_3.h> #include <CGAL/linear_least_squares_fitting_3.h>
#ifdef CGAL_EIGEN3_ENABLED #ifdef CGAL_EIGEN3_ENABLED

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// Example program for the linear_least_square_fitting function // Example program for the linear_least_square_fitting function
// on a set of tetrahedra in 3D // on a set of tetrahedra in 3D

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// test for the linear_least_square_fitting() functions. // test for the linear_least_square_fitting() functions.
#include <CGAL/Cartesian.h> #include <CGAL/Cartesian.h>
#include <CGAL/algorithm.h> #include <CGAL/algorithm.h>

View File

@ -1,3 +1,5 @@
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
// Example program for the linear_least_square_fitting function on set of triangles in 3D // Example program for the linear_least_square_fitting function on set of triangles in 3D
#include <CGAL/Cartesian.h> #include <CGAL/Cartesian.h>
#include <CGAL/linear_least_squares_fitting_3.h> #include <CGAL/linear_least_squares_fitting_3.h>

View File

@ -37,7 +37,8 @@
#include <CGAL/iterator.h> #include <CGAL/iterator.h>
#include <CGAL/CC_safe_handle.h> #include <CGAL/CC_safe_handle.h>
#include <tbb/tbb.h> #include <tbb/enumerable_thread_specific.h>
#include <tbb/queuing_mutex.h>
#include <boost/mpl/if.hpp> #include <boost/mpl/if.hpp>

View File

@ -0,0 +1,101 @@
// Copyright (c) 2018 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0+
//
// Author(s) : Simon Giraudot
#ifndef CGAL_THREAD_H
#define CGAL_THREAD_H
#include <CGAL/config.h>
/*
This file defines the following:
- CGAL::cpp11::thread
- CGAL::cpp11::atomic
- CGAL::cpp11::sleep_for
It uses either TBB or STD depending on what's available: as TBB can
quite often override `std::thread`, it is possible that TBB will be
used instead of STD even if the real CXX11 `std::thread` is
available.
As the conflicting API between TBB and STD can be quite complicated,
we offer a more generic `sleep_for()` function that takes
double-typed seconds as argument and deals with it.
*/
#if defined(CGAL_LINKED_WITH_TBB)
# include <tbb/tbb_config.h>
# if TBB_IMPLEMENT_CPP0X
# include <tbb/compat/thread>
# include <tbb/atomic.h>
# include <tbb/tick_count.h>
# define CGAL_USE_TBB_THREADS 1
# else
# define CGAL_USE_TBB_THREADS 0
# endif
#else
# define CGAL_USE_TBB_THREADS 0
#endif
#if !CGAL_USE_TBB_THREADS
# include <thread>
# include <atomic>
# include <chrono>
#endif
namespace CGAL {
namespace cpp11 {
#if CGAL_USE_TBB_THREADS
using std::thread; // std::thread is declared by TBB if TBB_IMPLEMENT_CPP0X == 1
using tbb::atomic;
inline void sleep_for (double seconds)
{
// std::this_thread::sleep_for is declared by TBB if TBB_IMPLEMENT_CPP0X == 1
// It takes interval_t types as argument (!= from the std norm)
std::this_thread::sleep_for(tbb::tick_count::interval_t(seconds));
}
#else
using std::thread;
using std::atomic;
inline void sleep_for (double seconds)
{
// MSVC2013 cannot call `sleep_for()` with other types than
// std::chrono::nanoseconds (bug in the implementation of the norm).
typedef std::chrono::nanoseconds nanoseconds;
nanoseconds ns (nanoseconds::rep (1000000000.0 * seconds));
std::this_thread::sleep_for(ns);
}
#endif
} // cpp11
} //namespace CGAL
#undef CGAL_USE_TBB_THREADS
#endif // CGAL_THREAD_H

View File

@ -61,11 +61,10 @@ namespace Scale_space_reconstruction_3
* \tparam DiagonalizeTraits model of `DiagonalizeTraits` that * \tparam DiagonalizeTraits model of `DiagonalizeTraits` that
* determines how to diagonalize a weighted covariance matrix to * determines how to diagonalize a weighted covariance matrix to
* approximate a weighted point set. It can be omitted: if Eigen 3 * approximate a weighted point set. It can be omitted if Eigen 3 (or
* (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined * greater) is available and `CGAL_EIGEN3_ENABLED` is defined: in
* then an overload using `Eigen_diagonalize_traits` is * that case, an overload using `Eigen_diagonalize_traits` is
* provided. Otherwise, the internal implementation * provided.
* `Diagonalize_traits` is used.
* \tparam ConcurrencyTag indicates whether to use concurrent * \tparam ConcurrencyTag indicates whether to use concurrent
* processing. It can be omitted: if TBB (or greater) is available * processing. It can be omitted: if TBB (or greater) is available
* and `CGAL_LINKED_WITH_TBB` is defined then `Parallel_tag` is * and `CGAL_LINKED_WITH_TBB` is defined then `Parallel_tag` is

View File

@ -17,8 +17,6 @@ follows:
\tparam FT Number type \tparam FT Number type
\tparam dim Dimension of the matrices and vectors \tparam dim Dimension of the matrices and vectors
\cgalHasModel `CGAL::Default_diagonalize_traits`
\cgalHasModel `CGAL::Diagonalize_traits`
\cgalHasModel `CGAL::Eigen_diagonalize_traits` \cgalHasModel `CGAL::Eigen_diagonalize_traits`
*/ */

View File

@ -31,10 +31,8 @@
## Classes ## ## Classes ##
- `CGAL::Diagonalize_traits`
- `CGAL::Eigen_solver_traits` - `CGAL::Eigen_solver_traits`
- `CGAL::Eigen_diagonalize_traits` - `CGAL::Eigen_diagonalize_traits`
- `CGAL::Default_diagonalize_traits`
- `CGAL::Eigen_vector` - `CGAL::Eigen_vector`
- `CGAL::Eigen_matrix` - `CGAL::Eigen_matrix`
- `CGAL::Eigen_sparse_matrix` - `CGAL::Eigen_sparse_matrix`

Some files were not shown because too many files have changed in this diff Show More