You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
656 lines
28 KiB
656 lines
28 KiB
/**************************************************************************** |
|
* VCGLib o o * |
|
* Visual and Computer Graphics Library o o * |
|
* _ O _ * |
|
* Copyright(C) 2004-2016 \/)\/ * |
|
* 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_HALFEDGE_ |
|
#define __VCGLIB_HALFEDGE_ |
|
|
|
#include <vcg/complex/algorithms/clean.h> |
|
#include <vcg/complex/algorithms/update/topology.h> |
|
#include <vcg/complex/algorithms/update/halfedge_topology.h> |
|
|
|
namespace vcg |
|
{ |
|
namespace tri{ |
|
/// \ingroup trimesh |
|
/// \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::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);} |
|
bool operator <(const VertexPairEdgePtr &o) const {return (v0 == o.v0)? (v1<o.v1):(v0<o.v0);} |
|
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; |
|
}; |
|
|
|
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)); |
|
|
|
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; |
|
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; |
|
} |
|
|
|
m.hedge.clear(); |
|
m.hn = 0; |
|
|
|
// allocate the half edges |
|
typename MeshType::HEdgeIterator ei = vcg::tri::Allocator<MeshType>::AddHEdges(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); |
|
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))) |
|
borderEdges.push_back(FacePtrInt(&(*fi),i)); |
|
} |
|
firstEdge += (*fi).VN(); |
|
} |
|
|
|
// 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 |
|
{ |
|
|
|
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); |
|
|
|
|
|
// 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 ); |
|
|
|
std::sort(all.begin(),all.end()); |
|
assert(all.size() == n_edges); |
|
|
|
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; |
|
} |
|
|
|
if(HasEHAdjacency(m) && HasHEAdjacency(m)) |
|
{ |
|
assert(m.edge.size() == 0 || m.edge.size() == n_edges/2); |
|
|
|
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); |
|
|
|
for(ei = m.hedge.begin(); ei != m.hedge.end(); ++ei) |
|
{ |
|
if((*ei).HEp() == NULL) |
|
{ |
|
(*ei).HEp() = &(*edge_i); |
|
(*ei).HOp()->HEp() = &(*edge_i); |
|
|
|
(*edge_i).EHp() = &(*ei); |
|
|
|
++edge_i; |
|
} |
|
} |
|
|
|
} |
|
else |
|
{ |
|
|
|
if(HasEVAdjacency(m) && HasHEAdjacency(m) && HasEHAdjacency(m)) |
|
{ |
|
//update edge relations |
|
|
|
for(typename MeshType::EdgeIterator ei1 = m.edge.begin(); ei1 != m.edge.end(); ++ei1 ) |
|
{ |
|
std::vector<HEdgePointer> hedges = HalfEdgeTopology<MeshType>::get_incident_hedges((*ei1).V(0)); |
|
|
|
for(typename std::vector<HEdgePointer>::iterator hi = hedges.begin(); hi != hedges.end(); ++hi) |
|
{ |
|
if((*hi)->HOp()->HVp() == (*ei1).V(1)) |
|
{ |
|
|
|
assert((*hi)->HEp() == NULL); |
|
assert((*hi)->HOp()->HEp() == NULL); |
|
|
|
// EH |
|
(*ei1).EHp() = *hi; |
|
|
|
// HE |
|
(*hi)->HEp() = &(*ei1); |
|
(*hi)->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::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) && (m.en!=0)) |
|
{ |
|
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(hasHP) |
|
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) && HasHEAdjacency(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){ |
|
assert(e1!=e0->HNp()); |
|
assert(e0!=e1->HNp()); |
|
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); |
|
|
|
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); |
|
|
|
(*ei0).HOp() = &(*ei1); |
|
(*ei1).HOp() = &(*ei0); |
|
|
|
|
|
if( HEdgeType::HasHFAdjacency() && FaceType::HasFHAdjacency()){ |
|
vcg::tri::Allocator<MeshType>::AddFaces(m,1); |
|
m.face.back().ImportData(*e0->HFp()); |
|
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 |
|
<--- e->HENPp -X --- <---------eO_HEPp--- |
|
^ |
|
|| |
|
e || e->HEOp() |
|
|| |
|
v |
|
----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()); |
|
|
|
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()); |
|
} |
|
|
|
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; |
|
|
|
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()); |
|
|
|
} |
|
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; |
|
|
|
struct VertexPairEdgePtr{ |
|
VertexPairEdgePtr(VertexPointer _v0,VertexPointer _v1,HEdgePointer _ep):v0(_v0),v1(_v1),ep(_ep){if(v0>v1) std::swap(v0,v1);} |
|
bool operator <(const VertexPairEdgePtr &o) const {return (v0 == o.v0)? (v1<o.v1):(v0<o.v0);} |
|
bool operator ==(const VertexPairEdgePtr &o) const {return (v0 == o.v0)&& (v1==o.v1);} |
|
|
|
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 hasHEF; |
|
//bool createFace,hasHEF,hasFHE; |
|
|
|
// 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); |
|
|
|
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(); |
|
|
|
ep = epF = &(*ei); |
|
std::vector<VertexPointer> vpts; |
|
do{vpts.push_back((*ep).HVp()); ep=ep->HNp();}while(ep!=epF); |
|
//int idbg =fp->VN(); |
|
if(size_t(fp->VN()) != vpts.size()){ |
|
fp->Dealloc(); |
|
fp ->Alloc(vpts.size()); |
|
} |
|
//int idbg1 =fp->VN(); |
|
for(size_t 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); |
|
} |
|
|
|
}; |
|
} // end namespace vcg |
|
} |
|
#endif // __VCGLIB_EDGE_SUPPORT
|
|
|