Rework the storing of cost marices for GH simplification

This commit is contained in:
Mael Rouxel-Labbé 2019-09-19 14:29:54 +02:00
parent 4a0f4536d6
commit cb3c68eca2
5 changed files with 124 additions and 48 deletions

View File

@ -26,6 +26,8 @@
#include <CGAL/Surface_mesh_simplification/internal/Common.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h>
#include <CGAL/tags.h>
#include <boost/optional/optional.hpp>
#include <utility>
@ -33,25 +35,51 @@
namespace CGAL {
namespace Surface_mesh_simplification {
template<class TM_>
template <typename TM_>
struct GarlandHeckbert_cost_matrix
{
typedef internal::GarlandHeckbert_core<TM_> GH_Core;
typedef typename GH_Core::Matrix4x4 type;
};
template <typename TM_, typename VCM_>
class GarlandHeckbert_cost
{
typedef TM_ TM;
typedef VCM_ Vertex_cost_map;
public:
typedef TM_ TM;
typedef typename boost::graph_traits<TM>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
typedef typename internal::GarlandHeckbertCore<TM> 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<TM> GH_Core;
typedef typename GHC::FT FT;
typedef typename boost::optional<FT> 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<FT> 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 <typename Profile>
boost::optional<typename Profile::FT>
operator()(const Profile& aProfile,
@ -60,19 +88,29 @@ public:
if(!aPlacement)
return boost::optional<typename Profile::FT>();
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 <typename Profile>
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

View File

@ -26,10 +26,10 @@
namespace CGAL {
namespace Surface_mesh_simplification {
template <class FT>
template <class FT_>
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 <typename F, typename Profile>
bool operator()(const F& aCurrentCost,
template <typename Profile>
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

View File

@ -24,50 +24,52 @@
#include <CGAL/license/Surface_mesh_simplification.h>
#include <CGAL/Surface_mesh_simplification/internal/Common.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/Lindstrom_Turk_core.h>
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h>
#include <boost/optional/optional.hpp>
namespace CGAL {
namespace Surface_mesh_simplification {
template<class TM_>
template<class TM_, typename VCM_>
class GarlandHeckbert_placement
{
public:
typedef TM_ TM;
typedef typename internal::GarlandHeckbertCore<TM> 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<FT> Optional_FT;
typedef typename internal::GarlandHeckbert_core<TM> 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 <typename Profile>
boost::optional<typename Profile::Point> 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<typename Profile::Point> 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<typename Profile::Point> 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

View File

@ -39,7 +39,7 @@ namespace Surface_mesh_simplification {
namespace internal {
template<class TM_>
struct GarlandHeckbertCore
struct GarlandHeckbert_core
{
typedef TM_ TM;
typedef boost::graph_traits<TM> GraphTraits;
@ -61,8 +61,6 @@ struct GarlandHeckbertCore
typedef typename Eigen::Matrix<FT, 1, 4> Row4;
typedef typename Eigen::Matrix<FT, 4, 1> Col4;
typedef std::unordered_map<vertex_descriptor, Matrix4x4> garland_heckbert_state_type;
static Col4 point_to_homogenous_column(const Point& pt)
{
return Col4(pt.x(), pt.y(), pt.z(), FT(1));

View File

@ -33,6 +33,21 @@
namespace CGAL {
namespace Surface_mesh_simplification {
namespace internal {
BOOST_MPL_HAS_XXX_TRAIT_DEF(Update_tag)
template <typename Cost_oracle,
bool has_Update_tag = has_Update_tag<Cost_oracle>::value>
struct Oracles_require_updates :
public CGAL::Boolean_tag<Cost_oracle::Update_tag::value>
// when Mesh_domain has the nested type Has_features
{ };
template <typename Cost_oracle>
struct Oracles_require_updates<Cost_oracle, false> : public CGAL::Tag_false { };
} // namespace internal
// Implementation of the vertex-pair collapse triangulated surface mesh simplification algorithm
template<class TM_,
@ -171,8 +186,22 @@ public:
int run();
private:
template <bool Tag = internal::Oracles_require_updates<GetCost>::value>
void initialize_oracles() const { };
template <>
void initialize_oracles<true>() const { Get_cost.initialize(mSurface); }
template <bool Tag = internal::Oracles_require_updates<GetCost>::value>
void update_oracles_after_collapse(const Profile& /*aProfile*/, const vertex_descriptor /*aKeptV*/) const { };
template <>
void update_oracles_after_collapse<true>(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);