Simplexus  1.0
Création d'un pavage par des simplexes de dimension N et visualisation graphique en dimension 2.
pavage.hpp
Go to the documentation of this file.
1 #ifndef _PAVAGE_H
2 #define _PAVAGE_H
3 
11 #include <cstddef>
12 #include <iostream>
13 #include <cstdlib>
14 #include <cassert>
15 #include <cstdarg>
16 #include <cmath>
17 #include <set>
18 #include <vector>
19 #include <list>
20 #include <utility>
21 #include <algorithm>
22 #include <iterator>
23 #include <sstream>
24 #include <string>
25 #include <cstring>
26 #include <cstdio>
27 #include <fstream>
28 #include "point.hpp"
29 #include "mathutil.hpp"
30 
32 template<std::size_t N>
38 class Pavage
39 {
40  private:
41  std::set<std::vector<Point<N>*>> figures;
42  std::list<std::pair<Point<N>, double>> points;
43  int toUpdate = 0;
44  public:
51  Pavage() {};
52 
67  Pavage(bool notToDisplay);
68 
76  Pavage(std::list<std::pair<Point<N>, double>>& _points);
77 
87  bool isPointInFigure(const std::vector<Point<N>*>& figure, const Point<N>& pt) const;
88 
97  void addPoint(Point<N>& pt, double val);
98 
106  std::set<std::vector<Point<N>*>>& getFigures();
107 
115  std::list<std::pair<Point<N>, double>>& getPoints();
116 
125  double volume(const std::vector<Point<N>*>& figure) const;
126 
136  double interpolation(const Point<N>& point) const;
137 
147  bool contain(std::list<Point<N>*> _points, const Point<N>& _point) const;
148 
156  std::list<Point<N>*> getSinglePoints() const;
157 
165  bool empty() const;
166 
174  void affectValToBoundries();
175 
183  std::list<std::pair<Point<N>, double>*> getBoundries();
184 
192  template<std::size_t P>
193  friend std::ostream& operator<<(std::ostream& os, const Pavage<P>& pavage);
194 };
195 
196 
197 template<std::size_t N>
198 Pavage<N>::Pavage(bool notToDisplay /* =true */)
199 {
200  /*
201  * On va créer un pavage composé d'une enveloppe
202  * Les points de l'enveloppe seront NOTAMMENT de la forme :
203  * P1 : (x1_min, 0 , 0 ..., 0)
204  * P2 : (x1_max, 0 , 0 ..., 0)
205  * P2i : (0, ..., xi_min, ..., 0)
206  * P2i+1 : (0, ..., xi_max, ..., 0)
207  * ...
208  * avec x1_min = x2_min = ... = xi_min = xn_min = VAL_MIN
209  * et x1_max = x2_max = ... = xi_max = xn_max = VAL_MAX
210  * */
211 
212 
213  double valmin = 0.;
214  double valmax = 0.;
215 
216  // Convention : Si on ne doit pas etre amené a afficher le pavage :
217  // VAL_MIN = -25000
218  // VAL_MAX = 25000
219  if (notToDisplay){
220  valmin= -25000.0;
221  valmax= 25000.0;
222  }
223  // Convention : Si on ne doit etre amené a afficher le pavage :
224  // VAL_MIN = -300
225  // VAL_MAX = 300
226  else {
227  valmin=-300.0;
228  valmax=300.0;
229  }
230 
231  //On créé les différents points de l'enveloppe
232  Point<N> *pointXMin;
233  Point<N> *pointXMax;
234 
235  points.push_back(std::make_pair(Point<N>({valmin}), 0.0));
236  pointXMin = &(points.back().first);
237  pointXMin->toBoundry();
238  points.push_back(std::make_pair(Point<N>({valmax}), 0.0));
239  pointXMax = &(points.back().first);
240  pointXMax->toBoundry();
241 
242  std::vector<Point<N>*> figureCur;
243  for (unsigned i=0; i<=N-1; i++){
244 
245  std::vector<double> v(N-1, valmin);
246 
247  for (unsigned j=0;j<i;j++){
248  v.at(j)=valmax;
249  }
250 
251  int coord_cpt = 0;
252  do {
253  coord_cpt++;
254  figureCur.clear();
255 
256  figureCur.push_back(pointXMin);
257  figureCur.push_back(pointXMax);
258  for(unsigned k=0; k<v.size(); k++){
259  Point<N> p{};
260  p.toBoundry();
261 
262  for(unsigned l=0; l<N; l++){
263  p.setCoord(l, 0.0);
264  }
265 
266  p.setCoord(k+1, v.at(k));
267  Point<N>* pointToInsert;
268 
269  bool insert = false;
270 
271  for (typename std::list<std::pair<Point<N>, double>>::iterator it1=points.begin(); it1 != points.end(); ++it1){
272  if ((*it1).first==p){
273  insert = true;
274  pointToInsert = &((*it1).first);
275  pointToInsert->toBoundry();
276  }
277  }
278 
279  if (insert){
280  figureCur.push_back(pointToInsert);
281  }
282  else {
283  points.push_back(std::make_pair(std::move(p), 0.0));
284  figureCur.push_back(&(points.back().first));
285  }
286  }
287 
288  figures.insert(figureCur);
289  //Pour créer les différents points, il faut faire des permutations sur un vecteur de points
290  } while (std::prev_permutation(v.begin(), v.end()));
291  }
292 
293  /*
294  * On effectue une rotation de pi/2 pour chaque point du pavage
295  * pour un meilleur rendu visuel si on va afficher le pavage
296  * */
297  if (!notToDisplay && N==2){
298  for (std::pair<Point<N>, double>& paire : points){
299  Point<N>& pt = paire.first;
300  double x= pt.getCoord(0);
301  double y= pt.getCoord(1);
302 
303  double theta = pi()/4.;
304  double newX = std::round(std::sin(theta)*y + std::cos(theta)*x);
305  double newY = std::round(std::cos(theta)*y - std::sin(theta)*x);
306 
307  pt.setCoord(0,newX);
308  pt.setCoord(1,newY);
309  }
310  }
311 }
312 
313 template<std::size_t N>
314 Pavage<N>::Pavage(std::list<std::pair<Point<N>, double>>& _points)
315 {
316  if (_points.size() != N+1) {
317  std::cerr << "Il faut donner " << N+1 << " points" << std::endl;
318  abort();
319  }
320  points = _points;
321  std::vector<Point<N>*> newFigure;
322 
323  for(auto& pair : _points){
324  newFigure.push_back(&pair.first);
325  }
326 
327  figures.insert(newFigure);
328 }
329 
330 template<std::size_t N>
331 std::list<Point<N>*> Pavage<N>::getSinglePoints() const{
332  std::list<Point<N>*> singlePoints;
333  for (const std::pair<Point<N>, double>& pair : this->points){
334  singlePoints.push_back(const_cast<Point<N>* >(&(pair.first)));
335  }
336  return singlePoints;
337 }
338 
339 template<std::size_t N>
340 bool Pavage<N>::contain(std::list<Point<N>*> _points, const Point<N>& _point) const{
341  for (Point<N>* point : _points){
342  if (*point ==_point){
343  return true;
344  }
345  }
346  return false;
347 }
348 
349 template<std::size_t N>
350 std::ostream& operator<<(std::ostream& os, const Pavage<N>& pavage){
351  auto& figures = const_cast<Pavage<N>&>(pavage).getFigures();
352 
353  int cpt=1;
354  os << const_cast<Pavage<N>&>(pavage).getPoints().size() <<" points, " << figures.size() << " figures." << std::endl;
355  for (typename std::set<std::vector<Point<N>*>>::iterator it=figures.begin(); it != figures.end(); ++it){
356  os << "Figure " << cpt << " : ";
357  for(unsigned int i=0; i<N+1; i++){
358  os << *(it->at(i)) << " ";
359  }
360  os << std::endl;
361  cpt++;
362  }
363  return os;
364 }
365 
366 template<std::size_t N>
367 std::set<std::vector<Point<N>*>>& Pavage<N>::getFigures(){
368  return this->figures;
369 }
370 
371 template<std::size_t N>
372 std::list<std::pair<Point<N>, double>>& Pavage<N>::getPoints(){
373  return this->points;
374 }
375 
376 template<std::size_t N>
377 bool Pavage<N>::empty() const{
378  if (this->figures.size() == 0){
379  return true;
380  }
381  return false;
382 }
383 
384 template<std::size_t N>
385 bool Pavage<N>::isPointInFigure(const std::vector<Point<N>*>& figure, const Point<N>& pt) const {
386  //On va déterminer si un point P appartient a une figure F
387  //représentée par un vecteur de points
388  for(unsigned int i=0; i<figure.size(); i++){
389  std::vector<std::vector<double>> det1;
390  std::vector<std::vector<double>> det2;
391 
392  //Pour chaque point Pi de la figure F
393  Point<N>* pointDuMemeCote = figure.at(i);
394 
395  //Pour ce faire, on calcule deux déterminants pour chaque point de la figure F
396  for (unsigned int j=0 ; j < N; j++){
397  std::vector<double> line1;
398  std::vector<double> line2;
399  for (unsigned int k=0; k< figure.size(); k++){
400  if (k!=i){
401  //Le premier est celui de la matrice composée des vecteurs
402  //PPj pour chaque Pj appartenant à la figure F privé de Pi
403  line1.push_back(pt.getCoord(j) - figure.at(k)->getCoord(j));
404 
405  //Le deuxieme est celui de la matrice composée des vecteurs
406  //PiPj pour chaque Pj appartenant à la figure F privé de Pi
407  line2.push_back(pointDuMemeCote->getCoord(j) - figure.at(k)->getCoord(j));
408  }
409  }
410  det1.push_back(line1);
411  det2.push_back(line2);
412  line1.empty();
413  line2.empty();
414  }
415  double determinant1 = determinant(det1);
416  double determinant2 = determinant(det2);
417  det1.empty();
418  det2.empty();
419 
420  //Si la multiplication des deux déterminants est négative, le point n'appartient pas à la figure
421  //Moralement, cela veut dire que le point est "du meme coté" que chaque point de la figure
422  if (determinant1*determinant2<=0){
423  return false;
424  }
425  }
426  return true;
427 }
428 
429 template<std::size_t N>
430 void Pavage<N>::addPoint(Point<N>& pt, double val) {
431 
432  //Pour ajouter un point au pavage qui contient au moins une figure
433  if (this->points.size() >= N+1){
434 
435  //Si le point n'appartient pas déja au pavage
436  if (!contain(this->getSinglePoints(), pt)){
437 
438  //On l'ajoute à la liste des points du pavage
439  points.push_back(std::make_pair(std::move(pt), val));
440 
441  Point<N>& noCopyPt = points.back().first;
442  std::set<std::vector<Point<N>*>> newFigures;
443 
444  //On recherche la figure F à laquelle appartient le point P
445  //On créé à partir de la figure de N+1 points,
446  //N+1 nouvelles figures composées de N points parmi les N+1 points + le point P
447  //Puis on supprime la figure F
448  for (typename std::set<std::vector<Point<N>*>>::iterator it=figures.begin(); it != figures.end(); ++it){
449  std::vector<Point<N>*> figureCur = *it;
450  if (this->isPointInFigure(figureCur,noCopyPt) && newFigures.find(figureCur) == newFigures.end()){
451 
452  //On créé les nouvelles figures
453  for (unsigned i=0; i <figureCur.size(); i++){
454  //On créé la nouvelle figure
455  std::vector<Point<N>*> newFigure;
456  for (unsigned j=0; j < figureCur.size(); j++){
457  Point<N>* copyPoint(figureCur.at(j));
458  if (i!=j){
459  newFigure.push_back(copyPoint);
460  }
461  }
462  //On ajoute la nouvelle figure parmi la liste des nouvelles figures à ajouter au pavage
463  newFigure.push_back(&(noCopyPt));
464  newFigures.insert(newFigure);
465  }
466  //On supprime F
467  this->figures.erase(it);
468 
469  }
470  }
471 
472  //On insère les figures précédemment crées dans la liste des figures du pavage
473  for (typename std::set<std::vector<Point<N>*>>::iterator it=newFigures.begin(); it != newFigures.end(); ++it){
474  if (volume(*it) != 0){
475  this->figures.insert(*it);
476  }
477  }
478  }
479  //Si le point appartient déja au pavage, on met juste à jour sa valeur
480  else {
481  for (std::pair<Point<N>, double>& pair : this->points){
482  if (const_cast<Point<N>& >(pt) == pair.first){
483  pair.second = val;
484  }
485  }
486  }
487  }
488  //Si le pavage ne contient aucune figure mais qui lui manque un seul point pour en créer une
489  //On ajoute le point à la liste des points du pavage et on créé la premiere figure du pavage
490  else if (this->points.size() == N) {
491  this->points.push_back(std::make_pair(std::move(pt), val));
492  std::vector<Point<N>*> figure;
493 
494  for (std::pair<Point<N>, double>& paire : this->points) {
495  Point<N>& pt = paire.first;
496  figure.push_back(&pt);
497  }
498  this->figures.insert(figure);
499  }
500  //Si le pavage est à plus de 1 point d'avoir une premiere figure,
501  //On ajoute juste le point a la liste des points du pavage
502  else{
503  this->points.push_back(std::make_pair(std::move(pt), val));
504  }
505 
506  //Convention
507  //On décide de mettre à jour la valeur des points de l'enveloppe du pavage après l'ajout de 5 points
508  //Les points qui ont permis au départ de créer le pavage n'avait pas de valeur affectée par l'utilisateur
509  //On conviendra ainsi que leur valeur sera la moyenne pondéré des valeurs des autres points
510  //du pavage en fonction de la distance
511  this->toUpdate++;
512  if(this->toUpdate > 5){
513  this->toUpdate =0;
514  this->affectValToBoundries();
515  }
516 
517 }
518 
519 template<std::size_t N>
520 double Pavage<N>::volume(const std::vector<Point<N>*>& figure) const{
521  //On va construire une matrice de coordonnées qui nous permettre de calculer le déterminant récursivement en s'affranchissant des templates
522  std::vector<std::vector<double>> det;
523  //Si la figure ne possède aucun points, il n'est pas possible de calculer le volume
524  if (figure.size() ==0){
525  std::cerr << "Volume impossible a calculer" << std::endl;
526  abort();
527  }
528  //Si la figure possède un seul point ou deux points, on conviendra que le volume est nul
529  if (figure.size() ==1){
530  return 0.0;
531  }
532  if (figure.size() ==2){
533  return 0.0;
534  }
535  //Cas où la dimension est égale à 2 on a pour un triangle ABC,
536  //avec A(xA,yA), B(xB,yB), C(xC,yC):
537  // |xA xB xC|
538  // volume = |yA yB yC| / factorielle(N)
539  // |1 1 1 |
540  // avec |...| qui représente l'opération du déterminant
541  if (figure.size()==3){
542  std::vector<double> curColumn;
543  for(unsigned int i=0; i<figure.size(); i++){
544  curColumn.clear();
545  for(unsigned j=0; j<N; j++){
546  curColumn.push_back(figure.at(i)->getCoord(j));
547  }
548  curColumn.push_back(1);
549  det.push_back(curColumn);
550  }
551  }
552  //Cas où la dimension est supérieure à 2 et égale à N on a pour un N-Simplexe,
553  //avec P1(x1,1;x1,2;...;x1,n), P2(x2,1;x2,2;...;x2,n), ..., Pn+1(xn+1,1;xn+1,2;...;xn+1,n):
554  //
555  // |x2,2 - x1,1 ... xn+1,1 - x1,1|
556  // |x2,2 - x1,2 ... xn+1,2 - x1,2|
557  // volume = |... ... ... | / factorielle(N)
558  // |... ... ... |
559  // |x2,n - x1,n ... xn+1,n - x1,n|
560  //
561  // avec |...| qui représente l'opération du déterminant
562  else{
563  Point<N>* firstPoint = figure.at(0);
564  for(unsigned int i=1; i<figure.size(); i++){
565  std::vector<double> curColumn;
566  for(unsigned j=0; j<N; j++){
567  curColumn.push_back(figure.at(i)->getCoord(j)-firstPoint->getCoord(j));
568  }
569  det.push_back(curColumn);
570  curColumn.clear();
571  }
572  }
573 
574  return determinant(det)/(Factorial<N>::valeur);
575 }
576 
577 template<std::size_t N>
578 double Pavage<N>::interpolation(const Point<N>& point) const{
579 
580  double interpo=0.;
581 
582  for (typename std::set<std::vector<Point<N>*>>::iterator it=figures.begin(); it != figures.end(); ++it){
583  //On recherche tout d'abord la figure F1 à laquelle appartient le point passé en argument
584  std::vector<Point<N>*> figureCur = *it;
585  if (this->isPointInFigure(figureCur,point)){
586  //On calcule le volume de la figure F1 dans laquelle le point est contenu
587  double denominateur = this->volume(figureCur);
588  if (denominateur == 0){
589  std::cerr << "Volume de la figure nulle"<<std::endl;
590  abort();
591  }
592  std::vector<double> coordsBarycentriques;
593  //On calcule les coordonnées barycentriques du points
594  for (unsigned i=0; i < figureCur.size(); i++){
595  //Pour calculer une coordonnée barycentrique d'un point P associé à un point Pi de F1,
596 
597  //Il faut tout d'abord calculer le volume de la figure F2 de N+1 points
598  //formée par :
599  // N points parmi les N+1 points de la figure à laquelle le point appartient (privé du point Pi)
600  // + le point du point P
601 
602  //On créé la figure F2
603  std::vector<Point<N>*> newFigure;
604  newFigure.clear();
605  for (unsigned j=0; j < figureCur.size(); j++){
606  if (i!=j){
607  newFigure.push_back(figureCur.at(j));
608  }
609  }
610  newFigure.push_back(&(const_cast<Point<N>&>(point)));
611 
612  //On calcule le volume de la figure F2
613  double numerateur = this->volume(newFigure);
614 
615  //La coordonnée barycentrique est alors volume(F20)/volume(F2)
616  double coordBarycentriquei=std::abs(numerateur)/std::abs(denominateur);
617  coordsBarycentriques.push_back(coordBarycentriquei);
618  }
619  for (unsigned i=0; i < figureCur.size(); i++){
620  double eval = 0.;
621  for(std::pair<Point<N>, double>& pair : const_cast<std::list<std::pair<Point<N>, double> >& >(points)){
622  if (const_cast<Point<N>&>(pair.first) == *figureCur.at(i)){
623  eval = pair.second;
624  }
625  }
626  //L'interpolation du point est finalement
627  //la somme des coordonnées barycentriques associé à Pi * la valeur associée au point Pi
628  interpo += coordsBarycentriques.at(i)*eval;
629  }
630  }
631  }
632  return interpo;
633 }
634 
635 
636 template<std::size_t N>
638  auto& pts = this->getPoints();
639 
640  for (std::pair<Point<N>, double>* boundry : this->getBoundries()){
641  double sumDist = 0.;
642  double moyVal = 0.;
643  for (auto& pt : pts){
644  if (!pt.first.isBoundry()){
645  double distance = boundry->first.distance(pt.first);
646  sumDist += distance;
647  moyVal += distance*pt.second;
648  }
649  }
650  boundry->second=moyVal/sumDist;
651  }
652 }
653 
654 template<std::size_t N>
655 std::list<std::pair<Point<N>, double>*> Pavage<N>::getBoundries(){
656 
657  std::list<std::pair<Point<N>, double>*> boundries;
658  std::list<std::pair<Point<N>, double>>& listOfPoints = this->getPoints();
659 
660  typename std::list<std::pair<Point<N>, double>>::iterator it;
661 
662  for (it = listOfPoints.begin(); it != listOfPoints.end(); ++it){
663  Point<N>& pt = (*it).first;
664  for (unsigned int i=0; i<N; i++){
665  if (pt.isBoundry()){
666  std::pair<Point<N>, double>& paire = *it;
667  boundries.insert(boundries.end(),&paire);
668  break;
669  }
670  }
671  }
672 
673  return boundries;
674 }
675 
676 
677 #endif
Bibliothèque d'opération sur des points de dimension N templatée.
void affectValToBoundries()
Affectation de valeurs aux bornes du pavage.
Definition: pavage.hpp:637
double determinant(std::vector< std::vector< double >> det)
Calcul d'un déterminant.
Definition: mathutil.cpp:7
bool isPointInFigure(const std::vector< Point< N > * > &figure, const Point< N > &pt) const
Test d'appartenance d'un point à une figure.
Definition: pavage.hpp:385
bool isBoundry()
Détermine si le point est une borne.
Definition: point.hpp:408
classe representant un pavage consitué de trisimplexe dans un espace de dimension N ...
Definition: pavage.hpp:38
double volume(const std::vector< Point< N > * > &figure) const
Calcul du volume d'une figure.
Definition: pavage.hpp:520
std::list< std::pair< Point< N >, double > > & getPoints()
Getter des couples (point, valeur) du pavage.
Definition: pavage.hpp:372
Calcul de la Factorial de N.
Definition: mathutil.hpp:25
double getCoord(unsigned int index) const
Getter d'une coordonnée.
Definition: point.hpp:341
bool empty() const
Teste si le pavage est vide.
Definition: pavage.hpp:377
void addPoint(Point< N > &pt, double val)
Ajout d'un point au pavage.
Definition: pavage.hpp:430
void setCoord(unsigned int index, double val)
setter d'une coordonnée du point e la coordonnée d'index index du point
Definition: point.hpp:320
void toBoundry()
Identificateur d'un point comme borne.
Definition: point.hpp:403
bool contain(std::list< Point< N > * > _points, const Point< N > &_point) const
Test d'appartenance d'un point a une liste de pointeurs sur point.
Definition: pavage.hpp:340
double interpolation(const Point< N > &point) const
Calcul de la valeur d'interpolation d'un point.
Definition: pavage.hpp:578
std::list< std::pair< Point< N >, double > * > getBoundries()
Récupềre les bornes du pavage.
Definition: pavage.hpp:655
constexpr double pi()
Calcul de pi.
Definition: mathutil.hpp:82
Pavage()
Constructeur vide d'un pavage.
Definition: pavage.hpp:51
classe representant un point dans un espace de dimension N
Definition: point.hpp:29
Fonction mathématiques de base.
std::set< std::vector< Point< N > * > > & getFigures()
Getter des figures du pavage.
Definition: pavage.hpp:367
std::list< Point< N > * > getSinglePoints() const
Getter des points du pavage.
Definition: pavage.hpp:331