First working version!
This commit is contained in:
parent
d7d79a8867
commit
9c4727960d
|
@ -1,41 +1,34 @@
|
|||
/*#***************************************************************************
|
||||
* Geodesic.h o o *
|
||||
* o o *
|
||||
* Visual Computing Group _ O _ *
|
||||
* IEI Institute, CNUCE Institute, CNR Pisa \/)\/ *
|
||||
* /\/| *
|
||||
* Copyright(C) 1999 by Paolo Cignoni, | *
|
||||
* All rights reserved. \ *
|
||||
* *
|
||||
* Permission to use, copy, modify, distribute and sell this software and *
|
||||
* its documentation for any purpose is hereby granted without fee, provided *
|
||||
* that the above copyright notice appear in all copies and that both that *
|
||||
* copyright notice and this permission notice appear in supporting *
|
||||
* documentation. the author makes no representations about the suitability *
|
||||
* of this software for any purpose. It is provided "as is" without express *
|
||||
* or implied warranty. *
|
||||
* *
|
||||
***************************************************************************#*/
|
||||
/*#**************************************************************************
|
||||
/****************************************************************************
|
||||
* 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. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
History
|
||||
|
||||
2002 Apr 01 First Working release copiata, ripulita e templatata dal plyvcg(pc)
|
||||
Dic 27 Aggiunta classe Geo. First release (gano)
|
||||
2003 Jan 10 Aggiunto controllo IsD() in ComputeGeodesicQuality() (pc)
|
||||
Feb 02 Cambiato l'algoritmo e aggiunta FindPath
|
||||
May 05 Corretti un po' di bug sui casi limite e templatata la BuildSP
|
||||
Aggiunta SelectRegion
|
||||
May 13 Variazioni alla SelectRegion per la selezione di triangoli
|
||||
in casi limite (longobardi)
|
||||
May 19 Corretto baco in BuildSP, aggiunto template, ripulito un po' (gano)
|
||||
July 3 *** aggiornati i tipi di meshPos alla nuova versione
|
||||
aggiunta SelectRegionFF (gano)
|
||||
16 Aggiunto namespace
|
||||
Nov 14 Corretto bug nella ComputeGeodesicQuality. (pc)
|
||||
*#**************************************************************************/
|
||||
$Log: not supported by cvs2svn $
|
||||
|
||||
#ifndef __VCG_GEODESIC__
|
||||
#define __VCG_GEODESIC__
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __VCG_GEODESIC
|
||||
#define __VCG_GEODESIC
|
||||
|
||||
namespace vcg {
|
||||
|
||||
|
@ -149,902 +142,4 @@ void ComputeGeodesicQuality(MESH &m, bool per_face ) // R1
|
|||
|
||||
|
||||
|
||||
// ************************************** classe GEo
|
||||
// first release
|
||||
// Modo d'uso
|
||||
// Geo<TYPE_MESH> geo(m); //dichiare e definisce
|
||||
// m.VFTopology();
|
||||
// geo.FartestPoint(....);//dato un insieme di punti a distanza 0 trova
|
||||
// // il punto piu'lontano sulla superficie (una versione ritorna anche il
|
||||
// // cammino)
|
||||
//
|
||||
// geo.FindPath(...); // determina il cammino minimo tra due vertici
|
||||
// m.ComputeVBorderFlag(); (SOLO SE SI USA MostInternal)
|
||||
// geo.MostInternal(....);// punto piu'lontano dal bordo: invoca FartestPoint passando
|
||||
// // tutti i vertici di bordo come insieme di partenza.
|
||||
// // NB: questa fa la stessa cosa di ComputeGeodesicQuality
|
||||
// // ma non scrive sul campo qualita' del vertice
|
||||
//
|
||||
//
|
||||
// *****************************************
|
||||
|
||||
template <class TMESH>
|
||||
class Geo{
|
||||
|
||||
public:
|
||||
|
||||
Geo( TMESH & m):TD(m.vert),TDP(m.vert),TDS(m.vert),TDF(m.face),M(m)
|
||||
{lessThan.pt = this;}
|
||||
~Geo(){}
|
||||
|
||||
TMESH &M;
|
||||
template <class TMESH>
|
||||
struct TempData{
|
||||
TempData(){}
|
||||
TempData(const double & d_){d=d_;visited=false;}
|
||||
double d;
|
||||
bool visited;
|
||||
};
|
||||
|
||||
template <class TMESH>
|
||||
struct TempDataPath{
|
||||
TempDataPath(){}
|
||||
TempDataPath(const TMESH::vertex_pointer & parent_){parent = parent_;}
|
||||
TMESH::vertex_pointer parent;
|
||||
};
|
||||
|
||||
template <class TMESH>
|
||||
struct TempDataSource{
|
||||
TempDataSource(){}
|
||||
TempDataSource(const TMESH::vertex_pointer & source_){source = source_;}
|
||||
TMESH::vertex_pointer source;
|
||||
};
|
||||
|
||||
TempData_vect<TMESH::vertex_type, TempData<TMESH> > TD;
|
||||
TempData_vect<TMESH::vertex_type, TempDataPath<TMESH> > TDP;
|
||||
TempData_vect<TMESH::vertex_type, TempDataSource<TMESH> > TDS;
|
||||
|
||||
|
||||
template<class VERTEX_POINTER, class PT>
|
||||
struct pred: public binary_function<VERTEX_POINTER,VERTEX_POINTER,bool>{
|
||||
PT * pt;
|
||||
bool operator()(const VERTEX_POINTER& v0, const VERTEX_POINTER& v1) const
|
||||
{return (pt->TD[v0].d > pt->TD[v1].d);}
|
||||
};
|
||||
|
||||
pred<TMESH::vertex_pointer,Geo<TMESH> > lessThan;
|
||||
|
||||
template<class VERTEX_POINTER>
|
||||
struct VPath{
|
||||
VPath(VERTEX_POINTER v0,VERTEX_POINTER v1, double dist):pathLenght(dist){
|
||||
sources[0] = v0;sources[1] = v1;
|
||||
}
|
||||
VERTEX_POINTER sources[2];
|
||||
double pathLenght;
|
||||
};
|
||||
|
||||
typedef typename VPath<TMESH::vertex_pointer> Path;
|
||||
|
||||
template <bool RETURN_PATH, bool CONNECT_TWO_SOURCES,bool FARTEST_ON_BORDER,bool SKIP_SELECTED>
|
||||
TMESH::vertex_pointer BuildSP(
|
||||
deque<TMESH::vertex_pointer> &path,
|
||||
vector<TMESH::vertex_pointer> & _frontier,
|
||||
double & max_distance
|
||||
)
|
||||
{
|
||||
TMESH::vertex_pointer curr=NULL,fartest=NULL,pw1;
|
||||
bool isLeaf;
|
||||
Path shortestPath(NULL,NULL,-1.0);
|
||||
TMESH::vertex_pointer sources[2];
|
||||
assert(!CONNECT_TWO_SOURCES || (_frontier.size()==2));
|
||||
|
||||
if(CONNECT_TWO_SOURCES){
|
||||
if( _frontier.size() != 2) return (TMESH::vertex_pointer)0;
|
||||
if( _frontier[0] == _frontier[1]) return (TMESH::vertex_pointer)0;
|
||||
sources[0] = _frontier[0];
|
||||
sources[1] = _frontier[1];
|
||||
}
|
||||
|
||||
vector<TMESH::vertex_pointer> frontier;
|
||||
frontier.clear();
|
||||
|
||||
//Requirements
|
||||
assert(M.HasVFTopology());
|
||||
|
||||
if(M.vn==0) return NULL;
|
||||
|
||||
list<TMESH::vertex_pointer> children;
|
||||
bool toQueue;
|
||||
|
||||
TD.Start(TempData<TMESH>(-1.0));
|
||||
|
||||
if(RETURN_PATH)
|
||||
TDP.Start(TempDataPath<TMESH>(NULL));
|
||||
|
||||
list<TMESH::vertex_pointer>::iterator is;
|
||||
deque<TMESH::vertex_pointer> leaves;
|
||||
vector <pair<TMESH::vertex_pointer,TMESH::scalar_type> > expansion;
|
||||
|
||||
vector <TMESH::vertex_pointer >::const_iterator ifr;
|
||||
TMESH::vedgepos_type x;int k;
|
||||
TMESH::vertex_pointer pw;
|
||||
|
||||
for(ifr = _frontier.begin(); ifr != _frontier.end(); ++ifr){
|
||||
TD[*ifr].visited= true;
|
||||
TD[*ifr].d = 0.0;
|
||||
}
|
||||
if(CONNECT_TWO_SOURCES){
|
||||
TDS.Start(TempDataSource<TMESH>(NULL));
|
||||
for(ifr = _frontier.begin(); ifr != _frontier.end(); ++ifr)
|
||||
TDS[*ifr].source= (*ifr);
|
||||
}
|
||||
|
||||
for(ifr = _frontier.begin(); ifr != _frontier.end(); ++ifr)
|
||||
{
|
||||
if(RETURN_PATH)
|
||||
TDP[*ifr].parent=NULL;
|
||||
// determina la distanza dei vertici della fan
|
||||
|
||||
for( x.f = (*ifr)->Fp(), x.z = (*ifr)->Zp(); x.f!=0; x.NextF() )
|
||||
for(k=0;k<2;++k)
|
||||
{
|
||||
if(k==0) pw = x.f->V1(x.z);
|
||||
else pw = x.f->V2(x.z);
|
||||
|
||||
|
||||
|
||||
if(SKIP_SELECTED)
|
||||
if(pw->IsS())
|
||||
continue;
|
||||
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
{
|
||||
if( (TDS[pw].source != NULL)&&(TDS[pw].source!= TDS[*ifr].source)){
|
||||
double l = TD[pw].d + Distance((*ifr)->cP(),pw->cP());
|
||||
if( (shortestPath.pathLenght== -1)||(l < shortestPath.pathLenght))
|
||||
shortestPath = Path((*ifr),pw,l );
|
||||
}
|
||||
}
|
||||
|
||||
if(TD[pw].d ==-1){
|
||||
TD[pw].d = Distance(pw->cP(),(*ifr)->cP());
|
||||
frontier.push_back(pw);
|
||||
|
||||
if(RETURN_PATH)
|
||||
if(!TD[pw].visited)
|
||||
TDP[pw].parent= (*ifr);
|
||||
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
TDS[pw].source = (*ifr);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
if(shortestPath.pathLenght != -1)
|
||||
goto found;
|
||||
|
||||
|
||||
double curr_d,d_curr = 0.0;
|
||||
max_distance=0.0;
|
||||
|
||||
make_heap(frontier.begin(),frontier.end(),lessThan);
|
||||
while(!frontier.empty()){
|
||||
expansion.clear();
|
||||
pop_heap(frontier.begin(),frontier.end(),lessThan);
|
||||
curr = frontier.back();
|
||||
frontier.pop_back();
|
||||
d_curr = TD[curr].d;
|
||||
TD[curr].visited=true;
|
||||
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
{
|
||||
double otherDist;
|
||||
|
||||
if(shortestPath.pathLenght!= -1)
|
||||
{
|
||||
if( TDS[curr].source == TDS[shortestPath.sources[0]].source)
|
||||
otherDist = TD[shortestPath.sources[1]].d;
|
||||
else
|
||||
otherDist = TD[shortestPath.sources[0]].d;
|
||||
|
||||
if (d_curr > shortestPath.pathLenght-otherDist)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
isLeaf = (!FARTEST_ON_BORDER || curr->IsB());
|
||||
|
||||
TMESH::vedgepos_type x;int k;
|
||||
|
||||
for( x.f = curr->Fp(), x.z = curr->Zp(); x.f!=0; x.NextF() )
|
||||
for(k=0;k<2;++k)
|
||||
{
|
||||
if(k==0) {
|
||||
pw = x.f->V1(x.z);
|
||||
pw1=x.f->V2(x.z);
|
||||
}
|
||||
else {
|
||||
pw = x.f->V2(x.z);
|
||||
pw1=x.f->V1(x.z);
|
||||
}
|
||||
const double & d_pw1 = TD[pw1].d;
|
||||
|
||||
if(SKIP_SELECTED)
|
||||
if(pw->IsS())
|
||||
continue;
|
||||
|
||||
if((TD[pw].visited &&
|
||||
(!CONNECT_TWO_SOURCES || (TDS[pw].source == TDS[curr].source))))
|
||||
continue;
|
||||
|
||||
if(CONNECT_TWO_SOURCES){
|
||||
if( (TDS[pw].source!=TDS[curr].source) && (TDS[pw].source!=NULL)&& (TDS[curr].source!=NULL)){
|
||||
double l = TD[curr].d+ TD[pw].d + Distance(curr->cP(),pw->cP());
|
||||
if( (shortestPath.pathLenght == -1) || (shortestPath.pathLenght > l) )
|
||||
shortestPath = Path(curr,pw,l);
|
||||
continue;
|
||||
}
|
||||
if( (TDS[pw1].source!=TDS[curr].source) && (TDS[pw1].source!=NULL)&& (TDS[curr].source!=NULL)){
|
||||
double l = TD[curr].d+ TD[pw1].d + Distance(curr->cP(),pw1->cP());
|
||||
if( (shortestPath.pathLenght == -1) || (shortestPath.pathLenght > l) )
|
||||
shortestPath = Path(curr,pw1,l);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if((!TD[pw1].visited ) ||(d_pw1 == 0.0) )
|
||||
continue;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if(CONNECT_TWO_SOURCES){
|
||||
assert(TDS[pw1].source == TDS[curr].source);
|
||||
assert((TDP[curr].parent == NULL) || TDS[curr].source == TDS[TDP[curr].parent].source);
|
||||
}
|
||||
assert( TD[pw1].d != -1);
|
||||
assert( TD[pw1].d != 0.0);
|
||||
assert( (curr!=pw) && (pw!=pw1) && (pw1 != curr));
|
||||
assert(d_pw1!=-1.0);
|
||||
#endif
|
||||
|
||||
//************** calcolo della distanza di pw in base alle distanze note di pw1 e curr
|
||||
//************** sapendo che (curr,pw,pw1) e'una faccia della mesh
|
||||
//************** (vedi figura in file distance.gif)
|
||||
Point3<TMESH::scalar_type> w_c = pw->cP()- curr->cP();
|
||||
Point3<TMESH::scalar_type> w_w1 = pw->cP()- pw1->cP();
|
||||
Point3<TMESH::scalar_type> w1_c = pw1->cP()- curr->cP();
|
||||
|
||||
double ew_c = (w_c).Norm();
|
||||
double ew_w1 = (w_w1).Norm();
|
||||
double ec_w1 = (w1_c).Norm();
|
||||
double alpha,alpha_, beta,beta_,theta,h,delta,s,a,b;
|
||||
|
||||
alpha = acos((w_c*w1_c)/(ew_c*ec_w1));
|
||||
s = (d_curr + d_pw1+ec_w1)/2;
|
||||
a = s/ec_w1;
|
||||
b = a*s;
|
||||
alpha_ = 2*acos ( min(1.0,sqrt( (b- a* d_pw1)/d_curr)));
|
||||
|
||||
if ( alpha+alpha_ > M_PI){
|
||||
curr_d = d_curr + ew_c;
|
||||
}else
|
||||
{
|
||||
beta_ = 2*acos ( min(1.0,sqrt( (b- a* d_curr)/d_pw1)));
|
||||
beta = acos((w_w1)*(-w1_c)/(ew_w1*ec_w1));
|
||||
|
||||
if ( beta+beta_ > M_PI){
|
||||
curr_d = d_pw1 + ew_w1;
|
||||
}
|
||||
else
|
||||
{
|
||||
theta = M_PI-alpha-alpha_;
|
||||
delta = cos(theta)* ew_c;
|
||||
h = sin(theta)* ew_c;
|
||||
curr_d = sqrt( pow(h,2)+ pow(d_curr + delta,2));
|
||||
}
|
||||
}
|
||||
//**************************************************************************************
|
||||
|
||||
toQueue = (TD[(pw)].d==-1);
|
||||
|
||||
if(toQueue){// se non e'gia' in coda ce lo mette
|
||||
if(RETURN_PATH)//aggiorna il puntatore al genitore se richiesto
|
||||
{
|
||||
if(( TD[curr].d + ew_c) < (d_pw1 + ew_w1))
|
||||
TDP[(pw)].parent = curr;
|
||||
else
|
||||
TDP[(pw)].parent = pw1;
|
||||
assert(curr_d!=0.0);
|
||||
}
|
||||
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
TDS[pw].source = TDS[TDP[pw].parent].source;
|
||||
|
||||
expansion.push_back(pair<TMESH::vertex_pointer,double>(pw,curr_d));
|
||||
isLeaf =false;
|
||||
}else{
|
||||
if( TD[pw].d > curr_d )
|
||||
{
|
||||
if(RETURN_PATH)
|
||||
if(( d_curr + ew_c) < (d_pw1 + ew_w1))
|
||||
TDP[(pw)].parent = curr;
|
||||
else
|
||||
TDP[(pw)].parent = pw1;
|
||||
|
||||
TD[(pw)].d = curr_d;
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
TDS[pw].source = TDS[curr].source;
|
||||
|
||||
assert(!((TD[pw].visited && (TDS[pw].source != TDS[curr].source))));
|
||||
|
||||
isLeaf =false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isLeaf){
|
||||
if(d_curr > max_distance){
|
||||
max_distance = d_curr;
|
||||
fartest = curr;
|
||||
}
|
||||
}
|
||||
|
||||
vector <pair<TMESH::vertex_pointer,double> > ::iterator i;
|
||||
|
||||
for(i = expansion.begin(); i!= expansion.end(); ++i){
|
||||
if(TD[(*i).first].d== -1.0){
|
||||
TD[(*i).first].d = (*i).second;
|
||||
frontier.push_back((*i).first);
|
||||
push_heap(frontier.begin(),frontier.end(),lessThan);
|
||||
}
|
||||
}
|
||||
}// end while: la frontiera e'vuota
|
||||
|
||||
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
if(shortestPath.pathLenght == -1)// i path non si sono incontrati
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
// scrivi le distanze sul campo qualita' (nn: farlo parametrico)
|
||||
TMESH::vertex_iterator vi;
|
||||
for(vi = M.vert.begin(); vi != M.vert.end(); ++vi)
|
||||
(*vi).Q() = TD[&(*vi)].d;
|
||||
|
||||
if(RETURN_PATH)
|
||||
{
|
||||
TMESH::vertex_pointer s;
|
||||
if(CONNECT_TWO_SOURCES)
|
||||
{
|
||||
curr = shortestPath.sources[0];
|
||||
pw = shortestPath.sources[1];
|
||||
|
||||
if(TDS[curr].source != sources[0]) swap(curr,pw);
|
||||
|
||||
// curr e' il vertice estremo di una sorgente
|
||||
// pw quello dell'altra
|
||||
max_distance = TD[curr].d+ TD[pw].d + Distance(curr->cP(),pw->cP());
|
||||
s = TDS[pw].source;
|
||||
while(pw!=NULL){// pw->Q() = 2.0 *max_distance;
|
||||
assert(TDS[pw].source == s);
|
||||
path.push_front(pw);
|
||||
pw = TDP[pw].parent;
|
||||
}
|
||||
s=TDS[curr].source;
|
||||
}
|
||||
while(curr!=NULL){
|
||||
//curr->Q() = max_distance;
|
||||
assert(!CONNECT_TWO_SOURCES || (TDS[curr].source == s));
|
||||
path.push_back(curr);
|
||||
curr = TDP[curr].parent;
|
||||
}
|
||||
}
|
||||
|
||||
TD.Stop();
|
||||
TDP.Stop();
|
||||
TDS.Stop();
|
||||
return CONNECT_TWO_SOURCES? 0 : fartest;
|
||||
}
|
||||
|
||||
// SelectRegion: dato un vertice esegue una visita di superficie.
|
||||
// Un ramo della visita si ferma quando incontra un vertice marcato S(elected)
|
||||
// Serve per selecionare delle regioni delimitate da liste di vertici gia' definite
|
||||
template <class STL_CONT_VERT,class STL_CONT_FACE, bool LIMITED, bool USE_FLAG_V>
|
||||
bool SelectRegion(int iter,STL_CONT_VERT & frontier, STL_CONT_FACE & result ) {
|
||||
//result.clear();
|
||||
int i =0 ;
|
||||
TMESH::vertex_pointer curr=NULL;
|
||||
if (!USE_FLAG_V)
|
||||
TD.Start(TempData<TMESH>(-1.0));
|
||||
|
||||
//Requirements
|
||||
assert(M.HasVFTopology());
|
||||
|
||||
if(M.vn==0) return false;
|
||||
|
||||
|
||||
bool toQueue;
|
||||
TMESH::EdgePos x;int k;
|
||||
TMESH::vertex_pointer pw;
|
||||
|
||||
while((!frontier.empty())&&( LIMITED?(i<iter):true))
|
||||
{ if(LIMITED)
|
||||
i++;
|
||||
curr = frontier.back();
|
||||
frontier.pop_back();
|
||||
|
||||
if (USE_FLAG_V)
|
||||
curr->SetV();
|
||||
else
|
||||
TD[curr].visited = true;
|
||||
|
||||
for( x.f = curr->Fp(), x.z = curr->Zp(); x.f!=0; x.NextF() )
|
||||
for(k=0;k<2;++k)
|
||||
{
|
||||
if(k==0) pw = x.f->V1(x.z);
|
||||
else pw = x.f->V2(x.z);
|
||||
|
||||
if(!(x.f)->IsS())
|
||||
result.push_back(x.f);
|
||||
|
||||
if(!pw->IsV() && !pw->IsS())
|
||||
frontier.push_back(pw);
|
||||
}
|
||||
}
|
||||
|
||||
if (!USE_FLAG_V)
|
||||
TD.Stop();
|
||||
|
||||
return frontier.empty();
|
||||
|
||||
}
|
||||
|
||||
// versione temporanea: data una faccia e un vertice seleziona la regione
|
||||
// procedendo per adiacenze faccia-faccia
|
||||
|
||||
struct TempDataFace{
|
||||
TempDataFace():front(0){}
|
||||
TempDataFace(const short int & _front):front(_front){}
|
||||
short int front;
|
||||
bool IsV(const int &i){
|
||||
return (front & (1<<i));
|
||||
}
|
||||
bool SetV(const int &i){
|
||||
return (front|= (1<<i));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TempData_vect<TMESH::face_type, TempDataFace > TDF;
|
||||
|
||||
// versione rozza: non fa region growing, se si limita il numero di iterazioni
|
||||
// puo'terminare con un insieme di facce a genus diverso da zero
|
||||
template <class STL_CONT_VERT,class STL_CONT_FACE, bool LIMITED,bool USE_FLAG_V>
|
||||
bool SelectRegionFF(int iter,STL_CONT_FACE & frontier, STL_CONT_FACE & result ) {
|
||||
//result.clear();
|
||||
int i =0, h=0 ;
|
||||
TDF.Start(TempDataFace(0));
|
||||
|
||||
TMESH::face_pointer curr= NULL;
|
||||
|
||||
if (!USE_FLAG_V)
|
||||
TD.Start(TempData<TMESH>(-1.0));
|
||||
//Requirements
|
||||
assert(M.HasFFTopology());
|
||||
|
||||
if(M.vn==0) return false;
|
||||
|
||||
bool toQueue;
|
||||
TMESH::vedgepos_type x;int k;
|
||||
TMESH::vertex_pointer pw;
|
||||
|
||||
while((!frontier.empty())&&( LIMITED?(i<iter):true))
|
||||
{ if(LIMITED)
|
||||
i++;
|
||||
curr = frontier.back();
|
||||
frontier.pop_back();
|
||||
|
||||
curr->SetV();
|
||||
for(h = 0; h<3;++h){
|
||||
TMESH::face_type* iii =(TMESH::face_type* )curr->F(h);
|
||||
TempDataFace & tdf = TDF[iii];
|
||||
if( !tdf.IsV(curr->Z(h)) && (curr->F(h) != curr)){
|
||||
if(!(curr->F(h))->IsS()) {
|
||||
result.push_back((TMESH::face_type* )curr->F(h));
|
||||
frontier.push_back((TMESH::face_type* )curr->F(h));
|
||||
}
|
||||
tdf.SetV(curr->Z(h));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TDF.Stop();
|
||||
return frontier.empty();
|
||||
}
|
||||
|
||||
|
||||
// multiple sorgenti - no max iter
|
||||
template <class STL_CONT_VERT,class STL_CONT_FACE, bool USE_FLAG_V>
|
||||
bool SelectRegion(STL_CONT_VERT & frontier, STL_CONT_FACE & result){
|
||||
return SelectRegion<STL_CONT_VERT,STL_CONT_FACE, false,USE_FLAG_V>
|
||||
(STL_CONT_VERT & frontier, STL_CONT_FACE & result );
|
||||
}
|
||||
|
||||
// multiple sorgenti - max iter
|
||||
template <class STL_CONT_VERT,class STL_CONT_FACE, bool USE_FLAG_V>
|
||||
bool SelectRegion(STL_CONT_VERT & frontier, STL_CONT_FACE & result, int iter){
|
||||
return SelectRegion<STL_CONT_VERT,STL_CONT_FACE, false,USE_FLAG_V>
|
||||
(iter,STL_CONT_VERT & frontier, STL_CONT_FACE & result);
|
||||
}
|
||||
|
||||
// singola sorgente - max iter
|
||||
template <class STL_CONT_VERT,class STL_CONT_FACE, bool USE_FLAG_V>
|
||||
bool SelectRegion(const TMESH::vertex_pointer & v0, STL_CONT_FACE & result, int iter) {
|
||||
|
||||
STL_CONT_VERT frontier;
|
||||
frontier.push_back(v0);
|
||||
return SelectRegion<STL_CONT_VERT,STL_CONT_FACE,true,USE_FLAG_V>( iter, frontier,result);
|
||||
}
|
||||
|
||||
// singola sorgente - no max iter
|
||||
template <class STL_CONT_VERT,class STL_CONT_FACE, bool USE_FLAG_V>
|
||||
bool SelectRegion(const TMESH::vertex_pointer & v0, STL_CONT_FACE & result) {
|
||||
|
||||
STL_CONT_VERT frontier;
|
||||
frontier.push_back(v0);
|
||||
return SelectRegion<STL_CONT_VERT,STL_CONT_FACE,false,USE_FLAG_V>( 0, frontier,result);
|
||||
}
|
||||
|
||||
|
||||
template<class TMESH>
|
||||
struct cp{
|
||||
cp(){};
|
||||
cp(TMESH::vertex_pointer v0_,TMESH::vertex_pointer v1_):v0(v0_),v1(v1_){};
|
||||
TMESH::vertex_pointer v0,v1;
|
||||
const bool operator != (const cp<TMESH> & other)const {
|
||||
return ( ( v0 != other.v0) || ( v1 != other.v1));
|
||||
}
|
||||
|
||||
const bool operator < (const cp<TMESH> & other)const {
|
||||
return ( ( v0 == other.v0)? ( v1 < other.v1):v0 < other.v0);
|
||||
}
|
||||
};
|
||||
|
||||
set<cp<TMESH> > connected;
|
||||
bool AreConn(TMESH::vertex_pointer v0,TMESH::vertex_pointer v1){
|
||||
return (connected.find(cp<TMESH>(v0,v1))!=connected.end());
|
||||
}
|
||||
void Conn(TMESH::vertex_pointer v0,TMESH::vertex_pointer v1){
|
||||
connected.insert(cp<TMESH>(v0,v1));
|
||||
connected.insert(cp<TMESH>(v1,v0));
|
||||
}
|
||||
|
||||
|
||||
void Delaunay(
|
||||
deque<TMESH::vertex_pointer> &path,
|
||||
vector<TMESH::vertex_pointer> & _frontier)
|
||||
{
|
||||
TMESH::vertex_pointer s;
|
||||
bool isLeaf,found=false;
|
||||
vector<TMESH::vertex_pointer> frontier;
|
||||
frontier.clear();
|
||||
//Requirements
|
||||
assert(M.HasVFTopology());
|
||||
TMESH::vertex_iterator ii;
|
||||
list<TMESH::vertex_pointer> children;
|
||||
TMESH::vertex_pointer curr = NULL,fartest,pw1;
|
||||
bool toQueue;
|
||||
|
||||
TD.Start(TempData<TMESH>(-1.0));
|
||||
TDP.Start(TempDataPath<TMESH>(NULL));
|
||||
|
||||
list<TMESH::vertex_pointer>::iterator is;
|
||||
deque<TMESH::vertex_pointer> leaves;
|
||||
vector <pair<TMESH::vertex_pointer,TMESH::scalar_type> > expansion;
|
||||
|
||||
vector <TMESH::vertex_pointer >::const_iterator ifr;
|
||||
TMESH::EdgePos x;int k;
|
||||
TMESH::vertex_pointer pw;
|
||||
|
||||
for(ifr = _frontier.begin(); ifr != _frontier.end(); ++ifr){
|
||||
TD[*ifr].visited= true;
|
||||
TD[*ifr].d = 0.0;
|
||||
}
|
||||
|
||||
TDS.Start(TempDataSource<TMESH>(NULL));
|
||||
for(ifr = _frontier.begin(); ifr != _frontier.end(); ++ifr)
|
||||
TDS[*ifr].source= (*ifr);
|
||||
|
||||
for(ifr = _frontier.begin(); ifr != _frontier.end(); ++ifr)
|
||||
{
|
||||
|
||||
TDP[*ifr].parent=NULL;
|
||||
// determina la distanza dei vertici della fan
|
||||
for( x.f = (*ifr)->Fp(), x.z = (*ifr)->Zp(); x.f!=0; x.NextF() )
|
||||
for(k=0;k<2;++k)
|
||||
{
|
||||
if(k==0) pw = x.f->V1(x.z);
|
||||
else pw = x.f->V2(x.z);
|
||||
|
||||
if(TD[pw].d ==-1){
|
||||
TD[pw].d = Distance(pw->cP(),(*ifr)->cP());
|
||||
frontier.push_back(pw);
|
||||
|
||||
if(TD[pw].visited)
|
||||
TDP[pw].parent= (*ifr);
|
||||
TDS[pw].source = (*ifr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
make_heap(frontier.begin(),frontier.end(),lessThan);
|
||||
double curr_d,d_curr = 0.0;
|
||||
|
||||
vector<TMESH::vertex_type >:: iterator iv;
|
||||
while(!frontier.empty()){
|
||||
|
||||
expansion.clear();
|
||||
|
||||
pop_heap(frontier.begin(),frontier.end(),lessThan);
|
||||
curr = frontier.back();
|
||||
frontier.pop_back();
|
||||
d_curr = TD[curr].d;
|
||||
TD[curr].visited=true;
|
||||
|
||||
isLeaf = true;
|
||||
|
||||
TMESH::EdgePos x;int k;
|
||||
|
||||
for( x.f = curr->Fp(), x.z = curr->Zp(); x.f!=0; x.NextF() )
|
||||
for(k=0;k<2;++k)
|
||||
{
|
||||
if(k==0) {
|
||||
pw = x.f->V1(x.z);
|
||||
pw1=x.f->V2(x.z);
|
||||
}
|
||||
else {
|
||||
pw = x.f->V2(x.z);
|
||||
pw1=x.f->V1(x.z);
|
||||
}
|
||||
const double & d_pw1 = TD[pw1].d;
|
||||
|
||||
if((!TD[pw1].visited ) ||(d_pw1 == 0.0) ||
|
||||
(TD[pw].visited && (TDS[pw].source == TDS[curr].source))
|
||||
)
|
||||
continue;
|
||||
|
||||
if( (TDS[pw].source!=TDS[curr].source) && (TDS[pw].source!=NULL)&& (TDS[curr].source!=NULL)
|
||||
)
|
||||
if(AreConn(TDS[pw].source,TDS[curr].source)) continue;
|
||||
else
|
||||
found=true;
|
||||
|
||||
if( (TDS[pw1].source!=TDS[curr].source) && (TDS[pw1].source!=NULL)&& (TDS[curr].source!=NULL))
|
||||
{
|
||||
if(AreConn(TDS[pw1].source,TDS[curr].source))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
pw = pw1;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(found){
|
||||
s = TDS[pw].source;
|
||||
TMESH::vertex_pointer v0 = pw,v1=curr;
|
||||
while(v0!=NULL){
|
||||
//v0->Q() = 2.0;
|
||||
assert(TDS[v0].source == s);
|
||||
path.push_front(v0);
|
||||
v0 = TDP[v0].parent;
|
||||
}
|
||||
|
||||
s=TDS[v1].source;
|
||||
while(v1!=NULL){
|
||||
//v1->Q() = 10;
|
||||
assert(TDS[v1].source == s);
|
||||
path.push_back(v1);
|
||||
v1 = TDP[v1].parent;
|
||||
}
|
||||
Conn(TDS[pw].source,TDS[curr].source);
|
||||
assert(AreConn(TDS[pw].source,TDS[curr].source));
|
||||
found = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
assert(TDS[pw1].source == TDS[curr].source);
|
||||
assert((TDP[curr].parent == NULL) || TDS[curr].source == TDS[TDP[curr].parent].source);
|
||||
assert( TD[pw1].d != -1);
|
||||
assert( TD[pw1].d != 0.0);
|
||||
assert( (curr!=pw) && (pw!=pw1) && (pw1 != curr));
|
||||
assert(d_pw1!=-1.0);
|
||||
|
||||
//************** calcolo della distanza di pw in base alle distanze note di pw1 e curr
|
||||
//************** sapendo che (curr,pw,pw1) e'una faccia della mesh
|
||||
//************** (vedi figura in file distance.gif)
|
||||
Point3<TMESH::scalar_type> w_c = pw->cP()- curr->cP();
|
||||
Point3<TMESH::scalar_type> w_w1 = pw->cP()- pw1->cP();
|
||||
Point3<TMESH::scalar_type> w1_c = pw1->cP()- curr->cP();
|
||||
|
||||
double ew_c = (w_c).Norm();
|
||||
double ew_w1 = (w_w1).Norm();
|
||||
double ec_w1 = (w1_c).Norm();
|
||||
double alpha,alpha_, beta,beta_,theta_c,theta,h,delta,s,a,b;
|
||||
|
||||
alpha = acos((w_c*w1_c)/(ew_c*ec_w1));
|
||||
s = (d_curr + d_pw1+ec_w1)/2;
|
||||
a = s/ec_w1;
|
||||
b = a*s;
|
||||
alpha_ = 2*acos ( min(1.0,sqrt( (b- a* d_pw1)/d_curr)));
|
||||
|
||||
if ( alpha+alpha_ > M_PI){
|
||||
curr_d = d_curr + ew_c;
|
||||
}else
|
||||
{
|
||||
beta_ = 2*acos ( min(1.0,sqrt( (b- a* d_curr)/d_pw1)));
|
||||
beta = acos((w_w1)*(-w1_c)/(ew_w1*ec_w1));
|
||||
|
||||
if ( beta+beta_ > M_PI){
|
||||
curr_d = d_pw1 + ew_w1;
|
||||
}
|
||||
else
|
||||
{
|
||||
theta = M_PI-alpha-alpha_;
|
||||
delta = cos(theta)* ew_c;
|
||||
h = sin(theta)* ew_c;
|
||||
curr_d = sqrt( pow(h,2)+ pow(d_curr + delta,2));
|
||||
}
|
||||
}
|
||||
//**************************************************************************************
|
||||
|
||||
toQueue = (TD[(pw)].d==-1);
|
||||
|
||||
if(toQueue){// se non e'gia' in coda ce lo mette
|
||||
if(( TD[curr].d + ew_c) < (d_pw1 + ew_w1))
|
||||
TDP[(pw)].parent = curr;
|
||||
else
|
||||
TDP[(pw)].parent = pw1;
|
||||
assert(curr_d!=0.0);
|
||||
TDS[pw].source = TDS[curr].source;
|
||||
|
||||
expansion.push_back(pair<TMESH::vertex_pointer,double>(pw,curr_d));
|
||||
isLeaf =false;
|
||||
}else{
|
||||
if( TD[(pw)].d > curr_d )
|
||||
{
|
||||
if(( d_curr + ew_c) < (d_pw1 + ew_w1))
|
||||
TDP[(pw)].parent = curr;
|
||||
else
|
||||
TDP[(pw)].parent = pw1;
|
||||
|
||||
TD[(pw)].d = curr_d;
|
||||
TDS[pw].source = TDS[curr].source;
|
||||
isLeaf =false;
|
||||
}
|
||||
}
|
||||
|
||||
vector <pair<TMESH::vertex_pointer,double> > ::iterator i;
|
||||
// unique(expansion.begin(),expansion.end());
|
||||
for(i = expansion.begin(); i!= expansion.end(); ++i){
|
||||
if(TD[(*i).first].d== -1.0){
|
||||
TD[(*i).first].d = (*i).second;
|
||||
frontier.push_back((*i).first);
|
||||
push_heap(frontier.begin(),frontier.end(),lessThan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}// end while
|
||||
// scrivi le distanze sul campo qualita' (nn: farlo parametrico)
|
||||
/*
|
||||
TMESH::vertex_iterator vi;
|
||||
for(vi = M.vert.begin(); vi != M.vert.end(); ++vi)
|
||||
(*vi).Q() = TD[&(*vi)].d;
|
||||
*/
|
||||
|
||||
|
||||
TD.Stop();
|
||||
TDP.Stop();
|
||||
TDS.Stop;
|
||||
|
||||
}
|
||||
public:
|
||||
template <bool SKIP_SELECTED>
|
||||
void FartestPoint( vector<TMESH::vertex_pointer> & fro,//insieme di vertici da cui trovare le distanze
|
||||
TMESH::vertex_pointer & fartest, //punto piu'lontano
|
||||
double & distance){ //distaza geodesica
|
||||
deque<TMESH::vertex_pointer> _;
|
||||
fartest = BuildSP<false,false,false,SKIP_SELECTED> (_,fro,distancee);
|
||||
}
|
||||
template <bool SKIP_SELECTED>
|
||||
void FartestPoint( vector<TMESH::vertex_pointer> & fro, //insieme di vertici da cui trovare le distanze
|
||||
TMESH::vertex_pointer & fartest, //punto piu'lontano
|
||||
double & distance, //distaza geodesica
|
||||
deque<TMESH::vertex_pointer> & path){// ritorna esplicitamente il cammino minimo
|
||||
vector<TMESH::vertex_pointer> _;
|
||||
fartest = BuildSP<true,false,false,SKIP_SELECTED>(path,fro,distance);
|
||||
}
|
||||
template <bool SKIP_SELECTED>
|
||||
void FartestBPoint( vector<TMESH::vertex_pointer> & fro, //insieme di vertici da cui trovare le distanze
|
||||
TMESH::vertex_pointer & fartest, //punto piu'lontano
|
||||
double & distance, //distaza geodesica
|
||||
deque<TMESH::vertex_pointer> & path){// ritorna esplicitamente il cammino minimo
|
||||
vector<TMESH::vertex_pointer> _;
|
||||
fartest = BuildSP<true,false,false,SKIP_SELECTED>(path,fro,distance);
|
||||
}
|
||||
template <bool SKIP_SELECTED>
|
||||
void FartestBPoint( vector<TMESH::vertex_pointer> & fro, //insieme di vertici da cui trovare le distanze
|
||||
TMESH::vertex_pointer & fartest, //punto piu'lontano
|
||||
double & distance){ //distaza geodesica
|
||||
deque<TMESH::vertex_pointer> _;
|
||||
fartest = BuildSP<true,false,true,SKIP_SELECTED>(_,fro,distance);
|
||||
}
|
||||
|
||||
template <bool SKIP_SELECTED>
|
||||
void FindPath( const TMESH::vertex_pointer & v0, //vertice di partenza
|
||||
const TMESH::vertex_pointer & v1, //vertice cercato
|
||||
deque<TMESH::vertex_pointer> & path,
|
||||
double & dist)
|
||||
{
|
||||
vector<TMESH::vertex_pointer> fro;
|
||||
fro.push_back(v0);
|
||||
fro.push_back(v1);
|
||||
BuildSP<true,true,false,SKIP_SELECTED>(path,fro,dist);
|
||||
|
||||
// v0 = fro[0];
|
||||
// v1 = fro[1];
|
||||
}
|
||||
|
||||
template <bool SKIP_SELECTED>
|
||||
bool MostInternal( TMESH::vertex_pointer & v0, //ritorna il vertice piu'lontano da ogni punto sul bordo
|
||||
TMESH::vertex_pointer & v1, // ritorna il vertice di bordo piu'vicino a v0
|
||||
double & distance, // distanza geodesica tra v0 e v1
|
||||
deque<TMESH::vertex_pointer> & path)// ritorna il path tra i due
|
||||
{
|
||||
vector<TMESH::vertex_pointer> border_vertices;
|
||||
|
||||
TMESH::vertex_iterator ii;
|
||||
double maxDistance = 0.0;
|
||||
|
||||
for(ii = M.vert.begin(); ii != M.vert.end();++ii)
|
||||
if((*ii).IsB())
|
||||
border_vertices.push_back(&(*ii));
|
||||
|
||||
if(border_vertices.empty()) return false;
|
||||
|
||||
vector<TMESH::vertex_pointer> _;
|
||||
|
||||
BuildSP<true,false,false,SKIP_SELECTED>(path,border_vertices,distance);
|
||||
|
||||
if(path.empty()) return false;
|
||||
v0 = *path.begin();
|
||||
v1 = path.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool SKIP_SELECTED>
|
||||
bool MostInternal( TMESH::vertex_pointer & v0, //ritorna il vertice piu'lontano da ogni punto sul bordo
|
||||
TMESH::vertex_pointer & v1, // ritorna il vertice di bordo piu'vicino a v0
|
||||
double & distance// distanza geodesica tra v0 e v1
|
||||
)
|
||||
{
|
||||
vector<TMESH::vertex_pointer> border_vertices;
|
||||
deque<TMESH::vertex_pointer> path;
|
||||
TMESH::vertex_iterator ii;
|
||||
double maxDistance = 0.0;
|
||||
|
||||
for(ii = M.vert.begin(); ii != M.vert.end();++ii)
|
||||
if((*ii).IsB())
|
||||
border_vertices.push_back(&(*ii));
|
||||
|
||||
if(border_vertices.empty()) return false;
|
||||
BuildSP<true,false,false,SKIP_SELECTED>(path,border_vertices,distance);
|
||||
if(path.empty()) return false;
|
||||
v0 = *path.begin();
|
||||
v1 = path.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue