first working implementationof "EAR HOLE FILLING".

This commit is contained in:
Paolo Cignoni 2006-10-06 15:28:14 +00:00
parent d878081824
commit 2daa4cdd9b
1 changed files with 685 additions and 580 deletions

View File

@ -21,9 +21,12 @@
* *
****************************************************************************/
/****************************************************************************
History
History
$Log: not supported by cvs2svn $
Revision 1.4 2006/10/02 12:06:40 giec
BugFix
Revision 1.3 2006/09/27 15:33:32 giec
It close one simple hole . . .
@ -43,11 +46,11 @@ Questa Classe serve per gestire la non duplicazione degli edge durante la chiusu
di un buco.
*/
namespace vcg {
namespace tri {
namespace tri {
template<class MESH>
class SimpleEdge
{
template<class MESH>
class SimpleEdge
{
public:
typename MESH::VertexType v[2];
SimpleEdge()
@ -88,12 +91,12 @@ class SimpleEdge
else return false;
}
};
};
template<class MESH>
class HoleInfo
{
public:
template<class MESH>
class HoleInfo
{
public:
HoleInfo(){}
HoleInfo(face::Pos<typename MESH::FaceType> const &pHole, int const pHoleSize, vcg::Box3<typename MESH::ScalarType> &pHoleBB)
{
@ -101,9 +104,25 @@ public:
size=pHoleSize;
bb=pHoleBB;
}
HoleInfo(face::Pos<typename MESH::FaceType> const &pHole, int const pHoleSize, vcg::Box3<typename MESH::ScalarType> &pHoleBB, int FI)
{
p=pHole;
size=pHoleSize;
bb=pHoleBB;
faceindex = FI;
}
typename face::Pos<typename MESH::FaceType> p;
int size;
vcg::Box3<typename MESH::ScalarType> bb;
int faceindex;
void Refresh(MESH &m)
{
p.f = (MESH::FacePointer)(faceindex + &(*(m.face.begin())));
}
bool operator < (const HoleInfo & hh) const {return size < hh.size;}
bool operator > (const HoleInfo & hh) const {return size > hh.size;}
@ -112,7 +131,7 @@ public:
bool operator >= (const HoleInfo & hh) const {return size >= hh.size;}
bool operator <= (const HoleInfo & hh) const {return size <= hh.size;}
typename MESH::ScalarType Perimeter()
typename MESH::ScalarType Perimeter()
{
MESH::ScalarType sum=0;
face::Pos<typename MESH::FaceType> ip = p;
@ -158,11 +177,11 @@ typename MESH::ScalarType Perimeter()
return EV.size();
}
};
};
template<class MESH>
void FindHole(MESH &m, face::Pos<typename MESH::FaceType> ep, HoleInfo<MESH> &h)
{
template<class MESH>
void FindHole(MESH &m, face::Pos<typename MESH::FaceType> ep, HoleInfo<MESH> &h)
{
if(!ep.IsBorder()) return;
int holesize = 0;
@ -180,11 +199,11 @@ void FindHole(MESH &m, face::Pos<typename MESH::FaceType> ep, HoleInfo<MESH> &h)
}
while (ep != init);
h=HoleInfo<MESH>(ep,holesize,hbox);
}
}
template<class MESH,class STL_CONTAINER_HOLES>
void FindHole(MESH &m, STL_CONTAINER_HOLES & H)
{
template<class MESH,class STL_CONTAINER_HOLES>
void FindHole(MESH &m, STL_CONTAINER_HOLES & H)
{
MESH::FaceIterator pf;
int holesize;
for (pf=m.face.begin(); pf!=m.face.end(); ++pf)
@ -220,11 +239,11 @@ void FindHole(MESH &m, STL_CONTAINER_HOLES & H)
}
}
}
};
};
/*
Un ear e' identificato da due hedge pos.
/*
Un ear e' identificato da due hedge pos.
i vertici dell'ear sono
e0.FlipV().v
@ -234,22 +253,22 @@ Un ear e' identificato da due hedge pos.
Vale che e1== e0.NextB();
e che e1.FlipV() == e0;
Situazioni ear non manifold, e degeneri (buco triangolare)
Situazioni ear non manifold, e degeneri (buco triangolare)
T XXXXXXXXXXXXX A /XXXXX B en/XXXXX
/XXXXXXXXXXXXXXX /XXXXXX /XXXXXX
XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX
XXXXXX ----/| XX ------ ----/| XX ------ ----/|XXX
XXXXXX| /e1 XX XXXXXX| /e1 XX XXXXXX| o/e0 XX
XXXXXX| /XXXXXX XXXXXX| /XXXXXX XXXXXX| /XXXXXX
XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX
XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
/XXXXXXXXXXXXXXX /XXXXXX /XXXXXX
XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX
XXXXXX ----/| XX ------ ----/| XX ------ ----/|XXX
XXXXXX| /e1 XX XXXXXX| /e1 XX XXXXXX| o/e0 XX
XXXXXX| /XXXXXX XXXXXX| /XXXXXX XXXXXX| /XXXXXX
XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX
XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX
*/
template<class MSH_TYPE> class TrivialEar
{
*/
template<class MSH_TYPE> class TrivialEar
{
public:
face::Pos<typename MSH_TYPE::FaceType> e0; //
face::Pos<typename MSH_TYPE::FaceType> e1; //
@ -315,7 +334,7 @@ template<class MSH_TYPE> class TrivialEar
face::Pos<typename MSH_TYPE::FaceType> en=e1; en.NextB(); // he successivo a e1
// caso ear degenere per buco triangolare
if(ep==en) return true;
if(ep==en) return true;//provo a togliere sto controllo
// Caso ear non manifold a
if(ep.v==en.v) return true;
// Caso ear non manifold b
@ -403,89 +422,111 @@ template<class MSH_TYPE> class TrivialEar
return true;
}
};
};
// Funzione principale per chiudier un buco in maniera topologicamente corretta.
// Gestisce situazioni non manifold ragionevoli
// (tutte eccetto quelle piu' di 2 facce per 1 edge).
// Controlla che non si generino nuove situazioni non manifold chiudendo orecchie
// che sottendono un edge che gia'esiste.
//
// Attenzione: se per riaggiungere facce deve riallocare il vettore non funge!!!!
//
template<class MESH, class EAR>
typename MESH::FaceIterator CloseHole(MESH &m, HoleInfo <MESH> &h)
{
// Funzione principale per chiudier un buco in maniera topologicamente corretta.
// Gestisce situazioni non manifold ragionevoli
// (tutte eccetto quelle piu' di 2 facce per 1 edge).
// Controlla che non si generino nuove situazioni non manifold chiudendo orecchie
// che sottendono un edge che gia'esiste.
template<class MESH>
tri::HoleInfo<MESH> getHoleInfo(MESH &m, face::Pos<typename MESH::FaceType> sp,
face::Pos<typename MESH::FaceType> fp,
int UBIT)
{
int holesize=0;
std::vector<SimpleEdge<MESH> > ES;
//set<SimpleEdge<MESH> > ES; // vettore con tutti gli edge adiacenti al buco.
Box3<MESH::ScalarType> hbox;
hbox.Add(sp.v->cP());
h.CollectEdges(ES);
vector<EAR> H; // Heap delle ear da chiudere
H.reserve(h.size);
do
{
sp.f->SetUserBit(UBIT);
hbox.Add(sp.v->cP());
++holesize;
sp.NextB();
assert(sp.IsBorder());
}while(sp != fp);
int tmp = ((int)(sp.f - &(*(m.face.begin()))));
return tri::HoleInfo<MESH>(sp,holesize,hbox, tmp );
}
template<class MESH,class EAR , class VECTOR_EAR>
void refreshHole(MESH &m, VECTOR_EAR &ve, face::Pos<typename MESH::FaceType> &fp, std::vector<typename MESH::VertexType > &vv)
{
face::Pos<typename MESH::FaceType> ff = fp;
do{
ve.push_back(EAR(fp));
vv.push_back(*fp.v);
fp.NextB();//semmai da provare a sostituire il codice della NextB();
assert(fp.IsBorder());
}while(fp!=ff);
}
template <class MESH, class EAR>
void fillHoleEar(MESH &m, tri::HoleInfo<MESH> &h ,int UBIT)
{
//Aggiungo le facce e aggiorno il puntatore alla faccia!
std::vector<MESH::FacePointer *> app;
app.push_back( &h.p.f );
MESH::FaceIterator f = tri::Allocator<MESH>::AddFaces(m, h.size-2, app);
h.CollectEdges(ES);
assert(h.p.IsBorder());
MESH::FaceIterator f = tri::Allocator<MESH>::AddFaces(m, h.size-2, app);
face::Pos<typename MESH::FaceType> ep=h.p;
h.Refresh(m); //rinfresco il puntatore tramite l'indice precedentemente salvato.
do {
H.push_back(EAR(ep));
ep.f->SetS();
ep.NextB();
assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto!
assert(ep.IsBorder());
} while(ep!=h.p);
std::vector<MESH::VertexType > vv; //vettore di vertici
std::vector<EAR > H; //vettore di orecchie
make_heap(H.begin(),H.end());
H.reserve(h.size);
//prendo le informazioni sul buco
refreshHole<MESH,EAR, std::vector<EAR> >(m,H,h.p,vv);
bool fitted = false;
int cnt=h.size;
MESH::FaceIterator tmp;
while( cnt > 2 && !H.empty() ) //finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare
{
//ordino il vettore di orecchie
//sort(H.begin(), H.end(), greater<EAR>() );//descending
sort(H.begin(), H.end(), less<EAR>() ); //ascending
EAR en0,en1;
MESH::FaceIterator firstf = f;
//SimpleEdge<MESH> se();
while(cnt > 2 && !H.empty())
{
//pop_heap(H.begin(),H.end());
SimpleEdge<MESH> se( *(H.back().e0.VFlip()) , *(H.back().e1.v));
// se.v = p.v;
// se.v[1] = p.v[1];
//Sostituito la funzione find con la ricerca manuale
std::vector<SimpleEdge<MESH> >::iterator it;
it = ES.begin();
while( it != ES.end() &&
se != ((SimpleEdge<MESH> )(*it)) )
MESH::VertexType vfit = *H.back().e0.v;
std::vector<MESH::VertexType >::iterator it;
it = vv.begin();
while( it != vv.end() && (vfit.P() != ((MESH::VertexType )(*it)).P() ) )
{it++; }
//per far funzionare il test sottostante.
MESH::FaceIterator Fadd = f;
if(H.back().IsUpToDate())
{
if(H.back().Degen() && it != ES.end()){
if(H.back().Degen() && it != vv.end()){
// Nota che nel caso di ear degeneri si DEVE permettere la creazione di un edge che gia'esiste
printf("\n -> Evitata orecchia brutta!");
}
else {
if(it == ES.end())
{
//H.back().Close(en0,en1,&*f);
int i = H.size();
}
else
{
if(H.back().Close(en0,en1,&*f))
{
//ES.insert(se);
ES.push_back(se);
/* ES.push_back(se);
if(!en0.IsNull()){
H.push_back(en0);
push_heap( H.begin(), H.end());
@ -493,51 +534,115 @@ typename MESH::FaceIterator CloseHole(MESH &m, HoleInfo <MESH> &h)
if(!en1.IsNull()){
H.push_back(en1);
push_heap( H.begin(), H.end());
}
}*/
--cnt;
tmp = f;
++f;
fitted = true;
}
}
}
if((cnt == 3) && ( H.back().e0.IsBorder() ) )
{
//dovrebbe mancare un triangolo da tappare
if(cnt == 3 && !fitted)
{//ultimo buco o unico buco
if(H.back().Close(en0,en1,&*f))
{
ES.push_back(se);
if(!en0.IsNull()){
H.push_back(en0);
push_heap( H.begin(), H.end());
}
if(!en1.IsNull()){
H.push_back(en1);
push_heap( H.begin(), H.end());
}
--cnt;
tmp = f;
++f;
fitted = true;
}
}
if(fitted && cnt >2)
{
face::Pos<typename MESH::FaceType> ff( &(*tmp) ,2);
//ho inserito il triangolo e devo aggiornare le strutture dati
H.clear();
vv.clear();
tmp->SetUserBit(UBIT);
//ri-prendo le informazioni sul buco
refreshHole<MESH,EAR, std::vector<EAR> >(m,H,ff,vv);
fitted = false;
}
else
{
//non ho messo il triangolo quindi tolgo l'orecchio e continuo
H.pop_back();
}
}//fine del while principale
//Delete the unused faces (caused by non 1-manifold vertexes)
while(f!=m.face.end())
{
(*f).SetD();
++f;
m.fn--;
}
return firstf;
};
/*
Trivial Ear con preferred Normal
*/
template<class MSH_TYPE> class TrivialEarN : public TrivialEar<MSH_TYPE>
{
}
template<class MESH>
void holeFillingEar(MESH &m, int sizeHole,bool Selected = false)
{
MESH::FaceIterator fi;
std::vector<tri::HoleInfo<MESH> > vinfo;
int UBIT = fi->LastBitFlag();
for(fi = m.face.begin(); fi!=m.face.end(); ++fi)
{
if(!(*fi).IsD())
{
if(Selected && !(*fi).IsS())
{
//se devo considerare solo i triangoli selezionati e
//quello che sto considerando non lo e' lo marchio e vado avanti
(*fi).SetUserBit(UBIT);
}
else
{
if( !(*fi).IsUserBit(UBIT) )
{
(*fi).SetUserBit(UBIT);
for(int j =0; j<3 ; ++j)
{
if( (*fi).IsB(j) )
{//Trovato una faccia di bordo non ancora visitata.
face::Pos<typename MESH::FaceType> sp(&*fi, j, (*fi).V(j));
// if(!(*fi).IsR())return;
tri::HoleInfo<MESH> HI = getHoleInfo<MESH>(m,sp,sp, UBIT);
//ho recuperato l'inofrmazione su tutto il buco
vinfo.push_back(HI);
}
}//for sugli edge del triangolo
}//se e' gia stato visitato
}//S & !S
}//!IsD()
}//for principale!!!
std::vector<tri::HoleInfo<MESH> >::iterator ith;
tri::HoleInfo<MESH> app;
for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith)
{
app=(tri::HoleInfo<MESH>)*ith;
if(app.size < sizeHole){
//app.Refresh(m);//non so se serve
fillHoleEar<MESH, typename tri::TrivialEar<MESH> >(m, app,UBIT);
}
}
for(fi = m.face.begin(); fi!=m.face.end(); ++fi)
{
if(!(*fi).IsD())
(*fi).ClearUserBit(UBIT);
}
}
/*
Trivial Ear con preferred Normal
*/
template<class MSH_TYPE> class TrivialEarN : public TrivialEar<MSH_TYPE>
{
public:
TrivialEarN(){}
@ -565,14 +670,14 @@ template<class MSH_TYPE> class TrivialEarN : public TrivialEar<MSH_TYPE>
};
};
};
/* 2d Triangulation Code */
class Triangulate2D
{
/* 2d Triangulation Code */
class Triangulate2D
{
static double Area(const vector<Point2d> &contour)
{
static double Area(const vector<Point2d> &contour)
{
int n = contour.size();
double A=0.0f;
@ -581,18 +686,18 @@ static double Area(const vector<Point2d> &contour)
A+= contour[p].X()*contour[q].Y() - contour[q].X()*contour[p].Y();
}
return A*0.5f;
}
}
/*
InsideTriangle decides if a point P is Inside of the triangle
defined by A, B, C.
*/
static bool InsideTriangle(double Ax, double Ay,
static bool InsideTriangle(double Ax, double Ay,
double Bx, double By,
double Cx, double Cy,
double Px, double Py)
{
{
double ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
double cCROSSap, bCROSScp, aCROSSbp;
@ -608,10 +713,10 @@ static bool InsideTriangle(double Ax, double Ay,
bCROSScp = bx*cpy - by*cpx;
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
};
};
static bool Snip(const vector<Point2d> &contour,int u,int v,int w,int n,int *V)
{
static bool Snip(const vector<Point2d> &contour,int u,int v,int w,int n,int *V)
{
int p;
double Ax, Ay, Bx, By, Cx, Cy, Px, Py;
const double epsilon =1e-2;
@ -636,10 +741,10 @@ static bool Snip(const vector<Point2d> &contour,int u,int v,int w,int n,int *V)
}
return true;
}
public:
static bool Process(const vector<Point2d> &contour,vector<int> &result)
{
}
public:
static bool Process(const vector<Point2d> &contour,vector<int> &result)
{
/* allocate and initialize list of Vertices in polygon */
int n = contour.size();
@ -709,9 +814,9 @@ static bool Process(const vector<Point2d> &contour,vector<int> &result)
delete V;
return true;
}
}
};
} // end namespace
};
} // end namespace
}
#endif