code refactory:

- half-edge vector instead of vertex vector, so it has pointer to border face

bug-fix: reselection after bridge removing
This commit is contained in:
Paolo Cignoni cignoni 2008-10-28 16:59:15 +00:00
parent 5ab1ca373b
commit 026c3213c8
4 changed files with 249 additions and 232 deletions

View File

@ -8,7 +8,7 @@
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* 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. *
@ -58,8 +58,8 @@ public:
FgtHole<MESH>* h;
};
/* Class rappresenting callback for feedback while auto bridging is running.
* It's necessary because auto bridging can spent a lot of time computing
/* Class rappresenting callback for feedback while auto bridging is running.
* It's necessary because auto bridging can spent a lot of time computing
* and user must know it is working.
*/
class AutoBridgingCallback
@ -76,17 +76,10 @@ template <class MESH>
class FgtBridgeBase
{
public:
typedef typename BridgeAbutment<MESH> AbutmentType;
typedef typename MESH::FaceType FaceType;
typedef typename MESH::FacePointer FacePointer;
typedef typename MESH::FaceIterator FaceIterator;
typedef typename vcg::face::Pos<FaceType> PosType;
typedef typename std::vector<PosType> PosVector;
typedef FgtHole<MESH> HoleType;
typedef typename std::vector<HoleType> HoleVector;
typedef typename MESH::VertexType VertexType;
typedef typename MESH::ScalarType ScalarType;
public:
virtual PosType GetAbutmentA() const =0;
virtual PosType GetAbutmentB() const =0;
@ -97,7 +90,7 @@ public:
virtual inline bool IsNull() const = 0;
virtual inline bool IsDeleted() const = 0;
protected:
HoleSetManager<MESH>* parentManager;
};
@ -105,15 +98,15 @@ protected:
/** Bridge between different FgtHoles or into the same one.
* Bridges rapresent connection between two border edges of different faces.
* Connection consists in 2 face adjcent each other over an edge and adjcent
* Connection consists in 2 face adjcent each other over an edge and adjcent
* with a mesh face over another edge, so both faces have a border edge.
*
*
* Bridge can connect 2 edge belong the same hole, result are 2 new holes.
* In this case bridge could be adjacent to mesh if edge are next, so this
* In this case bridge could be adjacent to mesh if edge are next, so this
* bridge could not been build.
*
* Bridge can also connect 2 or more different holes in only one hole.
*
*
* \ / B \ / \ / B \ /
* +------+-----+------+ +------+-----+------+
* | | | |\ f1 | |
@ -122,7 +115,7 @@ protected:
* | | | | \ | |
* | | | | f0 \| |
* +------+-----+------+ +------+-----+------+
* / \ A / \ / \ A / \
* / \ A / \ / \ A / \
* GOOD BRIDGE
* f0 and f1 are adjacent only with one mesh face
*
@ -148,9 +141,19 @@ protected:
template <class MESH>
class FgtBridge: public FgtBridgeBase<MESH>
{
typedef typename vcg::GridStaticPtr<FaceType, ScalarType > GridType;
typedef BridgeAbutment<MESH> AbutmentType;
typedef typename MESH::FaceType FaceType;
typedef typename MESH::FaceType FaceType;
typedef typename MESH::ScalarType ScalarType;
typedef typename vcg::face::Pos<FaceType> PosType;
typedef FgtHole<MESH> HoleType;
typedef typename std::vector<HoleType> HoleVector;
typedef typename MESH::FacePointer FacePointer;
typedef typename MESH::FaceIterator FaceIterator;
typedef typename vcg::GridStaticPtr<FaceType, ScalarType > GridType;
typedef typename std::vector< FgtBridge<MESH> > BridgeVector;
typedef typename BridgeVector::iterator BridgeIterator;
typedef typename MESH::VertexType VertexType;
public:
enum BridgeOption {NoOne, OptA, OptB};
@ -158,8 +161,8 @@ public:
FgtBridge(HoleSetManager<MESH>* parent)
{
f0=0;
f0=0;
parentManager = parent;
f0=0;
this->parentManager = parent;
};
inline void AddFaceReference(std::vector<FacePointer*> &facesReferences)
@ -168,11 +171,11 @@ public:
facesReferences.push_back(&f1);
};
inline PosType GetAbutmentA() const {
return PosType( f0->FFp(0), f0->FFi(0) );
inline PosType GetAbutmentA() const {
return PosType( f0->FFp(0), f0->FFi(0) );
};
inline PosType GetAbutmentB() const {
return PosType( f1->FFp(0), f1->FFi(0) );
inline PosType GetAbutmentB() const {
return PosType( f1->FFp(0), f1->FFi(0) );
};
inline PosType GetSideA() const{
@ -183,7 +186,7 @@ public:
inline PosType GetSideB() const{
if( opt==OptA ) return PosType(f1, SIDE_EDGE_OPTA);
else return PosType(f1, SIDE_EDGE_OPTB);
};
};
inline bool IsNull() const { return f0==0 && f1==0; };
inline bool IsDeleted() const { return f0->IsD() && f1->IsD(); };
@ -191,41 +194,41 @@ public:
void ResetFlag()
{
assert( !IsNull() );
assert( parentManager->IsBridgeFace( f0 ) );
assert( parentManager->IsBridgeFace( f1 ) );
assert( this->parentManager->IsBridgeFace( f0 ) );
assert( this->parentManager->IsBridgeFace( f1 ) );
parentManager->ClearBridgeAttr( f0 );
parentManager->ClearBridgeAttr( f1 );
this->parentManager->ClearBridgeAttr( f0 );
this->parentManager->ClearBridgeAttr( f1 );
};
void DeleteFromMesh()
{
assert(!IsNull() && !IsDeleted());
if( !f0->IsD() )
vcg::tri::Allocator<MESH>::DeleteFace(*parentManager->mesh, *f0);
vcg::tri::Allocator<MESH>::DeleteFace(*this->parentManager->mesh, *f0);
if( !f1->IsD() )
vcg::tri::Allocator<MESH>::DeleteFace(*parentManager->mesh, *f1);
vcg::tri::Allocator<MESH>::DeleteFace(*this->parentManager->mesh, *f1);
// update mesh topology after bridge faces removal, restore border
for(int e=0; e<3; e++)
{
{
if(!vcg::face::IsBorder<FaceType>(*f0, e))
{
FacePointer adjF = f0->FFp(e);
if(!parentManager->IsBridgeFace(adjF))
{
if(!this->parentManager->IsBridgeFace(adjF))
{
int adjEI = f0->FFi(e);
adjF->FFp( adjEI ) = adjF;
adjF->FFi( adjEI ) = adjEI;
assert(vcg::face::IsBorder<FaceType>(*adjF, adjEI));
}
}
if(!vcg::face::IsBorder<FaceType>(*f1, e))
{
FacePointer adjF = f1->FFp(e);
if(!parentManager->IsBridgeFace(adjF))
{
if(!this->parentManager->IsBridgeFace(adjF))
{
int adjEI = f1->FFi(e);
adjF->FFp( adjEI ) = adjF;
adjF->FFi( adjEI ) = adjEI;
@ -238,7 +241,7 @@ public:
private:
void build(AbutmentType sideA, AbutmentType sideB, BridgeOption o, std::vector<FacePointer *> &app, bool test=false)
{
{
opt = o;
if(test)
if(!testAbutmentDistance(sideA, sideB) && (opt=computeBestBridgeOpt(sideA, sideB)) == NoOne)
@ -247,37 +250,37 @@ private:
opt = NoOne;
return;
}
assert(testAbutmentDistance(sideA, sideB));
assert(opt!=NoOne);
app.push_back(&sideA.f);
app.push_back(&sideB.f);
FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(*parentManager->mesh, 2, app);
parentManager->faceAttr->UpdateSize();
FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(*this->parentManager->mesh, 2, app);
this->parentManager->faceAttr->UpdateSize();
app.pop_back();
app.pop_back();
f0 = &*fit;
f1 = &*(fit+1);
parentManager->SetBridgeAttr(f0);
parentManager->SetBridgeAttr(f1);
parentManager->SetHoleBorderAttr(f0);
parentManager->SetHoleBorderAttr(f1);
this->parentManager->SetBridgeAttr(f0);
this->parentManager->SetBridgeAttr(f1);
this->parentManager->SetHoleBorderAttr(f0);
this->parentManager->SetHoleBorderAttr(f1);
this->parentManager->ClearHoleBorderAttr(sideA.f);
this->parentManager->ClearHoleBorderAttr(sideB.f);
parentManager->ClearHoleBorderAttr(sideA.f);
parentManager->ClearHoleBorderAttr(sideB.f);
// the index of edge adjacent between new 2 face, is the same for both new faces
int adjEdgeIndex = -1;
int adjEdgeIndex = -1;
// the index of edge adjacent between new 2 face, is the same for both new faces
int sideEdgeIndex = -1;
setVertexByOption(sideA, sideB, opt, *f0, *f1);
if( opt == OptA )
{
{
adjEdgeIndex = ADJ_EDGE_OPTA;
sideEdgeIndex = SIDE_EDGE_OPTA;
}
@ -295,7 +298,7 @@ private:
f0->FFi(0) = sideA.z;
f1->FFp(0) = sideB.f;
f1->FFi(0) = sideB.z;
sideA.f->FFp(sideA.z) = f0;
sideA.f->FFi(sideA.z) = 0;
sideB.f->FFp(sideB.z) = f1;
@ -313,8 +316,8 @@ private:
f1->FFp(sideEdgeIndex) = f1;
f1->FFi(sideEdgeIndex) = sideEdgeIndex;
assert( parentManager->IsBridgeFace( f0 ) );
assert( parentManager->IsBridgeFace( f1 ) );
assert( this->parentManager->IsBridgeFace( f0 ) );
assert( this->parentManager->IsBridgeFace( f1 ) );
};
/*** funzioni statiche ***/
@ -322,13 +325,13 @@ private:
public:
/* Build a bridge between 2 border edge.
* If the bridge is inside the same hole it cannot be adjacent the hole border,
* If the bridge is inside the same hole it cannot be adjacent the hole border,
* this means fill another sub hole.
*/
static bool CreateBridge(AbutmentType &sideA, AbutmentType &sideB,
static bool CreateBridge(AbutmentType &sideA, AbutmentType &sideB,
HoleSetManager<MESH>* holesManager, QString &err, std::vector<FacePointer *> *app=0)
{
assert( vcg::face::IsBorder<FaceType>(*sideA.f, sideA.z) &&
assert( vcg::face::IsBorder<FaceType>(*sideA.f, sideA.z) &&
vcg::face::IsBorder<FaceType>(*sideB.f, sideB.z));
assert(!sideA.h->IsFilled() && !sideB.h->IsFilled());
@ -361,7 +364,7 @@ public:
};
/* Build a bridge inner to the same hole. It chooses the best bridge computing quality
/* Build a bridge inner to the same hole. It chooses the best bridge computing quality
* of 2 faces and similarity (as number of edge) of two next hole. Bridge is build follow
* bridge's rule, bridge must have 2 border edge.
* infoLabel paramter is used to show work progress.
@ -378,7 +381,7 @@ public:
}
GridType gM;
gM.Set(holesManager->mesh->face.begin(),holesManager->mesh->face.end());
std::vector<FacePointer *> tmpFaceRef;
HoleType* oldRef = 0;
AbutmentType sideA, sideB;
@ -393,16 +396,16 @@ public:
assert(!thehole.IsFilled());
ScalarType maxQuality = -1;
// initP: first bridge abutment
PosType initP = thehole.p;
PosType initP = thehole.p;
for(int i=0; i<thehole.Size();i++)
{
// initP: second bridge abutment
PosType endP = initP;
endP.NextB();endP.NextB();
for(int j=3; j<=thehole.Size()/2; j++)
{
{
endP.NextB();
// two edge used as bridge abutment are adjacent to the same face... bridge can't be build
@ -417,7 +420,7 @@ public:
AbutmentType b(endP.f, endP.z, &thehole);
if(!testAbutmentDistance(a,b))
continue;
ScalarType q;
BridgeOption opt = computeBestBridgeOpt(a, b, &q, &gM);
if(opt != NoOne)
@ -429,9 +432,9 @@ public:
bestOpt = opt;
sideA.f=initP.f; sideA.z=initP.z; sideA.h=&thehole;
sideB.f=endP.f; sideB.z=endP.z; sideB.h=&thehole;
}
}
}
if(holesManager->autoBridgeCB != 0)
{
if(clock()- timer > holesManager->autoBridgeCB->GetOffset())
@ -442,7 +445,7 @@ public:
}
}
}// scansione del edge di arrivo
initP.NextB();
}// scansione dell'edge di partenza
@ -451,21 +454,21 @@ public:
if( oldRef != &*holesManager->holes.begin() )
{
// si può
// si può
tmpFaceRef.clear();
if(app!=0)
tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
holesManager->AddFaceReference(tmpFaceRef);
tmpFaceRef.push_back(&sideA.f);
tmpFaceRef.push_back(&sideB.f);
oldRef = &*holesManager->holes.begin();
oldRef = &*holesManager->holes.begin();
}
if( maxQuality > -1)
{
subdivideHoleWithBridge(sideA, sideB, bestOpt, holesManager, tmpFaceRef);
gM.Set(holesManager->mesh->face.begin(), holesManager->mesh->face.end());
// la subdivideHole.. aggiunge un hole pertanto bisogna aggiornare anche la lista di
// la subdivideHole.. aggiunge un hole pertanto bisogna aggiornare anche la lista di
// reference a facce
tmpFaceRef.push_back(&holesManager->holes.back().p.f);
}
@ -477,7 +480,7 @@ public:
};
/* It connects iteratively selected holes with the best bridge.
/* It connects iteratively selected holes with the best bridge.
* Result is unique hole instead of init holes.
* Return number of bridges builded.
*/
@ -491,32 +494,32 @@ public:
}
GridType gM;
std::vector<FacePointer *> tmpFaceRef;
AbutmentType sideA, sideB;
BridgeOption bestOpt;
std::vector<HoleType*> selectedHoles;
typename std::vector<HoleType*>::iterator shit1, shit2;
typename std::vector<HoleType*>::iterator shit1, shit2;
typename HoleVector::iterator hit;
int nIteration = -1;
int iteration = 0;
// iterate, unify holes, until selected hole is only one
do{
sideA.SetNull();
sideB.SetNull();
// prendo gli hole selezionati
selectedHoles.clear();
for(hit=holesManager->holes.begin(); hit!=holesManager->holes.end(); hit++)
if(hit->IsSelected())
selectedHoles.push_back(&*hit);
if(selectedHoles.size() < 2)
return;
gM.Set(holesManager->mesh->face.begin(),holesManager->mesh->face.end());
float casesViewed = 0, cases2View = 0;
for(shit1=selectedHoles.begin(); shit1!=selectedHoles.end(); shit1++)
for(shit2=shit1+1; shit2!=selectedHoles.end(); shit2++)
@ -526,11 +529,11 @@ public:
nIteration = selectedHoles.size()-1;
// cerco la miglior combinazione tra le facce di un hole con quelle di un'altro
ScalarType maxQuality = -1;
ScalarType maxQuality = -1;
for(shit1=selectedHoles.begin(); shit1!=selectedHoles.end(); shit1++)
{
{
for(shit2=shit1+1; shit2!=selectedHoles.end(); shit2++)
{
{
PosType ph1((*shit1)->p.f, (*shit1)->p.z);
PosType ph2((*shit2)->p.f, (*shit2)->p.z);
do{ //scansione edge di bordo del primo buco
@ -560,16 +563,16 @@ public:
casesViewed++;
ph2.NextB();
}while(ph2 != (*shit2)->p);
}while(ph2 != (*shit2)->p);
ph1.NextB();
}while(ph1 != (*shit1)->p);
} // for(shit2=shit1+1; shit2!=selectedHoles.end(); shit2++)
}while(ph1 != (*shit1)->p);
} // for(shit2=shit1+1; shit2!=selectedHoles.end(); shit2++)
}
// adesso ho la miglior coppia di edge si deve creare il bridge
assert(!sideA.IsNull() && !sideB.IsNull());
// la rimozione di hole dovuta alla unifyHoles.. provoca l'aggiornamento della lista di holes
// pertanto si deve avere sempre aggiornata la lista dei riferimenti alle facce
// la quale dipende anche dagli holes
@ -579,10 +582,10 @@ public:
holesManager->AddFaceReference(tmpFaceRef);
tmpFaceRef.push_back(&sideA.f);
tmpFaceRef.push_back(&sideB.f);
if(maxQuality > -1)
unifyHolesWithBridge(sideA, sideB, bestOpt, holesManager, tmpFaceRef);
else
else
return;
iteration ++;
}while(true);
@ -591,7 +594,7 @@ public:
private:
/* Compute distance between bridge side to allow no bridge adjacent to hole border.
/* Compute distance between bridge side to allow no bridge adjacent to hole border.
* A bridge must have 2 border faces.
*/
static bool testAbutmentDistance(const AbutmentType &sideA, const AbutmentType &sideB)
@ -600,7 +603,7 @@ private:
// at least 2 edges have to be between 2 bridge side.
if(!sideA.h->IsNonManifold())
{
{
// so adjacent edges of a side haven't to share a vertex with other side.
PosType pos(sideA.f, sideA.z);
assert(pos.IsBorder());
@ -619,12 +622,12 @@ private:
// if exist a face which share a vertex with each side then the bridge cannot be built
PosType initPos(sideA.f, sideA.z);
PosType curPos=initPos;
VertexType* va0=sideA.f->V0(sideA.z);
VertexType* va1=sideA.f->V1(sideA.z);
VertexType* vb0=sideB.f->V0(sideB.z);
VertexType* vb1=sideB.f->V1(sideB.z);
do{
VertexType* cv0=curPos.f->V0(curPos.z);
VertexType* cv1=curPos.f->V1(curPos.z);
@ -633,14 +636,14 @@ private:
if( cv0 == vb0 || cv1 == vb0 ||
cv0 == vb1 || cv1 == vb1 )
return false;
curPos.NextB();
}while( curPos != initPos );
}while( curPos != initPos );
}
return true;
};
static void subdivideHoleWithBridge(AbutmentType &sideA, AbutmentType &sideB,
static void subdivideHoleWithBridge(AbutmentType &sideA, AbutmentType &sideB,
BridgeOption bo, HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> &app)
{
assert(sideA.h==sideB.h);
@ -658,7 +661,7 @@ private:
holesManager->holes.push_back( newHole );
};
static void unifyHolesWithBridge(AbutmentType &sideA, AbutmentType &sideB,
static void unifyHolesWithBridge(AbutmentType &sideA, AbutmentType &sideB,
BridgeOption bo, HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> &app)
{
assert(vcg::face::IsBorder<FaceType>(*sideA.f, sideA.z));
@ -688,12 +691,12 @@ private:
static void setVertexByOption(AbutmentType &sideA, AbutmentType &sideB, BridgeOption o,
FaceType &bf0, FaceType &bf1)
{
VertexType* vA0 = sideA.f->V0( sideA.z ); // first vertex of pos' 1-edge
VertexType* vA0 = sideA.f->V0( sideA.z ); // first vertex of pos' 1-edge
VertexType* vA1 = sideA.f->V1( sideA.z ); // second vertex of pos' 1-edge
VertexType* vB0 = sideB.f->V0( sideB.z ); // first vertex of pos' 2-edge
VertexType* vB1 = sideB.f->V1( sideB.z ); // second vertex of pos' 2-edge
VertexType* vB0 = sideB.f->V0( sideB.z ); // first vertex of pos' 2-edge
VertexType* vB1 = sideB.f->V1( sideB.z ); // second vertex of pos' 2-edge
// Quality
// Quality
if(o==OptA)
{
bf0.V(0) = vA1; bf0.V(1) = vA0; bf0.V(2) = vB0;
@ -706,10 +709,10 @@ private:
}
}
/* Find how triangolate two bridge faces.
/* Find how triangolate two bridge faces.
* If return "NoOne" means bridge is compenetrating with mesh for both option
*/
static BridgeOption computeBestBridgeOpt(AbutmentType sideA,
static BridgeOption computeBestBridgeOpt(AbutmentType sideA,
AbutmentType sideB, ScalarType* quality=0, GridType* gM=0)
{
HoleSetManager<MESH>* hm = sideA.h->parentManager;
@ -720,7 +723,7 @@ private:
gM->Set(hm->mesh->face.begin(),hm->mesh->face.end());
delgm = true;
}
FaceType bf0, bf1;
ScalarType qA = -1;
// Caso A
@ -728,7 +731,7 @@ private:
if( !HoleType::TestFaceMeshCompenetration(*hm->mesh, *gM, &bf0) &&
!HoleType::TestFaceMeshCompenetration(*hm->mesh, *gM, &bf1) )
qA = QualityFace(bf0)+ QualityFace(bf1);
// Caso B
ScalarType qB = -1;
setVertexByOption(sideA, sideB, OptB, bf0, bf1);
@ -752,14 +755,14 @@ private:
return NoOne; // both autocompenetrant with mesh
else if(qA>qB)
return OptA;
else
else
return OptB;
};
private:
BridgeOption opt;
public:
FacePointer f0;
FacePointer f1;
@ -768,23 +771,41 @@ public:
/* "Bridge" (face) added to close non manifold holes
*
*
* -----+------+------ ----+------+--------
* \ A / \ A /|
* \ / \ / |
* holeX \/ holeX holeX \/ | holeY
* /\ /\f0|
* / \ / \ |
* / B \ / B \|
* -----+------+------ ----+------+--------
* HoleX is Non-Manifold HoleX and HoleY aren't
* Non-Manifold
*/
template <class MESH>
class FgtNMBridge: public FgtBridgeBase<MESH>
{
typedef typename MESH::FaceType FaceType;
typedef typename MESH::FacePointer FacePointer;
typedef typename vcg::face::Pos<FaceType> PosType;
typedef FgtHole<MESH> HoleType;
typedef typename MESH::FaceIterator FaceIterator;
public:
FgtNMBridge(FacePointer f, HoleSetManager<MESH>* parent)
{
f0 = f;
parentManager = parent;
this->parentManager = parent;
};
inline PosType GetAbutmentA() const {
return PosType( f0->FFp(0), f0->FFi(0));
inline PosType GetAbutmentA() const {
return PosType( f0->FFp(0), f0->FFi(0));
};
inline PosType GetAbutmentB() const {
return PosType( f0->FFp(2), f0->FFi(2));
inline PosType GetAbutmentB() const {
return PosType( f0->FFp(2), f0->FFi(2));
};
inline bool IsNull() const { return f0==0; };
@ -799,25 +820,25 @@ public:
void ResetFlag()
{
assert( !IsNull() );
assert(parentManager->IsBridgeFace(f0) );
parentManager->ClearBridgeAttr(f0);
assert(this->parentManager->IsBridgeFace(f0) );
this->parentManager->ClearBridgeAttr(f0);
};
void DeleteFromMesh()
{
assert( !IsNull() );
assert( parentManager->IsBridgeFace(f0) );
assert( this->parentManager->IsBridgeFace(f0) );
if( !f0->IsD() )
vcg::tri::Allocator<MESH>::DeleteFace(*parentManager->mesh, *f0);
vcg::tri::Allocator<MESH>::DeleteFace(*this->parentManager->mesh, *f0);
// update mesh topology after bridge faces removal, restore border
for(int e=0; e<3; e++)
{
{
if(!vcg::face::IsBorder<FaceType>(*f0, e))
{
FacePointer adjF = f0->FFp(e);
if(!parentManager->IsBridgeFace(adjF))
{
if(!this->parentManager->IsBridgeFace(adjF))
{
int adjEI = f0->FFi(e);
adjF->FFp( adjEI ) = adjF;
adjF->FFi( adjEI ) = adjEI;
@ -833,16 +854,16 @@ public:
static void CloseNonManifoldVertex(HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> *app=0)
{
int startNholes = holesManager->holes.size();
std::vector<FacePointer *> tmpFaceRef;
HoleType* oldRef = 0;
HoleType* oldRef = 0;
for(int i=0; i<startNholes; i++)
{
HoleType *h = &holesManager->holes.at(i);
if(!(h->IsNonManifold() && h->IsSelected()))
continue;
// walk the border, mark as visit each vertex. If walk twice over the same vertex go back over the border
// to find other edge sharing this vertex
PosType curPos = h->p;
@ -854,7 +875,7 @@ public:
do{
assert(p0.IsNull());
if(curPos.v->IsV())
p0.Set(curPos.f, curPos.z, curPos.v);
p0.Set(curPos.f, curPos.z, curPos.v);
else
curPos.v->SetV();
curPos.NextB();
@ -894,7 +915,7 @@ public:
// p2 is half-edge adjcent to connect to patch edge which usually is border
PosType p2 = p0;
p2.FlipV();
p2.NextB();
p2.NextB();
// face is build to have as vertex 0 the non-manifold vertex, so it have adge 1 as border edge
fit->V(0) = p0.v;
@ -911,13 +932,13 @@ public:
p0.f->FFp(p0.z) = &*fit;
p0.f->FFi(p0.z) = 2;
p1.f->FFp(p1.z) = &*fit;
p1.f->FFi(p1.z) = 0;
p1.f->FFi(p1.z) = 0;
}
else
{
fit->V(1) = p0.f->V(p0.z);
fit->V(2) = p1.f->V1(p1.z);
fit->FFp(0) = p0.f;
fit->FFi(0) = p0.z;
fit->FFp(2) = p1.f;
@ -935,13 +956,13 @@ public:
if(dist==2)
{
// face used to close non-manifold holes, close entirely a "sub-hole" (sub-hole has
// face used to close non-manifold holes, close entirely a "sub-hole" (sub-hole has
// only 3 border edge). This face become a patch face wich fill an invisible subhole.
holesManager->SetPatchAttr(&*fit);
fit->FFp(1) = p2.f;
fit->FFi(1) = p2.z;
p2.f->FFp(p2.z) = &*fit;
p2.f->FFi(p2.z) = 1;
p2.f->FFi(p2.z) = 1;
}
else
{
@ -952,9 +973,9 @@ public:
if(h->IsSelected())
newhole.SetSelect(true);
newhole.SetBridged(true);
holesManager->holes.push_back(newhole);
holesManager->holes.push_back(newhole);
tmpFaceRef.push_back(&holesManager->holes.back().p.f);
// adding hole can reallocate hole vector so h must be updated
if( oldRef != &*holesManager->holes.begin() )
h = &holesManager->holes.at(i);
@ -973,7 +994,7 @@ public:
//forzo l'aggiornamento delle info dell'hole
h->SetStartPos(h->p);
h->SetBridged(true);
}// for(int i=0; i<startNholes...
}// for(int i=0; i<startNholes...
};
public:

View File

@ -90,6 +90,7 @@ public:
typedef typename MESH::VertexType VertexType;
typedef typename MESH::ScalarType ScalarType;
typedef typename vcg::face::Pos<FaceType> PosType;
typedef typename std::vector< PosType > PosVector;
typedef typename vcg::tri::Hole<MESH> vcgHole;
typedef typename vcgHole::Info HoleInfo;
typedef typename std::vector< FgtHole<MESH> > HoleVector;
@ -168,10 +169,10 @@ public:
void Draw() const
{
typename std::vector<VertexType*>::const_iterator it = vertexes.begin();
typename PosVector::const_iterator it = borderPos.begin();
glBegin(GL_LINE_LOOP);
for( ; it != vertexes.end(); it++)
glVertex( (*it)->P() );
for( ; it != borderPos.end(); it++)
glVertex( it->v->P() );
glEnd();
};
@ -297,9 +298,9 @@ public:
}
// hole filling leaves V flag to border vertex... resetting!
typename std::vector<VertexType*>::const_iterator it = vertexes.begin();
for( ;it!=vertexes.end(); it++)
(*it)->ClearV();
typename PosVector::const_iterator it = borderPos.begin();
for( ;it!=borderPos.end(); it++)
it->v->ClearV();
parentManager->faceAttr->UpdateSize();
@ -314,14 +315,10 @@ public:
bool HaveBorderFace(FacePointer bFace) const
{
assert(parentManager->IsHoleBorderFace(bFace));
assert( !IsFilled() );
PosType curPos = this->p;
do{
if(curPos.f == bFace)
typename PosVector::const_iterator it;
for(it=borderPos.begin(); it!= borderPos.end(); it++)
if( bFace == it->f )
return true;
curPos.NextB();
}while( curPos != this->p );
return false;
}
@ -329,12 +326,13 @@ public:
bool HavePatchFace(FacePointer pFace) const
{
assert( parentManager->IsPatchFace(pFace) );
assert( IsFilled() );
if( !IsFilled() )
return false;
// follow algorithm used to fill with EAR, each faces added share at least e vertex with hole
typename std::vector<VertexType*>::const_iterator it;
for(it = vertexes.begin(); it!=vertexes.end(); it++)
if(pFace->V(0) == *it || pFace->V(1) == *it || pFace->V(2) == *it)
typename std::vector<FacePointer>::const_iterator it;
for(it = patches.begin(); it!=patches.end(); it++)
if(pFace == *it)
return true;
return false;
};
@ -361,6 +359,18 @@ public:
SetBridged(false);
};
// concats its face reference to a vector
void AddFaceReference(std::vector<FacePointer*> &facesReferences)
{
facesReferences.push_back(&this->p.f);
typename PosVector::iterator pit;
for(pit=borderPos.begin(); pit != borderPos.end(); pit++)
facesReferences.push_back( &pit->f );
typename std::vector<FacePointer>::iterator fit;
for(fit=patches.begin(); fit!=patches.end(); fit++)
facesReferences.push_back(&(*fit));
};
private:
@ -368,7 +378,7 @@ private:
void updateInfo()
{
assert(!IsFilled());
vertexes.clear();
borderPos.clear();
_state &= (~NONMANIF);
this->bb.SetNull();
this->size = 0;
@ -376,15 +386,14 @@ private:
PosType curPos = this->p;
do{
assert(!curPos.f->IsD());
borderPos.push_back(curPos);
parentManager->SetHoleBorderAttr(curPos.f);
this->bb.Add(curPos.v->cP());
++this->size;
vertexes.push_back(curPos.v);
if(curPos.v->IsV())
_state |= NONMANIF;
else
curPos.v->SetV();
curPos.NextB();
assert(curPos.IsBorder());
}while( curPos != this->p );
@ -405,7 +414,7 @@ private:
_state &= (~NONMANIF);
PosType curPos = this->p;
do{
vertexes.push_back(curPos.v);
borderPos.push_back(curPos);
if(curPos.v->IsV())
_state |= NONMANIF;
else
@ -522,7 +531,7 @@ private:
int _state;
ScalarType perimeter;
std::vector<VertexType*> vertexes;
std::vector<PosType> borderPos;
};

View File

@ -31,8 +31,9 @@
#include "fgtBridge.h"
#include "holeSetManager.h"
/* This class is the "model" of model-view architecture, so it implements methods to esposes data
/* This class is the "model" of model-view architecture, so it implements methods to exposes data
* informations about holes as QAbstractItemModel says.
* It contains an istance of HoleSetManager to know and manipulate holes and bridges.
*/
class HoleListModel : public QAbstractItemModel
{
@ -101,11 +102,9 @@ private:
public:
HoleSetManager<CMeshO> holesManager;
Q_SIGNALS:
void SGN_needUpdateGLA();
void SGN_ExistBridge(bool exist);
};

View File

@ -30,8 +30,8 @@
#include <vcg/container/simple_temporary_data.h>
/* HoleSetManager class rappresent an entity which manages the holes founded
* into the same MESH.
/* HoleSetManager class rappresent an entity which manages the holes and bridges
* founded into the same MESH.
* It allows to invoke some functionality for each (may be the selected ones)
* holes as filling and bridging.
* His presence is necessary because it connect holes to a mesh with the
@ -131,25 +131,26 @@ public:
return true;
};
/* For accepted holes:
/* For accepted holes: patch faces and its adjacent bridge faces become
* faces of this mesh.
* - reset additional data for its faces
* - remove hole from list
* - accept bridge adjacent to hole
*
* For not accepted holes:
* For not accepted holes: patch faces are removed from mesh
* - remove hole patch and restore border
*/
void ConfirmFilling(bool accept)
{
std::vector<FacePointer> bridgeF;
std::vector<FacePointer>::iterator fpit;
typename std::vector<FacePointer > bridgeF;
typename std::vector<FacePointer >::iterator fpit;
HoleIterator it = holes.begin();
while( it != holes.end() )
{
if( it->IsFilled() )
{
if( ( it->IsSelected() && !it->IsAccepted() ) || !accept)
{
if( it->IsFilled() )
@ -162,7 +163,7 @@ public:
for(fpit = it->patches.begin(); fpit != it->patches.end(); fpit++)
{
if( IsBridgeFace( *fpit ) )
bridgeF.push_back( *fpit );
bridgeF.push_back( *fpit );
for(int i=0; i<3; i++)
{
@ -170,7 +171,7 @@ public:
bridgeF.push_back( (*fpit)->FFp(i) );
}
}
}
}
it->ResetFlag();
it = holes.erase(it);
continue;
@ -199,7 +200,7 @@ public:
}
// update bridging status for holes remaining.
// some hole marked as "bridged" can be adjacent to bridge which is accepted
// some hole marked as "bridged" can be adjacent to bridge which is accepted
// because it is adjacent to hole filled and accepted, so they arent "bridged" now.
for( it= holes.begin(); it != holes.end(); it++)
{
@ -207,25 +208,30 @@ public:
if( it->IsBridged() )
it->UpdateBridgingStatus();
}
countSelected();
};
/* Bridges became face of this mesh
*/
inline void ConfirmBridges()
{
{
BridgeIterator bit = bridges.begin();
for( ; bit != bridges.end(); bit++ )
{
{
(*bit)->ResetFlag();
delete *bit;
}
bridges.clear();
HoleVector::iterator hit = holes.begin();
typename HoleVector::iterator hit = holes.begin();
for( ; hit!=holes.end(); hit++ )
hit->SetBridged(false);
hit->SetBridged(false);
};
/* Bridges are removed from bridges vector and mesh is restored,
* bridge faces are removed from mesh.
*/
inline void DiscardBridges()
{
removeBridges();
@ -252,56 +258,40 @@ public:
/** Return index of hole adjacent to picked face into holes vector.
* Also return the iterator on correct position in holes list.
*/
int FindHoleFromFace(FacePointer bFace, HoleIterator &it)
int FindHoleFromFace(FacePointer pFace, HoleIterator &it)
{
int index = 0;
HoleIterator hit = holes.begin();
// it know if bFace is adjacent to patchFace
FacePointer patchF = 0;
if(IsPatchFace(bFace))
patchF = bFace;
else
if(IsPatchFace(pFace))
{
for( int i=0; i<3; i++)
if(IsPatchFace(bFace->FFp(i)) && !IsBridgeFace(bFace->FFp(i)))
patchF = bFace->FFp(i);
}
HoleIterator hit = holes.begin();
if(patchF == 0)
{
if(IsHoleBorderFace(bFace))
{
// border face belong to an hole not filled... it can walk on border
for( ; hit != holes.end(); ++hit)
{
if(!hit->IsFilled())
if(hit->HaveBorderFace(bFace))
{
it = hit;
return index;
}
index++;
}
}
}
else
{
// bFace belong filled hole, adjF is its patch
assert(IsPatchFace(patchF));
HoleIterator hit = holes.begin();
for( ; hit != holes.end(); ++hit)
{
// for each hole check if face is its border face
if(hit->IsFilled())
if(hit->HavePatchFace(patchF))
{
it = hit;
return index;
}
if(hit->HavePatchFace(pFace))
{
it = hit;
return index;
}
index++;
}
}
else if(IsHoleBorderFace(pFace))
{
for( ; hit != holes.end(); ++hit)
{
// for each hole check if face is its border face
if(hit->HaveBorderFace(pFace))
{
it = hit;
return index;
}
index++;
}
}
it = holes.end(); // invalid iterator
return -1;
};
@ -344,23 +334,18 @@ public:
};
/* Starting from holes stored into a vector this function extract all reference to mesh faces
* and adds them to vector facesReferences
/* Appends all its face reference to a vector, all face reference of its hole type
* and its bridge.
*/
void AddFaceReference(std::vector<FacePointer*> &facesReferences)
{
typename HoleVector::iterator it = holes.begin();
for( ; it!=holes.end(); it++)
{
facesReferences.push_back(&it->p.f);
typename std::vector<FacePointer>::iterator fit;
for(fit=it->patches.begin(); fit!=it->patches.end(); fit++)
facesReferences.push_back(&(*fit));
}
typename HoleVector::iterator hit = holes.begin();
for( ; hit!=holes.end(); hit++)
hit->AddFaceReference(facesReferences);
BridgeIterator bit = bridges.begin();
for( ; bit != bridges.end(); bit++ )
(*bit)->AddFaceReference(facesReferences);
(*bit)->AddFaceReference(facesReferences);
}
@ -434,9 +419,11 @@ private:
return PosType(face, nearest, face->V(nearest) );
};
/* Remove all face marked as bridge. */
/* Remove all bridges updating holes vector and its selection
*/
void removeBridges()
{
assert( holes.size()>0 );
// contains all half-edge located over non-bridge face and over edge shared with bridge face.
// these half-edges will become border edge when bridge faces are removed.
PosVector adjBorderPos;
@ -448,7 +435,7 @@ private:
adjBorderPos.push_back( (*bit)->GetAbutmentA() );
adjBorderPos.push_back( (*bit)->GetAbutmentB() );
}
// remove holes adjacent to bridge
HoleIterator hit = holes.begin();
while(hit != holes.end() )
@ -457,11 +444,12 @@ private:
{
if( hit->IsSelected() )
{
PosType p = hit->p;
// get adjacent border edge because start position in bridged holes
// is bridge face so it'll be removed
p.NextB();
p.f->SetS();
PosType curPos = hit->p;
do
{
curPos.f->SetS();
curPos.NextB();
}while( curPos != hit->p );
}
hit = holes.erase(hit);
}
@ -475,7 +463,7 @@ private:
delete *bit;
}
bridges.clear();
// update hole list inserting holes touched by bridge
// use adjBorderPos element as start pos to walk over the border, if walking doesn't
// visit some adjBorderPos element means this belongo to other hole.
@ -483,7 +471,7 @@ private:
typename PosVector::iterator it;
for( it=adjBorderPos.begin(); it!=adjBorderPos.end(); it++)
{
// bridge abutment can be placed over face of another bridge...
// bridge abutment can be placed over face of another bridge...
// this abutments must be ignored
if(it->f->IsD())
continue;
@ -494,7 +482,7 @@ private:
if(it->f->IsV() || it->f->IsD())
continue;
curPos = initPos = *it;
do{
curPos.f->SetV();
@ -503,7 +491,7 @@ private:
curPos.NextB();
assert(curPos.IsBorder());
}while(curPos != initPos);
FgtHole<MESH> newHole(initPos, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), this);
newHole.SetSelect(sel);
holes.push_back( newHole );
@ -520,10 +508,10 @@ private:
curPos.NextB();
assert(curPos.IsBorder());
}while(curPos != initPos);
}
}
};
// update statistical info
void countSelected()
{
nSelected = 0;