Code refactory:

- use additional data instead of flag
 - add higher level entity as manager of holes' set

bug-fix:close more than one non manifold hole selected
This commit is contained in:
Paolo Cignoni cignoni 2008-10-23 15:29:13 +00:00
parent a25c5f9824
commit e254f8613c
9 changed files with 1139 additions and 981 deletions

View File

@ -44,7 +44,6 @@ EditHolePlugin::EditHolePlugin() {
EditHolePlugin::~EditHolePlugin()
{
FgtHole<CMeshO>::DeleteFlag();
if ( dialogFiller !=0 )
{
delete dialogFiller;
@ -63,11 +62,11 @@ const QString EditHolePlugin::Info()
return tr("Allow fill one or more hole into place");
}
void EditHolePlugin::mouseReleaseEvent(QMouseEvent * e, MeshModel &/*m*/, GLArea * gla)
void EditHolePlugin::mouseReleaseEvent(QMouseEvent * /*e*/, MeshModel &/*m*/, GLArea * /*gla*/)
{
}
void EditHolePlugin::mousePressEvent(QMouseEvent * e, MeshModel &m, GLArea * gla)
void EditHolePlugin::mousePressEvent(QMouseEvent *e, MeshModel &/*m*/, GLArea * /*gla*/)
{
if ( (e->button()==Qt::LeftButton) )
{
@ -77,7 +76,7 @@ void EditHolePlugin::mousePressEvent(QMouseEvent * e, MeshModel &m, GLArea * gla
}
}
void EditHolePlugin::mouseMoveEvent(QMouseEvent * e, MeshModel &/*m*/, GLArea * gla)
void EditHolePlugin::mouseMoveEvent(QMouseEvent * /*e*/, MeshModel &/*m*/, GLArea * /*gla*/)
{
}
@ -131,6 +130,7 @@ void EditHolePlugin::StartEdit(MeshModel &m, GLArea *gla )
delete holesModel;
}
holesModel = new HoleListModel(&m);
holesModel->holesManager.autoBridgeCB = new EditHoleAutoBridgingCB(dialogFiller->ui.infoLbl, 800);
connect(holesModel, SIGNAL(SGN_needUpdateGLA()), this, SLOT(upGlA()) );
connect(holesModel, SIGNAL(SGN_ExistBridge(bool)), dialogFiller, SLOT(SLOT_ExistBridge(bool)) );
holeSorter = new HoleSorterFilter();
@ -159,15 +159,15 @@ void EditHolePlugin::Decorate(MeshModel &m, GLArea * gla)
pickedFace =0;
int inverseY = gla->curSiz.height() - cur.y();
GLPickTri<CMeshO>::PickNearestFace(cur.x(), inverseY, m.cm, pickedFace, 4, 4);
// guardo se nella faccia pi<70> vicina uno dei vertici <20> di bordo
if( pickedFace != 0 )
{
bool oldAbutmentPresence;
switch(holesModel->getState())
{
case HoleListModel::Selection:
if(FgtHole<CMeshO>::IsHoleBorderFace(*pickedFace))
holesModel->toggleSelectionHoleFromBorderFace(pickedFace);
if(holesModel->holesManager.IsHoleBorderFace(pickedFace))
holesModel->toggleSelectionHoleFromFace(pickedFace);
break;
case HoleListModel::Filled:
holesModel->toggleAcceptanceHole(pickedFace);
@ -191,7 +191,7 @@ void EditHolePlugin::Decorate(MeshModel &m, GLArea * gla)
glPopMatrix();
}
void EditHolePlugin::EndEdit(MeshModel &m, GLArea *gla ){
void EditHolePlugin::EndEdit(MeshModel &/*m*/, GLArea *gla ){
if(holesModel == 0) // means editing is not started
return;
@ -199,8 +199,6 @@ void EditHolePlugin::Decorate(MeshModel &m, GLArea * gla)
holesModel->acceptFilling(false);
holesModel->removeBridges();
FgtHole<CMeshO>::DeleteFlag();
if ( dialogFiller!=0) {
delete dialogFiller;
delete holesModel;
@ -222,12 +220,12 @@ void EditHolePlugin::upGlA()
void EditHolePlugin::setInfoLabel()
{
int ns = holesModel->SelectionCount();
int nh = holesModel->HolesCount();
int ns = holesModel->holesManager.SelectionCount();
int nh = holesModel->holesManager.HolesCount();
QString infoStr;
if(holesModel->getState() == HoleListModel::Filled)
{
int na = holesModel->AcceptedCount();
int na = holesModel->holesManager.AcceptedCount();
infoStr = QString("Filled: %1/%2; Accepted: %3").arg(ns).arg(nh).arg(na);
}
else
@ -296,7 +294,7 @@ void EditHolePlugin::manualBridge()
{
holesModel->setEndBridging();
dialogFiller->clickEndBridging();
gla->setCursor(QCursor());
gla->setCursor(QCursor());
}
gla->update();
}
@ -304,7 +302,7 @@ void EditHolePlugin::manualBridge()
void EditHolePlugin::autoBridge()
{
bool singleHole = dialogFiller->ui.selfHoleChkB->isChecked();
holesModel->autoBridge(singleHole, bridgeOptSldVal*0.0017, dialogFiller->ui.infoLbl);
holesModel->autoBridge(singleHole, bridgeOptSldVal*0.0017);
upGlA();
}
@ -342,6 +340,7 @@ void EditHolePlugin::skipTab(int index)
{
holesModel->setEndBridging();
dialogFiller->clickEndBridging();
gla->setCursor(QCursor());
}
else
cancelFill();

View File

@ -25,24 +25,37 @@
#define EDITHOLEPLUGIN_H
#include <QObject>
#include <QList>
#include "fillerDialog.h"
#include "holeListModel.h"
#include <meshlab/meshmodel.h>
#include <meshlab/interfaces.h>
class EditHoleAutoBridgingCB : public AutoBridgingCallback
{
public:
EditHoleAutoBridgingCB(QLabel* lab, int off)
{
offset = off;
label = lab;
};
void Invoke(int val)
{
label->setText( QString("Auto-bridging: %1%").arg(val) );
label->repaint();
};
private:
QLabel* label;
};
class EditHolePlugin : public QObject, public MeshEditInterface
{
Q_OBJECT
Q_INTERFACES(MeshEditInterface)
public:
typedef vcg::tri::Hole<CMeshO> vcgHole;
typedef vcgHole::Info HoleInfo;
typedef std::vector< FgtHole<CMeshO> > HoleVector;
typedef vcg::face::Pos<CMeshO::FaceType> PosType;
typedef CMeshO::FaceIterator FaceIterator;
EditHolePlugin();
virtual ~EditHolePlugin();
static const QString Info();

View File

@ -6,6 +6,7 @@ HEADERS = edit_hole_factory.h \
holeListModel.h \
fgtHole.h \
fgtBridge.h \
holeSetManager.h \
../../meshlab/meshmodel.h
SOURCES = edit_hole_factory.cpp \

View File

@ -29,8 +29,11 @@
#include "vcg/space/line2.h"
#include "vcg/space/triangle3.h"
#include "fgtHole.h"
#include "meshlab/mainwindow.h"
#include "holeSetManager.h"
#include <ctime>
template <class MESH> class FgtHole;
template <class MESH> class HoleSetManager;
/* Struct rappresenting the mesh edge where the bridge starts/ends. */
template <class MESH>
@ -54,7 +57,24 @@ public:
FgtHole<MESH>* h;
};
/** Object rapresent connection between two border edges of different faces.
/* 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
{
public:
inline int GetOffset() const { return offset; };
virtual void Invoke(int) = 0;
protected:
int offset; // minor time before 2 calling (in ms)
};
/** Class entirely static, it offers functions to manage bridges 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
* with a mesh face over another edge, so both faces have a border edge.
*
@ -100,12 +120,9 @@ public:
typedef typename std::vector<PosType> PosVector;
typedef FgtHole<MESH> HoleType;
typedef typename std::vector<HoleType> HoleVector;
typedef typename MESH::VertexType VertexType;
typedef typename MESH::CoordType CoordType;
typedef typename MESH::ScalarType ScalarType;
typedef typename vcg::Triangle3<ScalarType> TriangleType;
/**** Static functions ******/
public:
@ -114,29 +131,31 @@ public:
* If the bridge is inside the same hole it cannot be adjacent the hole border,
* this means fill another sub hole.
*/
static bool CreateBridge(BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB, MESH &mesh,
HoleVector &holes, std::vector<FacePointer *> *app=0)
static bool CreateBridge(BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB,
HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> *app=0)
{
assert(FgtHole<MESH>::IsHoleBorderFace(*sideA.f) && FgtHole<MESH>::IsHoleBorderFace(*sideB.f));
assert( holesManager->IsHoleBorderFace(sideA.f) &&
holesManager->IsHoleBorderFace(sideB.f));
assert(!sideA.h->IsFilled() && !sideB.h->IsFilled());
std::vector<FacePointer *> tmpFaceRef;
if(app!=0)
tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
FgtHole<MESH>::AddFaceReference(holes, tmpFaceRef);
FgtHole<MESH>::AddFaceReference(holesManager->holes, tmpFaceRef);
if(sideA.h == sideB.h)
{
if( testAbutmentDistance(sideA, sideB))
return subdivideHoleWithBridge(sideA, sideB, mesh, holes, tmpFaceRef);
return subdivideHoleWithBridge(sideA, sideB, holesManager, tmpFaceRef);
else
return false;
}
else
return unifyHolesWithBridge(sideA, sideB, mesh, holes, tmpFaceRef);
return unifyHolesWithBridge(sideA, sideB, holesManager, tmpFaceRef);
};
static void AcceptBridges(HoleVector &holes)
// clear flags of faces marked as bridge, bridge faces become mesh faces
static void AcceptBridges(HoleSetManager<MESH>* holeManager)
{
// contains bridge faces reached navigating the holes.
std::vector<FacePointer> bridgeFaces;
@ -146,22 +165,22 @@ public:
PosVector adjBorderPos;
PosType curPos;
getBridgeInfo(holes, bridgeFaces, adjBorderPos);
getBridgeInfo(holeManager, bridgeFaces, adjBorderPos);
typename std::vector<FacePointer>::iterator fit;
for(fit=bridgeFaces.begin(); fit!=bridgeFaces.end(); fit++ )
{
(*fit)->ClearUserBit( FgtHole<MESH>::HolePatchFlag() );
(*fit)->ClearUserBit( FgtHole<MESH>::PatchCompFlag() );
(*fit)->ClearUserBit( FgtHole<MESH>::BridgeFlag() );
holeManager->ClearPatchAttr(*fit);
holeManager->ClearCompAttr(*fit);
holeManager->ClearBridgeAttr(*fit);
}
typename HoleVector::iterator it = holes.begin();
for( ; it!=holes.end(); it++ )
typename HoleVector::iterator it = holeManager->holes.begin();
for( ; it!=holeManager->holes.end(); it++ )
it->SetBridged(false);
};
/* Remove all face marked as Bridge. */
static void RemoveBridges(MESH &mesh, HoleVector &holes)
/* Remove all face marked as bridge. */
static void RemoveBridges(HoleSetManager<MESH> *holeManager)
{
// contains bridge faces reached navigating the holes.
std::vector<FacePointer> bridgeFaces;
@ -171,37 +190,37 @@ public:
PosVector adjBorderPos;
PosType curPos;
getBridgeInfo(holes, bridgeFaces, adjBorderPos);
getBridgeInfo(holeManager, bridgeFaces, adjBorderPos);
// remove all holes which have a bridge face on its border and
// remove all bridge face
typename std::vector<FacePointer>::iterator fit;
for(fit=bridgeFaces.begin(); fit!=bridgeFaces.end(); fit++ )
{
if(FgtHole<MESH>::IsHoleBorderFace(**fit))
if(holeManager->IsHoleBorderFace(*fit))
{
typename HoleVector::iterator hit;
if(FgtHole<MESH>::FindHoleFromBorderFace(*fit, holes, hit) != -1)
if(holeManager->FindHoleFromFace(*fit, hit) != -1)
{
assert(!hit->IsFilled());
holes.erase(hit);
holeManager->holes.erase(hit);
}
}
if( !(*fit)->IsD() )
vcg::tri::Allocator<MESH>::DeleteFace(mesh, **fit);
vcg::tri::Allocator<MESH>::DeleteFace(*holeManager->mesh, **fit);
}
// remove also hole which have on its border faces finded from half-edge adjacent to bridge face
// these holes will be reinsert at the end
typename std::vector<PosType>::iterator pit;
for(pit=adjBorderPos.begin(); pit!=adjBorderPos.end(); pit++)
if(FgtHole<MESH>::IsHoleBorderFace(*pit->f))
if(holeManager->IsHoleBorderFace(pit->f))
{
typename HoleVector::iterator hit;
if(FgtHole<MESH>::FindHoleFromBorderFace(pit->f, holes, hit) != -1)
if(holeManager->FindHoleFromFace(pit->f, hit) != -1)
{
assert(!hit->IsFilled());
holes.erase(hit);
holeManager->holes.erase(hit);
}
}
@ -213,7 +232,7 @@ public:
if(!IsBorder(**fit, e))
{
FacePointer adjF = (*fit)->FFp(e);
if(!FgtHole<MESH>::IsBridgeFace(*adjF))
if(!holeManager->IsBridgeFace(adjF))
{
int adjEI = (*fit)->FFi(e);
adjF->FFp( adjEI ) = adjF;
@ -247,9 +266,9 @@ public:
assert(curPos.IsBorder());
}while(curPos != initPos);
FgtHole<MESH> newHole(initPos, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')) );
FgtHole<MESH> newHole(initPos, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), holeManager);
newHole.SetSelect(sel);
holes.push_back( newHole );
holeManager->holes.push_back( newHole );
}
// resetto falg visited sulle facce degli hole interessati
@ -266,88 +285,52 @@ public:
}
};
/** Return boolean indicatind if the picking have select a border face which can be used
* as abutment for a bridge. If true it also return BridgeAbutment allowing to know
* border edge and its relative hole.
*/
static bool FindBridgeAbutmentFromPick(FacePointer bFace, int pickedX, int pickedY,
HoleVector &holes, BridgeAbutment<MESH> &pickedResult)
{
if( vcg::face::BorderCount(*bFace) == 0 )
return false;
typename HoleVector::iterator hit;
if( FgtHole<MESH>::FindHoleFromBorderFace(bFace, holes, hit) < 0 )
{
pickedResult.SetNull();
return false;
}
pickedResult.h = &*hit;
pickedResult.f = bFace;
if( vcg::face::BorderCount(*bFace) == 1 )
{
// it choose the only one border edge
for(int i=0; i<3; i++)
if(vcg::face::IsBorder<FaceType>(*bFace, i))
pickedResult.z = i;
}
else
{
// looking for the closest border edge to pick point
PosType retPos = getClosestPos(bFace, pickedX, pickedY);
pickedResult.f = retPos.f;
pickedResult.z = retPos.z;
}
return true;
};
typedef void ProgressBridgingCallback(int v);
/* 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. exist between edge sharing a vertex or
* bridge's rule, bridge must have 2 border edge.
* infoLabel paramter is used to show work progress.
* Return number of bridge builded.
*/
static int AutoSelfBridging(MESH &mesh, HoleVector &holes, QLabel *infoLabel=0, double dist_coeff=0.0, std::vector<FacePointer *> *app=0)
static int AutoSelfBridging(HoleSetManager<MESH>* holesManager, double dist_coeff=0.0, std::vector<FacePointer *> *app=0)
{
QTime timer;
if(infoLabel != 0)
time_t timer;
if(holesManager->autoBridgeCB != 0)
{
infoLabel->setText(QString("Auto-bridging: %1%").arg(0) );
infoLabel->repaint();
timer.start();
holesManager->autoBridgeCB->Invoke(0);
timer = clock();
}
int nb = 0;
vcg::GridStaticPtr<FaceType, ScalarType > gM;
gM.Set(mesh.face.begin(),mesh.face.end());
gM.Set(holesManager->mesh->face.begin(),holesManager->mesh->face.end());
std::vector<FacePointer *> tmpFaceRef;
HoleType* oldRef = 0;
BridgeAbutment<MESH> sideA, sideB;
int nh = holes.size();
int nh = holesManager->holes.size();
for(int h=0; h<nh; ++h)
{
HoleType &thehole = holes.at(h);
HoleType &thehole = holesManager->holes.at(h);
if(!thehole.IsSelected() || thehole.Size()<6 )
continue;
assert(!thehole.IsFilled());
ScalarType maxQuality = -1;
// si scorre l'edge di partenza
PosType initP = thehole.p;
// initP: first bridge abutment
PosType initP = thehole.p;
for(int i=0; i<thehole.Size();i++)
{
// posiziono il secondo edge, la seconda spalla del ponte
// 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
// i due edge di bordo sono già collegati da 2 triangoli adiacenti,
// il bridge si sovrapporrebbe a questi 2 triangoli
if( endP.f->FFp(0) == initP.f ||
@ -374,8 +357,8 @@ public:
FaceType bfA1;
bfA1.V(0) = vB1; bfA1.V(1) = vB0; bfA1.V(2) = vA0;
if( !HoleType::TestFaceMeshCompenetration(mesh, gM, &bfA0) &&
!HoleType::TestFaceMeshCompenetration(mesh, gM, &bfA1) )
if( !HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfA0) &&
!HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfA1) )
{
ScalarType Aq = QualityFace(bfA0)+ QualityFace(bfA1) + dist_coeff * j;
if( Aq > maxQuality)
@ -389,8 +372,8 @@ public:
FaceType bfB1;
bfB1.V(0) = vB1; bfB1.V(1) = vB0; bfB1.V(2) = vA1;
if( !HoleType::TestFaceMeshCompenetration(mesh, gM, &bfB0) &&
!HoleType::TestFaceMeshCompenetration(mesh, gM, &bfB1) )
if( !HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfB0) &&
!HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfB1) )
{
ScalarType Bq = QualityFace(bfB0)+ QualityFace(bfB1) + dist_coeff * j;
if( Bq > maxQuality)
@ -403,16 +386,15 @@ public:
sideB.f=endP.f; sideB.z=endP.z; sideB.h=&thehole;
}
if(timer.elapsed() > 800)
if(holesManager->autoBridgeCB != 0)
{
float progress = (float)(((float)( ((float)j/(thehole.Size()-3)) + i) / thehole.Size()) + h) / nh;
//h + ((float)i/thehole.Size()) ) / nh );
infoLabel->setText(QString("Auto-bridging: %1%").arg((int)(progress*100)) );
infoLabel->repaint();
timer.restart();
if(clock()- timer > holesManager->autoBridgeCB->GetOffset())
{
float progress = (float)(((float)( ((float)j/(thehole.Size()-3)) + i) / thehole.Size()) + h) / nh;
holesManager->autoBridgeCB->Invoke(progress*100);
timer = clock();
}
}
}// scansione del edge di arrivo
initP.NextB();
@ -421,25 +403,25 @@ public:
assert(vcg::face::IsBorder<FaceType>(*sideA.f, sideA.z));
assert(vcg::face::IsBorder<FaceType>(*sideB.f, sideB.z));
if( oldRef != &*holes.begin() )
if( oldRef != &*holesManager->holes.begin() )
{
// si può
tmpFaceRef.clear();
if(app!=0)
tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
FgtHole<MESH>::AddFaceReference(holes, tmpFaceRef);
FgtHole<MESH>::AddFaceReference(holesManager->holes, tmpFaceRef);
tmpFaceRef.push_back(&sideA.f);
tmpFaceRef.push_back(&sideB.f);
oldRef = &*holes.begin();
oldRef = &*holesManager->holes.begin();
}
if(subdivideHoleWithBridge(sideA, sideB, mesh, holes, tmpFaceRef) )
if(subdivideHoleWithBridge(sideA, sideB, holesManager, tmpFaceRef) )
{
nb++;
gM.Set(mesh.face.begin(),mesh.face.end());
gM.Set(holesManager->mesh->face.begin(), holesManager->mesh->face.end());
// la subdivideHole.. aggiunge un hole pertanto bisogna aggiornare anche la lista di
// reference a facce
tmpFaceRef.push_back(&holes.back().p.f);
tmpFaceRef.push_back(&holesManager->holes.back().p.f);
}
} //scansione degli holes
@ -447,16 +429,17 @@ public:
};
/* Return number of bridges builded.
/* It connects iteratively selected holes with the best bridge.
* Result is unique hole instead of init holes.
* Return number of bridges builded.
*/
static int AutoMultiBridging(MESH &mesh, HoleVector &holes, QLabel* infoLabel=0, double dist_coeff=0.0, std::vector<FacePointer *> *app=0 )
static int AutoMultiBridging(HoleSetManager<MESH>* holesManager, double dist_coeff=0.0, std::vector<FacePointer *> *app=0 )
{
QTime timer;
if(infoLabel != 0)
time_t timer;
if(holesManager->autoBridgeCB != 0)
{
infoLabel->setText(QString("Auto-bridging: %1%").arg(0) );
infoLabel->repaint();
timer.start();
holesManager->autoBridgeCB->Invoke(0);
timer = clock();
}
int nb = 0;
@ -477,13 +460,13 @@ public:
// prendo gli hole selezionati
selectedHoles.clear();
for(hit=holes.begin(); hit!=holes.end(); hit++)
for(hit=holesManager->holes.begin(); hit!=holesManager->holes.end(); hit++)
if(hit->IsSelected())
selectedHoles.push_back(&*hit);
if(selectedHoles.size() < 2)
return nb;
gM.Set(mesh.face.begin(),mesh.face.end());
gM.Set(holesManager->mesh->face.begin(),holesManager->mesh->face.end());
float casesViewed = 0, cases2View = 0;
for(shit1=selectedHoles.begin(); shit1!=selectedHoles.end(); shit1++)
@ -517,8 +500,8 @@ public:
FaceType bfA1;
bfA1.V(0) = vB1; bfA1.V(1) = vB0; bfA1.V(2) = vA0;
if( !HoleType::TestFaceMeshCompenetration(mesh, gM, &bfA0) &&
!HoleType::TestFaceMeshCompenetration(mesh, gM, &bfA1) )
if( !HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfA0) &&
!HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfA1) )
{
ScalarType Aq = QualityFace(bfA0)+ QualityFace(bfA1);
if( Aq > maxQuality)
@ -532,8 +515,8 @@ public:
FaceType bfB1;
bfB1.V(0) = vB1; bfB1.V(1) = vB0; bfB1.V(2) = vA1;
if( !HoleType::TestFaceMeshCompenetration(mesh, gM, &bfB0) &&
!HoleType::TestFaceMeshCompenetration(mesh, gM, &bfB1) )
if( !HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfB0) &&
!HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfB1) )
{
ScalarType Bq = QualityFace(bfB0)+ QualityFace(bfB1);
if( Bq > maxQuality)
@ -546,13 +529,16 @@ public:
sideB = BridgeAbutment<MESH>(ph2.f, ph2.z, *shit2);
}
if(timer.elapsed() > 800)
if(holesManager->autoBridgeCB != 0)
{
int progress = ( (100 * ( iteration +(casesViewed/cases2View)))/nIteration );
infoLabel->setText(QString("Auto-bridging: %1%").arg(progress) );
infoLabel->repaint();
timer.restart();
if(clock() - timer > holesManager->autoBridgeCB->GetOffset())
{
int progress = ( (100 * ( iteration +(casesViewed/cases2View)))/nIteration );
holesManager->autoBridgeCB->Invoke(progress);
timer = clock();
}
}
casesViewed++;
ph2.NextB();
}while(ph2 != (*shit2)->p);
@ -571,11 +557,11 @@ public:
tmpFaceRef.clear();
if(app!=0)
tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
FgtHole<MESH>::AddFaceReference(holes, tmpFaceRef);
FgtHole<MESH>::AddFaceReference(holesManager->holes, tmpFaceRef);
tmpFaceRef.push_back(&sideA.f);
tmpFaceRef.push_back(&sideB.f);
if(unifyHolesWithBridge(sideA, sideB, mesh, holes, tmpFaceRef))
if(unifyHolesWithBridge(sideA, sideB, holesManager, tmpFaceRef))
nb++;
iteration ++;
@ -589,26 +575,22 @@ public:
* add face adjacent to non-manifold vertex.
* Return number of faces added.
*/
static int CloseNonManifoldVertex(MESH &mesh, HoleVector &holes, std::vector<FacePointer *> *app=0)
static int CloseNonManifoldVertex(HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> *app=0)
{
int startNholes = holes.size();
int startNholes = holesManager->holes.size();
int nf = 0;
// i riferimenti alle facce presenti nella lista di hole vengono gestiti qui perchè
// questo metodo può fare inserimenti sulla lista di hole e quindi provocarne il riallocamento
// e perdere così i riferimenti.
std::vector<FacePointer *> tmpFaceRef;
if(app!=0)
tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
FgtHole<MESH>::AddFaceReference(holes, tmpFaceRef);
HoleType* oldRef = &*holes.begin();
HoleType* oldRef = 0;
for(int i=0; i<startNholes; i++)
{
HoleType *h = &holes.at(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;
assert(curPos.IsBorder());
assert(!h->IsFilled());
@ -626,15 +608,25 @@ public:
if(!p0.IsNull())
{
if( oldRef != &*holesManager->holes.begin() )
{
// holes vector is been reallocated... tmpFaceRes must be recomputed
tmpFaceRef.clear();
if(app!=0)
tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
FgtHole<MESH>::AddFaceReference(holesManager->holes, tmpFaceRef);
oldRef = &*holesManager->holes.begin();
}
tmpFaceRef.push_back(&p0.f);
tmpFaceRef.push_back(&curPos.f);
FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(mesh, 1, tmpFaceRef);
FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(*holesManager->mesh, 1, tmpFaceRef);
holesManager->faceAttr->UpdateSize();
nf++;
tmpFaceRef.pop_back();
tmpFaceRef.pop_back();
// torno indietro lungo il bordo resettando il flag V dei vertici (tranne quello condiviso)
// e prendo l'edge che condivide un vertice (p1)
// non-manifold vertex found, go back over the border to find other edge share the vertex with p0
int dist = 0;
p1 = p0;
p1.FlipV();
@ -646,10 +638,9 @@ public:
PosType p2 = p0;
p2.FlipV();
p2.NextB();
p2.NextB();
// si costruisce la faccia in modo da avere vertice 0 il vertice non manifold
// e quindi l'edge 1 l'edge di bordo
// 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;
if( p0.VInd() == p0.z)
{
@ -683,13 +674,13 @@ public:
}
ComputeNormal(*fit);
fit->SetUserBit(FgtHole<MESH>::BridgeFlag());
holesManager->SetBridgeAttr(&*fit);
if(dist==2)
{
// il buco da chiudere è formato solo da 3 edge e quidni viene completamente chiuso
// senza possibilità di ripristinarlo, tanto la soluzione di riempimento è solo una
fit->SetUserBit(FgtHole<MESH>::HolePatchFlag());
// 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;
@ -700,23 +691,16 @@ public:
fit->FFp(1) = &*fit;
fit->FFi(1) = 1;
HoleType newhole(PosType(&*fit, 1), QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')));
HoleType newhole(PosType(&*fit, 1), QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), holesManager);
if(h->IsSelected())
newhole.SetSelect(true);
newhole.SetBridged(true);
holes.push_back(newhole);
if( oldRef != &*holes.begin() )
{
tmpFaceRef.clear();
if(app!=0)
tmpFaceRef.insert(tmpFaceRef.end(), app->begin(), app->end());
FgtHole<MESH>::AddFaceReference(holes, tmpFaceRef);
oldRef = &*holes.begin();
h = &holes.at(i);
}
else
tmpFaceRef.push_back(&holes.back().p.f);
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);
}
p0.SetNull();
}
@ -731,12 +715,11 @@ public:
//forzo l'aggiornamento delle info dell'hole
h->SetStartPos(h->p);
h->SetBridged(true);
return nf;
}// for(int i=0; i<startNholes...
return nf;
};
private:
/* Compute distance between bridge side to allow no bridge adjacent to hole border.
@ -764,7 +747,7 @@ private:
}
else
{
// if exist a face which share a vertex with each side bridge cannot be built
// 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;
@ -788,38 +771,38 @@ private:
return true;
};
static bool subdivideHoleWithBridge(BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB, MESH &mesh,
HoleVector &holes, std::vector<FacePointer *> &app)
static bool subdivideHoleWithBridge(BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB,
HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> &app)
{
PosType newP0, newP1;
if( !build(mesh, sideA, sideB, newP0, newP1, app) )
if( !build(holesManager, sideA, sideB, newP0, newP1, app) )
return false;
newP0.f->SetUserBit(FgtHole<MESH>::BridgeFlag());
newP1.f->SetUserBit(FgtHole<MESH>::BridgeFlag());
holesManager->SetBridgeAttr(newP0.f);
holesManager->SetBridgeAttr(newP1.f);
sideA.h->SetStartPos(newP0);
sideA.h->SetBridged(true);
FgtHole<MESH> newHole(newP1, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')) );
FgtHole<MESH> newHole(newP1, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), holesManager);
if(sideA.h->IsSelected())
newHole.SetSelect(true);
newHole.SetBridged(true);
holes.push_back( newHole );
holesManager->holes.push_back( newHole );
return true;
};
static bool unifyHolesWithBridge(BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB, MESH &mesh,
HoleVector &holes, std::vector<FacePointer *> &app)
static bool unifyHolesWithBridge(BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB,
HoleSetManager<MESH>* holesManager, std::vector<FacePointer *> &app)
{
assert(FgtHole<MESH>::IsHoleBorderFace(*sideA.f));
assert(FgtHole<MESH>::IsHoleBorderFace(*sideB.f));
assert(holesManager->IsHoleBorderFace(sideA.f));
assert(holesManager->IsHoleBorderFace(sideB.f));
PosType newP0, newP1;
if( !build(mesh, sideA, sideB, newP0, newP1, app) )
if( !build(holesManager, sideA, sideB, newP0, newP1, app) )
return false;
newP0.f->SetUserBit(FgtHole<MESH>::BridgeFlag());
newP1.f->SetUserBit(FgtHole<MESH>::BridgeFlag());
holesManager->SetBridgeAttr(newP0.f);
holesManager->SetBridgeAttr(newP1.f);
sideA.h->SetStartPos(newP0);
if(sideB.h->IsSelected())
@ -827,10 +810,10 @@ private:
sideA.h->SetBridged(true);
typename HoleVector::iterator hit;
for(hit=holes.begin(); hit!=holes.end(); ++hit)
for(hit=holesManager->holes.begin(); hit!=holesManager->holes.end(); ++hit)
if(&*hit == sideB.h)
{
holes.erase(hit);
holesManager->holes.erase(hit);
break;
}
return true;
@ -851,19 +834,18 @@ private:
*
* Return the pos located into new 2 faces added over its border edge
*/
static bool build(MESH &mesh, BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB,
static bool build(HoleSetManager<MESH> *holesManager, BridgeAbutment<MESH> &sideA, BridgeAbutment<MESH> &sideB,
PosType &pos0, PosType &pos1, std::vector<FacePointer *> &app)
{
vcg::GridStaticPtr<FaceType, ScalarType > gM;
gM.Set(mesh.face.begin(),mesh.face.end());
gM.Set(holesManager->mesh->face.begin(),holesManager->mesh->face.end());
// prima faccia del bridge
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
// solution A
// case A
FaceType bfA0;
bfA0.V(0) = vA1; bfA0.V(1) = vA0; bfA0.V(2) = vB0;
@ -871,13 +853,13 @@ private:
bfA1.V(0) = vB1; bfA1.V(1) = vB0; bfA1.V(2) = vA0;
ScalarType Aq;
if( HoleType::TestFaceMeshCompenetration(mesh, gM, &bfA0) ||
HoleType::TestFaceMeshCompenetration(mesh, gM, &bfA1) )
if( HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfA0) ||
HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfA1) )
Aq = -1;
else
Aq = QualityFace(bfA0)+ QualityFace(bfA1);
// solution B
// case B
FaceType bfB0;
bfB0.V(0) = vA1; bfB0.V(1) = vA0; bfB0.V(2) = vB1;
@ -885,8 +867,8 @@ private:
bfB1.V(0) = vB1; bfB1.V(1) = vB0; bfB1.V(2) = vA1;
ScalarType Bq;
if( HoleType::TestFaceMeshCompenetration(mesh, gM, &bfB0) ||
HoleType::TestFaceMeshCompenetration(mesh, gM, &bfB1) )
if( HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfB0) ||
HoleType::TestFaceMeshCompenetration(*holesManager->mesh, gM, &bfB1) )
Bq = -1;
else
Bq = QualityFace(bfB0)+ QualityFace(bfB1);
@ -895,14 +877,15 @@ private:
if(Aq == -1 && Bq == -1)
return false;
FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(mesh, 2, app);
FaceIterator fit = vcg::tri::Allocator<MESH>::AddFaces(*holesManager->mesh, 2, app);
holesManager->faceAttr->UpdateSize();
FacePointer f0 = &*fit;
FacePointer f1 = &*(fit+1);
sideA.f->ClearUserBit(FgtHole<MESH>::HoleFlag());
sideB.f->ClearUserBit(FgtHole<MESH>::HoleFlag());
f0->SetUserBit(FgtHole<MESH>::HoleFlag());
f1->SetUserBit(FgtHole<MESH>::HoleFlag());
holesManager->ClearHoleBorderAttr(sideA.f);
holesManager->ClearHoleBorderAttr(sideB.f);
holesManager->SetHoleBorderAttr(f0);
holesManager->SetHoleBorderAttr(f1);
// the index of edge adjacent between new 2 face, is the same for both new faces
int adjEdgeIndex = -1;
@ -969,51 +952,13 @@ private:
return true;
};
static PosType getClosestPos(FaceType* face, int x, int y)
{
double mvmatrix[16], projmatrix[16];
GLint viewport[4];
double rx, ry, rz;
vcg::Point2d vertex[3];
vcg::Point2d point((double)x, (double)y);
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
glGetIntegerv(GL_VIEWPORT, viewport);
for(int i=0; i<3; i++)
{
gluProject(face->V(i)->P()[0],face->V(i)->P()[1],face->V(i)->P()[2],mvmatrix,projmatrix,viewport,&rx,&ry,&rz);
vertex[i] = vcg::Point2d(rx,ry);
}
double dist = DBL_MAX;
int nearest = 0;
for(int i=0; i<3; i++)
{
if(!vcg::face::IsBorder<FaceType>(*face, i))
continue;
vcg::Line2d el(vertex[i], vertex[(i+1)%3]-vertex[i]);
double tmp = vcg::Distance(el, point);
if(dist > tmp)
{
dist = tmp;
nearest = i;
}
}
return PosType(face, nearest, face->V(nearest) );
};
/* Starting from an hole look for faces added to mesh as bridge jumping also into
* holes finded crossing bridges. If bridges'll be removed these holes could belong to the same hole.
* Put into bridgeFaces all faces added to mesh as bridge
* Put into adjBridgePos half-edges located over the edge which will become border edge
* after bridge face removing also mark with flag S the faces related to adjBridgePos
*/
static void getBridgeInfo(HoleVector &holes, std::vector<FacePointer> &bridgeFaces, std::vector<PosType> &adjBridgePos)
static void getBridgeInfo(HoleSetManager<MESH> *holesManager, std::vector<FacePointer> &bridgeFaces, std::vector<PosType> &adjBridgePos)
{
//scorro gli hole
PosType curPos;
@ -1022,7 +967,7 @@ private:
adjBridgePos.clear();
for(hit=holes.begin(); hit!=holes.end(); ++hit)
for(hit=holesManager->holes.begin(); hit!=holesManager->holes.end(); ++hit)
{
assert(!hit->IsFilled());
if(!hit->IsBridged())
@ -1032,7 +977,7 @@ private:
// This happens after non-manifold closure, it adds only a face to a side of non.manifold vertex,
// so a resultant "sub-hole" haven't bridged+border face.
// To know this hole is connected to other hole from bridge, we add its half-edge on adjBorderPos.
if(!FgtHole<MESH>::IsBridgeFace(*hit->p.f) )
if(!holesManager->IsBridgeFace(hit->p.f) )
{
if(hit->IsSelected())
hit->p.f->SetS();
@ -1053,7 +998,7 @@ private:
lastF = cp2.f;
cp2.FlipE();
cp2.FlipF();
if(FgtHole<MESH>::IsBridgeFace(*cp2.f) )
if(holesManager->IsBridgeFace(cp2.f) )
{
if(hit->IsSelected())
cp2.f->SetS();
@ -1088,7 +1033,7 @@ private:
lastPos = curPos;
curPos.FlipE();
curPos.FlipF();
if(FgtHole<MESH>::IsBridgeFace(*curPos.f))
if(holesManager->IsBridgeFace(curPos.f))
{
if(vf->IsS())
curPos.f->SetS();
@ -1102,7 +1047,7 @@ private:
// look for half-edge
FacePointer adjF = vf->FFp(e);
if(!FgtHole<MESH>::IsBridgeFace(*adjF) && !adjF->IsV())
if(!holesManager->IsBridgeFace(adjF) && !adjF->IsV())
{
adjF->SetV();
if(vf->IsS()) adjF->SetS();

View File

@ -35,14 +35,18 @@
#include <vcg/complex/trimesh/closest.h>
#include <vcg/space/index/grid_static_ptr.h>
#include "vcg/space/color4.h"
#include "holeSetManager.h"
/** An hole type, extends vcg::tri::Hole<MESH>::Info adding more information as filling, selection,
* filing autocompenetration and non manifoldness. This class also allow to fill (and restore) an
* hole using different criteria.
/** An hole type, extends vcg::tri::Hole<MESH>::Info adding more information
* as filling, selection, filing autocompenetration and non manifoldness.
* This class also allow to fill (and restore) an hole using different criteria.
*
* FgtHole uses flags to mark interesting face, so surfing the hole faces is driven by face-face
* ajacency and flag meaning. Hole face are flagged as:
* - HoleBorderFace: face which initially (before filling) have 1/2 border edge.
* FgtHole uses meshe's additional data to mark interesting face, so surfing
* the hole faces is driven by face-face ajacency and mark meaning.
* Additional data are accesible for an hole by parentManager (HoleSetManager)
* which links hole to a mesh.
* Characteristic faces for an hole are marked as:
* - HoleBorderFace: face which initially (before filling) have 1 or 2 border edge.
* - HolePatchFace: faces added to fill the hole
* - PatchCompFace: patch faces which are selfintersected with mesh.
* - BridgeFace: faces added to edit hole (unify 2 holes, subdivide an hole, partitioning a
@ -82,13 +86,9 @@ public:
typedef typename MESH::FaceType FaceType;
typedef typename MESH::FacePointer FacePointer;
typedef typename std::vector<FacePointer> FacePointerVector;
typedef typename MESH::FaceIterator FaceIterator;
typedef typename MESH::CoordType CoordType;
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 PosVector::iterator PosIterator;
typedef typename vcg::tri::Hole<MESH> vcgHole;
typedef typename vcgHole::Info HoleInfo;
typedef typename std::vector< FgtHole<MESH> > HoleVector;
@ -97,18 +97,20 @@ public:
typedef typename vcg::tri::MinimumWeightEar<MESH> MinimumWeightEar;
typedef typename vcg::tri::SelfIntersectionEar<MESH> SelfIntersectionEar;
FgtHole(HoleInfo &hi, QString holeName) :
FgtHole(HoleInfo &hi, QString holeName, HoleSetManager<MESH> *parent) :
HoleInfo(hi.p, hi.size, hi.bb)
{
parentManager = parent;
name = holeName;
_state = ACCEPTED;
perimeter = HoleInfo::Perimeter();
findNonManifoldness();
};
FgtHole(PosType startPos, QString holeName)
FgtHole(PosType startPos, QString holeName, HoleSetManager<MESH> *parent)
{
assert(startPos.IsBorder());
parentManager = parent;
name = holeName;
_state = ACCEPTED;
this->p = startPos;
@ -121,18 +123,8 @@ public:
inline ScalarType Perimeter() const { return this->perimeter; };
inline bool IsFilled() const { return (_state & FILLED) != 0; };
inline bool IsSelected() const { return (_state & SELECTED) != 0; };
inline void SetSelect(bool val)
{
if(val) _state |= SELECTED;
else _state &= (~SELECTED);
};
inline bool IsCompenetrating() const { return IsFilled() && (_state & COMPENET) != 0; };
inline bool IsAccepted() const { return !IsFilled() || ( (_state & ACCEPTED) != 0); };
inline void SetAccepted(bool val)
{
if(val) _state |= ACCEPTED;
else _state &= (~ACCEPTED);
};
inline bool IsNonManifold() const { return (_state & NONMANIF) != 0; };
inline bool IsBridged() const { return (_state & BRIDGED) != 0;; };
inline void SetBridged(bool val)
@ -141,6 +133,30 @@ public:
else _state &= (~BRIDGED);
};
void SetSelect(bool val)
{
bool oldVal = IsSelected();
if(val) _state |= SELECTED;
else _state &= (~SELECTED);
if(oldVal != val)
{
if(val) parentManager->nSelected++;
else parentManager->nSelected--;
}
};
void SetAccepted(bool val)
{
bool oldVal = IsAccepted();
if(val) _state |= ACCEPTED;
else _state &= (~ACCEPTED);
if(oldVal != val)
{
if(val) parentManager->nAccepted++;
else parentManager->nAccepted--;
}
};
inline void SetStartPos(PosType initP)
{
assert(!IsFilled());
@ -162,13 +178,11 @@ public:
{
assert(IsCompenetrating());
//std::vector<FacePointer> patch;
//getPatchFaces(patch);
typename std::vector<FacePointer>::const_iterator it;
glBegin(glmode);
for( it=patches.begin(); it != patches.end(); it++)
if((*it)->IsUserBit(PatchCompFlag()))
if( parentManager->IsCompFace(*it) )
{
glVertex( (*it)->V(0)->P() );
glVertex( (*it)->V(1)->P() );
@ -187,28 +201,24 @@ public:
std::vector<FacePointer> bridgesFaces;
if( IsFilled() )
{
//std::vector<FacePointer> patch;
//getPatchFaces(patch);
typename std::vector<FacePointer>::iterator it;
//for( it=patches.begin(); it != patches.end(); it++)
//{
while(patches.size()>0)
{
FacePointer f = patches.back();
patches.pop_back();
f->ClearUserBit(HolePatchFlag());
f->ClearUserBit(PatchCompFlag());
parentManager->ClearPatchAttr(f);
parentManager->ClearCompAttr(f);
// si conferma il filling della faccia BridgedFace+PatchFace aggiunta
// dalla partizione per ottenere hole non manifold
f->ClearUserBit(BridgeFlag());
parentManager->ClearBridgeAttr(f);
for(int i=0; i<3; i++)
{
FacePointer adjF = f->FFp(i);
adjF->ClearUserBit(HoleFlag());
if(IsBridgeFace(*adjF))
parentManager->ClearHoleBorderAttr(adjF);
if(parentManager->IsBridgeFace(adjF))
bridgesFaces.push_back(adjF);
}
}
@ -218,8 +228,8 @@ public:
// we can walk the border to find hole's faces added by bridges
PosType curPos = this->p;
do{
curPos.f->ClearUserBit(HoleFlag());
if( IsBridgeFace(*curPos.f))
parentManager->ClearHoleBorderAttr(curPos.f);
if( parentManager->IsBridgeFace(curPos.f))
bridgesFaces.push_back(curPos.f);
curPos.NextB();
}while( curPos != this->p );
@ -229,11 +239,11 @@ public:
{
FacePointer f = bridgesFaces.back();
bridgesFaces.pop_back();
f->ClearUserBit(BridgeFlag());
parentManager->ClearBridgeAttr(f);
for(int i=0; i<3; i++)
{
FacePointer adjF = f->FFp(i);
if(IsBridgeFace(*adjF) && !IsHoleBorderFace(*adjF))
if(parentManager->IsBridgeFace(adjF) && !parentManager->IsHoleBorderFace(adjF))
bridgesFaces.push_back(adjF);
}
}
@ -241,25 +251,23 @@ public:
/* Restore hole, remove patch faces applied to mesh to fill this hole. */
void RestoreHole(MESH &mesh)
void RestoreHole()
{
assert( IsFilled() );
//std::vector<FaceType*> patches;
//getPatchFaces(patches);
_state &= (~FILLED);
typename std::vector<FaceType*>::iterator it;
for(it = patches.begin(); it!=patches.end(); it++)
{
// PathcHoleFlag+BridgeFaceFlag is special case
if(IsBridgeFace(**it)) continue;
if(parentManager->IsBridgeFace(*it)) continue;
assert(IsPatchFace(**it));
assert(parentManager->IsPatchFace(*it));
for(int e=0; e<3; e++)
{
if(!IsBorder(**it, e))
{
FacePointer adjF = (*it)->FFp(e);
if(!FgtHole<MESH>::IsPatchFace(*adjF))
if(!parentManager->IsPatchFace(adjF))
{
int adjEI = (*it)->FFi(e);
adjF->FFp( adjEI ) = adjF;
@ -269,20 +277,21 @@ public:
}
}
if(!(**it).IsD())
vcg::tri::Allocator<MESH>::DeleteFace(mesh, **it);
vcg::tri::Allocator<MESH>::DeleteFace(*parentManager->mesh, **it);
}
patches.clear();
};
void Fill(FillerMode mode, MESH &mesh, std::vector<FacePointer * > &local_facePointer)
{
int patchBit = FaceType::NewBitFlag();
switch(mode)
{
case FgtHole<MESH>::Trivial:
vcgHole::template FillHoleEar< vcg::tri::TrivialEar<MESH> >(mesh, *this, HolePatchFlag(), local_facePointer);
vcgHole::template FillHoleEar< TrivialEar >(mesh, *this, patchBit, local_facePointer);
break;
case FgtHole<MESH>::MinimumWeight:
vcgHole::template FillHoleEar< vcg::tri::MinimumWeightEar<MESH> >(mesh, *this, HolePatchFlag(), local_facePointer);
vcgHole::template FillHoleEar< MinimumWeightEar >(mesh, *this, patchBit, local_facePointer);
break;
case FgtHole<MESH>::SelfIntersection:
std::vector<FacePointer * > vfp = local_facePointer;
@ -304,7 +313,7 @@ public:
for( ; fpi != SelfIntersectionEar::AdjacencyRing().end(); ++fpi)
vfp.push_back( &*fpi );
vcgHole::template FillHoleEar< SelfIntersectionEar >(mesh, *this, HolePatchFlag(), vfp);
vcgHole::template FillHoleEar< SelfIntersectionEar >(mesh, *this, patchBit, vfp);
SelfIntersectionEar::AdjacencyRing().clear();
break;
}
@ -314,12 +323,43 @@ public:
for( ;it!=vertexes.end(); it++)
(*it)->ClearV();
parentManager->faceAttr->UpdateSize();
_state |= FILLED;
_state |= ACCEPTED;
_state &= (~COMPENET);
updatePatchState(mesh);
updatePatchState(patchBit);
FaceType::DeleteBitFlag(patchBit);
};
/* Check if face is a border face of this hole */
bool HaveBorderFace(FacePointer bFace) const
{
assert(parentManager->IsHoleBorderFace(bFace));
assert( !IsFilled() );
PosType curPos = this->p;
do{
if(curPos.f == bFace)
return true;
curPos.NextB();
}while( curPos != this->p );
return false;
}
/* Check if pFace is a patch face of this hole */
bool HavePatchFace(FacePointer pFace) const
{
assert( parentManager->IsPatchFace(pFace) );
assert( IsFilled() );
// 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)
return true;
return false;
};
private:
@ -335,13 +375,12 @@ private:
PosType curPos = this->p;
do{
assert(!curPos.f->IsD());
curPos.f->SetUserBit(HoleFlag());
parentManager->SetHoleBorderAttr(curPos.f);
this->bb.Add(curPos.v->cP());
++this->size;
vertexes.push_back(curPos.v);
if(curPos.v->IsV())
_state |= NONMANIF;
//isNonManifold = true;
else
curPos.v->SetV();
@ -367,7 +406,6 @@ private:
do{
vertexes.push_back(curPos.v);
if(curPos.v->IsV())
//isNonManifold = true;
_state |= NONMANIF;
else
curPos.v->SetV();
@ -382,41 +420,42 @@ private:
};
/* set patch flag and auto-compenetration flag when needed */
void updatePatchState(MESH &mesh)
void updatePatchState(int patchFlag)
{
assert( IsFilled() );
_state &= (~COMPENET);
vcg::GridStaticPtr<FaceType, ScalarType > gM;
gM.Set(mesh.face.begin(),mesh.face.end());
gM.Set(parentManager->mesh->face.begin(),parentManager->mesh->face.end());
std::vector<FaceType*> inBox;
vcg::Box3< ScalarType> bbox;
//FacePointerVector patches;
//getPatchFaces(patches);
getPatchFaces();
getPatchFaces(patchFlag);
typename FacePointerVector::iterator pi = patches.begin();
for( ; pi!=patches.end(); ++pi)
{
FacePointer f = *pi;
if(TestFaceMeshCompenetration(mesh, gM, f))
if(TestFaceMeshCompenetration(*parentManager->mesh, gM, f))
{
_state |= COMPENET;
f->SetUserBit(PatchCompFlag());
parentManager->SetCompAttr(f);
}
(*pi)->ClearUserBit(patchFlag);
parentManager->SetPatchAttr(*pi);
}
};
/* First patch face is the adjacent one to initial Pos ("p" field of Hole::Info)
* Other patch face are found looking adjacent face on each vertex of known patch faces.
* NB: looking adjacent faces to vertexes it can find patches also for non manifold hole.
*/
void getPatchFaces()
void getPatchFaces(int patchFlag)
{
assert( IsFilled() );
patches.clear();
std::vector<FacePointer> stack;
PosType pos = this->p;
pos.FlipF();
assert(IsPatchFace(*pos.f));
assert(pos.f->IsUserBit(patchFlag));
pos.f->SetV();
stack.push_back(pos.f);
while(stack.size()>0)
@ -425,14 +464,14 @@ private:
stack.pop_back();
patches.push_back(f);
//visito le facce patch adiacenti ai vertici di questa faccia patch
// visit faces adjacent to f's vertexes
for(int v=0; v<3; v++)
{
pos = PosType(f, v);
do{
pos.FlipF();
pos.FlipE();
if(IsPatchFace(*pos.f) && !pos.f->IsV())
if(pos.f->IsUserBit(patchFlag) && !pos.f->IsV())
{
pos.f->SetV();
stack.push_back(pos.f);
@ -446,137 +485,12 @@ private:
(*it)->ClearV();
};
/* Check if face is a border face of this hole */
bool haveBorderFace(FacePointer bFace) const
{
assert(IsHoleBorderFace(*bFace));
assert( !IsFilled() );
PosType curPos = this->p;
do{
if(curPos.f == bFace)
return true;
curPos.NextB();
}while( curPos != this->p );
return false;
}
/* Check if pFace is a patch face of this hole */
bool havePatchFace(FacePointer pFace) const
{
assert( IsPatchFace(*pFace) );
assert( IsFilled() );
// 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)
return true;
return false;
};
/********* Static functions **********/
public:
static inline bool IsHoleBorderFace(FaceType &face)
{ return face.IsUserBit(HoleFlag()); };
static inline bool IsPatchFace(FaceType &face)
{ return face.IsUserBit(HolePatchFlag()); };
static inline bool IsBridgeFace(FaceType &face)
{ return face.IsUserBit(BridgeFlag()); };
/* Inspect a mesh to find its holes. */
static int GetMeshHoles(MESH &mesh, HoleVector &ret)
{
assert(HoleFlag() ==-1);
ret.clear();
std::vector<HoleInfo> vhi;
//prendo la lista di info(sugli hole) tutte le facce anche le non selezionate
HoleFlag() = vcgHole::GetInfo(mesh, false, vhi);
HolePatchFlag() = FaceType::NewBitFlag();
PatchCompFlag() = FaceType::NewBitFlag();
BridgeFlag() = FaceType::NewBitFlag();
ResetHoleId();
typename std::vector<HoleInfo>::iterator itH = vhi.begin();
int i=0;
for( ; itH != vhi.end(); itH++)
{
ret.push_back(FgtHole<MESH>(*itH, QString("Hole_%1").arg(GetHoleId(),3,10,QChar('0')) ));
i++;
}
return HoleFlag();
}
/** Return index of hole adjacent to picked face into holes vector.
* Also return the iterator on correct position in holes list.
/* Starting from holes stored into a vector this function extract all reference to mesh faces
* and adds them to vector facesReferences
*/
static int FindHoleFromBorderFace(FacePointer bFace, HoleVector &holes, HoleIterator &it)
{
assert(IsHoleBorderFace(*bFace));
int index = 0;
// it know if bFace is adjacent to patchFace
FacePointer adjF = 0;
for( int i=0; i<3; i++)
if(IsPatchFace(*bFace->FFp(i)) && !IsBridgeFace(*bFace->FFp(i)))
adjF = bFace->FFp(i);
HoleIterator hit = holes.begin();
if(adjF == 0)
{
// border face belong to an hole not filled
for( ; hit != holes.end(); ++hit)
{
if(!hit->IsFilled())
if(hit->haveBorderFace(bFace))
{
it = hit;
return index;
}
index++;
}
it = holes.end(); // invalid iterator
return -1;
}
else // bFace belong filled hole, adjF is its patch
return FindHoleFromPatchFace(adjF, holes, it);
}
/** Return index into holes vector of hole adjacent to picked face */
static int FindHoleFromPatchFace(FacePointer bFace, HoleVector &holes, HoleIterator &it)
{
assert(IsPatchFace(*bFace));
int index = 0;
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(bFace))
{
it = hit;
return index;
}
index++;
}
it = holes.end(); // invalid iterator
return -1; // means no find hole
};
static void DeleteFlag()
{
FaceType::DeleteBitFlag(BridgeFlag()); BridgeFlag()=-1;
FaceType::DeleteBitFlag(PatchCompFlag()); PatchCompFlag()=-1;
FaceType::DeleteBitFlag(HolePatchFlag()); HolePatchFlag()=-1;
FaceType::DeleteBitFlag(HoleFlag()); HoleFlag()=-1;
}
static void AddFaceReference(HoleVector& holes, std::vector<FacePointer*> &facesReferences)
{
typename HoleVector::iterator it = holes.begin();
@ -608,16 +522,15 @@ public:
public:
static int& HoleFlag() {static int _hf=-1; return _hf;};
static int& HolePatchFlag() {static int _pf=-1; return _pf; };
static int& PatchCompFlag() {static int _pcf=-1; return _pcf; };
static int& BridgeFlag() {static int _bf=-1; return _bf; };
static int &HoleId(){static int _holeId=0; return _holeId;};
static void ResetHoleId() { HoleId()=0; };
static int GetHoleId() { return ++HoleId(); };
QString name;
public:
HoleSetManager<MESH>* parentManager;
private:
static int &HoleId(){static int _holeId=0; return _holeId;};
int _state;
ScalarType perimeter;

View File

@ -38,7 +38,7 @@ FillerDialog::FillerDialog(QWidget *parent)
FillerDialog::~FillerDialog() {}
void FillerDialog::closeEvent ( QCloseEvent * event )
void FillerDialog::closeEvent ( QCloseEvent * /*event*/ )
{
emit SGN_Closing();
}

View File

@ -1,494 +1,420 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* 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. *
* *
****************************************************************************/
#include "holeListModel.h"
using namespace vcg;
HoleListModel::HoleListModel(MeshModel *m, QObject *parent)
: QAbstractItemModel(parent)
{
state = HoleListModel::Selection;
mesh = m;
userBitHole = -1;
pickedAbutment.SetNull();
updateModel();
}
void HoleListModel::clearModel()
{
HoleVector::iterator it;
for(it=holes.begin(); it!=holes.end(); it++)
it->ResetFlag();
holes.clear();
pickedAbutment.SetNull();
}
void HoleListModel::updateModel()
{
clearModel();
mesh->clearDataMask(MeshModel::MM_FACEFLAGBORDER);
mesh->updateDataMask(MeshModel::MM_FACEFACETOPO);
mesh->updateDataMask(MeshModel::MM_FACEFLAGBORDER);
userBitHole = FgtHole<CMeshO>::GetMeshHoles(mesh->cm, holes);
nSelected=0;
nAccepted=0;
emit dataChanged( index(0, 0), index(holes.size(), 2) );
emit SGN_needUpdateGLA();
}
void HoleListModel::drawHoles() const
{
// Disegno i contorni del buco
glLineWidth(2.0f);
glDepthMask(GL_TRUE);
glDepthFunc(GL_GREATER);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
// scorro tutti i buchi
HoleVector::const_iterator it = holes.begin();
for( ; it != holes.end(); ++it)
{
if( it->IsSelected())
{
if(it->IsAccepted())
glColor(Color4b::DarkGreen);
else
glColor(Color4b::DarkRed);
}
else
glColor(Color4b::DarkBlue);
it->Draw();
}
if(!pickedAbutment.IsNull())
{
glDepthFunc(GL_ALWAYS);
glLineWidth(2.0f);
glColor(Color4b::Yellow);
glBegin(GL_LINES);
glVertex( pickedAbutment.f->V0(pickedAbutment.z)->P() );
glVertex( pickedAbutment.f->V1(pickedAbutment.z)->P() );
glEnd();
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glLineWidth(2.0f);
for(it = holes.begin(); it != holes.end(); ++it)
{
if(it->IsSelected())
{
if(it->IsAccepted())
glColor(Color4b::Green);
else
glColor(Color4b::Red);
}
else
glColor(Color4b::Blue);
it->Draw();
}
}
void HoleListModel::drawCompenetratingFaces() const
{
glDisable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glDisable(GL_LIGHTING);
glColor3f(0.8f, 0.8f, 0.f);
HoleVector::const_iterator it;
for(it = holes.begin(); it != holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_LINE_LOOP);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
for(it = holes.begin(); it != holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_TRIANGLES);
glLineWidth(4.0f);
glColor3f(1.0f, 1.0f, 0.f);
for(it = holes.begin(); it != holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_LINE_LOOP);
}
void HoleListModel::toggleSelectionHoleFromBorderFace(CFaceO *bface)
{
assert(FgtHole<CMeshO>::IsHoleBorderFace(*bface));
HoleVector::iterator h;
int ind = FgtHole<CMeshO>::FindHoleFromBorderFace(bface, holes, h);
if( ind == -1)
return;
h->SetSelect( !h->IsSelected() );
if(h->IsSelected())
nSelected++;
else
nSelected--;
emit dataChanged( index(ind, 4), index(ind, 4) );
emit SGN_needUpdateGLA();
}
void HoleListModel::toggleAcceptanceHole(CFaceO *bface)
{
assert(state == HoleListModel::Filled);
HoleVector::iterator h;
int ind = -1;
if(FgtHole<CMeshO>::IsHoleBorderFace(*bface))
ind = FgtHole<CMeshO>::FindHoleFromBorderFace(bface, holes, h);
else if(FgtHole<CMeshO>::IsPatchFace(*bface) && !FgtHole<CMeshO>::IsBridgeFace(*bface))
ind = FgtHole<CMeshO>::FindHoleFromPatchFace(bface, holes, h);
if(ind == -1)
return;
h->SetAccepted( !h->IsAccepted() );
if(h->IsAccepted())
nAccepted++;
else
nAccepted--;
emit dataChanged( index(ind, 6), index(ind, 6) );
emit SGN_needUpdateGLA();
}
void HoleListModel::addBridgeFace(CFaceO *pickedFace, int pickedX, int pickedY)
{
BridgeAbutment<CMeshO> picked;
if (!FgtBridge<CMeshO>::FindBridgeAbutmentFromPick(pickedFace, pickedX, pickedY, holes, picked))
return;
if(pickedAbutment.f == picked.f && pickedAbutment.z == picked.z )
{
pickedAbutment.SetNull();
return;
}
if(pickedAbutment.IsNull() || pickedAbutment.f == picked.f)
pickedAbutment = picked;
else
{
std::vector<CMeshO::FacePointer *> local_facePointer;
local_facePointer.push_back(&pickedAbutment.f);
local_facePointer.push_back(&picked.f);
if(FgtBridge<CMeshO>::CreateBridge(pickedAbutment, picked, mesh->cm, holes, &local_facePointer))
{
emit SGN_ExistBridge(true);
emit layoutChanged();
}
else
QMessageBox::warning(0, tr("Bridge autocompenetration"), QString("Bridge is compenetrating with mesh."));
pickedAbutment.SetNull();
}
}
void HoleListModel::fill(FgtHole<CMeshO>::FillerMode mode)
{
std::vector<CMeshO::FacePointer *> local_facePointer;
HoleVector::iterator it;
FgtHole<CMeshO>::AddFaceReference(holes, local_facePointer);
for(it = holes.begin(); it != holes.end(); it++ )
if( it->IsSelected() )
{
it->Fill(mode, mesh->cm, local_facePointer);
state = HoleListModel::Filled;
}
nAccepted=nSelected;
emit layoutChanged();
}
void HoleListModel::acceptFilling(bool accept)
{
nSelected=0;
HoleVector::iterator it = holes.begin();
while( it != holes.end() )
{
if( it->IsFilled() )
{
if( (it->IsSelected() && !it->IsAccepted()) || !accept)
{
if( it->IsFilled() )
{
it->RestoreHole(mesh->cm);
nSelected++;
}
}
else if( it->IsSelected() && it->IsAccepted() )
{
it->ResetFlag();
it = holes.erase(it);
continue;
}
}
it++;
}
state = HoleListModel::Selection;
emit dataChanged( index(0, 0), index(holes.size(), 2) );
emit SGN_needUpdateGLA();
emit layoutChanged();
}
void HoleListModel::autoBridge(bool singleHole, double distCoeff, QLabel *infoLabel)
{
FgtBridge<CMeshO>::RemoveBridges(mesh->cm, holes);
int nb=0;
if(singleHole)
nb = FgtBridge<CMeshO>::AutoSelfBridging(mesh->cm, holes, infoLabel, distCoeff, 0);
else
nb = FgtBridge<CMeshO>::AutoMultiBridging(mesh->cm, holes, infoLabel, distCoeff, 0);
countSelected();
emit SGN_ExistBridge( nb>0 );
emit layoutChanged();
}
void HoleListModel::removeBridges()
{
FgtBridge<CMeshO>::RemoveBridges(mesh->cm, holes);
countSelected();
emit SGN_ExistBridge(false);
emit layoutChanged();
}
void HoleListModel::acceptBridges()
{
FgtBridge<CMeshO>::AcceptBridges(holes);
state = HoleListModel::Selection;
emit SGN_ExistBridge(false);
}
void HoleListModel::closeNonManifolds()
{
if (FgtBridge<CMeshO>::CloseNonManifoldVertex(mesh->cm, holes) > 0 )
{
countSelected();
emit SGN_ExistBridge(true);
}
emit layoutChanged();
}
void HoleListModel::countSelected()
{
nSelected = 0;
HoleVector::iterator hit = holes.begin();
for( ; hit!=holes.end(); hit++)
if(hit->IsSelected())
nSelected++;
}
/************* Implementazione QAbstractItemModel class *****************/
QVariant HoleListModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid() )
return QVariant();
if(role == Qt::DisplayRole)
{
switch(index.column())
{
case 0:
return holes[index.row()].name;
case 1:
return holes.at(index.row()).Size();
case 2:
return QString("%1").arg(holes.at(index.row()).Perimeter(), 0, 'f', 5);
}
}
else if (role == Qt::TextAlignmentRole)
{
if(index.column() == 0) return Qt::AlignLeft;
if(index.column() == 1 ||
index.column() == 2) return Qt::AlignRight;
return Qt::AlignCenter;
}
else if (role == Qt::CheckStateRole)
{
bool checked;
if(index.column() == 3)
checked = holes[index.row()].IsNonManifold();
else if(index.column() == 4)
checked = holes[index.row()].IsSelected();
else if(state == HoleListModel::Filled && holes[index.row()].IsSelected())
{
if(index.column() == 5)
checked = holes[index.row()].IsCompenetrating();
else if(index.column() == 6)
checked = holes[index.row()].IsAccepted();
else
return QVariant();
}
else
return QVariant();
if(checked)
return Qt::Checked;
else
return Qt::Unchecked;
}
return QVariant();
}
QVariant HoleListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch(section)
{
case 0:
return tr("Hole");
case 1:
return tr("Edges");
case 2:
return tr("Perimeter");
case 3:
return tr("Non Manif.");
case 4:
if(state == HoleListModel::Filled)
return tr("Fill");
else
return tr("Select");
case 5:
if(state == HoleListModel::Filled)
return tr("Comp.");
case 6:
if(state == HoleListModel::Filled)
return tr("Accept");
}
}
else if (orientation == Qt::Horizontal && role == Qt::SizeHintRole)
{
switch(section)
{
case 0:
return QSize(63, 20);
case 1:
return QSize(38, 20);
case 2:
return QSize(55, 20);
case 3:
return QSize(60, 20);
case 4:
if(state == HoleListModel::Filled)
return QSize(20, 20);
else
return QSize(50, 20);
case 5:
return QSize(38, 20);
case 6:
return QSize(42, 20);
}
}
else if (orientation == Qt::Horizontal && role == Qt::ToolTip && state==HoleListModel::Filled && section == 4)
return tr("Compenetration");
return QVariant();
}
QModelIndex HoleListModel::index(int row, int column, const QModelIndex &parent) const
{
if(row >= (int)holes.size())
return QModelIndex();
return createIndex(row,column, 0);
}
Qt::ItemFlags HoleListModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags ret = QAbstractItemModel::flags(index);
if (!index.isValid())
return Qt::ItemIsEnabled;
if(index.column() == 0)
ret = ret | Qt::ItemIsEditable;
else if( (index.column() == 4 && state == HoleListModel::Selection) ||
(index.column() == 6 && state == HoleListModel::Filled) )
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
//return ret = ret | Qt::ItemIsUserCheckable ;
return ret;
}
bool HoleListModel::setData( const QModelIndex & index, const QVariant & value, int role )
{
if(!index.isValid())
return false;
bool ret = false;
if(role == Qt::EditRole && index.column() == 0)
{
QString newName = value.toString().trimmed();
if(newName != "")
{
holes[index.row()].name = newName;
ret = true;
}
}
else if(role == Qt::CheckStateRole)
{
if(state == HoleListModel::Selection)
{
if(index.column() == 4 && state == HoleListModel::Selection)
{
holes[index.row()].SetSelect( !holes[index.row()].IsSelected() );
if(holes[index.row()].IsSelected() ) nSelected++;
else nSelected--;
ret = true;
}
}
else if(index.column() == 6)
{ // check accept
holes[index.row()].SetAccepted( !holes[index.row()].IsAccepted() );
if(holes[index.row()].IsAccepted() ) nAccepted++;
else nAccepted--;
ret = true;
}
}
if(ret)
{
emit dataChanged(index, index);
emit SGN_needUpdateGLA();
}
return ret;
}
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* 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. *
* *
****************************************************************************/
#include "holeListModel.h"
using namespace vcg;
HoleListModel::HoleListModel(MeshModel *m, QObject *parent)
: QAbstractItemModel(parent)
{
state = HoleListModel::Selection;
mesh = m;
pickedAbutment.SetNull();
mesh->clearDataMask(MeshModel::MM_FACEFLAGBORDER);
mesh->updateDataMask(MeshModel::MM_FACEFACETOPO);
mesh->updateDataMask(MeshModel::MM_FACEFLAGBORDER);
holesManager.Init(&m->cm);
emit dataChanged( index(0, 0), index(holesManager.HolesCount(), 2) );
emit SGN_needUpdateGLA();
}
void HoleListModel::drawHoles() const
{
glLineWidth(2.0f);
glDepthMask(GL_TRUE);
glDepthFunc(GL_GREATER);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
HoleVector::const_iterator it = holesManager.holes.begin();
for( ; it != holesManager.holes.end(); ++it)
{
if( it->IsSelected())
{
if(it->IsAccepted())
glColor(Color4b::DarkGreen);
else
glColor(Color4b::DarkRed);
}
else
glColor(Color4b::DarkBlue);
it->Draw();
}
// draw the edge selected as a bridge abutment in manual-bridging
if(!pickedAbutment.IsNull())
{
glDepthFunc(GL_ALWAYS);
glLineWidth(2.0f);
glColor(Color4b::Yellow);
glBegin(GL_LINES);
glVertex( pickedAbutment.f->V0(pickedAbutment.z)->P() );
glVertex( pickedAbutment.f->V1(pickedAbutment.z)->P() );
glEnd();
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glLineWidth(2.0f);
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
{
if(it->IsSelected())
{
if(it->IsAccepted())
glColor(Color4b::Green);
else
glColor(Color4b::Red);
}
else
glColor(Color4b::Blue);
it->Draw();
}
}
void HoleListModel::drawCompenetratingFaces() const
{
glDisable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glDisable(GL_LIGHTING);
glColor3f(0.8f, 0.8f, 0.f);
// draw face border also behind other face
HoleVector::const_iterator it;
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_LINE_LOOP);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// draw compenetrating face, only the visible part
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_TRIANGLES);
// draw face border only visible part
glLineWidth(4.0f);
glColor3f(1.0f, 1.0f, 0.f);
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_LINE_LOOP);
}
void HoleListModel::toggleSelectionHoleFromFace(CFaceO *bface)
{
assert(holesManager.IsHoleBorderFace(bface));
HoleVector::iterator h;
int ind = holesManager.FindHoleFromFace(bface, h);
if( ind == -1)
return;
h->SetSelect( !h->IsSelected() );
emit dataChanged( index(ind, 4), index(ind, 4) );
emit SGN_needUpdateGLA();
}
void HoleListModel::toggleAcceptanceHole(CFaceO *bface)
{
assert(state == HoleListModel::Filled);
HoleVector::iterator h;
int ind = holesManager.FindHoleFromFace(bface, h);
if(ind == -1)
return;
h->SetAccepted( !h->IsAccepted() );
emit dataChanged( index(ind, 6), index(ind, 6) );
emit SGN_needUpdateGLA();
}
void HoleListModel::addBridgeFace(CFaceO *pickedFace, int pickedX, int pickedY)
{
BridgeAbutment<CMeshO> picked;
if (!holesManager.FindBridgeAbutmentFromPick(pickedFace, pickedX, pickedY, picked))
return;
// reselect an already selected edge... deselect
if(pickedAbutment.f == picked.f && pickedAbutment.z == picked.z )
{
pickedAbutment.SetNull();
return;
}
if(pickedAbutment.IsNull() || pickedAbutment.f == picked.f)
pickedAbutment = picked;
else
{
// 2 edge selected... bridge building
std::vector<CMeshO::FacePointer *> local_facePointer;
local_facePointer.push_back(&pickedAbutment.f);
local_facePointer.push_back(&picked.f);
if(FgtBridge<CMeshO>::CreateBridge(pickedAbutment, picked, &holesManager, &local_facePointer))
{
emit SGN_ExistBridge(true);
emit layoutChanged();
}
else
QMessageBox::warning(0, tr("Bridge autocompenetration"), QString("Bridge is compenetrating with mesh."));
pickedAbutment.SetNull();
}
}
void HoleListModel::fill(FgtHole<CMeshO>::FillerMode mode)
{
if(holesManager.Fill(mode))
{
state = HoleListModel::Filled;
emit layoutChanged();
}
}
void HoleListModel::acceptFilling(bool accept)
{
holesManager.ConfirmFilling(accept);
state = HoleListModel::Selection;
emit dataChanged( index(0, 0), index(holesManager.HolesCount(), 2) );
emit SGN_needUpdateGLA();
emit layoutChanged();
}
void HoleListModel::autoBridge(bool singleHole, double distCoeff)
{
holesManager.DiscardBridges();
int nb=0;
if(singleHole)
nb = holesManager.AutoSelfBridging(distCoeff, 0);
else
nb = holesManager.AutoMultiBridging(distCoeff, 0);
emit SGN_ExistBridge( nb>0 );
emit layoutChanged();
}
void HoleListModel::removeBridges()
{
holesManager.DiscardBridges();
emit SGN_ExistBridge(false);
emit layoutChanged();
}
void HoleListModel::acceptBridges()
{
holesManager.ConfirmBridges();
emit SGN_ExistBridge(false);
}
void HoleListModel::closeNonManifolds()
{
if (holesManager.CloseNonManifoldHoles())
emit SGN_ExistBridge(true);
emit layoutChanged();
}
/************* Implementazione QAbstractItemModel class *****************/
QVariant HoleListModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid() )
return QVariant();
if(role == Qt::DisplayRole)
{
switch(index.column())
{
case 0:
return holesManager.holes[index.row()].name;
case 1:
return holesManager.holes.at(index.row()).Size();
case 2:
return QString("%1").arg(holesManager.holes.at(index.row()).Perimeter(), 0, 'f', 5);
}
}
else if (role == Qt::TextAlignmentRole)
{
if(index.column() == 0) return Qt::AlignLeft;
if(index.column() == 1 ||
index.column() == 2) return Qt::AlignRight;
return Qt::AlignCenter;
}
else if (role == Qt::CheckStateRole)
{
bool checked;
if(index.column() == 3)
checked = holesManager.holes[index.row()].IsNonManifold();
else if(index.column() == 4)
checked = holesManager.holes[index.row()].IsSelected();
else if(state == HoleListModel::Filled && holesManager.holes[index.row()].IsSelected())
{
if(index.column() == 5)
checked = holesManager.holes[index.row()].IsCompenetrating();
else if(index.column() == 6)
checked = holesManager.holes[index.row()].IsAccepted();
else
return QVariant();
}
else
return QVariant();
if(checked)
return Qt::Checked;
else
return Qt::Unchecked;
}
return QVariant();
}
QVariant HoleListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch(section)
{
case 0:
return tr("Hole");
case 1:
return tr("Edges");
case 2:
return tr("Perimeter");
case 3:
return tr("Non Manif.");
case 4:
if(state == HoleListModel::Filled)
return tr("Fill");
else
return tr("Select");
case 5:
if(state == HoleListModel::Filled)
return tr("Comp.");
case 6:
if(state == HoleListModel::Filled)
return tr("Accept");
}
}
else if (orientation == Qt::Horizontal && role == Qt::SizeHintRole)
{
switch(section)
{
case 0:
return QSize(63, 20);
case 1:
return QSize(38, 20);
case 2:
return QSize(55, 20);
case 3:
return QSize(60, 20);
case 4:
if(state == HoleListModel::Filled)
return QSize(20, 20);
else
return QSize(50, 20);
case 5:
return QSize(38, 20);
case 6:
return QSize(42, 20);
}
}
else if (orientation == Qt::Horizontal && role == Qt::ToolTip && state==HoleListModel::Filled && section == 4)
return tr("Compenetration");
return QVariant();
}
QModelIndex HoleListModel::index(int row, int column, const QModelIndex &/*parent*/) const
{
if(row >= (int)holesManager.holes.size())
return QModelIndex();
return createIndex(row,column, 0);
}
Qt::ItemFlags HoleListModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags ret = QAbstractItemModel::flags(index);
if (!index.isValid())
return Qt::ItemIsEnabled;
if(index.column() == 0)
ret = ret | Qt::ItemIsEditable;
else if( (index.column() == 4 && state == HoleListModel::Selection) ||
(index.column() == 6 && state == HoleListModel::Filled) )
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
//return ret = ret | Qt::ItemIsUserCheckable ;
return ret;
}
bool HoleListModel::setData( const QModelIndex & index, const QVariant & value, int role )
{
if(!index.isValid())
return false;
bool ret = false;
if(role == Qt::EditRole && index.column() == 0)
{
QString newName = value.toString().trimmed();
if(newName != "")
{
holesManager.holes[index.row()].name = newName;
ret = true;
}
}
else if(role == Qt::CheckStateRole)
{
if(state == HoleListModel::Selection)
{
if(index.column() == 4 && state == HoleListModel::Selection)
{
holesManager.holes[index.row()].SetSelect( !holesManager.holes[index.row()].IsSelected() );
ret = true;
}
}
else if(index.column() == 6)
{ // check accept
holesManager.holes[index.row()].SetAccepted( !holesManager.holes[index.row()].IsAccepted() );
ret = true;
}
}
if(ret)
{
emit dataChanged(index, index);
emit SGN_needUpdateGLA();
}
return ret;
}

View File

@ -26,14 +26,14 @@
#include <QWidget>
#include <QHeaderView>
#include <QtGui>
#include "meshlab/meshmodel.h"
#include "fgtHole.h"
#include "fgtBridge.h"
#include <meshlab/meshmodel.h>
#include <meshlab/interfaces.h>
#include "vcg/simplex/face/pos.h"
#include "vcg/complex/trimesh/base.h"
#include "vcg/space/color4.h"
#include "holeSetManager.h"
/* This class is the "model" of model-view architecture, so it implements methods to esposes data
* informations about holes as QAbstractItemModel says.
*/
class HoleListModel : public QAbstractItemModel
{
Q_OBJECT
@ -44,28 +44,21 @@ public:
Selection, ManualBridging, Filled
};
typedef vcg::tri::Hole<CMeshO> vcgHole;
typedef vcg::tri::Hole<CMeshO>::Info HoleInfo;
typedef FgtHole<CMeshO> HoleType;
typedef std::vector< HoleType > HoleVector;
typedef FgtBridge<CMeshO> BridgeType;
typedef std::vector< BridgeType > BridgeVector;
typedef vcg::face::Pos<CMeshO::FaceType> PosType;
typedef std::vector< PosType > PosVector;
typedef PosVector::iterator PosIterator;
typedef FgtHole<CMeshO> HoleType;
typedef std::vector< HoleType > HoleVector;
HoleListModel(MeshModel *m, QObject *parent = 0);
virtual ~HoleListModel() { clearModel(); };
virtual ~HoleListModel() { holesManager.Clear(); };
inline int rowCount(const QModelIndex &parent = QModelIndex()) const { return holes.size(); };
inline int columnCount(const QModelIndex &parent = QModelIndex()) const
inline int rowCount(const QModelIndex &/*parent = QModelIndex()*/) const { return holesManager.HolesCount(); };
inline int columnCount(const QModelIndex &/*parent = QModelIndex()*/) const
{
if(state == HoleListModel::Selection) return 5;
else return 7;
};
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &child) const { return QModelIndex(); };
QModelIndex parent(const QModelIndex &/*child*/) const { return QModelIndex(); };
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
@ -74,15 +67,12 @@ public:
bool setData( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole );
inline int getUserBitHole() const { return userBitHole; };
void clearModel();
void updateModel();
void drawHoles() const;
void drawCompenetratingFaces() const;
inline void setState(HoleListModel::FillerState s) { state = s; emit layoutChanged(); };
inline FillerState getState() const { return state; };
void toggleSelectionHoleFromBorderFace(CFaceO *bface);
void toggleSelectionHoleFromFace(CFaceO *bface);
void toggleAcceptanceHole(CFaceO *bface);
void fill(FgtHole<CMeshO>::FillerMode mode);
void acceptFilling(bool accept=true);
@ -91,31 +81,26 @@ public:
void closeNonManifolds();
inline MeshModel* getMesh() const { return mesh; };
void autoBridge(bool singleHole=false, double distCoeff=0, QLabel *infoLabel=0);
void autoBridge(bool singleHole=false, double distCoeff=0);
inline bool PickedAbutment() const {return !pickedAbutment.IsNull(); };
inline void setStartBridging()
{
assert(state != HoleListModel::Filled);
state = HoleListModel::ManualBridging ;
};
inline void setEndBridging() { state = HoleListModel::Selection; pickedAbutment.f = 0; };
inline void setEndBridging() { state = HoleListModel::Selection; pickedAbutment.SetNull(); };
void addBridgeFace(CFaceO *pickedFace, int pickX, int pickY);
void countSelected();
inline int SelectionCount() const { return nSelected; };
inline int HolesCount() const { return holes.size(); };
inline int AcceptedCount() const { return nAccepted; };
inline bool PickedAbutment() const {return !pickedAbutment.IsNull(); };
private:
MeshModel *mesh;
FillerState state;
int userBitHole;
BridgeAbutment<CMeshO> pickedAbutment;
int nSelected;
int nAccepted;
public:
HoleVector holes;
HoleSetManager<CMeshO> holesManager;
Q_SIGNALS:
void SGN_needUpdateGLA();

View File

@ -0,0 +1,376 @@
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* 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 HOLESETMANAGER_H
#define HOLESETMANAGER_H
#include "fgtHole.h"
#include "fgtBridge.h"
#include "vcg/complex/trimesh/hole.h"
#include <vcg/container/simple_temporary_data.h>
/* HoleSetManager class rappresent an entity which manages the holes 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
* additional data used by holes to mark its "characteristic" faces.
*/
template <class MESH>
class HoleSetManager
{
enum FaceAttribute
{
NONE = 0x0000,
BORDER = 0x0001,
PATCH = 0x0002,
COMPENET = 0x0004,
BRIDGE = 0x0020
};
typedef FgtHole< MESH > HoleType;
typedef typename std::vector< HoleType > HoleVector;
typedef typename HoleVector::iterator HoleIterator;
typedef typename MESH::FaceType FaceType;
typedef typename MESH::FacePointer FacePointer;
typedef typename MESH::FaceContainer FaceContainer;
typedef typename vcg::tri::Hole<MESH> vcgHole;
typedef typename vcgHole::Info HoleInfo;
typedef typename vcg::face::Pos<FaceType> PosType;
typedef typename vcg::SimpleTempData<FaceContainer, int> SimpleData;
typedef typename HoleType::FillerMode FillerMode;
public:
HoleSetManager()
{
autoBridgeCB = 0;
};
void Init(MESH* m)
{
nAccepted = nSelected = 0;
mesh = m;
faceAttr = new SimpleData (m->face, NONE);
getMeshHoles();
};
void Clear()
{
typename HoleVector::iterator it;
for(it=holes.begin(); it!=holes.end(); it++)
it->ResetFlag();
holes.clear();
};
/***************** PerFace additional data ********************/
inline bool IsHoleBorderFace(FacePointer f) const { return ( (*faceAttr)[f] & BORDER) != 0; };
inline bool IsPatchFace(FacePointer f) const { return ((*faceAttr)[f] & PATCH) != 0; };
inline bool IsCompFace(FacePointer f) const { return ((*faceAttr)[f] & COMPENET) != 0; };
inline bool IsBridgeFace(FacePointer f) const { return ((*faceAttr)[f] & BRIDGE) != 0; };
inline void SetHoleBorderAttr(FacePointer f) { (*faceAttr)[f] |= BORDER; };
inline void ClearHoleBorderAttr(FacePointer f) { (*faceAttr)[f] &= (~BORDER); };
inline void SetPatchAttr(FacePointer f) { (*faceAttr)[f] |= PATCH; };
inline void ClearPatchAttr(FacePointer f) { (*faceAttr)[f] &= (~PATCH); }
inline void SetCompAttr(FacePointer f) { (*faceAttr)[f] |= COMPENET; };
inline void ClearCompAttr(FacePointer f) { (*faceAttr)[f] &= (~COMPENET); };
inline void SetBridgeAttr(FacePointer f){ (*faceAttr)[f] |= BRIDGE; };
inline void ClearBridgeAttr(FacePointer f){ (*faceAttr)[f] &= (~BRIDGE); };
/**************** Statistical info *****************/
inline int SelectionCount() const { return nSelected; };
inline int HolesCount() const { return holes.size(); };
inline int AcceptedCount() const { return nAccepted; };
/**************** Holes editing ********************/
bool Fill(FillerMode mode)
{
if(nSelected==0)
return false;
std::vector<FacePointer *> local_facePointer;
HoleType::AddFaceReference(holes, local_facePointer);
HoleIterator it = holes.begin();
for( ; it != holes.end(); it++ )
if( it->IsSelected() )
it->Fill(mode, *mesh, local_facePointer);
nAccepted=nSelected;
return true;
};
void ConfirmFilling(bool accept)
{
nSelected=0;
HoleIterator it = holes.begin();
while( it != holes.end() )
{
if( it->IsFilled() )
{
if( (it->IsSelected() && !it->IsAccepted()) || !accept)
{
if( it->IsFilled() )
{
it->RestoreHole();
nSelected++;
}
}
else if( it->IsSelected() && it->IsAccepted() )
{
it->ResetFlag();
it = holes.erase(it);
continue;
}
}
it++;
}
countSelected();
};
inline void ConfirmBridges()
{
FgtBridge<CMeshO>::AcceptBridges(this);
};
inline void DiscardBridges()
{
FgtBridge<CMeshO>::RemoveBridges(this);
countSelected();
};
bool CloseNonManifoldHoles()
{
return (FgtBridge<CMeshO>::CloseNonManifoldVertex(this) >0);
};
int AutoSelfBridging(double distCoeff, std::vector<FacePointer*> *facesRef)
{
int n = FgtBridge<CMeshO>::AutoSelfBridging(this, distCoeff, facesRef);
countSelected();
return n;
};
int AutoMultiBridging(double distCoeff, std::vector<FacePointer*> *facesRef)
{
int n = FgtBridge<CMeshO>::AutoMultiBridging(this, distCoeff, facesRef);
countSelected();
return n;
};
/** 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 index = 0;
// it know if bFace is adjacent to patchFace
FacePointer patchF = 0;
if(IsPatchFace(bFace))
patchF = bFace;
else
{
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;
}
index++;
}
}
it = holes.end(); // invalid iterator
return -1;
};
/** Return boolean indicatind if the picking have select a border face which can be used
* as abutment for a bridge. If true it also return BridgeAbutment allowing to know
* border edge and its relative hole.
*/
bool FindBridgeAbutmentFromPick( FacePointer bFace, int pickedX, int pickedY,
BridgeAbutment<MESH> &pickedResult)
{
if( vcg::face::BorderCount(*bFace) == 0 )
return false;
HoleIterator hit;
if( FindHoleFromFace(bFace, hit) < 0 )
{
pickedResult.SetNull();
return false;
}
pickedResult.h = &*hit;
pickedResult.f = bFace;
if( vcg::face::BorderCount(*bFace) == 1 )
{
// it choose the only one border edge
for(int i=0; i<3; i++)
if(vcg::face::IsBorder<FaceType>(*bFace, i))
pickedResult.z = i;
}
else
{
// looking for the closest border edge to pick point
PosType retPos = getClosestPos(bFace, pickedX, pickedY);
pickedResult.f = retPos.f;
pickedResult.z = retPos.z;
}
return true;
};
private:
/* Inspect a mesh to find its holes. */
void getMeshHoles()
{
holes.clear();
std::vector<HoleInfo> vhi;
//prendo la lista di info(sugli hole) tutte le facce anche le non selezionate
FaceType::NewBitFlag();
int borderFlag = vcgHole::GetInfo(*mesh, false, vhi);
HoleType::ResetHoleId();
typename std::vector<HoleInfo>::iterator itH = vhi.begin();
for( ; itH != vhi.end(); itH++)
{
holes.push_back(HoleType(*itH, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), this));
// reset flag and setting of
PosType curPos = itH->p;
do{
curPos.f->ClearUserBit(borderFlag);
SetHoleBorderAttr(curPos.f);
curPos.NextB();
assert(curPos.IsBorder());
}while( curPos != itH->p );
}
FaceType::DeleteBitFlag(borderFlag);
};
/* Return border half-edge of the same face which is nearest to point(x, y) of glArea.
*/
static PosType getClosestPos(FaceType* face, int x, int y)
{
double mvmatrix[16], projmatrix[16];
GLint viewport[4];
double rx, ry, rz;
vcg::Point2d vertex[3];
vcg::Point2d point((double)x, (double)y);
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
glGetIntegerv(GL_VIEWPORT, viewport);
for(int i=0; i<3; i++)
{
gluProject(face->V(i)->P()[0],face->V(i)->P()[1],face->V(i)->P()[2],mvmatrix,projmatrix,viewport,&rx,&ry,&rz);
vertex[i] = vcg::Point2d(rx,ry);
}
double dist = DBL_MAX;
int nearest = 0;
for(int i=0; i<3; i++)
{
if(!vcg::face::IsBorder<FaceType>(*face, i))
continue;
vcg::Line2d el(vertex[i], vertex[(i+1)%3]-vertex[i]);
double tmp = vcg::Distance(el, point);
if(dist > tmp)
{
dist = tmp;
nearest = i;
}
}
return PosType(face, nearest, face->V(nearest) );
};
void HoleSetManager::countSelected()
{
nSelected = 0;
HoleIterator hit = holes.begin();
for( ; hit!=holes.end(); hit++)
if(hit->IsSelected())
nSelected++;
};
public:
int nSelected;
int nAccepted;
MESH* mesh;
HoleVector holes;
SimpleData* faceAttr;
AutoBridgingCallback* autoBridgeCB;
};
#endif