Heavily changed the whole hole filling class, now much shorter, more readable and hopefully more robust.
Still to better balance shape vs diedral angle quality measure.
This commit is contained in:
parent
0edde01197
commit
f3ef64cc0c
|
|
@ -19,120 +19,6 @@
|
||||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||||
* for more details. *
|
* for more details. *
|
||||||
* *
|
* *
|
||||||
****************************************************************************/
|
|
||||||
/****************************************************************************
|
|
||||||
History
|
|
||||||
|
|
||||||
$Log: not supported by cvs2svn $
|
|
||||||
Revision 1.34 2007/01/31 15:25:49 giec
|
|
||||||
Remove some usless code in Minimum Weight Triangulation.
|
|
||||||
|
|
||||||
Revision 1.33 2007/01/31 11:46:12 giec
|
|
||||||
Bug fix
|
|
||||||
|
|
||||||
Revision 1.32 2007/01/18 18:15:14 cignoni
|
|
||||||
added missing typenames
|
|
||||||
|
|
||||||
Revision 1.31 2007/01/18 11:17:43 giec
|
|
||||||
The minimum weight algorithm keep the topology consistent.
|
|
||||||
|
|
||||||
Revision 1.30 2007/01/10 12:07:54 giec
|
|
||||||
Bugfixed ComputeDihedralAngle function
|
|
||||||
|
|
||||||
Revision 1.29 2006/12/27 15:09:52 giec
|
|
||||||
Bug fix on ComputeDihedralAngle function
|
|
||||||
|
|
||||||
Revision 1.28 2006/12/12 11:14:51 cignoni
|
|
||||||
Commented some variant of the quality measure of weighted ears
|
|
||||||
|
|
||||||
Revision 1.27 2006/12/07 00:40:18 cignoni
|
|
||||||
Added many this-> for gcc compiling
|
|
||||||
|
|
||||||
Revision 1.26 2006/12/06 13:03:59 cignoni
|
|
||||||
Corrected bugs on selfintersection
|
|
||||||
|
|
||||||
Revision 1.25 2006/12/06 00:12:53 cignoni
|
|
||||||
Heavily restructured and corrected. Now a single Close ear function
|
|
||||||
Corrected Hole search function, and management of double non manifold vertex in a hole
|
|
||||||
Changed priority strategy in the heap, now a mix of quality and dihedral angle.
|
|
||||||
Changed but still untested IntersectionEar
|
|
||||||
|
|
||||||
Revision 1.24 2006/12/01 21:24:16 cignoni
|
|
||||||
Corrected bug in the search of holes. Removed output prints
|
|
||||||
|
|
||||||
Revision 1.23 2006/12/01 08:53:55 cignoni
|
|
||||||
Corrected pop_heap vs pop_back issue in heap usage
|
|
||||||
|
|
||||||
Revision 1.22 2006/12/01 00:11:17 cignoni
|
|
||||||
Added Callback, Corrected some spelling errors (adiacense -> adjacency).
|
|
||||||
Added Validity Check function for hole loops
|
|
||||||
|
|
||||||
Revision 1.21 2006/11/30 11:49:20 cignoni
|
|
||||||
small gcc compiling issues
|
|
||||||
|
|
||||||
Revision 1.20 2006/11/29 16:21:45 cignoni
|
|
||||||
Made static exposed funtions of the class
|
|
||||||
|
|
||||||
Revision 1.19 2006/11/29 15:25:22 giec
|
|
||||||
Removed limit.
|
|
||||||
|
|
||||||
Revision 1.18 2006/11/29 15:18:49 giec
|
|
||||||
Code refactory and bugfix.
|
|
||||||
|
|
||||||
Revision 1.17 2006/11/24 10:42:39 mariolatronico
|
|
||||||
Now compiles on gcc under linux.
|
|
||||||
|
|
||||||
Revision 1.16 2006/11/22 13:43:28 giec
|
|
||||||
Code refactory and added minimum weight triangolation.
|
|
||||||
|
|
||||||
Revision 1.15 2006/11/13 10:11:38 giec
|
|
||||||
Clear some useless code
|
|
||||||
|
|
||||||
Revision 1.14 2006/11/07 15:13:56 zifnab1974
|
|
||||||
Necessary changes for compilation with gcc 3.4.6. Especially the hash function is a problem
|
|
||||||
|
|
||||||
Revision 1.13 2006/11/07 11:47:11 cignoni
|
|
||||||
gcc compiling issues
|
|
||||||
|
|
||||||
Revision 1.12 2006/11/07 07:56:43 cignoni
|
|
||||||
Added missing std::
|
|
||||||
|
|
||||||
Revision 1.11 2006/11/06 16:12:29 giec
|
|
||||||
Leipa ear now compute max dihedral angle.
|
|
||||||
|
|
||||||
Revision 1.10 2006/10/31 11:30:41 ganovelli
|
|
||||||
changed access throught iterator with static call to comply 2005 compiler
|
|
||||||
|
|
||||||
Revision 1.9 2006/10/20 07:44:45 cignoni
|
|
||||||
Added missing std::
|
|
||||||
|
|
||||||
Revision 1.8 2006/10/18 15:06:47 giec
|
|
||||||
New policy for compute quality in TrivialEar.
|
|
||||||
Bugfixed LeipaEar.
|
|
||||||
Added new algorithm "selfintersection" with test for self intersection.
|
|
||||||
|
|
||||||
Revision 1.7 2006/10/10 09:12:02 giec
|
|
||||||
Bugfix and added a new type of ear (Liepa like)
|
|
||||||
|
|
||||||
Revision 1.6 2006/10/09 10:07:07 giec
|
|
||||||
Optimized version of "EAR HOLE FILLING", the Ear is selected according to its dihedral angle.
|
|
||||||
|
|
||||||
Revision 1.5 2006/10/06 15:28:14 giec
|
|
||||||
first working implementationof "EAR HOLE FILLING".
|
|
||||||
|
|
||||||
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 . . .
|
|
||||||
|
|
||||||
Revision 1.2 2006/09/27 09:29:53 giec
|
|
||||||
Frist working release whit a few bugs.
|
|
||||||
It almost fills the hole ...
|
|
||||||
|
|
||||||
Revision 1.1 2006/09/25 09:17:44 cignoni
|
|
||||||
First Non working Version
|
|
||||||
|
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#ifndef __VCG_TRI_UPDATE_HOLE
|
#ifndef __VCG_TRI_UPDATE_HOLE
|
||||||
#define __VCG_TRI_UPDATE_HOLE
|
#define __VCG_TRI_UPDATE_HOLE
|
||||||
|
|
@ -140,21 +26,29 @@ First Non working Version
|
||||||
#include <wrap/callback.h>
|
#include <wrap/callback.h>
|
||||||
#include <vcg/math/base.h>
|
#include <vcg/math/base.h>
|
||||||
#include <vcg/complex/algorithms/clean.h>
|
#include <vcg/complex/algorithms/clean.h>
|
||||||
#include <vcg/space/point3.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
|
// This file contains three Ear Classes
|
||||||
|
// - TrivialEar
|
||||||
|
// - MinimumWeightEar
|
||||||
|
// - SelfIntersectionEar
|
||||||
|
// and a static class Hole for filling holes that is templated on the ear class
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace vcg {
|
namespace vcg {
|
||||||
namespace tri {
|
namespace tri {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Un ear e' identificato da due hedge pos.
|
An ear is identified by TWO pos.
|
||||||
i vertici dell'ear sono
|
The Three vertexes of an Ear are:
|
||||||
e0.VFlip().v
|
e0.VFlip().v
|
||||||
e0.v
|
e0.v
|
||||||
e1.v
|
e1.v
|
||||||
Vale che e1== e0.NextB();
|
Invariants:
|
||||||
e che e1.FlipV() == e0;
|
e1 == e0.NextB();
|
||||||
|
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
|
T XXXXXXXXXXXXX A /XXXXX B en/XXXXX
|
||||||
|
|
@ -180,6 +74,8 @@ namespace vcg {
|
||||||
PosType e1;
|
PosType e1;
|
||||||
CoordType n; // the normal of the face defined by the ear
|
CoordType n; // the normal of the face defined by the ear
|
||||||
const char * Dump() {return 0;}
|
const char * Dump() {return 0;}
|
||||||
|
// The following members are useful to consider the Ear as a generic <triangle>
|
||||||
|
// with p0 the 'center' of the ear.
|
||||||
const CoordType &cP(int i) const {return P(i);}
|
const CoordType &cP(int i) const {return P(i);}
|
||||||
const CoordType &P(int i) const {
|
const CoordType &P(int i) const {
|
||||||
switch(i) {
|
switch(i) {
|
||||||
|
|
@ -192,8 +88,7 @@ namespace vcg {
|
||||||
}
|
}
|
||||||
|
|
||||||
ScalarType quality;
|
ScalarType quality;
|
||||||
ScalarType angle;
|
ScalarType angleRad;
|
||||||
//std::vector<typename MESH::FaceType>* vf;
|
|
||||||
TrivialEar(){}
|
TrivialEar(){}
|
||||||
TrivialEar(const PosType & ep)
|
TrivialEar(const PosType & ep)
|
||||||
{
|
{
|
||||||
|
|
@ -211,17 +106,17 @@ namespace vcg {
|
||||||
// the angle computation takes into account the case of reversed ears
|
// the angle computation takes into account the case of reversed ears
|
||||||
void ComputeAngle()
|
void ComputeAngle()
|
||||||
{
|
{
|
||||||
angle=Angle(cP(2)-cP(0), cP(1)-cP(0));
|
angleRad=Angle(cP(2)-cP(0), cP(1)-cP(0));
|
||||||
ScalarType flipAngle = n.dot(e0.v->N());
|
ScalarType flipAngle = n.dot(e0.v->N());
|
||||||
if(flipAngle<0) angle = (2.0 *(float)M_PI) - angle;
|
if(flipAngle<0) angleRad = (2.0 *(ScalarType)M_PI) - angleRad;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual inline bool operator < ( const TrivialEar & c ) const { return quality < c.quality; }
|
virtual inline bool operator < ( const TrivialEar & c ) const { return quality < c.quality; }
|
||||||
|
|
||||||
bool IsNull(){return e0.IsNull() || e1.IsNull();}
|
bool IsNull(){return e0.IsNull() || e1.IsNull();}
|
||||||
void SetNull(){e0.SetNull();e1.SetNull();}
|
void SetNull(){e0.SetNull();e1.SetNull();}
|
||||||
virtual void ComputeQuality() { quality = QualityFace(*this) ; };
|
virtual void ComputeQuality() { quality = QualityFace(*this) ; }
|
||||||
bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());};
|
bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());}
|
||||||
// An ear is degenerated if both of its two endpoints are non manifold.
|
// An ear is degenerated if both of its two endpoints are non manifold.
|
||||||
bool IsDegen(const int nonManifoldBit)
|
bool IsDegen(const int nonManifoldBit)
|
||||||
{
|
{
|
||||||
|
|
@ -229,7 +124,7 @@ namespace vcg {
|
||||||
return true;
|
return true;
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
bool IsConcave() const {return(angle > (float)M_PI);}
|
bool IsConcave() const {return(angleRad > (float)M_PI);}
|
||||||
|
|
||||||
virtual bool Close(PosType &np0, PosType &np1, FaceType * f)
|
virtual bool Close(PosType &np0, PosType &np1, FaceType * f)
|
||||||
{
|
{
|
||||||
|
|
@ -248,27 +143,15 @@ namespace vcg {
|
||||||
(*f).V(2) = e1.v;
|
(*f).V(2) = e1.v;
|
||||||
ComputeNormal(*f);
|
ComputeNormal(*f);
|
||||||
|
|
||||||
(*f).FFp(0) = e0.f;
|
face::FFAttachManifold(f,0,e0.f,e0.z);
|
||||||
(*f).FFi(0) = e0.z;
|
face::FFAttachManifold(f,1,e1.f,e1.z);
|
||||||
(*f).FFp(1) = e1.f;
|
face::FFSetBorder(f,2);
|
||||||
(*f).FFi(1) = e1.z;
|
|
||||||
(*f).FFp(2) = f;
|
|
||||||
(*f).FFi(2) = 2;
|
|
||||||
|
|
||||||
e0.f->FFp(e0.z)=f;
|
|
||||||
e0.f->FFi(e0.z)=0;
|
|
||||||
|
|
||||||
e1.f->FFp(e1.z)=f;
|
|
||||||
e1.f->FFi(e1.z)=1;
|
|
||||||
|
|
||||||
// caso ear degenere per buco triangolare
|
// caso ear degenere per buco triangolare
|
||||||
if(ep==en)
|
if(ep==en)
|
||||||
{
|
{
|
||||||
//printf("Closing the last triangle");
|
//printf("Closing the last triangle");
|
||||||
f->FFp(2)=en.f;
|
face::FFAttachManifold(f,2,en.f,en.z);
|
||||||
f->FFi(2)=en.z;
|
|
||||||
en.f->FFp(en.z)=f;
|
|
||||||
en.f->FFi(en.z)=2;
|
|
||||||
np0.SetNull();
|
np0.SetNull();
|
||||||
np1.SetNull();
|
np1.SetNull();
|
||||||
}
|
}
|
||||||
|
|
@ -278,10 +161,7 @@ namespace vcg {
|
||||||
//printf("Ear Non manif A\n");
|
//printf("Ear Non manif A\n");
|
||||||
PosType enold=en;
|
PosType enold=en;
|
||||||
en.NextB();
|
en.NextB();
|
||||||
f->FFp(2)=enold.f;
|
face::FFAttachManifold(f,2,enold.f,enold.z);
|
||||||
f->FFi(2)=enold.z;
|
|
||||||
enold.f->FFp(enold.z)=f;
|
|
||||||
enold.f->FFi(enold.z)=2;
|
|
||||||
np0=ep;
|
np0=ep;
|
||||||
np1=en;
|
np1=en;
|
||||||
}
|
}
|
||||||
|
|
@ -291,10 +171,7 @@ namespace vcg {
|
||||||
//printf("Ear Non manif B\n");
|
//printf("Ear Non manif B\n");
|
||||||
PosType epold=ep;
|
PosType epold=ep;
|
||||||
ep.FlipV(); ep.NextB(); ep.FlipV();
|
ep.FlipV(); ep.NextB(); ep.FlipV();
|
||||||
f->FFp(2)=epold.f;
|
face::FFAttachManifold(f,2,epold.f,epold.z);
|
||||||
f->FFi(2)=epold.z;
|
|
||||||
epold.f->FFp(epold.z)=f;
|
|
||||||
epold.f->FFi(epold.z)=2;
|
|
||||||
np0=ep; // assign the two new
|
np0=ep; // assign the two new
|
||||||
np1=en; // pos that denote the ears
|
np1=en; // pos that denote the ears
|
||||||
}
|
}
|
||||||
|
|
@ -306,13 +183,14 @@ namespace vcg {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
}; // end TrivialEar Class
|
||||||
|
|
||||||
//Ear with FillHoleMinimumWeight's quality policy
|
//Ear with FillHoleMinimumWeight's quality policy
|
||||||
template<class MESH> class MinimumWeightEar : public TrivialEar<MESH>
|
template<class MESH> class MinimumWeightEar : public TrivialEar<MESH>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static float &DiedralWeight() { static float _dw=1.0; return _dw;}
|
static float &DiedralWeight() { static float _dw=0.1; return _dw;}
|
||||||
typedef TrivialEar<MESH> TE;
|
typedef TrivialEar<MESH> TE;
|
||||||
typename MESH::ScalarType dihedralRad;
|
typename MESH::ScalarType dihedralRad;
|
||||||
typename MESH::ScalarType aspectRatio;
|
typename MESH::ScalarType aspectRatio;
|
||||||
|
|
@ -324,7 +202,6 @@ namespace vcg {
|
||||||
}
|
}
|
||||||
|
|
||||||
MinimumWeightEar(){}
|
MinimumWeightEar(){}
|
||||||
//MinimumWeightEar(const PosType & ep) : TrivialEar<MESH>(ep)
|
|
||||||
MinimumWeightEar(const typename face::Pos<typename MESH::FaceType>& ep) : TrivialEar<MESH>(ep)
|
MinimumWeightEar(const typename face::Pos<typename MESH::FaceType>& ep) : TrivialEar<MESH>(ep)
|
||||||
{
|
{
|
||||||
ComputeQuality();
|
ComputeQuality();
|
||||||
|
|
@ -338,13 +215,12 @@ namespace vcg {
|
||||||
|
|
||||||
virtual inline bool operator < ( const MinimumWeightEar & c ) const
|
virtual inline bool operator < ( const MinimumWeightEar & c ) const
|
||||||
{
|
{
|
||||||
if(TE::IsConcave() == c.IsConcave())
|
if(TE::IsConcave() && ! c.IsConcave() ) return true;
|
||||||
{
|
if(!TE::IsConcave() && c.IsConcave() ) return false;
|
||||||
return (pow((float)dihedralRad,(float)DiedralWeight())/aspectRatio) > (pow((float)c.dihedralRad,(float)DiedralWeight())/c.aspectRatio);
|
|
||||||
}
|
return aspectRatio - (dihedralRad/M_PI)*DiedralWeight() < c.aspectRatio -(c.dihedralRad/M_PI)*DiedralWeight();
|
||||||
if(TE::IsConcave()) return true;
|
|
||||||
// assert(c.IsConcave());
|
// return (pow((float)dihedralRad,(float)DiedralWeight())/aspectRatio) > (pow((float)c.dihedralRad,(float)DiedralWeight())/c.aspectRatio);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the real core of the whole hole filling strategy.
|
// the real core of the whole hole filling strategy.
|
||||||
|
|
@ -358,7 +234,9 @@ namespace vcg {
|
||||||
aspectRatio = QualityFace(*this);
|
aspectRatio = QualityFace(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}; // end class MinimumWeightEar
|
||||||
|
|
||||||
|
|
||||||
//Ear for selfintersection algorithm
|
//Ear for selfintersection algorithm
|
||||||
template<class MESH> class SelfIntersectionEar : public MinimumWeightEar<MESH>
|
template<class MESH> class SelfIntersectionEar : public MinimumWeightEar<MESH>
|
||||||
{
|
{
|
||||||
|
|
@ -382,53 +260,42 @@ namespace vcg {
|
||||||
{
|
{
|
||||||
PosType ep=this->e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0
|
PosType ep=this->e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0
|
||||||
PosType en=this->e1; en.NextB(); // he successivo a e1
|
PosType en=this->e1; en.NextB(); // he successivo a e1
|
||||||
|
// bool triangularHole = false;
|
||||||
|
// if(en==ep || en-) triangularHole=true;
|
||||||
|
|
||||||
|
|
||||||
//costruisco la faccia e poi testo, o copio o butto via.
|
//costruisco la faccia e poi testo, o copio o butto via.
|
||||||
(*f).V(0) = this->e0.VFlip();
|
(*f).V(0) = this->e0.VFlip();
|
||||||
(*f).V(1) = this->e0.v;
|
(*f).V(1) = this->e0.v;
|
||||||
(*f).V(2) = this->e1.v;
|
(*f).V(2) = this->e1.v;
|
||||||
|
face::FFSetBorder(f,0);
|
||||||
|
face::FFSetBorder(f,1);
|
||||||
|
face::FFSetBorder(f,2);
|
||||||
|
|
||||||
(*f).FFp(0) = this->e0.f;
|
|
||||||
(*f).FFi(0) = this->e0.z;
|
|
||||||
(*f).FFp(1) = this->e1.f;
|
|
||||||
(*f).FFi(1) = this->e1.z;
|
|
||||||
(*f).FFp(2) = f;
|
|
||||||
(*f).FFi(2) = 2;
|
|
||||||
|
|
||||||
int a1, a2;
|
|
||||||
a1= this->e0.z;
|
|
||||||
a2= this->e1.z;
|
|
||||||
|
|
||||||
this->e0.f->FFp(this->e0.z)=f;
|
|
||||||
this->e0.f->FFi(this->e0.z)=0;
|
|
||||||
|
|
||||||
this->e1.f->FFp(this->e1.z)=f;
|
|
||||||
this->e1.f->FFi(this->e1.z)=1;
|
|
||||||
typename std::vector< FacePointer >::iterator it;
|
typename std::vector< FacePointer >::iterator it;
|
||||||
for(it = this->AdjacencyRing().begin();it!= this->AdjacencyRing().end();++it)
|
for(it = this->AdjacencyRing().begin();it!= this->AdjacencyRing().end();++it)
|
||||||
{
|
{
|
||||||
if(!(*it)->IsD())
|
if(!(*it)->IsD())
|
||||||
if( tri::Clean<MESH>::TestFaceFaceIntersection(&(*f),*it))
|
|
||||||
{
|
{
|
||||||
this->e0.f->FFp(this->e0.z)= this->e0.f;
|
if( tri::Clean<MESH>::TestFaceFaceIntersection(f,*it))
|
||||||
this->e0.f->FFi(this->e0.z)=a1;
|
return false;
|
||||||
|
// We must also check that the newly created face does not have any edge in common with other existing surrounding faces
|
||||||
this->e1.f->FFp(this->e1.z)= this->e1.f;
|
// Only the two faces of the ear can share an edge with the new face
|
||||||
this->e1.f->FFi(this->e1.z)=a2;
|
if(face::CountSharedVertex(f,*it)==2)
|
||||||
|
{
|
||||||
|
int e0,e1;
|
||||||
|
bool ret=face::FindSharedEdge(f,*it,e0,e1);
|
||||||
|
assert(ret);
|
||||||
|
if(!face::IsBorder(**it,e1))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//return ((TrivialEar<MESH> *)this)->Close(np0,np1,f);
|
}
|
||||||
this->e0.f->FFp(this->e0.z)= this->e0.f;
|
|
||||||
this->e0.f->FFi(this->e0.z)=a1;
|
|
||||||
|
|
||||||
this->e1.f->FFp(this->e1.z)=this->e1.f;
|
|
||||||
this->e1.f->FFi(this->e1.z)=a2;
|
|
||||||
|
|
||||||
bool ret=TrivialEar<MESH>::Close(np0,np1,f);
|
bool ret=TrivialEar<MESH>::Close(np0,np1,f);
|
||||||
if(ret) AdjacencyRing().push_back(f);
|
if(ret) AdjacencyRing().push_back(f);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
}; // end class SelfIntersectionEar
|
||||||
|
|
||||||
// Funzione principale per chiudier un buco in maniera topologicamente corretta.
|
// Funzione principale per chiudier un buco in maniera topologicamente corretta.
|
||||||
// Gestisce situazioni non manifold ragionevoli
|
// Gestisce situazioni non manifold ragionevoli
|
||||||
|
|
@ -500,16 +367,39 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeToBeAvoided
|
||||||
|
{
|
||||||
|
VertexPointer v0,v1;
|
||||||
|
EdgeToBeAvoided(VertexPointer _v0, VertexPointer _v1):v0(_v0),v1(_v1)
|
||||||
|
{
|
||||||
|
if(v0>v1) swap(v0,v1);
|
||||||
|
}
|
||||||
|
bool operator < (const EdgeToBeAvoided &e)
|
||||||
|
{
|
||||||
|
if(this->v0!=e.v0) return this->v0<e.v0;
|
||||||
|
return this->v1<e.v1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/// Main Single Hole Filling Function
|
||||||
|
/// Given a specific hole (identified by the Info h) it fills it
|
||||||
|
/// It also update a vector of face pointers
|
||||||
|
/// It uses an heap to choose the best ear to be closed
|
||||||
|
|
||||||
template<class EAR>
|
template<class EAR>
|
||||||
static void FillHoleEar(MESH &m, Info &h ,int UBIT, std::vector<FacePointer *> &app,std::vector<FaceType > *vf =0)
|
static void FillHoleEar(MESH &m, // The mesh to be filled
|
||||||
|
Info &h, // the particular hole to be filled
|
||||||
|
std::vector<FacePointer *> &facePointersToBeUpdated)
|
||||||
{
|
{
|
||||||
//Aggiungo le facce e aggiorno il puntatore alla faccia!
|
//Aggiungo le facce e aggiorno il puntatore alla faccia!
|
||||||
FaceIterator f = tri::Allocator<MESH>::AddFaces(m, h.size-2, app);
|
FaceIterator f = tri::Allocator<MESH>::AddFaces(m, h.size-2, facePointersToBeUpdated);
|
||||||
|
|
||||||
assert(h.p.f >= &*m.face.begin());
|
assert(h.p.f >= &*m.face.begin());
|
||||||
assert(h.p.f <= &m.face.back());
|
assert(h.p.f <= &m.face.back());
|
||||||
assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto!
|
assert(h.p.IsBorder());
|
||||||
std::vector< EAR > H;
|
|
||||||
H.reserve(h.size);
|
std::vector< EAR > EarHeap;
|
||||||
|
EarHeap.reserve(h.size);
|
||||||
int nmBit= VertexType::NewBitFlag(); // non manifoldness bit
|
int nmBit= VertexType::NewBitFlag(); // non manifoldness bit
|
||||||
|
|
||||||
//First loops around the hole to mark non manifold vertices.
|
//First loops around the hole to mark non manifold vertices.
|
||||||
|
|
@ -530,8 +420,8 @@ template<class EAR>
|
||||||
|
|
||||||
PosType fp = h.p;
|
PosType fp = h.p;
|
||||||
do{
|
do{
|
||||||
EAR app = EAR(fp);
|
EAR appEar = EAR(fp);
|
||||||
H.push_back( app );
|
EarHeap.push_back( appEar );
|
||||||
//printf("Adding ear %s ",app.Dump());
|
//printf("Adding ear %s ",app.Dump());
|
||||||
fp.NextB();
|
fp.NextB();
|
||||||
assert(fp.IsBorder());
|
assert(fp.IsBorder());
|
||||||
|
|
@ -539,60 +429,56 @@ template<class EAR>
|
||||||
|
|
||||||
int cnt=h.size;
|
int cnt=h.size;
|
||||||
|
|
||||||
make_heap(H.begin(), H.end());
|
make_heap(EarHeap.begin(), EarHeap.end());
|
||||||
|
|
||||||
//finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare.
|
//finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare.
|
||||||
while( cnt > 2 && !H.empty() )
|
while( cnt > 2 && !EarHeap.empty() )
|
||||||
{
|
{
|
||||||
//printf("Front of the heap is %s", H.front().Dump());
|
//printf("Front of the heap is %s", H.front().Dump());
|
||||||
pop_heap(H.begin(), H.end()); // retrieve the MAXIMUM value and put in the back;
|
pop_heap(EarHeap.begin(), EarHeap.end()); // retrieve the MAXIMUM value and put in the back;
|
||||||
PosType ep0,ep1;
|
EAR BestEar=EarHeap.back();
|
||||||
EAR BestEar=H.back();
|
EarHeap.pop_back();
|
||||||
H.pop_back();
|
|
||||||
if(BestEar.IsUpToDate() && !BestEar.IsDegen(nmBit))
|
if(BestEar.IsUpToDate() && !BestEar.IsDegen(nmBit))
|
||||||
{
|
{
|
||||||
if((*f).HasPolyInfo()) (*f).Alloc(3);
|
if((*f).HasPolyInfo()) (*f).Alloc(3);
|
||||||
|
PosType ep0,ep1;
|
||||||
if(BestEar.Close(ep0,ep1,&*f))
|
if(BestEar.Close(ep0,ep1,&*f))
|
||||||
{
|
{
|
||||||
if(!ep0.IsNull()){
|
if(!ep0.IsNull()){
|
||||||
H.push_back(EAR(ep0));
|
EarHeap.push_back(EAR(ep0));
|
||||||
push_heap( H.begin(), H.end());
|
push_heap( EarHeap.begin(), EarHeap.end());
|
||||||
}
|
}
|
||||||
if(!ep1.IsNull()){
|
if(!ep1.IsNull()){
|
||||||
H.push_back(EAR(ep1));
|
EarHeap.push_back(EAR(ep1));
|
||||||
push_heap( H.begin(), H.end());
|
push_heap( EarHeap.begin(), EarHeap.end());
|
||||||
}
|
}
|
||||||
--cnt;
|
--cnt;
|
||||||
f->SetUserBit(UBIT);
|
|
||||||
if(vf != 0) (*vf).push_back(*f);
|
|
||||||
++f;
|
++f;
|
||||||
}
|
}
|
||||||
}//is update()
|
}//is update()
|
||||||
}//fine del while principale.
|
}//fine del while principale.
|
||||||
//tolgo le facce non utilizzate.
|
|
||||||
while(f!=m.face.end())
|
while(f!=m.face.end()){
|
||||||
{
|
tri::Allocator<MESH>::DeleteFace(m,*f);
|
||||||
(*f).SetD();
|
f++;
|
||||||
++f;
|
|
||||||
m.fn--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexType::DeleteBitFlag(nmBit); // non manifoldness bit
|
VertexType::DeleteBitFlag(nmBit); // non manifoldness bit
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class EAR>
|
template<class EAR>
|
||||||
static int EarCuttingFill(MESH &m, int sizeHole, const int UBIT, bool Selected = false, CallBackPos *cb=0)
|
static int EarCuttingFill(MESH &m, int sizeHole, bool Selected = false, CallBackPos *cb=0)
|
||||||
{
|
{
|
||||||
std::vector< Info > vinfo;
|
std::vector< Info > vinfo;
|
||||||
// int UBIT = GetInfo(m, Selected,vinfo);
|
GetInfo(m, Selected,vinfo);
|
||||||
|
|
||||||
typename std::vector<Info >::iterator ith;
|
typename std::vector<Info >::iterator ith;
|
||||||
//Info app;
|
|
||||||
int indCb=0;
|
int indCb=0;
|
||||||
int holeCnt=0;
|
int holeCnt=0;
|
||||||
std::vector<FacePointer *> vfp;
|
std::vector<FacePointer *> facePtrToBeUpdated;
|
||||||
for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith)
|
for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith)
|
||||||
vfp.push_back( &(*ith).p.f );
|
facePtrToBeUpdated.push_back( &(*ith).p.f );
|
||||||
|
|
||||||
for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith)
|
for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith)
|
||||||
{
|
{
|
||||||
|
|
@ -600,29 +486,21 @@ template<class EAR>
|
||||||
if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes");
|
if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes");
|
||||||
if((*ith).size < sizeHole){
|
if((*ith).size < sizeHole){
|
||||||
holeCnt++;
|
holeCnt++;
|
||||||
FillHoleEar< EAR >(m, *ith,UBIT,vfp);
|
FillHoleEar< EAR >(m, *ith,facePtrToBeUpdated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FaceIterator fi;
|
|
||||||
for(fi = m.face.begin(); fi!=m.face.end(); ++fi)
|
|
||||||
{
|
|
||||||
if(!(*fi).IsD())
|
|
||||||
(*fi).ClearUserBit(UBIT);
|
|
||||||
}
|
|
||||||
return holeCnt;
|
return holeCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// it returns the number of created holes.
|
/// Main Hole Filling function.
|
||||||
|
/// Given a mesh search for all the holes smaller than a given size and fill them
|
||||||
|
/// It returns the number of filled holes.
|
||||||
|
|
||||||
template<class EAR>
|
template<class EAR>
|
||||||
static int EarCuttingIntersectionFill(MESH &m, int sizeHole, const int UBIT, CallBackPos *cb=0)
|
static int EarCuttingIntersectionFill(MESH &m, const int maxSizeHole, bool Selected, CallBackPos *cb=0)
|
||||||
{
|
{
|
||||||
std::vector<Info > vinfo;
|
std::vector<Info > vinfo;
|
||||||
// int UBIT = GetInfo(m, Selected,vinfo);
|
GetInfo(m, Selected,vinfo);
|
||||||
std::vector<FaceType > vf;
|
|
||||||
PosType sp;
|
|
||||||
PosType ap;
|
|
||||||
typename std::vector<Info>::iterator ith;
|
typename std::vector<Info>::iterator ith;
|
||||||
|
|
||||||
// collect the face pointer that has to be updated by the various addfaces
|
// collect the face pointer that has to be updated by the various addfaces
|
||||||
|
|
@ -636,12 +514,12 @@ template<class EAR>
|
||||||
{
|
{
|
||||||
indCb++;
|
indCb++;
|
||||||
if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes");
|
if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes");
|
||||||
if((*ith).size < sizeHole){
|
if((*ith).size < maxSizeHole){
|
||||||
std::vector<FacePointer *> vfp;
|
std::vector<FacePointer *> facePtrToBeUpdated;
|
||||||
holeCnt++;
|
holeCnt++;
|
||||||
vfp=vfpOrig;
|
facePtrToBeUpdated=vfpOrig;
|
||||||
EAR::AdjacencyRing().clear();
|
EAR::AdjacencyRing().clear();
|
||||||
//Loops around the hole to collect the races .
|
//Loops around the hole to collect the faces that have to be tested for intersection.
|
||||||
PosType ip = (*ith).p;
|
PosType ip = (*ith).p;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
@ -657,25 +535,20 @@ template<class EAR>
|
||||||
|
|
||||||
typename std::vector<FacePointer>::iterator fpi;
|
typename std::vector<FacePointer>::iterator fpi;
|
||||||
for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi)
|
for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi)
|
||||||
vfp.push_back( &*fpi );
|
facePtrToBeUpdated.push_back( &*fpi );
|
||||||
|
|
||||||
FillHoleEar<EAR >(m, *ith,UBIT,vfp,&vf);
|
FillHoleEar<EAR >(m, *ith,facePtrToBeUpdated);
|
||||||
EAR::AdjacencyRing().clear();
|
EAR::AdjacencyRing().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FaceIterator fi;
|
|
||||||
for(fi = m.face.begin(); fi!=m.face.end(); ++fi)
|
|
||||||
{
|
|
||||||
if(!(*fi).IsD())
|
|
||||||
(*fi).ClearUserBit(UBIT);
|
|
||||||
}
|
|
||||||
return holeCnt;
|
return holeCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void GetInfo(MESH &m, const int UBIT, bool Selected ,std::vector<Info >& VHI)
|
static void GetInfo(MESH &m, bool Selected ,std::vector<Info >& VHI)
|
||||||
{
|
{
|
||||||
|
tri::UpdateFlags<MESH>::FaceClearV(m);
|
||||||
for(FaceIterator fi = m.face.begin(); fi!=m.face.end(); ++fi)
|
for(FaceIterator fi = m.face.begin(); fi!=m.face.end(); ++fi)
|
||||||
{
|
{
|
||||||
if(!(*fi).IsD())
|
if(!(*fi).IsD())
|
||||||
|
|
@ -684,15 +557,15 @@ template<class EAR>
|
||||||
{
|
{
|
||||||
//se devo considerare solo i triangoli selezionati e
|
//se devo considerare solo i triangoli selezionati e
|
||||||
//quello che sto considerando non lo e' lo marchio e vado avanti
|
//quello che sto considerando non lo e' lo marchio e vado avanti
|
||||||
(*fi).SetUserBit(UBIT);
|
(*fi).SetV();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(int j =0; j<3 ; ++j)
|
for(int j =0; j<3 ; ++j)
|
||||||
{
|
{
|
||||||
if( face::IsBorder(*fi,j) && !(*fi).IsUserBit(UBIT) )
|
if( face::IsBorder(*fi,j) && !(*fi).IsV() )
|
||||||
{//Trovato una faccia di bordo non ancora visitata.
|
{//Trovato una faccia di bordo non ancora visitata.
|
||||||
(*fi).SetUserBit(UBIT);
|
(*fi).SetV();
|
||||||
PosType sp(&*fi, j, (*fi).V(j));
|
PosType sp(&*fi, j, (*fi).V(j));
|
||||||
PosType fp=sp;
|
PosType fp=sp;
|
||||||
int holesize=0;
|
int holesize=0;
|
||||||
|
|
@ -700,14 +573,14 @@ template<class EAR>
|
||||||
Box3Type hbox;
|
Box3Type hbox;
|
||||||
hbox.Add(sp.v->cP());
|
hbox.Add(sp.v->cP());
|
||||||
//printf("Looping %i : (face %i edge %i) \n", VHI.size(),sp.f-&*m.face.begin(),sp.z);
|
//printf("Looping %i : (face %i edge %i) \n", VHI.size(),sp.f-&*m.face.begin(),sp.z);
|
||||||
sp.f->SetUserBit(UBIT);
|
sp.f->SetV();
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
sp.f->SetUserBit(UBIT);
|
sp.f->SetV();
|
||||||
hbox.Add(sp.v->cP());
|
hbox.Add(sp.v->cP());
|
||||||
++holesize;
|
++holesize;
|
||||||
sp.NextB();
|
sp.NextB();
|
||||||
sp.f->SetUserBit(UBIT);
|
sp.f->SetV();
|
||||||
assert(sp.IsBorder());
|
assert(sp.IsBorder());
|
||||||
}while(sp != fp);
|
}while(sp != fp);
|
||||||
|
|
||||||
|
|
@ -915,15 +788,14 @@ template<class EAR>
|
||||||
triangulate(m,f,k,j,vi,vv);
|
triangulate(m,f,k,j,vi,vv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MinimumWeightFill(MESH &m, const int UBIT, int holeSize, bool Selected)
|
static void MinimumWeightFill(MESH &m, int holeSize, bool Selected)
|
||||||
{
|
{
|
||||||
FaceIterator fi;
|
|
||||||
std::vector<PosType > vvi;
|
std::vector<PosType > vvi;
|
||||||
std::vector<FacePointer * > vfp;
|
std::vector<FacePointer * > vfp;
|
||||||
|
|
||||||
std::vector<Info > vinfo;
|
std::vector<Info > vinfo;
|
||||||
typename std::vector<Info >::iterator VIT;
|
typename std::vector<Info >::iterator VIT;
|
||||||
GetInfo(m, UBIT, Selected,vinfo);
|
GetInfo(m, Selected,vinfo);
|
||||||
|
|
||||||
for(VIT = vinfo.begin(); VIT != vinfo.end();++VIT)
|
for(VIT = vinfo.begin(); VIT != vinfo.end();++VIT)
|
||||||
{
|
{
|
||||||
|
|
@ -983,6 +855,6 @@ template<class EAR>
|
||||||
|
|
||||||
};//close class Hole
|
};//close class Hole
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace tri
|
||||||
}
|
} // end namespace vcg
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue