First working version!
This commit is contained in:
parent
d7d79a8867
commit
9c4727960d
|
@ -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
|
Loading…
Reference in New Issue