1 #ifndef MEDMEM_DTREE_HXX
2 #define MEDMEM_DTREE_HXX
4 #include "MEDMEM_dTreeSommet.hxx"
6 #define DTREE_FANTOME -1
8 #define DTREE_TERMINAL 1
9 #define DTREE_COURANT 2
11 #define DTREE_NON_CALCULE -1
12 #define DTREE_AUCUNE 0
13 #define DTREE_VALIDE 1
15 #define DTREE_NBR_MIN_NOEUDS 1
16 #define DTREE_NBR_MAX_DESC 8
17 // pour meilleu re lecture
18 #define _TEMPLATE_ template <class NOEUD,class NUAGENOEUD,int DIMENSION,int NBR_NOEUDS_PAR_CASE>
19 #define _DTREE_ dTree<NOEUD,NUAGENOEUD,DIMENSION,NBR_NOEUDS_PAR_CASE>
21 //////////////////////////////////////////////////////////////////
25 //////////////////////////////////////////////////////////////////
27 /*********************************************************/
29 /* Calcul Statique de Puissance */
31 /*********************************************************/
33 // Permet de Calculer 2^n de façon statique
35 template < int DIMENSION > struct DeuxPuissance
37 enum { valeur = 2 * DeuxPuissance<DIMENSION-1>::valeur } ;
40 template <> struct DeuxPuissance<0>
45 /*********************************************************/
49 /*********************************************************/
53 // - Problemes avec points sur les faces des hypercubes ?
54 // - Plantage sauvage si le point est plus loin de l'hypercube père que le diametre Linf de celui-ci.
55 // # Politique de classe :
56 // - NOEUD : voir dans MEDMEM_WrapperNodes.hxx la classe Wrapper_Noeud<..>
57 // - NUAGENOEUD : typiquement, c'est vector<NOEUD> en rédefinissant NUAGENOEUD<...>::SIZE()=vector<...>::size()
59 // - NBR_NOEUDS_PAR_CASE ne doit pas être modifié sauf peut-être dans le cas où l'utilisateur veut utiliser des d-Tree parallèles
61 template <class NOEUD,class NUAGENOEUD,int DIMENSION,int NBR_NOEUDS_PAR_CASE=DTREE_NBR_MIN_NOEUDS> class dTree
65 typedef _DTREE_ * Ptr_dTree;
67 static const int nbr_descendants=DeuxPuissance<DIMENSION>::valeur;
70 Ptr_dTree descendant[nbr_descendants];
71 vector<int> * noeud_contenu;
75 Sommet_dTree<DIMENSION> coord_max;
76 Sommet_dTree<DIMENSION> coord_min;
82 dTree(const Sommet_dTree<DIMENSION> &A,const Sommet_dTree<DIMENSION> &B,dTree *mypere);
83 dTree(const dTree &F);
85 void Get_Noeuds_Filtre(vector<int> &tmp);
86 Sommet_dTree<DIMENSION> Get_Max() const;
87 Sommet_dTree<DIMENSION> Get_Min() const;
88 int is_in_dTree(NOEUD P) const;
89 double calcule_distance(NOEUD P) const;
90 dTree & operator = (const dTree & F);
91 Sommet_dTree<DIMENSION> dTree::donne_sommet(int selecteur) const;
92 int a_des_fils() const;
93 dTree * trouve_dTree_contenant(NOEUD P) const;
94 int trouve_plus_proche_point_bourrin(NOEUD P) const;
95 int trouve_plus_proche_point(NOEUD P) const;
96 int trouve_un_point() const;
97 int tppp_rec(NOEUD P,double &delta,int &flag) const;
98 int Localise_Point(NOEUD P,double d) const;
99 void cree_filiation();
100 int Get_Nbr_Descendants_Non_Vides() const;
101 int Get_Nbr_Descendants_Vides() const;
102 int Get_Profondeur_Max() const;
106 //////////////////////////////////////////////////////////////////
110 //////////////////////////////////////////////////////////////////
112 _TEMPLATE_ void _DTREE_::init()
118 for (i=0;i<nbr_descendants;i++) descendant[i]=NULL;
122 _TEMPLATE_ _DTREE_::dTree()
128 _TEMPLATE_ _DTREE_::dTree(NUAGENOEUD *n)
136 cerr<<"DTREE : Nuage vide !"<<endl;
143 noeud_contenu=new vector<int>(nuage->size());
146 for (i=0;i<DIMENSION;i++)
148 coord_max[i]=(*nuage)[0][i];
149 coord_min[i]=(*nuage)[0][i];
151 (*noeud_contenu)[0]=0;
152 for (i=1;i<nuage->size();i++)
154 (*noeud_contenu)[i]=i;
155 for (j=0;j<DIMENSION;j++)
157 if ((*nuage)[i][j]>coord_max[j]) coord_max[j]=(*nuage)[i][j];
158 if ((*nuage)[i][j]<coord_min[j]) coord_min[j]=(*nuage)[i][j];
161 for (j=0;j<DIMENSION;j++)
163 tmp=(coord_max[j]-coord_min[j])*0.01;
171 _TEMPLATE_ _DTREE_::dTree(const Sommet_dTree<DIMENSION> &A,const Sommet_dTree<DIMENSION> &B,dTree *mypere)
182 niveau=pere->niveau+1;
186 noeud_contenu=new vector<int>;
187 noeud_contenu->reserve((pere->noeud_contenu->size())/nbr_descendants);
189 for (i=0;i<DIMENSION;i++)
191 coord_max[i]=(*nuage)[0][i];
192 coord_min[i]=(*nuage)[0][i];
195 for (i=0;i<DIMENSION;i++)
211 cerr<<"DTREE : Construction de descendance sans père !"<<endl;
215 _TEMPLATE_ _DTREE_::dTree(const _DTREE_ &F)
217 // Pas Super Top Moumoute ... Recopie de pointeurs et pas de contenus, merdique
220 for (i=0;i<nbr_descendants;i++) descendant[i]=F.descendant[i];
221 noeud_contenu=F.noeud_contenu;
225 coord_max=F.coord_max;
226 coord_min=F.coord_min;
228 _TEMPLATE_ _DTREE_::~dTree()
233 // cout<<*this<<endl;
236 delete noeud_contenu;
238 for (i=0;i<nbr_descendants;i++) if (descendant[i])
240 delete descendant[i];
243 _TEMPLATE_ void _DTREE_::Get_Noeuds_Filtre(vector<int> &tmp)
248 case DTREE_RACINE : int pourlefunlecompilolesttropcon;
250 for (i=0;i<nbr_descendants;i++) descendant[i]->Get_Noeuds_Filtre(tmp);
251 case DTREE_TERMINAL :
252 if (noeud_contenu->size()>0)
254 for (i=0;i<NBR_NOEUDS_PAR_CASE;i++) tmp.push_back((*noeud_contenu)[i]);
257 cerr<<"DTREE : dTree Non Valide dans Rempli_Noeuds_Filtre"<<endl;
261 _TEMPLATE_ Sommet_dTree<DIMENSION> _DTREE_::Get_Max() const
265 _TEMPLATE_ Sommet_dTree<DIMENSION> _DTREE_::Get_Min() const
269 _TEMPLATE_ int _DTREE_::is_in_dTree(NOEUD P) const
272 for (int i=0;i<DIMENSION;i++)
274 test=((coord_min[i]<=P[i])&&(P[i]<=coord_max[i]));
280 // calcule la distance Linf d'un point exterieur, si le point est interieur, le resultat sera erroné
281 _TEMPLATE_ double _DTREE_::calcule_distance(NOEUD P) const
283 double min=fabs(coord_max[0]-P[0]);
286 for (i=0;i<DIMENSION;i++)
288 tmp=fabs(coord_max[i]-P[i]);
289 if (min>tmp) min=tmp;
290 tmp=fabs(coord_min[i]-P[i]);
291 if (min>tmp) min=tmp;
295 _TEMPLATE_ _DTREE_ & _DTREE_::operator = (const _DTREE_ & F)
297 // Pas Super Top Moumoute ... Recopie de pointeurs et pas de contenus, merdique
300 for (i=0;i<nbr_descendans;i++) descendant[i]=F.descendant[i];
301 noeud_contenu=F.noeud_contenu;
305 coord_max=F.coord_max;
306 coord_min=F.coord_min;
308 // selecteur doit etre lu comme un nombre en base 2
309 // il specifie les coordonnes de reference du sommet dont on veut les coordonnees reelles
310 // ex : en dim 3 : coord_min=0+0*2+0*4=0
311 // coord_max=1+1*2*1*4=7
312 // donc les unites pour x, les 2aines pour y, les 4aines pour z
313 _TEMPLATE_ Sommet_dTree<DIMENSION> _DTREE_::donne_sommet(int selecteur) const
315 Sommet_dTree<DIMENSION> p;
317 int residu=selecteur;
319 for (i=0;i<DIMENSION;i++)
322 if (reste==0) p[i]=coord_min[i]; else p[i]=coord_max[i];
323 residu=(residu-reste)/2;
327 _TEMPLATE_ int _DTREE_::a_des_fils() const
329 if ((etat==DTREE_COURANT)||(etat=DTREE_RACINE)) return 1;
332 _TEMPLATE_ _DTREE_ * _DTREE_::trouve_dTree_contenant(NOEUD P) const
334 Sommet_dTree<DIMENSION> B(coord_min,coord_max);
336 if ((etat==DTREE_RACINE)&&(!is_in_dTree(P))) return NULL; // Le noeud est extérieur a l'dTree
337 else if (etat==DTREE_TERMINAL) return (dTree *) this; // Le noeud est dans *this qui est terminal
339 for (i=0;i<nbr_descendants;i++)
341 Sommet_dTree<DIMENSION> A=donne_sommet(i);
343 for (j=0;j<DIMENSION;j++)
345 if (A[j]<=B[j]) test=((A[j]<=P[j])&&(P[j]<=B[j]));
346 else test=((A[j]>=P[j])&&(P[j]>=B[j]));
350 if (test) return descendant[i]->trouve_dTree_contenant(P); // Propagation
353 // si de le dTree n'est pas TERMINAL, scanne tous les points du nuage du pere pour trouver le point le plus proche
354 // sinon scanne uniquement les points contenus dans le dTree
355 _TEMPLATE_ int _DTREE_::trouve_plus_proche_point_bourrin(NOEUD P) const
361 if (etat!=DTREE_TERMINAL)
363 min=DistanceL2(P,(*nuage)[0]);
364 for (i=1;i<nuage->size();i++)
366 tmp=DistanceL2(P,(*nuage)[i]);
377 if (noeud_contenu->size()!=0)
379 num_sol=(*noeud_contenu)[0];
380 min=DistanceL2(P,(*nuage)[num_sol]);
381 for (i=1;i<noeud_contenu->size();i++)
383 tmp=DistanceL2(P,(*nuage)[(*noeud_contenu)[i]]);
386 num_sol=(*noeud_contenu)[i];
392 else return DTREE_FANTOME;
395 // Fonction de pilotage de la recursion, lance les tests preliminaires et invoque la recursion
396 _TEMPLATE_ int _DTREE_::trouve_plus_proche_point(NOEUD P) const
399 if (etat==DTREE_FANTOME)
401 cerr<<"DTREE : TROUVE PLUS PROCHE POINT : L'octree n'est pas construit !"<<endl;
404 dTree *ref=trouve_dTree_contenant(P);
409 // Le point est intérieur
413 delta=DistanceInf((ref->pere->coord_max),(ref->pere->coord_min));
417 cerr<<"DTREE : TROUVE PLUS PROCHE POINT : l'octree contenant le noeud n'a pas de pere !"<<endl;
423 // Le point est extérieur
425 delta=DistanceL2(P,(*nuage)[0]);
431 retour=tppp_rec(P,delta,flag);
435 _TEMPLATE_ int _DTREE_::trouve_un_point() const
437 if (noeud_contenu!=NULL)
439 if (noeud_contenu->size()>0) return (*(noeud_contenu))[0];
444 for (i=0;i<nbr_descendants;i++)
446 return descendant[i]->trouve_un_point();
450 // partie recursive de l'algo ci dessus
451 // change le flag en 1 si un point plus proche est trouvé
452 // adapte automatiquement la distance delta de filtrage
453 _TEMPLATE_ int _DTREE_::tppp_rec(NOEUD P,double &delta,int &flag) const
455 if (Localise_Point(P,delta)==0)
457 // La distance du point à l'octree est plus grande que delta
458 return DTREE_FANTOME;
462 if (etat==DTREE_TERMINAL)
464 if (noeud_contenu->size()>0)
466 num_Ptmp=trouve_plus_proche_point_bourrin(P);
467 dtmp=DistanceL2((*nuage)[num_Ptmp],P);
470 // Le point le plus proche minimise delta, c'est un bon candidat, on l'envoie !
475 // Le point le plus proche ne minimise pas delta
476 // ===========> peut etre rajouter exit(-1); ??????????
477 return DTREE_FANTOME;
481 // L'octree qui contient P ne contient aucun point
482 return DTREE_FANTOME;
486 int num_sol=DTREE_FANTOME;
487 for (i=0;i<nbr_descendants;i++)
489 num_Ptmp=descendant[i]->tppp_rec(P,delta,flag);
490 if ((num_Ptmp!=DTREE_FANTOME)&&(flag==1))
492 // On a trouvé un point qui minimise delta dans une branche
496 // A ce stade, on a trouvé un point qui minimise tous les deltas, c'est donc le point le plus proche
499 // renvoie 1 si la distance L inf du noeud a l'octree est plus petite que d, 0 sinon
500 _TEMPLATE_ int _DTREE_::Localise_Point(NOEUD P,double d) const
503 for (i=0;i<DIMENSION;i++)
505 if (P[i]>coord_max[i]+d) return 0;
506 if (P[i]<coord_min[i]-d) return 0;
510 // Méthode de construction du dTree par propagation
511 _TEMPLATE_ void _DTREE_::cree_filiation()
513 if (etat!=DTREE_RACINE)
515 niveau=pere->niveau+1;
522 if (noeud_contenu->size()<=NBR_NOEUDS_PAR_CASE)
530 Sommet_dTree<DIMENSION> centre(coord_max,coord_min);
532 for (i=0;i<nbr_descendants;i++)
534 descendant[i]=new dTree(centre,donne_sommet(i),this);
537 for (num_loc=0;num_loc<noeud_contenu->size();num_loc++)
539 int indice=(*noeud_contenu)[num_loc];
540 NOEUD & courant=(*nuage)[indice];
542 for (i=0;(test)&&(i<nbr_descendants);i++)
544 if (descendant[i]->is_in_dTree(courant))
546 descendant[i]->noeud_contenu->push_back(indice);
552 delete noeud_contenu;
555 for (i=0;i<nbr_descendants;i++) descendant[i]->cree_filiation();
558 _TEMPLATE_ int _DTREE_::Get_Nbr_Descendants_Non_Vides() const
564 case DTREE_RACINE : int pourlefunlecompilolesttropcon;
566 for (i=0;i<nbr_descendants;i++) ndnv+=descendant[i]->Get_Nbr_Descendants_Non_Vides();
568 case DTREE_TERMINAL :
569 if (noeud_contenu->size()>0) return 1;
572 cerr<<"dTree Non Valide dans Get_Nbr_Descendants_Non_Vides"<<endl;
576 _TEMPLATE_ int _DTREE_::Get_Nbr_Descendants_Vides() const
582 case DTREE_RACINE : int pourlefunlecompilolesttropcon;
584 for (i=0;i<nbr_descendants;i++) ndnv+=descendant[i]->Get_Nbr_Descendants_Vides();
586 case DTREE_TERMINAL :
587 if (noeud_contenu->size()==0) return 1;
590 cerr<<"dTree Non Valide dans Get_Nbr_Descendants_Non_Vides"<<endl;
594 _TEMPLATE_ int _DTREE_::Get_Profondeur_Max() const
601 case DTREE_RACINE : int pourlefunlecompilolesttropcon;
603 for (i=0;i<nbr_descendants;i++)
605 tmp=descendant[i]->Get_Profondeur_Max();
606 if (tmp>prof) prof=tmp;
609 case DTREE_TERMINAL : return niveau;
611 cerr<<"dTree Non Valide dans Get_Nbr_Descendants_Non_Vides"<<endl;