From 4747f8ccaf62e43162c005446358429ed45ea299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 3 May 2019 14:56:21 +0200 Subject: [PATCH] Improve reader sanity - Re-indent to more normal standards - Remove usage of *_impl.h - Clean useless and trailing whitespace - some minor code readability changes --- .../Bounded_normal_change_placement.h | 2 +- .../Edge_collapse/Constrained_placement.h | 2 +- .../Count_ratio_stop_predicate.h | 10 +- .../Edge_collapse/Count_stop_predicate.h | 8 +- .../Policies/Edge_collapse/Edge_length_cost.h | 4 +- .../Edge_length_stop_predicate.h | 8 +- .../Edge_collapse/LindstromTurk_cost.h | 6 +- .../Edge_collapse/LindstromTurk_placement.h | 4 +- .../Edge_collapse/Midpoint_placement.h | 2 +- .../EdgeCollapseSimplificationVisitor.h | 16 +- .../Concepts/GetCost.h | 4 +- .../Concepts/GetPlacement.h | 2 +- .../Concepts/StopPredicate.h | 6 +- .../Surface_mesh_simplification.txt | 4 +- .../edge_collapse_OpenMesh.cpp | 12 +- .../edge_collapse_all_short_edges.cpp | 33 +- .../edge_collapse_bounded_normal_change.cpp | 18 +- .../edge_collapse_constrain_sharp_edges.cpp | 149 +- ...collapse_constrained_border_polyhedron.cpp | 94 +- ...llapse_constrained_border_surface_mesh.cpp | 81 +- .../edge_collapse_enriched_polyhedron.cpp | 6 +- .../edge_collapse_linear_cell_complex.cpp | 10 +- .../edge_collapse_polyhedron.cpp | 8 +- .../edge_collapse_surface_mesh.cpp | 6 +- .../edge_collapse_visitor_surface_mesh.cpp | 32 +- .../include/CGAL/Cartesian/MatrixC33.h | 280 ++-- .../include/CGAL/Null_matrix.h | 11 +- .../Detail/Common.h | 175 +-- .../Detail/Edge_collapse.h | 1395 +++++++++++++---- .../Detail/Edge_collapse_impl.h | 939 ----------- .../Edge_collapse_visitor_base.h | 59 +- .../HalfedgeGraph_Polyhedron_3.h | 4 - .../Bounded_normal_change_placement.h | 60 +- .../Edge_collapse/Constrained_placement.h | 37 +- .../Count_ratio_stop_predicate.h | 50 +- .../Edge_collapse/Count_stop_predicate.h | 50 +- .../Detail/Lindstrom_Turk_core.h | 806 ++++++++-- .../Detail/Lindstrom_Turk_core_impl.h | 620 -------- .../Policies/Edge_collapse/Edge_length_cost.h | 35 +- .../Edge_length_stop_predicate.h | 25 +- .../Policies/Edge_collapse/Edge_profile.h | 419 +++-- .../Edge_collapse/Edge_profile_impl.h | 214 --- .../Policies/Edge_collapse/LindstromTurk.h | 7 +- .../Edge_collapse/LindstromTurk_cost.h | 38 +- .../Edge_collapse/LindstromTurk_params.h | 42 +- .../Edge_collapse/LindstromTurk_placement.h | 37 +- .../Edge_collapse/Midpoint_and_length.h | 3 - .../Edge_collapse/Midpoint_placement.h | 2 +- .../edge_collapse.h | 200 +-- .../test/Surface_mesh_simplification/basics.h | 16 +- .../edge_collapse_topology.cpp | 22 +- .../test_edge_collapse_Polyhedron_3.cpp | 328 ++-- .../test_edge_profile_link.cpp | 28 +- .../test_self_intersection.h | 66 +- 54 files changed, 3052 insertions(+), 3443 deletions(-) delete mode 100644 Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h delete mode 100644 Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core_impl.h delete mode 100644 Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile_impl.h diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h index 3fabd75ee17..71193952207 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h @@ -44,7 +44,7 @@ triangle in the profile changes the normal by more than 90 degree. */ template optional -operator()( Profile const& profile ) const; +operator()(const Profile& profile) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h index 94e5c193e39..903a33cf2a9 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h @@ -30,7 +30,7 @@ Constructor */ Constrained_placement( EdgeIsConstrainedMap map=EdgeIsConstrainedMap(), - BasePlacement base= BasePlacement() ); + BasePlacement base= BasePlacement()); /// @} }; /* end Surface_mesh_simplification::Midpoint_placement */ diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h index 0d01d7b04a7..1d9cf188edb 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h @@ -26,7 +26,7 @@ public: /*! Initializes the predicate establishing the `ratio`. */ -Count_ratio_stop_predicate( double ratio ); +Count_ratio_stop_predicate(double ratio); /// @} @@ -34,14 +34,14 @@ Count_ratio_stop_predicate( double ratio ); /// @{ /*! -Returns ` ( ((double)current_count / (double)initial_count) < ratio)`. +Returns ` (((double)current_count / (double)initial_count) < ratio)`. All other parameters are ignored (but exist since this is a generic policy). */ -bool operator()( FT const& current_cost -, Profile const& edge_profile +bool operator()(FT const& current_cost +, const Profile& edge_profile , size_type initial_count , size_type current_count -) const ; +) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h index 7e11c1950ad..c661812fa8a 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h @@ -25,7 +25,7 @@ public: /*! Initializes the predicate establishing the `threshold` value. */ -Count_stop_predicate( size_type threshold ); +Count_stop_predicate(size_type threshold); /// @} @@ -35,11 +35,11 @@ Count_stop_predicate( size_type threshold ); /*! Returns `(current_count < threshold)`. All other parameters are ignored (but exist since this is a generic policy). */ -bool operator()( FT const& current_cost -, Profile const& edge_profile +bool operator()(FT const& current_cost +, const Profile& edge_profile , size_type initial_count , size_type current_count -) const ; +) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h index 58f43d54057..ad9bd4c76ec 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h @@ -39,8 +39,8 @@ The `placement` argument is ignored. */ template -optional operator()( Profile const& profile -, T const& placement ) const; +optional operator()(const Profile& profile +, T const& placement) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h index d2c11fec0be..8100e28e990 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h @@ -24,7 +24,7 @@ public: /*! Initializes the predicate establishing the `threshold` value. */ -Edge_length_stop_predicate( FT threshold ); +Edge_length_stop_predicate(FT threshold); /// @} @@ -35,11 +35,11 @@ Edge_length_stop_predicate( FT threshold ); Returns `(CGAL::squared_distance(edge_profile.p0(),edge_profile.p1()) > threshold*threshold)`. All other parameters are ignored (but exist since this is a generic policy). */ -bool operator()( FT const& -, Profile const& edge_profile +bool operator()(FT const& +, const Profile& edge_profile , size_type , size_type -) const ; +) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h index 8a5a91dd3ac..1c40ecb432b 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h @@ -26,7 +26,7 @@ public: Initializes the policy with the given weighting unit factor. See \ref SurfaceMeshSimplificationLindstromTurkStrategy for details on the meaning of this factor. */ -LindstromTurk_cost( FT const& factor = FT(0.5) ); +LindstromTurk_cost(FT const& factor = FT(0.5)); /// @} @@ -39,8 +39,8 @@ the new `placement` computed for it. */ template optional -operator()( Profile const& profile - , boost::optional const& placement ) const; +operator()(const Profile& profile + , boost::optional const& placement) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h index b182d0f246b..ab9b229c665 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h @@ -28,7 +28,7 @@ public: Initializes the policy with the given weighting unit factor. See \ref SurfaceMeshSimplificationLindstromTurkStrategy for details on the meaning of this factor. */ -LindstromTurk_placement( FT const& factor = FT(0.5) ); +LindstromTurk_placement(FT const& factor = FT(0.5)); /// @} @@ -41,7 +41,7 @@ Returns the new position for the remaining vertex after collapsing the edge */ template optional -operator()( Profile const& profile ) const; +operator()(const Profile& profile) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h index feef0b812da..be4baa1fd3f 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h @@ -37,7 +37,7 @@ the points of the source and target vertices */ template optional -operator()( Profile const& profile ) const; +operator()(const Profile& profile) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapseSimplificationVisitor.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapseSimplificationVisitor.h index 34a2067294e..b8e07c38ecd 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapseSimplificationVisitor.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/EdgeCollapseSimplificationVisitor.h @@ -49,26 +49,26 @@ typedef unspecified_type size_type; /*! Called before the algorithm starts. */ -void OnStarted( TriangleMesh& surface_mesh ); +void OnStarted(TriangleMesh& surface_mesh); /*! Called after the algorithm finishes. */ -void OnFinished ( TriangleMesh& surface_mesh ) ; +void OnFinished (TriangleMesh& surface_mesh); /*! Called when the `StopPredicate` returned `true` (but not if the algorithm terminates because the surface mesh could not be simplified any further). */ -void OnStopConditionReached( TriangleMesh& surface_mesh ) ; +void OnStopConditionReached(TriangleMesh& surface_mesh); /*! Called during the collecting phase (when a cost is assigned to the edges), for each edge collected. */ -void OnCollected( Profile const& profile, boost::optional cost ); +void OnCollected(const Profile& profile, boost::optional cost); /*! Called during the processing phase (when edges are collapsed), @@ -85,7 +85,7 @@ the edge will not be collapsed. the number of edges. */ -void OnSelected( Profile const& profile +void OnSelected(const Profile& profile , boost::optional cost , size_type initial_count , size_type current_count @@ -99,14 +99,14 @@ If `placement` is absent (meaning that it could not be computed) the edge will not be collapsed. */ -void OnCollapsing( Profile const& profile +void OnCollapsing(const Profile& profile , boost::optional placement ); /*! Called when an edge has been collapsed and replaced by the vertex `vd` */ -void OnCollapsed( Profile const&, Profile::vertex_descriptor const& vd) {} +void OnCollapsed(Profile const&, Profile::const vertex_descriptor vd) {} /*! Called for each selected edge which cannot be @@ -115,7 +115,7 @@ type of the surface mesh (turn it into a non-manifold for instance). */ -void OnNonCollapsable( Profile const& profile ); +void OnNonCollapsable(const Profile& profile); /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetCost.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetCost.h index dbae56866fa..c62332b3197 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetCost.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetCost.h @@ -32,8 +32,8 @@ using the calculated placement. \tparam Profile must be a model of `EdgeProfile`. */ template - boost::optional operator()( Profile const& edge_profile - , boost::optional const& placement ) const; + boost::optional operator()(const Profile& edge_profile + , boost::optional const& placement) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h index f04919ece77..c1a87ea6d3d 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/GetPlacement.h @@ -34,7 +34,7 @@ which replaces the collapsing edge (represented by its profile). \tparam Profile must be a model of `EdgeProfile`. */ template -boost::optionaloperator()( Profile const& edge_profile ) const; +boost::optionaloperator()(const Profile& edge_profile) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/StopPredicate.h b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/StopPredicate.h index 70b65d553e1..de612f22355 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/StopPredicate.h +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Concepts/StopPredicate.h @@ -55,11 +55,11 @@ If the return value is `true` the simplification terminates before processing th otherwise it continues normally. */ -bool operator()( FT const& current_cost -, Profile const& profile +bool operator()(FT const& current_cost +, const Profile& profile , size_type initial_count , size_type current_count -) const ; +) const; /// @} diff --git a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt index 536e8257e53..5d33bf29091 100644 --- a/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt +++ b/Surface_mesh_simplification/doc/Surface_mesh_simplification/Surface_mesh_simplification.txt @@ -95,7 +95,7 @@ and geometric conditions. The algorithm presented in \cgalCite{gh-ssqem-97} contracts (collapses) arbitrary vertex pairs and not only edges by considering certain vertex pairs as forming a pseudo-edge and proceeding to collapse -both edges and pseudo-edges in the same way as in \cgalCite{cgal:lt-fmeps-98}, \cgalCite{cgal:lt-ems-99} ( +both edges and pseudo-edges in the same way as in \cgalCite{cgal:lt-fmeps-98}, \cgalCite{cgal:lt-ems-99} ( which is the algorithm implemented here). However, contracting an arbitrary vertex-pair may result in a non-manifold surface mesh, but the current state of this package can only deal with manifold surface meshes, thus, it can only collapse edges. That is, this package cannot be used as a framework for vertex contraction. \section Surface_mesh_simplificationCost Cost Strategy @@ -249,7 +249,7 @@ int r = edge_collapse(surface_mesh .get_cost(cf) .get_placement(pf) .visitor(vis) - ); + ); \endcode diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_OpenMesh.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_OpenMesh.cpp index 6a766f1b2c8..eeee8eefedf 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_OpenMesh.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_OpenMesh.cpp @@ -53,18 +53,18 @@ private: -namespace SMS = CGAL::Surface_mesh_simplification ; +namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; Constrained_edge_map constraints_map(surface_mesh); - if (argc==2) + if(argc==2) OpenMesh::IO::read_mesh(surface_mesh, argv[1]); else OpenMesh::IO::read_mesh(surface_mesh, "cube.off"); - if (!CGAL::is_triangle_mesh(surface_mesh)){ + if(!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -89,11 +89,11 @@ int main( int argc, char** argv ) ,CGAL::parameters::halfedge_index_map (get(CGAL::halfedge_index ,surface_mesh)) .vertex_point_map(get(boost::vertex_point, surface_mesh)) .edge_is_constrained_map(constraints_map) - ); + ); surface_mesh.garbage_collection(); std::cout << "\nFinished...\n" << r << " edges removed.\n" - << num_edges(surface_mesh) << " final edges.\n" ; + << num_edges(surface_mesh) << " final edges.\n"; OpenMesh::IO::write_mesh(surface_mesh, "out.off"); diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_all_short_edges.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_all_short_edges.cpp index 7f51f4db768..15858ce9fca 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_all_short_edges.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_all_short_edges.cpp @@ -12,15 +12,14 @@ #include #include - typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef CGAL::Polyhedron_3 Surface_mesh; -namespace SMS = CGAL::Surface_mesh_simplification ; +namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { - if (argc<3) + if(argc<3) { std::cerr << "Usage: " << argv[0] << " input.off minimal_edge_length [out.off]\n"; return EXIT_FAILURE; @@ -28,29 +27,27 @@ int main( int argc, char** argv ) Surface_mesh surface_mesh; - std::ifstream is(argv[1]) ; is >> surface_mesh ; + std::ifstream is(argv[1]); is >> surface_mesh; double threshold = atof(argv[2]); - if (!CGAL::is_triangle_mesh(surface_mesh)){ + if(!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } - int r = SMS::edge_collapse - (surface_mesh - , CGAL::Surface_mesh_simplification::Edge_length_stop_predicate(threshold) - , CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index,surface_mesh)) - .halfedge_index_map (get(CGAL::halfedge_external_index ,surface_mesh)) - .get_cost (SMS::Edge_length_cost ()) - .get_placement(SMS::Midpoint_placement()) - ); + int r = SMS::edge_collapse(surface_mesh, + CGAL::Surface_mesh_simplification::Edge_length_stop_predicate(threshold), + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)) + .halfedge_index_map(get(CGAL::halfedge_external_index ,surface_mesh)) + .get_cost(SMS::Edge_length_cost ()) + .get_placement(SMS::Midpoint_placement())); std::cout << "\nFinished...\n" << r << " edges removed.\n" - << (surface_mesh.size_of_halfedges()/2) << " final edges.\n" ; + << (surface_mesh.size_of_halfedges()/2) << " final edges.\n"; - std::ofstream os( argc > 3 ? argv[3] : "out.off" ) ; + std::ofstream os(argc > 3 ? argv[3] : "out.off"); os.precision(17); - os << surface_mesh ; + os << surface_mesh; - return EXIT_SUCCESS ; + return EXIT_SUCCESS; } diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_bounded_normal_change.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_bounded_normal_change.cpp index 4e3072c4103..da9fa48583e 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_bounded_normal_change.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_bounded_normal_change.cpp @@ -9,13 +9,12 @@ #include #include - typedef CGAL::Simple_cartesian Kernel; -typedef CGAL::Surface_mesh Surface_mesh; +typedef CGAL::Surface_mesh Surface_mesh; namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; @@ -26,7 +25,7 @@ int main( int argc, char** argv ) // In this example, the simplification stops when the number of undirected edges // left in the surface mesh drops below the specified number (1000) SMS::Count_stop_predicate stop(num_halfedges(surface_mesh)/2 - 1); - + typedef SMS::Bounded_normal_change_placement > Placement; @@ -34,15 +33,14 @@ int main( int argc, char** argv ) // The surface mesh and stop conditions are mandatory arguments. // The index maps are needed because the vertices and edges // of this surface mesh lack an "id()" field. - SMS::edge_collapse( surface_mesh, + SMS::edge_collapse(surface_mesh, stop, - CGAL::parameters::get_cost (SMS::LindstromTurk_cost()) - .get_placement(Placement()) - ); + CGAL::parameters::get_cost(SMS::LindstromTurk_cost()) + .get_placement(Placement())); - std::ofstream os( argc > 2 ? argv[2] : "out.off" ); + std::ofstream os(argc > 2 ? argv[2] : "out.off"); os.precision(17); os << surface_mesh; - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp index 0e915652809..b5e3bb919e0 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrain_sharp_edges.cpp @@ -1,6 +1,3 @@ -#include -#include - #include #include @@ -10,21 +7,25 @@ #include #include #include + #include +#include +#include -typedef CGAL::Simple_cartesian Kernel; -typedef Kernel::Point_3 Point_3; -typedef CGAL::Polyhedron_3 Surface_mesh; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; -typedef boost::graph_traits::edge_descriptor edge_descriptor; -typedef boost::graph_traits::edge_iterator edge_iterator; +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Polyhedron_3 Surface_mesh; -namespace SMS = CGAL::Surface_mesh_simplification ; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; +typedef boost::graph_traits::edge_iterator edge_iterator; + +namespace SMS = CGAL::Surface_mesh_simplification; -// // BGL property map which indicates whether an edge is marked as non-removable -struct Constrained_edge_map : public boost::put_get_helper +struct Constrained_edge_map + : public boost::put_get_helper { typedef boost::readable_property_map_tag category; typedef bool value_type; @@ -37,7 +38,7 @@ struct Constrained_edge_map : public boost::put_get_helper::null_face() ) - || (face(opposite(halfedge(e,sm),sm),sm) == boost::graph_traits::null_face() ); + return (face(halfedge(e,sm),sm) == boost::graph_traits::null_face()) + || (face(opposite(halfedge(e,sm),sm),sm) == boost::graph_traits::null_face()); } Point_3 point(vertex_descriptor vd, const Surface_mesh& sm) @@ -56,26 +57,29 @@ Point_3 point(vertex_descriptor vd, const Surface_mesh& sm) return get(CGAL::vertex_point, sm, vd); } -int main( int argc, char** argv ) +int main(int argc, char** argv) { CGAL::Unique_hash_map constraint_hmap(false); Surface_mesh surface_mesh; - if (argc < 2){ + if(argc < 2) + { std::cerr << "Usage: " << argv[0] << " input.off [out.off]\n"; return EXIT_FAILURE; } std::ifstream is(argv[1]); - if(!is){ + if(!is) + { std::cerr << "Filename provided is invalid\n"; return EXIT_FAILURE; } - is >> surface_mesh ; + is >> surface_mesh ; - if (!CGAL::is_triangle_mesh(surface_mesh)){ + if(!CGAL::is_triangle_mesh(surface_mesh)) + { std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -94,28 +98,29 @@ int main( int argc, char** argv ) // detect sharp edges std::ofstream cst_output("constrained_edges.cgal"); - edge_iterator eb,ee; - for(boost::tie(eb,ee) = edges(surface_mesh); eb != ee ; ++eb ) + for(edge_descriptor ed : edges(surface_mesh)) { - halfedge_descriptor hd = halfedge(*eb,surface_mesh); - if ( is_border(*eb,surface_mesh) ){ + halfedge_descriptor hd = halfedge(ed, surface_mesh); + if(is_border(ed, surface_mesh)) + { std::cerr << "border" << std::endl; ++nb_sharp_edges; - constraint_hmap[*eb]=true; - constrained_edges[*eb]=std::make_pair(point(source(hd,surface_mesh),surface_mesh), - point(target(hd,surface_mesh),surface_mesh)); + constraint_hmap[ed] = true; + constrained_edges[ed] = std::make_pair(point(source(hd, surface_mesh), surface_mesh), + point(target(hd, surface_mesh), surface_mesh)); } - else{ - double angle = CGAL::approximate_dihedral_angle(point(target(opposite(hd,surface_mesh),surface_mesh),surface_mesh), - point(target(hd,surface_mesh),surface_mesh), - point(target(next(hd,surface_mesh),surface_mesh),surface_mesh), - point(target(next(opposite(hd,surface_mesh),surface_mesh),surface_mesh),surface_mesh)); - if ( CGAL::abs(angle)<100 ){ + else + { + double angle = CGAL::approximate_dihedral_angle(point(target(opposite(hd, surface_mesh), surface_mesh), surface_mesh), + point(target(hd, surface_mesh), surface_mesh), + point(target(next(hd, surface_mesh), surface_mesh), surface_mesh), + point(target(next(opposite(hd, surface_mesh), surface_mesh), surface_mesh), surface_mesh)); + if(CGAL::abs(angle)<100){ ++nb_sharp_edges; - constraint_hmap[*eb]=true; - Point_3 p = point(source(hd,surface_mesh),surface_mesh); - Point_3 q = point(target(hd,surface_mesh),surface_mesh); - constrained_edges[*eb]=std::make_pair(p,q); + constraint_hmap[ed] = true; + Point_3 p = point(source(hd, surface_mesh), surface_mesh); + Point_3 q = point(target(hd, surface_mesh), surface_mesh); + constrained_edges[ed] = std::make_pair(p,q); cst_output << "2 " << p << " " << q << "\n"; } } @@ -127,60 +132,60 @@ int main( int argc, char** argv ) // Contract the surface mesh as much as possible SMS::Count_stop_predicate stop(0); - int r - = SMS::edge_collapse(surface_mesh - ,stop - ,CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)) - .halfedge_index_map(get(CGAL::halfedge_external_index, surface_mesh)) - .edge_is_constrained_map(constraints_map) - .get_placement(placement) - ); + int r = SMS::edge_collapse(surface_mesh, + stop, + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)) + .halfedge_index_map(get(CGAL::halfedge_external_index, surface_mesh)) + .edge_is_constrained_map(constraints_map) + .get_placement(placement)); std::cout << "\nFinished...\n" << r << " edges removed.\n" - << num_edges(surface_mesh) << " final edges.\n" ; - std::ofstream os(argc > 2 ? argv[2] : "out.off") ; os << surface_mesh ; + << num_edges(surface_mesh) << " final edges.\n"; + std::ofstream os(argc > 2 ? argv[2] : "out.off"); os << surface_mesh; std::cout << "Checking sharped edges were preserved...\n"; // check sharp edges were preserved - for(boost::tie(eb,ee) = edges(surface_mesh); eb != ee ; ++eb ) + for(edge_descriptor ed : edges(surface_mesh)) { - halfedge_descriptor hd = halfedge(*eb,surface_mesh); - if ( is_border(*eb,surface_mesh) ){ + halfedge_descriptor hd = halfedge(ed, surface_mesh); + if(is_border(ed, surface_mesh)) + { --nb_sharp_edges; - assert( - constrained_edges[*eb]==std::make_pair( point(source(hd,surface_mesh),surface_mesh), - point(target(hd,surface_mesh),surface_mesh))); + assert(constrained_edges[ed] == std::make_pair(point(source(hd, surface_mesh), surface_mesh), + point(target(hd, surface_mesh), surface_mesh))); } - else{ - double angle = approximate_dihedral_angle(point(target(opposite(hd,surface_mesh),surface_mesh),surface_mesh), - point(target(hd,surface_mesh),surface_mesh), - point(target(next(hd,surface_mesh),surface_mesh),surface_mesh), - point(target(next(opposite(hd,surface_mesh),surface_mesh),surface_mesh),surface_mesh)); - if ( CGAL::abs(angle)<100 ){ + else + { + double angle = approximate_dihedral_angle(point(target(opposite(hd, surface_mesh), surface_mesh), surface_mesh), + point(target(hd, surface_mesh), surface_mesh), + point(target(next(hd, surface_mesh), surface_mesh), surface_mesh), + point(target(next(opposite(hd, surface_mesh), surface_mesh), surface_mesh), surface_mesh)); + if(CGAL::abs(angle)<100) + { --nb_sharp_edges; - assert( - constrained_edges[*eb]==std::make_pair( point(source(hd,surface_mesh),surface_mesh), - point(target(hd,surface_mesh),surface_mesh))); + assert(constrained_edges[ed] == std::make_pair(point(source(hd, surface_mesh), surface_mesh), + point(target(hd, surface_mesh), surface_mesh))); } } } + std::cout << "OK\n"; std::cerr << "# sharp edges = " << nb_sharp_edges << std::endl; std::cout << "Check that no removable edge has been forgotten..." << std::endl; - r = SMS::edge_collapse(surface_mesh - ,stop - ,CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)) - .halfedge_index_map (get(CGAL::halfedge_external_index, surface_mesh)) - .edge_is_constrained_map(constraints_map) - .get_placement(placement) - ); + r = SMS::edge_collapse(surface_mesh, + stop, + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)) + .halfedge_index_map(get(CGAL::halfedge_external_index, surface_mesh)) + .edge_is_constrained_map(constraints_map) + .get_placement(placement) + ); assert(r==0); - if ( r==0 ) + if(r == 0) { std::cout << "OK\n"; - else{ + } else { std::cout << "ERROR! " << r << " edges removed!\n"; return EXIT_FAILURE; } diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp index c8de61eb2c0..ad5d9ffe1b5 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_polyhedron.cpp @@ -1,7 +1,3 @@ -#include -#include -#include - #include #include @@ -17,54 +13,56 @@ // Stop-condition policy #include -typedef CGAL::Simple_cartesian Kernel; -typedef Kernel::Point_3 Point_3; -typedef CGAL::Polyhedron_3 Surface_mesh; +#include +#include +#include -namespace SMS = CGAL::Surface_mesh_simplification ; +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Polyhedron_3 Surface_mesh; + +namespace SMS = CGAL::Surface_mesh_simplification; -// // BGL property map which indicates whether an edge is marked as non-removable -// -struct Border_is_constrained_edge_map{ +struct Border_is_constrained_edge_map +{ const Surface_mesh* sm_ptr; typedef boost::graph_traits::edge_descriptor key_type; typedef bool value_type; typedef value_type reference; typedef boost::readable_property_map_tag category; - Border_is_constrained_edge_map(const Surface_mesh& sm) - : sm_ptr(&sm) - {} + Border_is_constrained_edge_map(const Surface_mesh& sm) : sm_ptr(&sm) {} friend bool get(Border_is_constrained_edge_map m, const key_type& edge) { return CGAL::is_border(edge, *m.sm_ptr); } }; -// // Placement class -// typedef SMS::Constrained_placement, Border_is_constrained_edge_map > Placement; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; - if (argc!=2){ + if(argc != 2) + { std::cerr << "Usage: " << argv[0] << " input.off\n"; return EXIT_FAILURE; } std::ifstream is(argv[1]); - if(!is){ + if(!is) + { std::cerr << "Filename provided is invalid\n"; return EXIT_FAILURE; } - is >> surface_mesh ; - if (!CGAL::is_triangle_mesh(surface_mesh)){ + is >> surface_mesh; + if(!CGAL::is_triangle_mesh(surface_mesh)) + { std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -74,56 +72,54 @@ int main( int argc, char** argv ) std::map >constrained_edges; std::size_t nb_border_edges=0; - for (Surface_mesh::Halfedge_iterator hit=surface_mesh.halfedges_begin(), - hit_end=surface_mesh.halfedges_end(); - hit!=hit_end; ++hit ) + for(Surface_mesh::Halfedge_iterator hit=surface_mesh.halfedges_begin(), + hit_end=surface_mesh.halfedges_end(); + hit!=hit_end; ++hit) { - if ( hit->is_border() ){ - constrained_edges[hit]=std::make_pair( hit->opposite()->vertex()->point(), - hit->vertex()->point() ); + if(hit->is_border()) + { + constrained_edges[hit] = std::make_pair(hit->opposite()->vertex()->point(), + hit->vertex()->point()); ++nb_border_edges; } } // Contract the surface mesh as much as possible SMS::Count_stop_predicate stop(0); - Border_is_constrained_edge_map bem(surface_mesh); - // This the actual call to the simplification algorithm. // The surface mesh and stop conditions are mandatory arguments. // The index maps are needed because the vertices and edges // of this surface mesh lack an "id()" field. - int r = SMS::edge_collapse - (surface_mesh - ,stop - ,CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index,surface_mesh)) - .halfedge_index_map (get(CGAL::halfedge_external_index ,surface_mesh)) - .edge_is_constrained_map(bem) - .get_placement(Placement(bem)) - ); + int r = SMS::edge_collapse(surface_mesh, + stop, + CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index,surface_mesh)) + .halfedge_index_map(get(CGAL::halfedge_external_index ,surface_mesh)) + .edge_is_constrained_map(bem) + .get_placement(Placement(bem))); std::cout << "\nFinished...\n" << r << " edges removed.\n" - << (surface_mesh.size_of_halfedges()/2) << " final edges.\n" ; + << (surface_mesh.size_of_halfedges()/2) << " final edges.\n"; - std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; - os.precision(17) ; - os << surface_mesh ; + std::ofstream os(argc > 2 ? argv[2] : "out.off"); + os.precision(17); + os << surface_mesh; // now check! - for (Surface_mesh::Halfedge_iterator hit=surface_mesh.halfedges_begin(), + for(Surface_mesh::Halfedge_iterator hit=surface_mesh.halfedges_begin(), hit_end=surface_mesh.halfedges_end(); - hit!=hit_end; ++hit ) + hit!=hit_end; ++hit) { - if (hit->is_border()){ + if(hit->is_border()) + { --nb_border_edges; - assert( constrained_edges[hit] == - std::make_pair( hit->opposite()->vertex()->point(), - hit->vertex()->point() ) ); + assert(constrained_edges[hit] == std::make_pair(hit->opposite()->vertex()->point(), + hit->vertex()->point())); } } - assert( nb_border_edges==0 ); - return EXIT_SUCCESS ; + assert(nb_border_edges==0); + + return EXIT_SUCCESS; } diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_surface_mesh.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_surface_mesh.cpp index af3840f2fb9..44e33b8c3b6 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_surface_mesh.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_constrained_border_surface_mesh.cpp @@ -1,6 +1,3 @@ -#include -#include - #include #include @@ -16,57 +13,58 @@ // Stop-condition policy #include -typedef CGAL::Simple_cartesian Kernel; -typedef Kernel::Point_3 Point_3; +#include +#include -typedef CGAL::Surface_mesh Surface_mesh; -typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; -typedef boost::graph_traits::edge_descriptor edge_descriptor; +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; + +typedef CGAL::Surface_mesh Surface_mesh; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; namespace SMS = CGAL::Surface_mesh_simplification; -// // BGL property map which indicates whether an edge is marked as non-removable -// -struct Border_is_constrained_edge_map{ +struct Border_is_constrained_edge_map +{ const Surface_mesh* sm_ptr; typedef edge_descriptor key_type; typedef bool value_type; typedef value_type reference; typedef boost::readable_property_map_tag category; - Border_is_constrained_edge_map(const Surface_mesh& sm) - : sm_ptr(&sm) - {} + Border_is_constrained_edge_map(const Surface_mesh& sm) : sm_ptr(&sm) {} friend bool get(Border_is_constrained_edge_map m, const key_type& edge) { - return CGAL::is_border(edge, *m.sm_ptr); + return CGAL::is_border(edge, *m.sm_ptr); } }; -// // Placement class -// typedef SMS::Constrained_placement, Border_is_constrained_edge_map > Placement; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; - if (argc!=2){ + if(argc!=2) + { std::cerr << "Usage: " << argv[0] << " input.off\n"; return EXIT_FAILURE; } std::ifstream is(argv[1]); - if(!is){ + if(!is) + { std::cerr << "Filename provided is invalid\n"; return EXIT_FAILURE; } - is >> surface_mesh ; - if (!CGAL::is_triangle_mesh(surface_mesh)){ + is >> surface_mesh; + if(!CGAL::is_triangle_mesh(surface_mesh)) + { std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -76,47 +74,48 @@ int main( int argc, char** argv ) constrained_halfedges = surface_mesh.add_property_map >("h:vertices").first; std::size_t nb_border_edges=0; - for(halfedge_descriptor hd : halfedges(surface_mesh)){ - if(CGAL::is_border(hd,surface_mesh)){ - constrained_halfedges[hd] = std::make_pair(surface_mesh.point(source(hd,surface_mesh)), - surface_mesh.point(target(hd,surface_mesh))); + for(halfedge_descriptor hd : halfedges(surface_mesh)) + { + if(CGAL::is_border(hd, surface_mesh)) + { + constrained_halfedges[hd] = std::make_pair(surface_mesh.point(source(hd, surface_mesh)), + surface_mesh.point(target(hd, surface_mesh))); ++nb_border_edges; } } // Contract the surface mesh as much as possible SMS::Count_stop_predicate stop(0); - Border_is_constrained_edge_map bem(surface_mesh); - + // This the actual call to the simplification algorithm. // The surface mesh and stop conditions are mandatory arguments. - int r = SMS::edge_collapse - (surface_mesh - ,stop - ,CGAL::parameters::edge_is_constrained_map(bem) - .get_placement(Placement(bem)) - ); + int r = SMS::edge_collapse(surface_mesh, + stop, + CGAL::parameters::edge_is_constrained_map(bem) + .get_placement(Placement(bem))); std::cout << "\nFinished...\n" << r << " edges removed.\n" << surface_mesh.number_of_edges() << " final edges.\n"; - std::ofstream os( argc > 2 ? argv[2] : "out.off" ); + std::ofstream os(argc > 2 ? argv[2] : "out.off"); os.precision(17); os << surface_mesh; // now check! - for(halfedge_descriptor hd : halfedges(surface_mesh)){ - if(CGAL::is_border(hd,surface_mesh)){ + for(halfedge_descriptor hd : halfedges(surface_mesh)) + { + if(CGAL::is_border(hd,surface_mesh)) + { --nb_border_edges; - if(constrained_halfedges[hd] != std::make_pair(surface_mesh.point(source(hd,surface_mesh)), - surface_mesh.point(target(hd,surface_mesh)))){ + if(constrained_halfedges[hd] != std::make_pair(surface_mesh.point(source(hd, surface_mesh)), + surface_mesh.point(target(hd, surface_mesh)))) + { std::cerr << "oops. send us a bug report\n"; } - } } - assert( nb_border_edges==0 ); + assert(nb_border_edges==0); return EXIT_SUCCESS; } diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_enriched_polyhedron.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_enriched_polyhedron.cpp index 8c17b66706e..3d7ec912846 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_enriched_polyhedron.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_enriched_polyhedron.cpp @@ -22,13 +22,13 @@ typedef boost::graph_traits::vertex_descriptor vertex_descriptor; namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; std::ifstream is(argv[1]); is >> surface_mesh; - if (!CGAL::is_triangle_mesh(surface_mesh)){ + if(!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -64,7 +64,7 @@ int main( int argc, char** argv ) std::cout << "\nFinished...\n" << r << " edges removed.\n" << (surface_mesh.size_of_halfedges()/2) << " final edges.\n"; - std::ofstream os( argc > 2 ? argv[2] : "out.off" ); + std::ofstream os(argc > 2 ? argv[2] : "out.off"); os.precision(17); os << surface_mesh; diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_linear_cell_complex.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_linear_cell_complex.cpp index bd3215f4b08..5e58e5ef4b2 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_linear_cell_complex.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_linear_cell_complex.cpp @@ -12,11 +12,11 @@ typedef CGAL::Simple_cartesian Kernel; typedef CGAL::Linear_cell_complex_traits<3, Kernel> MyTraits; typedef CGAL::Linear_cell_complex_for_bgl_combinatorial_map_helper <2, 3, MyTraits>::type LCC; -namespace SMS = CGAL::Surface_mesh_simplification ; +namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { - if (argc<2 || argc>3) + if(argc<2 || argc>3) { std::cout<<"Usage: simplification_Linear_cell_complex inofffile [outofffile]"<()) .get_placement(SMS::Midpoint_placement()) - ); + ); std::cout << "\nFinished...\n" << r << " edges removed.\n" - << (lcc.number_of_darts()/2) << " final edges.\n" ; + << (lcc.number_of_darts()/2) << " final edges.\n"; lcc.display_characteristics(std::cout)<<", is_valid="< Surface_mesh; namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; std::ifstream is(argv[1]); is >> surface_mesh; - if (!CGAL::is_triangle_mesh(surface_mesh)){ + if(!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -41,12 +41,12 @@ int main( int argc, char** argv ) ,stop ,CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, surface_mesh)) .halfedge_index_map (get(CGAL::halfedge_external_index, surface_mesh)) - ); + ); std::cout << "\nFinished...\n" << r << " edges removed.\n" << (surface_mesh.size_of_halfedges()/2) << " final edges.\n"; - std::ofstream os( argc > 2 ? argv[2] : "out.off" ); + std::ofstream os(argc > 2 ? argv[2] : "out.off"); os.precision(17); os << surface_mesh; diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_surface_mesh.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_surface_mesh.cpp index 7fa2a9edf42..ee73a164b20 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_surface_mesh.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_surface_mesh.cpp @@ -13,13 +13,13 @@ typedef CGAL::Surface_mesh Surface_mesh; namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; std::ifstream is(argv[1]); is >> surface_mesh; - if (!CGAL::is_triangle_mesh(surface_mesh)){ + if(!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -33,7 +33,7 @@ int main( int argc, char** argv ) std::cout << "\nFinished...\n" << r << " edges removed.\n" << surface_mesh.number_of_edges() << " final edges.\n"; - std::ofstream os( argc > 2 ? argv[2] : "out.off" ); + std::ofstream os(argc > 2 ? argv[2] : "out.off"); os.precision(17); os << surface_mesh; diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_visitor_surface_mesh.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_visitor_surface_mesh.cpp index 9688a107e6d..006c8a69dba 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_visitor_surface_mesh.cpp +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/edge_collapse_visitor_surface_mesh.cpp @@ -45,16 +45,16 @@ struct Stats std::size_t processed; std::size_t collapsed; std::size_t non_collapsable; - std::size_t cost_uncomputable ; + std::size_t cost_uncomputable; std::size_t placement_uncomputable; }; struct My_visitor : SMS::Edge_collapse_visitor_base { - My_visitor( Stats* s) : stats(s){} + My_visitor(Stats* s) : stats(s){} // Called during the collecting phase for each edge collected. - void OnCollected( Profile const&, boost::optional const& ) + void OnCollected(Profile const&, boost::optional const&) { ++ stats->collected; std::cerr << "\rEdges collected: " << stats->collected << std::flush; @@ -62,41 +62,41 @@ struct My_visitor : SMS::Edge_collapse_visitor_base // Called during the processing phase for each edge selected. // If cost is absent the edge won't be collapsed. - void OnSelected(Profile const& + void OnSelected(const Profile& ,boost::optional cost ,std::size_t initial ,std::size_t current - ) + ) { ++ stats->processed; - if ( !cost ) + if(!cost) ++ stats->cost_uncomputable; - if ( current == initial ) + if(current == initial) std::cerr << "\n" << std::flush; std::cerr << "\r" << current << std::flush; } // Called during the processing phase for each edge being collapsed. // If placement is absent the edge is left uncollapsed. - void OnCollapsing(Profile const& + void OnCollapsing(const Profile& ,boost::optional placement - ) + ) { - if ( !placement ) + if(!placement) ++ stats->placement_uncomputable; } // Called for each edge which failed the so called link-condition, // that is, which cannot be collapsed because doing so would // turn the surface mesh into a non-manifold. - void OnNonCollapsable( Profile const& ) + void OnNonCollapsable(Profile const&) { ++ stats->non_collapsable; } // Called after each edge has been collapsed - void OnCollapsed( Profile const&, vertex_descriptor ) + void OnCollapsed(Profile const&, vertex_descriptor) { ++ stats->collapsed; } @@ -105,13 +105,13 @@ struct My_visitor : SMS::Edge_collapse_visitor_base }; -int main( int argc, char** argv ) +int main(int argc, char** argv) { Surface_mesh surface_mesh; std::ifstream is(argv[1]); is >> surface_mesh; - if (!CGAL::is_triangle_mesh(surface_mesh)){ + if(!CGAL::is_triangle_mesh(surface_mesh)){ std::cerr << "Input geometry is not triangulated." << std::endl; return EXIT_FAILURE; } @@ -133,7 +133,7 @@ int main( int argc, char** argv ) (surface_mesh ,stop ,CGAL::parameters::visitor(vis) - ); + ); std::cout << "\nEdges collected: " << stats.collected << "\nEdges proccessed: " << stats.processed @@ -147,7 +147,7 @@ int main( int argc, char** argv ) std::cout << "\nFinished...\n" << r << " edges removed.\n" << surface_mesh.number_of_edges() << " final edges.\n"; - std::ofstream os( argc > 2 ? argv[2] : "out.off" ); + std::ofstream os(argc > 2 ? argv[2] : "out.off"); os.precision(17); os << surface_mesh; diff --git a/Surface_mesh_simplification/include/CGAL/Cartesian/MatrixC33.h b/Surface_mesh_simplification/include/CGAL/Cartesian/MatrixC33.h index 7dda2ffc778..e626e6fe9b6 100644 --- a/Surface_mesh_simplification/include/CGAL/Cartesian/MatrixC33.h +++ b/Surface_mesh_simplification/include/CGAL/Cartesian/MatrixC33.h @@ -22,8 +22,6 @@ #include - -#include #include #include #include @@ -33,231 +31,217 @@ namespace CGAL { template -class MatrixC33 +class MatrixC33 { public: - - typedef R_ R ; - - typedef typename R::FT RT ; - typedef typename R::Vector_3 Vector_3; + typedef R_ R; - MatrixC33 ( Null_matrix ) - : - mR0(NULL_VECTOR) - ,mR1(NULL_VECTOR) - ,mR2(NULL_VECTOR) + typedef typename R::FT RT; + typedef typename R::Vector_3 Vector_3; + + MatrixC33(Null_matrix) + : mR0(NULL_VECTOR), + mR1(NULL_VECTOR), + mR2(NULL_VECTOR) {} - - MatrixC33 ( RT const& r0x, RT const& r0y, RT const& r0z - , RT const& r1x, RT const& r1y, RT const& r1z - , RT const& r2x, RT const& r2y, RT const& r2z - ) - : - mR0(r0x,r0y,r0z) - ,mR1(r1x,r1y,r1z) - ,mR2(r2x,r2y,r2z) + + MatrixC33(const RT& r0x, const RT& r0y, const RT& r0z, + const RT& r1x, const RT& r1y, const RT& r1z, + const RT& r2x, const RT& r2y, const RT& r2z) + : mR0(r0x,r0y,r0z), + mR1(r1x,r1y,r1z), + mR2(r2x,r2y,r2z) {} - - MatrixC33 ( Vector_3 const& r0, Vector_3 const& r1, Vector_3 const& r2 ) - : - mR0(r0) - ,mR1(r1) - ,mR2(r2) + + MatrixC33(const Vector_3& r0, const Vector_3& r1, const Vector_3& r2) + : mR0(r0), + mR1(r1), + mR2(r2) {} - - Vector_3 const& r0() const { return mR0; } - Vector_3 const& r1() const { return mR1; } - Vector_3 const& r2() const { return mR2; } - + + const Vector_3& r0() const { return mR0; } + const Vector_3& r1() const { return mR1; } + const Vector_3& r2() const { return mR2; } + Vector_3& r0() { return mR0; } Vector_3& r1() { return mR1; } Vector_3& r2() { return mR2; } - Vector_3 const& operator[] ( int row ) const { return row == 0 ? mR0 : ( row == 1 ? mR1 : mR2 ) ; } - Vector_3& operator[] ( int row ) { return row == 0 ? mR0 : ( row == 1 ? mR1 : mR2 ) ; } - - MatrixC33& operator+= ( MatrixC33 const& m ) + const Vector_3& operator[](int row) const { return row == 0 ? mR0 : (row == 1 ? mR1 : mR2); } + Vector_3& operator[](int row) { return row == 0 ? mR0 : (row == 1 ? mR1 : mR2); } + + MatrixC33& operator+=(const MatrixC33& m) { - mR0 = mR0 + m.r0() ; - mR1 = mR1 + m.r1() ; - mR2 = mR2 + m.r2() ; - return *this ; + mR0 = mR0 + m.r0(); + mR1 = mR1 + m.r1(); + mR2 = mR2 + m.r2(); + return *this; } - - MatrixC33& operator-= ( MatrixC33 const& m ) + + MatrixC33& operator-=(const MatrixC33& m) { - mR0 = mR0 - m.r0() ; - mR1 = mR1 - m.r1() ; - mR2 = mR2 - m.r2() ; - return *this ; + mR0 = mR0 - m.r0(); + mR1 = mR1 - m.r1(); + mR2 = mR2 - m.r2(); + return *this; } - - MatrixC33& operator*= ( RT const& c ) + + MatrixC33& operator*=(const RT& c) { - mR0 = mR0 * c ; - mR1 = mR1 * c ; - mR2 = mR2 * c ; - return *this ; + mR0 = mR0 * c; + mR1 = mR1 * c; + mR2 = mR2 * c; + return *this; } - - MatrixC33& operator/= ( RT const& c ) + + MatrixC33& operator/=(const RT& c) { - mR0 = mR0 / c ; - mR1 = mR1 / c ; - mR2 = mR2 / c ; - return *this ; + mR0 = mR0 / c; + mR1 = mR1 / c; + mR2 = mR2 / c; + return *this; } - - friend MatrixC33 operator+ ( MatrixC33 const& a, MatrixC33 const& b ) + + friend MatrixC33 operator+(const MatrixC33& a, const MatrixC33& b) { - return MatrixC33(a.r0()+b.r0() - ,a.r1()+b.r1() - ,a.r2()+b.r2() - ); + return MatrixC33(a.r0() + b.r0(), + a.r1() + b.r1(), + a.r2() + b.r2()); } - - friend MatrixC33 operator- ( MatrixC33 const& a, MatrixC33 const& b ) + + friend MatrixC33 operator-(const MatrixC33& a, const MatrixC33& b) { - return MatrixC33(a.r0()-b.r0() - ,a.r1()-b.r1() - ,a.r2()-b.r2() - ); + return MatrixC33(a.r0() - b.r0(), + a.r1() - b.r1(), + a.r2() - b.r2()); } - - friend MatrixC33 operator* ( MatrixC33 const& m, RT const& c ) + + friend MatrixC33 operator*(const MatrixC33& m, const RT& c) { - return MatrixC33(m.r0()*c,m.r1()*c,m.r2()*c); + return MatrixC33(m.r0()*c, m.r1()*c, m.r2()*c); } - friend MatrixC33 operator* ( RT const& c, MatrixC33 const& m ) + friend MatrixC33 operator*(const RT& c, const MatrixC33& m) { - return MatrixC33(m.r0()*c,m.r1()*c,m.r2()*c); + return MatrixC33(m.r0()*c, m.r1()*c, m.r2()*c); } - - friend MatrixC33 operator/ ( MatrixC33 const& m, RT const& c ) + + friend MatrixC33 operator/(const MatrixC33& m, const RT& c) { - return MatrixC33(m.r0()/c,m.r1()/c,m.r2()/c); + return MatrixC33(m.r0()/c, m.r1()/c, m.r2()/c); } - - friend Vector_3 operator* ( MatrixC33 const& m, Vector_3 const& v ) + + friend Vector_3 operator*(const MatrixC33& m, const Vector_3& v) { - return Vector_3(m.r0()*v,m.r1()*v,m.r2()*v); + return Vector_3(m.r0()*v, m.r1()*v, m.r2()*v); } - friend Vector_3 operator* ( Vector_3 const& v, MatrixC33 const& m ) + friend Vector_3 operator*(const Vector_3& v, const MatrixC33& m) { - return Vector_3(v*m.r0(),v*m.r1(),v*m.r2()); + return Vector_3(v*m.r0(), v*m.r1(), v*m.r2()); } - + RT determinant() const { - return CGAL::determinant(r0().x(),r0().y(),r0().z() - ,r1().x(),r1().y(),r1().z() - ,r2().x(),r2().y(),r2().z() - ); + return CGAL::determinant(r0().x(), r0().y(), r0().z(), + r1().x(), r1().y(), r1().z(), + r2().x(), r2().y(), r2().z()); } - + MatrixC33& transpose() { mR0 = Vector_3(r0().x(),r1().x(),r2().x()); - mR1 = Vector_3(r0().y(),r1().y(),r2().y()); + mR1 = Vector_3(r0().y(),r1().y(),r2().y()); mR2 = Vector_3(r0().z(),r1().z(),r2().z()); - return *this ; + return *this; } - + private: - Vector_3 mR0 ; - Vector_3 mR1 ; - Vector_3 mR2 ; -} ; + Vector_3 mR0; + Vector_3 mR1; + Vector_3 mR2; +}; template inline -MatrixC33 direct_product ( Vector_3 const& u, Vector_3 const& v ) +MatrixC33 direct_product(Vector_3 const& u, Vector_3 const& v) { - return MatrixC33( v * u.x() - , v * u.y() - , v * u.z() - ) ; + return MatrixC33(v * u.x(), + v * u.y(), + v * u.z()); } template -MatrixC33 transposed_matrix ( MatrixC33 const& m ) +MatrixC33 transposed_matrix(const MatrixC33& m) { - MatrixC33 copy = m ; + MatrixC33 copy = m; copy.Transpose(); - return copy ; + return copy; } template -MatrixC33 cofactors_matrix ( MatrixC33 const& m ) +MatrixC33 cofactors_matrix(const MatrixC33& m) { - typedef typename R::RT RT ; - + typedef typename R::RT RT; + RT c00 = determinant(m.r1().y(),m.r1().z(),m.r2().y(),m.r2().z()); RT c01 = -determinant(m.r1().x(),m.r1().z(),m.r2().x(),m.r2().z()); RT c02 = determinant(m.r1().x(),m.r1().y(),m.r2().x(),m.r2().y()); - + RT c10 = -determinant(m.r0().y(),m.r0().z(),m.r2().y(),m.r2().z()); RT c11 = determinant(m.r0().x(),m.r0().z(),m.r2().x(),m.r2().z()); RT c12 = -determinant(m.r0().x(),m.r0().y(),m.r2().x(),m.r2().y()); - + RT c20 = determinant(m.r0().y(),m.r0().z(),m.r1().y(),m.r1().z()); RT c21 = -determinant(m.r0().x(),m.r0().z(),m.r1().x(),m.r1().z()); RT c22 = determinant(m.r0().x(),m.r0().y(),m.r1().x(),m.r1().y()); - - return MatrixC33(c00,c01,c02 - ,c10,c11,c12 - ,c20,c21,c22 - ); + + return MatrixC33(c00,c01,c02, + c10,c11,c12, + c20,c21,c22); } template -MatrixC33 adjoint_matrix ( MatrixC33 const& m ) +MatrixC33 adjoint_matrix(const MatrixC33& m) { - return cofactors_matrix(m).transpose() ; + return cofactors_matrix(m).transpose(); } template -boost::optional< MatrixC33 > inverse_matrix ( MatrixC33 const& m ) +boost::optional< MatrixC33 > inverse_matrix(const MatrixC33& m) { - typedef typename R::RT RT ; - - typedef MatrixC33 Matrix ; - - typedef boost::optional result_type ; - - result_type rInverse ; - + typedef typename R::RT RT; + typedef MatrixC33 Matrix; + typedef boost::optional result_type; + + result_type rInverse; + RT det = m.determinant(); - - if ( ! CGAL_NTS is_zero(det) ) + + if(! CGAL_NTS is_zero(det)) { - RT c00 = (m.r1().y()*m.r2().z() - m.r1().z()*m.r2().y()) / det; + RT c00 = (m.r1().y()*m.r2().z() - m.r1().z()*m.r2().y()) / det; RT c01 = (m.r2().y()*m.r0().z() - m.r0().y()*m.r2().z()) / det; - RT c02 = (m.r0().y()*m.r1().z() - m.r1().y()*m.r0().z()) / det; - - RT c10 = (m.r1().z()*m.r2().x() - m.r1().x()*m.r2().z()) / det; - RT c11 = (m.r0().x()*m.r2().z() - m.r2().x()*m.r0().z()) / det; - RT c12 = (m.r1().x()*m.r0().z() - m.r0().x()*m.r1().z()) / det; - - RT c20 = (m.r1().x()*m.r2().y() - m.r2().x()*m.r1().y()) / det; - RT c21 = (m.r2().x()*m.r0().y() - m.r0().x()*m.r2().y()) / det; - RT c22 = (m.r0().x()*m.r1().y() - m.r0().y()*m.r1().x()) / det; - - rInverse = result_type( Matrix(c00,c01,c02 - ,c10,c11,c12 - ,c20,c21,c22 - ) - ) ; + RT c02 = (m.r0().y()*m.r1().z() - m.r1().y()*m.r0().z()) / det; + + RT c10 = (m.r1().z()*m.r2().x() - m.r1().x()*m.r2().z()) / det; + RT c11 = (m.r0().x()*m.r2().z() - m.r2().x()*m.r0().z()) / det; + RT c12 = (m.r1().x()*m.r0().z() - m.r0().x()*m.r1().z()) / det; + + RT c20 = (m.r1().x()*m.r2().y() - m.r2().x()*m.r1().y()) / det; + RT c21 = (m.r2().x()*m.r0().y() - m.r0().x()*m.r2().y()) / det; + RT c22 = (m.r0().x()*m.r1().y() - m.r0().y()*m.r1().x()) / det; + + rInverse = result_type(Matrix(c00,c01,c02, + c10,c11,c12, + c20,c21,c22)); } - - return rInverse ; + + return rInverse; } } //namespace CGAL #endif // CGAL_CARTESIAN_MATRIXC33_H // // EOF // - - + + diff --git a/Surface_mesh_simplification/include/CGAL/Null_matrix.h b/Surface_mesh_simplification/include/CGAL/Null_matrix.h index 974f212bffe..5a11d04a897 100644 --- a/Surface_mesh_simplification/include/CGAL/Null_matrix.h +++ b/Surface_mesh_simplification/include/CGAL/Null_matrix.h @@ -22,19 +22,12 @@ #include - namespace CGAL { class Null_matrix {}; -static const Null_matrix NULL_MATRIX = Null_matrix() ; +static const Null_matrix NULL_MATRIX = Null_matrix(); } //namespace CGAL -#endif // CGAL_NULL_MATRIX_H // - -// EOF // - - - - +#endif // CGAL_NULL_MATRIX_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h index ff25c26f38a..b80589a8dcf 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Common.h @@ -18,16 +18,15 @@ // Author(s) : Fernando Cacciola // #ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_COMMON_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_COMMON_H 1 +#define CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_COMMON_H #include - -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include @@ -42,144 +41,130 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace CGAL { +namespace Surface_mesh_simplification { -namespace Surface_mesh_simplification -{ +using boost::num_edges; +using boost::num_vertices; +using boost::edges; +using boost::out_edges; +using boost::in_edges; +using boost::source; +using boost::target; -using boost::num_edges ; -using boost::num_vertices ; -using boost::edges ; -using boost::out_edges ; -using boost::in_edges ; -using boost::source ; -using boost::target ; +using boost::shared_ptr; +using boost::optional; +using boost::none; +using boost::put_get_helper; +using boost::get; +using boost::put; +using boost::addressof; -using boost::shared_ptr ; -using boost::optional ; -using boost::none ; -using boost::put_get_helper ; -using boost::get ; -using boost::put ; -using boost::addressof ; - -using namespace boost::tuples ; +using namespace boost::tuples; template -inline bool handle_assigned( Handle h ) { Handle null ; return h != null ; } +inline bool handle_assigned(Handle h) { Handle null; return h != null; } template -bool handle_exists ( Iterator begin, Iterator end, Handle h ) +bool handle_exists(Iterator begin, Iterator end, Handle h) { - if ( handle_assigned(h) ) - { - while ( begin != end ) - if ( begin++ == h ) - return true ; - } - return false ; + if(handle_assigned(h)) + { + while(begin != end) + if(begin++ == h) + return true; + } + + return false; } template -struct No_constrained_edge_map{ - typedef typename boost::graph_traits::edge_descriptor key_type; - typedef bool value_type; - typedef value_type reference; - typedef boost::readable_property_map_tag category; - friend bool get(No_constrained_edge_map, key_type) { - return false; - } +struct No_constrained_edge_map +{ + typedef typename boost::graph_traits::edge_descriptor key_type; + typedef bool value_type; + typedef value_type reference; + typedef boost::readable_property_map_tag category; + friend bool get(No_constrained_edge_map, key_type) { return false; } }; } // namespace Surface_mesh_simplification template -inline std::string n_to_string( N const& n ) -{ - return boost::str( boost::format("%|5.19g|") % n ) ; +inline std::string n_to_string(const N& n) { + return boost::str(boost::format("%|5.19g|") % n); } template -inline std::string xyz_to_string( XYZ const& xyz ) -{ - return boost::str( boost::format("(%|5.19g|,%|5.19g|,%|5.19g|)") % xyz.x() % xyz.y() % xyz.z() ) ; +inline std::string xyz_to_string(const XYZ& xyz) { + return boost::str(boost::format("(%|5.19g|,%|5.19g|,%|5.19g|)") % xyz.x() % xyz.y() % xyz.z()); } template -inline std::string matrix_to_string( Matrix const& m ) -{ - return boost::str( boost::format("[%1%|%2%|%3%]") % xyz_to_string(m.r0()) % xyz_to_string(m.r1()) % xyz_to_string(m.r2()) ) ; +inline std::string matrix_to_string(const Matrix& m) { + return boost::str(boost::format("[%1%|%2%|%3%]") % xyz_to_string(m.r0()) % xyz_to_string(m.r1()) % xyz_to_string(m.r2())); } template -inline std::string optional_to_string( boost::optional const& o ) -{ - if ( o ) - return boost::str( boost::format("%1%") % *o ) ; - else return std::string("NONE"); +inline std::string optional_to_string(const boost::optional& o) { + if(o) + return boost::str(boost::format("%1%") % *o); + else return std::string("NONE"); } +} // namespace CGAL -} //namespace CGAL - -#if defined(CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE) \ - || defined(CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE) +#if defined(CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE) \ + || defined(CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE) #define CGAL_SMS_ENABLE_TRACE #endif #ifdef CGAL_SMS_ENABLE_TRACE + #include + #include + #include -# include -# include -# include -namespace internal { namespace { bool cgal_enable_sms_trace = true ; } } -# define CGAL_SMS_TRACE_IMPL(m) \ - if ( ::internal::cgal_enable_sms_trace ) { \ - std::ostringstream ss ; ss << m ; std::string s = ss.str(); \ - /*Surface_simplification_external_trace(s)*/ std::cerr << s << std::endl; \ - } - -# define CGAL_SMS_DEBUG_CODE(code) code + namespace internal { namespace { bool cgal_enable_sms_trace = true; } } + #define CGAL_SMS_TRACE_IMPL(m) \ + if(::internal::cgal_enable_sms_trace) { \ + std::ostringstream ss; ss << m; std::string s = ss.str(); \ + /*Surface_simplification_external_trace(s)*/ std::cerr << s << std::endl; \ + } + #define CGAL_SMS_DEBUG_CODE(code) code #else - -# define CGAL_SMS_DEBUG_CODE(code) - + #define CGAL_SMS_DEBUG_CODE(code) #endif #ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE -# define CGAL_SMS_LT_TRACE(l,m) if ( (l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE ) CGAL_SMS_TRACE_IMPL(m) + #define CGAL_SMS_LT_TRACE(l,m) if((l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE) CGAL_SMS_TRACE_IMPL(m) #else -# define CGAL_SMS_LT_TRACE(l,m) + #define CGAL_SMS_LT_TRACE(l,m) #endif #ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE -# define CGAL_SMS_TRACE_IF(c,l,m) if ( (c) && ( (l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE) ) CGAL_SMS_TRACE_IMPL(m) -# define CGAL_SMS_TRACE(l,m) if ( (l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE ) CGAL_SMS_TRACE_IMPL(m) + #define CGAL_SMS_TRACE_IF(c,l,m) if((c) && ((l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE)) CGAL_SMS_TRACE_IMPL(m) + #define CGAL_SMS_TRACE(l,m) if((l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE) CGAL_SMS_TRACE_IMPL(m) #else -# define CGAL_SMS_TRACE_IF(c,l,m) -# define CGAL_SMS_TRACE(l,m) + #define CGAL_SMS_TRACE_IF(c,l,m) + #define CGAL_SMS_TRACE(l,m) #endif - #undef CGAL_SMS_ENABLE_TRACE #ifdef CGAL_TESTING_SURFACE_MESH_SIMPLIFICATION -# define CGAL_SURF_SIMPL_TEST_assertion(EX) CGAL_assertion(EX) -# define CGAL_SURF_SIMPL_TEST_assertion_msg(EX,MSG) CGAL_assertion_msg(EX,MSG) -# define CGAL_SURF_SIMPL_TEST_assertion_code(CODE) CGAL_assertion_code(CODE) + #define CGAL_SURF_SIMPL_TEST_assertion(EX) CGAL_assertion(EX) + #define CGAL_SURF_SIMPL_TEST_assertion_msg(EX,MSG) CGAL_assertion_msg(EX,MSG) + #define CGAL_SURF_SIMPL_TEST_assertion_code(CODE) CGAL_assertion_code(CODE) #else -# define CGAL_SURF_SIMPL_TEST_assertion(EX) -# define CGAL_SURF_SIMPL_TEST_assertion_msg(EX,MSG) -# define CGAL_SURF_SIMPL_TEST_assertion_code(CODE) + #define CGAL_SURF_SIMPL_TEST_assertion(EX) + #define CGAL_SURF_SIMPL_TEST_assertion_msg(EX,MSG) + #define CGAL_SURF_SIMPL_TEST_assertion_code(CODE) #endif - #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_COMMON_H // -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h index 2eeea15d937..bba95241917 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse.h @@ -27,384 +27,1245 @@ #include #include #include + namespace CGAL { +namespace Surface_mesh_simplification { -namespace Surface_mesh_simplification -{ - -// // Implementation of the vertex-pair collapse triangulated surface mesh simplification algorithm -// -template +template class EdgeCollapse { public: + typedef TM_ TM; + typedef ShouldStop_ ShouldStop; + typedef VertexIndexMap_ VertexIndexMap; + typedef VertexPointMap_ VertexPointMap; + typedef EdgeIndexMap_ EdgeIndexMap; + typedef EdgeIsConstrainedMap_ EdgeIsConstrainedMap; + typedef GetCost_ GetCost; + typedef GetPlacement_ GetPlacement; + typedef VisitorT_ VisitorT; - typedef TM_ TM ; - typedef ShouldStop_ ShouldStop ; - typedef VertexIndexMap_ VertexIndexMap ; - typedef VertexPointMap_ VertexPointMap ; - typedef EdgeIndexMap_ EdgeIndexMap ; - typedef EdgeIsConstrainedMap_ EdgeIsConstrainedMap; - typedef GetCost_ GetCost ; - typedef GetPlacement_ GetPlacement ; - typedef VisitorT_ VisitorT ; - - typedef EdgeCollapse Self ; - - typedef Edge_profile Profile ; - - typedef boost::graph_traits GraphTraits ; - typedef boost::graph_traits ConstGraphTraits ; - - typedef typename GraphTraits::vertex_descriptor vertex_descriptor ; - typedef typename GraphTraits::vertex_iterator vertex_iterator ; - typedef typename GraphTraits::halfedge_descriptor halfedge_descriptor ; - typedef typename GraphTraits::halfedge_iterator halfedge_iterator ; - typedef CGAL::Halfedge_around_source_iterator out_edge_iterator ; - typedef CGAL::Halfedge_around_target_iterator in_edge_iterator ; - typedef typename GraphTraits::traversal_category traversal_category ; - typedef typename GraphTraits::edges_size_type size_type ; - - typedef typename GraphTraits::edge_iterator edge_iterator ; - typedef VertexPointMap Vertex_point_pmap; - typedef typename boost::property_traits::value_type Point; - typedef typename Kernel_traits::Kernel Traits; - - typedef typename Traits::Equal_3 Equal_3 ; - - typedef typename Traits::Vector_3 Vector ; - typedef typename Traits::FT FT ; + typedef EdgeCollapse Self; - typedef optional Cost_type ; - typedef optional Placement_type ; + typedef Edge_profile Profile; + + typedef boost::graph_traits GraphTraits; + typedef boost::graph_traits ConstGraphTraits; + + typedef typename GraphTraits::vertex_descriptor vertex_descriptor; + typedef typename GraphTraits::vertex_iterator vertex_iterator; + typedef typename GraphTraits::halfedge_descriptor halfedge_descriptor; + typedef typename GraphTraits::halfedge_iterator halfedge_iterator; + typedef CGAL::Halfedge_around_source_iterator out_edge_iterator; + typedef CGAL::Halfedge_around_target_iterator in_edge_iterator; + typedef typename GraphTraits::traversal_category traversal_category; + typedef typename GraphTraits::edges_size_type size_type; + + typedef typename GraphTraits::edge_iterator edge_iterator; + typedef VertexPointMap Vertex_point_pmap; + typedef typename boost::property_traits::value_type Point; + typedef typename Kernel_traits::Kernel Traits; + + typedef typename Traits::Equal_3 Equal_3; + + typedef typename Traits::Vector_3 Vector; + typedef typename Traits::FT FT; + + typedef optional Cost_type; + typedef optional Placement_type; struct Compare_id { Compare_id() : mAlgorithm(0) {} - - Compare_id( Self const* aAlgorithm ) : mAlgorithm(aAlgorithm) {} - - bool operator() ( halfedge_descriptor const& a, halfedge_descriptor const& b ) const - { + Compare_id(const Self* aAlgorithm) : mAlgorithm(aAlgorithm) {} + + bool operator()(const halfedge_descriptor& a, const halfedge_descriptor& b) const { return mAlgorithm->get_halfedge_id(a) < mAlgorithm->get_halfedge_id(b); } - - Self const* mAlgorithm ; - } ; - + + Self const* mAlgorithm; + }; + struct Compare_cost { Compare_cost() : mAlgorithm(0) {} - - Compare_cost( Self const* aAlgorithm ) : mAlgorithm(aAlgorithm) {} - - bool operator() ( halfedge_descriptor const& a, halfedge_descriptor const& b ) const - { + Compare_cost(const Self* aAlgorithm) : mAlgorithm(aAlgorithm) {} + + bool operator()(const halfedge_descriptor& a, const halfedge_descriptor& b) const + { // NOTE: A cost is an optional<> value. // Absent optionals are ordered first; that is, "none < T" and "T > none" for any defined T != none. // In consequence, edges with undefined costs will be promoted to the top of the priority queue and poped out first. return mAlgorithm->get_data(a).cost() < mAlgorithm->get_data(b).cost(); } - - Self const* mAlgorithm ; - } ; - - struct edge_id : boost::put_get_helper + + Self const* mAlgorithm; + }; + + struct edge_id + : boost::put_get_helper { typedef boost::readable_property_map_tag category; typedef size_type value_type; typedef size_type reference; - typedef halfedge_descriptor key_type; - + typedef halfedge_descriptor key_type; + edge_id() : mAlgorithm(0) {} - - edge_id( Self const* aAlgorithm ) : mAlgorithm(aAlgorithm) {} - - size_type operator[] ( halfedge_descriptor const& e ) const { return mAlgorithm->get_edge_id(e); } - - Self const* mAlgorithm ; - } ; - - - typedef Modifiable_priority_queue PQ ; - typedef typename PQ::handle pq_handle ; - + edge_id(Self const* aAlgorithm) : mAlgorithm(aAlgorithm) {} + + size_type operator[] (const halfedge_descriptor e) const { return mAlgorithm->get_edge_id(e); } + + Self const* mAlgorithm; + }; + + typedef Modifiable_priority_queue PQ; + typedef typename PQ::handle pq_handle; + // An Edge_data is associated with EVERY _ edge in the mesh (collapsable or not). // It relates the edge with the PQ-handle needed to update the priority queue // It also relates the edge with a policy-based cache class Edge_data { public : - Edge_data() : mPQHandle() {} - - Cost_type const& cost() const { return mCost ; } - Cost_type & cost() { return mCost ; } - - pq_handle PQ_handle() const { return mPQHandle ;} - - bool is_in_PQ() const { return mPQHandle != PQ::null_handle() ; } - - void set_PQ_handle( pq_handle h ) { mPQHandle = h ; } - - void reset_PQ_handle() { mPQHandle = PQ::null_handle() ; } - - private: - - Cost_type mCost ; - pq_handle mPQHandle ; - } ; - typedef Edge_data* Edge_data_ptr ; - typedef boost::scoped_array Edge_data_array ; - - + + const Cost_type& cost() const { return mCost; } + Cost_type& cost() { return mCost; } + + pq_handle PQ_handle() const { return mPQHandle;} + bool is_in_PQ() const { return mPQHandle != PQ::null_handle(); } + void set_PQ_handle(pq_handle h) { mPQHandle = h; } + void reset_PQ_handle() { mPQHandle = PQ::null_handle(); } + + private: + Cost_type mCost; + pq_handle mPQHandle; + }; + + typedef Edge_data* Edge_data_ptr; + typedef boost::scoped_array Edge_data_array; + public: + EdgeCollapse(TM& aSurface, + const ShouldStop& aShouldStop, + const VertexIndexMap& aVertex_index_map, + const VertexPointMap& aVertex_point_map, + const EdgeIndexMap& aEdge_index_map, + const EdgeIsConstrainedMap& aEdge_is_constrained_map, + const GetCost& aGetCost, + const GetPlacement& aGetPlacement, + VisitorT aVisitor); - EdgeCollapse( TM& aSurface - , ShouldStop const& aShouldStop - , VertexIndexMap const& aVertex_index_map - , VertexPointMap const& aVertex_point_map - , EdgeIndexMap const& aEdge_index_map - , EdgeIsConstrainedMap const& aEdge_is_constrained_map - , GetCost const& aGetCost - , GetPlacement const& aGetPlacement - , VisitorT aVisitor - ) ; + int run(); - int run() ; - private: - - void Collect(); - void Loop(); - bool Is_collapse_topologically_valid( Profile const& aProfile ) ; - bool Is_tetrahedron( halfedge_descriptor const& h1 ) ; - bool Is_open_triangle( halfedge_descriptor const& h1 ) ; - bool Is_collapse_geometrically_valid( Profile const& aProfile, Placement_type aPlacement ) ; - void Collapse( Profile const& aProfile, Placement_type aPlacement ) ; - void Update_neighbors( vertex_descriptor const& aKeptV ) ; - - Profile create_profile ( halfedge_descriptor const& aEdge ) - { - return Profile(aEdge,mSurface,Vertex_index_map,Vertex_point_map,Edge_index_map, m_has_border); - } - - size_type get_halfedge_id ( halfedge_descriptor const& aEdge ) const { return Edge_index_map[aEdge]; } - size_type get_edge_id ( halfedge_descriptor const& aEdge ) const { return get_halfedge_id(aEdge) / 2 ; } + void collect(); + void loop(); + bool is_collapse_topologically_valid(const Profile& aProfile); + bool is_tetrahedron(const halfedge_descriptor h1); + bool is_open_triangle(const halfedge_descriptor h1); + bool is_collapse_geometrically_valid(const Profile& aProfile, Placement_type aPlacement); + void collapse(const Profile& aProfile, Placement_type aPlacement); + void update_neighbors(const vertex_descriptor aKeptV); - bool is_primary_edge ( halfedge_descriptor const& aEdge ) const { return ( get_halfedge_id(aEdge) % 2 ) == 0 ; } - - halfedge_descriptor primary_edge ( halfedge_descriptor const& aEdge ) - { - return is_primary_edge(aEdge) ? aEdge : opposite(aEdge,mSurface) ; - } - - bool is_border ( halfedge_descriptor const& aEdge ) const { return face(aEdge,mSurface) == boost::graph_traits::null_face() ; } - - bool is_constrained( halfedge_descriptor const& aEdge ) const { return get(Edge_is_constrained_map,edge(aEdge,mSurface)); } - bool is_constrained( vertex_descriptor const& aVertex ) const; + Profile create_profile(const halfedge_descriptor aEdge) { + return Profile(aEdge, mSurface, Vertex_index_map, Vertex_point_map, Edge_index_map, m_has_border); + } - bool is_border_or_constrained( halfedge_descriptor const& aEdge ) const { return is_border(aEdge) || is_constrained(aEdge); } + size_type get_halfedge_id(const halfedge_descriptor aEdge) const { return Edge_index_map[aEdge]; } + size_type get_edge_id (const halfedge_descriptor aEdge) const { return get_halfedge_id(aEdge) / 2; } - bool is_edge_a_border ( halfedge_descriptor const& aEdge ) const + bool is_primary_edge (const halfedge_descriptor aEdge) const { return (get_halfedge_id(aEdge) % 2) == 0; } + halfedge_descriptor primary_edge (const halfedge_descriptor aEdge) { + return is_primary_edge(aEdge) ? aEdge : opposite(aEdge, mSurface); + } + + bool is_border(const vertex_descriptor aV) const; + bool is_border (const halfedge_descriptor aEdge) const { + return face(aEdge, mSurface) == boost::graph_traits::null_face(); + } + + bool is_constrained(const vertex_descriptor aVertex) const; + bool is_constrained(const halfedge_descriptor aEdge) const { + return get(Edge_is_constrained_map, edge(aEdge, mSurface)); + } + + bool is_border_or_constrained(const vertex_descriptor aV) const; + bool is_border_or_constrained(const halfedge_descriptor aEdge) const { return is_border(aEdge) || is_constrained(aEdge); } + + bool is_edge_a_border (const halfedge_descriptor aEdge) const { - return is_border(aEdge) || is_border(opposite(aEdge,mSurface)) ; - } - - bool is_border ( vertex_descriptor const& aV ) const ; - - bool is_border_or_constrained ( vertex_descriptor const& aV ) const ; + return is_border(aEdge) || is_border(opposite(aEdge, mSurface)); + } - bool are_shared_triangles_valid( Point const& p0, Point const& p1, Point const& p2, Point const& p3 ) const ; - - halfedge_descriptor find_connection ( vertex_descriptor const& v0, vertex_descriptor const& v1 ) const ; - - vertex_descriptor find_exterior_link_triangle_3rd_vertex ( halfedge_descriptor const& e, vertex_descriptor const& v0, vertex_descriptor const& v1 ) const ; - - Edge_data& get_data ( halfedge_descriptor const& aEdge ) const - { - CGAL_assertion( is_primary_edge(aEdge) ) ; + bool are_shared_triangles_valid(const Point& p0, const Point& p1, const Point& p2, const Point& p3) const; + + halfedge_descriptor find_connection(const vertex_descriptor v0, const vertex_descriptor v1) const; + vertex_descriptor find_exterior_link_triangle_3rd_vertex(const halfedge_descriptor e, const vertex_descriptor v0, const vertex_descriptor v1) const; + + Edge_data& get_data(const halfedge_descriptor aEdge) const + { + CGAL_assertion(is_primary_edge(aEdge)); return mEdgeDataArray[get_edge_id(aEdge)]; } - + typename boost::property_traits::reference - get_point ( vertex_descriptor const& aV ) const + get_point(const vertex_descriptor aV) const { return get(Vertex_point_map, aV); } + + boost::tuple get_vertices(const halfedge_descriptor aEdge) const { - return get(Vertex_point_map,aV); - } - - boost::tuple get_vertices( halfedge_descriptor const& aEdge ) const - { - vertex_descriptor p,q ; - p = source(aEdge,mSurface); - q = target(aEdge,mSurface); + vertex_descriptor p, q; + p = source(aEdge, mSurface); + q = target(aEdge, mSurface); return boost::make_tuple(p,q); } - - boost::tuple get_vertices( halfedge_descriptor const& aEdge ) + + boost::tuple get_vertices(const halfedge_descriptor aEdge) { - vertex_descriptor p,q ; - p = source(aEdge,mSurface); - q = target(aEdge,mSurface); + vertex_descriptor p,q; + p = source(aEdge, mSurface); + q = target(aEdge, mSurface); return boost::make_tuple(p,q); } - - std::string vertex_to_string( vertex_descriptor const& v ) const + + std::string vertex_to_string(const vertex_descriptor v) const { - Point const& p = get_point(v); - return boost::str( boost::format("[V%1%:%2%]") % get(Vertex_index_map,v) % xyz_to_string(p) ) ; + const Point& p = get_point(v); + return boost::str(boost::format("[V%1%:%2%]") % get(Vertex_index_map,v) % xyz_to_string(p)); } - - std::string edge_to_string ( halfedge_descriptor const& aEdge ) const + + std::string edge_to_string (const halfedge_descriptor aEdge) const { - vertex_descriptor p,q ; boost::tie(p,q) = get_vertices(aEdge); - return boost::str( boost::format("{E%1% %2%->%3%}%4%") % get(Edge_index_map,aEdge) % vertex_to_string(p) % vertex_to_string(q) % ( is_border(aEdge) ? " (BORDER)" : ( is_border(opposite(aEdge,mSurface)) ? " (~BORDER)": "" ) ) ) ; + vertex_descriptor p,q; boost::tie(p,q) = get_vertices(aEdge); + return boost::str(boost::format("{E%1% %2%->%3%}%4%") % get(Edge_index_map, aEdge) % vertex_to_string(p) % vertex_to_string(q) % (is_border(aEdge) ? " (BORDER)" : (is_border(opposite(aEdge, mSurface)) ? " (~BORDER)": ""))); } - - Cost_type get_cost ( Profile const& aProfile ) const - { - return Get_cost(aProfile, get_placement(aProfile) ); + + Cost_type get_cost (const Profile& aProfile) const { + return Get_cost(aProfile, get_placement(aProfile)); } - - Placement_type get_placement( Profile const& aProfile ) const - { + + Placement_type get_placement(const Profile& aProfile) const { return Get_placement(aProfile); } - - void insert_in_PQ( halfedge_descriptor const& aEdge, Edge_data& aData ) + + void insert_in_PQ(const halfedge_descriptor aEdge, Edge_data& aData) { - CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(aEdge)) ; + CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(aEdge)); CGAL_SURF_SIMPL_TEST_assertion(!aData.is_in_PQ()); - CGAL_SURF_SIMPL_TEST_assertion(!mPQ->contains(aEdge) ) ; + CGAL_SURF_SIMPL_TEST_assertion(!mPQ->contains(aEdge)); aData.set_PQ_handle(mPQ->push(aEdge)); CGAL_SURF_SIMPL_TEST_assertion(aData.is_in_PQ()); - CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge) ) ; + CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge)); } - - void update_in_PQ( halfedge_descriptor const& aEdge, Edge_data& aData ) - { - CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(aEdge)) ; - CGAL_SURF_SIMPL_TEST_assertion(aData.is_in_PQ()); - CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge) ) ; - aData.set_PQ_handle(mPQ->update(aEdge,aData.PQ_handle())) ; + void update_in_PQ(const halfedge_descriptor aEdge, Edge_data& aData) + { + CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(aEdge)); + CGAL_SURF_SIMPL_TEST_assertion(aData.is_in_PQ()); + CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge)); + + aData.set_PQ_handle(mPQ->update(aEdge,aData.PQ_handle())); CGAL_SURF_SIMPL_TEST_assertion(aData.is_in_PQ()); - CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge) ) ; - } - - void remove_from_PQ( halfedge_descriptor const& aEdge, Edge_data& aData ) + CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge)); + } + + void remove_from_PQ(const halfedge_descriptor aEdge, Edge_data& aData) { - CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(aEdge)) ; + CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(aEdge)); CGAL_SURF_SIMPL_TEST_assertion(aData.is_in_PQ()); - CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge) ) ; + CGAL_SURF_SIMPL_TEST_assertion(mPQ->contains(aEdge)); aData.set_PQ_handle(mPQ->erase(aEdge,aData.PQ_handle())); CGAL_SURF_SIMPL_TEST_assertion(!aData.is_in_PQ()); - CGAL_SURF_SIMPL_TEST_assertion(!mPQ->contains(aEdge) ) ; - } - - optional pop_from_PQ() + CGAL_SURF_SIMPL_TEST_assertion(!mPQ->contains(aEdge)); + } + + optional pop_from_PQ() { optional rEdge = mPQ->extract_top(); - if ( rEdge ) + if(rEdge) { - CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(*rEdge) ) ; - CGAL_SURF_SIMPL_TEST_assertion(get_data(*rEdge).is_in_PQ()) ; + CGAL_SURF_SIMPL_TEST_assertion(is_primary_edge(*rEdge)); + CGAL_SURF_SIMPL_TEST_assertion(get_data(*rEdge).is_in_PQ()); get_data(*rEdge).reset_PQ_handle(); - CGAL_SURF_SIMPL_TEST_assertion(!get_data(*rEdge).is_in_PQ() ) ; - CGAL_SURF_SIMPL_TEST_assertion(!mPQ->contains(*rEdge)) ; - } - return rEdge ; + CGAL_SURF_SIMPL_TEST_assertion(!get_data(*rEdge).is_in_PQ()); + CGAL_SURF_SIMPL_TEST_assertion(!mPQ->contains(*rEdge)); + } + return rEdge; } /// Functions to ensure the backward compatibility before addition of the constrained edge map template vertex_descriptor - halfedge_collapse_bk_compatibility( - halfedge_descriptor const& pq, AEdgeIsConstrainedMap aEdge_is_constrained_map) + halfedge_collapse_bk_compatibility(const halfedge_descriptor pq, + AEdgeIsConstrainedMap aEdge_is_constrained_map) { - return CGAL::Euler::collapse_edge(edge(pq,mSurface), mSurface, aEdge_is_constrained_map); + return CGAL::Euler::collapse_edge(edge(pq, mSurface), mSurface, aEdge_is_constrained_map); } - template - vertex_descriptor - halfedge_collapse_bk_compatibility( - halfedge_descriptor const& pq, No_constrained_edge_map ) + vertex_descriptor halfedge_collapse_bk_compatibility(const halfedge_descriptor pq, + No_constrained_edge_map) { - vertex_descriptor vd = CGAL::Euler::collapse_edge(edge(pq,mSurface), mSurface); + vertex_descriptor vd = CGAL::Euler::collapse_edge(edge(pq, mSurface), mSurface); return vd; } - /// We wrap this test to avoid penalizing runtime when no constraints are present template - bool - is_edge_adjacent_to_a_constrained_edge( - Profile const& aProfile, AEdgeIsConstrainedMap) + bool is_edge_adjacent_to_a_constrained_edge(const Profile& aProfile, AEdgeIsConstrainedMap) { return is_constrained(aProfile.v0()) && is_constrained(aProfile.v1()); } template - bool - is_edge_adjacent_to_a_constrained_edge( - halfedge_descriptor const&, No_constrained_edge_map ) + bool is_edge_adjacent_to_a_constrained_edge(const halfedge_descriptor, No_constrained_edge_map) { return false; } - /// private: + TM& mSurface; + const ShouldStop& Should_stop; + const VertexIndexMap& Vertex_index_map; + const VertexPointMap& Vertex_point_map; + const EdgeIndexMap& Edge_index_map; + const EdgeIsConstrainedMap& Edge_is_constrained_map; + const GetCost& Get_cost; + const GetPlacement& Get_placement; + VisitorT Visitor; + bool m_has_border; - TM& mSurface ; - - ShouldStop const& Should_stop ; - VertexIndexMap const& Vertex_index_map ; - VertexPointMap const& Vertex_point_map ; - EdgeIndexMap const& Edge_index_map ; - EdgeIsConstrainedMap const& Edge_is_constrained_map; - GetCost const& Get_cost ; - GetPlacement const& Get_placement ; - VisitorT Visitor ; - bool m_has_border ; - private: + Edge_data_array mEdgeDataArray; - Edge_data_array mEdgeDataArray ; - - boost::scoped_ptr mPQ ; - - size_type mInitialEdgeCount ; - size_type mCurrentEdgeCount ; + boost::scoped_ptr mPQ; - FT mcMaxDihedralAngleCos2 ; - - CGAL_SMS_DEBUG_CODE ( unsigned mStep ; ) -} ; + size_type mInitialEdgeCount; + size_type mCurrentEdgeCount; + + FT mcMaxDihedralAngleCos2; + + CGAL_SMS_DEBUG_CODE (unsigned mStep;) +}; + +template +EdgeCollapse:: +EdgeCollapse(TM& aSurface, + const ShouldStop& aShould_stop, + const VertexIndexMap& aVertex_index_map, + const VertexPointMap& aVertex_point_map, + const EdgeIndexMap& aEdge_index_map, + const EdgeIsConstrainedMap& aEdge_is_constrained_map, + const GetCost& aGet_cost, + const GetPlacement& aGet_placement, + VisitorT aVisitor) + : + mSurface(aSurface), + Should_stop(aShould_stop), + Vertex_index_map(aVertex_index_map), + Vertex_point_map(aVertex_point_map), + Edge_index_map(aEdge_index_map), + Edge_is_constrained_map(aEdge_is_constrained_map), + Get_cost(aGet_cost), + Get_placement(aGet_placement), + Visitor(aVisitor), + m_has_border(false) +{ + const FT cMaxDihedralAngleCos = std::cos(1.0 * CGAL_PI / 180.0); + + mcMaxDihedralAngleCos2 = cMaxDihedralAngleCos * cMaxDihedralAngleCos; + + for(halfedge_descriptor ed : halfedges(mSurface)) + { + if(is_border(ed)) + { + m_has_border = true; + break; + } + } + + CGAL_SMS_TRACE(0,"EdgeCollapse of TM with " << (num_edges(aSurface)/2) << " edges"); + + CGAL_SMS_DEBUG_CODE (mStep = 0;) + +#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE + for(vertex_descriptor vd : vertices(mSurface)) + CGAL_SMS_TRACE(1, vertex_to_string(vd)); + + for(halfedge_descriptor ed : halfedges(mSurface)) + CGAL_SMS_TRACE(1, edge_to_string(ed)); +#endif +} + +template +int +EdgeCollapse:: +run() +{ + CGAL_SURF_SIMPL_TEST_assertion(mSurface.is_valid() && mSurface.is_pure_triangle()); + + Visitor.OnStarted(mSurface); + + // First collect all candidate edges in a PQ + collect(); + + // Then proceed to collapse each edge in turn + loop(); + + CGAL_SMS_TRACE(0,"Finished: " << (mInitialEdgeCount - mCurrentEdgeCount) << " edges removed."); + + int r = int(mInitialEdgeCount - mCurrentEdgeCount); + + Visitor.OnFinished(mSurface); + + return r; +} + +template +void +EdgeCollapse:: +collect() +{ + CGAL_SMS_TRACE(0,"collecting edges..."); + + // loop over all the _undirected_ edges in the surface putting them in the PQ + + Equal_3 equal_points = Traits().equal_3_object(); + + size_type lSize = num_edges(mSurface); + + mInitialEdgeCount = mCurrentEdgeCount = static_cast( + std::distance(boost::begin(edges(mSurface)), + boost::end(edges(mSurface))));; + + mEdgeDataArray.reset(new Edge_data[lSize]); + + mPQ.reset(new PQ (lSize, Compare_cost(this), edge_id(this))); + + std::size_t id = 0; + CGAL_SURF_SIMPL_TEST_assertion_code(size_type lInserted = 0); + CGAL_SURF_SIMPL_TEST_assertion_code(size_type lNotInserted = 0); + + std::set zero_length_edges; + + edge_iterator eb, ee; + for(boost::tie(eb,ee) = edges(mSurface); eb!=ee; ++eb, id+=2) + { + halfedge_descriptor lEdge = halfedge(*eb, mSurface); + + if(is_constrained(lEdge)) + continue; // no not insert constrainted edges + + // AF CGAL_assertion(get_halfedge_id(lEdge) == id); + // AF CGAL_assertion(get_halfedge_id(opposite(lEdge, mSurface)) == id+1); + + const Profile& lProfile = create_profile(lEdge); + if(!equal_points(lProfile.p0(), lProfile.p1())) + { + Edge_data& lData = get_data(lEdge); + + lData.cost() = get_cost(lProfile); + insert_in_PQ(lEdge, lData); + + Visitor.OnCollected(lProfile, lData.cost()); + + CGAL_SURF_SIMPL_TEST_assertion_code (++ lInserted); + } + else + { + zero_length_edges.insert(primary_edge(lEdge)); + CGAL_SURF_SIMPL_TEST_assertion_code (++ lNotInserted); + } + + CGAL_SMS_TRACE(2,edge_to_string(lEdge)); + } + + CGAL_SURF_SIMPL_TEST_assertion (lInserted + lNotInserted == mInitialEdgeCount); + + for(halfedge_descriptor hd : zero_length_edges) + { + const Profile& lProfile = create_profile(hd); + + if(!is_collapse_topologically_valid(lProfile)) + continue; + + // edges of length 0 removed no longer need to be treated + if(lProfile.left_face_exists()) + { + halfedge_descriptor lEdge_to_remove = is_constrained(lProfile.vL_v0()) ? + primary_edge(lProfile.v1_vL()) : + primary_edge(lProfile.vL_v0()); + zero_length_edges.erase(lEdge_to_remove); + Edge_data& lData = get_data(lEdge_to_remove); + + if(lData.is_in_PQ()) + { + CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map,lEdge_to_remove) << " from PQ"); + remove_from_PQ(lEdge_to_remove, lData); + } + + --mCurrentEdgeCount; + } + + if(lProfile.right_face_exists()) + { + halfedge_descriptor lEdge_to_remove = is_constrained(lProfile.vR_v1()) ? + primary_edge(lProfile.v0_vR()) : + primary_edge(lProfile.vR_v1()); + zero_length_edges.erase(lEdge_to_remove); + Edge_data& lData = get_data(lEdge_to_remove); + + if(lData.is_in_PQ()) + { + CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map,lEdge_to_remove) << " from PQ"); + remove_from_PQ(lEdge_to_remove, lData); + } + + --mCurrentEdgeCount; + } + + --mCurrentEdgeCount; + + //the placement is trivial, it's always the point itself + Placement_type lPlacement = lProfile.p0(); + vertex_descriptor rResult = halfedge_collapse_bk_compatibility(lProfile.v0_v1(), Edge_is_constrained_map); + put(Vertex_point_map,rResult,*lPlacement); + Visitor.OnCollapsed(lProfile,rResult); + } + + CGAL_SMS_TRACE(0,"Initial edge count: " << mInitialEdgeCount); +} + +template +void +EdgeCollapse:: +loop() +{ + CGAL_SMS_TRACE(0,"Collapsing edges..."); + + CGAL_SURF_SIMPL_TEST_assertion_code (size_type lloop_watchdog = 0); + CGAL_SURF_SIMPL_TEST_assertion_code (size_type lNonCollapsableCount = 0); + + // Pops and processes each edge from the PQ + + optional lEdge; +#ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING + int i_rm=0; +#endif + + while((lEdge = pop_from_PQ())) + { + CGAL_SURF_SIMPL_TEST_assertion(lloop_watchdog ++ < mInitialEdgeCount); + + CGAL_SMS_TRACE(1, "Popped " << edge_to_string(*lEdge)); + CGAL_assertion(!is_constrained(*lEdge)); + + const Profile& lProfile = create_profile(*lEdge); + Cost_type lCost = get_data(*lEdge).cost(); + + Visitor.OnSelected(lProfile, lCost, mInitialEdgeCount, mCurrentEdgeCount); + + if(lCost) + { + if(Should_stop(*lCost, lProfile, mInitialEdgeCount, mCurrentEdgeCount)) + { + Visitor.OnStopConditionReached(lProfile); + + CGAL_SMS_TRACE(0, "Stop condition reached with InitialEdgeCount=" << mInitialEdgeCount + << " CurrentEdgeCount=" << mCurrentEdgeCount + << " Current Edge: " << edge_to_string(*lEdge)); + break; + } + + if(is_collapse_topologically_valid(lProfile)) + { + // The external function Get_new_vertex_point() is allowed to return an absent point if there is no way to place the vertex + // satisfying its constraints. In that case the remaining vertex is simply left unmoved. + Placement_type lPlacement = get_placement(lProfile); + + if(is_collapse_geometrically_valid(lProfile,lPlacement)) + { +#ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING + std::cout << "step " << i_rm << " " << source(*lEdge, mSurface)->point() << " " << target(*lEdge, mSurface)->point() << "\n"; +#endif + collapse(lProfile, lPlacement); + +#ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING + std::stringstream sstr; + sstr << "debug/P-"; + if(i_rm<10) sstr << "0"; + if(i_rm<100) sstr << "0"; + sstr << i_rm << ".off"; + std::ofstream out(sstr.str().c_str()); + out << mSurface; + ++i_rm; +#endif + } + } + else + { + CGAL_SURF_SIMPL_TEST_assertion_code(lNonCollapsableCount++); + + Visitor.OnNonCollapsable(lProfile); + + CGAL_SMS_TRACE(1, edge_to_string(*lEdge) << " NOT Collapsable" ); + } + } + else + { + CGAL_SMS_TRACE(1,edge_to_string(*lEdge) << " uncomputable cost." ); + } + } +} + +template +bool +EdgeCollapse:: +is_border(const vertex_descriptor aV) const +{ + bool rR = false; + + for(halfedge_descriptor lEdge : halfedges_around_target(aV, mSurface)) + { + if(is_edge_a_border(lEdge)) + { + rR = true; + break; + } + } + + return rR; +} + +template +bool +EdgeCollapse:: +is_border_or_constrained(const vertex_descriptor aV) const +{ + for(halfedge_descriptor lEdge : halfedges_around_target(aV, mSurface)) + { + if(is_edge_a_border(lEdge) || is_constrained(lEdge)) + return true; + } + + return false; +} + +template +bool +EdgeCollapse:: +is_constrained(const vertex_descriptor aV) const +{ + for(halfedge_descriptor lEdge : halfedges_around_target(aV, mSurface)) + if(is_constrained(lEdge)) + return true; + + return false; +} + +// Some edges are NOT collapsable: doing so would break the topological consistency of the mesh. +// This function returns true if a edge 'p->q' can be collapsed. +// +// An edge p->q can be collapsed iff it satisfies the "link condition" +// (as described in the "Mesh Optimization" article of Hoppe et al (1993)) +// +// The link condition is as follows: for every vertex 'k' adjacent to both 'p and 'q', +// "p,k,q" is a facet of the mesh. +// +template +bool +EdgeCollapse:: +is_collapse_topologically_valid(const Profile& aProfile) +{ + bool rR = true; + + CGAL_SMS_TRACE(3,"Testing topological collapsabilty of p_q=V" << get(Vertex_index_map,aProfile.v0()) << "(%" << degree(aProfile.v0(), mSurface) << ")" + << "->V" << get(Vertex_index_map,aProfile.v1()) << "(%" << degree(aProfile.v1(), mSurface) << ")"); + + CGAL_SMS_TRACE(4, "is p_q border:" << aProfile.is_v0_v1_a_border()); + CGAL_SMS_TRACE(4, "is q_q border:" << aProfile.is_v1_v0_a_border()); + + out_edge_iterator eb1, ee1; + out_edge_iterator eb2, ee2; + + CGAL_SMS_TRACE(4, " t=V" << (aProfile.left_face_exists() ? get(Vertex_index_map,aProfile.vL()) : -1) + << "(%" << (aProfile.left_face_exists() ? degree(aProfile.vL(), mSurface) : 0) << ")"); + CGAL_SMS_TRACE(4, " b=V" << (aProfile.right_face_exists() ? get(Vertex_index_map,aProfile.vR()) : -1) + << "(%" << (aProfile.right_face_exists() ? degree(aProfile.vR(), mSurface) :0) << ")"); + + // Simple tests handling the case of non-manifold situations at a vertex or edge (pinching) + // (even if we advertise one should not use a surface mesh with such features) + if(aProfile.left_face_exists()) + { + if(CGAL::is_border(opposite(aProfile.v1_vL(), mSurface), mSurface) && + CGAL::is_border(opposite(aProfile.vL_v0(), mSurface), mSurface)) + return false; + + if(aProfile.right_face_exists() && + CGAL::is_border(opposite(aProfile.vR_v1(), mSurface), mSurface) && + CGAL::is_border(opposite(aProfile.v0_vR(), mSurface), mSurface)) + return false; + } + else + { + if(aProfile.right_face_exists()) + { + if(CGAL::is_border(opposite(aProfile.vR_v1(), mSurface), mSurface) && + CGAL::is_border(opposite(aProfile.v0_vR(), mSurface), mSurface)) + return false; + } + else + return false; + } + + // The following loop checks the link condition for v0_v1. + // Specifically, that for every vertex 'k' adjacent to both 'p and 'q', 'pkq' is a face of the mesh. + // + for(boost::tie(eb1,ee1) = halfedges_around_source(aProfile.v0(), mSurface); rR && eb1 != ee1; ++eb1) + { + halfedge_descriptor v0_k = *eb1; + + if(v0_k != aProfile.v0_v1()) + { + vertex_descriptor k = target(v0_k, mSurface); + + for(boost::tie(eb2,ee2) = halfedges_around_source(k, mSurface); rR && eb2 != ee2; ++eb2) + { + halfedge_descriptor k_v1 = *eb2; + + if(target(k_v1, mSurface) == aProfile.v1()) + { + // At this point we know p-q-k are connected and we need to determine if this triangle is a face of the mesh. + // + // Since the mesh is known to be triangular there are at most two faces sharing the edge p-q. + // + // If p->q is NOT a border edge, the top face is p->q->t where t is target(next(p->q)) + // If q->p is NOT a border edge, the bottom face is q->p->b where b is target(next(q->p)) + // + // If k is either t or b then p-q-k *might* be a face of the mesh. It won't be if k==t but p->q is border + // or k==b but q->b is a border (because in that case even though there exists triangles p->q->t (or q->p->b) + // they are holes, not faces) + // + + bool lIsFace = (aProfile.vL() == k && aProfile.left_face_exists()) || + (aProfile.vR() == k && aProfile.right_face_exists()); + + CGAL_SURF_SIMPL_TEST_assertion_code( + if(lIsFace) + { + // Is k_v1 the halfedge bounding the face 'k-v1-v0'? + if(!is_border(k_v1) && target(next(k_v1, mSurface), mSurface) == aProfile.v0()) + { + CGAL_SURF_SIMPL_TEST_assertion(!is_border(k_v1)); + CGAL_SURF_SIMPL_TEST_assertion(target(k_v1, mSurface) == aProfile.v1()); + CGAL_SURF_SIMPL_TEST_assertion(target(next(k_v1, mSurface), mSurface) == aProfile.v0()); + CGAL_SURF_SIMPL_TEST_assertion(target(next(next(k_v1, mSurface), mSurface), mSurface) == k); + } + else // or is it the opposite? + { + halfedge_descriptor v1_k = opposite(k_v1, mSurface); + CGAL_SURF_SIMPL_TEST_assertion(!is_border(v1_k)); + CGAL_SURF_SIMPL_TEST_assertion(target(v1_k, mSurface) == k); + CGAL_SURF_SIMPL_TEST_assertion(target(next(v1_k, mSurface), mSurface) == aProfile.v0()); + CGAL_SURF_SIMPL_TEST_assertion(target(next(next(v1_k, mSurface), mSurface), mSurface) == aProfile.v1()); + } + } + ); + + if(!lIsFace) + { + CGAL_SMS_TRACE(3," k=V" << get(Vertex_index_map,k) << " IS NOT in a face with p-q. NON-COLLAPSABLE edge."); + rR = false; + break; + } + else + { + CGAL_SMS_TRACE(4," k=V" << get(Vertex_index_map,k) << " is in a face with p-q"); + } + } + } + } + } + + if(rR) + { + /// ensure two constrained edges cannot get merged + if(is_edge_adjacent_to_a_constrained_edge(aProfile, Edge_is_constrained_map)) + return false; + + if(aProfile.is_v0_v1_a_border()) + { + if(is_open_triangle(aProfile.v0_v1())) + { + rR = false; + CGAL_SMS_TRACE(3," p-q belongs to an open triangle. NON-COLLAPSABLE edge."); + } + } + else if(aProfile.is_v1_v0_a_border()) + { + if(is_open_triangle(aProfile.v1_v0())) + { + rR = false; + CGAL_SMS_TRACE(3," p-q belongs to an open triangle. NON-COLLAPSABLE edge."); + } + } + else + { + if(is_border(aProfile.v0()) && is_border(aProfile.v1())) + { + rR = false; + CGAL_SMS_TRACE(3," both p and q are boundary vertices but p-q is not. NON-COLLAPSABLE edge."); + } + else + { + bool lTetra = is_tetrahedron(aProfile.v0_v1()); + + //CGAL_SURF_SIMPL_TEST_assertion(lTetra == mSurface.is_tetrahedron(aProfile.v0_v1())); + + if(lTetra) + { + rR = false; + CGAL_SMS_TRACE(3," p-q belongs to a tetrahedron. NON-COLLAPSABLE edge."); + } + + if(next(aProfile.v0_v1(), mSurface) == opposite(prev(aProfile.v1_v0(), mSurface), mSurface) && + prev(aProfile.v0_v1(), mSurface) == opposite(next(aProfile.v1_v0(), mSurface), mSurface)) + { + CGAL_SMS_TRACE(3," degenerate volume."); + return false; + } + } + } + } + + return rR; +} + +template +bool +EdgeCollapse:: +is_tetrahedron(const halfedge_descriptor h1) +{ + return CGAL::is_tetrahedron(h1, mSurface); +} + +template +bool +EdgeCollapse:: +is_open_triangle(const halfedge_descriptor h1) +{ + bool rR = false; + + halfedge_descriptor h2 = next(h1, mSurface); + halfedge_descriptor h3 = next(h2, mSurface); + + // First check if it is a triangle + if(next(h3, mSurface) == h1) + { + // Now check if it is open + CGAL_SMS_TRACE(4," p-q is a border edge... checking E" << get(Edge_index_map, h2) << " and E" << get(Edge_index_map,h3)); + + rR = is_border(h2) && is_border(h3); + + CGAL_SURF_SIMPL_TEST_assertion(rR == (is_border(h1) && + is_border(next(h1, mSurface)) && + is_border(next(next(h1, mSurface), mSurface)))); + } + + return rR; +} + +// Given triangles 'p0,p1,p2' and 'p0,p2,p3', both shared along edge 'v0-v2', +// determine if they are geometrically valid: that is, the ratio of their +// respective areas is no greater than a max value and the internal +// dihedral angle formed by their supporting planes is no greater than +// a given threshold +template +bool +EdgeCollapse:: +are_shared_triangles_valid(const Point& p0, const Point& p1, const Point& p2, const Point& p3) const +{ + bool rR = false; + + Vector e01 = Traits().construct_vector_3_object()(p0, p1); + Vector e02 = Traits().construct_vector_3_object()(p0, p2); + Vector e03 = Traits().construct_vector_3_object()(p0, p3); + + Vector n012 = Traits().construct_cross_product_vector_3_object()(e01, e02); + Vector n023 = Traits().construct_cross_product_vector_3_object()(e02, e03); + + FT l012 = Traits().compute_scalar_product_3_object()(n012, n012); + FT l023 = Traits().compute_scalar_product_3_object()(n023, n023); + + FT larger = (std::max)(l012, l023); + FT smaller = (std::min)(l012, l023); + + const double cMaxAreaRatio = 1e8; + + CGAL_SMS_TRACE(4," Testing validity of shared triangles:" + << "\n p0=" << xyz_to_string(p0) << "\n p1=" << xyz_to_string(p1) << "\n p2=" << xyz_to_string(p2) << "\n p3=" << xyz_to_string(p3) + << "\n e01=" << xyz_to_string(e01) << "\n e02=" << xyz_to_string(e02) << "\n e03=" << xyz_to_string(e03) + << "\n n012=" << xyz_to_string(n012) << "\n n023=" << xyz_to_string(n023) + << "\n l012=" << n_to_string(l012) << "\n l023=" << n_to_string(l023)); + + if(larger < cMaxAreaRatio * smaller) + { + FT l0123 = Traits().compute_scalar_product_3_object()(n012, n023); + CGAL_SMS_TRACE(4,"\n l0123=" << n_to_string(l0123)); + + if(CGAL_NTS is_positive(l0123)) + { + rR = true; + } + else + { + CGAL_SMS_TRACE(4,"\n lhs: " << n_to_string((l0123 * l0123) / (l012 * l023)) << " <= rhs: " << mcMaxDihedralAngleCos2); + + if((l0123 * l0123) <= mcMaxDihedralAngleCos2 * (l012 * l023)) + { + rR = true; + } + } + } + + return rR; +} + + +// Returns the directed halfedge connecting v0 to v1, if exists. +template +typename EdgeCollapse::halfedge_descriptor +EdgeCollapse:: +find_connection(const vertex_descriptor v0, + const vertex_descriptor v1) const +{ + for(halfedge_descriptor out : halfedges_around_source(v0, mSurface)) + { + if(target(out, mSurface) == v1) + return out; + } + + return GraphTraits::null_halfedge(); +} + +// Given the edge 'e' around the link for the collapsinge edge "v0-v1", finds the vertex that makes a triangle adjacent to 'e' but exterior to the link (i.e not containing v0 nor v1) +// If 'e' is a null handle OR 'e' is a border edge, there is no such triangle and a null handle is returned. +template +typename EdgeCollapse::vertex_descriptor +EdgeCollapse:: +find_exterior_link_triangle_3rd_vertex(const halfedge_descriptor e, + const vertex_descriptor v0, + const vertex_descriptor v1) const +{ + vertex_descriptor r; + + if(handle_assigned(e)) + { + vertex_descriptor ra = target(next(e, mSurface), mSurface); + vertex_descriptor rb = source(prev(e, mSurface), mSurface); + + if(ra == rb && ra != v0 && ra != v1) + { + r = ra; + } + else + { + ra = target(next(opposite(e, mSurface), mSurface), mSurface); + rb = source(prev(opposite(e, mSurface), mSurface), mSurface); + + if(ra == rb && ra != v0 && ra != v1) + { + r = ra; + } + } + } + + return r; +} + +// A collapse is geometrically valid if, in the resulting local mesh no two adjacent triangles form an internal dihedral angle +// greater than a fixed threshold (i.e. triangles do not "fold" into each other) +// +template +bool +EdgeCollapse:: +is_collapse_geometrically_valid(const Profile& aProfile, Placement_type k0) +{ + bool rR = true; + + CGAL_SMS_TRACE(3,"Testing geometrical collapsabilty of v0-v1=E" << get(Edge_index_map, aProfile.v0_v1())); + if(k0) + { + // Use the current link to extract all local triangles incident to 'vx' in the collapsed mesh (which at this point doesn't exist yet) + // + typedef typename Profile::vertex_descriptor_vector::const_iterator link_iterator; + link_iterator linkb = aProfile.link().begin(); + link_iterator linke = aProfile.link().end(); + link_iterator linkl = std::prev(linke); + + for(link_iterator l=linkb; l!=linke && rR; ++l) + { + link_iterator pv = (l == linkb ? linkl : std::prev(l)); + link_iterator nx = (l == linkl ? linkb : std::next(l)); + + // k0,k1 and k3 are three consecutive vertices along the link. + vertex_descriptor k1 = *pv; + vertex_descriptor k2 = *l; + vertex_descriptor k3 = *nx; + + CGAL_SMS_TRACE(4, " Screening link vertices k1=V" << get(Vertex_index_map, k1) + << " k2=V" << get(Vertex_index_map, k2) + << " k3=V" << get(Vertex_index_map, k3)); + + halfedge_descriptor e12 = find_connection(k1,k2); + halfedge_descriptor e23 = k3 != k1 ? find_connection(k2,k3) : GraphTraits::null_halfedge(); + + // If 'k1-k2-k3' are connected there will be two adjacent triangles 'k0,k1,k2' and 'k0,k2,k3' after the collapse. + if(handle_assigned(e12) && handle_assigned(e23)) + { + CGAL_SMS_TRACE(4," Link triangles shared"); + + if(!are_shared_triangles_valid(*k0, get_point(k1), get_point(k2), get_point(k3))) + { + CGAL_SMS_TRACE(3, " Triangles VX-V" << get(Vertex_index_map, k1) + << "-V" << get(Vertex_index_map, k2) + << " and VX-V" << get(Vertex_index_map, k3) + << " are not geometrically valid. Collapse rejected"); + rR = false; + } + } + + if(rR) + { + // Also check the triangles 'k0,k1,k2' and it's adjacent along e12: 'k4,k2,k1', if exist + vertex_descriptor k4 = find_exterior_link_triangle_3rd_vertex(e12,aProfile.v0(), aProfile.v1()); + + // There is indeed a triangle shared along e12 + if(handle_assigned(k4)) + { + CGAL_SMS_TRACE(4, " Found exterior link triangle shared along E" << get(Edge_index_map, e12) + << " with third vertex: V" << get(Vertex_index_map, k4)); + + if(!are_shared_triangles_valid(get_point(k1), get_point(k4), get_point(k2), *k0)) + { + CGAL_SMS_TRACE(3, " Triangles V" << get(Vertex_index_map, k1) + << "-V" << get(Vertex_index_map, k4) << " and V" + << get(Vertex_index_map, k2) << "-VX are not geometrically valid. Collapse rejected"); + rR = false; + } + } + } + + if(rR) + { + // And finally, check the triangles 'k0,k2,k3' and it's adjacent e23: 'k5,k3,k2' if exist + vertex_descriptor k5 = find_exterior_link_triangle_3rd_vertex(e23, aProfile.v0(), aProfile.v1()); + + // There is indeed a triangle shared along e12 + if(handle_assigned(k5)) + { + CGAL_SMS_TRACE(4, " Found exterior link triangle shared along E" << get(Edge_index_map, e23) + << " with third vertex: V" << get(Vertex_index_map, k5)); + + if(!are_shared_triangles_valid(get_point(k2), get_point(k5), get_point(k3), *k0)) + { + CGAL_SMS_TRACE(3, " Triangles V" << get(Vertex_index_map, k2) + << "-V" << get(Vertex_index_map, k5) + << " and V" << get(Vertex_index_map, k3) << "-VX are not geometrically valid. Collapse rejected"); + rR = false; + } + } + } + } + } + + return rR; +} + +template +void +EdgeCollapse:: +collapse(const Profile& aProfile, + Placement_type aPlacement) +{ + CGAL_SMS_TRACE(1,"S" << mStep << ". Collapsing " << edge_to_string(aProfile.v0_v1())); + + vertex_descriptor rResult; + + Visitor.OnCollapsing(aProfile,aPlacement); + + --mCurrentEdgeCount; + + CGAL_SURF_SIMPL_TEST_assertion_code( + size_type lResultingVertexCount = mSurface.size_of_vertices(); + size_type lResultingEdgeCount = mSurface.size_of_halfedges() / 2; + ); + + // If the top/bottom facets exists, they are removed and the edges v0vt and Q-B along with them. + // In that case their corresponding pairs must be pop off the queue + if(aProfile.left_face_exists()) + { + halfedge_descriptor lV0VL = primary_edge(aProfile.vL_v0()); + if(is_constrained(lV0VL)) //make sure a constrained edge will not disappear + lV0VL=primary_edge(aProfile.v1_vL()); + + CGAL_SMS_TRACE(3, "V0VL E" << get(Edge_index_map,lV0VL) + << "(V" << get(Vertex_index_map, source(lV0VL, mSurface)) + << "->V" << get(Vertex_index_map,target(lV0VL, mSurface)) << ")"); + + Edge_data& lData = get_data(lV0VL); + if(lData.is_in_PQ()) + { + CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map, lV0VL) << " from PQ"); + remove_from_PQ(lV0VL, lData); + } + + --mCurrentEdgeCount; + CGAL_SURF_SIMPL_TEST_assertion_code(--lResultingEdgeCount); + } + + if(aProfile.right_face_exists()) + { + halfedge_descriptor lVRV1 = primary_edge(aProfile.vR_v1()); + if(is_constrained(lVRV1)) //make sure a constrained edge will not disappear + lVRV1=primary_edge(aProfile.v0_vR()); + + CGAL_SMS_TRACE(3, "V1VRE" << get(Edge_index_map, lVRV1) + << "(V" << get(Vertex_index_map, source(lVRV1, mSurface)) + << "->V" << get(Vertex_index_map, target(lVRV1, mSurface)) << ")"); + + Edge_data& lData = get_data(lVRV1); + if(lData.is_in_PQ()) + { + CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map, lVRV1) << " from PQ"); + remove_from_PQ(lVRV1, lData); + } + + --mCurrentEdgeCount; + CGAL_SURF_SIMPL_TEST_assertion_code(--lResultingEdgeCount); + } + + CGAL_SMS_TRACE(1, "Removing:\n v0v1: E" << get(Edge_index_map, aProfile.v0_v1()) + << "(V" << get(Vertex_index_map, aProfile.v0()) + << "->V" << get(Vertex_index_map, aProfile.v1()) << ")"); + + // Perform the actuall collapse. + // This is an external function. + // It's REQUIRED to remove ONLY 1 vertex (P or Q) and edges PQ,PT and QB + // (PT and QB are removed if they are not null). + // All other edges must be kept. + // All directed edges incident to vertex removed are relink to the vertex kept. + rResult = halfedge_collapse_bk_compatibility(aProfile.v0_v1(), Edge_is_constrained_map); + + CGAL_SURF_SIMPL_TEST_assertion_code(--lResultingEdgeCount); + CGAL_SURF_SIMPL_TEST_assertion_code(--lResultingVertexCount); + + CGAL_SURF_SIMPL_TEST_assertion(lResultingEdgeCount * 2 == mSurface.size_of_halfedges()); + CGAL_SURF_SIMPL_TEST_assertion(lResultingVertexCount == mSurface.size_of_vertices()); + CGAL_SURF_SIMPL_TEST_assertion(mSurface.is_valid() && mSurface.is_pure_triangle()); + + CGAL_SMS_TRACE(1,"V" << get(Vertex_index_map,rResult) << " kept."); + +#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE + for(halfedge_descriptor hd : halfedges_around_source(rResult, mSurface)) + CGAL_SMS_TRACE(2, edge_to_string(hd)); +#endif + + if(aPlacement) + { + CGAL_SMS_TRACE(1,"New vertex point: " << xyz_to_string(*aPlacement)); + put(Vertex_point_map,rResult,*aPlacement); + } + + Visitor.OnCollapsed(aProfile,rResult); + + update_neighbors(rResult); + + CGAL_SMS_DEBUG_CODE (++mStep;) +} + +template +void +EdgeCollapse:: +update_neighbors(const vertex_descriptor aKeptV) +{ + CGAL_SMS_TRACE(3,"Updating cost of neighboring edges..."); + + // (A) collect all edges to update their cost: all those around each vertex adjacent to the vertex kept + typedef std::set edges; + + edges lToUpdate(Compare_id(this)); + edges lToInsert(Compare_id(this)); + + // (A.1) loop around all vertices adjacent to the vertex kept + for(halfedge_descriptor lEdge1 : halfedges_around_target(aKeptV, mSurface)) + { + vertex_descriptor lAdj_k = source(lEdge1, mSurface); + + // (A.2) loop around all edges incident on each adjacent vertex + for(halfedge_descriptor lEdge2 : halfedges_around_target(lAdj_k, mSurface)) + { + lEdge2 = primary_edge(lEdge2); + + Edge_data& lData2 = get_data(lEdge2); + CGAL_SMS_TRACE(4,"Inedge around V" << get(Vertex_index_map, lAdj_k) << edge_to_string(lEdge2)); + + // Only edges still in the PQ needs to be updated, the other needs to be re-inserted + if(lData2.is_in_PQ()) + lToUpdate.insert(lEdge2); + else + lToInsert.insert(lEdge2); + } + } + + // (B) Proceed to update the costs. + for(halfedge_descriptor lEdge : lToUpdate) + { + Edge_data& lData = get_data(lEdge); + const Profile& lProfile = create_profile(lEdge); + lData.cost() = get_cost(lProfile); + + CGAL_SMS_TRACE(3, edge_to_string(lEdge) << " updated in the PQ"); + + update_in_PQ(lEdge, lData); + } + + // (C) Insert ignored edges + // + // I think that this should be done for edges eliminated because of the geometric criteria + // and not the topological one.However maintaining such a set might be more expensive + // and hard to be safe ... + for(halfedge_descriptor lEdge : lToInsert) + { + if(is_constrained(lEdge)) + continue; //do not insert constrained edges + + Edge_data& lData = get_data(lEdge); + const Profile& lProfile = create_profile(lEdge); + lData.cost() = get_cost(lProfile); + + CGAL_SMS_TRACE(3, edge_to_string(lEdge) << " re-inserted in the PQ"); + insert_in_PQ(lEdge, lData); + } +} } // namespace Surface_mesh_simplification - -} //namespace CGAL - -#include +} // namespace CGAL #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_I_EDGE_COLLAPSE_H // -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h deleted file mode 100644 index f47d3d752f5..00000000000 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h +++ /dev/null @@ -1,939 +0,0 @@ -// Copyright (c) 2006 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) : Fernando Cacciola -// -#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_COLLAPSE_IMPL_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_COLLAPSE_IMPL_H - -#include - - -namespace CGAL { - -namespace Surface_mesh_simplification -{ - - template - EdgeCollapse::EdgeCollapse( TM& aSurface - , ShouldStop const& aShould_stop - , VertexIndexMap const& aVertex_index_map - , VertexPointMap const& aVertex_point_map - , EdgeIndexMap const& aEdge_index_map - , EdgeIsConstrainedMap const& aEdge_is_constrained_map - , GetCost const& aGet_cost - , GetPlacement const& aGet_placement - , VisitorT aVisitor - ) - : - mSurface (aSurface) - ,Should_stop (aShould_stop) - ,Vertex_index_map (aVertex_index_map) - ,Vertex_point_map (aVertex_point_map) - ,Edge_index_map (aEdge_index_map) - ,Edge_is_constrained_map (aEdge_is_constrained_map) - ,Get_cost (aGet_cost) - ,Get_placement (aGet_placement) - ,Visitor (aVisitor) - ,m_has_border (false) -{ - const FT cMaxDihedralAngleCos = std::cos( 1.0 * CGAL_PI / 180.0 ) ; - - mcMaxDihedralAngleCos2 = cMaxDihedralAngleCos * cMaxDihedralAngleCos ; - - halfedge_iterator eb, ee ; - for ( boost::tie(eb,ee) = halfedges(mSurface); eb!=ee; ++eb ) - { - halfedge_descriptor ed = *eb; - if(is_border(ed)){ - m_has_border = true; - break; - } - } - - CGAL_SMS_TRACE(0,"EdgeCollapse of TM with " << (num_edges(aSurface)/2) << " edges" ); - - CGAL_SMS_DEBUG_CODE ( mStep = 0 ; ) - -#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE - vertex_iterator vb, ve ; - for ( boost::tie(vb,ve) = vertices(mSurface) ; vb != ve ; ++ vb ) - CGAL_SMS_TRACE(1, vertex_to_string(*vb) ) ; - - for ( boost::tie(eb,ee) = halfedges(mSurface); eb!=ee; ++eb ) - CGAL_SMS_TRACE(1, edge_to_string(*eb) ) ; -#endif -} - - template - int EdgeCollapse::run() -{ - CGAL_SURF_SIMPL_TEST_assertion( mSurface.is_valid() && mSurface.is_pure_triangle() ) ; - - Visitor.OnStarted(mSurface); - - // First collect all candidate edges in a PQ - Collect(); - - // Then proceed to collapse each edge in turn - Loop(); - - CGAL_SMS_TRACE(0,"Finished: " << (mInitialEdgeCount - mCurrentEdgeCount) << " edges removed." ) ; - - int r = (int)(mInitialEdgeCount - mCurrentEdgeCount) ; - - Visitor.OnFinished(mSurface); - - return r ; -} - - template - void EdgeCollapse::Collect() -{ - CGAL_SMS_TRACE(0,"Collecting edges..."); - - // - // Loop over all the _undirected_ edges in the surface putting them in the PQ - // - - Equal_3 equal_points = Traits().equal_3_object(); - - size_type lSize = num_edges(mSurface); - - mInitialEdgeCount = mCurrentEdgeCount = static_cast( - std::distance( boost::begin(edges(mSurface)), - boost::end(edges(mSurface)) ) );; - - mEdgeDataArray.reset( new Edge_data[lSize] ) ; - - mPQ.reset( new PQ (lSize, Compare_cost(this), edge_id(this) ) ) ; - - std::size_t id = 0 ; - - CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lInserted = 0 ) ; - CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lNotInserted = 0 ) ; - - std::set zero_length_edges; - - edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = edges(mSurface); eb!=ee; ++eb, id+=2 ) - { - halfedge_descriptor lEdge = halfedge(*eb,mSurface) ; - - if ( is_constrained(lEdge) ) continue;//no not insert constrainted edges - - // AF CGAL_assertion( get_halfedge_id(lEdge) == id ) ; - // AF CGAL_assertion( get_halfedge_id(opposite(lEdge,mSurface)) == id+1 ) ; - - Profile const& lProfile = create_profile(lEdge); - if ( !equal_points(lProfile.p0(),lProfile.p1()) ) - { - Edge_data& lData = get_data(lEdge); - - lData.cost() = get_cost(lProfile) ; - insert_in_PQ(lEdge,lData); - - Visitor.OnCollected(lProfile,lData.cost()); - - CGAL_SURF_SIMPL_TEST_assertion_code ( ++ lInserted ) ; - } - else - { - zero_length_edges.insert(primary_edge(lEdge)); - CGAL_SURF_SIMPL_TEST_assertion_code ( ++ lNotInserted ) ; - } - - - CGAL_SMS_TRACE(2,edge_to_string(lEdge)); - } - - CGAL_SURF_SIMPL_TEST_assertion ( lInserted + lNotInserted == mInitialEdgeCount ) ; - - for (typename std::set::iterator it=zero_length_edges.begin(), - it_end=zero_length_edges.end();it!=it_end;++it) - { - Profile const& lProfile = create_profile(*it); - - if (!Is_collapse_topologically_valid(lProfile) ) continue; - - // edges of length 0 removed no longer need to be treated - if ( lProfile.left_face_exists() ) - { - halfedge_descriptor lEdge_to_remove = is_constrained(lProfile.vL_v0()) ? - primary_edge(lProfile.v1_vL()) : - primary_edge(lProfile.vL_v0()) ; - zero_length_edges.erase( lEdge_to_remove ); - Edge_data& lData = get_data(lEdge_to_remove) ; - if ( lData.is_in_PQ() ){ - CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map,lEdge_to_remove) << " from PQ" ); - remove_from_PQ(lEdge_to_remove,lData); - } - --mCurrentEdgeCount; - } - - if ( lProfile.right_face_exists() ) - { - halfedge_descriptor lEdge_to_remove = is_constrained(lProfile.vR_v1()) ? - primary_edge(lProfile.v0_vR()) : - primary_edge(lProfile.vR_v1()) ; - zero_length_edges.erase( lEdge_to_remove ); - Edge_data& lData = get_data(lEdge_to_remove) ; - if ( lData.is_in_PQ() ){ - CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map,lEdge_to_remove) << " from PQ" ); - remove_from_PQ(lEdge_to_remove,lData); - } - --mCurrentEdgeCount; - } - - --mCurrentEdgeCount; - - //the placement is trivial, it's always the point itself - Placement_type lPlacement = lProfile.p0(); - vertex_descriptor rResult - = halfedge_collapse_bk_compatibility(lProfile.v0_v1(), Edge_is_constrained_map); - put(Vertex_point_map,rResult,*lPlacement); - Visitor.OnCollapsed(lProfile,rResult); - } - - CGAL_SMS_TRACE(0,"Initial edge count: " << mInitialEdgeCount ) ; -} - - template - void EdgeCollapse::Loop() -{ - CGAL_SMS_TRACE(0,"Collapsing edges...") ; - - CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lLoop_watchdog = 0 ) ; - CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lNonCollapsableCount = 0 ) ; - - // - // Pops and processes each edge from the PQ - // - optional lEdge ; - #ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING - int i_rm=0; - #endif - while ( (lEdge = pop_from_PQ()) ) - { - CGAL_SURF_SIMPL_TEST_assertion ( lLoop_watchdog ++ < mInitialEdgeCount ) ; - - CGAL_SMS_TRACE(1,"Popped " << edge_to_string(*lEdge) ) ; - - CGAL_assertion( !is_constrained(*lEdge) ); - - Profile const& lProfile = create_profile(*lEdge); - - Cost_type lCost = get_data(*lEdge).cost(); - - Visitor.OnSelected(lProfile,lCost,mInitialEdgeCount,mCurrentEdgeCount); - - if ( lCost ) - { - if ( Should_stop(*lCost,lProfile,mInitialEdgeCount,mCurrentEdgeCount) ) - { - Visitor.OnStopConditionReached(lProfile); - - CGAL_SMS_TRACE(0,"Stop condition reached with InitialEdgeCount=" << mInitialEdgeCount - << " CurrentEdgeCount=" << mCurrentEdgeCount - << " Current Edge: " << edge_to_string(*lEdge) - ); - break ; - } - - if ( Is_collapse_topologically_valid(lProfile) ) - { - // The external function Get_new_vertex_point() is allowed to return an absent point if there is no way to place the vertex - // satisfying its constraints. In that case the remaining vertex is simply left unmoved. - Placement_type lPlacement = get_placement(lProfile); - - if ( Is_collapse_geometrically_valid(lProfile,lPlacement) ) - { - #ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING - std::cout << "step " << i_rm << " " << source(*lEdge,mSurface)->point() << " " << target(*lEdge,mSurface)->point() << "\n"; - #endif - Collapse(lProfile,lPlacement); - #ifdef CGAL_SURF_SIMPL_INTERMEDIATE_STEPS_PRINTING - std::stringstream sstr; - sstr << "debug/P-"; - if (i_rm<10) sstr << "0"; - if (i_rm<100) sstr << "0"; - sstr << i_rm << ".off"; - std::ofstream out(sstr.str().c_str()); - out << mSurface; - ++i_rm; - #endif - } - } - else - { - CGAL_SURF_SIMPL_TEST_assertion_code ( lNonCollapsableCount++ ) ; - - Visitor.OnNonCollapsable(lProfile); - - CGAL_SMS_TRACE(1,edge_to_string(*lEdge) << " NOT Collapsable" ); - } - } - else - { - CGAL_SMS_TRACE(1,edge_to_string(*lEdge) << " uncomputable cost." ); - } - } -} - -template -bool EdgeCollapse::is_border( vertex_descriptor const& aV ) const -{ - bool rR = false ; - - in_edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = halfedges_around_target(aV,mSurface) ; eb != ee ; ++ eb ) - { - halfedge_descriptor lEdge = *eb ; - if ( is_edge_a_border(lEdge) ) - { - rR = true ; - break ; - } - } - - return rR ; -} - -template -bool EdgeCollapse::is_border_or_constrained( vertex_descriptor const& aV ) const -{ - in_edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = halfedges_around_target(aV,mSurface) ; eb != ee ; ++ eb ) - { - halfedge_descriptor lEdge = *eb ; - if ( is_edge_a_border(lEdge) || is_constrained(lEdge) ) - return true; - } - return false; -} - -template -bool EdgeCollapse::is_constrained( vertex_descriptor const& aV ) const -{ - in_edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = halfedges_around_target(aV,mSurface) ; eb != ee ; ++ eb ) - if ( is_constrained(*eb) ) return true; - return false; -} - -// Some edges are NOT collapsable: doing so would break the topological consistency of the mesh. -// This function returns true if a edge 'p->q' can be collapsed. -// -// An edge p->q can be collapsed iff it satisfies the "link condition" -// (as described in the "Mesh Optimization" article of Hoppe et al (1993)) -// -// The link condition is as follows: for every vertex 'k' adjacent to both 'p and 'q', -// "p,k,q" is a facet of the mesh. -// -template -bool EdgeCollapse::Is_collapse_topologically_valid( Profile const& aProfile ) -{ - bool rR = true ; - - CGAL_SMS_TRACE(3,"Testing topological collapsabilty of p_q=V" << get(Vertex_index_map,aProfile.v0()) << "(%" << degree(aProfile.v0(),mSurface) << ")" - << "->V" << get(Vertex_index_map,aProfile.v1()) << "(%" << degree(aProfile.v1(),mSurface) << ")" - ); - - CGAL_SMS_TRACE(4, "is p_q border:" << aProfile.is_v0_v1_a_border() ); - CGAL_SMS_TRACE(4, "is q_q border:" << aProfile.is_v1_v0_a_border() ); - - out_edge_iterator eb1, ee1 ; - out_edge_iterator eb2, ee2 ; - - CGAL_SMS_TRACE(4," t=V" - << ( aProfile.left_face_exists() ? get(Vertex_index_map,aProfile.vL()) : -1 ) - << "(%" - << ( aProfile.left_face_exists() ? degree(aProfile.vL(),mSurface) : 0 ) - << ")" - ); - CGAL_SMS_TRACE(4," b=V" - << ( aProfile.right_face_exists() ? get(Vertex_index_map,aProfile.vR()) : -1 ) - << "(%" - << ( aProfile.right_face_exists() ? degree(aProfile.vR(),mSurface) :0 ) - << ")" - ); - - // Simple tests handling the case of non-manifold situations at a vertex or edge (pinching) - // (even if we advertise one should not use a surface mesh with such features) - if ( aProfile.left_face_exists () ) - { - if ( CGAL::is_border( opposite(aProfile.v1_vL(), mSurface), mSurface ) && - CGAL::is_border( opposite(aProfile.vL_v0(), mSurface), mSurface ) - ) return false; - - if ( aProfile.right_face_exists () && - CGAL::is_border( opposite(aProfile.vR_v1(), mSurface), mSurface ) && - CGAL::is_border( opposite(aProfile.v0_vR(), mSurface), mSurface ) - ) return false; - } - else{ - if ( aProfile.right_face_exists () ) - { - if ( CGAL::is_border( opposite(aProfile.vR_v1(), mSurface), mSurface ) && - CGAL::is_border( opposite(aProfile.v0_vR(), mSurface), mSurface ) - ) return false; - } - else - return false; - } - - // The following loop checks the link condition for v0_v1. - // Specifically, that for every vertex 'k' adjacent to both 'p and 'q', 'pkq' is a face of the mesh. - // - for ( boost::tie(eb1,ee1) = halfedges_around_source(aProfile.v0(),mSurface) ; rR && eb1 != ee1 ; ++ eb1 ) - { - halfedge_descriptor v0_k = *eb1 ; - - if ( v0_k != aProfile.v0_v1() ) - { - vertex_descriptor k = target(v0_k,mSurface); - - for ( boost::tie(eb2,ee2) = halfedges_around_source(k,mSurface) ; rR && eb2 != ee2 ; ++ eb2 ) - { - halfedge_descriptor k_v1 = *eb2 ; - - if ( target(k_v1,mSurface) == aProfile.v1() ) - { - // At this point we know p-q-k are connected and we need to determine if this triangle is a face of the mesh. - // - // Since the mesh is known to be triangular there are at most two faces sharing the edge p-q. - // - // If p->q is NOT a border edge, the top face is p->q->t where t is target(next(p->q)) - // If q->p is NOT a border edge, the bottom face is q->p->b where b is target(next(q->p)) - // - // If k is either t or b then p-q-k *might* be a face of the mesh. It won't be if k==t but p->q is border - // or k==b but q->b is a border (because in that case even though there exists triangles p->q->t (or q->p->b) - // they are holes, not faces) - // - - bool lIsFace = ( aProfile.vL() == k && aProfile.left_face_exists () ) - || ( aProfile.vR() == k && aProfile.right_face_exists() ) ; - - CGAL_SURF_SIMPL_TEST_assertion_code - ( - if ( lIsFace ) - { - // Is k_v1 the halfedge bounding the face 'k-v1-v0'? - if ( ! is_border(k_v1) && target(next(k_v1,mSurface),mSurface) == aProfile.v0() ) - { - CGAL_SURF_SIMPL_TEST_assertion( ! is_border(k_v1) ) ; - CGAL_SURF_SIMPL_TEST_assertion( target(k_v1,mSurface) == aProfile.v1() ) ; - CGAL_SURF_SIMPL_TEST_assertion( target(next(k_v1,mSurface),mSurface) == aProfile.v0() ) ; - CGAL_SURF_SIMPL_TEST_assertion( target(next(next(k_v1,mSurface),mSurface),mSurface) == k ) ; - } - else // or is it the opposite? - { - halfedge_descriptor v1_k = opposite(k_v1,mSurface); - CGAL_SURF_SIMPL_TEST_assertion( ! is_border(v1_k) ) ; - CGAL_SURF_SIMPL_TEST_assertion( target(v1_k,mSurface) == k ) ; - CGAL_SURF_SIMPL_TEST_assertion( target(next(v1_k, mSurface),mSurface) == aProfile.v0() ) ; - CGAL_SURF_SIMPL_TEST_assertion( target(next(next(v1_k, mSurface),mSurface),mSurface) == aProfile.v1() ) ; - } - } - ); - - if ( !lIsFace ) - { - CGAL_SMS_TRACE(3," k=V" << get(Vertex_index_map,k) << " IS NOT in a face with p-q. NON-COLLAPSABLE edge." ) ; - rR = false ; - break ; - } - else - { - CGAL_SMS_TRACE(4," k=V" << get(Vertex_index_map,k) << " is in a face with p-q") ; - } - } - } - } - } - - if ( rR ) - { - /// ensure two constrained edges cannot get merged - if ( is_edge_adjacent_to_a_constrained_edge( - aProfile, Edge_is_constrained_map) ) return false ; - - if ( aProfile.is_v0_v1_a_border() ) - { - if ( Is_open_triangle(aProfile.v0_v1()) ) - { - rR = false ; - CGAL_SMS_TRACE(3," p-q belongs to an open triangle. NON-COLLAPSABLE edge." ) ; - } - } - else if ( aProfile.is_v1_v0_a_border() ) - { - if ( Is_open_triangle(aProfile.v1_v0()) ) - { - rR = false ; - CGAL_SMS_TRACE(3," p-q belongs to an open triangle. NON-COLLAPSABLE edge." ) ; - } - } - else - { - if ( is_border(aProfile.v0()) && is_border(aProfile.v1()) ) - { - rR = false ; - CGAL_SMS_TRACE(3," both p and q are boundary vertices but p-q is not. NON-COLLAPSABLE edge." ) ; - } - else - { - bool lTetra = Is_tetrahedron(aProfile.v0_v1()); - - //CGAL_SURF_SIMPL_TEST_assertion( lTetra == mSurface.is_tetrahedron(aProfile.v0_v1()) ) ; - - if ( lTetra ) - { - rR = false ; - CGAL_SMS_TRACE(3," p-q belongs to a tetrahedron. NON-COLLAPSABLE edge." ) ; - } - - if ( next(aProfile.v0_v1(), mSurface) == opposite(prev(aProfile.v1_v0(), mSurface), mSurface) && - prev(aProfile.v0_v1(), mSurface) == opposite(next(aProfile.v1_v0(), mSurface), mSurface) ) - { - CGAL_SMS_TRACE(3," degenerate volume." ) ; - return false ; - } - } - } - } - - return rR ; -} - -template -bool EdgeCollapse::Is_tetrahedron( halfedge_descriptor const& h1 ) -{ - return is_tetrahedron(h1,mSurface); -} - -template -bool EdgeCollapse::Is_open_triangle( halfedge_descriptor const& h1 ) -{ - bool rR = false ; - - halfedge_descriptor h2 = next(h1,mSurface); - halfedge_descriptor h3 = next(h2,mSurface); - - // First check if it is a triangle - if ( next(h3,mSurface) == h1 ) - { - // Now check if it is open - CGAL_SMS_TRACE(4," p-q is a border edge... checking E" << get(Edge_index_map,h2) << " and E" << get(Edge_index_map,h3) ) ; - - rR = is_border(h2) && is_border(h3); - - CGAL_SURF_SIMPL_TEST_assertion( rR == ( is_border(h1) - && is_border(next(h1,mSurface)) - && is_border(next(next(h1,mSurface),mSurface)) - ) - ) ; - } - - return rR ; -} - -// Given triangles 'p0,p1,p2' and 'p0,p2,p3', both shared along edge 'v0-v2', -// determine if they are geometrically valid: that is, the ratio of their -// respective areas is no greater than a max value and the internal -// dihedral angle formed by their supporting planes is no greater than -// a given threshold -template -bool EdgeCollapse::are_shared_triangles_valid( Point const& p0, Point const& p1, Point const& p2, Point const& p3 ) const -{ - bool rR = false ; - - Vector e01 = Traits().construct_vector_3_object()(p0,p1) ; - Vector e02 = Traits().construct_vector_3_object()(p0,p2) ; - Vector e03 = Traits().construct_vector_3_object()(p0,p3) ; - - Vector n012 = Traits().construct_cross_product_vector_3_object()(e01,e02); - Vector n023 = Traits().construct_cross_product_vector_3_object()(e02,e03); - - FT l012 = Traits().compute_scalar_product_3_object()(n012, n012) ; - FT l023 = Traits().compute_scalar_product_3_object()(n023, n023) ; - - FT larger = (std::max)(l012,l023); - FT smaller = (std::min)(l012,l023); - - const double cMaxAreaRatio = 1e8 ; - - CGAL_SMS_TRACE(4," Testing validity of shared triangles:" - << "\n p0=" << xyz_to_string(p0) << "\n p1=" << xyz_to_string(p1) << "\n p2=" << xyz_to_string(p2) << "\n p3=" << xyz_to_string(p3) - << "\n e01=" << xyz_to_string(e01) << "\n e02=" << xyz_to_string(e02) << "\n e03=" << xyz_to_string(e03) - << "\n n012=" << xyz_to_string(n012) << "\n n023=" << xyz_to_string(n023) - << "\n l012=" << n_to_string(l012) << "\n l023=" << n_to_string(l023) - ); - - if ( larger < cMaxAreaRatio * smaller ) - { - FT l0123 = Traits().compute_scalar_product_3_object()(n012, n023) ; - CGAL_SMS_TRACE(4,"\n l0123=" << n_to_string(l0123) ); - - if ( CGAL_NTS is_positive(l0123) ) - { - rR = true ; - } - else - { - CGAL_SMS_TRACE(4,"\n lhs: " << n_to_string(( l0123 * l0123 ) / ( l012 * l023 )) << " <= rhs: " << mcMaxDihedralAngleCos2 ) ; - - if ( ( l0123 * l0123 ) <= mcMaxDihedralAngleCos2 * ( l012 * l023 ) ) - { - rR = true ; - } - } - } - - return rR ; -} - - -// Returns the directed halfedge connecting v0 to v1, if exists. -template -typename EdgeCollapse::halfedge_descriptor -EdgeCollapse::find_connection ( vertex_descriptor const& v0, vertex_descriptor const& v1 ) const -{ - out_edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = halfedges_around_source(v0,mSurface) ; eb != ee ; ++ eb ) - { - halfedge_descriptor out = *eb ; - if ( target(out,mSurface) == v1 ) - return out ; - } - - return halfedge_descriptor() ; -} - -// Given the edge 'e' around the link for the collapsinge edge "v0-v1", finds the vertex that makes a triangle adjacent to 'e' but exterior to the link (i.e not containing v0 nor v1) -// If 'e' is a null handle OR 'e' is a border edge, there is no such triangle and a null handle is returned. -template -typename EdgeCollapse::vertex_descriptor -EdgeCollapse::find_exterior_link_triangle_3rd_vertex ( halfedge_descriptor const& e, vertex_descriptor const& v0, vertex_descriptor const& v1 ) const -{ - vertex_descriptor r ; - - if ( handle_assigned(e) ) - { - vertex_descriptor ra = target(next(e, mSurface), mSurface); - vertex_descriptor rb = source(prev(e, mSurface), mSurface); - - if ( ra == rb && ra != v0 && ra != v1 ) - { - r = ra ; - } - else - { - ra = target(next(opposite(e,mSurface), mSurface), mSurface); - rb = source(prev(opposite(e,mSurface), mSurface), mSurface); - - if ( ra == rb && ra != v0 && ra != v1 ) - { - r = ra ; - } - } - } - - return r ; -} - - -// A collapse is geometrically valid if, in the resulting local mesh no two adjacent triangles form an internal dihedral angle -// greater than a fixed threshold (i.e. triangles do not "fold" into each other) -// -template -bool EdgeCollapse::Is_collapse_geometrically_valid( Profile const& aProfile, Placement_type k0) -{ - bool rR = true ; - - - - CGAL_SMS_TRACE(3,"Testing geometrical collapsabilty of v0-v1=E" << get(Edge_index_map,aProfile.v0_v1()) ); - if ( k0 ) - { - // Use the current link to extract all local triangles incident to 'vx' in the collapsed mesh (which at this point doesn't exist yet) - // - typedef typename Profile::vertex_descriptor_vector::const_iterator link_iterator ; - link_iterator linkb = aProfile.link().begin(); - link_iterator linke = aProfile.link().end (); - link_iterator linkl = std::prev(linke) ; - - for ( link_iterator l = linkb ; l != linke && rR ; ++ l ) - { - link_iterator pv = ( l == linkb ? linkl : std::prev (l) ); - link_iterator nx = ( l == linkl ? linkb : std::next (l) ) ; - - // k0,k1 and k3 are three consecutive vertices along the link. - vertex_descriptor k1 = *pv ; - vertex_descriptor k2 = * l ; - vertex_descriptor k3 = *nx ; - - CGAL_SMS_TRACE(4," Screening link vertices k1=V" << get(Vertex_index_map,k1) << " k2=V" << get(Vertex_index_map,k2) << " k3=V" << get(Vertex_index_map,k3) ) ; - - halfedge_descriptor e12 = find_connection(k1,k2); - halfedge_descriptor e23 = k3 != k1 ? find_connection(k2,k3) : halfedge_descriptor() ; - - // If 'k1-k2-k3' are connected there will be two adjacent triangles 'k0,k1,k2' and 'k0,k2,k3' after the collapse. - if ( handle_assigned(e12) && handle_assigned(e23) ) - { - CGAL_SMS_TRACE(4," Link triangles shared" ) ; - - if ( !are_shared_triangles_valid( *k0, get_point(k1), get_point(k2), get_point(k3) ) ) - { - CGAL_SMS_TRACE(3," Triangles VX-V" << get(Vertex_index_map,k1) << "-V" << get(Vertex_index_map,k2) << " and VX-V" << get(Vertex_index_map,k3) << " are not geometrically valid. Collapse rejected"); - rR = false ; - } - } - - if ( rR ) - { - // Also check the triangles 'k0,k1,k2' and it's adjacent along e12: 'k4,k2,k1', if exist - vertex_descriptor k4 = find_exterior_link_triangle_3rd_vertex(e12,aProfile.v0(),aProfile.v1()); - - // There is indeed a triangle shared along e12 - if ( handle_assigned(k4) ) - { - CGAL_SMS_TRACE(4," Found exterior link triangle shared along E" << get(Edge_index_map,e12) << " with third vertex: V" << get(Vertex_index_map,k4) ) ; - - if ( !are_shared_triangles_valid( get_point(k1), get_point(k4), get_point(k2), *k0 ) ) - { - CGAL_SMS_TRACE(3," Triangles V" << get(Vertex_index_map,k1) << "-V" << get(Vertex_index_map,k4) << " and V" << get(Vertex_index_map,k2) << "-VX are not geometrically valid. Collapse rejected"); - rR = false ; - } - } - } - - if ( rR ) - { - // And finally, check the triangles 'k0,k2,k3' and it's adjacent e23: 'k5,k3,k2' if exist - vertex_descriptor k5 = find_exterior_link_triangle_3rd_vertex(e23,aProfile.v0(),aProfile.v1()); - - // There is indeed a triangle shared along e12 - if ( handle_assigned(k5) ) - { - CGAL_SMS_TRACE(4," Found exterior link triangle shared along E" << get(Edge_index_map,e23) << " with third vertex: V" << get(Vertex_index_map,k5) ) ; - - if ( !are_shared_triangles_valid( get_point(k2), get_point(k5), get_point(k3), *k0 ) ) - { - CGAL_SMS_TRACE(3," Triangles V" << get(Vertex_index_map,k2) << "-V" << get(Vertex_index_map,k5) << " and V" << get(Vertex_index_map,k3) << "-VX are not geometrically valid. Collapse rejected"); - rR = false ; - } - } - } - } - - } - - return rR ; -} - -template -void EdgeCollapse::Collapse( Profile const& aProfile, Placement_type aPlacement ) -{ - - CGAL_SMS_TRACE(1,"S" << mStep << ". Collapsing " << edge_to_string(aProfile.v0_v1()) ) ; - - vertex_descriptor rResult ; - - Visitor.OnCollapsing(aProfile,aPlacement); - - -- mCurrentEdgeCount ; - - CGAL_SURF_SIMPL_TEST_assertion_code( size_type lResultingVertexCount = mSurface.size_of_vertices() ; - size_type lResultingEdgeCount = mSurface.size_of_halfedges() / 2 ; - ) ; - - // If the top/bottom facets exists, they are removed and the edges v0vt and Q-B along with them. - // In that case their corresponding pairs must be pop off the queue - - if ( aProfile.left_face_exists() ) - { - halfedge_descriptor lV0VL = primary_edge(aProfile.vL_v0()); - if ( is_constrained(lV0VL) ) //make sure a constrained edge will not disappear - lV0VL=primary_edge(aProfile.v1_vL()); - - CGAL_SMS_TRACE(3,"V0VL E" << get(Edge_index_map,lV0VL) - << "(V" << get(Vertex_index_map, source(lV0VL,mSurface)) << "->V" << get(Vertex_index_map,target(lV0VL,mSurface)) << ")" - ) ; - - Edge_data& lData = get_data(lV0VL) ; - if ( lData.is_in_PQ() ) - { - CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map,lV0VL) << " from PQ" ) ; - remove_from_PQ(lV0VL,lData) ; - } - - -- mCurrentEdgeCount ; - CGAL_SURF_SIMPL_TEST_assertion_code( -- lResultingEdgeCount ) ; - } - - if ( aProfile.right_face_exists() ) - { - halfedge_descriptor lVRV1 = primary_edge(aProfile.vR_v1()); - if ( is_constrained(lVRV1) ) //make sure a constrained edge will not disappear - lVRV1=primary_edge(aProfile.v0_vR()); - - CGAL_SMS_TRACE(3,"V1VRE" << get(Edge_index_map,lVRV1) - << "(V" << get(Vertex_index_map, source(lVRV1,mSurface)) << "->V" << get(Vertex_index_map, target(lVRV1,mSurface)) << ")" - ) ; - - Edge_data& lData = get_data(lVRV1) ; - if ( lData.is_in_PQ() ) - { - CGAL_SMS_TRACE(2,"Removing E" << get(Edge_index_map,lVRV1) << " from PQ") ; - remove_from_PQ(lVRV1,lData) ; - } - -- mCurrentEdgeCount ; - CGAL_SURF_SIMPL_TEST_assertion_code( -- lResultingEdgeCount ) ; - } - - CGAL_SMS_TRACE(1,"Removing:\n v0v1: E" << get(Edge_index_map,aProfile.v0_v1()) << "(V" << get(Vertex_index_map,aProfile.v0()) << "->V" << get(Vertex_index_map,aProfile.v1()) << ")" ); - - - // Perform the actuall collapse. - // This is an external function. - // It's REQUIRED to remove ONLY 1 vertex (P or Q) and edges PQ,PT and QB - // (PT and QB are removed if they are not null). - // All other edges must be kept. - // All directed edges incident to vertex removed are relink to the vertex kept. - rResult = halfedge_collapse_bk_compatibility(aProfile.v0_v1(), Edge_is_constrained_map); - - CGAL_SURF_SIMPL_TEST_assertion_code( -- lResultingEdgeCount ) ; - - CGAL_SURF_SIMPL_TEST_assertion_code( -- lResultingVertexCount ) ; - - CGAL_SURF_SIMPL_TEST_assertion( lResultingEdgeCount * 2 == mSurface.size_of_halfedges() ) ; - - CGAL_SURF_SIMPL_TEST_assertion( lResultingVertexCount == mSurface.size_of_vertices() ) ; - - CGAL_SURF_SIMPL_TEST_assertion( mSurface.is_valid() && mSurface.is_pure_triangle() ) ; - - CGAL_SMS_TRACE(1,"V" << get(Vertex_index_map,rResult) << " kept." ) ; - -#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE - out_edge_iterator eb1, ee1 ; - for ( boost::tie(eb1,ee1) = halfedges_around_source(rResult,mSurface) ; eb1 != ee1 ; ++ eb1 ) - CGAL_SMS_TRACE(2, edge_to_string(*eb1) ) ; -#endif - - if ( aPlacement ) - { - CGAL_SMS_TRACE(1,"New vertex point: " << xyz_to_string(*aPlacement) ) ; - put(Vertex_point_map,rResult,*aPlacement) ; - } - - Visitor.OnCollapsed(aProfile,rResult); - - Update_neighbors(rResult) ; - - CGAL_SMS_DEBUG_CODE ( ++mStep ; ) -} - -template -void EdgeCollapse::Update_neighbors( vertex_descriptor const& aKeptV ) -{ - CGAL_SMS_TRACE(3,"Updating cost of neighboring edges..." ) ; - - // - // (A) Collect all edges to update their cost: all those around each vertex adjacent to the vertex kept - // - - typedef std::set edges ; - - edges lToUpdate(Compare_id(this)) ; - edges lToInsert(Compare_id(this)) ; - - // (A.1) Loop around all vertices adjacent to the vertex kept - in_edge_iterator eb1, ee1 ; - for ( boost::tie(eb1,ee1) = halfedges_around_target(aKeptV,mSurface) ; eb1 != ee1 ; ++ eb1 ) - { - halfedge_descriptor lEdge1 = *eb1 ; - - vertex_descriptor lAdj_k = source(lEdge1,mSurface); - - // (A.2) Loop around all edges incident on each adjacent vertex - in_edge_iterator eb2, ee2 ; - for ( boost::tie(eb2,ee2) = halfedges_around_target(lAdj_k,mSurface) ; eb2 != ee2 ; ++ eb2 ) - { - halfedge_descriptor lEdge2 = primary_edge(*eb2) ; - - Edge_data& lData2 = get_data(lEdge2); - CGAL_SMS_TRACE(4,"Inedge around V" << get(Vertex_index_map,lAdj_k) << edge_to_string(lEdge2) ) ; - - // Only edges still in the PQ needs to be updated, the other needs to be re-inserted - if ( lData2.is_in_PQ() ) - lToUpdate.insert(lEdge2) ; - else - lToInsert.insert(lEdge2) ; - } - } - - // - // (B) Proceed to update the costs. - // - - for ( typename edges::iterator it = lToUpdate.begin(), eit = lToUpdate.end() ; it != eit ; ++ it ) - { - halfedge_descriptor lEdge = *it; - - Edge_data& lData = get_data(lEdge); - - Profile const& lProfile = create_profile(lEdge); - - lData.cost() = get_cost(lProfile) ; - - CGAL_SMS_TRACE(3, edge_to_string(lEdge) << " updated in the PQ") ; - - update_in_PQ(lEdge,lData); - } - - // - // (C) Insert ignored edges - // - // I think that this should be done for edges eliminated because of the geometric criteria - // and not the topological one.However maintaining such a set might be more expensive - // and hard to be safe ... - for ( typename edges::iterator it = lToInsert.begin(), - eit = lToInsert.end() ; it != eit ; ++ it ) - { - halfedge_descriptor lEdge = *it; - if ( is_constrained(lEdge) ) continue; //do not insert constrained edges - Edge_data& lData = get_data(lEdge); - - Profile const& lProfile = create_profile(lEdge); - - lData.cost() = get_cost(lProfile) ; - - CGAL_SMS_TRACE(3, edge_to_string(lEdge) << " re-inserted in the PQ") ; - - insert_in_PQ(lEdge,lData); - } -} - - -} // namespace Surface_mesh_simplification - -} //namespace CGAL - -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_COLLAPSE_IMPL_H // -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Edge_collapse_visitor_base.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Edge_collapse_visitor_base.h index 5c8c51c46cb..ad6a367b29d 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Edge_collapse_visitor_base.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Edge_collapse_visitor_base.h @@ -22,52 +22,37 @@ #include - #include #include namespace CGAL { - -namespace Surface_mesh_simplification -{ +namespace Surface_mesh_simplification { template struct Edge_collapse_visitor_base { - typedef TM_ TM ; - - typedef Edge_profile Profile ; - - typedef boost::graph_traits GraphTraits ; - - typedef typename GraphTraits::edges_size_type size_type ; - typedef typename GraphTraits::vertex_descriptor vertex_descriptor ; - typedef typename boost::property_map::type Vertex_point_pmap; - typedef typename boost::property_traits::value_type Point; - typedef typename Kernel_traits::Kernel Kernel ; - typedef typename Kernel::FT FT ; - - void OnStarted( TM& ) {} - - void OnFinished ( TM& ) {} - - void OnStopConditionReached( Profile const& ) {} - - void OnCollected( Profile const&, boost::optional const& ) {} - - void OnSelected( Profile const&, boost::optional const&, size_type, size_type ) {} - - void OnCollapsing(Profile const&, boost::optional const& ) {} - - void OnCollapsed( Profile const&, vertex_descriptor const& ) {} + typedef TM_ TM; + typedef Edge_profile Profile; + typedef boost::graph_traits GraphTraits; - void OnNonCollapsable(Profile const& ) {} -} ; + typedef typename GraphTraits::edges_size_type size_type; + typedef typename GraphTraits::vertex_descriptor vertex_descriptor; + typedef typename boost::property_map::type Vertex_point_pmap; + typedef typename boost::property_traits::value_type Point; + typedef typename Kernel_traits::Kernel Kernel; + typedef typename Kernel::FT FT; + + void OnStarted(TM&) {} + void OnFinished(TM&) {} + void OnStopConditionReached(const Profile&) {} + void OnCollected(const Profile&, const boost::optional&) {} + void OnSelected(const Profile&, const boost::optional&, size_type, size_type) {} + void OnCollapsing(const Profile&, const boost::optional&) {} + void OnCollapsed(const Profile&, const vertex_descriptor&) {} + void OnNonCollapsable(const Profile&) {} +}; } // namespace Surface_mesh_simplification +} // namespace CGAL -} //namespace CGAL - -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_EDGE_COLLAPSE_VISITOR_BASE_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_EDGE_COLLAPSE_VISITOR_BASE_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/HalfedgeGraph_Polyhedron_3.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/HalfedgeGraph_Polyhedron_3.h index eff63b905d9..83b77c9f23f 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/HalfedgeGraph_Polyhedron_3.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/HalfedgeGraph_Polyhedron_3.h @@ -22,11 +22,7 @@ #include - #include #include #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_HALFEDGEGRAPH_POLYHEDRON_3_H -// EOF // - - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h index bc53b7f5e2a..c9b26a949ee 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Bounded_normal_change_placement.h @@ -24,57 +24,55 @@ #include namespace CGAL { - -namespace Surface_mesh_simplification -{ +namespace Surface_mesh_simplification { template class Bounded_normal_change_placement { public: - - typedef typename Placement::TM TM ; - -public: - - Bounded_normal_change_placement(const Placement& placement = Placement() ) + typedef typename Placement::TM TM; + + Bounded_normal_change_placement(const Placement& placement = Placement()) : mPlacement(placement) {} - - template + + template boost::optional - operator()( Profile const& aProfile) const + operator()(const Profile& aProfile) const { boost::optional op = mPlacement(aProfile); - if(op){ + if(op) + { // triangles returns the triangles of the star of the vertices of the edge to collapse // First the two trianges incident to the edge, then the other triangles // The second vertex of each triangle is the vertex that gets placed const typename Profile::Triangle_vector& triangles = aProfile.triangles(); - if(triangles.size()>2){ + if(triangles.size() > 2) + { typedef typename Profile::Point Point; typedef typename Profile::Kernel Traits; typedef typename Traits::Vector_3 Vector; typename Profile::VertexPointMap ppmap = aProfile.vertex_point_map(); typename Profile::Triangle_vector::const_iterator it = triangles.begin(); - if(aProfile.left_face_exists()){ - ++it; - } - if(aProfile.right_face_exists()){ + + if(aProfile.left_face_exists()) ++it; - } - while(it!= triangles.end()){ + if(aProfile.right_face_exists()) + ++it; + + while(it!= triangles.end()) + { const typename Profile::Triangle& t = *it; Point p = get(ppmap,t.v0); Point q = get(ppmap,t.v1); Point r = get(ppmap,t.v2); Point q2 = *op; - - Vector eqp = Traits().construct_vector_3_object()(q,p) ; - Vector eqr = Traits().construct_vector_3_object()(q,r) ; - Vector eq2p = Traits().construct_vector_3_object()(q2,p) ; - Vector eq2r = Traits().construct_vector_3_object()(q2,r) ; - + + Vector eqp = Traits().construct_vector_3_object()(q,p); + Vector eqr = Traits().construct_vector_3_object()(q,r); + Vector eq2p = Traits().construct_vector_3_object()(q2,p); + Vector eq2r = Traits().construct_vector_3_object()(q2,r); + Vector n1 = Traits().construct_cross_product_vector_3_object()(eqp,eqr); Vector n2 = Traits().construct_cross_product_vector_3_object()(eq2p,eq2r); if(! is_positive(Traits().compute_scalar_product_3_object()(n1, n2))){ @@ -86,18 +84,12 @@ public: } return op; } - + private: - - Placement mPlacement ; - + Placement mPlacement; }; - } // namespace Surface_mesh_simplification - } //namespace CGAL #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_BOUNDED_NORMAL_CHANGE_PLACEMENT_H - - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h index 81f97dc1741..1f9319e194e 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Constrained_placement.h @@ -22,48 +22,44 @@ #include - #include #include namespace CGAL { - -namespace Surface_mesh_simplification -{ +namespace Surface_mesh_simplification { template -class Constrained_placement : public BasePlacement +class Constrained_placement + : public BasePlacement { public: - EdgeIsConstrainedMap Edge_is_constrained_map; -public: - Constrained_placement( - EdgeIsConstrainedMap map=EdgeIsConstrainedMap(), - BasePlacement base=BasePlacement() ) - : BasePlacement(base) - , Edge_is_constrained_map(map) + Constrained_placement(EdgeIsConstrainedMap map=EdgeIsConstrainedMap(), + BasePlacement base=BasePlacement()) + : BasePlacement(base), + Edge_is_constrained_map(map) {} template - optional operator()( Profile const& aProfile ) const + optional operator()(const Profile& aProfile) const { typedef typename Profile::TM TM; typedef typename CGAL::Halfedge_around_target_iterator in_edge_iterator; - in_edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = halfedges_around_target(aProfile.v0(),aProfile.surface_mesh()); - eb != ee ; ++ eb ) + in_edge_iterator eb, ee; + for(boost::tie(eb,ee) = halfedges_around_target(aProfile.v0(),aProfile.surface_mesh()); + eb != ee; ++ eb) { - if( get(Edge_is_constrained_map, edge(*eb,aProfile.surface_mesh())) ) + if(get(Edge_is_constrained_map, edge(*eb,aProfile.surface_mesh()))) return get(aProfile.vertex_point_map(), aProfile.v0()); } - for ( boost::tie(eb,ee) = halfedges_around_target(aProfile.v1(),aProfile.surface_mesh()); - eb != ee ; ++ eb ) + + for(boost::tie(eb,ee) = halfedges_around_target(aProfile.v1(),aProfile.surface_mesh()); + eb != ee; ++ eb) { - if( get(Edge_is_constrained_map, edge(*eb,aProfile.surface_mesh())) ) + if(get(Edge_is_constrained_map, edge(*eb,aProfile.surface_mesh()))) return get(aProfile.vertex_point_map(), aProfile.v1()); } @@ -73,7 +69,6 @@ public: }; } // namespace Surface_mesh_simplification - } //namespace CGAL #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_CONSTRAINED_PLACEMENT_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h index dc2e13b4810..b3a665940f4 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_ratio_stop_predicate.h @@ -22,14 +22,11 @@ #include - #include #include namespace CGAL { - -namespace Surface_mesh_simplification -{ +namespace Surface_mesh_simplification { //******************************************************************************************************************* // -= stopping condition predicate =- @@ -39,42 +36,33 @@ namespace Surface_mesh_simplification // //******************************************************************************************************************* -// // Stops when the ratio of initial to current vertex pairs is below some value. -// -template +template class Count_ratio_stop_predicate { public: + typedef TM_ TM; + typedef Edge_profile Profile; - typedef TM_ TM ; - - typedef Edge_profile Profile ; - - typedef typename boost::graph_traits::edge_descriptor edge_descriptor ; - typedef typename boost::graph_traits::edges_size_type size_type ; - - Count_ratio_stop_predicate( double aRatio ) : mRatio(aRatio) {} - - template - bool operator()( F const& // aCurrentCost - , Profile const& // aEdgeProfile - , size_type aInitialCount - , size_type aCurrentCount - ) const + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::edges_size_type size_type; + + Count_ratio_stop_predicate(double aRatio) : mRatio(aRatio) {} + + template + bool operator()(const F&, // aCurrentCost + const Profile&, // aEdgeProfile + size_type aInitialCount, + size_type aCurrentCount) const { - return ( static_cast(aCurrentCount) / static_cast(aInitialCount) ) < mRatio ; + return (static_cast(aCurrentCount) / static_cast(aInitialCount)) < mRatio; } - + private: - - double mRatio ; -}; + double mRatio; +}; } // namespace Surface_mesh_simplification - } //namespace CGAL -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_RATIO_STOP_PREDICATE_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_RATIO_STOP_PREDICATE_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h index 0099e126d31..6248bb5776f 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Count_stop_predicate.h @@ -18,18 +18,15 @@ // Author(s) : Fernando Cacciola // #ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_STOP_PREDICATE_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_STOP_PREDICATE_H 1 +#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_STOP_PREDICATE_H #include - #include #include namespace CGAL { - -namespace Surface_mesh_simplification -{ +namespace Surface_mesh_simplification { //******************************************************************************************************************* // -= stopping condition predicate =- @@ -39,45 +36,30 @@ namespace Surface_mesh_simplification // //******************************************************************************************************************* -// // Stops when the number of edges left falls below a given number. -// -template +template class Count_stop_predicate { public: + typedef TM_ TM; + typedef typename boost::graph_traits::edges_size_type size_type; - typedef TM_ TM ; + Count_stop_predicate(std::size_t aThres) : mThres(aThres) {} - // typedef Edge_profile Profile ; - - typedef typename boost::graph_traits::edges_size_type size_type ; - - // typedef typename Kernel::FT FT ; - -public : - - Count_stop_predicate( std::size_t aThres ) : mThres(aThres) {} - - template - bool operator()( F const& // aCurrentCost - , Profile const& // aEdgeProfile - , std::size_t // aInitialCount - , std::size_t aCurrentCount - ) const + template + bool operator()(const F&, // aCurrentCost + const Profile&, // aEdgeProfile + std::size_t, // aInitialCount + std::size_t aCurrentCount) const { - return aCurrentCount < mThres ; + return aCurrentCount < mThres; } - + private: - - std::size_t mThres ; -}; + std::size_t mThres; +}; } // namespace Surface_mesh_simplification - } //namespace CGAL -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_STOP_PREDICATE_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_COUNT_STOP_PREDICATE_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core.h index 291c4342654..f453d2b5af4 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core.h @@ -22,180 +22,740 @@ #include - -#include - #include #include #include #include -namespace CGAL { +#include -// -// This should be in +// This should be in // // Implementation of the collapsing cost and placement strategy from: // // "Fast and Memory Efficient Polygonal Symplification" // Peter Lindstrom, Greg Turk -// -namespace Surface_mesh_simplification -{ +namespace CGAL { +namespace Surface_mesh_simplification { - template +template class LindstromTurkCore { public: - - typedef TM_ TM ; - typedef Profile_ Profile ; - - typedef boost::graph_traits GraphTraits ; - - typedef typename GraphTraits::vertex_descriptor vertex_descriptor ; - typedef typename GraphTraits::halfedge_descriptor halfedge_descriptor ; - - typedef LindstromTurk_params Params ; - - typedef typename Profile::Point Point ; + typedef TM_ TM; + typedef Profile_ Profile; - typedef typename Profile::VertexPointMap Vertex_point_pmap; + typedef boost::graph_traits GraphTraits; + + typedef typename GraphTraits::vertex_descriptor vertex_descriptor; + typedef typename GraphTraits::halfedge_descriptor halfedge_descriptor; + + typedef LindstromTurk_params Params; + + typedef typename Profile::Point Point; + typedef typename Profile::VertexPointMap Vertex_point_pmap; typedef typename boost::property_traits::value_type TM_Point; - - typedef typename Kernel_traits::Kernel TM_Kernel ; - - typedef typename Kernel_traits::Kernel Kernel; - typedef typename Kernel::Vector_3 Vector ; - typedef typename Kernel::FT FT ; - - typedef optional Optional_FT ; - typedef optional Optional_point ; - typedef optional Optional_vector ; - - typedef MatrixC33 Matrix ; - - typedef typename Profile::Triangle Triangle ; - typedef typename Profile::vertex_descriptor_vector vertex_descriptor_vector ; - - typedef typename Profile::Triangle_vector ::const_iterator const_triangle_iterator ; - typedef typename Profile::halfedge_descriptor_vector::const_iterator const_border_edge_iterator ; - -public: - - LindstromTurkCore( Params const& aParams, Profile const& aProfile ) ; - - Optional_point compute_placement() ; - Optional_FT compute_cost( Optional_point const& p ) ; - -private : + typedef typename Kernel_traits::Kernel TM_Kernel; + + typedef typename Kernel_traits::Kernel Kernel; + typedef typename Kernel::Vector_3 Vector; + typedef typename Kernel::FT FT; + + typedef optional Optional_FT; + typedef optional Optional_point; + typedef optional Optional_vector; + + typedef MatrixC33 Matrix; + + typedef typename Profile::Triangle Triangle; + typedef typename Profile::vertex_descriptor_vector vertex_descriptor_vector; + + typedef typename Profile::Triangle_vector::const_iterator const_triangle_iterator; + typedef typename Profile::halfedge_descriptor_vector::const_iterator const_border_edge_iterator; + +public: + LindstromTurkCore(Params const& aParams, const Profile& aProfile); + + Optional_point compute_placement(); + Optional_FT compute_cost(const Optional_point& p); + +private : struct Triangle_data { - Triangle_data( Vector const& aNormalV, FT const& aNormalL ) : NormalV(aNormalV), NormalL(aNormalL) {} - - Vector NormalV ; - FT NormalL ; - } ; + Triangle_data(const Vector& aNormalV, const FT& aNormalL) + : NormalV(aNormalV), NormalL(aNormalL) + {} + + Vector NormalV; + FT NormalL; + }; + struct Boundary_data { - Boundary_data ( Point s_, Point t_, Vector const& v_, Vector const& n_ ) : s(s_), t(t_), v(v_), n(n_) {} + Boundary_data(Point s_, Point t_, const Vector& v_, const Vector& n_) + : s(s_), t(t_), v(v_), n(n_) {} + + Point s, t; + Vector v, n; + }; + + typedef std::vector Triangle_data_vector; + typedef std::vector Boundary_data_vector; - Point s, t ; - Vector v, n ; - } ; - typedef std::vector Triangle_data_vector ; - typedef std::vector Boundary_data_vector ; - private : - - void Extract_triangle_data(); - void Extract_boundary_data(); - - void Add_boundary_preservation_constraints( Boundary_data_vector const& aBdry ) ; - void Add_volume_preservation_constraints( Triangle_data_vector const& aTriangles ); - void Add_boundary_and_volume_optimization_constraints( Boundary_data_vector const& aBdry, Triangle_data_vector const& aTriangles ) ; - void Add_shape_optimization_constraints( vertex_descriptor_vector const& aLink ) ; + void extract_triangle_data(); + void extract_boundary_data(); - FT Compute_boundary_cost( Vector const& v, Boundary_data_vector const& aBdry ) ; - FT Compute_volume_cost ( Vector const& v, Triangle_data_vector const& aTriangles ) ; - FT Compute_shape_cost ( Point const& p, vertex_descriptor_vector const& aLink ) ; + void add_boundary_preservation_constraints(const Boundary_data_vector& aBdry); + void add_volume_preservation_constraints(const Triangle_data_vector& aTriangles); + void add_boundary_and_volume_optimization_constraints(const Boundary_data_vector& aBdry, const Triangle_data_vector& aTriangles); + void add_shape_optimization_constraints(const vertex_descriptor_vector& aLink); - Point get_point ( vertex_descriptor const& v ) const + FT compute_boundary_cost(const Vector& v, const Boundary_data_vector& aBdry); + FT compute_volume_cost(const Vector& v, const Triangle_data_vector& aTriangles); + FT compute_shape_cost(Point const& p, const vertex_descriptor_vector& aLink); + + Point get_point(const vertex_descriptor v) const { - return convert(get(mProfile.vertex_point_map(),v)); + return convert(get(mProfile.vertex_point_map(), v)); } - static Vector Point_cross_product ( Point const& a, Point const& b ) + static Vector point_cross_product(const Point& a, const Point& b) { - return cross_product(a-ORIGIN,b-ORIGIN); + return cross_product(a-ORIGIN, b-ORIGIN); } // This is the (uX)(Xu) product described in the Lindstrom-Turk paper - static Matrix LT_product( Vector const& u ) + static Matrix LT_product(const Vector& u) { - FT a00 = ( u.y()*u.y() ) + ( u.z()*u.z() ) ; + FT a00 = (u.y()*u.y()) + (u.z()*u.z()); FT a01 = -u.x()*u.y(); FT a02 = -u.x()*u.z(); - - FT a10 = a01 ; - FT a11 = ( u.x()*u.x() ) + ( u.z()*u.z() ) ; - FT a12 = - u.y() * u.z(); - - FT a20 = a02 ; - FT a21 = a12 ; - FT a22 = ( u.x()*u.x() ) + ( u.y()*u.y() ) ; - - return Matrix(a00,a01,a02 - ,a10,a11,a12 - ,a20,a21,a22 - ); - } - - static FT big_value() { return static_cast((std::numeric_limits::max)()) ; } - static bool is_finite ( FT const& n ) { return CGAL_NTS is_finite(n) ; } - static bool is_finite ( Point const& p ) { return is_finite(p.x()) && is_finite(p.y()) && is_finite(p.z()) ; } - static bool is_finite ( Vector const& v ) { return is_finite(v.x()) && is_finite(v.y()) && is_finite(v.z()) ; } - static bool is_finite ( Matrix const& m ) { return is_finite(m.r0()) && is_finite(m.r1()) && is_finite(m.r2()) ; } + FT a10 = a01; + FT a11 = (u.x()*u.x()) + (u.z()*u.z()); + FT a12 = - u.y() * u.z(); + + FT a20 = a02; + FT a21 = a12; + FT a22 = (u.x()*u.x()) + (u.y()*u.y()); + + return Matrix(a00, a01, a02, + a10, a11, a12, + a20, a21, a22); + } + + static FT big_value() { return static_cast((std::numeric_limits::max)()); } + + static bool is_finite(const FT& n) { return CGAL_NTS is_finite(n); } + static bool is_finite(const Point& p) { return is_finite(p.x()) && is_finite(p.y()) && is_finite(p.z()); } + static bool is_finite(const Vector& v) { return is_finite(v.x()) && is_finite(v.y()) && is_finite(v.z()); } + static bool is_finite(const Matrix& m) { return is_finite(m.r0()) && is_finite(m.r1()) && is_finite(m.r2()); } template - static optional filter_infinity ( T const& n ) { return is_finite(n) ? optional(n) : optional() ; } + static optional filter_infinity (T const& n) { return is_finite(n) ? optional(n) : optional(); } - TM& surface() const { return mProfile.surface() ; } - -private: + TM& surface() const { return mProfile.surface(); } - Params const& mParams ; - Profile const& mProfile ; +private: + Params const& mParams; + const Profile& mProfile; - void Add_constraint_if_alpha_compatible( Vector const& Ai, FT const& bi ) ; - - void Add_constraint_from_gradient ( Matrix const& H, Vector const& c ) ; + void add_constraint_if_alpha_compatible(const Vector& Ai, const FT& bi); + void add_constraint_from_gradient(const Matrix& H, const Vector& c); -private: +private: + Triangle_data_vector mTriangle_data; + Boundary_data_vector mBdry_data; - Triangle_data_vector mTriangle_data ; - Boundary_data_vector mBdry_data ; - - int mConstraints_n ; - Matrix mConstraints_A ; - Vector mConstraints_b ; + int mConstraints_n; + Matrix mConstraints_A; + Vector mConstraints_b; - Cartesian_converter convert ; + Cartesian_converter convert; FT mSquared_cos_alpha; FT mSquared_sin_alpha; }; +template +LindstromTurkCore:: +LindstromTurkCore(Params const& aParams, const Profile& aProfile) + : + mParams(aParams), + mProfile(aProfile), + mConstraints_n(0), + mConstraints_A(NULL_MATRIX), + mConstraints_b(NULL_VECTOR) +{ + double alpha = 1.0 * CGAL_PI / 180.0; + + FT cos_alpha = std::cos(alpha); + FT sin_alpha = std::sin(alpha); + + mSquared_cos_alpha = cos_alpha * cos_alpha; + mSquared_sin_alpha = sin_alpha * sin_alpha; + + extract_triangle_data(); + extract_boundary_data(); +} + +template +void +LindstromTurkCore:: +extract_boundary_data() +{ + mBdry_data.reserve(mProfile.border_edges().size()); + for(const_border_edge_iterator it = mProfile.border_edges().begin(), eit = mProfile.border_edges().end(); it != eit; ++ it) + { + halfedge_descriptor border_edge = *it; + halfedge_descriptor face_edge = opposite(border_edge,surface()); + + vertex_descriptor sv = source(face_edge,surface()); + vertex_descriptor tv = target(face_edge,surface()); + + const Point& sp = get_point(sv); + const Point& tp = get_point(tv); + + Vector v = tp - sp; + Vector n = point_cross_product(tp,sp); + + CGAL_SMS_LT_TRACE(1, " Boundary edge. S:" << xyz_to_string(sp) << " T:" << xyz_to_string(tp) + << " V:" << xyz_to_string(v) << " N:" << xyz_to_string(n)); + + mBdry_data.push_back(Boundary_data(sp,tp,v,n)); + } +} + +template +void +LindstromTurkCore:: +extract_triangle_data() +{ + mTriangle_data.reserve(mProfile.triangles().size()); + for(const_triangle_iterator it = mProfile.triangles().begin(), eit = mProfile.triangles().end(); it != eit; ++ it) + { + Triangle const& tri = *it; + + const Point& p0 = get_point(tri.v0); + const Point& p1 = get_point(tri.v1); + const Point& p2 = get_point(tri.v2); + + Vector v01 = p1 - p0; + Vector v02 = p2 - p0; + + Vector lNormalV = cross_product(v01,v02); + FT lNormalL = point_cross_product(p0,p1) * (p2-ORIGIN); + + CGAL_SMS_LT_TRACE(1, " Extracting triangle v" << tri.v0 << "->v" << tri.v1 << "->v" << tri.v2 + << " N:" << xyz_to_string(lNormalV) << " L:" << n_to_string(lNormalL)); + + mTriangle_data.push_back(Triangle_data(lNormalV,lNormalL)); + } +} + +template +typename LindstromTurkCore::Optional_point +LindstromTurkCore:: +compute_placement() +{ + Optional_point rPlacementP; + Optional_vector lPlacementV; + + CGAL_SMS_LT_TRACE(0, "Computing LT placement for E" << mProfile.v0_v1() + << " (V" << mProfile.v0() << "->V" << mProfile.v1() << ")"); + + // Each vertex constraint is an equation of the form: Ai * v = bi + // Where 'v' is a vector representing the vertex, + // 'Ai' is a (row) vector and 'bi' a scalar. + // + // The vertex is completely determined with 3 such constraints, + // so is the solution to the folloing system: + // + // A.r0(). * v = b0 + // A1 * v = b1 + // A2 * v = b2 + // + // Which in matrix form is : A * v = b + // + // (with 'A' a 3x3 matrix and 'b' a vector) + // + // The member variable mConstrinas contains A and b. Indidivual constraints (Ai,bi) can be added to it. + // Once 3 such constraints have been added 'v' is directly solved a: + // + // v = b*inverse(A) + // + // A constraint (Ai,bi) must be alpha-compatible with the previously added constraints (see Paper); if it's not, is discarded. + // + if(mBdry_data.size() > 0) + add_boundary_preservation_constraints(mBdry_data); + + if(mConstraints_n < 3) + add_volume_preservation_constraints(mTriangle_data); + + if(mConstraints_n < 3) + add_boundary_and_volume_optimization_constraints(mBdry_data,mTriangle_data); + + if(mConstraints_n < 3) + add_shape_optimization_constraints(mProfile.link()); + + // It might happen that there were not enough alpha-compatible constraints. + // In that case there is simply no good vertex placement + if(mConstraints_n == 3) + { + // If the matrix is singular it's inverse cannot be computed so an 'absent' value is returned. + optional lOptional_Ai = inverse_matrix(mConstraints_A); + if(lOptional_Ai) + { + const Matrix& lAi = *lOptional_Ai; + + CGAL_SMS_LT_TRACE(2," b: " << xyz_to_string(mConstraints_b)); + CGAL_SMS_LT_TRACE(2," inv(A): " << matrix_to_string(lAi)); + + lPlacementV = filter_infinity(mConstraints_b * lAi); + + CGAL_SMS_LT_TRACE(0," New vertex point: " << xyz_to_string(*lPlacementV)); + } + else + { + CGAL_SMS_LT_TRACE(1," Can't solve optimization, singular system."); + } + } + else + { + CGAL_SMS_LT_TRACE(1," Can't solve optimization, not enough alpha-compatible constraints."); + } + + if(lPlacementV) + rPlacementP = ORIGIN + (*lPlacementV); + + return rPlacementP; +} + +template +typename LindstromTurkCore::Optional_FT +LindstromTurkCore:: +compute_cost(const Optional_point& aP) +{ + Optional_FT rCost; + + if(aP) + { + CGAL_SMS_LT_TRACE(0,"Computing LT cost for E" << mProfile.v0_v1()); + Vector lV = (*aP) - ORIGIN; + + FT lSquaredLength = squared_distance(mProfile.p0(),mProfile.p1()); + + FT lBdryCost = compute_boundary_cost(lV ,mBdry_data); + FT lVolumeCost = compute_volume_cost(lV ,mTriangle_data); + FT lShapeCost = compute_shape_cost(*aP,mProfile.link()); + + FT lTotalCost = FT(mParams.VolumeWeight) * lVolumeCost + + FT(mParams.BoundaryWeight) * lBdryCost * lSquaredLength + + FT(mParams.ShapeWeight) * lShapeCost * lSquaredLength * lSquaredLength; + + rCost = filter_infinity(lTotalCost); + + CGAL_SMS_LT_TRACE(0, " Squared edge length: " << n_to_string(lSquaredLength) + << "\n Boundary cost: " << n_to_string(lBdryCost) << " weight: " << mParams.BoundaryWeight + << "\n Volume cost: " << n_to_string(lVolumeCost) << " weight: " << mParams.VolumeWeight + << "\n Shape cost: " << n_to_string(lShapeCost) << " weight: " << mParams.ShapeWeight + << "\n TOTAL COST: " << n_to_string(lTotalCost)); + + } + + return rCost; +} + +template +void +LindstromTurkCore:: +add_boundary_preservation_constraints(const Boundary_data_vector& aBdry) +{ + if(aBdry.size() > 0) + { + Vector e1 = NULL_VECTOR; + Vector e2 = NULL_VECTOR; + + FT e1x = FT(0), + e1y = FT(0), + e1z = FT(0); + + for(typename Boundary_data_vector::const_iterator it = aBdry.begin(); it != aBdry.end(); ++ it) + { + e1 = e1 + it->v; + e2 = e2 + it->n; + + FT vx = it->v.x(); + FT vy = it->v.y(); + FT vz = it->v.z(); + + e1x = e1x + vx; + e1y = e1y + vy; + e1z = e1z + vz; + + CGAL_SMS_LT_TRACE(1," vx:" << n_to_string(vx) << " vy:" << n_to_string(vy) << " vz:" << n_to_string(vz) << " e1x:" + << n_to_string(e1x) << " e1y:" << n_to_string(e1y) << " e1z:" << n_to_string(e1z)); + } + + Matrix H = LT_product(e1); + Vector c = cross_product(e1,e2); + + CGAL_SMS_LT_TRACE(1, " Adding boundary preservation constraint." + << "\n SumV:" << xyz_to_string(e1) + << "\n SumN:" << xyz_to_string(e2) + << "\n H:" << matrix_to_string(H) + << "\n c:" << xyz_to_string(c)); + + add_constraint_from_gradient(H,c); + } +} + +template +void +LindstromTurkCore:: +add_volume_preservation_constraints(const Triangle_data_vector& aTriangles) +{ + CGAL_SMS_LT_TRACE(1," Adding volume preservation constraint. " << aTriangles.size() << " triangles."); + + Vector lSumV = NULL_VECTOR; + FT lSumL(0); + + for(typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end(); it != eit; ++it) + { + lSumV = lSumV + it->NormalV; + lSumL = lSumL + it->NormalL; + } + + CGAL_SMS_LT_TRACE(1, " SumV:" << xyz_to_string(lSumV) << "\n SumL:" << n_to_string(lSumL)); + + add_constraint_if_alpha_compatible(lSumV,lSumL); +} + +template +void +LindstromTurkCore:: +add_boundary_and_volume_optimization_constraints(const Boundary_data_vector& aBdry, + const Triangle_data_vector& aTriangles) +{ + CGAL_SMS_LT_TRACE(1," Adding boundary and volume optimization constraints. "); + + Matrix H = NULL_MATRIX; + Vector c = NULL_VECTOR; + + // Volume optimization + for(typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end(); it != eit; ++it) + { + Triangle_data const& lTri = *it; + + H += direct_product(lTri.NormalV, lTri.NormalV); + + c = c - (lTri.NormalL * lTri.NormalV); + } + + CGAL_SMS_LT_TRACE(2," Hv:" << matrix_to_string(H) << "\n cv:" << xyz_to_string(c)); + + if(aBdry.size() > 0) + { + // Boundary optimization + Matrix Hb = NULL_MATRIX; + Vector cb = NULL_VECTOR; + + for(typename Boundary_data_vector::const_iterator it = aBdry.begin(); it != aBdry.end(); ++ it) + { + Matrix H = LT_product(it->v); + Vector c = cross_product(it->v,it->n); + + Hb += H; + cb = cb + c; + } + + CGAL_SMS_LT_TRACE(2," Hb:" << matrix_to_string(Hb) << "\n cb:" << xyz_to_string(cb)); + + // Weighted average + FT lScaledBoundaryWeight = FT(9) * FT(mParams.BoundaryWeight) * squared_distance(mProfile.p0(),mProfile.p1()) ; + + H *= mParams.VolumeWeight; + c = c * mParams.VolumeWeight; + + H += lScaledBoundaryWeight * Hb; + c = c + (lScaledBoundaryWeight * cb); + + CGAL_SMS_LT_TRACE(2," H:" << matrix_to_string(H) << "\n c:" << xyz_to_string(c)); + CGAL_SMS_LT_TRACE(2," VolW:" << mParams.VolumeWeight << " BdryW:" << mParams.BoundaryWeight << " ScaledBdryW:" << lScaledBoundaryWeight); + } + + add_constraint_from_gradient(H,c); +} + +template +void +LindstromTurkCore:: +add_shape_optimization_constraints(const vertex_descriptor_vector& aLink) +{ + FT s(double(aLink.size())); + + Matrix H (s, 0.0, 0.0, + 0.0, s, 0.0, + 0.0, 0.0, s); + + Vector c = NULL_VECTOR; + + for(typename vertex_descriptor_vector::const_iterator it = aLink.begin(), eit = aLink.end(); it != eit; ++it) + c = c + (ORIGIN - get_point(*it)); + + CGAL_SMS_LT_TRACE(1," Adding shape optimization constraint. Shape vector: " << xyz_to_string(c)); + + add_constraint_from_gradient(H,c); +} + +template +typename LindstromTurkCore::FT +LindstromTurkCore:: +compute_boundary_cost(const Vector& v, + const Boundary_data_vector& aBdry) +{ + FT rCost(0); + for(typename Boundary_data_vector::const_iterator it = aBdry.begin(); it != aBdry.end(); ++ it) + { + Vector u = (it->t - ORIGIN) - v; + Vector c = cross_product(it->v,u); + rCost += c*c; + } + + return rCost / FT(4); +} + +template +typename LindstromTurkCore::FT +LindstromTurkCore:: +compute_volume_cost(const Vector& v, + const Triangle_data_vector& aTriangles) +{ + FT rCost(0); + + for(typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end(); it != eit; ++it) + { + Triangle_data const& lTri = *it; + FT lF = lTri.NormalV * v - lTri.NormalL; + + rCost += (lF * lF); + } + + return rCost / FT(36); +} + +template +typename LindstromTurkCore::FT +LindstromTurkCore:: +compute_shape_cost(const Point& p, + const vertex_descriptor_vector& aLink) +{ + FT rCost(0); + + for(typename vertex_descriptor_vector::const_iterator it = aLink.begin(), eit = aLink.end(); it != eit; ++it) + rCost += squared_distance(p,get_point(*it)); + + return rCost; +} + +template +void +LindstromTurkCore:: +add_constraint_if_alpha_compatible(const Vector& Ai, + const FT& bi) +{ + CGAL_SMS_LT_TRACE(3, " Adding new constraints if alpha-compatible.\n Ai: " << xyz_to_string(Ai) << "\n bi:" << n_to_string(bi) << ")"); + + FT slai = Ai*Ai; + CGAL_SMS_LT_TRACE(3, "\n slai: " << n_to_string(slai) << ")"); + + if(is_finite(slai)) + { + FT l = CGAL_NTS sqrt(slai); + CGAL_SMS_LT_TRACE(3, " l: " << n_to_string(l)); + + if(!CGAL_NTS is_zero(l)) + { + Vector Ain = Ai / l; + FT bin = bi / l; + CGAL_SMS_LT_TRACE(3," Ain: " << xyz_to_string(Ain) << " bin:" << n_to_string(bin)); + + bool lAddIt = true; + + if(mConstraints_n == 1) + { + FT d01 = mConstraints_A.r0() * Ai ; + FT sla0 = mConstraints_A.r0() * mConstraints_A.r0(); + FT sd01 = d01 * d01; + FT max = sla0 * slai * mSquared_cos_alpha; + + CGAL_SMS_LT_TRACE(3," Second constraint. d01: " << n_to_string(d01) << " sla0:" << n_to_string(sla0) << " sd01:" << n_to_string(sd01) << " max:" << n_to_string(max)); + + if(sd01 > max) + lAddIt = false; + } + else if(mConstraints_n == 2) + { + Vector N = cross_product(mConstraints_A.r0(),mConstraints_A.r1()); + + FT dc012 = N * Ai; + + FT slc01 = N * N; + FT sdc012 = dc012 * dc012; + + FT min = slc01 * slai * mSquared_sin_alpha; + + CGAL_SMS_LT_TRACE(3, " Third constraint. N: " << xyz_to_string(N) << " dc012:" << n_to_string(dc012) << " slc01:" << n_to_string(slc01) + << " sdc012:" << n_to_string(sdc012) << " min:" << n_to_string(min)); + + if(sdc012 <= min) + lAddIt = false; + } + + if(lAddIt) + { + switch(mConstraints_n) + { + case 0: + mConstraints_A.r0() = Ain; + mConstraints_b = Vector(bin,mConstraints_b.y(),mConstraints_b.z()); + break; + case 1: + mConstraints_A.r1() = Ain; + mConstraints_b = Vector(mConstraints_b.x(),bin,mConstraints_b.z()); + break; + case 2: + mConstraints_A.r2() = Ain; + mConstraints_b = Vector(mConstraints_b.x(),mConstraints_b.y(),bin); + break; + } + + CGAL_SMS_LT_TRACE(3," Accepting # " << mConstraints_n << " A:" << matrix_to_string(mConstraints_A) << " b:" << xyz_to_string(mConstraints_b)); + + ++ mConstraints_n; + } + else + { + CGAL_SMS_LT_TRACE(3," INCOMPATIBLE. Discarded"); + } + } + else + { + CGAL_SMS_LT_TRACE(3," l is ZERO. Discarded"); + } + } + else + { + CGAL_SMS_LT_TRACE(3," OVERFLOW. Discarded"); + } +} + +template +int index_of_max_component (V const& v) +{ + typedef typename Kernel_traits::Kernel::FT FT; + + int i = 0; + FT max = v.x(); + + if(max < v.y()) + { + max = v.y(); + i = 1; + } + + if(max < v.z()) + { + max = v.z(); + i = 2; + } + + return i; +} + +template +void +LindstromTurkCore:: +add_constraint_from_gradient(const Matrix& H, + const Vector& c) +{ + CGAL_SMS_LT_TRACE(3," Adding constraint from gradient. Current n=" << mConstraints_n); + + CGAL_precondition(mConstraints_n >= 0 && mConstraints_n<=2); + + switch(mConstraints_n) + { + case 0: + add_constraint_if_alpha_compatible(H.r0(),-c.x()); + add_constraint_if_alpha_compatible(H.r1(),-c.y()); + add_constraint_if_alpha_compatible(H.r2(),-c.z()); + break; + case 1: + { + const Vector& A0 = mConstraints_A.r0(); + + CGAL_assertion(A0 != NULL_VECTOR); + + Vector AbsA0(CGAL::abs(A0.x()), + CGAL::abs(A0.y()), + CGAL::abs(A0.z())); + + Vector Q0; + switch(index_of_max_component(AbsA0)) + { + // Since A0 is guaranteed to be non-zero, the denominators here are known to be non-zero too. + + case 0: + Q0 = Vector(- A0.z()/A0.x(), 0, 1); + break; + case 1: + Q0 = Vector(0,- A0.z()/A0.y(), 1); + break; + case 2: + Q0 = Vector(1, 0, - A0.x()/A0.z()); + break; + default: + Q0 = NULL_VECTOR; // This should never happen! + } + + CGAL_SMS_LT_TRACE(3," Q0:" << xyz_to_string(Q0)); + + CGAL_assertion(Q0 != NULL_VECTOR); + + Vector Q1 = cross_product(A0,Q0); + + Vector A1 = H * Q0; + Vector A2 = H * Q1; + + FT b1 = - (Q0 * c); + FT b2 = - (Q1 * c); + + CGAL_SMS_LT_TRACE(3, " Q1:" << xyz_to_string(Q1) << "\n A1: " << xyz_to_string(A1) << "\n A2:" << xyz_to_string(A2) + << "\n b1:" << n_to_string(b1) << "\n b2:" << n_to_string(b2)); + + add_constraint_if_alpha_compatible(A1,b1); + add_constraint_if_alpha_compatible(A2,b2); + } + break; + + case 2: + { + Vector Q = cross_product(mConstraints_A.r0(),mConstraints_A.r1()); + Vector A2 = H * Q; + FT b2 = - (Q * c); + CGAL_SMS_LT_TRACE(3," Q:" << xyz_to_string(Q) << "\n A2: " << xyz_to_string(A2) << "\n b2:" << n_to_string(b2)); + + add_constraint_if_alpha_compatible(A2,b2); + } + break; + } +} + } // namespace Surface_mesh_simplification +} // namespace CGAL -} //namespace CGAL - -#include - -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_DETAIL_LINDSTROM_TURK_CORE_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_DETAIL_LINDSTROM_TURK_CORE_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core_impl.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core_impl.h deleted file mode 100644 index 95472f50957..00000000000 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Detail/Lindstrom_Turk_core_impl.h +++ /dev/null @@ -1,620 +0,0 @@ -// Copyright (c) 2005, 2006 Fernando Luis Cacciola Carballal. 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 Surface_mesh_simplification license may use this file in -// accordance with the Surface_mesh_simplification 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) : Fernando Cacciola -// -#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_DETAIL_LINDSTROM_TURK_CORE_IMPL_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_DETAIL_LINDSTROM_TURK_CORE_IMPL_H 1 - -#include - - -namespace CGAL { - - -// -// Implementation of the strategy from: -// -// "Fast and Memory Efficient Polygonal Symplification" -// Peter Lindstrom, Greg Turk -// - -namespace Surface_mesh_simplification -{ - -template -LindstromTurkCore::LindstromTurkCore( Params const& aParams, Profile const& aProfile ) - : - mParams(aParams) - ,mProfile(aProfile) - ,mConstraints_n(0) - ,mConstraints_A(NULL_MATRIX) - ,mConstraints_b(NULL_VECTOR) -{ - double alpha = 1.0 * CGAL_PI / 180.0; - - FT cos_alpha = std::cos(alpha); - FT sin_alpha = std::sin(alpha); - - mSquared_cos_alpha = cos_alpha * cos_alpha ; - mSquared_sin_alpha = sin_alpha * sin_alpha ; - - Extract_triangle_data(); - Extract_boundary_data(); -} - -template -void LindstromTurkCore::Extract_boundary_data() -{ - mBdry_data.reserve(mProfile.border_edges().size()); - for ( const_border_edge_iterator it = mProfile.border_edges().begin(), eit = mProfile.border_edges().end() ; it != eit ; ++ it ) - { - halfedge_descriptor border_edge = *it ; - - halfedge_descriptor face_edge = opposite(border_edge,surface()) ; - - vertex_descriptor sv = source(face_edge,surface()); - vertex_descriptor tv = target(face_edge,surface()); - - Point const& sp = get_point(sv); - Point const& tp = get_point(tv); - - Vector v = tp - sp ; - Vector n = Point_cross_product(tp,sp) ; - - CGAL_SMS_LT_TRACE(1," Boundary edge. S:" << xyz_to_string(sp) << " T:" << xyz_to_string(tp) - << " V:" << xyz_to_string(v) << " N:" << xyz_to_string(n) - ) ; - - mBdry_data.push_back( Boundary_data(sp,tp,v,n) ) ; - } -} - -template -void LindstromTurkCore::Extract_triangle_data() -{ - mTriangle_data.reserve(mProfile.triangles().size()); - for ( const_triangle_iterator it = mProfile.triangles().begin(), eit = mProfile.triangles().end() ; it != eit ; ++ it ) - { - Triangle const& tri = *it ; - - Point const& p0 = get_point(tri.v0); - Point const& p1 = get_point(tri.v1); - Point const& p2 = get_point(tri.v2); - - Vector v01 = p1 - p0 ; - Vector v02 = p2 - p0 ; - - Vector lNormalV = cross_product(v01,v02); - - FT lNormalL = Point_cross_product(p0,p1) * (p2-ORIGIN); - - CGAL_SMS_LT_TRACE(1," Extracting triangle v" << tri.v0 << "->v" << tri.v1 << "->v" << tri.v2 - << " N:" << xyz_to_string(lNormalV) << " L:" << n_to_string(lNormalL) - ); - - mTriangle_data.push_back(Triangle_data(lNormalV,lNormalL)); - } -} - -template -typename LindstromTurkCore::Optional_point LindstromTurkCore::compute_placement() -{ - Optional_point rPlacementP ; - Optional_vector lPlacementV ; - - CGAL_SMS_LT_TRACE(0,"Computing LT placement for E" << mProfile.v0_v1() << " (V" << mProfile.v0() << "->V" << mProfile.v1() << ")" ); - - // - // Each vertex constraint is an equation of the form: Ai * v = bi - // Where 'v' is a vector representing the vertex, - // 'Ai' is a (row) vector and 'bi' a scalar. - // - // The vertex is completely determined with 3 such constraints, - // so is the solution to the folloing system: - // - // A.r0(). * v = b0 - // A1 * v = b1 - // A2 * v = b2 - // - // Which in matrix form is : A * v = b - // - // (with 'A' a 3x3 matrix and 'b' a vector) - // - // The member variable mConstrinas contains A and b. Indidivual constraints (Ai,bi) can be added to it. - // Once 3 such constraints have been added 'v' is directly solved a: - // - // v = b*inverse(A) - // - // A constraint (Ai,bi) must be alpha-compatible with the previously added constraints (see Paper); if it's not, is discarded. - // - if ( mBdry_data.size() > 0 ) - Add_boundary_preservation_constraints(mBdry_data); - - if ( mConstraints_n < 3 ) - Add_volume_preservation_constraints(mTriangle_data); - - if ( mConstraints_n < 3 ) - Add_boundary_and_volume_optimization_constraints(mBdry_data,mTriangle_data); - - if ( mConstraints_n < 3 ) - Add_shape_optimization_constraints(mProfile.link()); - - // It might happen that there were not enough alpha-compatible constraints. - // In that case there is simply no good vertex placement - if ( mConstraints_n == 3 ) - { - // If the matrix is singular it's inverse cannot be computed so an 'absent' value is returned. - optional lOptional_Ai = inverse_matrix(mConstraints_A); - if ( lOptional_Ai ) - { - Matrix const& lAi = *lOptional_Ai ; - - CGAL_SMS_LT_TRACE(2," b: " << xyz_to_string(mConstraints_b) ); - CGAL_SMS_LT_TRACE(2," inv(A): " << matrix_to_string(lAi) ); - - lPlacementV = filter_infinity(mConstraints_b * lAi) ; - - CGAL_SMS_LT_TRACE(0," New vertex point: " << xyz_to_string(*lPlacementV) ); - } - else - { - CGAL_SMS_LT_TRACE(1," Can't solve optimization, singular system."); - } - } - else - { - CGAL_SMS_LT_TRACE(1," Can't solve optimization, not enough alpha-compatible constraints."); - } - - if ( lPlacementV ) - rPlacementP = ORIGIN + (*lPlacementV) ; - - return rPlacementP; -} - -template -typename LindstromTurkCore::Optional_FT LindstromTurkCore::compute_cost( Optional_point const& aP ) -{ - Optional_FT rCost ; - - if ( aP ) - { - CGAL_SMS_LT_TRACE(0,"Computing LT cost for E" << mProfile.v0_v1() ); - Vector lV = (*aP) - ORIGIN ; - - FT lSquaredLength = squared_distance(mProfile.p0(),mProfile.p1()); - - FT lBdryCost = Compute_boundary_cost(lV ,mBdry_data); - FT lVolumeCost = Compute_volume_cost (lV ,mTriangle_data); - FT lShapeCost = Compute_shape_cost (*aP,mProfile.link()); - - FT lTotalCost = FT(mParams.VolumeWeight) * lVolumeCost - + FT(mParams.BoundaryWeight) * lBdryCost * lSquaredLength - + FT(mParams.ShapeWeight) * lShapeCost * lSquaredLength * lSquaredLength ; - - rCost = filter_infinity(lTotalCost); - - CGAL_SMS_LT_TRACE(0, " Squared edge length: " << n_to_string(lSquaredLength) - << "\n Boundary cost: " << n_to_string(lBdryCost) << " weight: " << mParams.BoundaryWeight - << "\n Volume cost: " << n_to_string(lVolumeCost) << " weight: " << mParams.VolumeWeight - << "\n Shape cost: " << n_to_string(lShapeCost) << " weight: " << mParams.ShapeWeight - << "\n TOTAL COST: " << n_to_string(lTotalCost) - ); - - } - - return rCost; -} - - -template -void LindstromTurkCore::Add_boundary_preservation_constraints( Boundary_data_vector const& aBdry ) -{ - - if ( aBdry.size() > 0 ) - { - Vector e1 = NULL_VECTOR ; - Vector e2 = NULL_VECTOR ; - - FT e1x = FT(0.0), e1y = FT(0.0), e1z = FT(0.0) ; - - for ( typename Boundary_data_vector::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it ) - { - e1 = e1 + it->v ; - e2 = e2 + it->n ; - - FT vx = it->v.x() ; - FT vy = it->v.y() ; - FT vz = it->v.z() ; - - e1x = e1x + vx; - e1y = e1y + vy; - e1z = e1z + vz; - - CGAL_SMS_LT_TRACE(1," vx:" << n_to_string(vx) << " vy:" << n_to_string(vy) << " vz:" << n_to_string(vz) << " e1x:" - << n_to_string(e1x) << " e1y:" << n_to_string(e1y) << " e1z:" << n_to_string(e1z) ); - } - - Matrix H = LT_product(e1); - - Vector c = cross_product(e1,e2); - - CGAL_SMS_LT_TRACE(1 - ," Adding boundary preservation constraint." - << "\n SumV:" << xyz_to_string(e1) - << "\n SumN:" << xyz_to_string(e2) - << "\n H:" << matrix_to_string(H) - << "\n c:" << xyz_to_string(c) - ); - - Add_constraint_from_gradient(H,c); - } -} - -template -void LindstromTurkCore::Add_volume_preservation_constraints( Triangle_data_vector const& aTriangles ) -{ - CGAL_SMS_LT_TRACE(1," Adding volume preservation constraint. " << aTriangles.size() << " triangles."); - - Vector lSumV = NULL_VECTOR ; - FT lSumL(0) ; - - for( typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it ) - { - lSumV = lSumV + it->NormalV ; - lSumL = lSumL + it->NormalL ; - } - - CGAL_SMS_LT_TRACE(1, " SumV:" << xyz_to_string(lSumV) << "\n SumL:" << n_to_string(lSumL) ); - - Add_constraint_if_alpha_compatible(lSumV,lSumL); - -} - -template -void LindstromTurkCore::Add_boundary_and_volume_optimization_constraints( Boundary_data_vector const& aBdry - , Triangle_data_vector const& aTriangles - ) -{ - CGAL_SMS_LT_TRACE(1," Adding boundary and volume optimization constraints. "); - - Matrix H = NULL_MATRIX ; - Vector c = NULL_VECTOR ; - - // - // Volume optimization - // - for( typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it ) - { - Triangle_data const& lTri = *it ; - - H += direct_product(lTri.NormalV,lTri.NormalV) ; - - c = c - ( lTri.NormalL * lTri.NormalV ) ; - } - - CGAL_SMS_LT_TRACE(2," Hv:" << matrix_to_string(H) << "\n cv:" << xyz_to_string(c) ) ; - - - if ( aBdry.size() > 0 ) - { - // - // Boundary optimization - // - Matrix Hb = NULL_MATRIX ; - Vector cb = NULL_VECTOR ; - - for ( typename Boundary_data_vector::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it ) - { - Matrix H = LT_product(it->v); - Vector c = cross_product(it->v,it->n); - - Hb += H ; - cb = cb + c ; - } - - CGAL_SMS_LT_TRACE(2," Hb:" << matrix_to_string(Hb) << "\n cb:" << xyz_to_string(cb) ) ; - - // - // Weighted average - // - FT lScaledBoundaryWeight = FT(9) * FT(mParams.BoundaryWeight) * squared_distance(mProfile.p0(),mProfile.p1()) ; - - H *= mParams.VolumeWeight ; - c = c * mParams.VolumeWeight ; - - H += lScaledBoundaryWeight * Hb ; - c = c + ( lScaledBoundaryWeight * cb ) ; - - CGAL_SMS_LT_TRACE(2," H:" << matrix_to_string(H) << "\n c:" << xyz_to_string(c) ) ; - CGAL_SMS_LT_TRACE(2," VolW:" << mParams.VolumeWeight << " BdryW:" << mParams.BoundaryWeight << " ScaledBdryW:" << lScaledBoundaryWeight ) ; - - } - - Add_constraint_from_gradient(H,c); -} - -template -void LindstromTurkCore::Add_shape_optimization_constraints( vertex_descriptor_vector const& aLink ) -{ - FT s((double)aLink.size()); - - Matrix H ( s,0.0,0.0 - ,0.0, s,0.0 - ,0.0,0.0, s - ); - - Vector c = NULL_VECTOR ; - - for( typename vertex_descriptor_vector::const_iterator it = aLink.begin(), eit = aLink.end() ; it != eit ; ++it ) - c = c + (ORIGIN - get_point(*it)) ; - - CGAL_SMS_LT_TRACE(1," Adding shape optimization constraint. Shape vector: " << xyz_to_string(c) ); - - Add_constraint_from_gradient(H,c); -} - -template -typename LindstromTurkCore::FT -LindstromTurkCore::Compute_boundary_cost( Vector const& v, Boundary_data_vector const& aBdry ) -{ - FT rCost(0); - for ( typename Boundary_data_vector::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it ) - { - Vector u = (it->t - ORIGIN ) - v ; - Vector c = cross_product(it->v,u); - rCost += c*c; - } - return rCost / FT(4) ; -} - -template -typename LindstromTurkCore::FT -LindstromTurkCore::Compute_volume_cost( Vector const& v, Triangle_data_vector const& aTriangles ) -{ - FT rCost(0); - - for( typename Triangle_data_vector::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it ) - { - Triangle_data const& lTri = *it ; - - FT lF = lTri.NormalV * v - lTri.NormalL ; - - rCost += ( lF * lF ) ; - - } - - return rCost / FT(36) ; -} - -template -typename LindstromTurkCore::FT -LindstromTurkCore::Compute_shape_cost( Point const& p, vertex_descriptor_vector const& aLink ) -{ - FT rCost(0); - - for( typename vertex_descriptor_vector::const_iterator it = aLink.begin(), eit = aLink.end() ; it != eit ; ++it ) - rCost += squared_distance(p,get_point(*it)) ; - - return rCost ; -} - -template -void LindstromTurkCore::Add_constraint_if_alpha_compatible( Vector const& Ai, FT const& bi ) -{ - CGAL_SMS_LT_TRACE(3," Adding new constraints if alpha-compatible.\n Ai: " << xyz_to_string(Ai) << "\n bi:" << n_to_string(bi) << ")" ); - - FT slai = Ai*Ai ; - - CGAL_SMS_LT_TRACE(3,"\n slai: " << n_to_string(slai) << ")" ); - - if ( is_finite(slai) ) - { - FT l = CGAL_NTS sqrt( slai ) ; - - CGAL_SMS_LT_TRACE(3," l: " << n_to_string(l) ); - - if ( !CGAL_NTS is_zero(l) ) - { - Vector Ain = Ai / l ; - FT bin = bi / l ; - - CGAL_SMS_LT_TRACE(3," Ain: " << xyz_to_string(Ain) << " bin:" << n_to_string(bin) ); - - bool lAddIt = true ; - - if ( mConstraints_n == 1 ) - { - FT d01 = mConstraints_A.r0() * Ai ; - - FT sla0 = mConstraints_A.r0() * mConstraints_A.r0() ; - FT sd01 = d01 * d01 ; - - FT max = sla0 * slai * mSquared_cos_alpha ; - - CGAL_SMS_LT_TRACE(3," Second constraint. d01: " << n_to_string(d01) << " sla0:" << n_to_string(sla0) << " sd01:" << n_to_string(sd01) << " max:" << n_to_string(max) ); - - if ( sd01 > max ) - lAddIt = false ; - } - else if ( mConstraints_n == 2 ) - { - Vector N = cross_product(mConstraints_A.r0(),mConstraints_A.r1()); - - FT dc012 = N * Ai ; - - FT slc01 = N * N ; - FT sdc012 = dc012 * dc012; - - FT min = slc01 * slai * mSquared_sin_alpha ; - - CGAL_SMS_LT_TRACE(3," Third constraint. N: " << xyz_to_string(N) << " dc012:" << n_to_string(dc012) << " slc01:" << n_to_string(slc01) - << " sdc012:" << n_to_string(sdc012) << " min:" << n_to_string(min) ); - - if ( sdc012 <= min ) - lAddIt = false ; - } - - if ( lAddIt ) - { - switch ( mConstraints_n ) - { - case 0 : - mConstraints_A.r0() = Ain ; - mConstraints_b = Vector(bin,mConstraints_b.y(),mConstraints_b.z()); - break ; - case 1 : - mConstraints_A.r1() = Ain ; - mConstraints_b = Vector(mConstraints_b.x(),bin,mConstraints_b.z()); - break ; - case 2 : - mConstraints_A.r2() = Ain ; - mConstraints_b = Vector(mConstraints_b.x(),mConstraints_b.y(),bin); - break ; - } - - CGAL_SMS_LT_TRACE(3," Accepting # " << mConstraints_n << " A:" << matrix_to_string(mConstraints_A) << " b:" << xyz_to_string(mConstraints_b) ) ; - - ++ mConstraints_n ; - - } - else - { - CGAL_SMS_LT_TRACE(3," INCOMPATIBLE. Discarded" ) ; - } - } - else - { - CGAL_SMS_LT_TRACE(3," l is ZERO. Discarded" ); - } - } - else - { - CGAL_SMS_LT_TRACE(3," OVERFLOW. Discarded" ) ; - } -} - -template -int index_of_max_component ( V const& v ) -{ - typedef typename Kernel_traits::Kernel::FT FT ; - - int i = 0 ; - - FT max = v.x(); - - if ( max < v.y() ) - { - max = v.y(); - i = 1 ; - } - if ( max < v.z() ) - { - max = v.z(); - i = 2 ; - } - return i ; -} - -template -void LindstromTurkCore::Add_constraint_from_gradient ( Matrix const& H, Vector const& c ) -{ - CGAL_SMS_LT_TRACE(3," Adding constraint from gradient. Current n=" << mConstraints_n ) ; - - CGAL_precondition(mConstraints_n >= 0 && mConstraints_n<=2 ); - - switch(mConstraints_n) - { - case 0 : - - Add_constraint_if_alpha_compatible(H.r0(),-c.x()); - Add_constraint_if_alpha_compatible(H.r1(),-c.y()); - Add_constraint_if_alpha_compatible(H.r2(),-c.z()); - - break; - - case 1 : - { - Vector const& A0 = mConstraints_A.r0(); - - CGAL_assertion( A0 != NULL_VECTOR ) ; - - Vector AbsA0( CGAL::abs(A0.x()) - , CGAL::abs(A0.y()) - , CGAL::abs(A0.z()) - ); - - Vector Q0; - switch ( index_of_max_component(AbsA0) ) - { - // Since A0 is guaranteed to be non-zero, the denominators here are known to be non-zero too. - - case 0: Q0 = Vector(- A0.z()/A0.x(),0 ,1 ); break; - case 1: Q0 = Vector(0 ,- A0.z()/A0.y(),1 ); break; - case 2: Q0 = Vector(1 ,0 ,- A0.x()/A0.z()); break; - - default : Q0 = NULL_VECTOR ; // This should never happen! - } - - CGAL_SMS_LT_TRACE(3," Q0:" << xyz_to_string(Q0) ) ; - - CGAL_assertion( Q0 != NULL_VECTOR ) ; - - Vector Q1 = cross_product(A0,Q0); - - Vector A1 = H * Q0 ; - Vector A2 = H * Q1 ; - - FT b1 = - ( Q0 * c ) ; - FT b2 = - ( Q1 * c ) ; - - CGAL_SMS_LT_TRACE(3," Q1:" << xyz_to_string(Q1) << "\n A1: " << xyz_to_string(A1) << "\n A2:" << xyz_to_string(A2) - << "\n b1:" << n_to_string(b1) << "\n b2:" << n_to_string(b2) ) ; - - Add_constraint_if_alpha_compatible(A1,b1); - Add_constraint_if_alpha_compatible(A2,b2); - - } - break ; - - case 2: - { - - Vector Q = cross_product(mConstraints_A.r0(),mConstraints_A.r1()); - - Vector A2 = H * Q ; - - FT b2 = - ( Q * c ) ; - - CGAL_SMS_LT_TRACE(3," Q:" << xyz_to_string(Q) << "\n A2: " << xyz_to_string(A2) << "\n b2:" << n_to_string(b2) ) ; - - Add_constraint_if_alpha_compatible(A2,b2); - - } - break ; - - } -} - -} // namespace Surface_mesh_simplification - -} //namespace CGAL - -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_DETAIL_LINDSTROMTURK_CORE_IMPL_H // -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h index 4ed242b1b0d..84f5b900118 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_cost.h @@ -22,51 +22,28 @@ #include - #include #include namespace CGAL { +namespace Surface_mesh_simplification { -namespace Surface_mesh_simplification -{ - -// // Edge-length cost: the squared length of the collapsing edge -// - template +template class Edge_length_cost { public: - /* - typedef TM_ TM ; - - typedef Edge_profile Profile ; - typedef typename Profile::Point Point; - typedef typename Kernel_traits::Kernel Kernel ; - typedef typename Kernel::FT FT ; - typedef optional result_type ; - */ -public: + Edge_length_cost() {} - Edge_length_cost() - {} - - template - optional operator()( Profile const& aProfile, T const& /*aPlacement*/ ) const + template + optional operator()(const Profile& aProfile, const T& /*aPlacement*/) const { typedef optional result_type; - return result_type(squared_distance(aProfile.p0(),aProfile.p1())); + return result_type(squared_distance(aProfile.p0(), aProfile.p1())); } - }; - } // namespace Surface_mesh_simplification - - } //namespace CGAL #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_EDGE_LENGHT_COST_H -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h index 511fe9f40d1..1e85d1d8f69 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_length_stop_predicate.h @@ -24,34 +24,29 @@ #include namespace CGAL { - -namespace Surface_mesh_simplification -{ +namespace Surface_mesh_simplification { template class Edge_length_stop_predicate { FT m_edge_sq_length_threshold; + public: - Edge_length_stop_predicate( double edge_length_threshold ) - : m_edge_sq_length_threshold(edge_length_threshold*edge_length_threshold) + Edge_length_stop_predicate(double edge_length_threshold) + : m_edge_sq_length_threshold(edge_length_threshold * edge_length_threshold) {} template - bool operator()( F const& - , Profile const& profile - , std::size_t - , std::size_t - ) const + bool operator()(const F&, + const Profile& profile, + std::size_t, + std::size_t) const { - return CGAL::squared_distance(profile.p0(), profile.p1()) > - m_edge_sq_length_threshold; + return CGAL::squared_distance(profile.p0(), profile.p1()) > m_edge_sq_length_threshold; } }; } // namespace Surface_mesh_simplification - } //namespace CGAL -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_EDGE_LENGTH_STOP_PREDICATE_H // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_EDGE_LENGTH_STOP_PREDICATE_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile.h index 1c249349ff5..90493cd0c92 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile.h @@ -18,161 +18,141 @@ // Author(s) : Fernando Cacciola // #ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_PROFILE_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_PROFILE_H 1 +#define CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_PROFILE_H #include +#include #include #include -#include - namespace CGAL { +namespace Surface_mesh_simplification { -namespace Surface_mesh_simplification -{ - - template::type> +template::type> class Edge_profile { public: + typedef TM_ TM; + typedef VertexPointMap_ VertexPointMap; + typedef boost::graph_traits GraphTraits; - typedef TM_ TM ; - typedef VertexPointMap_ VertexPointMap; - typedef boost::graph_traits GraphTraits ; - - typedef typename GraphTraits::vertex_descriptor vertex_descriptor ; - typedef typename GraphTraits::face_descriptor face_descriptor ; - typedef typename GraphTraits::halfedge_descriptor halfedge_descriptor ; + typedef typename GraphTraits::vertex_descriptor vertex_descriptor; + typedef typename GraphTraits::halfedge_descriptor halfedge_descriptor; + typedef typename GraphTraits::face_descriptor face_descriptor; + typedef std::vector vertex_descriptor_vector; + typedef std::vector halfedge_descriptor_vector; - //typedef typename boost::property_map::type Vertex_point_pmap; - typedef typename boost::property_traits::value_type Point; - typedef typename Kernel_traits::Kernel Kernel; - typedef typename Kernel::FT FT; + typedef typename boost::property_traits::value_type Point; + typedef typename Kernel_traits::Kernel Kernel; + typedef typename Kernel::FT FT; public: - struct Triangle { Triangle() {} - - Triangle( vertex_descriptor const& a_v0 - , vertex_descriptor const& a_v1 - , vertex_descriptor const& a_v2 - ) - : v0(a_v0), v1(a_v1), v2(a_v2) + + Triangle(const vertex_descriptor a_v0, + const vertex_descriptor a_v1, + const vertex_descriptor a_v2) + : v0(a_v0), v1(a_v1), v2(a_v2) { - CGAL_SURF_SIMPL_TEST_assertion( handle_assigned(v0) && handle_assigned(v1) && handle_assigned(v2) ) ; - CGAL_SURF_SIMPL_TEST_assertion( v0 != v1 && v1 != v2 && v2 != v0 ) ; + CGAL_SURF_SIMPL_TEST_assertion(handle_assigned(v0) && handle_assigned(v1) && handle_assigned(v2)); + CGAL_SURF_SIMPL_TEST_assertion(v0 != v1 && v1 != v2 && v2 != v0); } - - vertex_descriptor v0 ; - vertex_descriptor v1 ; - vertex_descriptor v2 ; - } ; - - typedef std::vector vertex_descriptor_vector ; - typedef std::vector halfedge_descriptor_vector ; - - typedef std::vector Triangle_vector ; - + + vertex_descriptor v0; + vertex_descriptor v1; + vertex_descriptor v2; + }; + + typedef std::vector Triangle_vector; + public : - - template - Edge_profile ( halfedge_descriptor const& aV0V1 - , TM& aSurface - , VertexIdxMap const& aVertex_index_map - , VertexPointMap const& aVertex_point_map - , EdgeIdxMap const& aEdge_index_map - , bool has_border - ) ; - + template + Edge_profile(const halfedge_descriptor& aV0V1, + TM& aSurface, + const VertexIdxMap& aVertex_index_map, + const VertexPointMap& aVertex_point_map, + const EdgeIdxMap& aEdge_index_map, + bool has_border); + public : + const halfedge_descriptor v0_v1() const { return mV0V1; } + const halfedge_descriptor v1_v0() const { return mV1V0; } - halfedge_descriptor const& v0_v1() const { return mV0V1; } - halfedge_descriptor const& v1_v0() const { return mV1V0; } - - vertex_descriptor const& v0() const { return mV0; } - vertex_descriptor const& v1() const { return mV1; } + const vertex_descriptor v0() const { return mV0; } + const vertex_descriptor v1() const { return mV1; } - // These are null if v0v1 is a border (thius there is no face to its left) - vertex_descriptor const& vL() const { return mVL; } - halfedge_descriptor const& v1_vL() const { return mV1VL; } - halfedge_descriptor const& vL_v0() const { return mVLV0; } - - // These are null if v1v0 is a border (thius there is no face to its left) - vertex_descriptor const& vR() const { return mVR; } - halfedge_descriptor const& v0_vR() const { return mV0VR; } - halfedge_descriptor const& vR_v1() const { return mVRV1; } + // These are null if v0v1 is a border (thius there is no face to its left) + const vertex_descriptor vL() const { return mVL; } + const halfedge_descriptor v1_vL() const { return mV1VL; } + const halfedge_descriptor vL_v0() const { return mVLV0; } - Triangle_vector const& triangles() const { + // These are null if v1v0 is a border (thius there is no face to its left) + const vertex_descriptor vR() const { return mVR; } + const halfedge_descriptor v0_vR() const { return mV0VR; } + const halfedge_descriptor vR_v1() const { return mVRV1; } - if(mTriangles.empty()){ - const_cast(this)->Extract_triangles_and_link(); - } - CGAL_HISTOGRAM_PROFILER("triangles.size()", mTriangles.size()); - return mTriangles ; } - - // The cycle of vertices around the edge - vertex_descriptor_vector const& link() const { - CGAL_PROFILER("link calls"); - if(mLink.empty()){ - - const_cast(this)->Extract_triangles_and_link(); - } - return mLink ; } - - halfedge_descriptor_vector const& border_edges() const { - return mBorderEdges ; - } - TM& surface() const { return *mSurface ; } - TM& surface_mesh() const { return *mSurface ; } - - VertexPointMap vertex_point_map() const { return mvpm ; } - -public : - - Point const& p0() const { return mP0; } - Point const& p1() const { return mP1; } - - bool is_v0_v1_a_border() const { return mIsBorderV0V1 ; } - bool is_v1_v0_a_border() const { return mIsBorderV1V0 ; } - - bool left_face_exists () const { return !mIsBorderV0V1 ; } - bool right_face_exists() const { return !mIsBorderV1V0 ; } - -private: - - // typedef typename GraphTraits::in_edge_iterator in_edge_iterator ; - - bool is_border(halfedge_descriptor e) const + const Triangle_vector& triangles() const { + if(mTriangles.empty()) + const_cast(this)->extract_triangles_and_link(); + + CGAL_HISTOGRAM_PROFILER("triangles.size()", mTriangles.size()); + return mTriangles; + } + + // The cycle of vertices around the edge + const vertex_descriptor_vector& link() const + { + CGAL_PROFILER("link calls"); + if(mLink.empty()) + const_cast(this)->extract_triangles_and_link(); + + return mLink; + } + + const halfedge_descriptor_vector& border_edges() const { return mBorderEdges; } + TM& surface() const { return *mSurface; } + TM& surface_mesh() const { return *mSurface; } + VertexPointMap vertex_point_map() const { return mvpm; } + +public : + const Point& p0() const { return mP0; } + const Point& p1() const { return mP1; } + + bool is_v0_v1_a_border() const { return mIsBorderV0V1; } + bool is_v1_v0_a_border() const { return mIsBorderV1V0; } + + bool left_face_exists () const { return !mIsBorderV0V1; } + bool right_face_exists() const { return !mIsBorderV1V0; } + +private: + bool is_border(halfedge_descriptor e) const { return face(e,*mSurface) == boost::graph_traits::null_face(); } - - void Extract_borders() ; - - void Extract_triangles_and_link() ; - + void extract_borders(); + void extract_triangles_and_link(); + private: - halfedge_descriptor mV0V1; halfedge_descriptor mV1V0; - bool mIsBorderV0V1 ; - bool mIsBorderV1V0 ; - + bool mIsBorderV0V1; + bool mIsBorderV1V0; + vertex_descriptor mV0; vertex_descriptor mV1; - - Point mP0 ; - Point mP1 ; - + + Point mP0; + Point mP1; + vertex_descriptor mVL; vertex_descriptor mVR; @@ -180,21 +160,198 @@ private: halfedge_descriptor mVLV0; halfedge_descriptor mV0VR; halfedge_descriptor mVRV1; - - vertex_descriptor_vector mLink ; - halfedge_descriptor_vector mBorderEdges ; - Triangle_vector mTriangles ; - - TM* mSurface ; - VertexPointMap mvpm; -} ; - -} // namespace Surface_mesh_simplification + vertex_descriptor_vector mLink; + halfedge_descriptor_vector mBorderEdges; + Triangle_vector mTriangles; + + TM* mSurface; + VertexPointMap mvpm; +}; + +template +template +Edge_profile:: +Edge_profile(const halfedge_descriptor& aV0V1, + TM& aSurface, + const VertexIdxMap&, + const VertexPointMap& aVertex_point_map, + const EdgeIdxMap&, + bool has_border) + : + mV0V1(aV0V1), + mSurface(boost::addressof(aSurface)), + mvpm(aVertex_point_map) +{ + CGAL_PROFILER("Edge_profile constructor calls"); + + mLink.reserve(12); + mTriangles.reserve(16); + mV1V0 = opposite(v0_v1(), surface_mesh()); + + mV0 = source(v0_v1(), surface_mesh()); + mV1 = target(v0_v1(), surface_mesh()); + + CGAL_assertion(mV0 != mV1); + + mP0 = get(vertex_point_map(),mV0); + mP1 = get(vertex_point_map(),mV1); + + mIsBorderV0V1 = is_border(v0_v1()); + mIsBorderV1V0 = is_border(v1_v0()); + + if(left_face_exists()) + { + CGAL_SURF_SIMPL_TEST_assertion(! is_border(mV0V1)); + + mVLV0 = prev(v0_v1(), surface_mesh()); + mV1VL = next(v0_v1(), surface_mesh()); + mVL = target(v1_vL(), surface_mesh()); + + CGAL_SURF_SIMPL_TEST_assertion(mV0 != mVL); + CGAL_SURF_SIMPL_TEST_assertion(mVL == source(vL_v0(), surface_mesh())); + } + else + { + CGAL_SURF_SIMPL_TEST_assertion(is_border(mV0V1)); + } + + if(right_face_exists()) + { + CGAL_SURF_SIMPL_TEST_assertion(! is_border(mV1V0)); + + mV0VR = next(v1_v0(), surface_mesh()); + mVRV1 = prev(v1_v0(), surface_mesh()); + mVR = target(v0_vR(), surface_mesh()); + + CGAL_SURF_SIMPL_TEST_assertion(mV0 != mVR); + CGAL_SURF_SIMPL_TEST_assertion(mVR == source(vR_v1(), surface_mesh())); + } + else + { + CGAL_SURF_SIMPL_TEST_assertion(is_border(mV1V0)); + } + + if(has_border) + extract_borders(); +} + +template +void +Edge_profile:: +extract_borders() +{ + halfedge_descriptor e = mV0V1; + halfedge_descriptor oe = opposite(e, surface_mesh()); + + bool b; + if((b = is_border(e)) || is_border(oe)) + mBorderEdges.push_back(b?e:oe); + + e = next(oe, surface_mesh()); + oe = opposite(e, surface_mesh()); + while(e != mV0V1) + { + if((b = is_border(e)) || is_border(oe)) + mBorderEdges.push_back(b?e:oe); + + e = next(oe, surface_mesh()); + oe = opposite(e, surface_mesh()); + } + + e = opposite(next(e, surface_mesh()), surface_mesh()); + oe = opposite(e, surface_mesh()); + while(e != mV0V1) + { + if((b = is_border(e)) || is_border(oe)) + mBorderEdges.push_back(b?e:oe); + + e = opposite(next(e, surface_mesh()), surface_mesh()); + oe = opposite(e, surface_mesh()); + } +} + +// Extract all triangles (its normals) and vertices (the link) around the collapsing edge p_q +template +void +Edge_profile:: +extract_triangles_and_link() +{ +#ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK + std::set vertex_already_inserted; +#endif + // look at the two faces or holes adjacent to edge (v0,v1) + // and at the opposite vertex if it exists + halfedge_descriptor endleft = next(v1_v0(), surface_mesh()); + halfedge_descriptor endright = next(v0_v1(), surface_mesh()); + + if(left_face_exists()) + mTriangles.push_back(Triangle(v0(), v1(), vL())); + if(right_face_exists()) + mTriangles.push_back(Triangle(v1(), v0(), vR())); + + // counterclockwise around v0 + halfedge_descriptor e02 = opposite(prev(v0_v1(), surface_mesh()), surface_mesh()); + vertex_descriptor v = target(e02, surface_mesh()), v2 = v; + + while(e02 != endleft) + { +#ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK + if(vertex_already_inserted.insert(v2).second) +#endif + mLink.push_back(v2); + + bool is_b = is_border(e02); + e02 = opposite(prev(e02, surface_mesh()), surface_mesh()); + v = target(e02, surface_mesh()); + if(!is_b) + mTriangles.push_back(Triangle(v, v0(), v2)); + + v2 = v; + } + + e02 = opposite(prev(v1_v0(), surface_mesh()), surface_mesh()); + if(target(e02, surface_mesh()) != v) // add the vertex if it is not added in the following loop + { +#ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK + if(vertex_already_inserted.insert(v).second) +#endif + mLink.push_back(v); + } + + // counterclockwise around v1 + v2 = target(e02, surface_mesh()); + v = v2; + while(e02 != endright) + { +#ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK + if(vertex_already_inserted.insert(v2).second) +#endif + mLink.push_back(v2); + + bool is_b = is_border(e02); + e02 = opposite(prev(e02, surface_mesh()), surface_mesh()); + v = target(e02, surface_mesh()); + + if(!is_b) + mTriangles.push_back(Triangle(v,v1(),v2)); + + v2 = v; + } + + if(mLink.empty() || //handle link of an isolated triangle + target(opposite(prev(v0_v1(), surface_mesh()), surface_mesh()), surface_mesh())!=v) + { +#ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK + if(vertex_already_inserted.insert(v).second) +#endif + mLink.push_back(v); + } + + CGAL_assertion(!mLink.empty()); +} + +} // namespace Surface_mesh_simplification } //namespace CGAL -#include - #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_PROFILE_H -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile_impl.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile_impl.h deleted file mode 100644 index e4647edaa3e..00000000000 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Edge_profile_impl.h +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (c) 2006 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 Surface_mesh_simplification license may use this file in -// accordance with the Surface_mesh_simplification 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) : Fernando Cacciola -// -#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_PROFILE_IMPL_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_PROFILE_IMPL_H 1 - -#include - - -namespace CGAL { - -namespace Surface_mesh_simplification -{ - - template - -template - Edge_profile::Edge_profile ( halfedge_descriptor const& aV0V1 - , TM& aSurface - , VertexIdxMap const& - , VertexPointMap const& aVertex_point_map - , EdgeIdxMap const& - , bool has_border - - ) - : - mV0V1(aV0V1) - ,mSurface(boost::addressof(aSurface)) - , mvpm(aVertex_point_map) - -{ - CGAL_PROFILER("Edge_profile constructor calls"); - - mLink.reserve(12); - mTriangles.reserve(16); - mV1V0 = opposite(v0_v1(),surface_mesh()); - - mV0 = source(v0_v1(),surface_mesh()); - mV1 = target(v0_v1(),surface_mesh()); - - CGAL_assertion( mV0 != mV1 ); - - mP0 = get(vertex_point_map(),mV0); - mP1 = get(vertex_point_map(),mV1); - - mIsBorderV0V1 = is_border(v0_v1()); - mIsBorderV1V0 = is_border(v1_v0()); - - if ( left_face_exists() ) - { - CGAL_SURF_SIMPL_TEST_assertion( ! is_border(mV0V1) ) ; - - mVLV0 = prev(v0_v1(),surface_mesh()); - mV1VL = next(v0_v1(),surface_mesh()); - mVL = target(v1_vL(),surface_mesh()); - - CGAL_SURF_SIMPL_TEST_assertion( mV0 != mVL ); - CGAL_SURF_SIMPL_TEST_assertion( mVL == source(vL_v0(),surface_mesh()) ); - } - else - { - CGAL_SURF_SIMPL_TEST_assertion( is_border(mV0V1) ) ; - } - - if ( right_face_exists() ) - { - CGAL_SURF_SIMPL_TEST_assertion( ! is_border(mV1V0) ) ; - - mV0VR = next(v1_v0(),surface_mesh()); - mVRV1 = prev(v1_v0(),surface_mesh()); - mVR = target(v0_vR(),surface_mesh()); - - CGAL_SURF_SIMPL_TEST_assertion( mV0 != mVR ); - CGAL_SURF_SIMPL_TEST_assertion( mVR == source(vR_v1(),surface_mesh()) ); - } - else - { - CGAL_SURF_SIMPL_TEST_assertion( is_border(mV1V0) ) ; - } - - if(has_border){ - Extract_borders(); - } -} - - - template - void Edge_profile::Extract_borders() -{ - halfedge_descriptor e = mV0V1; - halfedge_descriptor oe = opposite(e, surface_mesh()); - bool b; - if((b = is_border(e)) || is_border(oe)){ - mBorderEdges.push_back(b?e:oe); - } - e = next(oe,surface_mesh()); - oe = opposite(e,surface_mesh()); - while(e != mV0V1){ - if((b = is_border(e)) || is_border(oe)){ - mBorderEdges.push_back(b?e:oe); - } - e = next(oe,surface_mesh()); - oe = opposite(e,surface_mesh()); - } - e = opposite(next(e,surface_mesh()),surface_mesh()); - oe = opposite(e,surface_mesh()); - while(e != mV0V1){ - if((b = is_border(e)) || is_border(oe)){ - mBorderEdges.push_back(b?e:oe); - } - e = opposite(next(e,surface_mesh()),surface_mesh()); - oe = opposite(e,surface_mesh()); - } -} - - - -// Extract all triangles (its normals) and vertices (the link) around the collapsing edge p_q -// - template - void Edge_profile::Extract_triangles_and_link() -{ - #ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK - std::set vertex_already_inserted; - #endif - // look at the two faces or holes adjacent to edge (v0,v1) - // and at the opposite vertex if it exists - halfedge_descriptor endleft = next(v1_v0(), surface_mesh()); - halfedge_descriptor endright = next(v0_v1(), surface_mesh()); - - if( left_face_exists() ) - mTriangles.push_back(Triangle(v0(),v1(),vL()) ) ; - if( right_face_exists() ) - mTriangles.push_back(Triangle(v1(),v0(),vR()) ) ; - - // counterclockwise around v0 - halfedge_descriptor e02 = opposite(prev(v0_v1(),surface_mesh()), surface_mesh()); - vertex_descriptor v=target(e02,surface_mesh()), v2=v; - while(e02 != endleft) { - #ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK - if (vertex_already_inserted.insert(v2).second) - #endif - mLink.push_back(v2); - bool is_b = is_border(e02); - e02 = opposite(prev(e02,surface_mesh()), surface_mesh()); - v = target(e02,surface_mesh()); - if( !is_b ) - mTriangles.push_back(Triangle(v,v0(),v2) ) ; - v2 = v; - } - - e02 = opposite(prev(v1_v0(),surface_mesh()), surface_mesh()); - if(target(e02, surface_mesh())!=v ) // add the vertex if it is not added in the following loop - { - #ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK - if (vertex_already_inserted.insert(v).second) - #endif - mLink.push_back(v); - } - - // counterclockwise around v1 - v2 = target(e02,surface_mesh()); - v = v2; - while(e02 != endright) { - #ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK - if (vertex_already_inserted.insert(v2).second) - #endif - mLink.push_back(v2); - bool is_b = is_border(e02); - e02 = opposite(prev(e02,surface_mesh()), surface_mesh()); - v = target(e02,surface_mesh()); - if( !is_b ){ - mTriangles.push_back(Triangle(v,v1(),v2) ) ; - } - v2 = v; - } - - if(mLink.empty() || //handle link of an isolated triangle - target(opposite(prev(v0_v1(),surface_mesh()), surface_mesh()), surface_mesh())!=v) - { - #ifdef CGAL_SMS_EDGE_PROFILE_ALWAYS_NEED_UNIQUE_VERTEX_IN_LINK - if (vertex_already_inserted.insert(v).second) - #endif - mLink.push_back(v); - } - - CGAL_assertion(!mLink.empty()); -} - -} // namespace Surface_mesh_simplification - -} //namespace CGAL - -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_PROFILE_IMPL_H -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk.h index d68953458b0..c58def26e59 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk.h @@ -18,15 +18,12 @@ // Author(s) : Fernando Cacciola // #ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_H 1 +#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_H #include - #include #include #include -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h index 095e1b643ba..e215d09a67d 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_cost.h @@ -18,53 +18,39 @@ // Author(s) : Fernando Cacciola // #ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_COST_H -#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_COST_H 1 +#define CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_COST_H #include - #include #include namespace CGAL { +namespace Surface_mesh_simplification { -namespace Surface_mesh_simplification -{ - - template +template class LindstromTurk_cost { public: - - typedef TM_ TM ; - /* + typedef TM_ TM; - typedef Edge_profile Profile ; - typedef typename Traits::Point_3 Point; - typedef typename Traits::FT FT ; - - typedef optional result_type ; - */ -public: + LindstromTurk_cost(LindstromTurk_params const& aParams = LindstromTurk_params()) + : mParams(aParams) + {} - LindstromTurk_cost( LindstromTurk_params const& aParams = LindstromTurk_params() ) : mParams(aParams) {} - template optional - operator()( Profile const& aProfile, optional const& aPlacement ) const + operator()(const Profile& aProfile, + const optional& aPlacement) const { - return LindstromTurkCore(mParams,aProfile).compute_cost(aPlacement) ; + return LindstromTurkCore(mParams,aProfile).compute_cost(aPlacement); } private: - - LindstromTurk_params mParams ; + LindstromTurk_params mParams; }; } // namespace Surface_mesh_simplification - } //namespace CGAL -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_COST_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_COST_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_params.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_params.h index 32dc525ad97..840051e02b7 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_params.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_params.h @@ -22,37 +22,31 @@ #include - namespace CGAL { - -namespace Surface_mesh_simplification -{ +namespace Surface_mesh_simplification { struct LindstromTurk_params { LindstromTurk_params() : - VolumeWeight (0.5) - ,BoundaryWeight(0.5) - ,ShapeWeight (0) + VolumeWeight(0.5), + BoundaryWeight(0.5), + ShapeWeight(0) {} - - LindstromTurk_params( double aVolumeWeight, double aBoundaryWeight, double aShapeWeight ) - : - VolumeWeight (aVolumeWeight) - ,BoundaryWeight(aBoundaryWeight) - ,ShapeWeight (aShapeWeight) - {} - - double VolumeWeight ; - double BoundaryWeight ; - double ShapeWeight ; -}; - -} // namespace Surface_mesh_simplification -} //namespace CGAL + LindstromTurk_params(double aVolumeWeight, double aBoundaryWeight, double aShapeWeight) + : + VolumeWeight(aVolumeWeight), + BoundaryWeight(aBoundaryWeight), + ShapeWeight(aShapeWeight) + {} + + double VolumeWeight; + double BoundaryWeight; + double ShapeWeight; +}; + +} // namespace Surface_mesh_simplification +} // namespace CGAL #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_PARAMS_H -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h index b99e061e155..a03d585e440 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/LindstromTurk_placement.h @@ -22,44 +22,33 @@ #include - #include #include namespace CGAL { +namespace Surface_mesh_simplification { -namespace Surface_mesh_simplification -{ - - template +template class LindstromTurk_placement { public: - - typedef TM_ TM ; - -public: + typedef TM_ TM; - LindstromTurk_placement( LindstromTurk_params const& aParams = LindstromTurk_params() ) : mParams(aParams) {} - - template - optional - operator()( Profile const& aProfile) const + LindstromTurk_placement(LindstromTurk_params const& aParams = LindstromTurk_params()) + : mParams(aParams) + {} + + template + optional operator()(const Profile& aProfile) const { - return LindstromTurkCore(mParams,aProfile).compute_placement() ; + return LindstromTurkCore(mParams,aProfile).compute_placement(); } - + private: - - LindstromTurk_params mParams ; - + LindstromTurk_params mParams; }; - } // namespace Surface_mesh_simplification - } //namespace CGAL -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_PLACEMENT_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_LINDSTROMTURK_PLACEMENT_H diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_and_length.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_and_length.h index 30459feaac8..4a7abcd76bc 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_and_length.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_and_length.h @@ -22,10 +22,7 @@ #include - #include #include #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_POLICIES_EDGE_COLLAPSE_MIDPOINT_AND_LENGTH_H -// EOF // - diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h index bfaaa42bbcd..3a6223bc29d 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/Midpoint_placement.h @@ -42,7 +42,7 @@ public: {} template - optional operator()( Profile const& aProfile ) const + optional operator()(const Profile& aProfile) const { return optional (midpoint(aProfile.p0(),aProfile.p1())); } diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h index 09db7ab2890..69550442436 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/edge_collapse.h @@ -22,7 +22,6 @@ #include - #include #include @@ -31,143 +30,118 @@ #include namespace CGAL { +namespace Surface_mesh_simplification { -namespace Surface_mesh_simplification -{ - -template -int edge_collapse ( TM& aSurface - , ShouldStop const& aShould_stop - // optional mesh information policies - , VertexIndexMap const& aVertex_index_map // defaults to get(vertex_index,aSurface) - , VertexPointMap const& aVertex_point_map // defaults to get(vertex_point,aSurface) - , EdgeIndexMap const& aEdge_index_map // defaults to get(edge_index,aSurface) - , EdgeIsConstrainedMap const& aEdge_is_constrained_map // defaults to No_constrained_edge_map() - +template +int edge_collapse(TM& aSurface, + const ShouldStop& aShould_stop, + // optional mesh information policies + const VertexIndexMap& aVertex_index_map, // defaults to get(vertex_index, aSurface) + const VertexPointMap& aVertex_point_map, // defaults to get(vertex_point, aSurface) + const EdgeIndexMap& aEdge_index_map, // defaults to get(edge_index, aSurface) + const EdgeIsConstrainedMap& aEdge_is_constrained_map, // defaults to No_constrained_edge_map() // optional strategy policies - defaults to LindstomTurk - , GetCost const& aGet_cost - , GetPlacement const& aGet_placement - - , Visitor aVisitor - ) + const GetCost& aGet_cost, + const GetPlacement& aGet_placement, + Visitor aVisitor) { - typedef EdgeCollapse< TM - , ShouldStop - , VertexIndexMap - , VertexPointMap - , EdgeIndexMap - , EdgeIsConstrainedMap - , GetCost - , GetPlacement - , Visitor - > - Algorithm; - - Algorithm algorithm( aSurface - , aShould_stop - , aVertex_index_map - , aVertex_point_map - , aEdge_index_map - , aEdge_is_constrained_map - , aGet_cost - , aGet_placement - , aVisitor - ) ; - - return algorithm.run(); -} + typedef EdgeCollapse Algorithm; + Algorithm algorithm(aSurface, aShould_stop, + aVertex_index_map, aVertex_point_map, aEdge_index_map, aEdge_is_constrained_map, + aGet_cost, aGet_placement, aVisitor); + + return algorithm.run(); +} struct Dummy_visitor { - template void OnStarted( TM& ) const {} - template void OnFinished ( TM& ) const {} - template void OnStopConditionReached( Profile const& ) const {} - template void OnCollected( Profile const&, OFT const& ) const {} - template void OnSelected( Profile const&, OFT const&, Size_type, Size_type ) const {} - template void OnCollapsing(Profile const&, OPoint const& ) const {} - template void OnCollapsed( Profile const&, VH ) const {} - template void OnNonCollapsable(Profile const& ) const {} -} ; + template + void OnStarted(TM&) const {} + template + void OnFinished(TM&) const {} + template + void OnStopConditionReached(const Profile&) const {} + template + void OnCollected(Profile const&, const OFT&) const {} + template + void OnSelected(Profile const&, const OFT&, Size_type, Size_type) const {} + template + void OnCollapsing(const Profile&, const OPoint&) const {} + template + void OnCollapsed(const Profile&, VH) const {} + template + void OnNonCollapsable(Profile const&) const {} +}; template -int edge_collapse ( TM& aSurface - , ShouldStop const& aShould_stop - , cgal_bgl_named_params const& aParams - ) +int edge_collapse(TM& aSurface, + const ShouldStop& aShould_stop, + cgal_bgl_named_params const& aParams) { - using boost::choose_param ; - using boost::choose_const_pmap ; - using boost::get_param ; - - LindstromTurk_params lPolicyParams ; - - internal_np::graph_visitor_t vis = internal_np::graph_visitor_t() ; + using boost::choose_param; + using boost::choose_const_pmap; + using boost::get_param; - return edge_collapse(aSurface - ,aShould_stop - ,choose_const_pmap(get_param(aParams,internal_np::vertex_index),aSurface,boost::vertex_index) - ,choose_pmap(get_param(aParams,internal_np::vertex_point),aSurface,boost::vertex_point) - ,choose_const_pmap(get_param(aParams,internal_np::halfedge_index),aSurface,boost::halfedge_index) - ,choose_param (get_param(aParams,internal_np::edge_is_constrained),No_constrained_edge_map()) - ,choose_param (get_param(aParams,internal_np::get_cost_policy), LindstromTurk_cost()) - ,choose_param (get_param(aParams,internal_np::get_placement_policy), LindstromTurk_placement()) - ,choose_param (get_param(aParams,vis), Dummy_visitor()) - ); + LindstromTurk_params lPolicyParams; + internal_np::graph_visitor_t vis = internal_np::graph_visitor_t(); + return edge_collapse(aSurface, aShould_stop, + choose_const_pmap(get_param(aParams,internal_np::vertex_index),aSurface,boost::vertex_index), + choose_pmap(get_param(aParams,internal_np::vertex_point),aSurface,boost::vertex_point), + choose_const_pmap(get_param(aParams,internal_np::halfedge_index),aSurface,boost::halfedge_index), + choose_param(get_param(aParams,internal_np::edge_is_constrained),No_constrained_edge_map()), + choose_param(get_param(aParams,internal_np::get_cost_policy), LindstromTurk_cost()), + choose_param(get_param(aParams,internal_np::get_placement_policy), LindstromTurk_placement()), + choose_param(get_param(aParams,vis), Dummy_visitor())); } - template -int edge_collapse ( TM& aSurface - , ShouldStop const& aShould_stop - , cgal_bgl_named_params const& aParams - ) -{ - using boost::choose_param ; - using boost::choose_const_pmap ; - using boost::get_param ; - - LindstromTurk_params lPolicyParams ; - - internal_np::graph_visitor_t vis = internal_np::graph_visitor_t() ; - - return edge_collapse(aSurface - ,aShould_stop - ,choose_const_pmap(get_param(aParams,internal_np::vertex_index),aSurface,boost::vertex_index) - ,choose_const_pmap(get_param(aParams,internal_np::vertex_point),aSurface,boost::vertex_point) - ,choose_const_pmap(get_param(aParams,internal_np::halfedge_index),aSurface,boost::halfedge_index) - ,choose_param (get_param(aParams,internal_np::edge_is_constrained),No_constrained_edge_map()) - ,choose_param (get_param(aParams,internal_np::get_cost_policy), LindstromTurk_cost()) - ,choose_param (get_param(aParams,internal_np::get_placement_policy), LindstromTurk_placement()) - ,choose_param (get_param(aParams,vis), Dummy_visitor()) - ); +template +int edge_collapse(TM& aSurface, + ShouldStop const& aShould_stop, + cgal_bgl_named_params const& aParams) +{ + using boost::choose_param; + using boost::choose_const_pmap; + using boost::get_param; + + LindstromTurk_params lPolicyParams; + internal_np::graph_visitor_t vis = internal_np::graph_visitor_t(); + + return edge_collapse(aSurface, aShould_stop, + choose_const_pmap(get_param(aParams,internal_np::vertex_index),aSurface,boost::vertex_index), + choose_const_pmap(get_param(aParams,internal_np::vertex_point),aSurface,boost::vertex_point), + choose_const_pmap(get_param(aParams,internal_np::halfedge_index),aSurface,boost::halfedge_index), + choose_param(get_param(aParams,internal_np::edge_is_constrained),No_constrained_edge_map()), + choose_param(get_param(aParams,internal_np::get_cost_policy), LindstromTurk_cost()), + choose_param(get_param(aParams,internal_np::get_placement_policy), LindstromTurk_placement()), + choose_param(get_param(aParams,vis), Dummy_visitor())); } template -int edge_collapse ( TM& aSurface, ShouldStop const& aShould_stop ) +int edge_collapse(TM& aSurface, const ShouldStop& aShould_stop) { return edge_collapse(aSurface,aShould_stop, CGAL::parameters::halfedge_index_map(get(boost::halfedge_index,aSurface))); } - template - int edge_collapse ( TM& aSurface, ShouldStop const& aShould_stop) +template +int edge_collapse(TM& aSurface, const ShouldStop& aShould_stop) { return edge_collapse(aSurface,aShould_stop, CGAL::parameters::halfedge_index_map(get(boost::halfedge_index,aSurface))); } } // namespace Surface_mesh_simplification -} //namespace CGAL +} // namespace CGAL -#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_EDGE_COLLAPSE_H // -// EOF // - +#endif // CGAL_SURFACE_MESH_SIMPLIFICATION_EDGE_COLLAPSE_H diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/basics.h b/Surface_mesh_simplification/test/Surface_mesh_simplification/basics.h index 0dc8b196a84..bb442bab3e1 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/basics.h +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/basics.h @@ -16,10 +16,10 @@ //#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE 4 //#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE 4 -void Surface_simplification_external_trace( std::string s ) +void Surface_simplification_external_trace(std::string s) { static std::ofstream out("log.txt"); - out << s << std::endl ; + out << s << std::endl; } #include @@ -39,9 +39,9 @@ void Surface_simplification_external_trace( std::string s ) #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel ; +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef Kernel::FT FT ; +typedef Kernel::FT FT; typedef Kernel::Vector_3 Vector; typedef Kernel::Point_3 Point; @@ -60,11 +60,11 @@ typedef Surface::Facet_const_iterator Facet_const_iterator; typedef Surface::Facet_const_handle Facet_const_handle; typedef Surface::Halfedge_around_vertex_const_circulator HV_circulator; typedef Surface::Halfedge_around_facet_circulator HF_circulator; -typedef Surface::size_type size_type ; +typedef Surface::size_type size_type; -using namespace std ; -using namespace boost ; -using namespace CGAL ; +using namespace std; +using namespace boost; +using namespace CGAL; diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp index 2501ead0069..04ca3726e0c 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_topology.cpp @@ -13,27 +13,27 @@ typedef CGAL::Simple_cartesian Kernel; typedef CGAL::Polyhedron_3 Surface; -namespace SMS = CGAL::Surface_mesh_simplification ; +namespace SMS = CGAL::Surface_mesh_simplification; -int main( int argc, char** argv ) +int main(int argc, char** argv) { - if (argc!=2){ + if(argc!=2){ std::cerr << "Please provide only an off-file as input\n"; return 1; } std::ifstream is(argv[1]); - if (!is){ + if(!is){ std::cerr << "Error reading the input\n"; return 1; } Surface surface; - is >> surface ; + is >> surface; std::size_t initial_count = (surface.size_of_halfedges()/2); - std::cout << "Initial count " << initial_count << " edges.\n" ; + std::cout << "Initial count " << initial_count << " edges.\n"; // Contract the surface as much as possible SMS::Count_stop_predicate stop(0); @@ -43,15 +43,15 @@ int main( int argc, char** argv ) ,stop ,CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index,surface)) .halfedge_index_map (get(CGAL::halfedge_external_index ,surface)) - ); + ); std::cout << "\nFinished...\n" << r << " edges removed.\n" - << (surface.size_of_halfedges()/2) << " final edges.\n" ; + << (surface.size_of_halfedges()/2) << " final edges.\n"; - assert( initial_count == (surface.size_of_halfedges()/2) + r ); - // std::ofstream os( argc > 2 ? argv[2] : "out.off" ) ; os << surface ; + assert(initial_count == (surface.size_of_halfedges()/2) + r); + // std::ofstream os(argc > 2 ? argv[2] : "out.off"); os << surface; - return 0 ; + return 0; } // EOF // diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_collapse_Polyhedron_3.cpp b/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_collapse_Polyhedron_3.cpp index 16f95f9ed65..312c9a29196 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_collapse_Polyhedron_3.cpp +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_collapse_Polyhedron_3.cpp @@ -28,10 +28,10 @@ //#define TEST_TEST_TRACE_ENABLED -template struct eat_sizeof {} ; +template struct eat_sizeof {}; #ifdef TEST_TEST_TRACE_ENABLED -# define TEST_TRACE(m) std::cerr << m << std::endl ; +# define TEST_TRACE(m) std::cerr << m << std::endl; #else # define TEST_TRACE(m) (eat_sizeof()) @@ -39,54 +39,54 @@ template struct eat_sizeof {} ; // This is here only to allow a breakpoint to be placed so I can trace back the problem. -void error_handler ( char const* what, char const* expr, char const* file, int line, char const* msg ) +void error_handler (char const* what, char const* expr, char const* file, int line, char const* msg) { cerr << "CGAL error: " << what << " violation!" << endl << "Expr: " << expr << endl << "File: " << file << endl << "Line: " << line << endl; - if ( msg != 0) + if(msg != 0) cerr << "Explanation:" << msg << endl; throw std::runtime_error(expr); } -namespace SMS = CGAL::Surface_mesh_simplification ; +namespace SMS = CGAL::Surface_mesh_simplification; -typedef SMS::Edge_profile Profile ; +typedef SMS::Edge_profile Profile; -typedef boost::shared_ptr SurfaceSP ; +typedef boost::shared_ptr SurfaceSP; // Constructs a flat polyhedron containing just the link of an edge or vertex. class Link_builder : public CGAL::Modifier_base { - map mMap ; + map mMap; - int mVIdx ; + int mVIdx; protected: - typedef boost::graph_traits GraphTraits ; + typedef boost::graph_traits GraphTraits; - typedef CGAL::Halfedge_around_source_iterator out_edge_iterator ; - typedef GraphTraits::halfedge_descriptor halfedge_descriptor ; - typedef GraphTraits::vertex_descriptor vertex_descriptor ; - typedef CGAL::Polyhedron_incremental_builder_3 Builder ; + typedef CGAL::Halfedge_around_source_iterator out_edge_iterator; + typedef GraphTraits::halfedge_descriptor halfedge_descriptor; + typedef GraphTraits::vertex_descriptor vertex_descriptor; + typedef CGAL::Polyhedron_incremental_builder_3 Builder; Link_builder() : mVIdx(0) {} - void add_vertex( Builder& aBuilder, Vertex_const_handle v ) + void add_vertex(Builder& aBuilder, Vertex_const_handle v) { aBuilder.add_vertex(v->point()); - mMap.insert( make_pair(v->id(),mVIdx++) ); + mMap.insert(make_pair(v->id(),mVIdx++)); } - void add_triangle( Builder& aBuilder, Profile::Triangle const& aTri ) + void add_triangle(Builder& aBuilder, Profile::Triangle const& aTri) { aBuilder.begin_facet(); - aBuilder.add_vertex_to_facet( mMap[aTri.v0->id()] ); - aBuilder.add_vertex_to_facet( mMap[aTri.v1->id()] ); - aBuilder.add_vertex_to_facet( mMap[aTri.v2->id()] ); + aBuilder.add_vertex_to_facet(mMap[aTri.v0->id()]); + aBuilder.add_vertex_to_facet(mMap[aTri.v1->id()]); + aBuilder.add_vertex_to_facet(mMap[aTri.v2->id()]); aBuilder.end_facet(); } }; @@ -94,26 +94,26 @@ protected: // Constructs a flat polyhedron containing just the link of an edge class Edge_link_builder : public Link_builder { - Profile const& mProfile ; + const Profile& mProfile; public: - Edge_link_builder( Profile const& aProfile ) : mProfile(aProfile) {} + Edge_link_builder(const Profile& aProfile) : mProfile(aProfile) {} - void operator()( Surface::HalfedgeDS& hds) + void operator()(Surface::HalfedgeDS& hds) { - Builder B( hds, true); + Builder B(hds, true); - B.begin_surface( 2 + mProfile.link().size(), mProfile.triangles().size() ); + B.begin_surface(2 + mProfile.link().size(), mProfile.triangles().size()); this->add_vertex(B,mProfile.v0()); this->add_vertex(B,mProfile.v1()); - for ( Profile::vertex_descriptor_vector::const_iterator vit = mProfile.link().begin(); vit != mProfile.link().end(); ++ vit ) - this->add_vertex(B, *vit ); + for(Profile::vertex_descriptor_vector::const_iterator vit = mProfile.link().begin(); vit != mProfile.link().end(); ++ vit) + this->add_vertex(B, *vit); - for ( Profile::Triangle_vector::const_iterator tit = mProfile.triangles().begin(); tit != mProfile.triangles().end(); ++ tit ) + for(Profile::Triangle_vector::const_iterator tit = mProfile.triangles().begin(); tit != mProfile.triangles().end(); ++ tit) this->add_triangle(B,*tit); B.end_surface(); @@ -123,227 +123,227 @@ public: // Constructs a flat polyhedron containing just the link of a vertex class Vertex_link_builder : public Link_builder { - Surface* m_tm ; - Vertex_handle mV ; + Surface* m_tm; + Vertex_handle mV; - Surface& tm() { return *m_tm ; } + Surface& tm() { return *m_tm; } public: - Vertex_link_builder( Surface& aTM, Vertex_handle aV) : m_tm(&aTM), mV(aV) {} + Vertex_link_builder(Surface& aTM, Vertex_handle aV) : m_tm(&aTM), mV(aV) {} - void operator()( Surface::HalfedgeDS& hds ) + void operator()(Surface::HalfedgeDS& hds) { - Builder B( hds, true); + Builder B(hds, true); - B.begin_surface( 1 + out_degree(mV,tm()), out_degree(mV,tm()) ); + B.begin_surface(1 + out_degree(mV,tm()), out_degree(mV,tm())); this->add_vertex(B,mV); - Profile::Triangle_vector triangles ; + Profile::Triangle_vector triangles; - out_edge_iterator eb, ee ; - for ( boost::tie(eb,ee) = halfedges_around_source(opposite(halfedge(mV,tm()),tm()),tm()) ; eb != ee ; ++ eb ) + out_edge_iterator eb, ee; + for(boost::tie(eb,ee) = halfedges_around_source(opposite(halfedge(mV,tm()),tm()),tm()); eb != ee; ++ eb) { - halfedge_descriptor out_edge1 = *eb ; + halfedge_descriptor out_edge1 = *eb; halfedge_descriptor out_edge2 = out_edge1->opposite()->next(); vertex_descriptor v1 = target(out_edge1,tm()); vertex_descriptor v2 = target(out_edge2,tm()); this->add_vertex(B,v1); - triangles.push_back( Profile::Triangle(mV,v1,v2) ) ; + triangles.push_back(Profile::Triangle(mV,v1,v2)); } - for ( Profile::Triangle_vector::const_iterator tit = triangles.begin(); tit != triangles.end(); ++ tit ) + for(Profile::Triangle_vector::const_iterator tit = triangles.begin(); tit != triangles.end(); ++ tit) this->add_triangle(B,*tit); B.end_surface(); } }; -SurfaceSP create_edge_link ( Profile const& aProfile ) +SurfaceSP create_edge_link (const Profile& aProfile) { - SurfaceSP rLink( new Surface ); + SurfaceSP rLink(new Surface); try { - Edge_link_builder lBuilder(aProfile) ; + Edge_link_builder lBuilder(aProfile); rLink->delegate(lBuilder); } catch(...) { - cerr << "Unable to create local mesh" << endl ; + cerr << "Unable to create local mesh" << endl; } - return rLink ; + return rLink; } -SurfaceSP create_vertex_link ( Profile const& aProfile, Vertex_handle aV ) +SurfaceSP create_vertex_link (const Profile& aProfile, Vertex_handle aV) { - SurfaceSP rLink( new Surface ); + SurfaceSP rLink(new Surface); try { - Vertex_link_builder lBuilder(aProfile.surface(),aV) ; + Vertex_link_builder lBuilder(aProfile.surface(),aV); rLink->delegate(lBuilder); } - catch ( ... ) + catch (...) { - cerr << "Unable to create local mesh" << endl ; + cerr << "Unable to create local mesh" << endl; } - return rLink ; + return rLink; } -void write ( SurfaceSP aSurface, string aName ) +void write (SurfaceSP aSurface, string aName) { ofstream out(aName.c_str()); - out << *aSurface ; + out << *aSurface; } template -string opt2str ( boost::optional const& o ) +string opt2str (boost::optional const& o) { - ostringstream ss ; - if ( o ) - ss << *o ; - else ss << "" ; + ostringstream ss; + if(o) + ss << *o; + else ss << ""; return ss.str(); } template -string float2str ( N n ) +string float2str (N n) { - return boost::str( boost::format("%+05.19g") % to_double(n) ) ; + return boost::str(boost::format("%+05.19g") % to_double(n)); } template -string point2str ( P const& p ) +string point2str (P const& p) { - return boost::str( boost::format( "(%+05.19g %+05.19g %+05.19g)") % to_double(p.x()) % to_double(p.y()) % to_double(p.z()) ) ; + return boost::str(boost::format("(%+05.19g %+05.19g %+05.19g)") % to_double(p.x()) % to_double(p.y()) % to_double(p.z())); } template -string optpoint2str ( boost::optional

const& p ) +string optpoint2str (boost::optional

const& p) { - ostringstream ss ; - if ( p ) + ostringstream ss; + if(p) ss << point2str(*p); - else ss << "" ; + else ss << ""; return ss.str(); } template -string optfloat2str ( boost::optional const& n ) +string optfloat2str (boost::optional const& n) { - ostringstream ss ; - if ( n ) + ostringstream ss; + if(n) ss << float2str(*n); - else ss << "" ; + else ss << ""; return ss.str(); } template -string vertex2str ( V const& v ) +string vertex2str (V const& v) { - ostringstream ss ; - ss << "[V" << v->id() << point2str(v->point()) << "]" ; + ostringstream ss; + ss << "[V" << v->id() << point2str(v->point()) << "]"; return ss.str(); } template -string edge2str ( E const& e ) +string edge2str (E const& e) { - ostringstream ss ; - ss << "{E" << e->id() << vertex2str(e->opposite()->vertex()) << "->" << vertex2str(e->vertex()) << "}" ; + ostringstream ss; + ss << "{E" << e->id() << vertex2str(e->opposite()->vertex()) << "->" << vertex2str(e->vertex()) << "}"; return ss.str(); } -template ostream& operator << ( ostream& os, boost::optional const& o ) { return os << opt2str(o); } +template ostream& operator << (ostream& os, boost::optional const& o) { return os << opt2str(o); } -string normalize_EOL ( string line ) +string normalize_EOL (string line) { string::size_type l = line.length(); - string::size_type d = ( l > 0 && line[l-1] == '\r' ) ? 1 : 0 ; - return line.substr(0, l-d ) ; + string::size_type d = (l > 0 && line[l-1] == '\r') ? 1 : 0; + return line.substr(0, l-d); } #define REPORT_ERROR(msg) error(__FILE__,__LINE__,0, msg); #define REPORT_ERROR2(pred,msg) REPORT_ERROR(msg) -#define CHECK_MSG(pred,msg) if (!(pred)) REPORT_ERROR2(#pred,msg) +#define CHECK_MSG(pred,msg) if(!(pred)) REPORT_ERROR2(#pred,msg) #define CHECK(pred) CHECK_MSG(pred,string("")) -#define CHECK_EQUAL(x,y) CHECK_MSG(((x)==(y)), str(format("Assertion failed: %1%(=%2%)==%3%(=%4%)") % (#x) % (x) % (#y) % (y) ) ) -#define CHECK_NOT_EQUAL(x,y) CHECK_MSG(((x)!=(y)), str(format("Assertion failed: %1%(=%2%)!=%3%(=%4%)") % (#x) % (x) % (#y) % (y) ) ) +#define CHECK_EQUAL(x,y) CHECK_MSG(((x)==(y)), str(format("Assertion failed: %1%(=%2%)==%3%(=%4%)") % (#x) % (x) % (#y) % (y))) +#define CHECK_NOT_EQUAL(x,y) CHECK_MSG(((x)!=(y)), str(format("Assertion failed: %1%(=%2%)!=%3%(=%4%)") % (#x) % (x) % (#y) % (y))) class Visitor : public SMS::Edge_collapse_visitor_base { public : - Visitor( string aTestCase ) : mTestCase(aTestCase) + Visitor(string aTestCase) : mTestCase(aTestCase) { #ifdef CGAL_SMS_TRACE_IMPL - ::internal::cgal_enable_sms_trace = true ; + ::internal::cgal_enable_sms_trace = true; #endif - mStep = 0 ; + mStep = 0; } virtual ~Visitor() { } - virtual void OnStarted( Surface& ) const + virtual void OnStarted(Surface&) const { } - virtual void OnFinished ( Surface& aSurface ) const + virtual void OnFinished (Surface& aSurface) const { CHECK(aSurface.is_valid()); } - virtual void OnCollected( Profile const& aProfile, boost::optional const& aCost ) const + virtual void OnCollected(const Profile& aProfile, boost::optional const& aCost) const { - TEST_TRACE( str ( format("Collecting %1% : cost=%2%") % edge2str(aProfile.v0_v1()) % optfloat2str(aCost) ) ) ; + TEST_TRACE(str (format("Collecting %1% : cost=%2%") % edge2str(aProfile.v0_v1()) % optfloat2str(aCost))); } - virtual void OnCollapsing( Profile const& aProfile, boost::optional const& aP ) const + virtual void OnCollapsing(const Profile& aProfile, boost::optional const& aP) const { - TEST_TRACE( str ( format("S %1% - Collapsing %2% : placement=%3%") % mStep % edge2str(aProfile.v0_v1()) % optpoint2str(aP) ) ) ; + TEST_TRACE(str (format("S %1% - Collapsing %2% : placement=%3%") % mStep % edge2str(aProfile.v0_v1()) % optpoint2str(aP))); //mBefore = create_edge_link(aProfile); } - virtual void OnCollapsed( Profile const& aProfile, Vertex_handle const& aV ) const + virtual void OnCollapsed(const Profile& aProfile, Vertex_handle const& aV) const { // Some collapse can result in self-intersections in any case, so we can't mark it as a failure - if ( false && Is_self_intersecting( aProfile.surface() ) ) + if(false && Is_self_intersecting(aProfile.surface())) { SurfaceSP lAfter = create_vertex_link(aProfile, aV); - write(mBefore, str( format( "%1%.step-%2%-before.off" ) % mTestCase % mStep ) ) ; - write(lAfter , str( format( "%1%.step-%2%-after.off" ) % mTestCase % mStep ) ) ; + write(mBefore, str(format("%1%.step-%2%-before.off") % mTestCase % mStep)); + write(lAfter , str(format("%1%.step-%2%-after.off") % mTestCase % mStep)); - REPORT_ERROR( str( format("Resulting surface self-intersects after step %1% (%2% edges left)") % mStep % ( aProfile.surface().size_of_halfedges() / 2 ) ) ) ; + REPORT_ERROR(str(format("Resulting surface self-intersects after step %1% (%2% edges left)") % mStep % (aProfile.surface().size_of_halfedges() / 2))); } - ++ mStep ; + ++ mStep; } private: - void error ( char const* file, int line, char const* pred, string msg ) const + void error (char const* file, int line, char const* pred, string msg) const { - cerr << "ERROR in " << file << " at " << line << endl ; - if ( pred ) - cerr << " Assertion failed: " << pred << endl ; - cerr << " " << msg << endl ; + cerr << "ERROR in " << file << " at " << line << endl; + if(pred) + cerr << " Assertion failed: " << pred << endl; + cerr << " " << msg << endl; throw runtime_error(""); @@ -351,100 +351,100 @@ private: private: - string mTestCase ; - mutable int mStep ; + string mTestCase; + mutable int mStep; mutable SurfaceSP mBefore; -} ; +}; -bool sWriteResult = false ; -bool sUseMP = false ; -int sStop = 1 ; +bool sWriteResult = false; +bool sUseMP = false; +int sStop = 1; -bool Test ( string aName ) +bool Test (string aName) { - bool rSucceeded = false ; + bool rSucceeded = false; try { - string off_name = aName ; + string off_name = aName; ifstream off_is(off_name.c_str()); - if ( off_is ) + if(off_is) { Surface lSurface; - off_is >> lSurface ; - if ( lSurface.is_valid() ) + off_is >> lSurface; + if(lSurface.is_valid()) { - if ( lSurface.is_pure_triangle() ) + if(lSurface.is_pure_triangle()) { - cerr << "Processing " << aName << " (" << ( lSurface.size_of_halfedges() / 2 ) << " edges)" << endl ; + cerr << "Processing " << aName << " (" << (lSurface.size_of_halfedges() / 2) << " edges)" << endl; - Visitor vis(aName) ; + Visitor vis(aName); set_halfedgeds_items_id(lSurface); SMS::Count_stop_predicate stop(sStop); - Real_timer t ; t.start(); + Real_timer t; t.start(); - if ( sUseMP ) + if(sUseMP) { - SMS::Edge_length_cost cost ; - SMS::Midpoint_placement placement ; + SMS::Edge_length_cost cost; + SMS::Midpoint_placement placement; - edge_collapse(lSurface,stop,CGAL::parameters::get_cost(cost).get_placement(placement).visitor(vis) ); + edge_collapse(lSurface,stop,CGAL::parameters::get_cost(cost).get_placement(placement).visitor(vis)); } else { - SMS::LindstromTurk_cost cost ; - SMS::LindstromTurk_placement placement ; + SMS::LindstromTurk_cost cost; + SMS::LindstromTurk_placement placement; - edge_collapse(lSurface,stop,CGAL::parameters::get_cost(cost).get_placement(placement).visitor(vis) ); + edge_collapse(lSurface,stop,CGAL::parameters::get_cost(cost).get_placement(placement).visitor(vis)); } t.stop(); - rSucceeded = lSurface.is_valid() && lSurface.is_pure_triangle() ; + rSucceeded = lSurface.is_valid() && lSurface.is_pure_triangle(); - cerr << "\r" << aName << ( rSucceeded ? " succeeded" : "FAILED" ) << ". Elapsed time=" << t.time() << " seconds." << endl ; + cerr << "\r" << aName << (rSucceeded ? " succeeded" : "FAILED") << ". Elapsed time=" << t.time() << " seconds." << endl; - if ( sWriteResult ) + if(sWriteResult) { - string out_name = off_name ; - out_name.replace( off_name.find_last_of('.'), 15, ".simplified.off"); + string out_name = off_name; + out_name.replace(off_name.find_last_of('.'), 15, ".simplified.off"); ofstream out(out_name.c_str()); - out << lSurface ; - cerr << "Result written into: " << out_name << endl ; + out << lSurface; + cerr << "Result written into: " << out_name << endl; } } else { - cerr << "Surface is not triangulated (has faces with more than 3 sides): " << aName << endl ; + cerr << "Surface is not triangulated (has faces with more than 3 sides): " << aName << endl; } } else { - cerr << "Invalid surface: " << aName << endl ; + cerr << "Invalid surface: " << aName << endl; } } else { - cerr << "Unable to open test file " << aName << endl ; + cerr << "Unable to open test file " << aName << endl; } } - catch ( std::exception const& x ) + catch (std::exception const& x) { string what(x.what()); - if ( what.length() > 0 ) - cerr << "Exception caught: " << what << endl ; + if(what.length() > 0) + cerr << "Exception caught: " << what << endl; } - return rSucceeded ; + return rSucceeded; } -int main( int argc, char** argv ) +int main(int argc, char** argv) { set_error_handler (error_handler); set_warning_handler(error_handler); @@ -452,52 +452,52 @@ int main( int argc, char** argv ) cout << setprecision(4); cerr << setprecision(4); - vector lCases ; + vector lCases; - for ( int i = 1 ; i < argc ; ++i ) + for(int i = 1; i < argc; ++i) { - if ( argv[i][0] == '-' ) + if(argv[i][0] == '-') { switch(argv[i][1]) { - case 'w': sWriteResult = true ; break ; - case 's': sStop = atoi(&argv[i][2]) ; break ; - case 'm': sUseMP = true ; break ; + case 'w': sWriteResult = true; break; + case 's': sStop = atoi(&argv[i][2]); break; + case 'm': sUseMP = true; break; } } else { - string c( normalize_EOL( string(argv[i]) ) ) ; - string::size_type pos = c.find_last_of(".") ; - if ( pos != string::npos ) + string c(normalize_EOL(string(argv[i]))); + string::size_type pos = c.find_last_of("."); + if(pos != string::npos) { string ext = c.substr(pos); - if ( ext == ".off" ) + if(ext == ".off") lCases.push_back(c); } } } - if ( lCases.size() == 0 ) + if(lCases.size() == 0) { - cout << "collapse_edge_test file0 [-w] [-sNUM_EDGES] [-m] file1 ... fileN\n" ; - return 1 ; + cout << "collapse_edge_test file0 [-w] [-sNUM_EDGES] [-m] file1 ... fileN\n"; + return 1; } else { - unsigned lOK = 0 ; - for ( vector::const_iterator it = lCases.begin(); it != lCases.end() ; ++ it ) + unsigned lOK = 0; + for(vector::const_iterator it = lCases.begin(); it != lCases.end(); ++ it) { - if ( Test(*it) ) - ++ lOK ; + if(Test(*it)) + ++ lOK; } cout << endl << lOK << " cases succedded." << endl - << (lCases.size() - lOK ) << " cases failed." << endl ; + << (lCases.size() - lOK) << " cases failed." << endl; - return lOK == lCases.size() ? 0 : 1 ; + return lOK == lCases.size() ? 0 : 1; } } @@ -505,15 +505,15 @@ int main( int argc, char** argv ) namespace CGAL { -void assertion_fail( const char* expr, const char* file, int line ) +void assertion_fail(const char* expr, const char* file, int line) { assertion_fail(expr,file,line,""); } -void precondition_fail( const char* expr, const char* file, int line ) +void precondition_fail(const char* expr, const char* file, int line) { precondition_fail(expr,file,line,""); } -void postcondition_fail( const char* expr, const char* file, int line ) +void postcondition_fail(const char* expr, const char* file, int line) { postcondition_fail(expr,file,line,""); } diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_profile_link.cpp b/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_profile_link.cpp index 57bf10f33eb..aba46096325 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_profile_link.cpp +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/test_edge_profile_link.cpp @@ -13,12 +13,12 @@ void naive_all_triangles(Mesh::Halfedge_index h, Mesh& m, std::set> m; assert(num_vertices(m)!=0); A a; @@ -77,18 +77,18 @@ void test(const char* fname) Profile profile(h, m, a, get(boost::vertex_point, m), a, true); - if (CGAL::Euler::does_satisfy_link_condition(edge(h, m), m)) + if(CGAL::Euler::does_satisfy_link_condition(edge(h, m), m)) { std::set link_vertices; naive_link_vertices(h, m, triangles, link_vertices); - assert( link_vertices.size()==profile.link().size() ); - assert( std::set(profile.link().begin(), + assert(link_vertices.size()==profile.link().size()); + assert(std::set(profile.link().begin(), profile.link().end()).size() - == link_vertices.size() ); + == link_vertices.size()); for(const Mesh::Vertex_index& v : profile.link()) { - assert( link_vertices.count(v) == 1 ); + assert(link_vertices.count(v) == 1); } } @@ -96,23 +96,23 @@ void test(const char* fname) std::set > triple_set; for(const Profile::Triangle& t : profile.triangles()) { - triple_set.insert( make_canonical_tuple(t) ); + triple_set.insert(make_canonical_tuple(t)); } for(Mesh::Face_index f : triangles) { - assert( triple_set.count( make_canonical_tuple(f, m) ) == 1 ); + assert(triple_set.count(make_canonical_tuple(f, m)) == 1); } } } int main(int argc, char** argv) { - for (int i=1; i triangles; struct Intersect_facets { - void operator()( const Box* b, const Box* c) const + void operator()(const Box* b, const Box* c) const { Halfedge_const_handle h = b->handle()->halfedge(); // check for shared egde --> no intersection - if ( h->opposite()->facet() == c->handle() + if(h->opposite()->facet() == c->handle() || h->next()->opposite()->facet() == c->handle() || h->next()->next()->opposite()->facet() == c->handle()) return; // check for shared vertex --> maybe intersection, maybe not Halfedge_const_handle g = c->handle()->halfedge(); Halfedge_const_handle v; - if ( h->vertex() == g->vertex()) + if(h->vertex() == g->vertex()) v = g; - if ( h->vertex() == g->next()->vertex()) + if(h->vertex() == g->next()->vertex()) v = g->next(); - if ( h->vertex() == g->next()->next()->vertex()) + if(h->vertex() == g->next()->next()->vertex()) v = g->next()->next(); - if ( v == Halfedge_const_handle()) { + if(v == Halfedge_const_handle()) { h = h->next(); - if ( h->vertex() == g->vertex()) + if(h->vertex() == g->vertex()) v = g; - if ( h->vertex() == g->next()->vertex()) + if(h->vertex() == g->next()->vertex()) v = g->next(); - if ( h->vertex() == g->next()->next()->vertex()) + if(h->vertex() == g->next()->next()->vertex()) v = g->next()->next(); - if ( v == Halfedge_const_handle()) { + if(v == Halfedge_const_handle()) { h = h->next(); - if ( h->vertex() == g->vertex()) + if(h->vertex() == g->vertex()) v = g; - if ( h->vertex() == g->next()->vertex()) + if(h->vertex() == g->next()->vertex()) v = g->next(); - if ( h->vertex() == g->next()->next()->vertex()) + if(h->vertex() == g->next()->next()->vertex()) v = g->next()->next(); } } - if ( v != Halfedge_const_handle()) { + if(v != Halfedge_const_handle()) { // found shared vertex: - assert( h->vertex() == v->vertex()); + assert(h->vertex() == v->vertex()); // geomtric check if the opposite segments intersect the triangles - Triangle t1( h->vertex()->point(), + Triangle t1(h->vertex()->point(), h->next()->vertex()->point(), h->next()->next()->vertex()->point()); - Triangle t2( v->vertex()->point(), + Triangle t2(v->vertex()->point(), v->next()->vertex()->point(), v->next()->next()->vertex()->point()); - Segment s1( h->next()->vertex()->point(), + Segment s1(h->next()->vertex()->point(), h->next()->next()->vertex()->point()); - Segment s2( v->next()->vertex()->point(), + Segment s2(v->next()->vertex()->point(), v->next()->next()->vertex()->point()); - if ( CGAL::do_intersect( t1, s2)) { + if(CGAL::do_intersect(t1, s2)) { //cerr << "Triangles intersect (t1,s2):\n T1: " << t1 // << "\n T2 :" << t2 << endl; triangles.push_back(t1); triangles.push_back(t2); - } else if ( CGAL::do_intersect( t2, s1)) { + } else if(CGAL::do_intersect(t2, s1)) { //cerr << "Triangles intersect (t2,s1):\n T1: " << t1 // << "\n T2 :" << t2 << endl; triangles.push_back(t1); @@ -76,13 +76,13 @@ struct Intersect_facets return; } // check for geometric intersection - Triangle t1( h->vertex()->point(), + Triangle t1(h->vertex()->point(), h->next()->vertex()->point(), h->next()->next()->vertex()->point()); - Triangle t2( g->vertex()->point(), + Triangle t2(g->vertex()->point(), g->next()->vertex()->point(), g->next()->next()->vertex()->point()); - if ( CGAL::do_intersect( t1, t2)) { + if(CGAL::do_intersect(t1, t2)) { //cerr << "Triangles intersect:\n T1: " << t1 << "\n T2 :" // << t2 << endl; triangles.push_back(t1); @@ -92,26 +92,26 @@ struct Intersect_facets }; -bool Is_self_intersecting( Surface const& s ) +bool Is_self_intersecting(Surface const& s) { std::vector boxes; - boxes.reserve( s.size_of_facets()); - for ( Facet_const_iterator i = s.facets_begin(); i != s.facets_end(); ++i) + boxes.reserve(s.size_of_facets()); + for(Facet_const_iterator i = s.facets_begin(); i != s.facets_end(); ++i) { boxes.push_back( - Box( i->halfedge()->vertex()->point().bbox() + Box(i->halfedge()->vertex()->point().bbox() + i->halfedge()->next()->vertex()->point().bbox() + i->halfedge()->next()->next()->vertex()->point().bbox(), i)); } std::vector box_ptr; - box_ptr.reserve( s.size_of_facets()); - for ( std::vector::iterator j = boxes.begin(); j != boxes.end(); ++j) + box_ptr.reserve(s.size_of_facets()); + for(std::vector::iterator j = boxes.begin(); j != boxes.end(); ++j) { - box_ptr.push_back( &*j); + box_ptr.push_back(&*j); } - CGAL::box_self_intersection_d( box_ptr.begin(), box_ptr.end(), + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), Intersect_facets(), std::ptrdiff_t(2000)); - return triangles.size() > 0 ; + return triangles.size() > 0; }