First working version!

This commit is contained in:
Paolo Cignoni 2004-03-29 14:26:57 +00:00
parent d7d79a8867
commit 9c4727960d
1 changed files with 144 additions and 1049 deletions

View File

@ -1,41 +1,34 @@
/*#*************************************************************************** /****************************************************************************
* Geodesic.h o o * * VCGLib o o *
* o o * * Visual and Computer Graphics Library o o *
* Visual Computing Group _ O _ * * _ O _ *
* IEI Institute, CNUCE Institute, CNR Pisa \/)\/ * * Copyright(C) 2004 \/)\/ *
* /\/| * * Visual Computing Lab /\/| *
* Copyright(C) 1999 by Paolo Cignoni, | * * ISTI - Italian National Research Council | *
* All rights reserved. \ * * \ *
* * * 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 * * This program is free software; you can redistribute it and/or modify *
* that the above copyright notice appear in all copies and that both that * * it under the terms of the GNU General Public License as published by *
* copyright notice and this permission notice appear in supporting * * the Free Software Foundation; either version 2 of the License, or *
* documentation. the author makes no representations about the suitability * * (at your option) any later version. *
* of this software for any purpose. It is provided "as is" without express * * *
* or implied warranty. * * 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 History
2002 Apr 01 First Working release copiata, ripulita e templatata dal plyvcg(pc) $Log: not supported by cvs2svn $
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)
*#**************************************************************************/
#ifndef __VCG_GEODESIC__ ****************************************************************************/
#define __VCG_GEODESIC__
#ifndef __VCG_GEODESIC
#define __VCG_GEODESIC
namespace vcg { 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 #endif