2017-01-11 17:27:44 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <OpenMesh/Core/Mesh/BaseKernel.hh>
|
|
|
|
|
#include <OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh>
|
|
|
|
|
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
namespace OpenMesh {
|
|
|
|
|
namespace Subdivider {
|
|
|
|
|
namespace Uniform {
|
|
|
|
|
|
2017-01-12 17:09:27 +01:00
|
|
|
/**
|
|
|
|
|
* Midpoint subdivision algorithm.
|
|
|
|
|
*
|
2017-01-13 16:56:02 +01:00
|
|
|
* With every step, the set of vertices is replaced by the midpoints of all
|
2017-01-12 17:09:27 +01:00
|
|
|
* current edges. Then, two sets of faces are created to set up the new
|
|
|
|
|
* connectivity: From all midpoints of edges surrounding an original face, a new
|
|
|
|
|
* face is created. Also, for all midpoints of edges surrounding an original
|
|
|
|
|
* vertex, a new face is created.
|
|
|
|
|
*
|
|
|
|
|
* @note This algorithm ignores the _update_points option.
|
|
|
|
|
* @note This algorithm is best suited for closed meshes since boundaries tend
|
|
|
|
|
* to fragment into isolated faces after a few iterations.
|
|
|
|
|
*/
|
2017-01-11 17:27:44 +01:00
|
|
|
template<typename MeshType, typename RealType = double>
|
|
|
|
|
class MidpointT : public SubdividerT<MeshType, RealType>
|
|
|
|
|
{
|
|
|
|
|
public:
|
2017-01-12 13:38:57 +01:00
|
|
|
typedef RealType real_t;
|
|
|
|
|
typedef MeshType mesh_t;
|
|
|
|
|
typedef SubdividerT<MeshType, RealType> parent_t;
|
2017-01-11 17:27:44 +01:00
|
|
|
|
2017-01-12 13:38:57 +01:00
|
|
|
// Inherited constructors
|
|
|
|
|
MidpointT() : parent_t() {}
|
|
|
|
|
MidpointT(mesh_t& _m) : parent_t(_m) {}
|
2017-01-11 17:27:44 +01:00
|
|
|
|
|
|
|
|
const char* name() const { return "midpoint"; }
|
|
|
|
|
|
|
|
|
|
protected: // SubdividerT interface
|
2017-01-12 13:38:57 +01:00
|
|
|
bool prepare(mesh_t& _m)
|
2017-01-11 17:27:44 +01:00
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-12 17:09:27 +01:00
|
|
|
//! Performs one step of Midpoint subdivision.
|
|
|
|
|
//! @note The _update_points option is ignored
|
2017-01-12 13:38:57 +01:00
|
|
|
bool subdivide(mesh_t& _m, size_t _n, const bool _update_points = true)
|
2017-01-11 17:27:44 +01:00
|
|
|
{
|
2017-01-13 17:22:06 +01:00
|
|
|
_m.request_halfedge_status();
|
|
|
|
|
_m.request_edge_status();
|
|
|
|
|
_m.request_vertex_status();
|
|
|
|
|
_m.request_face_status();
|
2017-01-12 13:38:57 +01:00
|
|
|
PropertyManager<EPropHandleT<typename mesh_t::VertexHandle>, mesh_t> edge_midpoint(_m, "edge_midpoint");
|
|
|
|
|
PropertyManager<VPropHandleT<bool>, mesh_t> is_original_vertex(_m, "is_original_vertex");
|
2017-01-11 17:27:44 +01:00
|
|
|
|
|
|
|
|
for (size_t iteration = 0; iteration < _n; ++iteration) {
|
|
|
|
|
is_original_vertex.set_range(_m.vertices_begin(), _m.vertices_end(), true);
|
|
|
|
|
// Create vertices on edge midpoints
|
2017-01-12 13:38:57 +01:00
|
|
|
for (typename mesh_t::EdgeIter it = _m.edges_begin(), end = _m.edges_end(); it != end; ++it) {
|
|
|
|
|
EdgeHandle eh = *it;
|
|
|
|
|
VertexHandle new_vh = _m.new_vertex(_m.calc_edge_midpoint(eh));
|
2017-01-11 17:27:44 +01:00
|
|
|
edge_midpoint[eh] = new_vh;
|
|
|
|
|
is_original_vertex[new_vh] = false;
|
|
|
|
|
}
|
|
|
|
|
// Create new faces from original faces
|
2017-01-12 13:38:57 +01:00
|
|
|
for (typename mesh_t::FaceIter it = _m.faces_begin(), end = _m.faces_end(); it != end; ++it) {
|
|
|
|
|
FaceHandle fh = *it;
|
2017-01-11 17:27:44 +01:00
|
|
|
std::vector<typename mesh_t::VertexHandle> new_corners;
|
2017-01-12 13:38:57 +01:00
|
|
|
for (typename mesh_t::FaceEdgeIter it = _m.fe_begin(fh), end = _m.fe_end(fh); it != end; ++it) {
|
|
|
|
|
EdgeHandle eh = *it;
|
2017-01-11 17:27:44 +01:00
|
|
|
new_corners.push_back(edge_midpoint[eh]);
|
|
|
|
|
}
|
|
|
|
|
_m.add_face(new_corners);
|
|
|
|
|
}
|
|
|
|
|
// Create new faces from original vertices
|
2017-01-12 13:38:57 +01:00
|
|
|
for (typename mesh_t::VertexIter it = _m.vertices_begin(), end = _m.vertices_end(); it != end; ++it) {
|
|
|
|
|
VertexHandle vh = *it;
|
2017-01-11 17:27:44 +01:00
|
|
|
if (is_original_vertex[vh]) {
|
|
|
|
|
if (!_m.is_boundary(vh)) {
|
|
|
|
|
std::vector<typename mesh_t::VertexHandle> new_corners;
|
2017-01-12 13:38:57 +01:00
|
|
|
for (typename mesh_t::VertexEdgeIter it = _m.ve_begin(vh), end = _m.ve_end(vh); it != end; ++it) {
|
|
|
|
|
EdgeHandle eh = *it;
|
2017-01-11 17:27:44 +01:00
|
|
|
new_corners.push_back(edge_midpoint[eh]);
|
|
|
|
|
}
|
2017-01-12 13:38:57 +01:00
|
|
|
std::reverse(new_corners.begin(), new_corners.end());
|
2017-01-11 17:27:44 +01:00
|
|
|
_m.add_face(new_corners);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-01-12 13:38:57 +01:00
|
|
|
for (typename mesh_t::VertexIter it = _m.vertices_begin(), end = _m.vertices_end(); it != end; ++it) {
|
|
|
|
|
VertexHandle vh = *it;
|
2017-01-11 17:27:44 +01:00
|
|
|
if (is_original_vertex[vh]) {
|
|
|
|
|
_m.delete_vertex(vh);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-01-13 17:22:06 +01:00
|
|
|
_m.garbage_collection();
|
2017-01-11 17:27:44 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-12 13:38:57 +01:00
|
|
|
bool cleanup(mesh_t& _m)
|
2017-01-11 17:27:44 +01:00
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace Uniform
|
|
|
|
|
} // namespace Subdivider
|
|
|
|
|
} // namespace OpenMesh
|