| #pragma once |
| |
| #ifndef TCG_MESH_HPP |
| #define TCG_MESH_HPP |
| |
| |
| #include "../mesh.h" |
| |
| namespace tcg { |
| |
| |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int Mesh<V, E, F>::edgeInciding(int vIdx1, int vIdx2, int n) const { |
| const V &v1 = vertex(vIdx1); |
| |
| const tcg::list<int> &incidingV1 = v1.edges(); |
| tcg::list<int>::const_iterator it; |
| |
| for (it = incidingV1.begin(); it != incidingV1.end(); ++it) { |
| const E &e = edge(*it); |
| if (e.otherVertex(vIdx1) == vIdx2 && n-- == 0) break; |
| } |
| |
| return (it == incidingV1.end()) ? -1 : (*it); |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int Mesh<V, E, F>::addEdge(const E &ed) { |
| int e = int(m_edges.push_back(ed)); |
| m_edges[e].setIndex(e); |
| |
| |
| typename edge_traits<E>::vertices_const_iterator it, end(ed.verticesEnd()); |
| for (it = ed.verticesBegin(); it != end; ++it) m_vertices[*it].addEdge(e); |
| |
| return e; |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int Mesh<V, E, F>::addFace(const F &fc) { |
| int f = int(m_faces.push_back(fc)); |
| m_faces[f].setIndex(f); |
| |
| |
| typename face_traits<F>::edges_const_iterator it, end = fc.edgesEnd(); |
| for (it = fc.edgesBegin(); it != end; ++it) m_edges[*it].addFace(f); |
| |
| return f; |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| void Mesh<V, E, F>::removeVertex(int v) { |
| V &vx = vertex(v); |
| |
| |
| while (vx.edgesCount() > 0) removeEdge(vx.edges().front()); |
| |
| m_vertices.erase(v); |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| void Mesh<V, E, F>::removeEdge(int e) { |
| E &ed = edge(e); |
| |
| |
| typename edge_traits<E>::faces_iterator ft; |
| while ((ft = ed.facesBegin()) != |
| ed.facesEnd()) |
| removeFace(*ft); |
| |
| |
| typename edge_traits<E>::vertices_iterator vt, vEnd = ed.verticesEnd(); |
| for (vt = ed.verticesBegin(); vt != vEnd; ++vt) { |
| V &vx = vertex(*vt); |
| typename vertex_traits<V>::edges_iterator et = |
| std::find(vx.edgesBegin(), vx.edgesEnd(), e); |
| |
| assert(et != vx.edgesEnd()); |
| vx.eraseEdge(et); |
| } |
| |
| m_edges.erase(e); |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| void Mesh<V, E, F>::removeFace(int f) { |
| F &fc = face(f); |
| |
| |
| typename face_traits<F>::edges_iterator et, eEnd = fc.edgesEnd(); |
| for (et = fc.edgesBegin(); et != eEnd; ++et) { |
| E &ed = edge(*et); |
| typename edge_traits<E>::faces_iterator ft = |
| std::find(ed.facesBegin(), ed.facesEnd(), f); |
| |
| assert(ft != ed.facesEnd()); |
| ed.eraseFace(ft); |
| } |
| |
| m_faces.erase(f); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename V, typename E, typename F> |
| void Mesh<V, E, F>::squeeze() { |
| |
| typename tcg::list<F>::iterator it, endI(m_faces.end()); |
| int i; |
| for (i = 0, it = m_faces.begin(); it != endI; ++i, ++it) it->setIndex(i); |
| |
| typename tcg::list<E>::iterator jt, endJ(m_edges.end()); |
| for (i = 0, jt = m_edges.begin(); jt != endJ; ++i, ++jt) jt->setIndex(i); |
| |
| typename tcg::list<V>::iterator kt, endK(m_vertices.end()); |
| for (i = 0, kt = m_vertices.begin(); kt != endK; ++i, ++kt) kt->setIndex(i); |
| |
| |
| for (it = m_faces.begin(); it != endI; ++it) { |
| F &face = *it; |
| |
| typename face_traits<F>::edges_iterator et, eEnd = face.edgesEnd(); |
| for (et = face.edgesBegin(); et != eEnd; ++et) *et = edge(*et).getIndex(); |
| } |
| |
| for (jt = m_edges.begin(); jt != endJ; ++jt) { |
| E &edge = *jt; |
| |
| typename edge_traits<E>::vertices_iterator vt, vEnd = edge.verticesEnd(); |
| for (vt = edge.verticesBegin(); vt != vEnd; ++vt) |
| *vt = vertex(*vt).getIndex(); |
| |
| typename edge_traits<E>::faces_iterator ft, fEnd = edge.facesEnd(); |
| for (ft = edge.facesBegin(); ft != fEnd; ++ft) *ft = face(*ft).getIndex(); |
| } |
| |
| tcg::list<int>::iterator lt; |
| for (kt = m_vertices.begin(); kt != endK; ++kt) { |
| V &vertex = *kt; |
| |
| typename vertex_traits<V>::edges_iterator et, eEnd = vertex.edgesEnd(); |
| for (et = vertex.edgesBegin(); et != eEnd; ++et) *et = edge(*et).getIndex(); |
| } |
| |
| |
| if (!m_faces.empty()) { |
| tcg::list<F> temp(m_faces.begin(), m_faces.end()); |
| std::swap(m_faces, temp); |
| } |
| |
| if (!m_edges.empty()) { |
| tcg::list<E> temp(m_edges.begin(), m_edges.end()); |
| std::swap(m_edges, temp); |
| } |
| |
| if (!m_vertices.empty()) { |
| tcg::list<V> temp(m_vertices.begin(), m_vertices.end()); |
| std::swap(m_vertices, temp); |
| } |
| } |
| |
| |
| |
| |
| |
| template <typename V, typename E, typename F> |
| TriMesh<V, E, F>::TriMesh(int verticesHint) { |
| int edgesHint = (3 * verticesHint) / 2; |
| |
| m_vertices.reserve(verticesHint); |
| m_edges.reserve(edgesHint); |
| m_faces.reserve(edgesHint + 1); |
| |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int TriMesh<V, E, F>::addFace(V &vx1, V &vx2, V &vx3) { |
| int v1 = vx1.getIndex(), v2 = vx2.getIndex(), v3 = vx3.getIndex(); |
| |
| |
| int e1, e2, e3; |
| |
| e1 = this->edgeInciding(v1, v2); |
| e2 = this->edgeInciding(v2, v3); |
| e3 = this->edgeInciding(v3, v1); |
| |
| if (e1 < 0) e1 = this->addEdge(E(v1, v2)); |
| if (e2 < 0) e2 = this->addEdge(E(v2, v3)); |
| if (e3 < 0) e3 = this->addEdge(E(v3, v1)); |
| |
| F fc; |
| fc.addEdge(e1), fc.addEdge(e2), fc.addEdge(e3); |
| |
| int f = int(m_faces.push_back(fc)); |
| |
| m_faces[f].setIndex(f); |
| |
| E &E1 = this->edge(e1); |
| E1.addFace(f); |
| E &E2 = this->edge(e2); |
| E2.addFace(f); |
| E &E3 = this->edge(e3); |
| E3.addFace(f); |
| |
| return f; |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int TriMesh<V, E, F>::otherFaceVertex(int f, int e) const { |
| const F &face = Mesh<V, E, F>::face(f); |
| const E &otherEdge = |
| face.edge(0) == e ? this->edge(face.edge(1)) : this->edge(face.edge(0)); |
| |
| int v1 = this->edge(e).vertex(0), v2 = this->edge(e).vertex(1), |
| v3 = otherEdge.otherVertex(v1); |
| return (v3 == v2) ? otherEdge.otherVertex(v2) : v3; |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int TriMesh<V, E, F>::otherFaceEdge(int f, int v) const { |
| const F &face = Mesh<V, E, F>::face(f); |
| |
| { |
| const E &ed = this->edge(face.edge(0)); |
| if (ed.vertex(0) != v && ed.vertex(1) != v) return face.edge(0); |
| } |
| |
| { |
| const E &ed = this->edge(face.edge(1)); |
| if (ed.vertex(0) != v && ed.vertex(1) != v) return face.edge(1); |
| } |
| |
| return face.edge(2); |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int TriMesh<V, E, F>::swapEdge(int e) { |
| E &ed = this->edge(e); |
| |
| if (ed.facesCount() < 2) return -1; |
| |
| int f1 = ed.face(0), f2 = ed.face(1); |
| |
| |
| int v1 = ed.vertex(0), v2 = ed.vertex(1); |
| int v3 = otherFaceVertex(f1, e), v4 = otherFaceVertex(f2, e); |
| |
| assert(this->edgeInciding(v3, v4) < 0); |
| |
| |
| this->removeEdge(e); |
| |
| |
| addFace(v1, v3, v4); |
| addFace(v2, v4, v3); |
| |
| return this->edgeInciding(v3, v4); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int TriMesh<V, E, F>::collapseEdge(int e) { |
| E &ed = this->edge(e); |
| |
| |
| int vKeep = ed.vertex(0), vDelete = ed.vertex(1); |
| V &vxKeep = this->vertex(vKeep), &vxDelete = this->vertex(vDelete); |
| |
| |
| int f, fCount = ed.facesCount(); |
| int otherV[2]; |
| |
| for (f = 0; f != fCount; ++f) otherV[f] = otherFaceVertex(ed.face(f), e); |
| |
| |
| this->removeEdge(e); |
| |
| |
| |
| for (f = 0; f != fCount; ++f) { |
| int srcE = this->edgeInciding(vDelete, otherV[f]), |
| dstE = this->edgeInciding(vKeep, otherV[f]); |
| |
| E &srcEd = this->edge(srcE), &dstEd = this->edge(dstE); |
| |
| typename edge_traits<E>::faces_iterator ft = srcEd.facesBegin(); |
| while (ft != srcEd.facesEnd()) |
| { |
| F &fc = this->face(*ft); |
| |
| (fc.edge(0) == srcE) |
| ? fc.setEdge(0, dstE) |
| : (fc.edge(1) == srcE) ? fc.setEdge(1, dstE) : fc.setEdge(2, dstE); |
| |
| dstEd.addFace(*ft); |
| ft = srcEd.eraseFace(ft); |
| } |
| |
| this->removeEdge(srcE); |
| } |
| |
| |
| typename vertex_traits<V>::edges_iterator et = vxDelete.edgesBegin(); |
| while (et != vxDelete.edgesEnd()) |
| { |
| E &ed = this->edge(*et); |
| |
| |
| |
| |
| #if 0 |
| assert("Detected vertex adjacent to collapsed edge's endpoints, but not to its faces." && |
| edgeInciding(ed.otherVertex(vDelete), vKeep) < 0); |
| #endif |
| (ed.vertex(0) == vDelete) ? ed.setVertex(0, vKeep) : ed.setVertex(1, vKeep); |
| |
| vxKeep.addEdge(*et); |
| et = vxDelete.eraseEdge(et); |
| } |
| |
| |
| vxKeep.P() = 0.5 * (vxKeep.P() + vxDelete.P()); |
| m_vertices.erase(vDelete); |
| |
| return vKeep; |
| } |
| |
| |
| |
| template <typename V, typename E, typename F> |
| int TriMesh<V, E, F>::splitEdge(int e) { |
| E &ed = this->edge(e); |
| |
| |
| int v1 = ed.vertex(0), v2 = ed.vertex(1); |
| |
| V &vx1 = this->vertex(v1), &vx2 = this->vertex(v2); |
| V v(0.5 * (vx1.P() + vx2.P())); |
| |
| int vIdx = this->addVertex(v); |
| |
| |
| int otherV[2]; |
| int f, |
| fCount = |
| ed.facesCount(); |
| |
| for (f = 0; f != fCount; ++f) |
| otherV[f] = otherFaceVertex(ed.face(f), e); |
| |
| |
| this->removeEdge(e); |
| |
| |
| this->addEdge(E(v1, vIdx)); |
| this->addEdge(E(vIdx, v2)); |
| |
| |
| for (f = 0; f != fCount; ++f) |
| addFace(v1, vIdx, otherV[f]), addFace(vIdx, v2, otherV[f]); |
| |
| return vIdx; |
| } |
| |
| } |
| |
| #endif // TCG_MESH_HPP |