vcglib/vcg/complex/trimesh/edge_support.h

458 lines
16 KiB
C
Raw Normal View History

/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef __VCGLIB_EDGE_SUPPORT
#define __VCGLIB_EDGE_SUPPORT
#include <vector>
#include <vcg/complex/trimesh/allocate.h>
2008-12-18 18:52:48 +01:00
#include <vcg/complex/trimesh/clean.h>
#include <vcg/complex/trimesh/update/topology.h>
#include <vcg/complex/trimesh/base.h>
namespace vcg
{
namespace tri{
/// \ingroup trimesh
/// \headerfile edge_support.h vcg/complex/trimesh/edge_support.h
/// \brief This class is used to build edge based data structure from indexed data structure and viceversa
/**
*/
template <class MeshType >
class EdgeSupport{
public:
typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::VertexPointer VertexPointer;
typedef typename MeshType::EdgePointer EdgePointer;
typedef typename MeshType::EdgeType EdgeType;
typedef typename MeshType::EdgeIterator EdgeIterator;
typedef typename MeshType::FaceIterator FaceIterator;
typedef typename MeshType::FaceType FaceType;
struct VertexPairEdgePtr{
VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,EdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);}
2009-04-01 15:07:08 +02:00
const bool operator <(const VertexPairEdgePtr &o) const {return (v0 == o.v0)? (v1<o.v1):(v0<o.v0);}
const bool operator ==(const VertexPairEdgePtr &o) const {return (v0 == o.v0)&& (v1==o.v1);}
VertexPointer v0,v1;
EdgePointer ep;
};
2008-12-18 18:52:48 +01:00
struct FacePtrInt{
FacePtrInt ( FaceType * _f,int _i):f(_f),i(_i){}
FaceType * f;
int i;
};
typedef std::vector<bool> BitVector;
/**
build a half-edge data structure from an indexed data structure. Note that the half-edges are allocated here for the first time.
If you have a mesh where there are already edges, they will be removed and the data lost, so do not use this function
to just "update" the topology of half edges.
**/
static void ComputeHalfEdgeFromIndexed(MeshType & m){
assert(HasFVAdjacency(m));
assert(MeshType::EdgeType::HasHENextAdjacency());
assert(MeshType::EdgeType::HasHEOppAdjacency());
2009-04-01 15:07:08 +02:00
typename MeshType::template PerFaceAttributeHandle<BitVector> flagVisited =
vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<BitVector>(m,"");
2008-12-18 18:52:48 +01:00
std::vector<FacePtrInt > borderEdges;
// allocate all new half edges
FaceIterator fi;
int n_edges = 0;
2008-12-18 18:52:48 +01:00
// count how many half edge to allocate
for(fi = m.face.begin(); fi != m.face.end(); ++fi) if(! (*fi).IsD())
{n_edges+=(*fi).VN();
for(int i = 0; i < (*fi).VN(); ++i)
if(vcg::face::IsBorder<FaceType>((*fi),(i)))
++n_edges;
}
// allocate the half edges
typename MeshType::EdgeIterator ei = vcg::tri::Allocator<MeshType>::AddEdges(m,n_edges);
std::vector<VertexPairEdgePtr> all;
int firstEdge = 0;
for(fi = m.face.begin(); fi != m.face.end(); ++fi)if(!(*fi).IsD()){
assert((*fi).VN()>2);
2008-12-18 18:52:48 +01:00
if(flagVisited[*fi].empty()) {flagVisited[*fi].resize((*fi).VN());}
for(int i = 0; i < (*fi).VN(); ++i,++ei)
{
(*ei).HEVp() = (*fi).V(i);
(*ei).HENp() = &m.edge[firstEdge + (i +1) % (*fi).VN()];
if(MeshType::EdgeType::HasEFAdjacency())
(*ei).EFp() = &(*fi);
if( MeshType::FaceType::HasFHEAdjacency())
(*fi).FHEp() = &(*ei);
if(MeshType::EdgeType::HasHEPrevAdjacency())
(*ei).HEPp() = &m.edge[firstEdge + (i +(*fi).VN()-1) % (*fi).VN()];
if(HasVEAdjacency(m))
(*ei).HEVp()->VEp() = &(*ei);
all.push_back(VertexPairEdgePtr((*fi).V(i), (*fi).V((*fi).Next(i)),&(*ei)));// it will be used to link the hedges
2008-12-18 18:52:48 +01:00
if( vcg::face::IsBorder<FaceType>((*fi),(i)))
borderEdges.push_back(FacePtrInt(&(*fi),i));
}
firstEdge += (*fi).VN();
}
2008-12-18 18:52:48 +01:00
// add all the border edges
int borderLength;
2009-04-01 15:07:08 +02:00
typename std::vector<FacePtrInt >::iterator ebi;
2008-12-18 18:52:48 +01:00
for( ebi = borderEdges.begin(); ebi != borderEdges.end(); ++ebi)
if( !flagVisited[(*ebi).f][(*ebi).i])// not already inserted
{
borderLength = 0;
vcg::face::Pos<FaceType> bp((*ebi).f,(*ebi).i);
FaceType * start = (*ebi).f;
do{
all.push_back( VertexPairEdgePtr ( bp.f->V( bp.f->Next(bp.z) ),bp.f->V( bp.z ),&(*ei)));
(*ei).HEVp() = bp.f->V(bp.f->Next(bp.z)) ;
flagVisited[bp.f][bp.z] = true;
++ei;
bp.NextB();
++borderLength;
}while (bp.f != start);
// run over the border edges to link the adjacencies
for(int be = 0; be < borderLength; ++be){
if(MeshType::EdgeType::HasEFAdjacency())
m.edge[firstEdge + be].EFp() = NULL;
if(MeshType::EdgeType::HasHEPrevAdjacency())
m.edge[firstEdge + be].HEPp() = &m.edge[firstEdge + (be +borderLength-1) % borderLength];
m.edge[firstEdge + be].HENp() = &m.edge[firstEdge + (be +1) % borderLength];
}
firstEdge+=borderLength;
}
2009-04-01 15:07:08 +02:00
vcg::tri::Allocator<MeshType>:: template DeletePerFaceAttribute<BitVector>(m,flagVisited );
2008-12-18 18:52:48 +01:00
std::sort(all.begin(),all.end());
assert(all.size() == n_edges);
for(int i = 0 ; i < all.size(); )
if(all[i] == all[i+1])
{
all[i].ep->HEOp() = all[i+1].ep;
all[i+1].ep->HEOp() = all[i].ep;
i+=2;
}
else
{
all[i].ep->HEOp() = all[i].ep;
i+=1;
}
}
/**
builds an indexed data structure from a half-edge data structure.
Note: if the half edge have the pointer to face
their relation FV (face-vertex) will be computed and the data possibly stored in the
face will be preserved.
**/
static void ComputeIndexedFromHalfEdge( MeshType & m ){
assert(HasFVAdjacency(m));
assert(MeshType::EdgeType::HasHENextAdjacency());
assert(MeshType::EdgeType::HasHEVAdjacency());
assert(MeshType::EdgeType::HasHEOppAdjacency());
assert(MeshType::FaceType::HasFHEAdjacency());
bool createFace,hasHEF,hasFHE;
typename MeshType::template PerEdgeAttributeHandle<bool> hV = Allocator<MeshType>::template AddPerEdgeAttribute<bool>(m,"");
typename MeshType::EdgeIterator ei;
typename MeshType::FacePointer fp;
typename MeshType::FaceIterator fi;
typename MeshType::EdgePointer ep,epF;
int vi = 0;
hasHEF = (MeshType::EdgeType::HasEFAdjacency());
assert( !hasHEF || (hasHEF && m.fn>0));
// if the edgetype has the pointer to face
// it is assumed the the edget2face pointer (HEFp) are correct
// and the faces are allocated
for ( ei = m.edge.begin(); ei != m.edge.end(); ++ei)
2008-12-18 18:52:48 +01:00
if(!(*ei).IsD()) // it has not been deleted
if(!hasHEF || ( hasHEF && (*ei).EFp()!=NULL)) // if it has a pointer to the face it is
// not null (i.e. it is not a border edge)
if(!hV[(*ei)] ) // it has not be visited yet
{
if(!hasHEF)// if it has
fp = &(* Allocator<MeshType>::AddFaces(m,1));
else
fp = (*ei).EFp();
ep = epF = &(*ei);
std::vector<VertexPointer> vpts;
do{vpts.push_back((*ep).HEVp()); ep=ep->HENp();}while(ep!=epF);
int idbg =fp->VN();
if(fp->VN() != vpts.size()){
fp->Dealloc();
fp ->Alloc(vpts.size());
}
int idbg1 =fp->VN();
for(int i = 0; i < vpts.size();++i) fp ->V(i) = vpts[i];// set the pointer from face to vertex
hV[(*ei)] = true;
}
Allocator<MeshType>::DeletePerEdgeAttribute(m,hV);
}
/**
Checks pointers FHEp() are valid
**/
static bool CheckConsistency_FHEp(MeshType & m){
assert(MeshType::FaceType::HasFHEAdjacency());
FaceIterator fi;
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
if(!(*fi).IsD()){
if((*fi).FHEp() < &(*m.edge.begin())) return false;
if((*fi).FHEp() > &(m.edge.back())) return false;
}
return true;
}
/**
Checks that half edges and face relation are consistent
**/
static bool CheckConsistency(MeshType & m){
assert(MeshType::EdgeType::HasHENextAdjacency());
assert(MeshType::EdgeType::HasHEOppAdjacency());
assert(MeshType::EdgeType::HasHEVAdjacency());
assert(MeshType::FaceType::HasFHEAdjacency());
bool hasHEF = ( MeshType::EdgeType::HasEFAdjacency());
bool hasHEP = ( MeshType::EdgeType::HasHEPrevAdjacency());
FaceIterator fi;
EdgePointer ep,ep1;
int cnt = 0;
if(( MeshType::EdgeType::HasEFAdjacency())){
int iDb = 0;
for(fi = m.face.begin(); fi != m.face.end(); ++fi,++iDb)
if(!(*fi).IsD())
{
ep = ep1 = (*fi).FHEp();
do{
if(ep->IsD())
return false; // the edge should not be connected, it has been deleted
if(ep->EFp() != &(*fi))
return false;// edge is not pointing to the rigth face
ep = ep->HENp();
if(cnt++ > m.en)
return false; // edges are ill connected (HENp())
}while(ep!=ep1);
}
}
EdgePointer epPrev;
EdgeIterator ei;
bool extEdge ;
for( ei = m.edge.begin(); ei != m.edge.end(); ++ei)
if(!(*ei).IsD())
{
cnt = 0;
epPrev = ep = ep1 = &(*ei);
do{
extEdge = (ep->EFp()==NULL);
if(hasHEP){
if( ep->HENp()->HEPp() != ep)
return false; // next and prev relation are not mutual
if( ep->HEPp() == ep)
return false; // the previous of an edge cannot be the edge itself
}
if( ep->HEOp() == ep)
return false; // opposite relation is not mutual
if( ep->HEOp()->HEOp() != ep)
return false; // opposite relation is not mutual
if(ep->HENp() == ep)
return false; // the next of an edge cannot be the edge itself
ep = ep->HENp();
if( ep->HEVp() != epPrev->HEOp()->HEVp())
return false; // the opposite edge points to a vertex different that the vertex of the next edge
epPrev = ep;
if(cnt++ > m.en)
return false; // edges are ill connected (HENp())
}while(ep!=ep1);
}
return true;
}
/** Set the relations HEFp(), FHEp() from a loop of edges to a face
*/
private:
static void SetRelationsLoopFace(EdgeType * e0, FaceType * f){
assert(EdgeType::HasHENextAdjacency());
assert(FaceType::HasFHEAdjacency());
EdgeType *e = e0;
assert(e!=NULL);
do{ e->EFp() = f; e = e->HENp(); } while(e != e0);
f->FHEp() = e0;
}
/**
Merge the two faces. This will probably become a class template or a functor
*/
static void MergeFaces(FaceType *, FaceType *){};
/**
Find previous hedge in the loop
*/
static EdgeType * PreviousEdge(EdgeType * e0){
EdgeType * ep = e0;
do{
if(ep->HENp() == e0) return ep;
ep = ep->HENp();
}while(ep!=e0);
}
public:
/** Adds an edge between the sources of e0 and e1 and set all the topology relations.
If the edges store the pointers to the faces then a new face is created.
<--- e1 ---- X <------e1_HEPp---
^
||
ei0 || ei1
||
v
----e0_HEPp-> X ----- e0 ------>
*/
static void AddEdge(MeshType &m, EdgeType * e0, EdgeType * e1){
EdgeType *iii =e0->HENp();
assert(e1!=e0->HENp());
assert(e0!=e1->HENp());
EdgePointer tmp;
bool hasP = MeshType::EdgeType::HasHEPrevAdjacency();
assert(e0->HEOp() != e1); // the hedge already exists
assert(e0!=e1->HENp());
std::vector<typename MeshType::EdgePointer* > toUpdate;
toUpdate.push_back(&e0);
toUpdate.push_back(&e1);
EdgeIterator ei0 = vcg::tri::Allocator<MeshType>::AddEdges(m,2,toUpdate);
EdgeIterator ei1 = ei0; ++ei1;
(*ei0).HENp() = e1;(*ei0).HEVp() = e0->HEVp();
(*ei1).HENp() = e0;(*ei1).HEVp() = e1->HEVp();
EdgePointer e0_HEPp = 0,e1_HEPp = 0,ep =0;
if(hasP){
e0_HEPp = e0->HEPp();
e1_HEPp = e1->HEPp();
}else{// does not have pointer to previous, it must be computed
ep = e0;
do{
if(ep->HENp() == e0) e0_HEPp = ep;
if(ep->HENp() == e1) e1_HEPp = ep;
ep = ep->HENp();
}while(ep!=e0);
}
if(hasP){
(*ei0).HEPp() = e0->HEPp();
(*ei1).HEPp() = e1->HEPp();
e0->HEPp() = &(*ei1);
e1->HEPp() = &(*ei0);
}
e0_HEPp -> HENp() = &(*ei0);
e1_HEPp -> HENp() = &(*ei1);
(*ei0).HEOp() = &(*ei1);
(*ei1).HEOp() = &(*ei0);
if( EdgeType::HasEFAdjacency() && FaceType::HasFHEAdjacency()){
FaceIterator fi0 = vcg::tri::Allocator<MeshType>::AddFaces(m,1);
m.face.back().ImportLocal(*e0->EFp());
SetRelationsLoopFace(&(*ei0),e1->EFp()); // one loop to the old face
SetRelationsLoopFace(&(*ei1),&m.face.back()); // the other to the new face
}
}
/** Detach the topology relations of a given edge
<--- e->HENPp -X --- <---------eO_HEPp---
^
||
e || e->HEOp()
||
v
----e_HEPp--> X ----- e->HEOp->HENPp() ------>
*/
static void RemoveEdge(MeshType &m, EdgeType * e){
assert(MeshType::EdgeType::HasHENextAdjacency());
assert(MeshType::EdgeType::HasHEOppAdjacency());
assert(MeshType::FaceType::HasFHEAdjacency());
bool hasP = MeshType::EdgeType::HasHEPrevAdjacency();
EdgePointer e_HEPp,eO_HEPp;
if(hasP){
e_HEPp = e->HEPp();
eO_HEPp = e->HEOp()->HEPp();
}else{
e_HEPp = PreviousEdge(e);
eO_HEPp = PreviousEdge(e->HEOp());
}
assert(e_HEPp->HENp() == e);
assert(eO_HEPp->HENp() == e->HEOp());
e_HEPp->HENp() = e->HEOp()->HENp();
eO_HEPp->HENp() = e-> HENp();
if(hasP) {
e->HEOp()->HENp()->HEPp() = e_HEPp;
e->HENp()->HEPp() = eO_HEPp;
e->HEPp() = NULL;
e-> HEOp()->HEPp() = NULL;
}
// take care of the faces
if(MeshType::EdgeType::HasEFAdjacency()){
MergeFaces(e_HEPp->EFp(),eO_HEPp->EFp());
vcg::tri::Allocator<MeshType>::DeleteFace(m,*eO_HEPp->EFp());
SetRelationsLoopFace(e_HEPp,e_HEPp->EFp());
}
vcg::tri::Allocator<MeshType>::DeleteEdge(m,*e->HEOp());
vcg::tri::Allocator<MeshType>::DeleteEdge(m,*e);
}
};// end class EdgeSupport
} // end namespace vcg
}
#endif // __VCGLIB_EDGE_SUPPORT