added allocation and conversion of edges in function FromIndexed
added new tests in function CheckConsistency
This commit is contained in:
parent
01a0a4b93c
commit
5c9ee5cdff
|
@ -32,451 +32,625 @@
|
|||
|
||||
namespace vcg
|
||||
{
|
||||
namespace tri{
|
||||
/// \ingroup trimesh
|
||||
namespace tri{
|
||||
/// \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 >
|
||||
class UpdateHalfEdges{
|
||||
public:
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::VertexPointer VertexPointer;
|
||||
typedef typename MeshType::HEdgePointer HEdgePointer;
|
||||
typedef typename MeshType::HEdgeType HEdgeType;
|
||||
typedef typename MeshType::HEdgeIterator HEdgeIterator;
|
||||
typedef typename MeshType::FaceIterator FaceIterator;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
template <class MeshType >
|
||||
class UpdateHalfEdges{
|
||||
public:
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::VertexPointer VertexPointer;
|
||||
typedef typename MeshType::VertexIterator VertexIterator;
|
||||
typedef typename MeshType::HEdgePointer HEdgePointer;
|
||||
typedef typename MeshType::HEdgeType HEdgeType;
|
||||
typedef typename MeshType::EdgePointer EdgePointer;
|
||||
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{
|
||||
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);}
|
||||
struct VertexPairEdgePtr{
|
||||
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);}
|
||||
|
||||
VertexPointer v0,v1;
|
||||
HEdgePointer ep;
|
||||
};
|
||||
struct FacePtrInt{
|
||||
FacePtrInt ( FaceType * _f,int _i):f(_f),i(_i){}
|
||||
FaceType * f;
|
||||
int i;
|
||||
};
|
||||
VertexPointer v0,v1;
|
||||
HEdgePointer ep;
|
||||
};
|
||||
struct FacePtrInt{
|
||||
FacePtrInt ( FaceType * _f,int _i):f(_f),i(_i){}
|
||||
FaceType * f;
|
||||
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.
|
||||
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 FromIndexed(MeshType & m){
|
||||
assert(HasFVAdjacency(m));
|
||||
assert(HasHOppAdjacency(m));
|
||||
assert(HasHNextAdjacency(m));
|
||||
/**
|
||||
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 FromIndexed(MeshType & m){
|
||||
assert(HasFVAdjacency(m));
|
||||
assert(HasHOppAdjacency(m));
|
||||
assert(HasHNextAdjacency(m));
|
||||
assert(HasHEAdjacency(m));
|
||||
|
||||
typename MeshType::template PerFaceAttributeHandle<BitVector> flagVisited =
|
||||
vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<BitVector>(m,"");
|
||||
std::vector<FacePtrInt > borderEdges;
|
||||
typename MeshType::template PerFaceAttributeHandle<BitVector> flagVisited =
|
||||
vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<BitVector>(m,"");
|
||||
std::vector<FacePtrInt > borderEdges;
|
||||
|
||||
// allocate all new half edges
|
||||
FaceIterator fi;
|
||||
int n_edges = 0;
|
||||
// allocate all new half edges
|
||||
FaceIterator fi;
|
||||
unsigned int n_edges = 0;
|
||||
|
||||
// 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;
|
||||
}
|
||||
// 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::HEdgeIterator ei = vcg::tri::Allocator<MeshType>::AddHEdges(m,n_edges);
|
||||
m.hedge.clear();
|
||||
m.hn = 0;
|
||||
|
||||
std::vector<VertexPairEdgePtr> all;
|
||||
int firstEdge = 0;
|
||||
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());}
|
||||
// allocate the half edges
|
||||
typename MeshType::HEdgeIterator ei = vcg::tri::Allocator<MeshType>::AddHEdges(m,n_edges);
|
||||
|
||||
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)))
|
||||
borderEdges.push_back(FacePtrInt(&(*fi),i));
|
||||
}
|
||||
firstEdge += (*fi).VN();
|
||||
}
|
||||
std::vector<VertexPairEdgePtr> all;
|
||||
int firstEdge = 0;
|
||||
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());}
|
||||
|
||||
// add all the border edges
|
||||
int borderLength;
|
||||
typename std::vector<FacePtrInt >::iterator ebi;
|
||||
for( ebi = borderEdges.begin(); ebi != borderEdges.end(); ++ebi)
|
||||
if( !flagVisited[(*ebi).f][(*ebi).i])// not already inserted
|
||||
{
|
||||
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
|
||||
|
||||
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).HVp() = bp.f->V(bp.f->Next(bp.z)) ;
|
||||
flagVisited[bp.f][bp.z] = true;
|
||||
++ei;
|
||||
bp.NextB();
|
||||
++borderLength;
|
||||
}while (bp.f != start);
|
||||
if( vcg::face::IsBorder<FaceType>((*fi),(i)))
|
||||
borderEdges.push_back(FacePtrInt(&(*fi),i));
|
||||
}
|
||||
firstEdge += (*fi).VN();
|
||||
}
|
||||
|
||||
// run over the border edges to link the adjacencies
|
||||
for(int be = 0; be < borderLength; ++be){
|
||||
if(MeshType::HEdgeType::HasHFAdjacency())
|
||||
m.hedge[firstEdge + be].HFp() = NULL;
|
||||
if(MeshType::HEdgeType::HasHPrevAdjacency())
|
||||
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 );
|
||||
// add all the border hedges
|
||||
int borderLength;
|
||||
typename std::vector<FacePtrInt >::iterator ebi;
|
||||
for( ebi = borderEdges.begin(); ebi != borderEdges.end(); ++ebi)
|
||||
if( !flagVisited[(*ebi).f][(*ebi).i])// not already inserted
|
||||
{
|
||||
|
||||
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->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;
|
||||
}
|
||||
borderLength = 0;
|
||||
vcg::face::Pos<FaceType> bp((*ebi).f,(*ebi).i);
|
||||
|
||||
}
|
||||
//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;
|
||||
}
|
||||
|
||||
/**
|
||||
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::FaceType::HasFHAdjacency());
|
||||
// run over the border edges to link the adjacencies
|
||||
for(int be = 0; be < borderLength; ++be)
|
||||
{
|
||||
if(MeshType::HEdgeType::HasHFAdjacency())
|
||||
m.hedge[firstEdge + be].HFp() = NULL;
|
||||
|
||||
bool hasHEF = ( MeshType::HEdgeType::HasHFAdjacency());
|
||||
bool hasHEP = ( MeshType::HEdgeType::HasHPrevAdjacency());
|
||||
if(MeshType::HEdgeType::HasHPrevAdjacency())
|
||||
m.hedge[firstEdge + be].HPp() = &m.hedge[firstEdge + (be +borderLength-1) % borderLength];
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
m.hedge[firstEdge + be].HNp() = &m.hedge[firstEdge + (be +1) % borderLength];
|
||||
}
|
||||
firstEdge+=borderLength;
|
||||
}
|
||||
|
||||
HEdgePointer epPrev;
|
||||
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);
|
||||
}
|
||||
vcg::tri::Allocator<MeshType>:: template DeletePerFaceAttribute<BitVector>(m,flagVisited );
|
||||
|
||||
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
|
||||
*/
|
||||
private:
|
||||
static void SetRelationsLoopFace(HEdgeType * e0, FaceType * f){
|
||||
assert(HEdgeType::HasHNextAdjacency());
|
||||
assert(FaceType::HasFHAdjacency());
|
||||
for(unsigned 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;
|
||||
}
|
||||
|
||||
HEdgeType *e = e0;
|
||||
assert(e!=NULL);
|
||||
do{ e->HFp() = f; e = e->HNp(); } while(e != e0);
|
||||
f->FHp() = e0;
|
||||
}
|
||||
if(HasEHAdjacency(m) && HasHEAdjacency(m))
|
||||
{
|
||||
assert(m.edge.size() == 0 || m.edge.size() == n_edges/2);
|
||||
|
||||
/**
|
||||
Merge the two faces. This will probably become a class template or a functor
|
||||
*/
|
||||
static void MergeFaces(FaceType *, FaceType *){};
|
||||
if ( m.edge.size() == 0 )
|
||||
{
|
||||
m.en = 0;
|
||||
// allocate the edges
|
||||
typename MeshType::EdgeIterator edge_i = vcg::tri::Allocator<MeshType>::AddEdges(m,n_edges/2);
|
||||
|
||||
/**
|
||||
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;
|
||||
}
|
||||
for(ei = m.hedge.begin(); ei != m.hedge.end(); ++ei)
|
||||
{
|
||||
if((*ei).HEp() == NULL)
|
||||
{
|
||||
(*ei).HEp() = &(*edge_i);
|
||||
(*ei).HOp()->HEp() = &(*edge_i);
|
||||
|
||||
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.
|
||||
(*edge_i).EHp() = &(*ei);
|
||||
|
||||
++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---
|
||||
^
|
||||
||
|
||||
ei0 || ei1
|
||||
||
|
||||
v
|
||||
----e0_HEPp-> X ----- e0 ------>
|
||||
*/
|
||||
static void AddHEdge(MeshType &m, HEdgeType * e0, HEdgeType * e1){
|
||||
HEdgeType *iii =e0->HNp();
|
||||
assert(e1!=e0->HNp());
|
||||
assert(e0!=e1->HNp());
|
||||
HEdgePointer tmp;
|
||||
bool hasP = MeshType::HEdgeType::HasHPrevAdjacency();
|
||||
assert(e0->HOp() != e1); // the hedge already exists
|
||||
assert(e0!=e1->HNp());
|
||||
----e0_HEPp-> X ----- e0 ------>
|
||||
*/
|
||||
static void AddHEdge(MeshType &m, HEdgeType * e0, HEdgeType * e1){
|
||||
HEdgeType *iii =e0->HNp();
|
||||
assert(e1!=e0->HNp());
|
||||
assert(e0!=e1->HNp());
|
||||
HEdgePointer tmp;
|
||||
bool hasP = MeshType::HEdgeType::HasHPrevAdjacency();
|
||||
assert(e0->HOp() != e1); // the hedge already exists
|
||||
assert(e0!=e1->HNp());
|
||||
|
||||
std::vector<typename MeshType::HEdgePointer* > toUpdate;
|
||||
toUpdate.push_back(&e0);
|
||||
toUpdate.push_back(&e1);
|
||||
HEdgeIterator ei0 = vcg::tri::Allocator<MeshType>::AddHEdges(m,2,toUpdate);
|
||||
std::vector<typename MeshType::HEdgePointer* > toUpdate;
|
||||
toUpdate.push_back(&e0);
|
||||
toUpdate.push_back(&e1);
|
||||
HEdgeIterator ei0 = vcg::tri::Allocator<MeshType>::AddHEdges(m,2,toUpdate);
|
||||
|
||||
HEdgeIterator ei1 = ei0; ++ei1;
|
||||
(*ei0).HNp() = e1;(*ei0).HVp() = e0->HVp();
|
||||
(*ei1).HNp() = e0;(*ei1).HVp() = e1->HVp();
|
||||
HEdgeIterator ei1 = ei0; ++ei1;
|
||||
(*ei0).HNp() = e1;(*ei0).HVp() = e0->HVp();
|
||||
(*ei1).HNp() = e0;(*ei1).HVp() = e1->HVp();
|
||||
|
||||
HEdgePointer e0_HEPp = 0,e1_HEPp = 0,ep =0;
|
||||
if(hasP){
|
||||
e0_HEPp = e0->HPp();
|
||||
e1_HEPp = e1->HPp();
|
||||
}else{// does not have pointer to previous, it must be computed
|
||||
ep = e0;
|
||||
do{
|
||||
if(ep->HNp() == e0) e0_HEPp = ep;
|
||||
if(ep->HNp() == e1) e1_HEPp = ep;
|
||||
ep = ep->HNp();
|
||||
}while(ep!=e0);
|
||||
}
|
||||
if(hasP){
|
||||
(*ei0).HPp() = e0->HPp();
|
||||
(*ei1).HPp() = e1->HPp();
|
||||
e0->HPp() = &(*ei1);
|
||||
e1->HPp() = &(*ei0);
|
||||
}
|
||||
e0_HEPp -> HNp() = &(*ei0);
|
||||
e1_HEPp -> HNp() = &(*ei1);
|
||||
HEdgePointer e0_HEPp = 0,e1_HEPp = 0,ep =0;
|
||||
if(hasP){
|
||||
e0_HEPp = e0->HPp();
|
||||
e1_HEPp = e1->HPp();
|
||||
}else{// does not have pointer to previous, it must be computed
|
||||
ep = e0;
|
||||
do{
|
||||
if(ep->HNp() == e0) e0_HEPp = ep;
|
||||
if(ep->HNp() == e1) e1_HEPp = ep;
|
||||
ep = ep->HNp();
|
||||
}while(ep!=e0);
|
||||
}
|
||||
if(hasP){
|
||||
(*ei0).HPp() = e0->HPp();
|
||||
(*ei1).HPp() = e1->HPp();
|
||||
e0->HPp() = &(*ei1);
|
||||
e1->HPp() = &(*ei0);
|
||||
}
|
||||
e0_HEPp -> HNp() = &(*ei0);
|
||||
e1_HEPp -> HNp() = &(*ei1);
|
||||
|
||||
(*ei0).HOp() = &(*ei1);
|
||||
(*ei1).HOp() = &(*ei0);
|
||||
(*ei0).HOp() = &(*ei1);
|
||||
(*ei1).HOp() = &(*ei0);
|
||||
|
||||
|
||||
if( HEdgeType::HasHFAdjacency() && FaceType::HasFHAdjacency()){
|
||||
FaceIterator fi0 = vcg::tri::Allocator<MeshType>::AddFaces(m,1);
|
||||
m.face.back().ImportLocal(*e0->HFp());
|
||||
if( HEdgeType::HasHFAdjacency() && FaceType::HasFHAdjacency()){
|
||||
FaceIterator fi0 = vcg::tri::Allocator<MeshType>::AddFaces(m,1);
|
||||
m.face.back().ImportLocal(*e0->HFp());
|
||||
|
||||
SetRelationsLoopFace(&(*ei0),e1->HFp()); // one loop to the old face
|
||||
SetRelationsLoopFace(&(*ei1),&m.face.back()); // the other to the new face
|
||||
}
|
||||
}
|
||||
SetRelationsLoopFace(&(*ei0),e1->HFp()); // 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
|
||||
/** Detach the topology relations of a given edge
|
||||
<--- e->HENPp -X --- <---------eO_HEPp---
|
||||
^
|
||||
||
|
||||
e || e->HEOp()
|
||||
||
|
||||
v
|
||||
----e_HEPp--> X ----- e->HEOp->HENPp() ------>
|
||||
----e_HEPp--> X ----- e->HEOp->HENPp() ------>
|
||||
|
||||
*/
|
||||
static void RemoveHEdge(MeshType &m, HEdgeType * e){
|
||||
assert(MeshType::HEdgeType::HasHNextAdjacency());
|
||||
assert(MeshType::HEdgeType::HasHOppAdjacency());
|
||||
assert(MeshType::FaceType::HasFHAdjacency());
|
||||
*/
|
||||
static void RemoveHEdge(MeshType &m, HEdgeType * e){
|
||||
assert(MeshType::HEdgeType::HasHNextAdjacency());
|
||||
assert(MeshType::HEdgeType::HasHOppAdjacency());
|
||||
assert(MeshType::FaceType::HasFHAdjacency());
|
||||
|
||||
bool hasP = MeshType::HEdgeType::HasHPrevAdjacency();
|
||||
HEdgePointer e_HEPp,eO_HEPp;
|
||||
bool hasP = MeshType::HEdgeType::HasHPrevAdjacency();
|
||||
HEdgePointer e_HEPp,eO_HEPp;
|
||||
|
||||
if(hasP){
|
||||
e_HEPp = e->HPp();
|
||||
eO_HEPp = e->HOp()->HPp();
|
||||
}else{
|
||||
e_HEPp = PreviousEdge(e);
|
||||
eO_HEPp = PreviousEdge(e->HOp());
|
||||
}
|
||||
if(hasP){
|
||||
e_HEPp = e->HPp();
|
||||
eO_HEPp = e->HOp()->HPp();
|
||||
}else{
|
||||
e_HEPp = PreviousEdge(e);
|
||||
eO_HEPp = PreviousEdge(e->HOp());
|
||||
}
|
||||
|
||||
assert(e_HEPp->HNp() == e);
|
||||
assert(eO_HEPp->HNp() == e->HOp());
|
||||
e_HEPp->HNp() = e->HOp()->HNp();
|
||||
eO_HEPp->HNp() = e-> HNp();
|
||||
assert(e_HEPp->HNp() == e);
|
||||
assert(eO_HEPp->HNp() == e->HOp());
|
||||
e_HEPp->HNp() = e->HOp()->HNp();
|
||||
eO_HEPp->HNp() = e-> HNp();
|
||||
|
||||
if(hasP) {
|
||||
e->HOp()->HNp()->HPp() = e_HEPp;
|
||||
e->HNp()->HPp() = eO_HEPp;
|
||||
if(hasP) {
|
||||
e->HOp()->HNp()->HPp() = e_HEPp;
|
||||
e->HNp()->HPp() = eO_HEPp;
|
||||
|
||||
e->HPp() = NULL;
|
||||
e-> HOp()->HPp() = NULL;
|
||||
}
|
||||
e->HPp() = NULL;
|
||||
e-> HOp()->HPp() = NULL;
|
||||
}
|
||||
|
||||
|
||||
// take care of the faces
|
||||
if(MeshType::HEdgeType::HasHFAdjacency()){
|
||||
MergeFaces(e_HEPp->HFp(),eO_HEPp->HFp());
|
||||
vcg::tri::Allocator<MeshType>::DeleteFace(m,*eO_HEPp->HFp());
|
||||
SetRelationsLoopFace(e_HEPp,e_HEPp->HFp());
|
||||
// take care of the faces
|
||||
if(MeshType::HEdgeType::HasHFAdjacency()){
|
||||
MergeFaces(e_HEPp->HFp(),eO_HEPp->HFp());
|
||||
vcg::tri::Allocator<MeshType>::DeleteFace(m,*eO_HEPp->HFp());
|
||||
SetRelationsLoopFace(e_HEPp,e_HEPp->HFp());
|
||||
|
||||
}
|
||||
vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e->HOp());
|
||||
vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e);
|
||||
}
|
||||
vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e->HOp());
|
||||
vcg::tri::Allocator<MeshType>::DeleteHEdge(m,*e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};// end class
|
||||
template <class MeshType >
|
||||
struct UpdateIndexed{
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::VertexPointer VertexPointer;
|
||||
typedef typename MeshType::HEdgePointer HEdgePointer;
|
||||
typedef typename MeshType::HEdgeType HEdgeType;
|
||||
typedef typename MeshType::HEdgeIterator HEdgeIterator;
|
||||
typedef typename MeshType::FaceIterator FaceIterator;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
};// end class
|
||||
template <class MeshType >
|
||||
struct UpdateIndexed{
|
||||
typedef typename MeshType::VertexType VertexType;
|
||||
typedef typename MeshType::VertexPointer VertexPointer;
|
||||
typedef typename MeshType::HEdgePointer HEdgePointer;
|
||||
typedef typename MeshType::HEdgeType HEdgeType;
|
||||
typedef typename MeshType::HEdgeIterator HEdgeIterator;
|
||||
typedef typename MeshType::FaceIterator FaceIterator;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
|
||||
struct VertexPairEdgePtr{
|
||||
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);}
|
||||
struct VertexPairEdgePtr{
|
||||
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);}
|
||||
|
||||
VertexPointer v0,v1;
|
||||
HEdgePointer ep;
|
||||
};
|
||||
VertexPointer v0,v1;
|
||||
HEdgePointer ep;
|
||||
};
|
||||
|
||||
/**
|
||||
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 FromHalfEdges( MeshType & m ){
|
||||
assert(HasFVAdjacency(m));
|
||||
assert(MeshType::HEdgeType::HasHNextAdjacency());
|
||||
assert(MeshType::HEdgeType::HasHVAdjacency());
|
||||
assert(MeshType::HEdgeType::HasHOppAdjacency());
|
||||
assert(MeshType::FaceType::HasFHAdjacency());
|
||||
bool createFace,hasHEF,hasFHE;
|
||||
/**
|
||||
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 FromHalfEdges( MeshType & m ){
|
||||
assert(HasFVAdjacency(m));
|
||||
assert(MeshType::HEdgeType::HasHNextAdjacency());
|
||||
assert(MeshType::HEdgeType::HasHVAdjacency());
|
||||
assert(MeshType::HEdgeType::HasHOppAdjacency());
|
||||
assert(MeshType::FaceType::HasFHAdjacency());
|
||||
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::FacePointer fp;
|
||||
typename MeshType::FaceIterator fi;
|
||||
typename MeshType::HEdgePointer ep,epF;
|
||||
int vi = 0;
|
||||
vcg::SimpleTempData<typename MeshType::HEdgeContainer,bool> hV(m.hedge);
|
||||
typename MeshType::HEdgeIterator ei;
|
||||
typename MeshType::FacePointer fp;
|
||||
typename MeshType::FaceIterator fi;
|
||||
typename MeshType::HEdgePointer ep,epF;
|
||||
//int vi = 0;
|
||||
vcg::SimpleTempData<typename MeshType::HEdgeContainer,bool> hV(m.hedge);
|
||||
|
||||
hasHEF = (MeshType::HEdgeType::HasHFAdjacency());
|
||||
assert( !hasHEF || (hasHEF && m.fn>0));
|
||||
hasHEF = (MeshType::HEdgeType::HasHFAdjacency());
|
||||
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.hedge.begin(); ei != m.hedge.end(); ++ei)
|
||||
if(!(*ei).IsD()) // it has not been deleted
|
||||
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)
|
||||
if(!hV[(*ei)] ) // it has not be visited yet
|
||||
{
|
||||
if(!hasHEF)// if it has
|
||||
fp = &(* Allocator<MeshType>::AddFaces(m,1));
|
||||
else
|
||||
fp = (*ei).HFp();
|
||||
// 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.hedge.begin(); ei != m.hedge.end(); ++ei)
|
||||
if(!(*ei).IsD()) // it has not been deleted
|
||||
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)
|
||||
if(!hV[(*ei)] ) // it has not be visited yet
|
||||
{
|
||||
if(!hasHEF)// if it has
|
||||
fp = &(* Allocator<MeshType>::AddFaces(m,1));
|
||||
else
|
||||
fp = (*ei).HFp();
|
||||
|
||||
ep = epF = &(*ei);
|
||||
std::vector<VertexPointer> vpts;
|
||||
do{vpts.push_back((*ep).HVp()); ep=ep->HNp();}while(ep!=epF);
|
||||
int idbg =fp->VN();
|
||||
if(fp->VN() != vpts.size()){
|
||||
fp->Dealloc();
|
||||
fp ->Alloc(vpts.size());
|
||||
}
|
||||
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
|
||||
ep = epF = &(*ei);
|
||||
std::vector<VertexPointer> vpts;
|
||||
do{vpts.push_back((*ep).HVp()); ep=ep->HNp();}while(ep!=epF);
|
||||
//int idbg =fp->VN();
|
||||
if(fp->VN() != vpts.size()){
|
||||
fp->Dealloc();
|
||||
fp ->Alloc(vpts.size());
|
||||
}
|
||||
//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
|
||||
|
||||
hV[(*ei)] = true;
|
||||
}
|
||||
//Allocator<MeshType>::DeletePerHEdgeAttribute(m,hV);
|
||||
}
|
||||
hV[(*ei)] = true;
|
||||
}
|
||||
//Allocator<MeshType>::DeletePerHEdgeAttribute(m,hV);
|
||||
}
|
||||
|
||||
};
|
||||
} // end namespace vcg
|
||||
};
|
||||
} // end namespace vcg
|
||||
}
|
||||
#endif // __VCGLIB_EDGE_SUPPORT
|
||||
|
|
Loading…
Reference in New Issue