mirror of https://github.com/CGAL/cgal
Merge branch 'master' into Periodic_3_mesh_3-Feature-MBogdanov
This commit is contained in:
commit
10a84aa34e
|
|
@ -32,24 +32,36 @@
|
|||
|
||||
#include <CGAL/boost/graph/Euler_operations.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 {
|
||||
/*!
|
||||
\ingroup PkgBGLIOFct
|
||||
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`.
|
||||
|
||||
*/
|
||||
template <typename FaceGraph>
|
||||
template <typename FaceGraph, typename NamedParameters>
|
||||
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>::face_descriptor face_descriptor;
|
||||
typedef typename boost::graph_traits<FaceGraph>::vertices_size_type vertices_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));
|
||||
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`.
|
||||
|
||||
*/
|
||||
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>
|
||||
bool write_off(const char* fname,
|
||||
const FaceGraph& g)
|
||||
{
|
||||
std::ofstream out(fname);
|
||||
if(out.good()){
|
||||
return write_off(out,g);
|
||||
}
|
||||
return false;
|
||||
return write_off(fname,g,
|
||||
parameters::all_default());
|
||||
}
|
||||
|
||||
template <typename FaceGraph>
|
||||
bool write_off(const std::string& fname,
|
||||
const FaceGraph& g)
|
||||
{ return write_off(fname.c_str(), g); }
|
||||
{ return write_off(fname, g,
|
||||
parameters::all_default()); }
|
||||
|
||||
namespace internal { namespace read_off_tools {
|
||||
|
||||
|
|
@ -122,14 +158,21 @@ inline std::string next_non_comment(std::istream& is)
|
|||
/*!
|
||||
\ingroup PkgBGLIOFct
|
||||
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`.
|
||||
\pre The data must represent a 2-manifold
|
||||
\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,
|
||||
FaceGraph& g)
|
||||
FaceGraph& g,
|
||||
NamedParameters np)
|
||||
{
|
||||
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>::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;
|
||||
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;
|
||||
faces_size_type nf;
|
||||
int ignore;
|
||||
|
|
@ -182,6 +227,12 @@ bool read_off(std::istream& is,
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename FaceGraph>
|
||||
bool read_off(std::istream& is,
|
||||
FaceGraph& g)
|
||||
{
|
||||
return read_off(is, g, parameters::all_default());
|
||||
}
|
||||
|
||||
/*!
|
||||
\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.
|
||||
|
||||
*/
|
||||
template <typename FaceGraph>
|
||||
template <typename FaceGraph, typename NamedParameters>
|
||||
bool read_off(const char* fname,
|
||||
FaceGraph& g)
|
||||
FaceGraph& g,
|
||||
NamedParameters np)
|
||||
{
|
||||
std::ifstream in(fname);
|
||||
if(in.good()){
|
||||
return read_off(in, g);
|
||||
return read_off(in, g, np);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename FaceGraph>
|
||||
bool read_off(const std::string& fname,
|
||||
bool read_off(const char* fname,
|
||||
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>
|
||||
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,
|
||||
const FaceGraph& g,
|
||||
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>::face_descriptor face_descriptor;
|
||||
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;
|
||||
|
||||
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";
|
||||
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;
|
||||
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
|
||||
|
||||
#endif // CGAL_BOOST_GRAPH_IO_H
|
||||
|
|
|
|||
|
|
@ -23,14 +23,6 @@
|
|||
|
||||
#include <CGAL/Kernel_traits.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/boost/graph/properties.h>
|
||||
|
|
@ -41,6 +33,15 @@
|
|||
#include <boost/version.hpp>
|
||||
|
||||
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
|
||||
template<typename PolygonMesh, typename PropertyTag>
|
||||
class property_map_selector
|
||||
|
|
|
|||
|
|
@ -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(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(apply_per_connected_component_t, apply_per_connected_component, apply_per_connected_component)
|
||||
CGAL_add_named_parameter(projection_functor_t, projection_functor, projection_functor)
|
||||
|
||||
// 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(diagonalize_traits_t, diagonalize_traits, diagonalize_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(edge_sensitivity_t, edge_sensitivity, edge_sensitivity)
|
||||
CGAL_add_named_parameter(neighbor_radius_t, neighbor_radius, neighbor_radius)
|
||||
|
|
|
|||
|
|
@ -19,5 +19,4 @@ Number_types
|
|||
Profiling_tools
|
||||
Property_map
|
||||
STL_Extension
|
||||
Solver_interface
|
||||
Stream_support
|
||||
|
|
|
|||
|
|
@ -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::preserve_genus).v == 40);
|
||||
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
|
||||
|
|
@ -153,7 +154,8 @@ void test(const NamedParameters& np)
|
|||
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<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()
|
||||
|
|
@ -204,7 +206,8 @@ int main()
|
|||
.weight_calculator(A<39>(39))
|
||||
.preserve_genus(A<40>(40))
|
||||
.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;
|
||||
|
|
|
|||
|
|
@ -137,6 +137,8 @@ for display in Maplesoft's Maple.
|
|||
|
||||
\cgalExample{Approximate_min_ellipsoid_d/ellipsoid_for_maple.cpp}
|
||||
|
||||
\note This class requires the \ref thirdpartyEigen library.
|
||||
|
||||
*/
|
||||
template< typename Traits >
|
||||
class Approximate_min_ellipsoid_d {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{1.1}
|
||||
\cgalPkgDependsOn{\ref thirdpartyEigen}
|
||||
\cgalPkgBib{cgal:fghhs-bv}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{2D Bounding Volumes,bounding_volumes_2.zip}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,18 @@ if ( CGAL_FOUND )
|
|||
|
||||
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
|
||||
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
foreach(cppfile ${cppfiles})
|
||||
if(NOT (${cppfile} STREQUAL "ellipsoid.cpp") OR EIGEN3_FOUND)
|
||||
create_single_source_cgal_program( "${cppfile}" )
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -16,10 +16,18 @@ if ( CGAL_FOUND )
|
|||
|
||||
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
|
||||
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
foreach(cppfile ${cppfiles})
|
||||
if(NOT (${cppfile} STREQUAL "Approximate_min_ellipsoid_d.cpp") OR EIGEN3_FOUND)
|
||||
create_single_source_cgal_program( "${cppfile}" )
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -25,6 +25,14 @@ find_package(CGAL QUIET COMPONENTS Core)
|
|||
if ( CGAL_FOUND )
|
||||
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)
|
||||
|
||||
if ( IPE_FOUND )
|
||||
|
|
|
|||
|
|
@ -39,6 +39,16 @@ find_package(TBB 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_directories( BEFORE include )
|
||||
|
||||
|
|
|
|||
|
|
@ -184,10 +184,9 @@ public:
|
|||
algorithm. Possible values are `Parallel_tag` (default value is %CGAL
|
||||
is linked with TBB) or `Sequential_tag` (default value otherwise).
|
||||
\tparam DiagonalizeTraits model of `DiagonalizeTraits` used for
|
||||
matrix diagonalization. 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.
|
||||
matrix diagonalization. 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.
|
||||
|
||||
\param input point range.
|
||||
\param point_map property map to access the input points.
|
||||
|
|
|
|||
|
|
@ -87,10 +87,8 @@ namespace Classification {
|
|||
is linked with TBB) or `Sequential_tag` (default value otherwise).
|
||||
\tparam DiagonalizeTraits model of `DiagonalizeTraits` used for
|
||||
matrix diagonalization. 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.
|
||||
|
||||
is available and `CGAL_EIGEN3_ENABLED` is defined: in that case, an
|
||||
overload using `Eigen_diagonalize_traits` is provided.
|
||||
*/
|
||||
template <typename GeomTraits,
|
||||
typename PointRange,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include <CGAL/Search_traits_3.h>
|
||||
#include <CGAL/Fuzzy_sphere.h>
|
||||
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
||||
#include <CGAL/Default_diagonalize_traits.h>
|
||||
#include <CGAL/centroid.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
#include <CGAL/squared_distance_3.h>
|
||||
|
|
|
|||
|
|
@ -16,10 +16,20 @@ if ( CGAL_FOUND )
|
|||
|
||||
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
|
||||
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
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}" )
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -16,10 +16,18 @@ if ( CGAL_FOUND )
|
|||
|
||||
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
|
||||
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
foreach(cppfile ${cppfiles})
|
||||
if(NOT (${cppfile} STREQUAL "generic_random_test.cpp") OR EIGEN3_FOUND)
|
||||
create_single_source_cgal_program( "${cppfile}" )
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ find_package(CGAL COMPONENTS Qt5 Core)
|
|||
|
||||
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)
|
||||
|
||||
include_directories (BEFORE ../../include)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
Release History
|
||||
===============
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
- 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.
|
||||
|
||||
- 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
|
||||
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)
|
||||
|
||||
- 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
|
||||
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
|
||||
------------
|
||||
|
|
|
|||
|
|
@ -195,9 +195,14 @@
|
|||
#if defined(BOOST_NO_0X_HDR_UNORDERED_SET) || \
|
||||
defined(BOOST_NO_0X_HDR_UNORDERED_MAP) || \
|
||||
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
|
||||
#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) || \
|
||||
defined(BOOST_NO_CXX11_DECLTYPE) || (BOOST_VERSION < 103600)
|
||||
#define CGAL_CFG_NO_CPP0X_DECLTYPE 1
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ algebra algorithm required by the fitting method. The scalar type, `SvdTraits::
|
|||
\sa `Eigen_svd`
|
||||
\sa `Monge_form`
|
||||
|
||||
\note This class requires the \ref thirdpartyEigen library.
|
||||
*/
|
||||
template< typename DataKernel, typename LocalKernel, typename SvdTraits >
|
||||
class Monge_via_jet_fitting {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{3.3}
|
||||
\cgalPkgDependsOn{\ref PkgSolverSummary}
|
||||
\cgalPkgDependsOn{\ref PkgSolverSummary and \ref thirdpartyEigen}
|
||||
\cgalPkgBib{cgal:pc-eldp}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{Polyhedron demo,polyhedron_3.zip}
|
||||
|
|
|
|||
|
|
@ -33,9 +33,13 @@
|
|||
|
||||
|
||||
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 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);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
|
||||
#include "IO.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include <CGAL/boost/graph/named_function_params.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
|
||||
//== IMPLEMENTATION ===========================================================
|
||||
|
||||
|
|
@ -39,12 +40,13 @@ template <typename T> void read(FILE* in, T& t)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
template <typename NamedParameters>
|
||||
bool read_off_ascii(Surface_mesh& mesh,
|
||||
FILE* in,
|
||||
const bool has_normals,
|
||||
const bool has_texcoords,
|
||||
const bool has_colors)
|
||||
const bool has_colors,
|
||||
NamedParameters& np)
|
||||
{
|
||||
char line[100], *lp;
|
||||
unsigned int i, j, items, idx, nc;
|
||||
|
|
@ -52,6 +54,9 @@ bool read_off_ascii(Surface_mesh& mesh,
|
|||
Vec3f p, n, c;
|
||||
Vec2f t;
|
||||
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
|
||||
|
|
@ -78,7 +83,8 @@ bool read_off_ascii(Surface_mesh& mesh,
|
|||
// position
|
||||
items = sscanf(lp, "%f %f %f%n", &p[0], &p[1], &p[2], &nc);
|
||||
assert(items==3);
|
||||
v = mesh.add_vertex((Point)p);
|
||||
Surface_mesh::Vertex v = mesh.add_vertex();
|
||||
put(vpm, v, (Point)p);
|
||||
lp += nc;
|
||||
|
||||
// normal
|
||||
|
|
@ -146,12 +152,13 @@ bool read_off_ascii(Surface_mesh& mesh,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
template<typename NamedParameters>
|
||||
bool read_off_binary(Surface_mesh& mesh,
|
||||
FILE* in,
|
||||
const bool has_normals,
|
||||
const bool has_texcoords,
|
||||
const bool has_colors)
|
||||
const bool has_colors,
|
||||
NamedParameters& np)
|
||||
{
|
||||
unsigned int i, j, idx;
|
||||
unsigned int nV, nF, nE;
|
||||
|
|
@ -169,6 +176,9 @@ bool read_off_binary(Surface_mesh& mesh,
|
|||
Surface_mesh::Vertex_property<Texture_coordinate> texcoords;
|
||||
if (has_normals) normals = mesh.vertex_property<Normal>("v:normal");
|
||||
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
|
||||
|
|
@ -184,7 +194,8 @@ bool read_off_binary(Surface_mesh& mesh,
|
|||
{
|
||||
// position
|
||||
read(in, p);
|
||||
v = mesh.add_vertex((Point)p);
|
||||
Surface_mesh::Vertex v = mesh.add_vertex();
|
||||
put(vpm, v, (Point)p);
|
||||
|
||||
// normal
|
||||
if (has_normals)
|
||||
|
|
@ -224,8 +235,8 @@ bool read_off_binary(Surface_mesh& mesh,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
bool read_off(Surface_mesh& mesh, const std::string& filename)
|
||||
template<typename NamedParameters>
|
||||
bool read_off(Surface_mesh& mesh, const std::string& filename, NamedParameters& np)
|
||||
{
|
||||
char line[100];
|
||||
bool has_texcoords = false;
|
||||
|
|
@ -274,8 +285,8 @@ bool read_off(Surface_mesh& mesh, const std::string& filename)
|
|||
|
||||
// read as ASCII or binary
|
||||
bool ok = (is_binary ?
|
||||
read_off_binary(mesh, in, has_normals, has_texcoords, has_colors) :
|
||||
read_off_ascii(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, np));
|
||||
|
||||
|
||||
fclose(in);
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ lloyd_optimize_mesh_3(c3t3,
|
|||
\sa `CGAL::perturb_mesh_3()`
|
||||
\sa `CGAL::odt_optimize_mesh_3()`
|
||||
|
||||
\note This function requires the \ref thirdpartyEigen library.
|
||||
*/
|
||||
|
||||
template<typename C3T3, typename MD>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{3.5}
|
||||
\cgalPkgDependsOn{\ref PkgTriangulation3Summary}
|
||||
\cgalPkgDependsOn{\ref PkgTriangulation3Summary and \ref thirdpartyEigen}
|
||||
\cgalPkgBib{cgal:rty-m3}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{Polyhedron demo,polyhedron_3.zip}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@ if ( CGAL_FOUND )
|
|||
endif( LINK_WITH_TBB )
|
||||
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 "")
|
||||
find_package(VTK QUIET COMPONENTS vtkImagingGeneral vtkIOImage NO_MODULE)
|
||||
if(VTK_FOUND)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
# include <tbb/parallel_do.h>
|
||||
# include <tbb/mutex.h>
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
|
|
|
|||
|
|
@ -57,11 +57,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
# if TBB_IMPLEMENT_CPP0X
|
||||
# include <tbb/compat/thread>
|
||||
# else
|
||||
# include <thread>
|
||||
# endif
|
||||
# include <tbb/task_scheduler_init.h>
|
||||
#endif
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
# include <tbb/task.h>
|
||||
# include <tbb/tbb.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@
|
|||
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
|
||||
#include <CGAL/Meshes/Triangulation_mesher_level_traits_3.h>
|
||||
#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
|
||||
|
||||
#include <CGAL/Meshes/Filtered_deque_container.h>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@
|
|||
#include <CGAL/Mesh_3/Mesher_level.h>
|
||||
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <tbb/tbb.h>
|
||||
#include <tbb/enumerable_thread_specific.h>
|
||||
#include <tbb/parallel_do.h>
|
||||
#endif
|
||||
|
||||
#include <CGAL/Meshes/Filtered_deque_container.h>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,15 @@ if ( CGAL_FOUND )
|
|||
include_directories (BEFORE ../../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_c3t3.cpp" )
|
||||
create_single_source_cgal_program( "test_mesh_capsule_var_distance_bound.cpp" )
|
||||
|
|
|
|||
|
|
@ -10,6 +10,5 @@ Point_set_processing_3
|
|||
Profiling_tools
|
||||
Property_map
|
||||
STL_Extension
|
||||
Solver_interface
|
||||
Stream_support
|
||||
Surface_mesh
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ No default value.
|
|||
\cgalNPBegin{diagonalize_traits} \anchor PSP_diagonalize_traits
|
||||
is the solver used for diagonalizing covariance matrices.\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
|
||||
|
||||
\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
|
||||
\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
|
||||
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
|
||||
|
|
|
|||
|
|
@ -632,6 +632,26 @@ point set:
|
|||
\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
|
||||
|
||||
|
|
|
|||
|
|
@ -17,4 +17,5 @@
|
|||
\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/structuring_example.cpp
|
||||
\example Point_set_processing_3/callback_example.cpp
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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( "edge_aware_upsample_point_set_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)
|
||||
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
|
||||
normals_example
|
||||
jet_smoothing_example
|
||||
normal_estimation)
|
||||
normal_estimation
|
||||
callback_example)
|
||||
if(TBB_FOUND AND TARGET ${target})
|
||||
CGAL_target_use_TBB(${target})
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include <CGAL/point_set_processing_assertions.h>
|
||||
#include <CGAL/Point_with_normal_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_params_helper.h>
|
||||
|
|
@ -45,9 +46,11 @@
|
|||
#include <CGAL/property_map.h>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <CGAL/internal/Parallel_callback.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/scalable_allocator.h>
|
||||
#include <tbb/atomic.h>
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
|
||||
// Default allocator: use TBB allocators if available
|
||||
|
|
@ -300,18 +303,27 @@ class Compute_pwns_neighbors
|
|||
const Tree & m_tree;
|
||||
const Pwns & m_pwns;
|
||||
Pwns_neighbors & m_pwns_neighbors;
|
||||
cpp11::atomic<std::size_t>& advancement;
|
||||
cpp11::atomic<bool>& interrupted;
|
||||
|
||||
public:
|
||||
Compute_pwns_neighbors(unsigned int k, const Tree &tree,
|
||||
const Pwns &pwns, Pwns_neighbors &neighbors)
|
||||
: m_k(k), m_tree(tree), m_pwns(pwns), m_pwns_neighbors(neighbors) {}
|
||||
const Pwns &pwns, 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
|
||||
{
|
||||
for (size_t i = r.begin(); i!=r.end(); i++)
|
||||
{
|
||||
if (interrupted)
|
||||
break;
|
||||
|
||||
m_pwns_neighbors[i] = bilateral_smooth_point_set_internal::
|
||||
compute_kdtree_neighbors<Kernel, Tree>(m_pwns[i], m_tree, m_k);
|
||||
++ advancement;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -331,30 +343,37 @@ class Pwn_updater
|
|||
Pwns* pwns;
|
||||
Pwns* update_pwns;
|
||||
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* pwns_neighbors;
|
||||
cpp11::atomic<std::size_t>& advancement;
|
||||
cpp11::atomic<bool>& interrupted;
|
||||
|
||||
public:
|
||||
Pwn_updater(FT sharpness,
|
||||
FT r,
|
||||
Pwns *in,
|
||||
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),
|
||||
radius(r),
|
||||
pwns(in),
|
||||
update_pwns(out),
|
||||
pwns_neighbors(neighbors){}
|
||||
|
||||
pwns_neighbors(neighbors),
|
||||
advancement (advancement),
|
||||
interrupted (interrupted) {}
|
||||
|
||||
void operator() ( const tbb::blocked_range<size_t>& r ) const
|
||||
{
|
||||
for (size_t i = r.begin(); i != r.end(); ++i)
|
||||
{
|
||||
if (interrupted)
|
||||
break;
|
||||
(*update_pwns)[i] = bilateral_smooth_point_set_internal::
|
||||
compute_denoise_projection<Kernel>((*pwns)[i],
|
||||
(*pwns_neighbors)[i],
|
||||
radius,
|
||||
sharpness_angle);
|
||||
|
||||
++ advancement;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -402,6 +421,13 @@ public:
|
|||
\cgalParamBegin{normal_map} a model of `ReadWritePropertyMap` with value type
|
||||
`geom_traits::Vector_3`.\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
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
|
|
@ -434,6 +460,8 @@ bilateral_smooth_point_set(
|
|||
typedef typename Kernel::FT FT;
|
||||
|
||||
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(k > 1);
|
||||
|
|
@ -513,8 +541,23 @@ bilateral_smooth_point_set(
|
|||
#else
|
||||
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);
|
||||
|
||||
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
|
||||
#endif
|
||||
|
|
@ -522,10 +565,13 @@ bilateral_smooth_point_set(
|
|||
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
|
||||
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::
|
||||
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
|
||||
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::blocked_range<size_t> block(0, nb_points);
|
||||
Pwn_updater<Kernel> pwn_updater(sharpness_angle,
|
||||
guess_neighbor_radius,
|
||||
&pwns,
|
||||
&update_pwns,
|
||||
&pwns_neighbors);
|
||||
&pwns_neighbors,
|
||||
parallel_callback.advancement(),
|
||||
parallel_callback.interrupted());
|
||||
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
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
{
|
||||
std::size_t nb = nb_points;
|
||||
|
||||
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::iterator
|
||||
update_iter = update_pwns.begin();
|
||||
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
|
||||
neighbor_iter = pwns_neighbors.begin();
|
||||
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::
|
||||
compute_denoise_projection<Kernel>
|
||||
|
|
@ -570,6 +629,8 @@ bilateral_smooth_point_set(
|
|||
*neighbor_iter,
|
||||
guess_neighbor_radius,
|
||||
sharpness_angle);
|
||||
if (callback && !callback ((nb+1) / double(2. * nb_points)))
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
}
|
||||
#ifdef CGAL_PSP3_VERBOSE
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/point_set_processing_assertions.h>
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/function.h>
|
||||
|
||||
#include <CGAL/boost/graph/named_function_params.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
#include <list>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <CGAL/internal/Parallel_callback.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.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 std::vector<Point>& input;
|
||||
std::vector<FT>& output;
|
||||
cpp11::atomic<std::size_t>& advancement;
|
||||
cpp11::atomic<bool>& interrupted;
|
||||
|
||||
public:
|
||||
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)
|
||||
, advancement (advancement)
|
||||
, interrupted (interrupted)
|
||||
{ }
|
||||
|
||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||
{
|
||||
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);
|
||||
++ advancement;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -153,6 +167,13 @@ compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point who
|
|||
\cgalNamedParamsBegin
|
||||
\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
|
||||
\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
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
|
|
@ -184,6 +205,8 @@ compute_average_spacing(
|
|||
typedef typename Kernel::Point_3 Point;
|
||||
|
||||
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
|
||||
typedef typename Kernel::FT FT;
|
||||
|
|
@ -209,6 +232,7 @@ compute_average_spacing(
|
|||
// iterate over input points, compute and output normal
|
||||
// vectors (already normalized)
|
||||
FT sum_spacings = (FT)0.0;
|
||||
std::size_t nb = 0;
|
||||
|
||||
#ifndef CGAL_LINKED_WITH_TBB
|
||||
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
|
||||
|
|
@ -216,26 +240,43 @@ compute_average_spacing(
|
|||
#else
|
||||
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>
|
||||
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);
|
||||
|
||||
for (unsigned int i = 0; i < spacings.size (); ++ i)
|
||||
if (spacings[i] >= 0.)
|
||||
{
|
||||
sum_spacings += spacings[i];
|
||||
++ nb;
|
||||
}
|
||||
|
||||
parallel_callback.join();
|
||||
}
|
||||
else
|
||||
#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>(
|
||||
get(point_map,*it),
|
||||
tree,k);
|
||||
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||
{
|
||||
++ nb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return average spacing
|
||||
return sum_spacings / (FT)(kd_tree_points.size ());
|
||||
return sum_spacings / (FT)(nb);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <CGAL/point_set_processing_assertions.h>
|
||||
#include <CGAL/unordered.h>
|
||||
#include <CGAL/Iterator_range.h>
|
||||
#include <CGAL/function.h>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#include <CGAL/boost/graph/named_function_params.h>
|
||||
|
|
@ -188,6 +189,13 @@ public:
|
|||
\cgalNamedParamsBegin
|
||||
\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
|
||||
\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
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
|
|
@ -204,6 +212,8 @@ grid_simplify_point_set(
|
|||
|
||||
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());
|
||||
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||
cpp11::function<bool(double)>());
|
||||
|
||||
// actual type of input points
|
||||
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[].
|
||||
Epsilon_point_set_3<Enriched_point, PointMap> points_to_keep(epsilon, point_map);
|
||||
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;
|
||||
result = points_to_keep.insert(*it);
|
||||
if (!result.second) // if not inserted
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <CGAL/PCA_util.h>
|
||||
#include <CGAL/squared_distance_3.h>
|
||||
#include <CGAL/Iterator_range.h>
|
||||
#include <CGAL/function.h>
|
||||
|
||||
#include <CGAL/boost/graph/named_function_params.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
|
||||
using `Eigen_diagonalize_traits` is provided. Otherwise, the internal implementation
|
||||
`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
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
|
|
@ -167,6 +175,8 @@ namespace CGAL {
|
|||
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);
|
||||
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;
|
||||
|
||||
|
|
@ -192,6 +202,8 @@ namespace CGAL {
|
|||
std::list<Input_type> points_to_keep;
|
||||
std::list<Input_type> points_to_remove;
|
||||
|
||||
std::size_t nb_done = 0;
|
||||
|
||||
while (!(clusters_stack.empty ()))
|
||||
{
|
||||
cluster_iterator current_cluster = clusters_stack.begin ();
|
||||
|
|
@ -203,6 +215,7 @@ namespace CGAL {
|
|||
points_to_keep.splice (points_to_keep.end (), current_cluster->first,
|
||||
current_cluster->first.begin ());
|
||||
clusters_stack.pop_front ();
|
||||
++ nb_done;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -268,6 +281,7 @@ namespace CGAL {
|
|||
cluster_iterator nonempty = (current_cluster->first.empty ()
|
||||
? negative_side : current_cluster);
|
||||
|
||||
nb_done += nonempty->first.size();
|
||||
// Compute the centroid
|
||||
nonempty->second = internal::hsps_centroid (nonempty->first.begin (),
|
||||
nonempty->first.end (),
|
||||
|
|
@ -279,6 +293,7 @@ namespace CGAL {
|
|||
point_map,
|
||||
nonempty->second,
|
||||
Kernel ());
|
||||
|
||||
clusters_stack.pop_front ();
|
||||
clusters_stack.pop_front ();
|
||||
}
|
||||
|
|
@ -311,6 +326,7 @@ namespace CGAL {
|
|||
// and output point
|
||||
else
|
||||
{
|
||||
nb_done += current_cluster->first.size();
|
||||
internal::hsc_terminate_cluster (current_cluster->first,
|
||||
points_to_keep,
|
||||
points_to_remove,
|
||||
|
|
@ -319,7 +335,14 @@ namespace CGAL {
|
|||
Kernel ());
|
||||
clusters_stack.pop_front ();
|
||||
}
|
||||
|
||||
if (callback && !callback (nb_done / double (points.size())))
|
||||
break;
|
||||
}
|
||||
|
||||
if (callback)
|
||||
callback (1.);
|
||||
|
||||
typename PointRange::iterator first_point_to_remove =
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/point_set_processing_assertions.h>
|
||||
#include <CGAL/Memory_sizer.h>
|
||||
#include <CGAL/function.h>
|
||||
|
||||
#include <CGAL/boost/graph/named_function_params.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
#include <list>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <CGAL/internal/Parallel_callback.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.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 std::vector<Point>& input;
|
||||
std::vector<Vector>& output;
|
||||
cpp11::atomic<std::size_t>& advancement;
|
||||
cpp11::atomic<bool>& interrupted;
|
||||
|
||||
public:
|
||||
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)
|
||||
, advancement (advancement)
|
||||
, interrupted (interrupted)
|
||||
{ }
|
||||
|
||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||
{
|
||||
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);
|
||||
++ 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
|
||||
\ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined,
|
||||
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
|
||||
\cgalNamedParamsEnd
|
||||
*/
|
||||
|
|
@ -212,6 +232,8 @@ jet_estimate_normals(
|
|||
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());
|
||||
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;
|
||||
|
||||
|
|
@ -254,27 +276,36 @@ jet_estimate_normals(
|
|||
#else
|
||||
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>
|
||||
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);
|
||||
unsigned int i = 0;
|
||||
std::size_t i = 0;
|
||||
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
||||
{
|
||||
if (normals[i] != CGAL::NULL_VECTOR)
|
||||
put (normal_map, *it, normals[i]);
|
||||
}
|
||||
|
||||
parallel_callback.join();
|
||||
}
|
||||
else
|
||||
#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>(
|
||||
get(point_map,*it),
|
||||
tree, k, degree_fitting);
|
||||
|
||||
put(normal_map, *it, normal); // normal_map[it] = normal
|
||||
|
||||
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <CGAL/Monge_via_jet_fitting.h>
|
||||
#include <CGAL/property_map.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_params_helper.h>
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
#include <list>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <CGAL/internal/Parallel_callback.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/scalable_allocator.h>
|
||||
|
|
@ -125,20 +127,31 @@ jet_smooth_point(
|
|||
unsigned int degree_monge;
|
||||
const std::vector<Point>& input;
|
||||
std::vector<Point>& output;
|
||||
cpp11::atomic<std::size_t>& advancement;
|
||||
cpp11::atomic<bool>& interrupted;
|
||||
|
||||
public:
|
||||
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),
|
||||
degree_monge (degree_monge), input (points), output (output)
|
||||
, advancement (advancement)
|
||||
, interrupted (interrupted)
|
||||
{ }
|
||||
|
||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||
{
|
||||
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,
|
||||
degree_fitting,
|
||||
degree_monge);
|
||||
++ advancement;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -182,6 +195,13 @@ jet_smooth_point(
|
|||
\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,
|
||||
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
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
|
|
@ -210,6 +230,8 @@ jet_smooth_point_set(
|
|||
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_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;
|
||||
|
||||
|
|
@ -244,27 +266,36 @@ jet_smooth_point_set(
|
|||
#else
|
||||
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>
|
||||
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);
|
||||
unsigned int i = 0;
|
||||
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
||||
{
|
||||
if (mutated_points[i] != CGAL::ORIGIN)
|
||||
put(point_map, *it, mutated_points[i]);
|
||||
|
||||
}
|
||||
parallel_callback.join();
|
||||
|
||||
}
|
||||
else
|
||||
#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);
|
||||
put(point_map, *it ,
|
||||
internal::jet_smooth_point<Kernel, SvdTraits>(
|
||||
p,tree,k,degree_fitting,degree_monge) );
|
||||
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/point_set_processing_assertions.h>
|
||||
#include <CGAL/Memory_sizer.h>
|
||||
#include <CGAL/function.h>
|
||||
|
||||
#include <CGAL/boost/graph/named_function_params.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
|
|
@ -41,6 +42,7 @@
|
|||
#include <list>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <CGAL/internal/Parallel_callback.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.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 std::vector<Point>& input;
|
||||
std::vector<Vector>& output;
|
||||
cpp11::atomic<std::size_t>& advancement;
|
||||
cpp11::atomic<bool>& interrupted;
|
||||
|
||||
public:
|
||||
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)
|
||||
, advancement (advancement)
|
||||
, interrupted (interrupted)
|
||||
{ }
|
||||
|
||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||
{
|
||||
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);
|
||||
++ 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
|
||||
\cgalParamBegin{normal_map} a model of `WritablePropertyMap` with value type
|
||||
`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
|
||||
\cgalNamedParamsEnd
|
||||
*/
|
||||
|
|
@ -193,6 +213,8 @@ pca_estimate_normals(
|
|||
|
||||
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());
|
||||
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||
cpp11::function<bool(double)>());
|
||||
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
|
||||
|
|
@ -235,20 +257,28 @@ pca_estimate_normals(
|
|||
#else
|
||||
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>
|
||||
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);
|
||||
unsigned int i = 0;
|
||||
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
||||
{
|
||||
if (normals[i] != CGAL::NULL_VECTOR)
|
||||
put (normal_map, *it, normals[i]);
|
||||
}
|
||||
|
||||
parallel_callback.join();
|
||||
}
|
||||
else
|
||||
#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>(
|
||||
get(point_map,*it),
|
||||
|
|
@ -256,6 +286,8 @@ pca_estimate_normals(
|
|||
k);
|
||||
|
||||
put(normal_map, *it, normal); // normal_map[it] = normal
|
||||
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
||||
#include <CGAL/property_map.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_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_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
|
||||
\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
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
|
|
@ -163,6 +171,8 @@ remove_outliers(
|
|||
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_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;
|
||||
|
||||
|
|
@ -198,12 +208,15 @@ remove_outliers(
|
|||
|
||||
// iterate over input points and add them to multimap sorted by distance to k
|
||||
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>(
|
||||
get(point_map,*it),
|
||||
tree, k);
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -42,8 +42,10 @@
|
|||
#include <ctime>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <CGAL/internal/Parallel_callback.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/scalable_allocator.h>
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
|
@ -354,6 +356,8 @@ class Sample_point_updater
|
|||
const typename Kernel::FT radius;
|
||||
const std::vector<typename Kernel::FT> &original_densities;
|
||||
const std::vector<typename Kernel::FT> &sample_densities;
|
||||
cpp11::atomic<std::size_t>& advancement;
|
||||
cpp11::atomic<bool>& interrupted;
|
||||
|
||||
public:
|
||||
Sample_point_updater(
|
||||
|
|
@ -363,20 +367,25 @@ public:
|
|||
const Tree &_sample_kd_tree,
|
||||
const typename Kernel::FT _radius,
|
||||
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),
|
||||
sample_points(in),
|
||||
original_kd_tree(_original_kd_tree),
|
||||
sample_kd_tree(_sample_kd_tree),
|
||||
radius(_radius),
|
||||
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
|
||||
{
|
||||
for (size_t i = r.begin(); i != r.end(); ++i)
|
||||
{
|
||||
if (interrupted)
|
||||
break;
|
||||
update_sample_points[i] = simplify_and_regularize_internal::
|
||||
compute_update_sample_point<Kernel, Tree, RandomAccessIterator>(
|
||||
sample_points[i],
|
||||
|
|
@ -385,6 +394,7 @@ public:
|
|||
radius,
|
||||
original_densities,
|
||||
sample_densities);
|
||||
++ advancement;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -440,6 +450,13 @@ public:
|
|||
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
|
||||
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
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
|
|
@ -466,6 +483,8 @@ wlop_simplify_and_regularize_point_set(
|
|||
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);
|
||||
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::FT FT;
|
||||
|
|
@ -589,6 +608,9 @@ wlop_simplify_and_regularize_point_set(
|
|||
//parallel
|
||||
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);
|
||||
Sample_point_updater<Kernel, Kd_Tree, typename PointRange::iterator> sample_updater(
|
||||
update_sample_points,
|
||||
|
|
@ -597,15 +619,28 @@ wlop_simplify_and_regularize_point_set(
|
|||
sample_kd_tree,
|
||||
radius2,
|
||||
original_density_weights,
|
||||
sample_density_weights);
|
||||
sample_density_weights,
|
||||
parallel_callback.advancement(),
|
||||
parallel_callback.interrupted());
|
||||
|
||||
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
|
||||
#endif
|
||||
{
|
||||
//sequential
|
||||
std::size_t nb = iter_n * number_of_sample;
|
||||
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::
|
||||
compute_update_sample_point<Kernel,
|
||||
|
|
@ -617,6 +652,8 @@ wlop_simplify_and_regularize_point_set(
|
|||
radius2,
|
||||
original_density_weights,
|
||||
sample_density_weights);
|
||||
if (callback && !callback ((nb+1) / double(iter_number * number_of_sample)))
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,12 +23,18 @@ if ( CGAL_FOUND )
|
|||
|
||||
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_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_parameters.cpp" )
|
||||
create_single_source_cgal_program( "efficient_RANSAC_point_access.cpp" )
|
||||
create_single_source_cgal_program( "plane_regularization.cpp" )
|
||||
|
||||
else()
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
\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
|
||||
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#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/connected_components.h>
|
||||
#include <CGAL/array.h>
|
||||
#include <CGAL/Union_find.h>
|
||||
#include <CGAL/utility.h>
|
||||
|
|
@ -84,23 +85,21 @@ struct Less_for_halfedge
|
|||
const VertexPointMap& vpmap;
|
||||
};
|
||||
|
||||
template <typename PM, typename OutputIterator, typename LessHedge, typename VertexPointMap>
|
||||
OutputIterator
|
||||
collect_duplicated_stitchable_boundary_edges
|
||||
(PM& pmesh, OutputIterator out, LessHedge less_hedge, const VertexPointMap& vpmap)
|
||||
//add a pair of border halfedges to be stitched.
|
||||
//Specifies if they are manifold or not in the map.
|
||||
template<typename Halfedge,
|
||||
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;
|
||||
bool insertion_ok;
|
||||
CGAL::cpp11::tie(set_it, insertion_ok)
|
||||
|
|
@ -120,10 +119,118 @@ collect_duplicated_stitchable_boundary_edges
|
|||
}
|
||||
else
|
||||
if ( set_it->second.first > 2 )
|
||||
{
|
||||
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.
|
||||
// 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
|
||||
|
|
@ -133,6 +240,7 @@ collect_duplicated_stitchable_boundary_edges
|
|||
if( manifold_halfedge_pairs[i] )
|
||||
*out++=halfedge_pairs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
|
@ -503,9 +611,16 @@ void stitch_borders(PolygonMesh& pmesh,
|
|||
/// \cgalNamedParamsBegin
|
||||
/// \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
|
||||
/// `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
|
||||
///
|
||||
|
||||
template <typename PolygonMesh, class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
|
||||
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,
|
||||
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);
|
||||
internal::stitch_boundary_cycle_2(pmesh);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/stitch_borders.h>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
|
@ -34,6 +34,29 @@ void test_polyhedron(const char* fname)
|
|||
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)
|
||||
{
|
||||
|
|
@ -57,6 +80,29 @@ void test_surface_mesh(const char* fname)
|
|||
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()
|
||||
{
|
||||
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/non_manifold.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_quads.off");
|
||||
|
|
@ -84,7 +131,7 @@ int main()
|
|||
test_surface_mesh("data_stitching/non_stitchable.off");
|
||||
test_surface_mesh("data_stitching/deg_border.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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
|
|||
add_library(demo_framework SHARED
|
||||
Scene.cpp
|
||||
Viewer.cpp
|
||||
Three.cpp
|
||||
${ViewerUI_FILES}
|
||||
${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES}
|
||||
Viewer_interface_moc.cpp
|
||||
|
|
@ -184,6 +185,11 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
|
|||
target_link_libraries(demo_framework
|
||||
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)
|
||||
target_compile_definitions(demo_framework PRIVATE -DCGAL_USE_Qt5_RESOURCES)
|
||||
endif()
|
||||
|
|
@ -200,6 +206,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
|
|||
add_library(scene_color_ramp SHARED Color_ramp.cpp)
|
||||
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})
|
||||
target_link_libraries(point_dialog
|
||||
PUBLIC Qt5::OpenGL Qt5::Gui Qt5::Script Qt5::Widgets)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
#include <QStandardItem>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QTreeWidget>
|
||||
#include <QDockWidget>
|
||||
#include <stdexcept>
|
||||
#ifdef QT_SCRIPT_LIB
|
||||
# include <QScriptValue>
|
||||
|
|
@ -44,6 +45,7 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#include <CGAL/Three/Three.h>
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
|
||||
#include <CGAL/Three/Scene_item_with_properties.h>
|
||||
|
|
@ -131,6 +133,7 @@ MainWindow::MainWindow(bool verbose, QWidget* parent)
|
|||
ui = new Ui::MainWindow;
|
||||
ui->setupUi(this);
|
||||
menuBar()->setNativeMenuBar(false);
|
||||
CGAL::Three::Three::s_mainwindow = this;
|
||||
menu_map[ui->menuOperations->title()] = ui->menuOperations;
|
||||
this->verbose = verbose;
|
||||
// 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);
|
||||
viewer->textRenderer()->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()));
|
||||
{
|
||||
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);
|
||||
dock->setObjectName(debug_widgets_names[i]);
|
||||
dock->setWidget(debugger->widget(debug_widgets[i]));
|
||||
this->addDockWidget(Qt::BottomDockWidgetArea, dock);
|
||||
this->QMainWindow::addDockWidget(Qt::BottomDockWidgetArea, dock);
|
||||
dock->hide();
|
||||
}
|
||||
debugger->setAutoShowStandardWindow(false);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <QtOpenGL/qgl.h>
|
||||
#include <CGAL/Qt/DemosMainWindow.h>
|
||||
#include <CGAL/Three/Three.h>
|
||||
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptable>
|
||||
|
|
@ -48,6 +49,7 @@ namespace Ui {
|
|||
class MAINWINDOW_EXPORT MainWindow :
|
||||
public CGAL::Qt::DemosMainWindow,
|
||||
public Messages_interface,
|
||||
public CGAL::Three::Three,
|
||||
protected QScriptable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -410,6 +412,7 @@ private:
|
|||
//!Called when "Add new group" in the file menu is triggered.
|
||||
QAction* actionAddToGroup;
|
||||
QAction* actionResetDefaultLoaders;
|
||||
CGAL::Three::Three* three;
|
||||
void print_message(QString message) { messages->information(message); }
|
||||
Messages_interface* messages;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "Scene_polyhedron_selection_item.h"
|
||||
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
|
||||
#include <CGAL/Three/Three.h>
|
||||
#include <fstream>
|
||||
using namespace CGAL::Three;
|
||||
class Polyhedron_demo_selection_io_plugin :
|
||||
|
|
@ -19,7 +20,13 @@ public:
|
|||
#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) {
|
||||
if(fileinfo.suffix().toLower() != "txt") return 0;
|
||||
// There will be no actual loading at this step.
|
||||
|
|
|
|||
|
|
@ -46,17 +46,23 @@ class Polyhedron_demo_polyhedron_stitching_plugin :
|
|||
|
||||
QAction* actionDetectBorders;
|
||||
QAction* actionStitchBorders;
|
||||
QAction* actionStitchByCC;
|
||||
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 */)
|
||||
{
|
||||
scene = scene_interface;
|
||||
actionDetectBorders= new QAction(tr("Detect Boundaries"), mainWindow);
|
||||
actionStitchBorders= new QAction(tr("Stitch Duplicated Boundaries"), mainWindow);
|
||||
actionDetectBorders->setObjectName("actionDetectBorders");
|
||||
actionDetectBorders->setProperty("subMenuName", "Polygon Mesh Processing");
|
||||
actionStitchBorders= new QAction(tr("Stitch Duplicated Boundaries"), mainWindow);
|
||||
actionStitchBorders->setObjectName("actionStitchBorders");
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
@ -76,9 +82,13 @@ public:
|
|||
template <typename Item>
|
||||
void on_actionStitchBorders_triggered(Scene_interface::Item_id index);
|
||||
|
||||
template <typename Item>
|
||||
void on_actionStitchByCC_triggered(Scene_interface::Item_id index);
|
||||
|
||||
public Q_SLOTS:
|
||||
void on_actionDetectBorders_triggered();
|
||||
void on_actionStitchBorders_triggered();
|
||||
void on_actionStitchByCC_triggered();
|
||||
|
||||
}; // 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);
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ if(EIGEN3_FOUND)
|
|||
|
||||
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})
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
target_link_libraries(merge_point_sets_plugin PUBLIC scene_points_with_normal_item)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
//#undef CGAL_LINKED_WITH_TBB
|
||||
|
||||
#include "config.h"
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||
|
||||
#include <CGAL/compute_average_spacing.h>
|
||||
#include <CGAL/Timer.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/Memory_sizer.h>
|
||||
|
||||
#include <QObject>
|
||||
|
|
@ -14,6 +16,9 @@
|
|||
#include <QtPlugin>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "run_with_qprogressdialog.h"
|
||||
|
||||
// Concurrency
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||
|
|
@ -21,6 +26,26 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
|||
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||
#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;
|
||||
class Polyhedron_demo_point_set_average_spacing_plugin :
|
||||
public QObject,
|
||||
|
|
@ -86,16 +111,16 @@ void Polyhedron_demo_point_set_average_spacing_plugin::on_actionAverageSpacing_t
|
|||
if(!ok)
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
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";
|
||||
|
||||
// Computes average spacing
|
||||
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(
|
||||
points->all_or_selection_if_not_empty(),
|
||||
nb_neighbors,
|
||||
points->parameters());
|
||||
Compute_average_spacing_functor functor (points, nb_neighbors);
|
||||
run_with_qprogressdialog (functor, "Computing average spacing...", mw);
|
||||
|
||||
double average_spacing = *functor.result;
|
||||
|
||||
// Print result
|
||||
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")
|
||||
.arg(average_spacing)
|
||||
.arg(average_spacing/radius));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
#include <QtPlugin>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "run_with_qprogressdialog.h"
|
||||
|
||||
#include "ui_Point_set_bilateral_smoothing_plugin.h"
|
||||
|
||||
// Concurrency
|
||||
|
|
@ -23,6 +27,30 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
|||
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||
#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;
|
||||
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.neighborhood_size () << " and sharpness angle of "
|
||||
<< dialog.sharpness_angle () << "... ";
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
|
||||
CGAL::Timer task_timer; task_timer.start();
|
||||
|
||||
for (unsigned int i = 0; i < dialog.iterations (); ++i)
|
||||
{
|
||||
/* double error = */
|
||||
CGAL::bilateral_smooth_point_set<Concurrency_tag>
|
||||
(points->all_or_selection_if_not_empty(),
|
||||
std::ostringstream oss;
|
||||
oss << "Bilateral smoothing (iteration " << i+1 << "/" << dialog.iterations() << ")";
|
||||
|
||||
Bilateral_smoothing_functor functor (points,
|
||||
dialog.neighborhood_size (),
|
||||
points->parameters().
|
||||
sharpness_angle(dialog.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::cerr << task_timer.time() << " seconds, "
|
||||
<< (memory>>20) << " Mb allocated)"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "run_with_qprogressdialog.h"
|
||||
|
||||
#include "ui_Point_set_normal_estimation_plugin.h"
|
||||
|
||||
#if BOOST_VERSION == 105700
|
||||
|
|
@ -32,6 +34,49 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
|||
#else
|
||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||
#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;
|
||||
|
||||
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*) {
|
||||
|
||||
scene = scene_interface;
|
||||
mw = mainWindow;
|
||||
actionNormalEstimation = new QAction(tr("Normal Estimation"), mainWindow);
|
||||
actionNormalEstimation->setObjectName("actionNormalEstimation");
|
||||
actionNormalEstimation->setProperty("subMenuName","Point Set Processing");
|
||||
|
|
@ -160,7 +206,7 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
|
|||
if(!dialog.exec())
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
QApplication::processEvents();
|
||||
|
||||
// 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";
|
||||
|
||||
// Estimates normals direction.
|
||||
CGAL::pca_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
||||
dialog.pca_neighbors(),
|
||||
points->parameters());
|
||||
PCA_estimate_normals_functor functor (points, dialog.pca_neighbors());
|
||||
run_with_qprogressdialog (functor, "Estimating normals by PCA...", mw);
|
||||
|
||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||
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";
|
||||
|
||||
// Estimates normals direction.
|
||||
CGAL::jet_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
||||
dialog.jet_neighbors(),
|
||||
points->parameters());
|
||||
Jet_estimate_normals_functor functor (points, dialog.pca_neighbors());
|
||||
run_with_qprogressdialog (functor, "Estimating normals by jet fitting...", mw);
|
||||
|
||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "
|
||||
|
|
|
|||
|
|
@ -16,6 +16,39 @@
|
|||
#include <QMessageBox>
|
||||
|
||||
#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;
|
||||
class Polyhedron_demo_point_set_outliers_removal_plugin :
|
||||
public QObject,
|
||||
|
|
@ -31,6 +64,7 @@ private:
|
|||
public:
|
||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
||||
scene = scene_interface;
|
||||
mw = mainWindow;
|
||||
actionOutlierRemoval = new QAction(tr("Outliers Selection"), mainWindow);
|
||||
actionOutlierRemoval->setProperty("subMenuName","Point Set Processing");
|
||||
actionOutlierRemoval->setObjectName("actionOutlierRemoval");
|
||||
|
|
@ -87,24 +121,20 @@ void Polyhedron_demo_point_set_outliers_removal_plugin::on_actionOutlierRemoval_
|
|||
const double distance_threshold = dialog.distance();
|
||||
const int nb_neighbors = dialog.nbNeighbors();
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
|
||||
CGAL::Timer task_timer; task_timer.start();
|
||||
std::cerr << "Select outliers (" << removed_percentage <<"% with distance threshold "
|
||||
<< distance_threshold << ")...\n";
|
||||
|
||||
// Computes outliers
|
||||
Point_set::iterator first_point_to_remove =
|
||||
CGAL::remove_outliers(*points,
|
||||
nb_neighbors,
|
||||
points->parameters().
|
||||
threshold_percent(removed_percentage).
|
||||
threshold_distance(distance_threshold));
|
||||
|
||||
Outlier_removal_functor functor (points, nb_neighbors, removed_percentage, distance_threshold);
|
||||
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Selecting outliers...", mw);
|
||||
Point_set::iterator first_point_to_remove = *functor.result;
|
||||
|
||||
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::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, "
|
||||
<< (memory>>20) << " Mb allocated)"
|
||||
<< std::endl;
|
||||
|
|
|
|||
|
|
@ -38,8 +38,27 @@
|
|||
#include <boost/foreach.hpp>
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
|
||||
#include "run_with_qprogressdialog.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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -303,7 +235,7 @@ private:
|
|||
comments += "shape -1 no assigned shape\n";
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
|
||||
Shape_detection shape_detection;
|
||||
shape_detection.set_input(*points, points->point_map(), points->normal_map());
|
||||
|
|
@ -340,8 +272,8 @@ private:
|
|||
// The actual shape detection.
|
||||
CGAL::Real_timer t;
|
||||
t.start();
|
||||
Progress_bar_callback callback;
|
||||
shape_detection.detect(op, callback);
|
||||
Detect_shapes_functor<Shape_detection> functor (shape_detection, op);
|
||||
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Detecting shapes...", mw);
|
||||
t.stop();
|
||||
|
||||
std::cout << shape_detection.shapes().size() << " shapes found in "
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
#include <QtPlugin>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "run_with_qprogressdialog.h"
|
||||
|
||||
#include "ui_Point_set_simplification_plugin.h"
|
||||
|
||||
// Concurrency
|
||||
|
|
@ -26,6 +28,68 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
|||
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||
#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;
|
||||
class Polyhedron_demo_point_set_simplification_plugin :
|
||||
|
|
@ -41,6 +105,7 @@ class Polyhedron_demo_point_set_simplification_plugin :
|
|||
public:
|
||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface,Messages_interface*) {
|
||||
scene = scene_interface;
|
||||
mw = mainWindow;
|
||||
actionSimplify = new QAction(tr("Simplification Selection"), mainWindow);
|
||||
actionSimplify->setProperty("subMenuName","Point Set Processing");
|
||||
|
||||
|
|
@ -130,7 +195,7 @@ void Polyhedron_demo_point_set_simplification_plugin::on_actionSimplify_triggere
|
|||
if(!dialog.exec())
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
|
||||
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";
|
||||
|
||||
// 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
|
||||
first_point_to_remove =
|
||||
CGAL::grid_simplify_point_set(*points,
|
||||
dialog.gridCellSize()*average_spacing);
|
||||
first_point_to_remove = *functor.result;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Point set hierarchy simplification (cluster size = " << dialog.maximumClusterSize()
|
||||
<< ", maximum variation = " << dialog.maximumSurfaceVariation() << ")...\n";
|
||||
|
||||
// Computes points to remove by Grid Clustering
|
||||
first_point_to_remove =
|
||||
CGAL::hierarchy_simplify_point_set(*points,
|
||||
points->parameters().
|
||||
size(dialog.maximumClusterSize()).
|
||||
maximum_variation(dialog.maximumSurfaceVariation()));
|
||||
// Computes points to remove by Hierarchy
|
||||
Hierarchy_simplify_functor functor (points, dialog.maximumClusterSize(),
|
||||
dialog.maximumSurfaceVariation());
|
||||
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Hierarchy simplyfing...", mw);
|
||||
|
||||
first_point_to_remove = *functor.result;
|
||||
|
||||
}
|
||||
|
||||
std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <CGAL/jet_smooth_point_set.h>
|
||||
|
||||
#include "run_with_qprogressdialog.h"
|
||||
|
||||
// Concurrency
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||
|
|
@ -19,6 +21,24 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
|||
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||
#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;
|
||||
class Polyhedron_demo_point_set_smoothing_plugin :
|
||||
public QObject,
|
||||
|
|
@ -79,17 +99,14 @@ void Polyhedron_demo_point_set_smoothing_plugin::on_actionJetSmoothing_triggered
|
|||
&ok);
|
||||
if(!ok) return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
QApplication::processEvents();
|
||||
CGAL::jet_smooth_point_set<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
||||
nb_neighbors,
|
||||
points->parameters());
|
||||
|
||||
Jet_smoothing_functor functor (points, nb_neighbors);
|
||||
run_with_qprogressdialog (functor, "Smoothing point set...", mw);
|
||||
|
||||
points->invalidate_bounds();
|
||||
|
||||
// calling jet_smooth_point_set breaks the normals
|
||||
points->remove_normal_map();
|
||||
|
||||
// update scene
|
||||
item->invalidateOpenGLBuffers();
|
||||
scene->itemChanged(index);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#include <QtPlugin>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "run_with_qprogressdialog.h"
|
||||
|
||||
#include "ui_Point_set_wlop_plugin.h"
|
||||
|
||||
// Concurrency
|
||||
|
|
@ -24,6 +26,53 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
|||
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||
#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;
|
||||
class Polyhedron_demo_point_set_wlop_plugin :
|
||||
public QObject,
|
||||
|
|
@ -38,6 +87,7 @@ class Polyhedron_demo_point_set_wlop_plugin :
|
|||
public:
|
||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
||||
scene = scene_interface;
|
||||
mw = mainWindow;
|
||||
actionSimplifyAndRegularize = new QAction(tr("WLOP Simplification and Regularization Selection"), mainWindow);
|
||||
actionSimplifyAndRegularize->setProperty("subMenuName","Point Set Processing");
|
||||
actionSimplifyAndRegularize->setObjectName("actionSimplifyAndRegularize");
|
||||
|
|
@ -89,7 +139,7 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
|
|||
if(!dialog.exec())
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||
|
||||
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";
|
||||
|
||||
// Computes average spacing
|
||||
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
||||
6 /* knn = 1 ring */,
|
||||
points->parameters());
|
||||
Compute_average_spacing_functor functor_as (points, 6);
|
||||
run_with_qprogressdialog (functor_as, "WLOP: computing average spacing...", mw);
|
||||
double average_spacing = *functor_as.result;
|
||||
|
||||
Scene_points_with_normal_item* new_item
|
||||
= new Scene_points_with_normal_item();
|
||||
|
|
@ -109,12 +159,9 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
|
|||
item->setVisible(false);
|
||||
scene->addItem(new_item);
|
||||
|
||||
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 (dialog.retainedPercentage()).
|
||||
neighbor_radius (dialog.neighborhoodRadius()*average_spacing));
|
||||
Wlop_functor functor (points, dialog.retainedPercentage(),
|
||||
dialog.neighborhoodRadius() * average_spacing, new_item);
|
||||
run_with_qprogressdialog (functor, "WLOP simplification and regularization...", mw);
|
||||
|
||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||
std::cerr << "Simplification and regularization: "
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#include <CGAL/Search_traits_3.h>
|
||||
#include <CGAL/squared_distance_3.h>
|
||||
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
||||
#include <CGAL/Default_diagonalize_traits.h>
|
||||
#include <CGAL/compute_average_spacing.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
#include <CGAL/jet_smooth_point_set.h>
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/IO/print_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>
|
||||
|
||||
namespace CGAL {
|
||||
|
|
@ -36,16 +38,54 @@ namespace CGAL {
|
|||
template < class Traits,
|
||||
class Items,
|
||||
template < class T, class I, class A>
|
||||
class HDS, class Alloc>
|
||||
class HDS, class Alloc, class NamedParameters>
|
||||
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
|
||||
// as the stream indicates.
|
||||
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();
|
||||
}
|
||||
|
||||
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,
|
||||
class Items,
|
||||
|
|
@ -53,13 +93,11 @@ template < class Traits,
|
|||
class HDS, class Alloc>
|
||||
bool
|
||||
read_off(std::istream& in,
|
||||
Polyhedron_3<Traits,Items,HDS,Alloc>& P) {
|
||||
// reads a polyhedron from `in' and appends it to P.
|
||||
CGAL::scan_OFF( in, P);
|
||||
return in.good();
|
||||
Polyhedron_3<Traits,Items,HDS,Alloc>& P)
|
||||
{
|
||||
return read_off(in, P, parameters::all_default());
|
||||
}
|
||||
|
||||
|
||||
template < class Traits,
|
||||
class Items,
|
||||
template < class T, class I, class A>
|
||||
|
|
|
|||
|
|
@ -15,221 +15,335 @@
|
|||
// $Id$
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
//
|
||||
// Author(s) : Andreas Fabri
|
||||
// Author(s) : Andreas Fabri,
|
||||
// Mael Rouxel-Labbé
|
||||
|
||||
#ifndef CGAL_IO_STL_READER_H
|
||||
#define CGAL_IO_STL_READER_H
|
||||
|
||||
#include <CGAL/array.h>
|
||||
#include <CGAL/IO/io.h>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
bool
|
||||
read_STL( std::istream& input,
|
||||
bool read_ASCII_facet(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<int,3> >& facets,
|
||||
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;
|
||||
cpp11::array<int,3> ijk;
|
||||
cpp11::array<double,3> p;
|
||||
std::map<cpp11::array<double, 3>, int> index_map;
|
||||
|
||||
char line[80];
|
||||
int i = 0, ni = 0;
|
||||
std::string s;
|
||||
std::string facet("facet"),
|
||||
endsolid("endsolid");
|
||||
|
||||
// read the 5 first characters to check if the first word is "solid"
|
||||
boost::uint8_t c;
|
||||
for(; i < 5; i++){
|
||||
while(input >> s)
|
||||
{
|
||||
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));
|
||||
line[i]=c;
|
||||
if(!input.good())
|
||||
break;
|
||||
|
||||
if(verbose)
|
||||
std::cout << c;
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
s = std::string(line,5);
|
||||
if(s == solid){
|
||||
// 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
|
||||
if(verbose)
|
||||
std::cout << std::endl;
|
||||
|
||||
// first skip whitespaces after solid
|
||||
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 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;
|
||||
}
|
||||
if(pos != 80)
|
||||
return true; // empty file
|
||||
|
||||
// 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;
|
||||
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;
|
||||
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];
|
||||
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[2]), sizeof(normal[2]));
|
||||
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[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;
|
||||
input.read(reinterpret_cast<char*>(&x), sizeof(x));
|
||||
input.read(reinterpret_cast<char*>(&y), sizeof(y));
|
||||
input.read(reinterpret_cast<char*>(&z), sizeof(z));
|
||||
if(!(input.read(reinterpret_cast<char*>(&x), sizeof(x))) ||
|
||||
!(input.read(reinterpret_cast<char*>(&y), sizeof(y))) ||
|
||||
!(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;
|
||||
|
||||
std::map<cpp11::array<double, 3>, int>::iterator iti =
|
||||
pmap.insert(std::make_pair(p,-1)).first;
|
||||
if(iti->second==-1){
|
||||
index_map.insert(std::make_pair(p, -1)).first;
|
||||
|
||||
if(iti->second == -1)
|
||||
{
|
||||
ijk[j] = index;
|
||||
iti->second = index++;
|
||||
points.push_back(p);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ijk[j] = iti->second;
|
||||
}
|
||||
}
|
||||
if((ijk[0] != ijk[1]) &&
|
||||
(ijk[0] != ijk[2]) &&
|
||||
(ijk[1] != ijk[2])){
|
||||
|
||||
facets.push_back(ijk);
|
||||
}else{
|
||||
if(verbose){
|
||||
std::cerr << "ignore degenerate face" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Read so-called attribute byte count and ignore it
|
||||
char c;
|
||||
input.read(reinterpret_cast<char*>(&c), sizeof(c));
|
||||
input.read(reinterpret_cast<char*>(&c), sizeof(c));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if(!(input.read(reinterpret_cast<char*>(&c), sizeof(c))) ||
|
||||
!(input.read(reinterpret_cast<char*>(&c), sizeof(c))))
|
||||
{
|
||||
if(verbose)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}while(s != endloop);
|
||||
|
||||
facets.push_back(ijk);
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
#endif // CGAL_IO_STL_READER_H
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#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/Inverse_index.h>
|
||||
|
|
@ -31,11 +35,12 @@
|
|||
|
||||
namespace CGAL {
|
||||
|
||||
template <class Polyhedron, class Writer>
|
||||
template <class Polyhedron, class Writer, class Vpm>
|
||||
void
|
||||
generic_print_polyhedron( std::ostream& out,
|
||||
const Polyhedron& P,
|
||||
Writer& writer) {
|
||||
Writer& writer,
|
||||
const Vpm& vpm ) {
|
||||
// writes P to `out' in the format provided by `writer'.
|
||||
typedef typename Polyhedron::Vertex_const_iterator VCI;
|
||||
typedef typename Polyhedron::Facet_const_iterator FCI;
|
||||
|
|
@ -45,10 +50,10 @@ generic_print_polyhedron( std::ostream& out,
|
|||
P.size_of_vertices(),
|
||||
P.size_of_halfedges(),
|
||||
P.size_of_facets());
|
||||
for( VCI vi = P.vertices_begin(); vi != P.vertices_end(); ++vi) {
|
||||
writer.write_vertex( ::CGAL::to_double( vi->point().x()),
|
||||
::CGAL::to_double( vi->point().y()),
|
||||
::CGAL::to_double( vi->point().z()));
|
||||
BOOST_FOREACH(typename boost::graph_traits<Polyhedron>::vertex_descriptor vi, vertices(P)) {
|
||||
writer.write_vertex( ::CGAL::to_double( get(vpm, vi).x()),
|
||||
::CGAL::to_double( get(vpm, vi).y()),
|
||||
::CGAL::to_double( get(vpm, vi).z()));
|
||||
}
|
||||
typedef Inverse_index< VCI> Index;
|
||||
Index index( P.vertices_begin(), P.vertices_end());
|
||||
|
|
@ -69,6 +74,15 @@ generic_print_polyhedron( std::ostream& out,
|
|||
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
|
||||
#endif // CGAL_IO_GENERIC_PRINT_POLYHEDRON_H //
|
||||
// EOF //
|
||||
|
|
|
|||
|
|
@ -33,16 +33,24 @@
|
|||
|
||||
namespace CGAL {
|
||||
|
||||
template <class Polyhedron>
|
||||
template <class Polyhedron, class Vpm>
|
||||
void print_polyhedron_with_header_OFF( std::ostream& out,
|
||||
const Polyhedron& P,
|
||||
const File_header_OFF& header) {
|
||||
const File_header_OFF& header,
|
||||
const Vpm& vpm) {
|
||||
File_writer_OFF writer( header);
|
||||
writer.header().set_polyhedral_surface( true);
|
||||
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>
|
||||
void print_polyhedron_OFF( std::ostream& out,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
solid cube_corner
|
||||
facet normal 0.0 -1.0 0.0
|
||||
outer loop
|
||||
|
|
@ -7,6 +8,7 @@ solid cube_corner
|
|||
endloop
|
||||
endfacet
|
||||
facet normal 0.0 0.0 -1.0
|
||||
|
||||
outer loop
|
||||
vertex 0.0 0.0 0.0
|
||||
vertex 0.0 1.0 0.0
|
||||
|
|
@ -28,4 +30,3 @@ solid cube_corner
|
|||
endloop
|
||||
endfacet
|
||||
endsolid
|
||||
|
||||
Binary file not shown.
|
|
@ -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++){
|
||||
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/triangle.stl", 3, 1);
|
||||
|
||||
|
||||
read("data/ascii-tetrahedron.stl", 4, 4);
|
||||
read("data/binary-tetrahedron-nice-header.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-4.stl", 4, 4);
|
||||
read("data/binary-tetrahedron-non-standard-header-5.stl", 4, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@ include_directories( ./ )
|
|||
find_package(CGAL COMPONENTS Qt5)
|
||||
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_package(Qt5 QUIET COMPONENTS Xml Script OpenGL)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 `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}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,10 +65,9 @@ value type of `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.
|
||||
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.
|
||||
|
||||
\note This function is significantly faster when using
|
||||
`Eigen_diagonalize_traits` and it is strongly advised to use this
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
#include <CGAL/Cartesian.h>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/linear_least_squares_fitting_3.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
|
||||
|
||||
// test for the linear_least_square_fitting() functions.
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/algorithm.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
|
||||
|
||||
// test for the linear_least_square_fitting() functions.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
|
||||
|
||||
// test for the linear_least_square_fitting() functions.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
|
||||
|
||||
// test for the linear_least_square_fitting() functions.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
|
||||
|
||||
// test for the linear_least_square_fitting() functions.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// Example program for the linear_least_square_fitting function
|
||||
|
||||
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
|
||||
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/linear_least_squares_fitting_3.h>
|
||||
#ifdef CGAL_EIGEN3_ENABLED
|
||||
|
|
|
|||
|
|
@ -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 tetrahedra in 3D
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <CGAL/internal/disable_deprecation_warnings_and_errors.h>
|
||||
|
||||
// test for the linear_least_square_fitting() functions.
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/algorithm.h>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/linear_least_squares_fitting_3.h>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@
|
|||
#include <CGAL/iterator.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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -61,11 +61,10 @@ namespace Scale_space_reconstruction_3
|
|||
|
||||
* \tparam DiagonalizeTraits model of `DiagonalizeTraits` that
|
||||
* determines how to diagonalize a weighted covariance matrix to
|
||||
* approximate a weighted point set. 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.
|
||||
* approximate a weighted point set. 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.
|
||||
* \tparam ConcurrencyTag indicates whether to use concurrent
|
||||
* processing. It can be omitted: if TBB (or greater) is available
|
||||
* and `CGAL_LINKED_WITH_TBB` is defined then `Parallel_tag` is
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ follows:
|
|||
\tparam FT Number type
|
||||
\tparam dim Dimension of the matrices and vectors
|
||||
|
||||
\cgalHasModel `CGAL::Default_diagonalize_traits`
|
||||
\cgalHasModel `CGAL::Diagonalize_traits`
|
||||
\cgalHasModel `CGAL::Eigen_diagonalize_traits`
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -31,10 +31,8 @@
|
|||
|
||||
## Classes ##
|
||||
|
||||
- `CGAL::Diagonalize_traits`
|
||||
- `CGAL::Eigen_solver_traits`
|
||||
- `CGAL::Eigen_diagonalize_traits`
|
||||
- `CGAL::Default_diagonalize_traits`
|
||||
- `CGAL::Eigen_vector`
|
||||
- `CGAL::Eigen_matrix`
|
||||
- `CGAL::Eigen_sparse_matrix`
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue