Commit 693d0664 authored by Philip Trettner's avatar Philip Trettner
Browse files

added can_add_face interface, made obj more robust, fixed add_or_get_edge bug

parent 5bc97ea6
......@@ -134,6 +134,7 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
std::vector<face> poly;
std::vector<halfedge_handle> poly_hs;
std::vector<vertex_index> poly_vs;
std::string fs;
std::string line_s;
......@@ -205,6 +206,7 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
else if (type == "f")
{
poly_hs.clear();
poly_vs.clear();
poly.clear();
while (line.good())
......@@ -244,6 +246,7 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
f.vh = mesh.handle_of(vertex_index(f.v - 1));
poly.push_back(f);
poly_vs.push_back(f.vh);
}
if (poly.size() < 3)
......@@ -252,6 +255,12 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
continue;
}
if (!mesh.faces().can_add(poly_vs))
{
n_error_faces++;
continue;
}
poly_hs.resize(poly.size());
for (auto i = 0u; i < poly.size(); ++i)
{
......@@ -302,10 +311,16 @@ void obj_reader::parse(std::istream &in, Mesh &mesh)
std::cerr << "Unable to parse line " << line_nr << ": " << line_s << std::endl;
}
}
if (n_error_faces > 0)
{
std::cerr << "skipped " << n_error_faces << " face(s) because mesh would become non-manifold" << std::endl;
}
}
void polymesh::read_obj(const std::string &filename, Mesh &mesh, vertex_attribute<glm::vec3> &position)
bool polymesh::read_obj(const std::string &filename, Mesh &mesh, vertex_attribute<glm::vec3> &position)
{
obj_reader reader(filename, mesh);
position = reader.positions_vec3();
return reader.error_faces() == 0;
}
......@@ -14,7 +14,7 @@ void write_obj(std::string const& filename,
vertex_attribute<glm::vec3> const& position,
vertex_attribute<glm::vec2> const* tex_coord = nullptr,
vertex_attribute<glm::vec3> const* normal = nullptr);
void read_obj(std::string const& filename, Mesh& mesh, vertex_attribute<glm::vec3>& position);
bool read_obj(std::string const& filename, Mesh& mesh, vertex_attribute<glm::vec3>& position);
struct obj_writer
{
......@@ -56,11 +56,16 @@ public:
halfedge_attribute<glm::vec2> tex_coords_vec2() const;
halfedge_attribute<glm::vec3> normals_vec3() const;
/// Number of faces that could not be added
int error_faces() const { return n_error_faces; }
private:
void parse(std::istream& in, Mesh& mesh);
vertex_attribute<glm::vec4> positions;
halfedge_attribute<glm::vec3> tex_coords;
halfedge_attribute<glm::vec3> normals;
int n_error_faces = 0;
};
}
......@@ -41,54 +41,201 @@ tmp::ref_if_mut<halfedge_index, MeshT> low_level_api_base<MeshT>::outgoing_halfe
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_all_faces() const
{
return m.size_all_faces();
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_all_vertices() const
{
return m.size_all_vertices();
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_all_edges() const
{
return m.size_all_edges();
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_all_halfedges() const
{
return m.size_all_halfedges();
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_valid_faces() const
{
return m.size_valid_faces();
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_valid_vertices() const
{
return m.size_valid_vertices();
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_valid_edges() const
{
return m.size_valid_edges();
}
template<class MeshT>
template <class MeshT>
int low_level_api_base<MeshT>::size_valid_halfedges() const
{
return m.size_valid_halfedges();
}
template <class MeshT>
bool low_level_api_base<MeshT>::can_add_face(const vertex_handle *v_handles, int vcnt) const
{
if (vcnt < 3)
return false; // too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for (auto i = 0; i < vcnt; ++i)
{
if (!is_boundary(v_handles[i]))
return false; // must be boundary
auto v0 = v_handles[i];
auto v1 = v_handles[(i + 1) % vcnt];
auto v2 = v_handles[(i + 2) % vcnt];
auto h0 = find_halfedge(v0, v1);
auto h1 = find_halfedge(v1, v2);
if (h0.is_valid() && !is_boundary(h0))
return false; // must be boundary
if (h0.is_invalid())
continue; // will be added
if (h1.is_invalid())
continue; // will be added
if (to_vertex_of(h0) != from_vertex_of(h1))
return false; // not a chain
if (next_halfedge_of(h0) == h1)
continue; // correctly wired
if (find_free_incident(opposite(h1), h0).is_invalid())
return false; // non-manifold
}
return true;
}
template <class MeshT>
bool low_level_api_base<MeshT>::can_add_face(const vertex_index *v_indices, int vcnt) const
{
if (vcnt < 3)
return false; // too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for (auto i = 0; i < vcnt; ++i)
{
if (!is_boundary(v_indices[i]))
return false; // must be boundary
auto v0 = v_indices[i];
auto v1 = v_indices[(i + 1) % vcnt];
auto v2 = v_indices[(i + 2) % vcnt];
auto h0 = find_halfedge(v0, v1);
auto h1 = find_halfedge(v1, v2);
if (h0.is_valid() && !is_boundary(h0))
return false; // must be boundary
if (h0.is_invalid())
continue; // will be added
if (h1.is_invalid())
continue; // will be added
if (to_vertex_of(h0) != from_vertex_of(h1))
return false; // not a chain
if (!is_free(h0))
return false; // already contains a face
if (next_halfedge_of(h0) == h1)
continue; // correctly wired
if (find_free_incident(opposite(h1), h0).is_invalid())
return false; // non-manifold
}
return true;
}
template <class MeshT>
bool low_level_api_base<MeshT>::can_add_face(const halfedge_handle *half_loop, int vcnt) const
{
if (vcnt < 3)
return false; // too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for (auto i = 0; i < vcnt; ++i)
{
auto h0 = half_loop[i].idx;
auto h1 = half_loop[(i + 1) % vcnt].idx;
if (to_vertex_of(h0) != from_vertex_of(h1))
return false; // not a chain
if (!is_free(h0))
return false; // already contains a face
if (next_halfedge_of(h0) == h1)
continue; // correctly wired
if (find_free_incident(opposite(h1), h0).is_invalid())
return false; // non-manifold
}
return true;
}
template <class MeshT>
bool low_level_api_base<MeshT>::can_add_face(const halfedge_index *half_loop, int vcnt) const
{
if (vcnt < 3)
return false; // too few vertices
// TODO: check duplicated vertices
// ensure that half-edges are adjacent at each vertex
for (auto i = 0; i < vcnt; ++i)
{
auto h0 = half_loop[i];
auto h1 = half_loop[(i + 1) % vcnt];
if (to_vertex_of(h0) != from_vertex_of(h1))
return false; // not a chain
if (!is_free(h0))
return false; // already contains a face
if (next_halfedge_of(h0) == h1)
continue; // correctly wired
if (find_free_incident(opposite(h1), h0).is_invalid())
return false; // non-manifold
}
return true;
}
template <class MeshT>
halfedge_index low_level_api_base<MeshT>::find_free_incident(halfedge_index in_begin, halfedge_index in_end) const
{
......
......@@ -104,8 +104,8 @@ inline edge_index low_level_api_mutable::add_or_get_edge(vertex_index v_from, ve
// setup data (self-connected edge)
to_vertex_of(h_from_to) = v_to;
to_vertex_of(h_to_from) = v_from;
next_halfedge_of(h_from_to) = h_to_from;
next_halfedge_of(h_to_from) = h_from_to;
connect_prev_next(h_from_to, h_to_from);
connect_prev_next(h_to_from, h_from_to);
// link from vertex
if (is_isolated(v_from))
......
......@@ -660,24 +660,48 @@ face_handle face_collection<iterator>::add(const vertex_handle *v_handles, int v
return this->mesh->handle_of(low_level_api(this->mesh).add_face(v_handles, vcnt));
}
template <class iterator>
face_handle face_collection<iterator>::add(const vertex_index *v_indices, int vcnt) const
{
return this->mesh->handle_of(low_level_api(this->mesh).add_face(v_indices, vcnt));
}
template <class iterator>
face_handle face_collection<iterator>::add(const halfedge_handle *half_loop, int vcnt) const
{
return this->mesh->handle_of(low_level_api(this->mesh).add_face(half_loop, vcnt));
}
template <class iterator>
face_handle face_collection<iterator>::add(const halfedge_index *half_loop, int vcnt) const
{
return this->mesh->handle_of(low_level_api(this->mesh).add_face(half_loop, vcnt));
}
template <class iterator>
face_handle face_collection<iterator>::add(std::vector<vertex_handle> const &v_handles) const
{
return add(v_handles.data(), v_handles.size());
}
template <class iterator>
face_handle face_collection<iterator>::add(std::vector<vertex_index> const &v_indices) const
{
return add(v_indices.data(), v_indices.size());
}
template <class iterator>
face_handle face_collection<iterator>::add(std::vector<halfedge_handle> const &half_loop) const
{
return add(half_loop.data(), (int)half_loop.size());
}
template <class iterator>
face_handle face_collection<iterator>::add(std::vector<halfedge_index> const &half_loop) const
{
return add(half_loop.data(), (int)half_loop.size());
}
template <class iterator>
face_handle face_collection<iterator>::add(vertex_handle v0, vertex_handle v1, vertex_handle v2) const
{
......@@ -735,6 +759,111 @@ face_handle face_collection<iterator>::add(const halfedge_handle (&half_loop)[N]
return this->mesh->handle_of(low_level_api(this->mesh).add_face(hs, N));
}
template <class iterator>
bool face_collection<iterator>::can_add(const vertex_handle *v_handles, int vcnt) const
{
return low_level_api(this->mesh).can_add_face(v_handles, vcnt);
}
template <class iterator>
bool face_collection<iterator>::can_add(const vertex_index *v_indices, int vcnt) const
{
return low_level_api(this->mesh).can_add_face(v_indices, vcnt);
}
template <class iterator>
bool face_collection<iterator>::can_add(const halfedge_handle *half_loop, int vcnt) const
{
return low_level_api(this->mesh).can_add_face(half_loop, vcnt);
}
template <class iterator>
bool face_collection<iterator>::can_add(const halfedge_index *half_loop, int vcnt) const
{
return low_level_api(this->mesh).can_add_face(half_loop, vcnt);
}
template <class iterator>
bool face_collection<iterator>::can_add(std::vector<vertex_handle> const &v_handles) const
{
return can_add(v_handles.data(), v_handles.size());
}
template <class iterator>
bool face_collection<iterator>::can_add(std::vector<vertex_index> const &v_indices) const
{
return can_add(v_indices.data(), v_indices.size());
}
template <class iterator>
bool face_collection<iterator>::can_add(std::vector<halfedge_handle> const &half_loop) const
{
return can_add(half_loop.data(), (int)half_loop.size());
}
template <class iterator>
bool face_collection<iterator>::can_add(std::vector<halfedge_index> const &half_loop) const
{
return can_add(half_loop.data(), (int)half_loop.size());
}
template <class iterator>
bool face_collection<iterator>::can_add(vertex_handle v0, vertex_handle v1, vertex_handle v2) const
{
halfedge_index hs[3] = {
low_level_api(this->mesh).can_add_or_get_halfedge(v0.idx, v1.idx), //
low_level_api(this->mesh).can_add_or_get_halfedge(v1.idx, v2.idx), //
low_level_api(this->mesh).can_add_or_get_halfedge(v2.idx, v0.idx), //
};
return low_level_api(this->mesh).can_add_face(hs, 3);
}
template <class iterator>
bool face_collection<iterator>::can_add(vertex_handle v0, vertex_handle v1, vertex_handle v2, vertex_handle v3) const
{
halfedge_index hs[4] = {
low_level_api(this->mesh).can_add_or_get_halfedge(v0.idx, v1.idx), //
low_level_api(this->mesh).can_add_or_get_halfedge(v1.idx, v2.idx), //
low_level_api(this->mesh).can_add_or_get_halfedge(v2.idx, v3.idx), //
low_level_api(this->mesh).can_add_or_get_halfedge(v3.idx, v0.idx), //
};
return low_level_api(this->mesh).can_add_face(hs, 4);
}
template <class iterator>
bool face_collection<iterator>::can_add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2) const
{
halfedge_index hs[3] = {h0.idx, h1.idx, h2.idx};
return low_level_api(this->mesh).can_add_face(hs, 3);
}
template <class iterator>
bool face_collection<iterator>::can_add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2, halfedge_handle h3) const
{
halfedge_index hs[4] = {h0.idx, h1.idx, h2.idx, h3.idx};
return low_level_api(this->mesh).can_add_face(hs, 4);
}
template <class iterator>
template <size_t N>
bool face_collection<iterator>::can_add(const vertex_handle (&v_handles)[N]) const
{
halfedge_index hs[N];
for (auto i = 0; i < N; ++i)
hs[i] = low_level_api(this->mesh).find_halfedge(v_handles[i].idx, v_handles[(i + 1) % N].idx);
return low_level_api(this->mesh).can_add_face(hs, N);
}
template <class iterator>
template <size_t N>
bool face_collection<iterator>::can_add(const halfedge_handle (&half_loop)[N]) const
{
halfedge_index hs[N];
for (auto i = 0; i < N; ++i)
hs[i] = half_loop[i].idx;
return low_level_api(this->mesh).can_add_face(hs, N);
}
template <class iterator>
edge_handle edge_collection<iterator>::add_or_get(vertex_handle v_from, vertex_handle v_to) const
{
......
......@@ -64,6 +64,14 @@ public:
face_index prev_valid_idx_from(face_index idx) const;
halfedge_index prev_valid_idx_from(halfedge_index idx) const;
// modification checks
public:
/// Returns true iff the face can be added
bool can_add_face(vertex_handle const* v_handles, int vcnt) const;
bool can_add_face(vertex_index const* v_indices, int vcnt) const;
bool can_add_face(halfedge_handle const* half_loop, int vcnt) const;
bool can_add_face(halfedge_index const* half_loop, int vcnt) const;
// topology helper
public:
/// Returns the opposite of a given valid half-edge
......@@ -296,5 +304,4 @@ inline low_level_api_const low_level_api(Mesh const& m) { return {m}; }
inline low_level_api_const low_level_api(Mesh const* m) { return {*m}; }
inline low_level_api_mutable low_level_api(Mesh& m) { return {m}; }
inline low_level_api_mutable low_level_api(Mesh* m) { return {*m}; }
}
......@@ -263,13 +263,35 @@ struct face_collection : smart_collection<Mesh*, face_tag, iterator>
face_handle add(vertex_handle v0, vertex_handle v1, vertex_handle v2) const;
face_handle add(vertex_handle v0, vertex_handle v1, vertex_handle v2, vertex_handle v3) const;
face_handle add(std::vector<vertex_handle> const& v_handles) const;
face_handle add(std::vector<vertex_index> const& v_indices) const;
face_handle add(vertex_handle const* v_handles, int vcnt) const;
face_handle add(vertex_index const* v_indices, int vcnt) const;
template <size_t N>
face_handle add(const halfedge_handle (&half_loop)[N]) const;
face_handle add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2) const;
face_handle add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2, halfedge_handle h3) const;
face_handle add(std::vector<halfedge_handle> const& half_loop) const;
face_handle add(std::vector<halfedge_index> const& half_loop) const;
face_handle add(halfedge_handle const* half_loop, int vcnt) const;
face_handle add(halfedge_index const* half_loop, int vcnt) const;
/// Returns true if face can be added
template <size_t N>
bool can_add(const vertex_handle (&v_handles)[N]) const;
bool can_add(vertex_handle v0, vertex_handle v1, vertex_handle v2) const;
bool can_add(vertex_handle v0, vertex_handle v1, vertex_handle v2, vertex_handle v3) const;
bool can_add(std::vector<vertex_handle> const& v_handles) const;
bool can_add(std::vector<vertex_index> const& v_indices) const;
bool can_add(vertex_handle const* v_handles, int vcnt) const;
bool can_add(vertex_index const* v_indices, int vcnt) const;
template <size_t N>
bool can_add(const halfedge_handle (&half_loop)[N]) const;
bool can_add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2) const;
bool can_add(halfedge_handle h0, halfedge_handle h1, halfedge_handle h2, halfedge_handle h3) const;
bool can_add(std::vector<halfedge_handle> const& half_loop) const;
bool can_add(std::vector<halfedge_index> const& half_loop) const;
bool can_add(halfedge_handle const* half_loop, int vcnt) const;
bool can_add(halfedge_index const* half_loop, int vcnt) const;
/// Splits a face by inserting a vertex (which is returned) and creating triangles towards it
/// Preserves half-edge attributes
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment