/*===========================================================================*\ * * * OpenMesh * * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * * www.openmesh.org * * * *---------------------------------------------------------------------------* * This file is part of OpenMesh. * * * * OpenMesh is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenMesh is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU LesserGeneral Public * * License along with OpenMesh. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $Date$ * * * \*===========================================================================*/ //== IMPLEMENTATION ========================================================== #include #include namespace OpenMesh { const PolyConnectivity::VertexHandle PolyConnectivity::InvalidVertexHandle; const PolyConnectivity::HalfedgeHandle PolyConnectivity::InvalidHalfedgeHandle; const PolyConnectivity::EdgeHandle PolyConnectivity::InvalidEdgeHandle; const PolyConnectivity::FaceHandle PolyConnectivity::InvalidFaceHandle; //----------------------------------------------------------------------------- PolyConnectivity::HalfedgeHandle PolyConnectivity::find_halfedge(VertexHandle _start_vh, VertexHandle _end_vh ) const { assert(_start_vh.is_valid() && _end_vh.is_valid()); for (ConstVertexVertexIter vvIt=cvv_iter(_start_vh); vvIt; ++vvIt) if (vvIt.handle() == _end_vh) return vvIt.current_halfedge_handle(); return InvalidHalfedgeHandle; } bool PolyConnectivity::is_boundary(FaceHandle _fh, bool _check_vertex) const { for (ConstFaceEdgeIter cfeit = cfe_iter( _fh ); cfeit; ++cfeit) if (is_boundary( cfeit.handle() ) ) return true; if (_check_vertex) { for (ConstFaceVertexIter cfvit = cfv_iter( _fh ); cfvit; ++cfvit) if (is_boundary( cfvit.handle() ) ) return true; } return false; } bool PolyConnectivity::is_manifold(VertexHandle _vh) const { /* The vertex is non-manifold if more than one gap exists, i.e. more than one outgoing boundary halfedge. If (at least) one boundary halfedge exists, the vertex' halfedge must be a boundary halfedge. If iterating around the vertex finds another boundary halfedge, the vertex is non-manifold. */ ConstVertexOHalfedgeIter vh_it(*this, _vh); if (vh_it) for (++vh_it; vh_it; ++vh_it) if (is_boundary(vh_it.handle())) return false; return true; } //----------------------------------------------------------------------------- void PolyConnectivity::adjust_outgoing_halfedge(VertexHandle _vh) { for (ConstVertexOHalfedgeIter vh_it=cvoh_iter(_vh); vh_it; ++vh_it) { if (is_boundary(vh_it.handle())) { set_halfedge_handle(_vh, vh_it.handle()); break; } } } //----------------------------------------------------------------------------- PolyConnectivity::FaceHandle PolyConnectivity::add_face(const VertexHandle* _vertex_handles, uint _vhs_size) { VertexHandle vh; uint i, ii, n(_vhs_size), id; HalfedgeHandle inner_next, inner_prev, outer_next, outer_prev, boundary_next, boundary_prev, patch_start, patch_end; // Check sufficient working storage available if (edgeData_.size() < n) { edgeData_.resize(n); next_cache_.resize(6*n); } next_cache_count_ = 0; // don't allow degenerated faces assert (n > 2); // test for topological errors for (i=0, ii=1; i face_handles; face_handles.reserve(8); for (VFIter vf_it(vf_iter(_vh)); vf_it; ++vf_it) face_handles.push_back(vf_it.handle()); // delete collected faces std::vector::iterator fh_it(face_handles.begin()), fh_end(face_handles.end()); for (; fh_it!=fh_end; ++fh_it) delete_face(*fh_it, _delete_isolated_vertices); status(_vh).set_deleted(true); } //----------------------------------------------------------------------------- void PolyConnectivity::delete_edge(EdgeHandle _eh, bool _delete_isolated_vertices) { FaceHandle fh0(face_handle(halfedge_handle(_eh, 0))); FaceHandle fh1(face_handle(halfedge_handle(_eh, 1))); if (fh0.is_valid()) delete_face(fh0, _delete_isolated_vertices); if (fh1.is_valid()) delete_face(fh1, _delete_isolated_vertices); } //----------------------------------------------------------------------------- void PolyConnectivity::delete_face(FaceHandle _fh, bool _delete_isolated_vertices) { assert(_fh.is_valid() && !status(_fh).deleted()); // mark face deleted status(_fh).set_deleted(true); // this vector will hold all boundary edges of face _fh // these edges will be deleted std::vector deleted_edges; deleted_edges.reserve(3); // this vector will hold all vertices of face _fh // for updating their outgoing halfedge std::vector vhandles; vhandles.reserve(3); // for all halfedges of face _fh do: // 1) invalidate face handle. // 2) collect all boundary halfedges, set them deleted // 3) store vertex handles HalfedgeHandle hh; for (FaceHalfedgeIter fh_it(fh_iter(_fh)); fh_it; ++fh_it) { hh = fh_it.handle(); set_boundary(hh);//set_face_handle(hh, InvalidFaceHandle); if (is_boundary(opposite_halfedge_handle(hh))) deleted_edges.push_back(edge_handle(hh)); vhandles.push_back(to_vertex_handle(hh)); } // delete all collected (half)edges // delete isolated vertices (if _delete_isolated_vertices is true) if (!deleted_edges.empty()) { std::vector::iterator del_it(deleted_edges.begin()), del_end(deleted_edges.end()); HalfedgeHandle h0, h1, next0, next1, prev0, prev1; VertexHandle v0, v1; for (; del_it!=del_end; ++del_it) { h0 = halfedge_handle(*del_it, 0); v0 = to_vertex_handle(h0); next0 = next_halfedge_handle(h0); prev0 = prev_halfedge_handle(h0); h1 = halfedge_handle(*del_it, 1); v1 = to_vertex_handle(h1); next1 = next_halfedge_handle(h1); prev1 = prev_halfedge_handle(h1); // adjust next and prev handles set_next_halfedge_handle(prev0, next1); set_next_halfedge_handle(prev1, next0); // mark edge deleted status(*del_it).set_deleted(true); // update v0 if (halfedge_handle(v0) == h1) { // isolated ? if (next0 == h1) { if (_delete_isolated_vertices) status(v0).set_deleted(true); set_isolated(v0); } else set_halfedge_handle(v0, next0); } // update v1 if (halfedge_handle(v1) == h0) { // isolated ? if (next1 == h0) { if (_delete_isolated_vertices) status(v1).set_deleted(true); set_isolated(v1); } else set_halfedge_handle(v1, next1); } } } // update outgoing halfedge handles of remaining vertices std::vector::iterator v_it(vhandles.begin()), v_end(vhandles.end()); for (; v_it!=v_end; ++v_it) adjust_outgoing_halfedge(*v_it); } //----------------------------------------------------------------------------- void PolyConnectivity::collapse(HalfedgeHandle _hh) { HalfedgeHandle h0 = _hh; HalfedgeHandle h1 = next_halfedge_handle(h0); HalfedgeHandle o0 = opposite_halfedge_handle(h0); HalfedgeHandle o1 = next_halfedge_handle(o0); // remove edge collapse_edge(h0); // remove loops if (next_halfedge_handle(next_halfedge_handle(h1)) == h1) collapse_loop(next_halfedge_handle(h1)); if (next_halfedge_handle(next_halfedge_handle(o1)) == o1) collapse_loop(o1); } //----------------------------------------------------------------------------- void PolyConnectivity::collapse_edge(HalfedgeHandle _hh) { HalfedgeHandle h = _hh; HalfedgeHandle hn = next_halfedge_handle(h); HalfedgeHandle hp = prev_halfedge_handle(h); HalfedgeHandle o = opposite_halfedge_handle(h); HalfedgeHandle on = next_halfedge_handle(o); HalfedgeHandle op = prev_halfedge_handle(o); FaceHandle fh = face_handle(h); FaceHandle fo = face_handle(o); VertexHandle vh = to_vertex_handle(h); VertexHandle vo = to_vertex_handle(o); // halfedge -> vertex for (VertexIHalfedgeIter vih_it(vih_iter(vo)); vih_it; ++vih_it) set_vertex_handle(vih_it.handle(), vh); // halfedge -> halfedge set_next_halfedge_handle(hp, hn); set_next_halfedge_handle(op, on); // face -> halfedge if (fh.is_valid()) set_halfedge_handle(fh, hn); if (fo.is_valid()) set_halfedge_handle(fo, on); // vertex -> halfedge if (halfedge_handle(vh) == o) set_halfedge_handle(vh, hn); adjust_outgoing_halfedge(vh); set_isolated(vo); // delete stuff status(edge_handle(h)).set_deleted(true); status(vo).set_deleted(true); } //----------------------------------------------------------------------------- void PolyConnectivity::collapse_loop(HalfedgeHandle _hh) { HalfedgeHandle h0 = _hh; HalfedgeHandle h1 = next_halfedge_handle(h0); HalfedgeHandle o0 = opposite_halfedge_handle(h0); HalfedgeHandle o1 = opposite_halfedge_handle(h1); VertexHandle v0 = to_vertex_handle(h0); VertexHandle v1 = to_vertex_handle(h1); FaceHandle fh = face_handle(h0); FaceHandle fo = face_handle(o0); // is it a loop ? assert ((next_halfedge_handle(h1) == h0) && (h1 != o0)); // halfedge -> halfedge set_next_halfedge_handle(h1, next_halfedge_handle(o0)); set_next_halfedge_handle(prev_halfedge_handle(o0), h1); // halfedge -> face set_face_handle(h1, fo); // vertex -> halfedge set_halfedge_handle(v0, h1); adjust_outgoing_halfedge(v0); set_halfedge_handle(v1, o1); adjust_outgoing_halfedge(v1); // face -> halfedge if (fo.is_valid() && halfedge_handle(fo) == o0) { set_halfedge_handle(fo, h1); } // delete stuff if (fh.is_valid()) { set_halfedge_handle(fh, InvalidHalfedgeHandle); status(fh).set_deleted(true); } status(edge_handle(h0)).set_deleted(true); } //----------------------------------------------------------------------------- bool PolyConnectivity::is_simple_link(EdgeHandle _eh) const { HalfedgeHandle heh0 = halfedge_handle(_eh, 0); HalfedgeHandle heh1 = halfedge_handle(_eh, 1); FaceHandle fh0 = face_handle(heh0);//fh0 or fh1 might be a invalid, FaceHandle fh1 = face_handle(heh1);//i.e., representing the boundary HalfedgeHandle next_heh = next_halfedge_handle(heh0); while (next_heh != heh0) {//check if there are no other edges shared between fh0 & fh1 if (opposite_face_handle(next_heh) == fh1) { return false; } next_heh = next_halfedge_handle(next_heh); } return true; } //----------------------------------------------------------------------------- bool PolyConnectivity::is_simply_connected(FaceHandle _fh) const { std::set nb_fhs; for (ConstFaceFaceIter cff_it = cff_iter(_fh); cff_it; ++cff_it) { if (nb_fhs.find(cff_it) == nb_fhs.end()) { nb_fhs.insert(cff_it); } else {//there is more than one link return false; } } return true; } //----------------------------------------------------------------------------- PolyConnectivity::FaceHandle PolyConnectivity::remove_edge(EdgeHandle _eh) { //don't allow "dangling" vertices and edges assert(!status(_eh).deleted() && is_simple_link(_eh)); HalfedgeHandle heh0 = halfedge_handle(_eh, 0); HalfedgeHandle heh1 = halfedge_handle(_eh, 1); //deal with the faces FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); if (!del_fh.is_valid()) {//boundary case - we must delete the rem_fh std::swap(del_fh, rem_fh); } assert(del_fh.is_valid()); /* for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it) {//set the face handle of the halfedges of del_fh to point to rem_fh set_face_handle(fh_it, rem_fh); } */ //fix the halfedge relations HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); set_next_halfedge_handle(prev_heh0, next_heh1); set_next_halfedge_handle(prev_heh1, next_heh0); //correct outgoing vertex handles for the _eh vertices (if needed) VertexHandle vh0 = to_vertex_handle(heh0); VertexHandle vh1 = to_vertex_handle(heh1); if (halfedge_handle(vh0) == heh1) { set_halfedge_handle(vh0, next_heh0); } if (halfedge_handle(vh1) == heh0) { set_halfedge_handle(vh1, next_heh1); } //correct the hafledge handle of rem_fh if needed and preserve its first vertex if (halfedge_handle(rem_fh) == heh0) {//rem_fh is the face at heh0 set_halfedge_handle(rem_fh, prev_heh1); } else if (halfedge_handle(rem_fh) == heh1) {//rem_fh is the face at heh1 set_halfedge_handle(rem_fh, prev_heh0); } for (FaceHalfedgeIter fh_it = fh_iter(rem_fh); fh_it; ++fh_it) {//set the face handle of the halfedges of del_fh to point to rem_fh set_face_handle(fh_it, rem_fh); } status(_eh).set_deleted(true); status(del_fh).set_deleted(true); return rem_fh;//returns the remaining face handle } //----------------------------------------------------------------------------- void PolyConnectivity::reinsert_edge(EdgeHandle _eh) { //this does not work without prev_halfedge_handle assert_compile(sizeof(Halfedge) == sizeof(Halfedge_with_prev)); //shoudl be deleted assert(status(_eh).deleted()); status(_eh).set_deleted(false); HalfedgeHandle heh0 = halfedge_handle(_eh, 0); HalfedgeHandle heh1 = halfedge_handle(_eh, 1); FaceHandle rem_fh = face_handle(heh0), del_fh = face_handle(heh1); if (!del_fh.is_valid()) {//boundary case - we must delete the rem_fh std::swap(del_fh, rem_fh); } assert(status(del_fh).deleted()); status(del_fh).set_deleted(false); //restore halfedge relations HalfedgeHandle prev_heh0 = prev_halfedge_handle(heh0); HalfedgeHandle prev_heh1 = prev_halfedge_handle(heh1); HalfedgeHandle next_heh0 = next_halfedge_handle(heh0); HalfedgeHandle next_heh1 = next_halfedge_handle(heh1); set_next_halfedge_handle(prev_heh0, heh0); set_prev_halfedge_handle(next_heh0, heh0); set_next_halfedge_handle(prev_heh1, heh1); set_prev_halfedge_handle(next_heh1, heh1); for (FaceHalfedgeIter fh_it = fh_iter(del_fh); fh_it; ++fh_it) {//reassign halfedges to del_fh set_face_handle(fh_it, del_fh); } if (face_handle(halfedge_handle(rem_fh)) == del_fh) {//correct the halfedge handle of rem_fh if (halfedge_handle(rem_fh) == prev_heh0) {//rem_fh is the face at heh1 set_halfedge_handle(rem_fh, heh1); } else {//rem_fh is the face at heh0 assert(halfedge_handle(rem_fh) == prev_heh1); set_halfedge_handle(rem_fh, heh0); } } } //----------------------------------------------------------------------------- PolyConnectivity::HalfedgeHandle PolyConnectivity::insert_edge(HalfedgeHandle _prev_heh, HalfedgeHandle _next_heh) { assert(face_handle(_prev_heh) == face_handle(_next_heh));//only the manifold case assert(next_halfedge_handle(_prev_heh) != _next_heh);//this can not be done VertexHandle vh0 = to_vertex_handle(_prev_heh); VertexHandle vh1 = from_vertex_handle(_next_heh); //create the link between vh0 and vh1 HalfedgeHandle heh0 = new_edge(vh0, vh1); HalfedgeHandle heh1 = opposite_halfedge_handle(heh0); HalfedgeHandle next_prev_heh = next_halfedge_handle(_prev_heh); HalfedgeHandle prev_next_heh = prev_halfedge_handle(_next_heh); set_next_halfedge_handle(_prev_heh, heh0); set_next_halfedge_handle(heh0, _next_heh); set_next_halfedge_handle(prev_next_heh, heh1); set_next_halfedge_handle(heh1, next_prev_heh); //now set the face handles - the new face is assigned to heh0 FaceHandle new_fh = new_face(); set_halfedge_handle(new_fh, heh0); for (FaceHalfedgeIter fh_it = fh_iter(new_fh); fh_it; ++fh_it) { set_face_handle(fh_it, new_fh); } FaceHandle old_fh = face_handle(next_prev_heh); set_face_handle(heh1, old_fh); if (old_fh.is_valid() && face_handle(halfedge_handle(old_fh)) == new_fh) {//fh pointed to one of the halfedges now assigned to new_fh set_halfedge_handle(old_fh, heh1); } adjust_outgoing_halfedge(vh0); adjust_outgoing_halfedge(vh1); return heh0; } //----------------------------------------------------------------------------- void PolyConnectivity::triangulate(FaceHandle _fh) { /* Split an arbitrary face into triangles by connecting each vertex of fh after its second to vh. - fh will remain valid (it will become one of the triangles) - the halfedge handles of the new triangles will point to the old halfedges */ HalfedgeHandle base_heh(halfedge_handle(_fh)); VertexHandle start_vh = from_vertex_handle(base_heh); HalfedgeHandle next_heh(next_halfedge_handle(base_heh)); while (to_vertex_handle(next_halfedge_handle(next_heh)) != start_vh) { HalfedgeHandle next_next_heh(next_halfedge_handle(next_heh)); FaceHandle new_fh = new_face(); set_halfedge_handle(new_fh, base_heh); HalfedgeHandle new_heh = new_edge(to_vertex_handle(next_heh), start_vh); set_next_halfedge_handle(base_heh, next_heh); set_next_halfedge_handle(next_heh, new_heh); set_next_halfedge_handle(new_heh, base_heh); set_face_handle(base_heh, new_fh); set_face_handle(next_heh, new_fh); set_face_handle(new_heh, new_fh); base_heh = opposite_halfedge_handle(new_heh); next_heh = next_next_heh; } set_halfedge_handle(_fh, base_heh); //the last face takes the handle _fh set_next_halfedge_handle(base_heh, next_heh); set_next_halfedge_handle(next_halfedge_handle(next_heh), base_heh); set_face_handle(base_heh, _fh); } //----------------------------------------------------------------------------- void PolyConnectivity::triangulate() { /* The iterators will stay valid, even though new faces are added, because they are now implemented index-based instead of pointer-based. */ FaceIter f_it(faces_begin()), f_end(faces_end()); for (; f_it!=f_end; ++f_it) triangulate(f_it); } //----------------------------------------------------------------------------- void PolyConnectivity::split(FaceHandle fh, VertexHandle vh) { /* Split an arbitrary face into triangles by connecting each vertex of fh to vh. - fh will remain valid (it will become one of the triangles) - the halfedge handles of the new triangles will point to the old halfeges */ HalfedgeHandle hend = halfedge_handle(fh); HalfedgeHandle hh = next_halfedge_handle(hend); HalfedgeHandle hold = new_edge(to_vertex_handle(hend), vh); set_next_halfedge_handle(hend, hold); set_face_handle(hold, fh); hold = opposite_halfedge_handle(hold); while (hh != hend) { HalfedgeHandle hnext = next_halfedge_handle(hh); FaceHandle fnew = new_face(); set_halfedge_handle(fnew, hh); HalfedgeHandle hnew = new_edge(to_vertex_handle(hh), vh); set_next_halfedge_handle(hnew, hold); set_next_halfedge_handle(hold, hh); set_next_halfedge_handle(hh, hnew); set_face_handle(hnew, fnew); set_face_handle(hold, fnew); set_face_handle(hh, fnew); hold = opposite_halfedge_handle(hnew); hh = hnext; } set_next_halfedge_handle(hold, hend); set_next_halfedge_handle(next_halfedge_handle(hend), hold); set_face_handle(hold, fh); set_halfedge_handle(vh, hold); } //----------------------------------------------------------------------------- uint PolyConnectivity::valence(VertexHandle _vh) const { uint count(0); for (ConstVertexVertexIter vv_it=cvv_iter(_vh); vv_it; ++vv_it) ++count; return count; } //----------------------------------------------------------------------------- uint PolyConnectivity::valence(FaceHandle _fh) const { uint count(0); for (ConstFaceVertexIter fv_it=cfv_iter(_fh); fv_it; ++fv_it) ++count; return count; } //----------------------------------------------------------------------------- void PolyConnectivity::split_edge(EdgeHandle _eh, VertexHandle _vh) { HalfedgeHandle h0 = halfedge_handle(_eh, 0); HalfedgeHandle h1 = halfedge_handle(_eh, 1); VertexHandle vfrom = from_vertex_handle(h0); HalfedgeHandle ph0 = prev_halfedge_handle(h0); HalfedgeHandle ph1 = prev_halfedge_handle(h1); HalfedgeHandle nh0 = next_halfedge_handle(h0); HalfedgeHandle nh1 = next_halfedge_handle(h1); bool boundary0 = is_boundary(h0); bool boundary1 = is_boundary(h1); //add the new edge HalfedgeHandle new_e = new_edge(from_vertex_handle(h0), _vh); //fix the vertex of the opposite halfedge set_vertex_handle(h1, _vh); //fix the halfedge connectivity set_next_halfedge_handle(new_e, h0); set_next_halfedge_handle(h1, opposite_halfedge_handle(new_e)); set_next_halfedge_handle(ph0, new_e); set_next_halfedge_handle(opposite_halfedge_handle(new_e), nh1); set_prev_halfedge_handle(new_e, ph0); set_prev_halfedge_handle(opposite_halfedge_handle(new_e), h1); set_prev_halfedge_handle(nh1, opposite_halfedge_handle(new_e)); set_prev_halfedge_handle(h0, new_e); if (!boundary0) { set_face_handle(new_e, face_handle(h0)); } else { set_boundary(new_e); } if (!boundary1) { set_face_handle(opposite_halfedge_handle(new_e), face_handle(h1)); } { set_boundary(opposite_halfedge_handle(new_e)); } if (halfedge_handle(vfrom) == h0) { set_halfedge_handle(vfrom, new_e); } } }//namespace OpenMesh