PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in...

36
POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per il CALCOLO SCIENTIFICO PROGETTO: Proiezione di punti su una superficie triangolata. progetto di: Elisa Maculan Matr. 679979 Anno Accademico 2006-2007

Transcript of PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in...

Page 1: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

POLITECNICO DI MILANO

Corso di Laurea Specialistica in Ingegneria MatematicaOrientamento Calcolo Scientifico

PROGRAMMAZIONE AVANZATA

per il

CALCOLO SCIENTIFICO

PROGETTO: Proiezione di punti su una superficie triangolata.

progetto di:Elisa MaculanMatr. 679979

Anno Accademico 2006-2007

Page 2: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Indice

1 Introduzione 2

2 Classi e strutture 32.1 Struct Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 Class Triangle . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 Class Mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3 Funzioni e metodi 103.1 Proiezione di un punto su un piano . . . . . . . . . . . . . . . 103.2 Appartenenza di un punto ad un triangolo . . . . . . . . . . . 14

4 Ricerca del triangolo stl di appartenenza della proiezione diogni nodo della mesh netgen 214.1 Metodo brute force . . . . . . . . . . . . . . . . . . . . . . . . 214.2 Metodo con ricerca del nodo stl piu vicino al nodo netgen . . 234.3 Metodo con algoritmo di ricerca del nearest neighbor . . . . . 25

5 Applicazioni e problemi riscontrati 28

6 Algoritmi alternativi 31

1

Page 3: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

1 Introduzione

Date una mesh netgen ed una superficie triangolata stl, l’obiettivo di questolavoro e quello di trovare per ogni nodo della mesh netgen i tre nodi piuvicini, nello spazio 3D, della superficie stl. Le due mesh sono fornite a priorie l’idea che si desidera sviluppare e quella di cercare per ogni nodo netgen iltriangolo stl a cui appartiene la sua proiezione, dato che il nodo netgen puonon giacere sul piano definito da un triangolo stl.

La ricerca dei tre nodi stl piu vicini ad ogni nodo netgen e utile in quantoper ogni nodo stl sono noti i suoi spostamenti in dieci istanti temporali diver-si. Percio, una volta individuati i tre nodi stl piu vicini ad un nodo netgened interpolati i loro spostamenti, si riesce a calcolare anche lo spostamentodel nodo netgen e quindi a ricostruire la mesh netgen ad ogni istante tem-porale. Questa mesh verra usata per il calcolo fluidodinamico d’interazionefluido-struttura, pero con struttura nota.

Per spiegare il procedimento seguito per il raggiungimento dell’obiettivo,questo lavoro si articola in paragrafi nel seguente modo:

• Paragrafo 2: CLASSI E STRUTTUREBreve descrizione della struttura Point e delle classi Triangle e Mesh,necessarie per la lettura della mesh netgen e della superficie triangolatastl di partenza.

• Paragrafo 3: FUNZIONI E METODIDescrizione delle idee teoriche alla base della funzione esterna di proiezionedi un punto sul piano individuato da un triangolo e del metodo dellaclasse Triangle che verifica l’appartenenza di un punto ad un triangolo,quando giacciono sullo stesso piano.

• Paragrafo 4: RICERCA DEL TRIANGOLO STL DI AP-PARTENENZA DELLA PROIEZIONE DI OGNI NODO NET-GENDescrizione di tre metodi differenti per la ricerca del triangolo stl diappartenenza. Il primo consiste in un metodo brute force che cicla sututti i triangoli della superficie stl, calcolando la proiezione di ogni no-do netgen sul piano individuato da ciascun triangolo e l’appartenenzadella proiezione stessa ad ogni triangolo stl. Il secondo, invece, ciclasu tutti i nodi stl per cercare quello piu vicino ad ogni nodo netgen;in seguito calcola proiezione e sua appartenenza ad ogni triangolo nel

2

Page 4: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

patch del nodo stl piu vicino. Il terzo esegue le stesse operazioni delsecondo, ma rende piu veloce ed efficiente la ricerca del nodo stl piuvicino sfruttando un algoritmo di ricerca del nearest neighbor di unalibreria esterna, la libreria ANN.

• Paragrafo 5: APPLICAZIONI E PROBLEMI RISCONTRATIApplicazione dei tre metodi ad un caso test semplice con mesh costi-tuite da pochissimi nodi (cilindro) e ad un caso reale piu complesso(arco aortico). Analisi dei problemi riscontrati eseguendo il codiceimplementato nel caso reale con geometria poco regolare.

• Paragrafo 6: ALGORITMI ALTERNATIVIDescrizione di due algoritmi alternativi, implementati per risolvere iproblemi descritti nel paragrafo precedente. Il primo algoritmo sfruttala libreria ANN per la ricerca diretta dei tre nearest neighbor di ogninodo netgen; il secondo calcola il baricentro di ogni triangolo stl, ricer-ca il baricentro piu vicino ad ogni nodo netgen e considera i vertici deltriangolo con questo baricentro come i tre punti stl piu vicini al nodonetgen.

2 Classi e strutture

In questo paragrafo introduciamo brevemente attributi e metodi delle strut-ture di base implementate, necessarie per la lettura della mesh netgen e dellasuperficie stl note e per i calcoli successivi.

2.1 Struct Point

Per leggere i nodi di una mesh e i punti 3D si e deciso di usare una strut-tura in modo tale da avere degli attributi pubblici a cui poter accederedirettamente, senza bisogno di metodi appositi. Questo perche si e sceltodi richiamare gli attributi in modo diretto anche nella funzione esterna diproiezione, ma naturalmente e possibile effettuare altre scelte.La struttura Point e dotata di quattro attributi:

double x;

double y;

double z;

che rappresentano le tre coordinate spaziali

3

Page 5: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

int ID;

che rappresenta un indicatore del nodo nella mesh ed e posto = −1 didefault per punti 3D che non appartengono ad alcuna mesh.

Per questa struttura vengono forniti diversi costruttori:

//costruttore di default

Point():x(0.0),y(0.0),z(0.0),ID(-1) {};

//costruttore che legge da file

Point(char* fileName,int num):ID(-1) {};

//costruttore a cui passo tre numeri in ingresso

Point(const double a, const double b, const double c):

x(a),y(b),z(c),ID(-1) {};

//costruttore di copia

Point(const Point& P): x(P.x),y(P.y),z(P.z),ID(P.ID) {}; .

Il distruttore non viene sovrascritto, dato che risulta essere gia adatto quellodi default. Questo, infatti, distrugge i membri della classe, che nel nostrocaso sono di tipo nativo, e quindi vengono distrutti in modo adeguato dalcompilatore.Infine si ha l’overloading degli operatori =, <<, ==, ! =

Point& operator=(const Point& P)

{x=P.x;

y=P.y;

z=P.z;

ID=P.ID;}

friend ostream& operator<<(ostream& s, const Point& P)

{s<<P.x<<" "<<P.y<<" "<<P.z<<" "<<P.ID;

return s;}

friend bool const operator==(const Point& P1, const Point& P2)

{

if(P1.x==P2.x && P1.y==P2.y && P1.z==P2.z)

return true;

4

Page 6: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

else

return false;

}

friend bool const operator!=(const Point& P1, const Point& P2)

{

if(P1.x!=P2.x && P1.y!=P2.y && P1.z!=P2.z)

return true;

else

return false;

} .

2.2 Class Triangle

Questa classe puo rappresentare un triangolo di una mesh oppure un qual-siasi triangolo posizionato in uno spazio 3D.I suoi attributi sono i seguenti:

Vertices vertici;

un vettore di tre punti che rappresenta i tre vertici del triangolo

Point normale;

che rappresenta la normale al triangolo (in realta questa sarebbe unvettore, ma in uno spazio 3D risulta comunque individuata da trecoordinate spaziali, l’ID e posto = −1 di default)

int ID;

che rappresenta un indicatore del triangolo nella mesh ed e posto = −1di default per triangoli 3D che non appartengono ad alcuna mesh.

Per quanto riguarda i metodi, ci sono diversi costruttori:

//costruttore che legge da file

Triangle(char* fileName,int num):ID(-1) {};

//costruttore che riceve tre punti in ingresso + la normale

Triangle(const Point& N, const Point& P1, const Point& P2, const

Point& P3):normale(N),ID(-1)

{

vertici.push_back(P1);

5

Page 7: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

vertici.push_back(P2);

vertici.push_back(P3);

}

//costruttore che riceve tre punti in ingresso

Triangle(const Point& P1, const Point& P2, const Point& P3):ID(-1)

{

vertici.push_back(P1);

vertici.push_back(P2);

vertici.push_back(P3);

normale = this->calcolanormale();

}

//costruttore che riceve in ingresso un vettore di vertici+la normale

Triangle(const Point& N,const Vertices& v):normale(N),ID(-1)

{

if(v.size()==3)

{ vertici.push_back(v.at(0));

vertici.push_back(v.at(1));

vertici.push_back(v.at(2));}

else {cout<<"dimensione del vettore di vertici passato deve essere = 3";}

}

//costruttore di copia

Triangle(const Triangle& T): normale(T.normale),ID(T.ID)

{

vertici.push_back(T.vertici.at(0));

vertici.push_back(T.vertici.at(1));

vertici.push_back(T.vertici.at(2));}

e per il distruttore viene usato ancora quello di default.Vi sono metodi per accedere agli attributi privati

//metodo che ritorna il vettore di vertici

vector<Point> getvertici() const {return vertici;}

//metodo che ritorna un vertice specifico

Point getvertice(int i) const {return vertici.at(i);}

6

Page 8: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

//metodo che ritorna la normale

Point getnormale() const {return normale;}

//metodo che ritorna l’ID

int getID() const {return ID;}

metodi per assegnare il valore agli attributi privati

//metodo che setta l’ID

void setID(int i) {ID=i;}

//metodo che setta la normale

void setnormale(Point N) {normale=N;}

metodi per calcolare attributi o grandezze caratteristiche del triangolo

//metodo che calcola il versore normale dati i vertici del triangolo

Point calcolanormale()

{

double a,b,c;

a=(vertici.at(1).y-vertici.at(0).y)*(vertici.at(2).z-vertici.at(0).z)

-(vertici.at(1).z-vertici.at(0).z)*(vertici.at(2).y-vertici.at(0).y);

b=(vertici.at(1).z-vertici.at(0).z)*(vertici.at(2).x-vertici.at(0).x)

-(vertici.at(1).x-vertici.at(0).x)*(vertici.at(2).z-vertici.at(0).z);

c=(vertici.at(1).x-vertici.at(0).x)*(vertici.at(2).y-vertici.at(0).y)

-(vertici.at(1).y-vertici.at(0).y)*(vertici.at(2).x-vertici.at(0).x);

//calcolo il versore normale

Point N;

N.x=a/sqrt(a*a+b*b+c*c);

N.y=b/sqrt(a*a+b*b+c*c);

N.z=c/sqrt(a*a+b*b+c*c);

return N;

}

//metodo che calcola il baricentro del triangolo dati i vertici

Point baricentro()

{

double xb,yb,zb;

xb=(vertici.at(0).x+vertici.at(1).x+vertici.at(2).x)/3;

yb=(vertici.at(0).y+vertici.at(1).y+vertici.at(2).y)/3;

7

Page 9: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

zb=(vertici.at(0).z+vertici.at(1).z+vertici.at(2).z)/3;

Point B(xb,yb,zb);

return B;

}

ed infine sono implementati i metodi

bool appartTriangle(const Point & P) {};

bool proiezandappart(const Point & P) {};

bool proiezandappart(const Point & P,double & dist) {};

bool proiezandappart(const Point & P,double & dist,

const Point & N){};

che saranno descritti piu precisamente nel paragrafo successivo.Anche per questa classe vengono sovrascritti gli operatori = e <<

friend ostream& operator<<(ostream& s, const Triangle& T)

{s<<"triangolo: "<<endl<<" vertice 1: "<<T.vertici[0]<<"\n vertice 2: "

<<T.vertici[1]<<"\n vertice 3: "<<T.vertici[2]<<"\n normale: "<<

T.normale<<"\n ID: "<<T.ID<<endl;

return s;}

Triangle& operator=(const Triangle& T)

{vertici.push_back(T.vertici.at(0));

vertici.push_back(T.vertici.at(1));

vertici.push_back(T.vertici.at(2));

normale=T.normale;

ID=T.ID;} .

2.3 Class Mesh

Questa classe rappresenta naturalmente una mesh ed e dotata di due soliattributi privati:

Nodes Mnodi;

vettore di punti che contiene tutti i nodi della mesh

8

Page 10: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Elements Mtriang;

vettore dei triangoli superficiali della mesh (per la mesh netgen non edefinito perche questa mesh non contiene informazioni sui triangoli).

Gli unici costruttori forniti leggono dal file.neu per costruire la mesh netgene dal file.stl per costruire la mesh stl:

//costruttore che legge da file.neu

Mesh(char* fileName, int ns, int es) {};

//costruttore che legge da file.stl

Mesh(char* fileName) {}; .

Questo secondo costruttore sfrutta anche le informazioni provenienti dalfile.dat, se questo e disponibile, risultando pero molto lento; per questoscrive la mesh in un file.txt piu strutturato e veloce da leggere che vieneusato tutte le volte successive in cui viene eseguito il codice.Ci sono poi metodi che ritornano il numero di nodi o di triangoli ed un nodoo un triangolo specifico:

//numero di punti

inline int nP() const {return Mnodi.size();}

//numero di triangoli (elementi di superficie)

inline int nT() const {return Mtriang.size();}

//referenza al nodo i-esimo (solo lettura)

inline const Point& nodo(int i) const {return Mnodi.at(i);}

//referenza al triangolo i-esimo (solo lettura)

inline Triangle& triangolo(int i) {return Mtriang.at(i);}

//vettore di nodi

inline Nodes nodi() {return Mnodi;} .

Il metodo

vector<list<int> > patch;

vector<list<int> > intornopunto()

{ patch.resize(Mnodi.size());

9

Page 11: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

for(int j=0;j<Mtriang.size();++j)

{

int idt=this->Mtriang.at(j).getID();

for(int k=0;k<=2;++k)

{

int i=this->Mtriang.at(j).getvertice(k).ID;

patch.at(i).push_back(idt);

}

}

return patch;

}

serve per costruire il patch di ogni nodo della mesh, contenuto poi nella listasituata nel vettore alla posizione corrispondente all’ID del nodo.Per questa classe si ha solo l’overloading dell’operatore <<

friend ostream& operator<<(ostream& s, const Mesh& M)

{int mn=M.Mnodi.size();

int mt=M.Mtriang.size();

s<<"vettore di "<<mn<<" punti:"<<endl;

for(int h=0;h<mn;++h){cout<<M.Mnodi.at(h)<<endl;}

s<<"vettore di "<<mt<<" triangoli:"<<endl;

for(int k=0;k<mt;++k){cout<<M.Mtriang.at(k)<<endl;}

return s;} .

3 Funzioni e metodi

In questo paragrafo introduciamo in modo piu accurato la funzione che cal-cola la proiezione di un punto sul piano individuato da un triangolo e ilmetodo della classe Triangle che verifica l’appartenenza di un punto ad untriangolo. In particolar modo descriviamo dettagliatamente le idee che sonoalla base di queste due funzioni, affrontate in entrambi i casi sfruttando lageometria analitica.

3.1 Proiezione di un punto su un piano

Noti un punto P di coordinate (xp, yp, zp) ed un triangolo con verticiP1 = (x1, y1, z1) P2 = (x2, y2, z2) P3 = (x3, y3, z3), calcoliamo la proiezionedi P , Pp, sul piano individuato dal triangolo: Ax + By + Cz + D = 0.

10

Page 12: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Figura 1: Proiezione del punto P sul piano individuato dal triangolo divertici P1 P2 P3.

Dalla geometria analitica sappiamo che il piano passante per tre punti edato da:

det

x− x1 y − y1 z − z1x2 − x1 y2 − y1 z2 − z1x3 − x1 y3 − y1 z3 − z1

= 0

risolvendo si ottiene che:

A = (y2 − y1)(z3 − z1)− (z2 − z1)(y3 − y1)B = (z2 − z1)(x3 − x1)− (x2 − x1)(z3 − z1)C = (x2 − x1)(y3 − y1)− (y2 − y1)(x3 − x1)D = −x1A− y1B − z1C.

Calcolando i vettoriP2P1 = (x2−x1, y2−y1, z2−z1) e P3P1 = (x3−x1, y3−y1, z3−z1) e facendoneil prodotto vettoriale otteniamo il vettore normale al piano n = (A,B, C).Dalla figura 1, il vettore u perpendicolare al piano e passante per P saraun multiplo di n (u = an) ed il suo modulo sara dato esattamente dalladistanza tra P e il piano che, sempre per la geometria analitica, vale:

d =∣∣∣∣Axp + Byp + Czp + D√

A2 + B2 + C2

∣∣∣∣.

11

Page 13: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Quindi a|n| = d ⇒ a = Axp+Byp+Czp+DA2+B2+C2 . Percio la nostra proiezione

sara data da:Pp = (xp − aA, yp − aB, zp − aC)

dato che Pp = P−u. Si puo osservare che, calcolando la proiezione in questomodo, non e necessario conoscere il verso in cui e diretta la normale; infattila costante moltiplicativa a puo assumere segno qualsiasi, adattando cosıautomaticamente il calcolo delle coordinate della proiezione al verso dellanormale stessa.Alternativamente la proiezione puo essere calcolata con la seguente formula:

PP = P − ((P − P1) · nn)nn

dove nn e il versore normale al triangolo.La funzione

Point proiezione(const Point& P1, const Point& P2, const Point& P3,

const Point& P) {};

implementa esattamente entrambe queste strategie.

Point proiezione(const Point& P1, const Point& P2, const Point& P3,

const Point& P)

{//coefficienti del piano su cui giace il triangolo

double a,b,c,d;

a=(P2.y-P1.y)*(P3.z-P1.z)-(P2.z-P1.z)*(P3.y-P1.y); cout<<"a: "<<a<<endl;

b=(P2.z-P1.z)*(P3.x-P1.x)-(P2.x-P1.x)*(P3.z-P1.z); cout<<"b: "<<b<<endl;

c=(P2.x-P1.x)*(P3.y-P1.y)-(P2.y-P1.y)*(P3.x-P1.x); cout<<"c: "<<c<<endl;

d=-P1.x*a-P1.y*b-P1.z*c; cout<<"d: "<<d<<endl;

//versore normale

Point N;

N.x=a/sqrt(a*a+b*b+c*c);

N.y=b/sqrt(a*a+b*b+c*c);

N.z=c/sqrt(a*a+b*b+c*c); cout<<"normale: "<<N<<endl;

//introduco la costante di moltiplicazione

double cm;

//cm=(a*P.x+b*P.y+c*P.z+d)/(a*a+b*b+c*c); cout<<"cm: "<<cm<<endl;

cm=(P.x-P1.x)*N.x+(P.y-P1.y)*N.y+(P.z-P1.z)*N.z;

//calcolo le tre coordinate del punto di proiezione

double x1,y1,z1;

12

Page 14: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

//x1=P.x-cm*a;

//y1=P.y-cm*b;

//z1=P.z-cm*c;

x1=P.x-cm*N.x;

y1=P.y-cm*N.y;

z1=P.z-cm*N.z;

//controllo che la proiezione appartenga al piano

cout<<"la proiezione appartiene al piano?"<<endl;

double temp=a*x1+b*y1+c*z1+d;

cout<<temp<<endl;

Point Pro(x1,y1,z1);

return Pro;

}

Per verificare la correttezza di queste strategie sono stati considerati dueesempi semplici, calcolabili anche a mano.Nel primo caso si calcolano le proiezioni dei punti P = (2, 5, 3), P ′ = (3, 6, 5),P ′′ = (3, 6, 1) sul piano individuato dal triangolo di vertici P1 = (3, 6, 9),P2 = (4, 2, 3) e P3 = (5, 7, 8). I risultati ottenuti, PP = (3.75497, 3.06954, 4.57947),P ′

P = (4.19205, 4.6887, 6.07285), P ′′P = (5.38411, 3.37748, 3.1458), coinci-

dono esattamente coi calcoli fatti a mano e sono visualizzati in figura 2.

Figura 2: Primo esempio semplice: visualizzazione dei punti, delle loroproiezioni e del triangolo.

13

Page 15: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Nel secondo caso P = (5, 3, 2), P1 = (1, 4, 8), P2 = (2, 3, 6) e P3 = (9, 1, 2).Anche per questo esempio il risultato, PP = (5, 1.4, 2.8), coincide perfetta-mente con il valore calcolato a mano ed e riportato in figura 3.

Figura 3: Secondo esempio semplice: visualizzazione del punto, della suaproiezione e del triangolo.

3.2 Appartenenza di un punto ad un triangolo

Dati un punto P = (xp, yp, zp) ed un triangolo di verticiP1 = (x1, y1, z1) P2 = (x2, y2, z2) P3 = (x3, y3, z3) che giacciono sullostesso piano, vogliamo verificare se P appartiene al triangolo oppure no.Come prima idea ci riconduciamo da un problema 3D ad uno 2D, riscrivendole coordinate dei punti rispetto ad un sistema di riferimento con origine inP1, asse x diretto come il vettore P2P1 e asse y perpendicolare; i versori degliassi del nuovo sistema di riferimento sono quindi:

ex = P2P1

|P2P1|

ez = nn

ey = nn × ex = (nnyexz − nnzexy)i + (nnzexx − nnxexz)j + (nnxexy − nnyexx)k.

14

Page 16: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Figura 4: Dati un punto P ed un triangolo di vertici P1 P2 P3 che giaccionosullo stesso piano vogliamo verificare l’appartenenza del punto al triangolo.

Le nuove coordinate di P1 e P2 sono facili da determinare:

P1 = (x1, y1) = (0, 0)l = |P2P1| =

√(x2 − x1)2 + (y2 − y1)2 + (z2 − z1)2

P2 = (x2, y2) = (l, 0).

mentre le nuove coordinate di P3 e P sono date da:

P3 = (x3, y3) con x3 = P3 · ex

y3 = P3 · ey

P = (xp, yp) con xp = P · ex

yp = P · ey

Riscrivendo P come combinazione lineare dei vertici del triangolo otteniamo

xp = λ1x1 + λ2x2 + λ3x3

yp = λ1y1 + λ2y2 + λ3y3

λ1 + λ2 + λ3 = 1

15

Page 17: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

dato che x1 = y1 = y2 = 0 ⇒λ3 = yp

y3

λ2 = xp−λ3x3

x2

λ1 = 1− λ2 − λ3

.

Se0 6 λ1 6 10 6 λ2 6 10 6 λ3 6 1

⇒P e combinazione convessa dei vertici del triangoloe appartiene al triangolo stesso.

Esiste un’altra possibile strategia per verificare l’appartenenza di un pun-to ad un triangolo. Una volta ricondotto il problema 3D ad un problema 2De riscritte le coordinate dei punti, e possibile implementare l’idea seguente.Si scrive la retta passante per P1 e P2, cioe per un lato del triangolo:

y2 − y1

x2 − x1x− y − y1 −

y2 − y1

x2 − x1x1 = 0.

Si vanno a sostituire nell’equazione della retta le coordinate del terzo vertice,P3, e del punto P e si osserva se si ottengono quantita di segno uguale, ilche implica che P3 e P giacciono dalla stessa parte rispetto alla retta, oopposto. In seguito si eseguono gli stessi calcoli per gli altri due lati. Se ilterzo vertice e P giacciono sempre dalla stessa parte rispetto a tutti e tre ilati, allora il punto P appartiene al triangolo.

Infine, una terza strategia plausibile analizza direttamente il problema3D. L’idea e all’incirca la stessa della strategia precedente, ma, al posto diprendere in considerazione le rette passanti per i lati del triangolo, si cal-colano i piani individuati dai vettori direzionati come i lati e come la normaleal triangolo.Cerchiamo di spiegare piu dettagliatamente questo metodo.Nello spazio 3D un piano puo essere individuato da due vettori ortogonaliche giacciono su di esso, oppure da un terzo vettore ortogonale ai primi due,le cui coordinate danno i coefficienti del piano stesso. Se infatti consideriamoil piano generico Ax + By + Cz + D = 0, il vettore (A, B, C) e ortogonaleal piano. Percio, conoscendo il vettore ortogonale al piano ed un punto cheappartiene ad esso e facile calcolare i coefficienti dell’equazione del pianostesso.Nel nostro caso, conoscendo i vertici del triangolo possiamo calcolare il ver-sore normale al triangolo nn come spiegato nel paragrafo riguardante laproiezione di un punto. Inoltre possiamo facilmente ottenere i vettori di-retti come i lati P2P1, P3P1 e P3P2. A questo punto possiamo calcolare icoefficienti del piano definito, ad esempio, dai vettori P2P1 e nn. Il vettore

16

Page 18: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

v ortogonale al piano sara dato da:

v = nn × P2P1 = (nny(z2 − z1)− nnz(y2 − y1))i++(nnz(x2 − x1)− nnx(z2 − z1))j + (nnx(y2 − y1)− nny(x2 − x1))k.

I primi coefficienti del piano saranno quindi: A = vx, B = vy, C = vz. Il fat-to che P1 appartenga al piano che si desidera ottenere permette di calcolareanche l’ultimo coefficiente: D = −x1A−y1B−z1C. A questo punto, avendoa disposizione l’equazione del piano, vi sostituiamo le coordinate del terzovertice del triangolo, P3, e del punto P e vediamo se otteniamo quantita diugual segno.Ripetiamo lo stesso ragionamento per i piani individuati da P3P1 e nn

A = nny(z3 − z1)− nnz(y3 − y1)B = nnz(x3 − x1)− nnx(z3 − z1)C = nnx(y3 − y1)− nny(x3 − x1)D = −x1A− y1B − z1C

e da P3P2 e nn

A = nny(z3 − z2)− nnz(y3 − y2)B = nnz(x3 − x2)− nnx(z3 − z2)C = nnx(y3 − y2)− nny(x3 − x2)D = −x2A− y2B − z2C.

Come nella seconda strategia, se in tutti e tre i casi le quantita ottenutehanno segno uguale il punto P appartiene al triangolo, altrimenti e esternoad esso.

Tutte queste strategie sono state implementate dal metodo della classeTriangle

bool appartTriangle(const Point & P) {}; .

Per verificare il loro corretto funzionamento sono stati usati gli stessi esempisemplici considerati nel paragrafo precedente. I risultati ottenuti sono ri-portati nelle figure 2 e 3 e sono facilmente verificabili a mano. Tutte e trei metodi sono teoricamente equivalenti ed in questi casi molto semplici concoordinate intere restituiscono gli stessi risultati. Quando, pero, vengonoapplicate a casi piu complessi, come quelli descritti nel paragrafo 5, le primedue strategie, che si riconducono ad un problema 2D, non sono robuste e

17

Page 19: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

restituiscono risultati errati (vedere figura 5), mentre la terza, che si basasul problema 3D, funziona correttamente (vedere figura 6).

Figura 5: Alcuni nodi netgen con le loro proiezioni ed i triangoli stl diappartenenza per il caso test del cilindro. Come si puo osservare alcuneproiezioni in realta non appartengono al triangolo a cui, secondo il codiceimplementato, dovrebbero appartenere. Si puo quindi affermare che, percasi abbastanza complessi, il codice con le prime due strategie non e robustoe restituisce risultati scorretti.

Riportiamo il codice piu robusto:

//metodo che sfrutta i piani passanti per i lati in 3D

bool appartTriangle(const Point & P)

{

//introduco delle variabili ausiliarie per facilita di scrittura

double x1=vertici.at(0).x; //cout<<"x1: "<<x1<<endl;

double y1=vertici.at(0).y; //cout<<"y1: "<<y1<<endl;

double z1=vertici.at(0).z; //cout<<"z1: "<<z1<<endl;

double x2=vertici.at(1).x; //cout<<"x2: "<<x2<<endl;

double y2=vertici.at(1).y; //cout<<"y2: "<<y2<<endl;

double z2=vertici.at(1).z; //cout<<"z2: "<<z2<<endl;

double x3=vertici.at(2).x; //cout<<"x3: "<<x3<<endl;

double y3=vertici.at(2).y; //cout<<"y3: "<<y3<<endl;

double z3=vertici.at(2).z; //cout<<"z3: "<<z3<<endl;

if((P.x==x1 && P.y==y1 && P.z==z1) || (P.x==x2 && P.y==y2 && P.z==z2)

18

Page 20: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Figura 6: Alcuni nodi netgen con le loro proiezioni ed i triangoli stl diappartenenza ottenuti con la terza strategia per il caso test del cilindro(prime 4 immagini) e per il caso reale dell’aorta (ultime 4 immagini). Si puonotare che tutte le proiezioni appartengono ai triangoli e quindi il codiceimplementato fornisce risultati corretti.

|| (P.x==x3 && P.y==y3 && P.z==z3))

{return true;} //il punto e uguale ad un vertice del triangolo

else

{//versore normale

19

Page 21: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Point N=this->calcolanormale(); cout<<N<<endl;

//coefficienti dei piani passanti per i lati (ax+by+cz+d=0)

//piano per P1 e P2

double a,b,c,d;

a=N.y*(z2-z1)-N.z*(y2-y1);

b=N.z*(x2-x1)-N.x*(z2-z1);

c=N.x*(y2-y1)-N.y*(x2-x1);

d=-a*x1-b*y1-c*z1;

//piano per P1 e P3

double a1,b1,c1,d1;

a1=N.y*(z3-z1)-N.z*(y3-y1);

b1=N.z*(x3-x1)-N.x*(z3-z1);

c1=N.x*(y3-y1)-N.y*(x3-x1);

d1=-a1*x1-b1*y1-c1*z1;

//piano per P2 e P3

double a2,b2,c2,d2;

a2=N.y*(z3-z2)-N.z*(y3-y2);

b2=N.z*(x3-x2)-N.x*(z3-z2);

c2=N.x*(y3-y2)-N.y*(x3-x2);

d2=-a2*x2-b2*y2-c2*z2;

//introduciamo nelle equazioni dei piani le coordinate del terzo vertice

//e del punto P ed andiamo a vedere se otteniamo valori con lo stesso

//segno per ogni piano.

double r12p, r12p3, r23p, r23p1, r13p, r13p2;

r12p=a*P.x+b*P.y+c*P.z+d;

r12p3=a*x3+b*y3+c*z3+d;

r23p=a2*P.x+b2*P.y+c2*P.z+d2;

r23p1=a2*x1+b2*y1+c2*z1+d2;

r13p=a1*P.x+b1*P.y+c1*P.z+d1;

r13p2=a1*x2+b1*y2+c1*z2+d1;

if(((r12p>=0 && r12p3>=0) || (r12p<=0 && r12p3<=0)) && ((r23p>=0 && r23p1>=0)

|| (r23p<=0 && r23p1<=0)) && ((r13p>=0 && r13p2>=0) || (r13p<=0 && r13p2<=0)))

return true;

else

return false;

}

}

20

Page 22: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Il metodo

bool proiezandappart(const Point & P) {};

calcola direttamente la proiezione di un punto 3D sul piano individuatoda un triangolo e l’appartenenza della proiezione stessa a questo triangolo,inglobando i codici descritti nel paragrafo precedente ed in questo.Il metodo

bool proiezandappart(const Point & P,double & dist) {};

restituisce anche la distanza fra punto 3D di partenza e sua proiezione.Infine il metodo

bool proiezandappart(const Point & P,double & dist,const Point & N)

{};

esegue gli stessi calcoli, pero proiettando il punto P lungo la normale passatacome input.

4 Ricerca del triangolo stl di appartenenza della

proiezione di ogni nodo della mesh netgen

Sfruttando le funzioni descritte nel paragrafo precedente e possibile raggiun-gere l’obiettivo prefissato per questo lavoro: per ogni nodo della mesh netgensi vuole calcolare la proiezione sulla superficie triangolata stl e trovare untriangolo stl a cui questa appartenga. Dato che puo succedere di trovare piutriangoli stl a cui appartiene la proiezione di un nodo netgen, si prenderain considerazione il triangolo di appartenenza a minima distanza dal nodonetgen stesso.

Per effettuare questa ricerca sono stati implementati tre metodi diversi,che verranno confrontati nel paragrafo successivo applicandoli ad un casotest e ad un caso reale.

4.1 Metodo brute force

Questo metodo viene definito a forza bruta perche usa due cicli for innestati,uno sui nodi netgen ed uno sui triangoli stl, e viene implementato per primoessendo il piu immediato in quanto usa semplicemente il penultimo meto-do introdotto nel paragrafo precedente, senza ulteriori calcoli. Il problema

21

Page 23: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

collaterale e che la complessita computazionale di questo metodo cresceraquadraticamente all’aumentare dei nodi e dei triangoli delle mesh.

Per ogni nodo netgen cicliamo, infatti, su tutti i triangoli stl, andandoa calcolare la proiezione del nodo netgen sul piano individuato da ciascuntriangolo e a verificare se essa appartiene al triangolo considerato di volta involta. Fra tutti i triangoli stl a cui appartiene la proiezione del nodo netgenprendiamo quello a minima distanza e lo scriviamo in un file.txt e in unvettore. Otteniamo quindi il triangolo stl di appartenenza per ogni nodo delmesh netgen.Il codice implementato nel main e il seguente:

vector<int> idtriangapp;

idtriangapp.reserve(npMn);

int idt(0);

double dist;

ofstream out("appBrutale.txt");

for(int pn=0;pn<npMn;++pn) //per ogni nodo della mesh netgen

{cout<<"\n\npunto "<<pn<<" della mesh netgen"<<endl;

idt=0;

dis=0;

dist=1000;

for(int ts=0;ts<ntMs2;++ts) // per ogni triangolo della mesh stl

{bool app=Ms2.triangolo(ts).proiezandappart(Mn.nodo(pn),dis);

cout<<"il punto appartiene al triangolo? "<<app<<endl;

cout<<"dis: "<<dis<<endl;

if(app==1)

{

if(dis<dist)

{

idt=Ms2.triangolo(ts).getID(); dist=dis;

}

cout<<"id:"<<idt<<endl<<"dist: "<<dist<<endl;

}

}

out<<"la proiezione a minima distanza del punto "<<Mn.nodo(pn)<<

" della mesh netgen appartiene al "<<Ms2.triangolo(idt)<<" della mesh stl"<<endl;

idtriangapp.push_back(idt);

}

22

Page 24: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

4.2 Metodo con ricerca del nodo stl piu vicino al nodo netgen

Questo metodo e meno immediato del primo perche prevede il calcolo delpatch di ogni nodo stl, cioe la creazione di una lista contenente gli ID ditutti i triangoli di cui il nodo stl e un vertice. Questi saranno i triangoli sucui cicleremo per trovare il triangolo stl di appartenenza della proiezione diogni nodo netgen, velocizzando notevolmente la ricerca.

Per ogni nodo netgen cicliamo su tutti i nodi stl per cercare quello a dis-tanza minima. Questo doppio ciclo e molto piu veloce di quello consideratonel metodo a forza bruta perche serve per svolgere una semplice operazionedi calcolo della distanza e non per la ricerca del triangolo di appartenenza.Questa viene eseguita solo sui triangoli appartenenti al patch del nodo stlpiu vicino ad ogni nodo netgen. Anche in questo caso consideriamo solo iltriangolo stl di appartenenza a distanza minima.Riportiamo di seguito il codice scritto nel main:

vector<list<int> > intorno;

intorno=Ms2.intornopunto();

vector<int> idtriangapp1;

idtriangapp1.reserve(npMn);

ofstream patch("apppatch.txt");

double dismin;

vector<double> distemp1;

distemp1.reserve(npMs2);

int idt1(0);

double dis1;

for(int pn=0; pn<npMn;++pn)

{cout<<"\n\npunto "<<pn<<" della mesh netgen"<<endl;

distemp1.clear();

idt1=0;

dismin=1000;

dis=0;

dis1=1000;

for(int ps=0; ps<npMs2; ++ps)

{

dis=distanza(Mn.nodo(pn),Ms2.nodo(ps)); cout<<"dis: "<<dis<<endl;

distemp1.push_back(dis);

}

cout<<"tot distanze: "<<distemp1.size()<<endl;

23

Page 25: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

for(int ps=0; ps<distemp1.size(); ++ps)

{

dismin=min(dismin,distemp1.at(ps));

}

cout<<"distanza min: "<<dismin<<endl;

int idtemp(0),idtemp1(0);

for(int i=0; i<distemp1.size(); ++i)

{

if(distemp1.at(i)!=dismin)

{++idtemp1; cout<<"idtemp1: "<<idtemp1<<endl;}

else {idtemp=idtemp1; cout<<"idtemp: "<<idtemp<<endl;}

}

Point Pmindis=Ms2.nodo(idtemp);

cout<<"punto a minima distanza: "<<Pmindis<<endl;

list<int>::iterator p1=intorno.at(idtemp).begin();

dis=0;

for(int j=0; j<intorno.at(idtemp).size();++j)

{

bool appart=Ms2.triangolo(*p1).proiezandappart(Mn.nodo(pn),dis);

cout<<"il punto appartiene al triangolo? "<<appart<<endl;

cout<<"dis: "<<dis<<endl;

if(appart==1)

{

if(dis<dis1)

{

idt1=Ms2.triangolo(*p1).getID();

dis1=dis;

}

cout<<"id:"<<idt1<<endl<<"dis1: "<<dis1<<endl;

}

++p1;

}

patch<<"la proiezione del punto "<<Mn.nodo(pn)<<" della mesh netgen

appartiene al "<<Ms2.triangolo(idt1)<<" della mesh stl"<<endl;

patch<<"punto a minima distanza: "<<Pmindis<<endl;

idtriangapp1.push_back(idt1);

}

24

Page 26: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

4.3 Metodo con algoritmo di ricerca del nearest neighbor

Questo metodo e ancora piu avanzato e veloce del secondo perche, al postodi ciclare su tutti i nodi stl per cercare quello piu vicino ad ogni nodo netgen,usa un algoritmo di ricerca del nearest neighbor appartenente ad una libreriaesterna specializzata nell’implementazione di questo codice: la libreria ANN.

Questa libreria supporta la ricerca esatta e approssimata di k nearestneighbor, con k definito dall’utente e nel nostro caso = 1, in spazi di qual-siasi dimensione. Un set di punti dati, nel nostro caso il vettore di nodidella superficie stl, viene preprocessato per costruire una struttura dati, piuprecisamente un kd-tree, in modo che la ricerca del nearest neighbor per ogninodo netgen sia piu veloce ed efficiente.

I kd-tree sono data structure basate su suddivisioni ortogonali ricorsivedello spazio in iperrettangoli disgiunti chiamati cells o boxes. Ogni nododell’albero e associato ad una di queste regioni ed al sottoinsieme di pun-ti che giacciono in essa. La radice dell’albero e legata ad un box limitatoche contiene tutti i punti dati, infatti e costituita da un puntatore al set dipunti dati. Inoltre fornisce due ulteriori informazioni: la splitting rule eduna costante piccola chiamata bucket size. Queste informazioni sono neces-sarie per un nodo arbitrario dell’albero. Difatti, finche il numero di puntiassociati a questo nodo e maggiore del bucket size il box viene suddivisoin due celle piu piccole da un iperpiano con asse ortogonale che interseca ilbox stesso; la selezione dell’iperpiano dipende dalla regola di suddivisioneconsiderata. I due box ottenuti vengono associati a due nodi figli del no-do in esame; i punti appartenenti al box originario sono suddivisi nelle duecelle derivate a seconda del lato dell’iperpiano in cui si trovano, quelli chegiacciono sull’iperpiano possono essere assegnati ad entrambi i box oppurevengono ridistribuiti secondo la splitting rule. Quando il numero di puntiassociati ad un nodo e minore del bucket size, questo nodo viene considera-to una foglia e non viene piu suddiviso. La struttura gerarchica dell’alberoviene sfruttata nell’algoritmo di ricerca chiamato standard search, che sibasa su un calcolo incrementale della distanza fra un nodo netgen e le celleassociate ai nodi dell’albero. Questo algoritmo opera ricorsivamente: quan-do si incontra un nodo del kd-tree, l’algoritmo prima visita il figlio che epiu vicino al punto netgen, in seguito, se l’altro figlio giace ad una distanzacompresa fra 1 e 1 + ε volte la distanza dal piu vicino punto trovato fino aquel momento, allora anche questo nodo viene visitato ricorsivamente.

Una volta trovato il nearest neighbor di ogni nodo netgen si procede

25

Page 27: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

come nel secondo metodo: si cerca il triangolo stl di appartenenza a minimadistanza fra i triangoli appartenenti al patch del nearest neighbor calcolato.Il codice implementato nel main e il seguente:

int k = 1; // number of nearest neighbors

int dim = 3; // dimension

double eps = 0; // error bound

int m_pts = 1000000; // maximum number of data points

int n_pts; // actual number of data points

ANNpointArray data_pts; // data points

ANNpoint query_pt; // query point

ANNidxArray nn_idx; // near neighbor indices

ANNdistArray dists; // near neighbor distances

ANNkd_tree *the_tree; // search structure

query_pt = annAllocPt(dim); // allocate query point

data_pts = annAllocPts(m_pts, dim); // allocate data points

nn_idx = new ANNidx[k]; // allocate near neigh indices

dists = new ANNdist[k]; // allocate near neighbor dists

n_pts = 0; // read data points

for(int i=0; i<npMs2; ++i)

{

data_pts[i][0]=Ms2.nodo(i).x;

data_pts[i][1]=Ms2.nodo(i).y;

data_pts[i][2]=Ms2.nodo(i).z;

n_pts++;

}

cout<<"numero data points: "<<n_pts<<endl;

cout<<"Data Points:\n";

for(int j=0;j<n_pts;++j)

{

printPt(cout, data_pts[j]);

}

the_tree = new ANNkd_tree( // build search structure

data_pts, // the data points

n_pts, // number of points

dim); // dimension of space

for(int i=0; i<npMn; ++i) // read query points

{

26

Page 28: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

query_pt[0]=Mn.nodo(i).x;

query_pt[1]=Mn.nodo(i).y;

query_pt[2]=Mn.nodo(i).z;

cout << "Query point: "; // echo query point

printPt(cout, query_pt);

the_tree->annkSearch( // search

query_pt, // query point

k, // number of near neighbors

nn_idx, // nearest neighbors (returned)

dists, // distance (returned)

eps); // error bound

std::ofstream ofile;

ofile.open("nearestneig.txt",std::ios::app);

for (int i = 0; i < k; i++) { // print summary

printPt( ofile, data_pts[ nn_idx[i] ] );

};

ofile.close();

}

//leggo il file nearestneig.txt e creo un vettore di punti

//mettendo gli ID corretti

Nodes vicini=creanearestneighbor("nearestneig.txt", Ms2.nodi());

//metodo che usa i nearest neighbor per trovare il triangolo della mesh stl

//di appartenenza di ogni nodo della mesh netgen a minima distanza

vector<int> idtriangapp2;

idtriangapp2.reserve(npMn);

int idt2(0);

double dis2;

ofstream patch1("apppatchnn.txt");

for(int k=0; k<vicini.size(); ++k)

{idt2=-1;

dis2=1000;

dis=0;

int id=vicini.at(k).ID;

list<int>::iterator p2=intorno.at(id).begin();

for(int j=0; j<intorno.at(id).size();++j)

{

bool appart=Ms2.triangolo(*p2).proiezandappart(Mn.nodo(k),dis);

27

Page 29: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

cout<<"il punto appartiene al triangolo? "<<appart<<endl;

cout<<"dis: "<<dis<<endl;

if(appart==1)

{

if(dis<dis2)

{

idt2=Ms2.triangolo(*p2).getID();

dis2=dis;

}

cout<<"id:"<<idt2<<endl<<"dis2: "<<dis2<<endl;

}

++p2;

}

if(idt2!=-1)

{

patch1<<"la proiezione del punto "<<Mn.nodo(k)<<" della mesh netgen

appartiene al "<<Ms2.triangolo(idt2)<<" della mesh stl"<<endl;

}

else

{ patch1<<"la proiezione del punto "<<Mn.nodo(k)<<" della mesh netgen

non appartiene a nessun triangolo stl del patch del nearest neighbor"<<endl;

}

patch1<<"punto a minima distanza: "<<vicini.at(k)<<endl;

idtriangapp2.push_back(idt2);

}

5 Applicazioni e problemi riscontrati

I tre metodi descritti nel paragrafo precedente sono stati applicati a due casidifferenti.

Il primo puo essere considerato un caso test per verificare il corretto fun-zionamento del codice implementato, in quanto e costituito da una geome-tria molto semplice: un cilindro. Su questo cilindro sono state costruite duemesh: una piu lasca (formata da 146 nodi) che sara la mesh netgen presa inconsiderazione (vedere figura 7) ed una piu fine (costituita da 846 nodi) chesara, invece, la superficie triangolata stl (vedere figura 8). Facendo girare itre codici su queste due mesh note si ottengono esattamente gli stessi risul-

28

Page 30: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Figura 7: Caso test del cilindro: mesh netgen.

Figura 8: Caso test del cilindro: superficie stl.

tati in tempi confrontabili e rapidi. Se si osservano bene i nearest neighbordei nodi netgen si vede che hanno coordinate molto vicine ai nodi netgenstessi e si puo notare che il triangolo stl di appartenenza correttamente faparte del patch del nearest neighbor (vedere figura 9). Inoltre, considerandocasualmente alcuni nodi netgen e visualizzandoli insieme alla loro proiezionee al triangolo stl di appartenenza calcolato (vedere figura 6), si puo osservareche la proiezione correttamente appartiene al triangolo.Questo esempio ha quindi permesso di ottenere risultati sensati in accordocon l’implementazione del codice e di osservare che, per mesh molto piccole,il costo computazionale ed il tempo di calcolo dei tre metodi e all’incircauguale.

29

Page 31: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

Figura 9: Un nodo netgen con la sua proiezione, il suo nearest neighbor edil patch di quest’ultimo.

Il secondo caso, invece, e un caso reale: un arco aortico ricostruito apartire da immagini TAC. Anche in questo caso si dispone di una superficietriangolata stl, costituita pero da tantissimi nodi (82674), e di una meshnetgen formata da 3107 nodi (vedere figura 10). Applicando i tre metodi si

(a) mesh netgen (b) superficie stl

Figura 10: Caso reale dell’aorta.

30

Page 32: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

ottengono gli stessi risultati per il secondo ed il terzo, ma non per il primo,perche in questo caso reale l’irregolarita della superficie comporta il fattoche alcuni nodi netgen abbiano una proiezione che non appartiene ad alcuntriangolo del patch del nearest neighbor. Quindi, con il secondo e il terzometodo non si riesce ad ottenere il triangolo stl di appartenenza per un nu-mero elevato di nodi netgen; mentre con il metodo a forza bruta cio succedesolo per pochi nodi, dato che in questo metodo si considera un ciclo su tutti itriangoli stl. Percio e necessario apportare dei cambiamenti che permettanodi trovare un triangolo stl di appartenenza anche per questi nodi netgen. Laprima idea e stata quella di calcolare una nuova normale, media delle nor-mali ai triangoli appartenenti al patch dei nearest neighbor di questi nodi,e di proiettare il nodo netgen lungo questa normale per vedere se la nuovaproiezione appartenga a uno dei triangoli del patch oppure no. Purtroppoquesto cambiamento apporta pochissimi miglioramenti e permette di trovareil triangolo stl di appartenenza solo per un numero molto ridotto di nodinetgen. Si e quindi deciso di implementare due algoritmi che abbandonanol’idea della ricerca del triangolo di appartenenza e cercano i tre nodi stl piuvicini ad ogni nodo netgen in maniera alternativa. Questi due algoritmi sonodescritti nel paragrafo successivo.In questo caso reale si puo osservare che il costo computazionale, il tempodi calcolo e l’efficienza variano notevolmente nei tre metodi per mesh connumero di nodi molto elevato. Il primo metodo, infatti, impiega 30 ore peril calcolo, il secondo 3 ore e 20 minuti, mentre il terzo pochi minuti.Per il vaso aortico, inoltre, abbiamo a disposizione anche gli spostamenti deinodi stl in dieci tempi differenti. Percio e stato possibile implementare ilcodice che calcola, una volta noti i tre punti stl piu vicini ad ogni nodo net-gen, l’interpolazione degli spostamenti di questi tre nodi e fornisce lo sposta-mento di ogni nodo netgen per tutti i tempi, permettendo di ricostruire lamesh netgen necessaria per i successivi calcoli fluidodinamici.

6 Algoritmi alternativi

Per risolvere il problema riscontrato nell’applicazione del codice implemen-tato al caso reale dell’aorta, sono stati scritti due algoritmi alternativi checalcolano i tre nodi stl piu vicini ad ogni nodo netgen, non con la ricerca deltriangolo stl di appartenenza della proiezione, ma in modo differente.

Il primo algoritmo sfrutta la libreria ANN per la ricerca diretta dei tre

31

Page 33: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

nearest neighbor. Come e gia stato detto, infatti, questa libreria permette dicalcolare in modo esatto ed approssimato i primi k nearest neighbor. Finoraquesta costante era stata posta = 1, per implementare il nuovo codice bastasettare k = 3 ed i tre punti stl piu vicini ad ogni nodo netgen vengonocalcolati automaticamente.Il codice implementato per questo algoritmo e il seguente:

int k = 3; // number of nearest neighbors

int dim = 3; // dimension

double eps = 0; // error bound

int m_pts = 1000000; // maximum number of data points

int n_pts; // actual number of data points

ANNpointArray data_pts; // data points

ANNpoint query_pt; // query point

ANNidxArray nn_idx; // near neighbor indices

ANNdistArray dists; // near neighbor distances

ANNkd_tree *the_tree; // search structure

query_pt = annAllocPt(dim); // allocate query point

data_pts = annAllocPts(m_pts, dim); // allocate data points

nn_idx = new ANNidx[k]; // allocate near neigh indices

dists = new ANNdist[k]; // allocate near neighbor dists

n_pts = 0; // read data points

for(int i=0; i<noditriang.size(); ++i)

{

data_pts[i][0]=noditriang.at(i).x;

data_pts[i][1]=noditriang.at(i).y;

data_pts[i][2]=noditriang.at(i).z;

n_pts++;

}

cout<<"numero data points: "<<n_pts<<endl;

cout<<"Data Points:\n";

for(int j=0;j<n_pts;++j)

{

printPt(cout, data_pts[j]);

}

the_tree = new ANNkd_tree( // build search structure

data_pts, // the data points

n_pts, // number of points

32

Page 34: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

dim); // dimension of space

for(int i=0; i<npMn; ++i) // read query points

{

query_pt[0]=Mn.nodo(i).x;

query_pt[1]=Mn.nodo(i).y;

query_pt[2]=Mn.nodo(i).z;

cout << "Query point: "; // echo query point

printPt(cout, query_pt);

the_tree->annkSearch( // search

query_pt, // query point

k, // number of near neighbors

nn_idx, // nearest neighbors (returned)

dists, // distance (returned)

eps); // error bound

std::ofstream ofile;

ofile.open("nearestneig3.txt",std::ios::app);

for (int i = 0; i < k; i++) { // print summary

printPt( ofile, data_pts[ nn_idx[i] ] );

};

ofile.close();

}

//leggo il file nearestneig3.txt e creo un vettore di punti

//mettendo gli ID corretti

Nodes vicini=creanearestneighbor("nearestneig3.txt", Ms2.nodi());

Il secondo algoritmo, invece, calcola il baricentro di ogni triangolo stlsfruttando il metodo apposito della classe Triangle. Successivamente effettuala ricerca del baricentro piu vicino ad ogni nodo netgen, sempre usando laricerca del nearest neighbor della libreria ANN. Infine considera come trepunti stl piu vicini ad ogni nodo netgen i vertici del triangolo col baricentropiu vicino.Riportiamo di seguito il codice che implementa questo algoritmo:

//creo il vettore dei baricentri per la ricerca di quello + vicino

//ad ogni nodo della mesh netgen

Nodes baricentritriang;

baricentritriang.reserve(ntMs2);

for(int i=0;i<ntMs2;++i)

{Point B;

33

Page 35: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

B=Ms2.triangolo(i).baricentro();

B.ID=Ms2.triangolo(i).getID();//B.ID=i;

baricentritriang.push_back(B);

}

int k = 1; // number of nearest neighbors

int dim = 3; // dimension

double eps = 0; // error bound

int m_pts = 1000000; // maximum number of data points

int n_pts; // actual number of data points

ANNpointArray data_pts; // data points

ANNpoint query_pt; // query point

ANNidxArray nn_idx; // near neighbor indices

ANNdistArray dists; // near neighbor distances

ANNkd_tree *the_tree; // search structure

query_pt = annAllocPt(dim); // allocate query point

data_pts = annAllocPts(m_pts, dim); // allocate data points

nn_idx = new ANNidx[k]; // allocate near neigh indices

dists = new ANNdist[k]; // allocate near neighbor dists

n_pts = 0; // read data points

for(int i=0; i<baricentritriang.size(); ++i)

{

data_pts[i][0]=baricentritriang.at(i).x;

data_pts[i][1]=baricentritriang.at(i).y;

data_pts[i][2]=baricentritriang.at(i).z;

n_pts++;

}

cout<<"numero data points: "<<n_pts<<endl;

cout<<"Data Points:\n";

for(int j=0;j<n_pts;++j)

{

printPt(cout, data_pts[j]);

}

the_tree = new ANNkd_tree( // build search structure

data_pts, // the data points

n_pts, // number of points

dim); // dimension of space

for(int i=0; i<npMn; ++i) // read query points

34

Page 36: PROGRAMMAZIONE AVANZATA per il CALCOLO …POLITECNICO DI MILANO Corso di Laurea Specialistica in Ingegneria Matematica Orientamento Calcolo Scientifico PROGRAMMAZIONE AVANZATA per

{

query_pt[0]=Mn.nodo(i).x;

query_pt[1]=Mn.nodo(i).y;

query_pt[2]=Mn.nodo(i).z;

cout << "Query point: "; // echo query point

printPt(cout, query_pt);

the_tree->annkSearch( // search

query_pt, // query point

k, // number of near neighbors

nn_idx, // nearest neighbors (returned)

dists, // distance (returned)

eps); // error bound

std::ofstream ofile;

ofile.open("nearestbar.txt",std::ios::app);

for (int i = 0; i < k; i++) { // print summary

printPt( ofile, data_pts[ nn_idx[i] ] );

};

ofile.close();

}

Questi due algoritmi permettono di trovare i tre nodi stl piu vicini adogni nodo netgen e quindi di calcolare il suo spostamento. Confrontando glispostamenti dei nodi netgen ottenuti a partire da questi due codici, si puoosservare che sono molto simili e per tantissimi nodi addirittura uguali. Per-cio, a questo punto, e possibile ricostruire la mesh netgen superficiale ad ogniistante temporale, estenderla con l’harmonic extension a mesh volumetricae procedere coi calcoli fluidodinamici.

Riferimenti bibliografici

[1] Daoqi Yang. “C++ AND OBJECT-ORIENTED NUMERIC COM-PUTING for Scientists and Engineers”. Springer.

[2] David M. Mount. “ANN Programming Manual”. University ofMaryland, College Park, Maryland 1998.

[3] Renato Betti. “Lezioni di Geometria”. Masson, Milano 1996.

[4] Wikipedia, the free encyclopedia: http://en.wikipedia.org

35