added allocation and conversion of edges in function FromIndexed

added new tests in function CheckConsistency
This commit is contained in:
Paolo Cignoni 2010-04-26 14:33:55 +00:00
parent 01a0a4b93c
commit 5c9ee5cdff
1 changed files with 553 additions and 379 deletions

View File

@ -32,451 +32,625 @@
namespace vcg namespace vcg
{ {
namespace tri{ namespace tri{
/// \ingroup trimesh /// \ingroup trimesh
/// \headerfile edge_support.h vcg/complex/trimesh/edge_support.h /// \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 /// \brief This class is used to build edge based data structure from indexed data structure and viceversa
/** /**
*/ */
template <class MeshType > template <class MeshType >
class UpdateHalfEdges{ class UpdateHalfEdges{
public: public:
typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::VertexPointer VertexPointer;
typedef typename MeshType::HEdgePointer HEdgePointer; typedef typename MeshType::VertexIterator VertexIterator;
typedef typename MeshType::HEdgeType HEdgeType; typedef typename MeshType::HEdgePointer HEdgePointer;
typedef typename MeshType::HEdgeIterator HEdgeIterator; typedef typename MeshType::HEdgeType HEdgeType;
typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::EdgePointer EdgePointer;
typedef typename MeshType::FaceType FaceType; typedef typename MeshType::EdgeType EdgeType;
typedef typename MeshType::EdgeIterator EdgeIterator;
typedef typename MeshType::HEdgeIterator HEdgeIterator;
typedef typename MeshType::FaceIterator FaceIterator;
typedef typename MeshType::FaceType FaceType;
struct VertexPairEdgePtr{ struct VertexPairEdgePtr{
VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,HEdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);} VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,HEdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);}
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):(v0<o.v0);}
const bool operator ==(const VertexPairEdgePtr &o) const {return (v0 == o.v0)&& (v1==o.v1);} const bool operator ==(const VertexPairEdgePtr &o) const {return (v0 == o.v0)&& (v1==o.v1);}
VertexPointer v0,v1; VertexPointer v0,v1;
HEdgePointer ep; HEdgePointer ep;
}; };
struct FacePtrInt{ struct FacePtrInt{
FacePtrInt ( FaceType * _f,int _i):f(_f),i(_i){} FacePtrInt ( FaceType * _f,int _i):f(_f),i(_i){}
FaceType * f; FaceType * f;
int i; int i;
}; };
typedef std::vector<bool> BitVector; 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. 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 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. to just "update" the topology of half edges.
**/ **/
static void FromIndexed(MeshType & m){ static void FromIndexed(MeshType & m){
assert(HasFVAdjacency(m)); assert(HasFVAdjacency(m));
assert(HasHOppAdjacency(m)); assert(HasHOppAdjacency(m));
assert(HasHNextAdjacency(m)); assert(HasHNextAdjacency(m));
assert(HasHEAdjacency(m));
typename MeshType::template PerFaceAttributeHandle<BitVector> flagVisited = typename MeshType::template PerFaceAttributeHandle<BitVector> flagVisited =
vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<BitVector>(m,""); vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<BitVector>(m,"");
std::vector<FacePtrInt > borderEdges; std::vector<FacePtrInt > borderEdges;
// allocate all new half edges // allocate all new half edges
FaceIterator fi; FaceIterator fi;
int n_edges = 0; unsigned int n_edges = 0;
// count how many half edge to allocate // count how many half edge to allocate
for(fi = m.face.begin(); fi != m.face.end(); ++fi) if(! (*fi).IsD()) for(fi = m.face.begin(); fi != m.face.end(); ++fi) if(! (*fi).IsD())
{n_edges+=(*fi).VN(); {n_edges+=(*fi).VN();
for(int i = 0; i < (*fi).VN(); ++i) for(int i = 0; i < (*fi).VN(); ++i)
if(vcg::face::IsBorder<FaceType>((*fi),(i))) if(vcg::face::IsBorder<FaceType>((*fi),(i)))
++n_edges; ++n_edges;
} }
// allocate the half edges m.hedge.clear();
typename MeshType::HEdgeIterator ei = vcg::tri::Allocator<MeshType>::AddHEdges(m,n_edges); m.hn = 0;
std::vector<VertexPairEdgePtr> all; // allocate the half edges
int firstEdge = 0; typename MeshType::HEdgeIterator ei = vcg::tri::Allocator<MeshType>::AddHEdges(m,n_edges);
for(fi = m.face.begin(); fi != m.face.end(); ++fi)if(!(*fi).IsD()){
assert((*fi).VN()>2);
if(flagVisited[*fi].empty()) {flagVisited[*fi].resize((*fi).VN());}
for(int i = 0; i < (*fi).VN(); ++i,++ei)
{
(*ei).HVp() = (*fi).V(i);
(*ei).HNp() = &m.hedge[firstEdge + (i +1) % (*fi).VN()];
if(MeshType::HEdgeType::HasHFAdjacency())
(*ei).HFp() = &(*fi);
if( MeshType::FaceType::HasFHAdjacency())
(*fi).FHp() = &(*ei);
if(MeshType::HEdgeType::HasHPrevAdjacency())
(*ei).HPp() = &m.hedge[firstEdge + (i +(*fi).VN()-1) % (*fi).VN()];
if(HasVHAdjacency(m))
(*ei).HVp()->VHp() = &(*ei);
all.push_back(VertexPairEdgePtr((*fi).V(i), (*fi).V((*fi).Next(i)),&(*ei)));// it will be used to link the hedges
if( vcg::face::IsBorder<FaceType>((*fi),(i))) std::vector<VertexPairEdgePtr> all;
borderEdges.push_back(FacePtrInt(&(*fi),i)); int firstEdge = 0;
} for(fi = m.face.begin(); fi != m.face.end(); ++fi)if(!(*fi).IsD()){
firstEdge += (*fi).VN(); assert((*fi).VN()>2);
} if(flagVisited[*fi].empty()) {flagVisited[*fi].resize((*fi).VN());}
// add all the border edges for(int i = 0; i < (*fi).VN(); ++i,++ei)
int borderLength; {
typename std::vector<FacePtrInt >::iterator ebi; (*ei).HVp() = (*fi).V(i);
for( ebi = borderEdges.begin(); ebi != borderEdges.end(); ++ebi) (*ei).HNp() = &m.hedge[firstEdge + (i +1) % (*fi).VN()];
if( !flagVisited[(*ebi).f][(*ebi).i])// not already inserted if(MeshType::HEdgeType::HasHFAdjacency())
{ (*ei).HFp() = &(*fi);
if( MeshType::FaceType::HasFHAdjacency())
(*fi).FHp() = &(*ei);
if(MeshType::HEdgeType::HasHPrevAdjacency())
(*ei).HPp() = &m.hedge[firstEdge + (i +(*fi).VN()-1) % (*fi).VN()];
if(HasVHAdjacency(m))
(*ei).HVp()->VHp() = &(*ei);
all.push_back(VertexPairEdgePtr((*fi).V(i), (*fi).V((*fi).Next(i)),&(*ei)));// it will be used to link the hedges
borderLength = 0; if( vcg::face::IsBorder<FaceType>((*fi),(i)))
vcg::face::Pos<FaceType> bp((*ebi).f,(*ebi).i); borderEdges.push_back(FacePtrInt(&(*fi),i));
FaceType * start = (*ebi).f; }
do{ firstEdge += (*fi).VN();
all.push_back( VertexPairEdgePtr ( bp.f->V( bp.f->Next(bp.z) ),bp.f->V( bp.z ),&(*ei))); }
(*ei).HVp() = 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 // add all the border hedges
for(int be = 0; be < borderLength; ++be){ int borderLength;
if(MeshType::HEdgeType::HasHFAdjacency()) typename std::vector<FacePtrInt >::iterator ebi;
m.hedge[firstEdge + be].HFp() = NULL; for( ebi = borderEdges.begin(); ebi != borderEdges.end(); ++ebi)
if(MeshType::HEdgeType::HasHPrevAdjacency()) if( !flagVisited[(*ebi).f][(*ebi).i])// not already inserted
m.hedge[firstEdge + be].HPp() = &m.hedge[firstEdge + (be +borderLength-1) % borderLength]; {
m.hedge[firstEdge + be].HNp() = &m.hedge[firstEdge + (be +1) % borderLength];
}
firstEdge+=borderLength;
}
vcg::tri::Allocator<MeshType>:: template DeletePerFaceAttribute<BitVector>(m,flagVisited );
std::sort(all.begin(),all.end()); borderLength = 0;
assert(all.size() == n_edges); vcg::face::Pos<FaceType> bp((*ebi).f,(*ebi).i);
for(int i = 0 ; i < all.size(); )
if(all[i] == all[i+1])
{
all[i].ep->HOp() = all[i+1].ep;
all[i+1].ep->HOp() = all[i].ep;
i+=2;
}
else
{
all[i].ep->HOp() = all[i].ep;
i+=1;
}
} //FaceType * start = (*ebi).f;
VertexType * start = ((*ebi).f)->V((*ebi).i);
do{
all.push_back( VertexPairEdgePtr ( bp.f->V( bp.f->Next(bp.z) ),bp.f->V( bp.z ),&(*ei)));
(*ei).HVp() = bp.f->V(bp.f->Next(bp.z)) ;
flagVisited[bp.f][bp.z] = true;
++ei;
bp.NextB();
++borderLength;
}while (bp.v != start);
//}while (bp.f != start);
/**
Checks pointers FHEp() are valid
**/
static bool CheckConsistency_FHp(MeshType & m){
assert(MeshType::FaceType::HasFHAdjacency());
FaceIterator fi;
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
if(!(*fi).IsD()){
if((*fi).FHp() < &(*m.hedge.begin())) return false;
if((*fi).FHp() > &(m.hedge.back())) return false;
}
return true;
}
/** // run over the border edges to link the adjacencies
Checks that half edges and face relation are consistent for(int be = 0; be < borderLength; ++be)
**/ {
static bool CheckConsistency(MeshType & m){ if(MeshType::HEdgeType::HasHFAdjacency())
assert(MeshType::HEdgeType::HasHNextAdjacency()); m.hedge[firstEdge + be].HFp() = NULL;
assert(MeshType::HEdgeType::HasHOppAdjacency());
assert(MeshType::HEdgeType::HasHVAdjacency());
assert(MeshType::FaceType::HasFHAdjacency());
bool hasHEF = ( MeshType::HEdgeType::HasHFAdjacency()); if(MeshType::HEdgeType::HasHPrevAdjacency())
bool hasHEP = ( MeshType::HEdgeType::HasHPrevAdjacency()); m.hedge[firstEdge + be].HPp() = &m.hedge[firstEdge + (be +borderLength-1) % borderLength];
FaceIterator fi; m.hedge[firstEdge + be].HNp() = &m.hedge[firstEdge + (be +1) % borderLength];
HEdgePointer ep,ep1; }
int cnt = 0; firstEdge+=borderLength;
if(( MeshType::HEdgeType::HasHFAdjacency())){ }
int iDb = 0;
for(fi = m.face.begin(); fi != m.face.end(); ++fi,++iDb)
if(!(*fi).IsD())
{
ep = ep1 = (*fi).FHp();
do{
if(ep->IsD())
return false; // the edge should not be connected, it has been deleted
if(ep->HFp() != &(*fi))
return false;// edge is not pointing to the rigth face
ep = ep->HNp();
if(cnt++ > m.hn)
return false; // edges are ill connected (HENp())
}while(ep!=ep1);
}
}
HEdgePointer epPrev; vcg::tri::Allocator<MeshType>:: template DeletePerFaceAttribute<BitVector>(m,flagVisited );
HEdgeIterator ei;
bool extEdge ;
for( ei = m.hedge.begin(); ei != m.hedge.end(); ++ei)
if(!(*ei).IsD())
{
cnt = 0;
epPrev = ep = ep1 = &(*ei);
do{
extEdge = (ep->HFp()==NULL);
if(hasHEP){
if( ep->HNp()->HPp() != ep)
return false; // next and prev relation are not mutual
if( ep->HPp() == ep)
return false; // the previous of an edge cannot be the edge itself
}
if( ep->HOp() == ep)
return false; // opposite relation is not mutual
if( ep->HOp()->HOp() != ep)
return false; // opposite relation is not mutual
if(ep->HNp() == ep)
return false; // the next of an edge cannot be the edge itself
ep = ep->HNp();
if( ep->HVp() != epPrev->HOp()->HVp())
return false; // the opposite edge points to a vertex different that the vertex of the next edge
epPrev = ep;
if(cnt++ > m.hn)
return false; // edges are ill connected (HENp())
}while(ep!=ep1);
}
return true; std::sort(all.begin(),all.end());
} assert(all.size() == n_edges);
/** Set the relations HFp(), FHp() from a loop of edges to a face for(unsigned int i = 0 ; i < all.size(); )
*/ if(all[i] == all[i+1])
private: {
static void SetRelationsLoopFace(HEdgeType * e0, FaceType * f){ all[i].ep->HOp() = all[i+1].ep;
assert(HEdgeType::HasHNextAdjacency()); all[i+1].ep->HOp() = all[i].ep;
assert(FaceType::HasFHAdjacency()); i+=2;
}
else
{
all[i].ep->HOp() = all[i].ep;
i+=1;
}
HEdgeType *e = e0; if(HasEHAdjacency(m) && HasHEAdjacency(m))
assert(e!=NULL); {
do{ e->HFp() = f; e = e->HNp(); } while(e != e0); assert(m.edge.size() == 0 || m.edge.size() == n_edges/2);
f->FHp() = e0;
}
/** if ( m.edge.size() == 0 )
Merge the two faces. This will probably become a class template or a functor {
*/ m.en = 0;
static void MergeFaces(FaceType *, FaceType *){}; // allocate the edges
typename MeshType::EdgeIterator edge_i = vcg::tri::Allocator<MeshType>::AddEdges(m,n_edges/2);
/** for(ei = m.hedge.begin(); ei != m.hedge.end(); ++ei)
Find previous hedge in the loop {
*/ if((*ei).HEp() == NULL)
static HEdgeType * PreviousEdge(HEdgeType * e0){ {
HEdgeType * ep = e0; (*ei).HEp() = &(*edge_i);
do{ (*ei).HOp()->HEp() = &(*edge_i);
if(ep->HNp() == e0) return ep;
ep = ep->HNp();
}while(ep!=e0);
assert(0); // degenerate loop
return 0;
}
public: (*edge_i).EHp() = &(*ei);
/** 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. ++edge_i;
}
}
}
else
{
assert(HasEVAdjacency(m));
//update edge relations
typename MeshType::EdgeIterator ei1;
for( ei1 = m.edge.begin(); ei1 != m.edge.end(); ++ei1 )
for( ei = m.hedge.begin(); ei != m.hedge.end(); ++ei )
if ( ((*ei).HVp() == (*ei1).V(0)) && ((*ei).HOp()->HVp() == (*ei1).V(1)) )
{
// EH
(*ei1).EHp() = &(*ei);
// HE
(*ei).HEp() = &(*ei1);
(*ei).HOp()->HEp() = &(*ei1);
break;
}
}
}
}
/**
Checks pointers FHEp() are valid
**/
static bool CheckConsistency_FHp(MeshType & m){
assert(MeshType::FaceType::HasFHAdjacency());
FaceIterator fi;
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
if(!(*fi).IsD()){
if((*fi).FHp() < &(*m.hedge.begin())) return false;
if((*fi).FHp() > &(m.hedge.back())) return false;
}
return true;
}
/**
Checks that half edges and face relation are consistent
**/
static bool CheckConsistency(MeshType & m){
assert(MeshType::HEdgeType::HasHNextAdjacency());
assert(MeshType::HEdgeType::HasHOppAdjacency());
assert(MeshType::HEdgeType::HasHVAdjacency());
assert(MeshType::HEdgeType::HasHEAdjacency());
assert(MeshType::FaceType::HasFHAdjacency());
//bool hasHEF = ( MeshType::HEdgeType::HasHFAdjacency());
bool hasHP = ( MeshType::HEdgeType::HasHPrevAdjacency());
FaceIterator fi;
HEdgePointer ep,ep1;
int cnt = 0;
if( MeshType::HEdgeType::HasHFAdjacency() )
{
int iDb = 0;
for(fi = m.face.begin(); fi != m.face.end(); ++fi,++iDb)
if(!(*fi).IsD())
{
ep = ep1 = (*fi).FHp();
do{
if(ep->IsD())
return false; // the hedge should not be connected, it has been deleted
if( ! ep->HFp())
return false;
if(ep->HFp() != &(*fi))
return false;// hedge is not pointing to the rigth face
ep = ep->HNp();
if(cnt++ > m.hn)
return false; // hedges are ill connected (HENp())
}while(ep!=ep1);
}
}
HEdgePointer epPrev;
HEdgeIterator hi;
//bool extEdge ;
for( hi = m.hedge.begin(); hi != m.hedge.end(); ++hi)
if(!(*hi).IsD())
{
//cnt = 0;
epPrev = ep = ep1 = &(*hi);
//do{
//extEdge = (ep->HFp()==NULL);
if(hasHP)
{
if( !ep->HPp())
return false;
if( ep->HPp() == ep)
return false; // the previous of an edge cannot be the edge itself
if( ep->HNp()->HPp() != ep)
return false; // next and prev relation are not mutual
if( ep->HPp()->IsD())
return false; //
}
if( ! ep->HOp() )
return false;
if( ep->HOp() == ep)
return false; // opposite relation is not mutual
if( ep->HOp()->IsD())
return false;
if( ep->HOp()->HOp() != ep)
return false; // opposite relation is not mutual
if( HasHFAdjacency(m) )
{
if(ep->HFp())
{
if( ep->HFp()->IsD())
return false; // pointed face must not be deleted
}
}
if( HasHEAdjacency(m) )
{
if( ! ep->HEp())
return false; //halfedge must point to an edge
if( ep->HEp()->IsD())
return false; // pointed edge must not be deleted
if(ep->HEp() != ep->HOp()->HEp())
return false; // he and opposite he must point to the same edge
if(ep->HEp()->EHp() != ep && ep->HEp()->EHp() != ep->HOp() )
return false; // halfedge points to an edge not pointing it or its opposite
}
if( !ep->HNp() )
return false;
if( ep->HNp() == ep )
return false; // the next of an hedge cannot be the hedge itself
if( ep->HNp()->IsD())
return false; //
if( ep->HNp()->HPp() != ep)
return false; //
if( HasHVAdjacency(m) )
{
if( ! ep->HVp() )
return false; // halfedge must point to a vertex
if( ep->HVp()->IsD() )
return false; // pointed vertex must not be deleted
if( HasVHAdjacency(m) )
if( ! (ep->HVp()->VHp()) )
return false; // halfedge points to a vertex pointing NULL
}
ep = ep->HNp();
if( ep->HVp() != epPrev->HOp()->HVp())
return false;
epPrev = ep;
// if(cnt++ > m.hn)
// return false; // edges are ill connected (HENp())
//}while(ep!=ep1);
}
if(HasEHAdjacency(m))
for(EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei)
{
if(!(*ei).IsD())
{
if( !(*ei).EHp())
return false; //edge must have a valid pointer to his halfedge
if( (*ei).EHp()->HEp() != &(*ei) )
return false; // edge's halfedge must point to the edge itself
if( (*ei).EHp()->IsD())
return false;
}
}
if(HasVHAdjacency(m))
for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
{
if( !(*vi).IsD() )
if( (*vi).VHp() )
{
if( (*vi).VHp()->HVp() != &(*vi) )
return false;
if( (*vi).VHp()->IsD())
return false;
}
}
return true;
}
/** Set the relations HFp(), FHp() from a loop of edges to a face
*/
private:
static void SetRelationsLoopFace(HEdgeType * e0, FaceType * f){
assert(HEdgeType::HasHNextAdjacency());
assert(FaceType::HasFHAdjacency());
HEdgeType *e = e0;
assert(e!=NULL);
do{ e->HFp() = f; e = e->HNp(); } while(e != e0);
f->FHp() = 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 HEdgeType * PreviousEdge(HEdgeType * e0){
HEdgeType * ep = e0;
do{
if(ep->HNp() == e0) return ep;
ep = ep->HNp();
}while(ep!=e0);
assert(0); // degenerate loop
return 0;
}
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--- <--- e1 ---- X <------e1_HEPp---
^ ^
|| ||
ei0 || ei1 ei0 || ei1
|| ||
v v
----e0_HEPp-> X ----- e0 ------> ----e0_HEPp-> X ----- e0 ------>
*/ */
static void AddHEdge(MeshType &m, HEdgeType * e0, HEdgeType * e1){ static void AddHEdge(MeshType &m, HEdgeType * e0, HEdgeType * e1){
HEdgeType *iii =e0->HNp(); HEdgeType *iii =e0->HNp();
assert(e1!=e0->HNp()); assert(e1!=e0->HNp());
assert(e0!=e1->HNp()); assert(e0!=e1->HNp());
HEdgePointer tmp; HEdgePointer tmp;
bool hasP = MeshType::HEdgeType::HasHPrevAdjacency(); bool hasP = MeshType::HEdgeType::HasHPrevAdjacency();
assert(e0->HOp() != e1); // the hedge already exists assert(e0->HOp() != e1); // the hedge already exists
assert(e0!=e1->HNp()); assert(e0!=e1->HNp());
std::vector<typename MeshType::HEdgePointer* > toUpdate; std::vector<typename MeshType::HEdgePointer* > toUpdate;
toUpdate.push_back(&e0); toUpdate.push_back(&e0);
toUpdate.push_back(&e1); toUpdate.push_back(&e1);
HEdgeIterator ei0 = vcg::tri::Allocator<MeshType>::AddHEdges(m,2,toUpdate); HEdgeIterator ei0 = vcg::tri::Allocator<MeshType>::AddHEdges(m,2,toUpdate);
HEdgeIterator ei1 = ei0; ++ei1; HEdgeIterator ei1 = ei0; ++ei1;
(*ei0).HNp() = e1;(*ei0).HVp() = e0->HVp(); (*ei0).HNp() = e1;(*ei0).HVp() = e0->HVp();
(*ei1).HNp() = e0;(*ei1).HVp() = e1->HVp(); (*ei1).HNp() = e0;(*ei1).HVp() = e1->HVp();
HEdgePointer e0_HEPp = 0,e1_HEPp = 0,ep =0; HEdgePointer e0_HEPp = 0,e1_HEPp = 0,ep =0;
if(hasP){ if(hasP){
e0_HEPp = e0->HPp(); e0_HEPp = e0->HPp();
e1_HEPp = e1->HPp(); e1_HEPp = e1->HPp();
}else{// does not have pointer to previous, it must be computed }else{// does not have pointer to previous, it must be computed
ep = e0; ep = e0;
do{ do{
if(ep->HNp() == e0) e0_HEPp = ep; if(ep->HNp() == e0) e0_HEPp = ep;
if(ep->HNp() == e1) e1_HEPp = ep; if(ep->HNp() == e1) e1_HEPp = ep;
ep = ep->HNp(); ep = ep->HNp();
}while(ep!=e0); }while(ep!=e0);
} }
if(hasP){ if(hasP){
(*ei0).HPp() = e0->HPp(); (*ei0).HPp() = e0->HPp();
(*ei1).HPp() = e1->HPp(); (*ei1).HPp() = e1->HPp();
e0->HPp() = &(*ei1); e0->HPp() = &(*ei1);
e1->HPp() = &(*ei0); e1->HPp() = &(*ei0);
} }
e0_HEPp -> HNp() = &(*ei0); e0_HEPp -> HNp() = &(*ei0);
e1_HEPp -> HNp() = &(*ei1); e1_HEPp -> HNp() = &(*ei1);
(*ei0).HOp() = &(*ei1); (*ei0).HOp() = &(*ei1);
(*ei1).HOp() = &(*ei0); (*ei1).HOp() = &(*ei0);
if( HEdgeType::HasHFAdjacency() && FaceType::HasFHAdjacency()){ if( HEdgeType::HasHFAdjacency() && FaceType::HasFHAdjacency()){
FaceIterator fi0 = vcg::tri::Allocator<MeshType>::AddFaces(m,1); FaceIterator fi0 = vcg::tri::Allocator<MeshType>::AddFaces(m,1);
m.face.back().ImportLocal(*e0->HFp()); m.face.back().ImportLocal(*e0->HFp());
SetRelationsLoopFace(&(*ei0),e1->HFp()); // one loop to the old face SetRelationsLoopFace(&(*ei0),e1->HFp()); // one loop to the old face
SetRelationsLoopFace(&(*ei1),&m.face.back()); // the other to the new face SetRelationsLoopFace(&(*ei1),&m.face.back()); // the other to the new face
} }
} }
/** Detach the topology relations of a given edge /** Detach the topology relations of a given edge
<--- e->HENPp -X --- <---------eO_HEPp--- <--- e->HENPp -X --- <---------eO_HEPp---
^ ^
|| ||
e || e->HEOp() e || e->HEOp()
|| ||
v v
----e_HEPp--> X ----- e->HEOp->HENPp() ------> ----e_HEPp--> X ----- e->HEOp->HENPp() ------>
*/ */
static void RemoveHEdge(MeshType &m, HEdgeType * e){ static void RemoveHEdge(MeshType &m, HEdgeType * e){
assert(MeshType::HEdgeType::HasHNextAdjacency()); assert(MeshType::HEdgeType::HasHNextAdjacency());
assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency());
assert(MeshType::FaceType::HasFHAdjacency()); assert(MeshType::FaceType::HasFHAdjacency());
bool hasP = MeshType::HEdgeType::HasHPrevAdjacency(); bool hasP = MeshType::HEdgeType::HasHPrevAdjacency();
HEdgePointer e_HEPp,eO_HEPp; HEdgePointer e_HEPp,eO_HEPp;
if(hasP){ if(hasP){
e_HEPp = e->HPp(); e_HEPp = e->HPp();
eO_HEPp = e->HOp()->HPp(); eO_HEPp = e->HOp()->HPp();
}else{ }else{
e_HEPp = PreviousEdge(e); e_HEPp = PreviousEdge(e);
eO_HEPp = PreviousEdge(e->HOp()); eO_HEPp = PreviousEdge(e->HOp());
} }
assert(e_HEPp->HNp() == e); assert(e_HEPp->HNp() == e);
assert(eO_HEPp->HNp() == e->HOp()); assert(eO_HEPp->HNp() == e->HOp());
e_HEPp->HNp() = e->HOp()->HNp(); e_HEPp->HNp() = e->HOp()->HNp();
eO_HEPp->HNp() = e-> HNp(); eO_HEPp->HNp() = e-> HNp();
if(hasP) { if(hasP) {
e->HOp()->HNp()->HPp() = e_HEPp; e->HOp()->HNp()->HPp() = e_HEPp;
e->HNp()->HPp() = eO_HEPp; e->HNp()->HPp() = eO_HEPp;
e->HPp() = NULL; e->HPp() = NULL;
e-> HOp()->HPp() = NULL; e-> HOp()->HPp() = NULL;
} }
// take care of the faces // take care of the faces
if(MeshType::HEdgeType::HasHFAdjacency()){ if(MeshType::HEdgeType::HasHFAdjacency()){
MergeFaces(e_HEPp->HFp(),eO_HEPp->HFp()); MergeFaces(e_HEPp->HFp(),eO_HEPp->HFp());
vcg::tri::Allocator<MeshType>::DeleteFace(m,*eO_HEPp->HFp()); vcg::tri::Allocator<MeshType>::DeleteFace(m,*eO_HEPp->HFp());
SetRelationsLoopFace(e_HEPp,e_HEPp->HFp()); SetRelationsLoopFace(e_HEPp,e_HEPp->HFp());
} }
vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e->HOp()); vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e->HOp());
vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e); vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e);
} }
};// end class };// end class
template <class MeshType > template <class MeshType >
struct UpdateIndexed{ struct UpdateIndexed{
typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::VertexPointer VertexPointer;
typedef typename MeshType::HEdgePointer HEdgePointer; typedef typename MeshType::HEdgePointer HEdgePointer;
typedef typename MeshType::HEdgeType HEdgeType; typedef typename MeshType::HEdgeType HEdgeType;
typedef typename MeshType::HEdgeIterator HEdgeIterator; typedef typename MeshType::HEdgeIterator HEdgeIterator;
typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceIterator FaceIterator;
typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FaceType FaceType;
struct VertexPairEdgePtr{ struct VertexPairEdgePtr{
VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,HEdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);} VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,HEdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);}
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):(v0<o.v0);}
const bool operator ==(const VertexPairEdgePtr &o) const {return (v0 == o.v0)&& (v1==o.v1);} const bool operator ==(const VertexPairEdgePtr &o) const {return (v0 == o.v0)&& (v1==o.v1);}
VertexPointer v0,v1; VertexPointer v0,v1;
HEdgePointer ep; HEdgePointer ep;
}; };
/** /**
builds an indexed data structure from a half-edge data structure. builds an indexed data structure from a half-edge data structure.
Note: if the half edge have the pointer to face 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 their relation FV (face-vertex) will be computed and the data possibly stored in the
face will be preserved. face will be preserved.
**/ **/
static void FromHalfEdges( MeshType & m ){ static void FromHalfEdges( MeshType & m ){
assert(HasFVAdjacency(m)); assert(HasFVAdjacency(m));
assert(MeshType::HEdgeType::HasHNextAdjacency()); assert(MeshType::HEdgeType::HasHNextAdjacency());
assert(MeshType::HEdgeType::HasHVAdjacency()); assert(MeshType::HEdgeType::HasHVAdjacency());
assert(MeshType::HEdgeType::HasHOppAdjacency()); assert(MeshType::HEdgeType::HasHOppAdjacency());
assert(MeshType::FaceType::HasFHAdjacency()); assert(MeshType::FaceType::HasFHAdjacency());
bool createFace,hasHEF,hasFHE; bool hasHEF;
//bool createFace,hasHEF,hasFHE;
// typename MeshType::template PerHEdgeAttributeHandle<bool> hV = Allocator<MeshType>::template AddPerHEdgeAttribute<bool>(m,""); // typename MeshType::template PerHEdgeAttributeHandle<bool> hV = Allocator<MeshType>::template AddPerHEdgeAttribute<bool>(m,"");
typename MeshType::HEdgeIterator ei; typename MeshType::HEdgeIterator ei;
typename MeshType::FacePointer fp; typename MeshType::FacePointer fp;
typename MeshType::FaceIterator fi; typename MeshType::FaceIterator fi;
typename MeshType::HEdgePointer ep,epF; typename MeshType::HEdgePointer ep,epF;
int vi = 0; //int vi = 0;
vcg::SimpleTempData<typename MeshType::HEdgeContainer,bool> hV(m.hedge); vcg::SimpleTempData<typename MeshType::HEdgeContainer,bool> hV(m.hedge);
hasHEF = (MeshType::HEdgeType::HasHFAdjacency()); hasHEF = (MeshType::HEdgeType::HasHFAdjacency());
assert( !hasHEF || (hasHEF && m.fn>0)); assert( !hasHEF || (hasHEF && m.fn>0));
// if the edgetype has the pointer to face // if the edgetype has the pointer to face
// it is assumed the the edget2face pointer (HEFp) are correct // it is assumed the the edget2face pointer (HEFp) are correct
// and the faces are allocated // and the faces are allocated
for ( ei = m.hedge.begin(); ei != m.hedge.end(); ++ei) for ( ei = m.hedge.begin(); ei != m.hedge.end(); ++ei)
if(!(*ei).IsD()) // it has not been deleted if(!(*ei).IsD()) // it has not been deleted
if(!hasHEF || ( hasHEF && (*ei).HFp()!=NULL)) // if it has a pointer to the face it is if(!hasHEF || ( hasHEF && (*ei).HFp()!=NULL)) // if it has a pointer to the face it is
// not null (i.e. it is not a border edge) // not null (i.e. it is not a border edge)
if(!hV[(*ei)] ) // it has not be visited yet if(!hV[(*ei)] ) // it has not be visited yet
{ {
if(!hasHEF)// if it has if(!hasHEF)// if it has
fp = &(* Allocator<MeshType>::AddFaces(m,1)); fp = &(* Allocator<MeshType>::AddFaces(m,1));
else else
fp = (*ei).HFp(); fp = (*ei).HFp();
ep = epF = &(*ei); ep = epF = &(*ei);
std::vector<VertexPointer> vpts; std::vector<VertexPointer> vpts;
do{vpts.push_back((*ep).HVp()); ep=ep->HNp();}while(ep!=epF); do{vpts.push_back((*ep).HVp()); ep=ep->HNp();}while(ep!=epF);
int idbg =fp->VN(); //int idbg =fp->VN();
if(fp->VN() != vpts.size()){ if(fp->VN() != vpts.size()){
fp->Dealloc(); fp->Dealloc();
fp ->Alloc(vpts.size()); fp ->Alloc(vpts.size());
} }
int idbg1 =fp->VN(); //int idbg1 =fp->VN();
for(unsigned int i = 0; i < vpts.size();++i) fp ->V(i) = vpts[i];// set the pointer from face to vertex for(unsigned int i = 0; i < vpts.size();++i) fp ->V(i) = vpts[i];// set the pointer from face to vertex
hV[(*ei)] = true; hV[(*ei)] = true;
} }
//Allocator<MeshType>::DeletePerHEdgeAttribute(m,hV); //Allocator<MeshType>::DeletePerHEdgeAttribute(m,hV);
} }
}; };
} // end namespace vcg } // end namespace vcg
} }
#endif // __VCGLIB_EDGE_SUPPORT #endif // __VCGLIB_EDGE_SUPPORT