449 lines
12 KiB
C++
449 lines
12 KiB
C++
|
|
//=============================================================================
|
||
|
|
//
|
||
|
|
// OpenMesh
|
||
|
|
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
|
||
|
|
// www.openmesh.org
|
||
|
|
//
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
//
|
||
|
|
// License
|
||
|
|
//
|
||
|
|
// This library 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, version 2.
|
||
|
|
//
|
||
|
|
// This library 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 Lesser General Public
|
||
|
|
// License along with this library; if not, write to the Free Software
|
||
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
|
//
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
//
|
||
|
|
// $Revision: 1801 $
|
||
|
|
// $Date: 2008-05-19 11:53:56 +0200 (Mo, 19. Mai 2008) $
|
||
|
|
//
|
||
|
|
//=============================================================================
|
||
|
|
// CLASS TriMeshT - IMPLEMENTATION
|
||
|
|
|
||
|
|
#include <OpenMesh/Core/Mesh/TriConnectivity.hh>
|
||
|
|
#include <OpenMesh/Core/System/omstream.hh>
|
||
|
|
|
||
|
|
namespace OpenMesh
|
||
|
|
{
|
||
|
|
|
||
|
|
TriConnectivity::FaceHandle
|
||
|
|
TriConnectivity::add_face(const VertexHandle* _vertex_handles, uint _vhs_size)
|
||
|
|
{
|
||
|
|
// need at least 3 vertices
|
||
|
|
if (_vhs_size < 3) return InvalidFaceHandle;
|
||
|
|
|
||
|
|
/// face is triangle -> ok
|
||
|
|
if (_vhs_size == 3)
|
||
|
|
return PolyConnectivity::add_face(_vertex_handles, _vhs_size);
|
||
|
|
|
||
|
|
/// face is not a triangle -> triangulate
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//omlog() << "triangulating " << _vhs_size << "_gon\n";
|
||
|
|
|
||
|
|
VertexHandle vhandles[3];
|
||
|
|
vhandles[0] = _vertex_handles[0];
|
||
|
|
|
||
|
|
FaceHandle fh;
|
||
|
|
unsigned int i(1);
|
||
|
|
--_vhs_size;
|
||
|
|
|
||
|
|
while (i < _vhs_size)
|
||
|
|
{
|
||
|
|
vhandles[1] = _vertex_handles[i];
|
||
|
|
vhandles[2] = _vertex_handles[++i];
|
||
|
|
fh = PolyConnectivity::add_face(vhandles, 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
return fh;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
bool TriConnectivity::is_collapse_ok(HalfedgeHandle v0v1)
|
||
|
|
{
|
||
|
|
HalfedgeHandle v1v0(opposite_halfedge_handle(v0v1));
|
||
|
|
VertexHandle v0(to_vertex_handle(v1v0));
|
||
|
|
VertexHandle v1(to_vertex_handle(v0v1));
|
||
|
|
|
||
|
|
// are vertices already deleted ?
|
||
|
|
if (status(v0).deleted() || status(v1).deleted())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
|
||
|
|
VertexHandle vl, vr;
|
||
|
|
HalfedgeHandle h1, h2;
|
||
|
|
|
||
|
|
|
||
|
|
// the edges v1-vl and vl-v0 must not be both boundary edges
|
||
|
|
if (!is_boundary(v0v1))
|
||
|
|
{
|
||
|
|
vl = to_vertex_handle(next_halfedge_handle(v0v1));
|
||
|
|
|
||
|
|
h1 = next_halfedge_handle(v0v1);
|
||
|
|
h2 = next_halfedge_handle(h1);
|
||
|
|
if (is_boundary(opposite_halfedge_handle(h1)) &&
|
||
|
|
is_boundary(opposite_halfedge_handle(h2)))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// the edges v0-vr and vr-v1 must not be both boundary edges
|
||
|
|
if (!is_boundary(v1v0))
|
||
|
|
{
|
||
|
|
vr = to_vertex_handle(next_halfedge_handle(v1v0));
|
||
|
|
|
||
|
|
h1 = next_halfedge_handle(v1v0);
|
||
|
|
h2 = next_halfedge_handle(h1);
|
||
|
|
if (is_boundary(opposite_halfedge_handle(h1)) &&
|
||
|
|
is_boundary(opposite_halfedge_handle(h2)))
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// if vl and vr are equal or both invalid -> fail
|
||
|
|
if (vl == vr) return false;
|
||
|
|
|
||
|
|
|
||
|
|
VertexVertexIter vv_it;
|
||
|
|
|
||
|
|
|
||
|
|
// test intersection of the one-rings of v0 and v1
|
||
|
|
for (vv_it = vv_iter(v0); vv_it; ++vv_it)
|
||
|
|
status(vv_it).set_tagged(false);
|
||
|
|
|
||
|
|
for (vv_it = vv_iter(v1); vv_it; ++vv_it)
|
||
|
|
status(vv_it).set_tagged(true);
|
||
|
|
|
||
|
|
for (vv_it = vv_iter(v0); vv_it; ++vv_it)
|
||
|
|
if (status(vv_it).tagged() && vv_it.handle() != vl && vv_it.handle() != vr)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// edge between two boundary vertices should be a boundary edge
|
||
|
|
if ( is_boundary(v0) && is_boundary(v1) &&
|
||
|
|
!is_boundary(v0v1) && !is_boundary(v1v0))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
// passed all tests
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
TriConnectivity::HalfedgeHandle
|
||
|
|
TriConnectivity::vertex_split(VertexHandle v0, VertexHandle v1,
|
||
|
|
VertexHandle vl, VertexHandle vr)
|
||
|
|
{
|
||
|
|
HalfedgeHandle v1vl, vlv1, vrv1, v0v1;
|
||
|
|
|
||
|
|
// build loop from halfedge v1->vl
|
||
|
|
if (vl.is_valid())
|
||
|
|
{
|
||
|
|
v1vl = find_halfedge(v1, vl);
|
||
|
|
assert(v1vl.is_valid());
|
||
|
|
vlv1 = insert_loop(v1vl);
|
||
|
|
}
|
||
|
|
|
||
|
|
// build loop from halfedge vr->v1
|
||
|
|
if (vr.is_valid())
|
||
|
|
{
|
||
|
|
vrv1 = find_halfedge(vr, v1);
|
||
|
|
assert(vrv1.is_valid());
|
||
|
|
insert_loop(vrv1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// handle boundary cases
|
||
|
|
if (!vl.is_valid())
|
||
|
|
vlv1 = prev_halfedge_handle(halfedge_handle(v1));
|
||
|
|
if (!vr.is_valid())
|
||
|
|
vrv1 = prev_halfedge_handle(halfedge_handle(v1));
|
||
|
|
|
||
|
|
|
||
|
|
// split vertex v1 into edge v0v1
|
||
|
|
v0v1 = insert_edge(v0, vlv1, vrv1);
|
||
|
|
|
||
|
|
|
||
|
|
return v0v1;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
TriConnectivity::HalfedgeHandle
|
||
|
|
TriConnectivity::insert_loop(HalfedgeHandle _hh)
|
||
|
|
{
|
||
|
|
HalfedgeHandle h0(_hh);
|
||
|
|
HalfedgeHandle o0(opposite_halfedge_handle(h0));
|
||
|
|
|
||
|
|
VertexHandle v0(to_vertex_handle(o0));
|
||
|
|
VertexHandle v1(to_vertex_handle(h0));
|
||
|
|
|
||
|
|
HalfedgeHandle h1 = new_edge(v1, v0);
|
||
|
|
HalfedgeHandle o1 = opposite_halfedge_handle(h1);
|
||
|
|
|
||
|
|
FaceHandle f0 = face_handle(h0);
|
||
|
|
FaceHandle f1 = new_face();
|
||
|
|
|
||
|
|
// halfedge -> halfedge
|
||
|
|
set_next_halfedge_handle(prev_halfedge_handle(h0), o1);
|
||
|
|
set_next_halfedge_handle(o1, next_halfedge_handle(h0));
|
||
|
|
set_next_halfedge_handle(h1, h0);
|
||
|
|
set_next_halfedge_handle(h0, h1);
|
||
|
|
|
||
|
|
// halfedge -> face
|
||
|
|
set_face_handle(o1, f0);
|
||
|
|
set_face_handle(h0, f1);
|
||
|
|
set_face_handle(h1, f1);
|
||
|
|
|
||
|
|
// face -> halfedge
|
||
|
|
set_halfedge_handle(f1, h0);
|
||
|
|
if (f0.is_valid())
|
||
|
|
set_halfedge_handle(f0, o1);
|
||
|
|
|
||
|
|
|
||
|
|
// vertex -> halfedge
|
||
|
|
adjust_outgoing_halfedge(v0);
|
||
|
|
adjust_outgoing_halfedge(v1);
|
||
|
|
|
||
|
|
return h1;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
TriConnectivity::HalfedgeHandle
|
||
|
|
TriConnectivity::insert_edge(VertexHandle _vh, HalfedgeHandle _h0, HalfedgeHandle _h1)
|
||
|
|
{
|
||
|
|
assert(_h0.is_valid() && _h1.is_valid());
|
||
|
|
|
||
|
|
VertexHandle v0 = _vh;
|
||
|
|
VertexHandle v1 = to_vertex_handle(_h0);
|
||
|
|
|
||
|
|
assert( v1 == to_vertex_handle(_h1));
|
||
|
|
|
||
|
|
HalfedgeHandle v0v1 = new_edge(v0, v1);
|
||
|
|
HalfedgeHandle v1v0 = opposite_halfedge_handle(v0v1);
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
// vertex -> halfedge
|
||
|
|
set_halfedge_handle(v0, v0v1);
|
||
|
|
set_halfedge_handle(v1, v1v0);
|
||
|
|
|
||
|
|
|
||
|
|
// halfedge -> halfedge
|
||
|
|
set_next_halfedge_handle(v0v1, next_halfedge_handle(_h0));
|
||
|
|
set_next_halfedge_handle(_h0, v0v1);
|
||
|
|
set_next_halfedge_handle(v1v0, next_halfedge_handle(_h1));
|
||
|
|
set_next_halfedge_handle(_h1, v1v0);
|
||
|
|
|
||
|
|
|
||
|
|
// halfedge -> vertex
|
||
|
|
for (VertexIHalfedgeIter vih_it(vih_iter(v0)); vih_it; ++vih_it)
|
||
|
|
set_vertex_handle(vih_it.handle(), v0);
|
||
|
|
|
||
|
|
|
||
|
|
// halfedge -> face
|
||
|
|
set_face_handle(v0v1, face_handle(_h0));
|
||
|
|
set_face_handle(v1v0, face_handle(_h1));
|
||
|
|
|
||
|
|
|
||
|
|
// face -> halfedge
|
||
|
|
if (face_handle(v0v1).is_valid())
|
||
|
|
set_halfedge_handle(face_handle(v0v1), v0v1);
|
||
|
|
if (face_handle(v1v0).is_valid())
|
||
|
|
set_halfedge_handle(face_handle(v1v0), v1v0);
|
||
|
|
|
||
|
|
|
||
|
|
// vertex -> halfedge
|
||
|
|
adjust_outgoing_halfedge(v0);
|
||
|
|
adjust_outgoing_halfedge(v1);
|
||
|
|
|
||
|
|
|
||
|
|
return v0v1;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
bool TriConnectivity::is_flip_ok(EdgeHandle _eh) const
|
||
|
|
{
|
||
|
|
// boundary edges cannot be flipped
|
||
|
|
if (is_boundary(_eh)) return false;
|
||
|
|
|
||
|
|
|
||
|
|
HalfedgeHandle hh = halfedge_handle(_eh, 0);
|
||
|
|
HalfedgeHandle oh = halfedge_handle(_eh, 1);
|
||
|
|
|
||
|
|
|
||
|
|
// check if the flipped edge is already present
|
||
|
|
// in the mesh
|
||
|
|
|
||
|
|
VertexHandle ah = to_vertex_handle(next_halfedge_handle(hh));
|
||
|
|
VertexHandle bh = to_vertex_handle(next_halfedge_handle(oh));
|
||
|
|
|
||
|
|
if (ah == bh) // this is generally a bad sign !!!
|
||
|
|
return false;
|
||
|
|
|
||
|
|
for (ConstVertexVertexIter vvi(*this, ah); vvi; ++vvi)
|
||
|
|
if (vvi.handle() == bh)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void TriConnectivity::flip(EdgeHandle _eh)
|
||
|
|
{
|
||
|
|
// CAUTION : Flipping a halfedge may result in
|
||
|
|
// a non-manifold mesh, hence check for yourself
|
||
|
|
// whether this operation is allowed or not!
|
||
|
|
assert(is_flip_ok(_eh));//let's make it sure it is actually checked
|
||
|
|
assert(!is_boundary(_eh));
|
||
|
|
|
||
|
|
HalfedgeHandle a0 = halfedge_handle(_eh, 0);
|
||
|
|
HalfedgeHandle b0 = halfedge_handle(_eh, 1);
|
||
|
|
|
||
|
|
HalfedgeHandle a1 = next_halfedge_handle(a0);
|
||
|
|
HalfedgeHandle a2 = next_halfedge_handle(a1);
|
||
|
|
|
||
|
|
HalfedgeHandle b1 = next_halfedge_handle(b0);
|
||
|
|
HalfedgeHandle b2 = next_halfedge_handle(b1);
|
||
|
|
|
||
|
|
VertexHandle va0 = to_vertex_handle(a0);
|
||
|
|
VertexHandle va1 = to_vertex_handle(a1);
|
||
|
|
|
||
|
|
VertexHandle vb0 = to_vertex_handle(b0);
|
||
|
|
VertexHandle vb1 = to_vertex_handle(b1);
|
||
|
|
|
||
|
|
FaceHandle fa = face_handle(a0);
|
||
|
|
FaceHandle fb = face_handle(b0);
|
||
|
|
|
||
|
|
set_vertex_handle(a0, va1);
|
||
|
|
set_vertex_handle(b0, vb1);
|
||
|
|
|
||
|
|
set_next_halfedge_handle(a0, a2);
|
||
|
|
set_next_halfedge_handle(a2, b1);
|
||
|
|
set_next_halfedge_handle(b1, a0);
|
||
|
|
|
||
|
|
set_next_halfedge_handle(b0, b2);
|
||
|
|
set_next_halfedge_handle(b2, a1);
|
||
|
|
set_next_halfedge_handle(a1, b0);
|
||
|
|
|
||
|
|
set_face_handle(a1, fb);
|
||
|
|
set_face_handle(b1, fa);
|
||
|
|
|
||
|
|
set_halfedge_handle(fa, a0);
|
||
|
|
set_halfedge_handle(fb, b0);
|
||
|
|
|
||
|
|
if (halfedge_handle(va0) == b0)
|
||
|
|
set_halfedge_handle(va0, a1);
|
||
|
|
if (halfedge_handle(vb0) == a0)
|
||
|
|
set_halfedge_handle(vb0, b1);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void TriConnectivity::split(EdgeHandle _eh, VertexHandle _vh)
|
||
|
|
{
|
||
|
|
HalfedgeHandle h0 = halfedge_handle(_eh, 0);
|
||
|
|
HalfedgeHandle o0 = halfedge_handle(_eh, 1);
|
||
|
|
|
||
|
|
VertexHandle v2 = to_vertex_handle(o0);
|
||
|
|
|
||
|
|
HalfedgeHandle e1 = new_edge(_vh, v2);
|
||
|
|
HalfedgeHandle t1 = opposite_halfedge_handle(e1);
|
||
|
|
|
||
|
|
FaceHandle f0 = face_handle(h0);
|
||
|
|
FaceHandle f3 = face_handle(o0);
|
||
|
|
|
||
|
|
set_halfedge_handle(_vh, h0);
|
||
|
|
set_vertex_handle(o0, _vh);
|
||
|
|
|
||
|
|
if (!is_boundary(h0))
|
||
|
|
{
|
||
|
|
HalfedgeHandle h1 = next_halfedge_handle(h0);
|
||
|
|
HalfedgeHandle h2 = next_halfedge_handle(h1);
|
||
|
|
|
||
|
|
VertexHandle v1 = to_vertex_handle(h1);
|
||
|
|
|
||
|
|
HalfedgeHandle e0 = new_edge(_vh, v1);
|
||
|
|
HalfedgeHandle t0 = opposite_halfedge_handle(e0);
|
||
|
|
|
||
|
|
FaceHandle f1 = new_face();
|
||
|
|
set_halfedge_handle(f0, h0);
|
||
|
|
set_halfedge_handle(f1, h2);
|
||
|
|
|
||
|
|
set_face_handle(h1, f0);
|
||
|
|
set_face_handle(t0, f0);
|
||
|
|
set_face_handle(h0, f0);
|
||
|
|
|
||
|
|
set_face_handle(h2, f1);
|
||
|
|
set_face_handle(t1, f1);
|
||
|
|
set_face_handle(e0, f1);
|
||
|
|
|
||
|
|
set_next_halfedge_handle(h0, h1);
|
||
|
|
set_next_halfedge_handle(h1, t0);
|
||
|
|
set_next_halfedge_handle(t0, h0);
|
||
|
|
|
||
|
|
set_next_halfedge_handle(e0, h2);
|
||
|
|
set_next_halfedge_handle(h2, t1);
|
||
|
|
set_next_halfedge_handle(t1, e0);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
set_next_halfedge_handle(prev_halfedge_handle(h0), t1);
|
||
|
|
set_next_halfedge_handle(t1, h0);
|
||
|
|
// halfedge handle of _vh already is h0
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if (!is_boundary(o0))
|
||
|
|
{
|
||
|
|
HalfedgeHandle o1 = next_halfedge_handle(o0);
|
||
|
|
HalfedgeHandle o2 = next_halfedge_handle(o1);
|
||
|
|
|
||
|
|
VertexHandle v3 = to_vertex_handle(o1);
|
||
|
|
|
||
|
|
HalfedgeHandle e2 = new_edge(_vh, v3);
|
||
|
|
HalfedgeHandle t2 = opposite_halfedge_handle(e2);
|
||
|
|
|
||
|
|
FaceHandle f2 = new_face();
|
||
|
|
set_halfedge_handle(f2, o1);
|
||
|
|
set_halfedge_handle(f3, o0);
|
||
|
|
|
||
|
|
set_face_handle(o1, f2);
|
||
|
|
set_face_handle(t2, f2);
|
||
|
|
set_face_handle(e1, f2);
|
||
|
|
|
||
|
|
set_face_handle(o2, f3);
|
||
|
|
set_face_handle(o0, f3);
|
||
|
|
set_face_handle(e2, f3);
|
||
|
|
|
||
|
|
set_next_halfedge_handle(e1, o1);
|
||
|
|
set_next_halfedge_handle(o1, t2);
|
||
|
|
set_next_halfedge_handle(t2, e1);
|
||
|
|
|
||
|
|
set_next_halfedge_handle(o0, e2);
|
||
|
|
set_next_halfedge_handle(e2, o2);
|
||
|
|
set_next_halfedge_handle(o2, o0);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
set_next_halfedge_handle(e1, next_halfedge_handle(o0));
|
||
|
|
set_next_halfedge_handle(o0, e1);
|
||
|
|
set_halfedge_handle(_vh, e1);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (halfedge_handle(v2) == h0)
|
||
|
|
set_halfedge_handle(v2, t1);
|
||
|
|
}
|
||
|
|
|
||
|
|
}// namespace OpenMesh
|