From cb3c68eca2bbf2633fd43602f6b2786a98ffa653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Thu, 19 Sep 2019 14:29:54 +0200 Subject: [PATCH] Rework the storing of cost marices for GH simplification --- .../Edge_collapse/GarlandHeckbert_cost.h | 74 ++++++++++++++----- .../GarlandHeckbert_cost_stop_predicate.h | 13 ++-- .../Edge_collapse/GarlandHeckbert_placement.h | 44 +++++------ .../internal/GarlandHeckbert_core.h | 4 +- .../internal/Edge_collapse.h | 37 +++++++++- 5 files changed, 124 insertions(+), 48 deletions(-) diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost.h index 43c78fea7b9..c37710b51e7 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost.h @@ -26,6 +26,8 @@ #include #include +#include + #include #include @@ -33,25 +35,51 @@ namespace CGAL { namespace Surface_mesh_simplification { -template +template +struct GarlandHeckbert_cost_matrix +{ + typedef internal::GarlandHeckbert_core GH_Core; + typedef typename GH_Core::Matrix4x4 type; +}; + +template class GarlandHeckbert_cost { + typedef TM_ TM; + typedef VCM_ Vertex_cost_map; + public: - typedef TM_ TM; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename internal::GarlandHeckbertCore GHC; - typedef typename GHC::garland_heckbert_state_type garland_heckbert_state_type; - typedef typename GHC::Matrix4x4 Matrix4x4; - typedef typename GHC::Row4 Row4; - typedef typename GHC::Col4 Col4; + typedef internal::GarlandHeckbert_core GH_Core; - typedef typename GHC::FT FT; - typedef typename boost::optional Optional_FT; + typedef typename GH_Core::Matrix4x4 Matrix4x4; + typedef typename GH_Core::Col4 Col4; - GarlandHeckbert_cost(const garland_heckbert_state_type& aCostMatrices) - : mCostMatrices(aCostMatrices) + typedef typename GH_Core::FT FT; + typedef typename boost::optional Optional_FT; + + // Tells the edge collapse main function that we need to call "initialize" + // and "update" functions. A bit awkward, but still better than abusing visitors. + typedef CGAL::Tag_true Update_tag; + + GarlandHeckbert_cost(Vertex_cost_map& vcm, + const FT discontinuity_multiplier = 100) + : + m_cost_matrices(vcm), + m_discontinuity_multiplier(discontinuity_multiplier) { } + void initialize(const TM& tmesh) const + { + for(const halfedge_descriptor h : halfedges(tmesh)) + { + const vertex_descriptor v = target(h, tmesh); + put(m_cost_matrices, v, GH_Core::fundamental_error_quadric(h, tmesh, m_discontinuity_multiplier)); + } + } + template boost::optional operator()(const Profile& aProfile, @@ -60,19 +88,29 @@ public: if(!aPlacement) return boost::optional(); - Matrix4x4 combinedMatrix = std::move(GHC::combine_matrices( - mCostMatrices.at(aProfile.v0()), - mCostMatrices.at(aProfile.v1()))); + CGAL_precondition(get(m_cost_matrices, aProfile.v0()) != Matrix4x4()); + CGAL_precondition(get(m_cost_matrices, aProfile.v1()) != Matrix4x4()); - Col4 pt = std::move(GHC::point_to_homogenous_column(*aPlacement)); - - Optional_FT cost = (pt.transpose() * combinedMatrix * pt)(0, 0); + const Matrix4x4 combined_matrix = GH_Core::combine_matrices(get(m_cost_matrices, aProfile.v0()), + get(m_cost_matrices, aProfile.v1())); + const Col4 pt = GH_Core::point_to_homogenous_column(*aPlacement); + const Optional_FT cost = (pt.transpose() * combined_matrix * pt)(0, 0); return cost; } + template + void update_after_collapse(const Profile& aProfile, + const vertex_descriptor new_v) const + { + put(m_cost_matrices, new_v, + GH_Core::combine_matrices(get(m_cost_matrices, aProfile.v0()), + get(m_cost_matrices, aProfile.v1()))); + } + private: - const garland_heckbert_state_type& mCostMatrices; + Vertex_cost_map m_cost_matrices; + const FT m_discontinuity_multiplier; }; } // namespace Surface_mesh_simplification diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost_stop_predicate.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost_stop_predicate.h index 972692b9e01..3f44c34cc29 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost_stop_predicate.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_cost_stop_predicate.h @@ -26,10 +26,10 @@ namespace CGAL { namespace Surface_mesh_simplification { -template +template class GarlandHeckbert_cost_stop_predicate { - const FT m_gh_cost_threshold; + typedef FT_ FT; public: GarlandHeckbert_cost_stop_predicate(const FT gh_cost_threshold) @@ -37,14 +37,17 @@ public: m_gh_cost_threshold(gh_cost_threshold) { } - template - bool operator()(const F& aCurrentCost, + template + bool operator()(const FT& current_cost, const Profile&, std::size_t, std::size_t) const { - return aCurrentCost >= m_gh_cost_threshold; + return current_cost >= m_gh_cost_threshold; } + +private: + const FT m_gh_cost_threshold; }; } // namespace Surface_mesh_simplification diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_placement.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_placement.h index 8fb475436d0..dbb1fef98c2 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_placement.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/GarlandHeckbert_placement.h @@ -24,50 +24,52 @@ #include #include -#include #include +#include namespace CGAL { namespace Surface_mesh_simplification { -template +template class GarlandHeckbert_placement { public: - typedef TM_ TM; - typedef typename internal::GarlandHeckbertCore GHC; - typedef typename GHC::garland_heckbert_state_type garland_heckbert_state_type; - typedef typename GHC::Matrix4x4 Matrix4x4; - typedef typename GHC::Row4 Row4; - typedef typename GHC::Col4 Col4; + typedef TM_ TM; + typedef VCM_ Vertex_cost_map; - typedef typename GHC::FT FT; - typedef typename boost::optional Optional_FT; + typedef typename internal::GarlandHeckbert_core GH_core; + typedef typename GH_core::Matrix4x4 Matrix4x4; + typedef typename GH_core::Col4 Col4; - GarlandHeckbert_placement(const garland_heckbert_state_type& aCostMatrices) - : mCostMatrices(aCostMatrices) + GarlandHeckbert_placement(const Vertex_cost_map& cost_matrices) + : m_cost_matrices(cost_matrices) { } template boost::optional operator()(const Profile& aProfile) const { - const Matrix4x4 combinedMatrix = std::move(GHC::combine_matrices( - mCostMatrices.at(aProfile.v0()), - mCostMatrices.at(aProfile.v1()))); + CGAL_precondition(get(m_cost_matrices, aProfile.v0()) != Matrix4x4()); + CGAL_precondition(get(m_cost_matrices, aProfile.v1()) != Matrix4x4()); - const Col4 p0 = std::move(GHC::point_to_homogenous_column(aProfile.p0())); - const Col4 p1 = std::move(GHC::point_to_homogenous_column(aProfile.p1())); - const Col4 opt = std::move(GHC::optimal_point(combinedMatrix, p0, p1)); + // the combined matrix has already been computed in the evaluation of the cost... + const Matrix4x4 combinedMatrix = GH_core::combine_matrices( + get(m_cost_matrices, aProfile.v0()), + get(m_cost_matrices, aProfile.v1())); - boost::optional pt - = typename Profile::Point(opt(0) / opt(3), opt(1) / opt(3), opt(2) / opt(3)); + const Col4 p0 = GH_core::point_to_homogenous_column(aProfile.p0()); + const Col4 p1 = GH_core::point_to_homogenous_column(aProfile.p1()); + const Col4 opt = GH_core::optimal_point(combinedMatrix, p0, p1); + + boost::optional pt = typename Profile::Point(opt(0) / opt(3), + opt(1) / opt(3), + opt(2) / opt(3)); return pt; } private: - const garland_heckbert_state_type& mCostMatrices; + const Vertex_cost_map m_cost_matrices; }; } // namespace Surface_mesh_simplification diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h index b315fa70604..25d748d01f8 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h @@ -39,7 +39,7 @@ namespace Surface_mesh_simplification { namespace internal { template -struct GarlandHeckbertCore +struct GarlandHeckbert_core { typedef TM_ TM; typedef boost::graph_traits GraphTraits; @@ -61,8 +61,6 @@ struct GarlandHeckbertCore typedef typename Eigen::Matrix Row4; typedef typename Eigen::Matrix Col4; - typedef std::unordered_map garland_heckbert_state_type; - static Col4 point_to_homogenous_column(const Point& pt) { return Col4(pt.x(), pt.y(), pt.z(), FT(1)); diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h index c638f262539..478edd48e7b 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/internal/Edge_collapse.h @@ -33,6 +33,21 @@ namespace CGAL { namespace Surface_mesh_simplification { +namespace internal { + +BOOST_MPL_HAS_XXX_TRAIT_DEF(Update_tag) + +template ::value> +struct Oracles_require_updates : + public CGAL::Boolean_tag + // when Mesh_domain has the nested type Has_features +{ }; + +template +struct Oracles_require_updates : public CGAL::Tag_false { }; + +} // namespace internal // Implementation of the vertex-pair collapse triangulated surface mesh simplification algorithm template::value> + void initialize_oracles() const { }; + template <> + void initialize_oracles() const { Get_cost.initialize(mSurface); } + + template ::value> + void update_oracles_after_collapse(const Profile& /*aProfile*/, const vertex_descriptor /*aKeptV*/) const { }; + template <> + void update_oracles_after_collapse(const Profile& aProfile, const vertex_descriptor aKeptV) const + { + Get_cost.update_after_collapse(aProfile, aKeptV); + } + 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); @@ -426,6 +455,9 @@ run() Visitor.OnStarted(mSurface); + // this is similar to the visitor, but for the cost/stop/placement oracles + initialize_oracles(); + // First collect all candidate edges in a PQ collect(); @@ -550,7 +582,9 @@ collect() 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); + update_oracles_after_collapse(lProfile, rResult); } CGAL_SMS_TRACE(0, "Initial edge count: " << mInitialEdgeCount); @@ -1196,7 +1230,8 @@ collapse(const Profile& aProfile, put(Vertex_point_map,rResult,*aPlacement); } - Visitor.OnCollapsed(aProfile,rResult); + Visitor.OnCollapsed(aProfile, rResult); + update_oracles_after_collapse(aProfile, rResult); update_neighbors(rResult);