Files
openmesh/src/OpenMesh/Core/Mesh/PolyConnectivity.cc

855 lines
27 KiB
C++
Raw Normal View History

/*===========================================================================*\
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision$ *
* $Date$ *
* *
\*===========================================================================*/
//== IMPLEMENTATION ==========================================================
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
#include <set>
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;
}
}
}
//-----------------------------------------------------------------------------
namespace
{
template <class _Handle>
struct NextCacheEntryT : public std::pair<_Handle, _Handle>
{
typedef std::pair<_Handle, _Handle> Base;
NextCacheEntryT(_Handle _heh0, _Handle _heh1)
: Base(_heh0, _heh1)
{
assert(_heh0.is_valid());
assert(_heh1.is_valid());
}
};
}
PolyConnectivity::FaceHandle
PolyConnectivity::add_face(const VertexHandle* _vertex_handles, uint _vhs_size)
{
VertexHandle vh;
uint i, ii, n(_vhs_size), id;
std::vector<HalfedgeHandle> halfedge_handles(n);
std::vector<bool> is_new(n), needs_adjust(n, false);
HalfedgeHandle inner_next, inner_prev,
outer_next, outer_prev,
boundary_next, boundary_prev,
patch_start, patch_end;
// cache for set_next_halfedge and vertex' set_halfedge
typedef NextCacheEntryT<HalfedgeHandle> NextCacheEntry;
typedef std::vector<NextCacheEntry> NextCache;
NextCache next_cache;
next_cache.reserve(3*n);
// don't allow degenerated faces
assert (n > 2);
// test for topological errors
for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
{
if ( !is_boundary(_vertex_handles[i]) )
{
omerr() << "PolyMeshT::add_face: complex vertex\n";
return InvalidFaceHandle;
}
halfedge_handles[i] = find_halfedge(_vertex_handles[i],
_vertex_handles[ii]);
is_new[i] = !halfedge_handles[i].is_valid();
if (!is_new[i] && !is_boundary(halfedge_handles[i]))
{
omerr() << "PolyMeshT::add_face: complex edge\n";
return InvalidFaceHandle;
}
}
// re-link patches if necessary
for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
{
if (!is_new[i] && !is_new[ii])
{
inner_prev = halfedge_handles[i];
inner_next = halfedge_handles[ii];
if (next_halfedge_handle(inner_prev) != inner_next)
{
// here comes the ugly part... we have to relink a whole patch
// search a free gap
// free gap will be between boundary_prev and boundary_next
outer_prev = opposite_halfedge_handle(inner_next);
outer_next = opposite_halfedge_handle(inner_prev);
boundary_prev = outer_prev;
do
boundary_prev =
opposite_halfedge_handle(next_halfedge_handle(boundary_prev));
while (!is_boundary(boundary_prev) || boundary_prev==inner_prev);
boundary_next = next_halfedge_handle(boundary_prev);
assert(is_boundary(boundary_prev));
assert(is_boundary(boundary_next));
// ok ?
if (boundary_next == inner_next)
{
omerr() << "PolyMeshT::add_face: patch re-linking failed\n";
return InvalidFaceHandle;
}
// other halfedges' handles
patch_start = next_halfedge_handle(inner_prev);
patch_end = prev_halfedge_handle(inner_next);
// relink
next_cache.push_back(NextCacheEntry(boundary_prev, patch_start));
next_cache.push_back(NextCacheEntry(patch_end, boundary_next));
next_cache.push_back(NextCacheEntry(inner_prev, inner_next));
}
}
}
// create missing edges
for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
if (is_new[i])
halfedge_handles[i] = new_edge(_vertex_handles[i], _vertex_handles[ii]);
// create the face
FaceHandle fh(new_face());
set_halfedge_handle(fh, halfedge_handles[n-1]);
// setup halfedges
for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
{
vh = _vertex_handles[ii];
inner_prev = halfedge_handles[i];
inner_next = halfedge_handles[ii];
id = 0;
if (is_new[i]) id |= 1;
if (is_new[ii]) id |= 2;
if (id)
{
outer_prev = opposite_halfedge_handle(inner_next);
outer_next = opposite_halfedge_handle(inner_prev);
// set outer links
switch (id)
{
case 1: // prev is new, next is old
boundary_prev = prev_halfedge_handle(inner_next);
next_cache.push_back(NextCacheEntry(boundary_prev, outer_next));
set_halfedge_handle(vh, outer_next);
break;
case 2: // next is new, prev is old
boundary_next = next_halfedge_handle(inner_prev);
next_cache.push_back(NextCacheEntry(outer_prev, boundary_next));
set_halfedge_handle(vh, boundary_next);
break;
case 3: // both are new
if (!halfedge_handle(vh).is_valid())
{
set_halfedge_handle(vh, outer_next);
next_cache.push_back(NextCacheEntry(outer_prev, outer_next));
}
else
{
boundary_next = halfedge_handle(vh);
boundary_prev = prev_halfedge_handle(boundary_next);
next_cache.push_back(NextCacheEntry(boundary_prev, outer_next));
next_cache.push_back(NextCacheEntry(outer_prev, boundary_next));
}
break;
}
// set inner link
next_cache.push_back(NextCacheEntry(inner_prev, inner_next));
}
else needs_adjust[ii] = (halfedge_handle(vh) == inner_next);
// set face handle
set_face_handle(halfedge_handles[i], fh);
}
// process next halfedge cache
NextCache::const_iterator ncIt(next_cache.begin()), ncEnd(next_cache.end());
for (; ncIt != ncEnd; ++ncIt)
set_next_halfedge_handle(ncIt->first, ncIt->second);
// adjust vertices' halfedge handle
for (i=0; i<n; ++i)
if (needs_adjust[i])
adjust_outgoing_halfedge(_vertex_handles[i]);
return fh;
}
//-----------------------------------------------------------------------------
void PolyConnectivity::delete_vertex(VertexHandle _vh, bool _delete_isolated_vertices)
{
// store incident faces
std::vector<FaceHandle> 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<FaceHandle>::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<EdgeHandle> deleted_edges;
deleted_edges.reserve(3);
// this vector will hold all vertices of face _fh
// for updating their outgoing halfedge
std::vector<VertexHandle> 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<EdgeHandle>::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<VertexHandle>::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<FaceHandle> 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;
}
}//namespace OpenMesh