mirror of https://github.com/CGAL/cgal
Rework the storing of cost marices for GH simplification
This commit is contained in:
parent
4a0f4536d6
commit
cb3c68eca2
|
|
@ -26,6 +26,8 @@
|
||||||
#include <CGAL/Surface_mesh_simplification/internal/Common.h>
|
#include <CGAL/Surface_mesh_simplification/internal/Common.h>
|
||||||
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h>
|
#include <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h>
|
||||||
|
|
||||||
|
#include <CGAL/tags.h>
|
||||||
|
|
||||||
#include <boost/optional/optional.hpp>
|
#include <boost/optional/optional.hpp>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
@ -33,25 +35,51 @@
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
namespace Surface_mesh_simplification {
|
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
|
class GarlandHeckbert_cost
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
typedef TM_ TM;
|
typedef TM_ TM;
|
||||||
|
typedef VCM_ Vertex_cost_map;
|
||||||
|
|
||||||
typedef typename internal::GarlandHeckbertCore<TM> GHC;
|
public:
|
||||||
typedef typename GHC::garland_heckbert_state_type garland_heckbert_state_type;
|
typedef typename boost::graph_traits<TM>::vertex_descriptor vertex_descriptor;
|
||||||
typedef typename GHC::Matrix4x4 Matrix4x4;
|
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
|
||||||
typedef typename GHC::Row4 Row4;
|
|
||||||
typedef typename GHC::Col4 Col4;
|
|
||||||
|
|
||||||
typedef typename GHC::FT FT;
|
typedef internal::GarlandHeckbert_core<TM> GH_Core;
|
||||||
|
|
||||||
|
typedef typename GH_Core::Matrix4x4 Matrix4x4;
|
||||||
|
typedef typename GH_Core::Col4 Col4;
|
||||||
|
|
||||||
|
typedef typename GH_Core::FT FT;
|
||||||
typedef typename boost::optional<FT> Optional_FT;
|
typedef typename boost::optional<FT> Optional_FT;
|
||||||
|
|
||||||
GarlandHeckbert_cost(const garland_heckbert_state_type& aCostMatrices)
|
// Tells the edge collapse main function that we need to call "initialize"
|
||||||
: mCostMatrices(aCostMatrices)
|
// 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>
|
template <typename Profile>
|
||||||
boost::optional<typename Profile::FT>
|
boost::optional<typename Profile::FT>
|
||||||
operator()(const Profile& aProfile,
|
operator()(const Profile& aProfile,
|
||||||
|
|
@ -60,19 +88,29 @@ public:
|
||||||
if(!aPlacement)
|
if(!aPlacement)
|
||||||
return boost::optional<typename Profile::FT>();
|
return boost::optional<typename Profile::FT>();
|
||||||
|
|
||||||
Matrix4x4 combinedMatrix = std::move(GHC::combine_matrices(
|
CGAL_precondition(get(m_cost_matrices, aProfile.v0()) != Matrix4x4());
|
||||||
mCostMatrices.at(aProfile.v0()),
|
CGAL_precondition(get(m_cost_matrices, aProfile.v1()) != Matrix4x4());
|
||||||
mCostMatrices.at(aProfile.v1())));
|
|
||||||
|
|
||||||
Col4 pt = std::move(GHC::point_to_homogenous_column(*aPlacement));
|
const Matrix4x4 combined_matrix = GH_Core::combine_matrices(get(m_cost_matrices, aProfile.v0()),
|
||||||
|
get(m_cost_matrices, aProfile.v1()));
|
||||||
Optional_FT cost = (pt.transpose() * combinedMatrix * pt)(0, 0);
|
const Col4 pt = GH_Core::point_to_homogenous_column(*aPlacement);
|
||||||
|
const Optional_FT cost = (pt.transpose() * combined_matrix * pt)(0, 0);
|
||||||
|
|
||||||
return cost;
|
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:
|
private:
|
||||||
const garland_heckbert_state_type& mCostMatrices;
|
Vertex_cost_map m_cost_matrices;
|
||||||
|
const FT m_discontinuity_multiplier;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Surface_mesh_simplification
|
} // namespace Surface_mesh_simplification
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,10 @@
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
namespace Surface_mesh_simplification {
|
namespace Surface_mesh_simplification {
|
||||||
|
|
||||||
template <class FT>
|
template <class FT_>
|
||||||
class GarlandHeckbert_cost_stop_predicate
|
class GarlandHeckbert_cost_stop_predicate
|
||||||
{
|
{
|
||||||
const FT m_gh_cost_threshold;
|
typedef FT_ FT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GarlandHeckbert_cost_stop_predicate(const FT gh_cost_threshold)
|
GarlandHeckbert_cost_stop_predicate(const FT gh_cost_threshold)
|
||||||
|
|
@ -37,14 +37,17 @@ public:
|
||||||
m_gh_cost_threshold(gh_cost_threshold)
|
m_gh_cost_threshold(gh_cost_threshold)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
template <typename F, typename Profile>
|
template <typename Profile>
|
||||||
bool operator()(const F& aCurrentCost,
|
bool operator()(const FT& current_cost,
|
||||||
const Profile&,
|
const Profile&,
|
||||||
std::size_t,
|
std::size_t,
|
||||||
std::size_t) const
|
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
|
} // namespace Surface_mesh_simplification
|
||||||
|
|
|
||||||
|
|
@ -24,50 +24,52 @@
|
||||||
#include <CGAL/license/Surface_mesh_simplification.h>
|
#include <CGAL/license/Surface_mesh_simplification.h>
|
||||||
|
|
||||||
#include <CGAL/Surface_mesh_simplification/internal/Common.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 <CGAL/Surface_mesh_simplification/Policies/Edge_collapse/internal/GarlandHeckbert_core.h>
|
||||||
|
|
||||||
|
#include <boost/optional/optional.hpp>
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
namespace Surface_mesh_simplification {
|
namespace Surface_mesh_simplification {
|
||||||
|
|
||||||
template<class TM_>
|
template<class TM_, typename VCM_>
|
||||||
class GarlandHeckbert_placement
|
class GarlandHeckbert_placement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef TM_ TM;
|
typedef TM_ TM;
|
||||||
typedef typename internal::GarlandHeckbertCore<TM> GHC;
|
typedef VCM_ Vertex_cost_map;
|
||||||
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 typename GHC::FT FT;
|
typedef typename internal::GarlandHeckbert_core<TM> GH_core;
|
||||||
typedef typename boost::optional<FT> Optional_FT;
|
typedef typename GH_core::Matrix4x4 Matrix4x4;
|
||||||
|
typedef typename GH_core::Col4 Col4;
|
||||||
|
|
||||||
GarlandHeckbert_placement(const garland_heckbert_state_type& aCostMatrices)
|
GarlandHeckbert_placement(const Vertex_cost_map& cost_matrices)
|
||||||
: mCostMatrices(aCostMatrices)
|
: m_cost_matrices(cost_matrices)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
template <typename Profile>
|
template <typename Profile>
|
||||||
boost::optional<typename Profile::Point> operator()(const Profile& aProfile) const
|
boost::optional<typename Profile::Point> operator()(const Profile& aProfile) const
|
||||||
{
|
{
|
||||||
const Matrix4x4 combinedMatrix = std::move(GHC::combine_matrices(
|
CGAL_precondition(get(m_cost_matrices, aProfile.v0()) != Matrix4x4());
|
||||||
mCostMatrices.at(aProfile.v0()),
|
CGAL_precondition(get(m_cost_matrices, aProfile.v1()) != Matrix4x4());
|
||||||
mCostMatrices.at(aProfile.v1())));
|
|
||||||
|
|
||||||
const Col4 p0 = std::move(GHC::point_to_homogenous_column(aProfile.p0()));
|
// the combined matrix has already been computed in the evaluation of the cost...
|
||||||
const Col4 p1 = std::move(GHC::point_to_homogenous_column(aProfile.p1()));
|
const Matrix4x4 combinedMatrix = GH_core::combine_matrices(
|
||||||
const Col4 opt = std::move(GHC::optimal_point(combinedMatrix, p0, p1));
|
get(m_cost_matrices, aProfile.v0()),
|
||||||
|
get(m_cost_matrices, aProfile.v1()));
|
||||||
|
|
||||||
boost::optional<typename Profile::Point> pt
|
const Col4 p0 = GH_core::point_to_homogenous_column(aProfile.p0());
|
||||||
= typename Profile::Point(opt(0) / opt(3), opt(1) / opt(3), opt(2) / opt(3));
|
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;
|
return pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const garland_heckbert_state_type& mCostMatrices;
|
const Vertex_cost_map m_cost_matrices;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Surface_mesh_simplification
|
} // namespace Surface_mesh_simplification
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ namespace Surface_mesh_simplification {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template<class TM_>
|
template<class TM_>
|
||||||
struct GarlandHeckbertCore
|
struct GarlandHeckbert_core
|
||||||
{
|
{
|
||||||
typedef TM_ TM;
|
typedef TM_ TM;
|
||||||
typedef boost::graph_traits<TM> GraphTraits;
|
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, 1, 4> Row4;
|
||||||
typedef typename Eigen::Matrix<FT, 4, 1> Col4;
|
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)
|
static Col4 point_to_homogenous_column(const Point& pt)
|
||||||
{
|
{
|
||||||
return Col4(pt.x(), pt.y(), pt.z(), FT(1));
|
return Col4(pt.x(), pt.y(), pt.z(), FT(1));
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,21 @@
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
namespace Surface_mesh_simplification {
|
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
|
// Implementation of the vertex-pair collapse triangulated surface mesh simplification algorithm
|
||||||
template<class TM_,
|
template<class TM_,
|
||||||
|
|
@ -171,8 +186,22 @@ public:
|
||||||
int run();
|
int run();
|
||||||
|
|
||||||
private:
|
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 collect();
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
bool is_collapse_topologically_valid(const Profile& aProfile);
|
bool is_collapse_topologically_valid(const Profile& aProfile);
|
||||||
bool is_tetrahedron(const halfedge_descriptor h1);
|
bool is_tetrahedron(const halfedge_descriptor h1);
|
||||||
bool is_open_triangle(const halfedge_descriptor h1);
|
bool is_open_triangle(const halfedge_descriptor h1);
|
||||||
|
|
@ -426,6 +455,9 @@ run()
|
||||||
|
|
||||||
Visitor.OnStarted(mSurface);
|
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
|
// First collect all candidate edges in a PQ
|
||||||
collect();
|
collect();
|
||||||
|
|
||||||
|
|
@ -550,7 +582,9 @@ collect()
|
||||||
Placement_type lPlacement = lProfile.p0();
|
Placement_type lPlacement = lProfile.p0();
|
||||||
vertex_descriptor rResult = halfedge_collapse_bk_compatibility(lProfile.v0_v1(), Edge_is_constrained_map);
|
vertex_descriptor rResult = halfedge_collapse_bk_compatibility(lProfile.v0_v1(), Edge_is_constrained_map);
|
||||||
put(Vertex_point_map, rResult, *lPlacement);
|
put(Vertex_point_map, rResult, *lPlacement);
|
||||||
|
|
||||||
Visitor.OnCollapsed(lProfile, rResult);
|
Visitor.OnCollapsed(lProfile, rResult);
|
||||||
|
update_oracles_after_collapse(lProfile, rResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGAL_SMS_TRACE(0, "Initial edge count: " << mInitialEdgeCount);
|
CGAL_SMS_TRACE(0, "Initial edge count: " << mInitialEdgeCount);
|
||||||
|
|
@ -1197,6 +1231,7 @@ collapse(const Profile& aProfile,
|
||||||
}
|
}
|
||||||
|
|
||||||
Visitor.OnCollapsed(aProfile, rResult);
|
Visitor.OnCollapsed(aProfile, rResult);
|
||||||
|
update_oracles_after_collapse(aProfile, rResult);
|
||||||
|
|
||||||
update_neighbors(rResult);
|
update_neighbors(rResult);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue