// FICHIER : Coordonnee.cc // CLASSE : Coordonnee // This file is part of the Herezh++ application. // // The finite element software Herezh++ is dedicated to the field // of mechanics for large transformations of solid structures. // It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600) // INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) . // // Herezh++ is distributed under GPL 3 license ou ultérieure. // // Copyright (C) 1997-2021 Université Bretagne Sud (France) // AUTHOR : Gérard Rio // E-MAIL : gerardrio56@free.fr // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, // or (at your option) any later version. // // 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 for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // For more information, please consult: . //#include "Debug.h" # include using namespace std; //introduces namespace std #include #include "Sortie.h" #include "ConstMath.h" #include "MathUtil.h" #include #include "ParaGlob.h" #include #include "Coordonnee.h" #ifndef COORDONNEE_H_deja_inclus // Constructeur par defaut // avant ->// N.B. : la dimension est affectee a 3 et les valeurs a 0 #ifndef MISE_AU_POINT inline #endif Coordonnee::Coordonnee () : dim (0) , coord (NULL),memoire(true) {}; // Constructeur utile si le nombre de coordonnees est connue // N.B. : les valeurs sont affectees a 0. #ifndef MISE_AU_POINT inline #endif Coordonnee::Coordonnee (int dimension) : dim ((short)dimension), memoire(true),coord (NULL) { if (dim == 0) return; #ifdef MISE_AU_POINT if ( (dimension<0) || (dimension>3) ) { cout << "\nErreur de dimension !\n"; cout << "COORDONNEE::COORDONNEE (int ) \n"; Sortie(1); }; #endif coord=new double [dim]; switch (dim) {case 3: coord[2]=0.0; case 2: coord[1]=0.0; case 1: coord[0]=0.0; }; }; // Constructeur pour un point a une dimension #ifndef MISE_AU_POINT inline #endif Coordonnee::Coordonnee (double x) : dim (1),memoire(true) { coord=new double [1]; coord[0]=x; }; // Constructeur pour un point a deux dimensions #ifndef MISE_AU_POINT inline #endif Coordonnee::Coordonnee (double x,double y) : dim (2),memoire(true) { coord=new double [2]; coord[0]=x; coord[1]=y; }; // Constructeur pour un point a trois dimensions #ifndef MISE_AU_POINT inline #endif Coordonnee::Coordonnee (double x,double y,double z) : dim (3) ,memoire(true) { coord=new double [3]; coord[0]=x; coord[1]=y; coord[2]=z; }; // constructeur fonction d'une adresse memoire ou sont stockee les coordonnees // et d'une dimension ( l'existance de la place mémoire est a la charge // de l'utilisateur. // DANS CE CAS IL N'Y A PAS DE CREATION DE MEMOIRE !! #ifndef MISE_AU_POINT inline #endif Coordonnee::Coordonnee (int dimension,double* t) : dim ((short) dimension),coord (t),memoire(false) {}; // Constructeur de copie // mais là on construit systématiquement un vrai coordonnée // même si la mémoire est fausse, car on ne veut pas que plusieur // coordonnée pointes sur les mêmes valeurs, sans précautions supplémentaires #ifndef MISE_AU_POINT inline #endif Coordonnee::Coordonnee (const Coordonnee& c) : dim (c.dim),memoire(true) { if ( dim==0 ) coord=NULL; else // copie des coordonnees { coord=new double [dim]; switch (dim) {case 3: coord[2]=c.coord[2]; case 2: coord[1]=c.coord[1]; case 1: coord[0]=c.coord[0]; }; }; }; // Destructeur // Desallocation de la place memoire allouee #ifndef MISE_AU_POINT inline #endif Coordonnee::~Coordonnee () {if (memoire) { if (dim > 0) { delete [] coord; coord=NULL; dim=0; } #ifdef MISE_AU_POINT else {if ( coord!=NULL ) { cout << "\nErreur de liberation de la place memoire\n"; cout << "COORDONNEE::LIBERE () \n"; Sortie(1); } } #endif } }; // fonction équivalente au constructeur: changement pour une place externe via un pointeur // ( l'existance de la place mémoire est a la charge // de l'utilisateur et ne sera pas détruite par le destructeur.) #ifndef MISE_AU_POINT inline #endif void Coordonnee::Change_place(int dimension,double* t) { // on commence par libérer la place Libere(); // création en fonction de la dimension dim = dimension; switch (dim) { case 0: memoire = true; break; // on met à true, car de toute manière il n'y a pas de mémoire case 1: case 2: case 3: { memoire = false; coord = t; break;} // cas normal default: { cout << "\n erreur la dimension n'est entre 0 et 3 : " << dimension << "\n Coordonnee::Change_place(int dimension,double* t)"; Sortie(1); } }; }; // changement des coordonnees #ifndef MISE_AU_POINT inline #endif void Coordonnee::Change_Coordonnee(int dimension, double x) // dimension 1 { if (dim == dimension) { coord[0] = x; } else { Change_dim(dimension); coord[0] = x; }; }; // changement des coordonnees #ifndef MISE_AU_POINT inline #endif void Coordonnee::Change_Coordonnee(int dimension, double x,double y) // dimension 2 { if (dim != dimension) Change_dim(dimension); coord[0] = x; coord[1] = y; }; // changement des coordonnees #ifndef MISE_AU_POINT inline #endif void Coordonnee::Change_Coordonnee(int dimension, double x,double y,double z) // dimension 3 { if (dim != dimension) Change_dim(dimension); coord[0] = x; coord[1] = y; coord[2] = z; }; // Renvoie le nombre de coordonnees #ifndef MISE_AU_POINT inline #endif int Coordonnee::Dimension () const { return dim; }; // Desallocation de la place memoire allouee #ifndef MISE_AU_POINT inline #endif void Coordonnee::Libere () {if (memoire) { if (dim > 0) { delete [] coord; coord=NULL; dim=0; } }; coord=NULL; dim=0; }; // Renvoie la ieme coordonnee #ifndef MISE_AU_POINT inline #endif double& Coordonnee::operator() (int i) { #ifdef MISE_AU_POINT if ( (i<1) || (i>dim) ) { cout << "\nErreur de dimension !\n"; cout << "COORDONNEE::OPERATOR() (int ) \n"; Sortie(1); }; #endif return coord[i-1]; }; // Renvoie une copie de la ieme coordonnee #ifndef MISE_AU_POINT inline #endif double Coordonnee::operator() (int i) const { #ifdef MISE_AU_POINT if ( (i<1) || (i>dim) ) { cout << "\nErreur de dimension !\n"; cout << "COORDONNEE::OPERATOR() (int ) \n"; Sortie(1); }; #endif return coord[i-1]; }; // changement de la dimension // dans le cas d'une nouvelle dimension inferieur on supprime les dernieres coord // dans le cas d'une dimension superieur, on ajoute des coord initialisees a zero` #ifndef MISE_AU_POINT inline #endif void Coordonnee::Change_dim(int dimen) { if (dimen == dim) return; // même dimension, on ne fait rien #ifdef MISE_AU_POINT if ((dimen<0) || (dimen>3)) { cout << "\n erreur, la nouvelle dimension doit etre comprise entre 0 et 3 ! "; cout << "\n dim voulue = " << dimen ; cout << "\nCoordonnee::Change_dim(int dim) " << endl; Sortie(1); } #endif double * sauve = coord; if (dimen == 0) { // comme on a déjà passé le cas où dimen == dim, cela veut dire que dim est non nulle Libere(); } else if (dim < dimen) // cas où la nouvelle dimension est supérieur {// dans le cas où il n'y a pas eu allocation, donc que la mémoire n'est // pas gérée par l'objet, on ne peut pas changer de dimension if (!memoire) { cout << "\n erreur, l'objet ne gere pas sa memoire, donc le changement de dim " << " n'est pas possible !! "; cout << "\n dim voulue = " << dimen << " ancienne dimension: " << dim ; cout << "\nCoordonnee::Change_dim(int dim) " << endl; Sortie(1); }; // donc pour la suite on considère que l'élément gère sa mémoire // les dimensions sont 1 ou 2 ou 3 // et le cas même dimension a déjà été réglé, donc ici il y a forcément // une différence if (dim ==0 ) // cas où rien n'exitait et dimen > 0 { coord = new double [dimen]; dim = dimen; switch (dim) {case 3: coord[2]=0.0; case 2: coord[1]=0.0; case 1: coord[0]=0.0; }; } else // cas où dim est différent de 0 {switch (dimen - dim) {case 2: // là obligatoirement: dimen=3 et dim = 1 { coord = new double [dimen]; dim = (short)dimen; coord[2]=0.;coord[1]=0.;coord[0]=sauve[0]; delete [] sauve; break; } case 1: // dim ne peut avoir comme dimension que 2 ou 1 { coord = new double [dimen]; switch (dim) {case 2: // dimen = 3 { coord[2]=0.;coord[1]=sauve[1];coord[0]=sauve[0]; break; } case 1: // dimen = 2 { coord[1]=0.;coord[0]=sauve[0]; break; } }; dim = (short)dimen; delete [] sauve; } }; } } else if (dim > dimen) // nouvelle dimension non nulle, plus petite { coord = new double [dimen]; switch (dimen) {case 3: coord[2]=sauve[2]; case 2: coord[1]=sauve[1]; case 1: coord[0]=sauve[0]; }; if (dim > 0) delete [] sauve; dim = (short) dimen; } }; // Surcharge de l'operateur = : realise l'affectation entre deux points #ifndef MISE_AU_POINT inline #endif Coordonnee& Coordonnee::operator= (const Coordonnee& c) { if (dim==c.dim) { switch (dim) {case 3: coord[2]=c.coord[2]; case 2: coord[1]=c.coord[1]; case 1: coord[0]=c.coord[0]; // case 0: on ne fait rien }; return (*this); } else if ( c.dim==0 ) { Libere();} else { if (!memoire) { cout << "\n erreur, l'objet ne gere pas sa memoire, donc le changement de dim " << " n'est pas possible !! "; cout << "\n dim voulue = " << c.dim << " ancienne dimension: " << dim ; cout << "\nCoordonnee::operator= (const Coordonnee& c) " << endl; Sortie(1); }; #ifdef MISE_AU_POINT if (dim != 0) cout << "\n attention, on change la dimension du point !!!" << " de "<Change_dim(dim); switch (dim) { case 3 : {*(entreePrinc.entree) >> coord[0] >> coord[1] >> coord[2] ; break;} case 2 : {*(entreePrinc.entree) >> coord[0] >> coord[1] ; break;} case 1 : {*(entreePrinc.entree) >> coord[0] ; break;} }; }; // lecture brut des coordonnées sans la dimension dans le flux par défaut #ifndef MISE_AU_POINT inline #endif // lecture brut des coordonnées sans la dimension void Coordonnee::Lecture () { // 4mars2014 : suppression des deux lignes qui suivent qui ne servent à rien // int dim = Dimension (); // il n'y a jamais de dimension 0 // this->Change_dim(dim); switch (dim) { case 3 : {cin >> coord[0] >> coord[1] >> coord[2] ; break;} case 2 : {cin >> coord[0] >> coord[1] ; break;} case 1 : {cin >> coord[0] ; break;} }; std::cin.ignore( std::numeric_limits::max(), '\n' );// purge de cin }; // surcharge de l'operateur de lecture #ifndef MISE_AU_POINT inline #endif istream & operator >> ( istream & ent, Coordonnee & coo) { // lecture du type et vérification string nomtype; ent >> nomtype; if (nomtype != "Coordonnee") { cout << "\n *** erreur en lecture: on attendait le mot cle Coordonne et on a lue " << nomtype << "\n operator >> ( istream & ent, Coordonnee & coo)"; Sortie(1); return ent; }; // lecture de la dimension int dim; ent >> nomtype >> dim; // on redimensionne éventuellement la taille if (coo.dim != dim) { if (coo.memoire) // cas ou c'est un vrai point { if (coo.coord != NULL) { delete [] coo.coord;} coo.coord = new double [dim]; coo.dim = dim; } else { cout << "\n erreur en lecture la dimension du point conteneur "<< dim << " est differente de celle lue " << dim << " et memoire est faux, donc on ne peut pas changer la dimension " << "\n operator >> ( istream & ent, Coordonnee & coo) " << endl ; Sortie(2); }; }; // les data switch (coo.dim) { case 3 : {ent >> coo.coord[0] >> coo.coord[1] >> coo.coord[2] ; break;} case 2 : {ent >> coo.coord[0] >> coo.coord[1] ; break;} case 1 : {ent >> coo.coord[0] ; break;} case 0 : break; // on ne fait rien }; return ent; }; // surcharge de l'operateur d'ecriture #ifndef MISE_AU_POINT inline #endif ostream & operator << ( ostream & sort,const Coordonnee & coo) { // écriture du type et de la dimension sort << "Coordonnee dim= " << coo.dim << " "; // les data switch (coo.dim) { case 3 : {sort << setprecision(ParaGlob::NbdigdoCA()) << coo.coord[0] << " " << setprecision(ParaGlob::NbdigdoCA()) << coo.coord[1] << " " << setprecision(ParaGlob::NbdigdoCA()) << coo.coord[2] << " "; break;} case 2 : {sort << setprecision(ParaGlob::NbdigdoCA()) << coo.coord[0] << " " << setprecision(ParaGlob::NbdigdoCA()) << coo.coord[1] << " "; break;} case 1 : {sort << setprecision(ParaGlob::NbdigdoCA()) << coo.coord[0] << " "; break;} case 0 : break; // on ne fait rien }; return sort; }; // Calcul de la norme euclidienne des composantes du point #ifndef MISE_AU_POINT inline #endif double Coordonnee::Norme () const { double norme=0.0; switch (dim) {case 3: norme+=coord[2] * coord[2]; case 2: norme+=coord[1] * coord[1]; case 1: norme+=coord[0] * coord[0]; case 0: ; }; return sqrt(norme); // norme=sqrt((double)norme); // calcul de la norme // return norme; }; // norme le vecteur coordonnée #ifndef MISE_AU_POINT inline #endif Coordonnee& Coordonnee::Normer () { double norme = this->Norme(); #ifdef MISE_AU_POINT if(Dabs(norme) <= ConstMath::trespetit) { cout << "\n erreur, division par zero "; cout << "\nCoordonnee3::Normer () " << endl; Sortie (1); }; #endif *this /= norme; return *this ; }; #ifndef MISE_AU_POINT inline #endif // Retourne le maximum en valeur absolue des composantes double Coordonnee::Max_val_abs () const { double maxi=0.; switch (dim) { case 3: maxi=DabsMaX(maxi,coord[2]); case 2: maxi=DabsMaX(maxi,coord[1]); case 1: maxi=DabsMaX(maxi,coord[0]); case 0: break; }; return maxi; }; #ifndef MISE_AU_POINT inline #endif // ramène l'indice du maxi en valeur absolu int Coordonnee::Indice_max_val_abs() const { double maxi=Dabs(coord[dim-1 ]);int indice=dim; switch (dim) { case 3: if (maxi < Dabs(coord[2])) {maxi = Dabs(coord[2]),indice = 3;} case 2: if (maxi < Dabs(coord[1])) {maxi = Dabs(coord[1]),indice = 2;} case 1: if (maxi < Dabs(coord[0])) {maxi = Dabs(coord[0]),indice = 1;} case 0: break; }; return maxi; }; #ifndef MISE_AU_POINT inline #endif // Retourne le maximum en valeur absolue des composantes et l'indice correspondant double Coordonnee::Max_val_abs (int& in) const { double maxi=0.; in = 0; switch (dim) { case 3: if (maxi < Dabs(coord[2])) {maxi=coord[2]; in=3;} case 2: if (maxi < Dabs(coord[1])) {maxi=coord[1]; in=2;} case 1: if (maxi < Dabs(coord[0])) {maxi=coord[0]; in=1;} case 0: break; }; return maxi; }; #ifndef MISE_AU_POINT inline #endif // Retourne le maximum en valeur absolue des composantes du Coordonnee // mais ramène la grandeur signée (avec son signe) double Coordonnee::Max_val_abs_signe () const { double maxi=0.; int in = 0; switch (dim) { case 3: if (maxi < Dabs(coord[2])) {maxi=coord[2]; in=3;} case 2: if (maxi < Dabs(coord[1])) {maxi=coord[1]; in=2;} case 1: if (maxi < Dabs(coord[0])) {maxi=coord[0]; in=1;} case 0: break; }; if (in != 0) {return coord[in-1];} else {return maxi;}; }; #ifndef MISE_AU_POINT inline #endif // Retourne le maximum en valeur absolue des composantes du Coordonnee // mais ramène la grandeur signée (avec son signe) et l'indice double Coordonnee::Max_val_abs_signe (int& in) const { double maxi=0.; in = 0; switch (dim) { case 3: if (maxi < Dabs(coord[2])) {maxi=coord[2]; in=3;} case 2: if (maxi < Dabs(coord[1])) {maxi=coord[1]; in=2;} case 1: if (maxi < Dabs(coord[0])) {maxi=coord[0]; in=1;} case 0: break; }; if (in != 0) {return coord[in-1];} else {return maxi;}; }; #ifndef MISE_AU_POINT inline #endif // modifie éventuellement les coordonnées de this pour quelles soient supérieures ou égales // aux coordonnées en paramètre void Coordonnee::Modif_en_max(const Coordonnee& v) { #ifdef MISE_AU_POINT if ( dim!=v.dim ) { cout << "\nErreur : dimensions non egales !\n"; cout << " Coordonnee::Modif_en_max(const Coordonnee& v) \n"; Sortie(1); }; #endif switch (dim) { case 3: if (coord[2] < v.coord[2]) coord[2]=v.coord[2]; case 2: if (coord[1] < v.coord[1]) coord[1]=v.coord[1]; case 1: if (coord[0] < v.coord[0]) coord[0]=v.coord[0]; case 0: break; }; }; #ifndef MISE_AU_POINT inline #endif // modifie éventuellement les coordonnées de this pour quelles soient inférieures ou égales // aux coordonnées en paramètre void Coordonnee::Modif_en_min(const Coordonnee& v) { #ifdef MISE_AU_POINT if ( dim!=v.dim ) { cout << "\nErreur : dimensions non egales !\n"; cout << " Coordonnee::Modif_en_min(const Coordonnee& v) \n"; Sortie(1); }; #endif switch (dim) { case 3: if (coord[2] > v.coord[2]) coord[2]=v.coord[2]; case 2: if (coord[1] > v.coord[1]) coord[1]=v.coord[1]; case 1: if (coord[0] > v.coord[0]) coord[0]=v.coord[0]; case 0: break; }; }; #ifndef MISE_AU_POINT inline #endif // ajoute une même valeur à tous les coordonnées void Coordonnee::Ajout_meme_valeur(double val) { switch (dim) {case 3: coord[2] += val; case 2: coord[1] += val; case 1: coord[0] += val; case 0: ; }; }; #ifndef MISE_AU_POINT inline #endif // sortie du schemaXML: en fonction de enu void Coordonnee::SchemaXML_Coordonnee(ofstream& sort,const Enum_IO_XML enu) { switch (enu) { case XML_TYPE_GLOBAUX : {sort << "\n " << "\n" << "\n " << "\n coordonnee de dimension 1 ou 2 ou 3: elements: " << "\n un entier (dim) donnant la dimension, et dim reels " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n " << "\n"; break; } case XML_IO_POINT_INFO : { break; } case XML_IO_POINT_BI : { break; } case XML_IO_ELEMENT_FINI : { break; } }; }; // définit des coordonnées sans variance à la même place que des coordonnées avec variances #ifndef MISE_AU_POINT inline #endif void Coordonnee::Meme_place(CoordonneeB& vB) { // on regarde s'il faut faire quelque chose pour optimiser if (coord != vB.coord) { // on commence par libérer la place Libere(); // création en fonction de la dimension dim = vB.dim; switch (dim) { case 0: memoire = true; break; // on met à true, car de toute manière il n'y a pas de mémoire default: { memoire = false; coord = vB.coord;} }; }; }; // définit des coordonnées sans variance à la même place que des coordonnées avec variances #ifndef MISE_AU_POINT inline #endif void Coordonnee::Meme_place(CoordonneeH& vH) { // on regarde s'il faut faire quelque chose pour optimiser if (coord != vH.coord) { // on commence par libérer la place Libere(); // création en fonction de la dimension dim = vH.dim; switch (dim) { case 0: memoire = true; break; // on met à true, car de toute manière il n'y a pas de mémoire default: { memoire = false; coord = vH.coord;} }; }; }; #endif