diff --git a/src/fgt/edit_hole/fgtBridge.h b/src/fgt/edit_hole/fgtBridge.h index 3b5e73785..f18419072 100644 --- a/src/fgt/edit_hole/fgtBridge.h +++ b/src/fgt/edit_hole/fgtBridge.h @@ -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* 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 FgtBridgeBase { public: - typedef typename BridgeAbutment AbutmentType; typedef typename MESH::FaceType FaceType; typedef typename MESH::FacePointer FacePointer; - typedef typename MESH::FaceIterator FaceIterator; typedef typename vcg::face::Pos PosType; - typedef typename std::vector PosVector; - typedef FgtHole HoleType; - typedef typename std::vector 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* 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 FgtBridge: public FgtBridgeBase { - typedef typename vcg::GridStaticPtr GridType; + typedef BridgeAbutment AbutmentType; + typedef typename MESH::FaceType FaceType; + typedef typename MESH::FaceType FaceType; + typedef typename MESH::ScalarType ScalarType; + typedef typename vcg::face::Pos PosType; + typedef FgtHole HoleType; + typedef typename std::vector HoleVector; + typedef typename MESH::FacePointer FacePointer; + typedef typename MESH::FaceIterator FaceIterator; + typedef typename vcg::GridStaticPtr GridType; typedef typename std::vector< FgtBridge > BridgeVector; typedef typename BridgeVector::iterator BridgeIterator; + typedef typename MESH::VertexType VertexType; public: enum BridgeOption {NoOne, OptA, OptB}; @@ -158,8 +161,8 @@ public: FgtBridge(HoleSetManager* parent) { f0=0; - f0=0; - parentManager = parent; + f0=0; + this->parentManager = parent; }; inline void AddFaceReference(std::vector &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::DeleteFace(*parentManager->mesh, *f0); + vcg::tri::Allocator::DeleteFace(*this->parentManager->mesh, *f0); if( !f1->IsD() ) - vcg::tri::Allocator::DeleteFace(*parentManager->mesh, *f1); + vcg::tri::Allocator::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(*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(*adjF, adjEI)); } } - + if(!vcg::face::IsBorder(*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 &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::AddFaces(*parentManager->mesh, 2, app); - parentManager->faceAttr->UpdateSize(); + FaceIterator fit = vcg::tri::Allocator::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* holesManager, QString &err, std::vector *app=0) { - assert( vcg::face::IsBorder(*sideA.f, sideA.z) && + assert( vcg::face::IsBorder(*sideA.f, sideA.z) && vcg::face::IsBorder(*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 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; iautoBridgeCB != 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 tmpFaceRef; AbutmentType sideA, sideB; BridgeOption bestOpt; std::vector selectedHoles; - typename std::vector::iterator shit1, shit2; + typename std::vector::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* holesManager, std::vector &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* holesManager, std::vector &app) { assert(vcg::face::IsBorder(*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* 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 FgtNMBridge: public FgtBridgeBase { + typedef typename MESH::FaceType FaceType; + typedef typename MESH::FacePointer FacePointer; + typedef typename vcg::face::Pos PosType; + typedef FgtHole HoleType; + typedef typename MESH::FaceIterator FaceIterator; + public: FgtNMBridge(FacePointer f, HoleSetManager* 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::DeleteFace(*parentManager->mesh, *f0); + vcg::tri::Allocator::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(*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* holesManager, std::vector *app=0) { int startNholes = holesManager->holes.size(); - + std::vector tmpFaceRef; - HoleType* oldRef = 0; + HoleType* oldRef = 0; for(int i=0; iholes.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 PosType; + typedef typename std::vector< PosType > PosVector; typedef typename vcg::tri::Hole vcgHole; typedef typename vcgHole::Info HoleInfo; typedef typename std::vector< FgtHole > HoleVector; @@ -168,10 +169,10 @@ public: void Draw() const { - typename std::vector::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::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::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::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 &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::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 vertexes; + std::vector borderPos; }; diff --git a/src/fgt/edit_hole/holeListModel.h b/src/fgt/edit_hole/holeListModel.h index 85ea638f4..6be1b5d3e 100644 --- a/src/fgt/edit_hole/holeListModel.h +++ b/src/fgt/edit_hole/holeListModel.h @@ -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 holesManager; - Q_SIGNALS: void SGN_needUpdateGLA(); void SGN_ExistBridge(bool exist); - }; diff --git a/src/fgt/edit_hole/holeSetManager.h b/src/fgt/edit_hole/holeSetManager.h index 05758e175..4ca707edd 100644 --- a/src/fgt/edit_hole/holeSetManager.h +++ b/src/fgt/edit_hole/holeSetManager.h @@ -30,8 +30,8 @@ #include -/* 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 bridgeF; - std::vector::iterator fpit; - + typename std::vector bridgeF; + typename std::vector::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 &facesReferences) { - typename HoleVector::iterator it = holes.begin(); - for( ; it!=holes.end(); it++) - { - facesReferences.push_back(&it->p.f); - typename std::vector::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 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;