Herezh_dev/Util/MvtSolide/MvtSolide.cc
2023-05-03 17:23:49 +02:00

597 lines
26 KiB
C++

// 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) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 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 <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.
#include "MvtSolide.h"
#include "ParaGlob.h"
#include <list>
#include "MathUtil.h"
#include "CharUtil.h"
// par défaut
MvtSolide::MvtSolide() :
tab_tcr(), tab_indic(),lis_centre_noeud()
{};
// de copie
MvtSolide::MvtSolide (const MvtSolide& mvt):
tab_tcr(mvt.tab_tcr), tab_indic(mvt.tab_indic)
,lis_centre_noeud(mvt.lis_centre_noeud)
{};
// DESTRUCTEUR :
MvtSolide::~MvtSolide ()
{};
// Affiche les donnees
void MvtSolide::Affiche () const
{ cout << " mouvement_solide_ ";
int taille = tab_tcr.Taille();
list <String_et_entier>::const_iterator il = lis_centre_noeud.begin();
for (int it=1; it<= taille; it++)
{ switch (tab_indic(it))
{ case 1: // cas d'une translation
{ cout << " translation_= " << tab_tcr(it);
break;
}
case 2: // cas d'une nouvelle définition du centre
{ cout << " centre_= " << tab_tcr(it);
break;
}
case 3: // cas d'une rotation
{ cout << " rotation_= " << tab_tcr(it);
break;
}
case 4: // cas d'une rotation
{ cout << " centre_a_un_noeud=_nom_maille " << (*il).nom
<< " numnoeud= " << (*il).n;
il++;
break;
}
case 5: // cas d'une homothétie
{ cout << " homothetie_= " << tab_tcr(it);
break;
}
}; // fin du switch: switch (tab_indic)
};
cout << " ";
};
// Realise l'egalite
MvtSolide& MvtSolide::operator= (const MvtSolide& mvt)
{ tab_tcr = mvt.tab_tcr;
tab_indic = mvt.tab_indic;
lis_centre_noeud = mvt.lis_centre_noeud;
return *this;
};
//Surcharge d'operateur logique
bool MvtSolide::operator == (const MvtSolide& mvt) const
{ return ((tab_tcr == mvt.tab_tcr) && (tab_indic == mvt.tab_indic)
&& (lis_centre_noeud == mvt.lis_centre_noeud));
};
// lecture des mouvements solides si nécessaire
void MvtSolide::Lecture_mouvements_solides(UtilLecture * entreePrinc)
{ if (strstr(entreePrinc->tablcar,MotCleMvtSolide().c_str())!=NULL)
// si on change le mot clé ne pas oublier de changer la fonction MotCleMvtSolide()
{ if (ParaGlob::NiveauImpression() >= 6)
cout << " lecture des mouvements solides " << endl ;
entreePrinc->NouvelleDonnee();
string nom;
int dima = ParaGlob::Dimension();
list <Coordonnee> list_tcr; // liste des translations, centres et rotation
list <int> list_indic; // indic le type de transformation lue: 1 pour translation
// 2 pour centre et 3 pour rotation
while (strstr(entreePrinc->tablcar,"fin_mouvement_solide_")==NULL)
{*(entreePrinc->entree) >> nom;
if (nom == "translation_=")
{ Coordonnee trans(dima);
trans.Lecture(*entreePrinc);
list_tcr.push_back(trans);
list_indic.push_back(1);
};
if (nom == "centre_=")
{ Coordonnee centre(dima);
centre.Lecture(*entreePrinc);
list_tcr.push_back(centre);
list_indic.push_back(2);
};
if (nom == "rotation_=")
{ Coordonnee rot(3); // le vecteur rotation est systématiquement en 3D
rot.Lecture(*entreePrinc);
if (strstr(entreePrinc->tablcar,"en_degre_")!=0)
// on transforme en radian
{ rot *= ConstMath::Pi / 180.;};
list_tcr.push_back(rot);
list_indic.push_back(3);
// on regarde s'il s'agit de degré éventuellement
};//-- fin du cas de la rotation
if (nom == "centre_noeud_=")
{ // cas d'un centre donné par un numero de noeud
String_et_entier nu;
string nom_mail;
*(entreePrinc->entree) >> nom_mail;
if (nom_mail == "nom_mail=")
{ // cas où il y a un nom de maillage
*(entreePrinc->entree) >> nu.nom; // lecture du nom
*(entreePrinc->entree) >> nu.n; // lecture du numero de noeud
}
else
{ // sinon cela veut dire que l'on vient de lire un numéro de noeud du premier maillage
nu.nom = "";
nu.n = ChangeEntier(nom_mail);
};
lis_centre_noeud.push_back(nu);
list_tcr.push_back(Coordonnee()); // un centre par défaut
list_indic.push_back(4);
};
if (nom == "homothetie_=")
{ Coordonnee homothetie(3); // le vecteur homothetie est systématiquement en 3D
// ainsi on peut avoir une dilatation différentielle suivant les 3 axes
homothetie.Lecture(*entreePrinc);
list_tcr.push_back(homothetie);
list_indic.push_back(5);
};//-- fin du cas d'une homothetie
entreePrinc->NouvelleDonnee();
}; //-- fin du while
// on passe le mot clé de fin
*(entreePrinc->entree) >> nom;
// entreePrinc->NouvelleDonnee();
// enregistrement des mouvements solides
int taille = list_tcr.size();
tab_tcr.Change_taille(taille);
tab_indic.Change_taille(taille);
list <Coordonnee>::iterator il,ilfin=list_tcr.end();
list <int>::iterator ii,iifin=list_indic.end();
int i =1; ii=list_indic.begin(); // init pour la boucle qui suit
for (il=list_tcr.begin();il != ilfin; il++,i++,ii++)
{tab_tcr(i)=(*il);
tab_indic(i)=(*ii);
};
}; //-- fin du if indiquant le cas ou il y a des mouvements solides
};
// retour de la première rotation: en fait l'axe de rotation
const Coordonnee& MvtSolide::Premiere_rotation()const
{ Coordonnee axe; // le vecteur de retour
int taille = tab_tcr.Taille();
int dima = ParaGlob::Dimension();
for (int it=1; it<= taille; it++)
{ switch (tab_indic(it))
{ case 3: // cas d'une rotation
{ switch (dima)
{case 1:
{cout << "\n erreur : pas de rotation en 1D !! "
<< "\n MvtSolide::Premiere_rotation(..";
Sortie(1); break;
}
case 2 : case 3: return tab_tcr(it);
}
break;
} // fin du cas 3
}; // fin du switch: switch (tab_indic)
}; // fin de la boucle sur tab_indic : for (int it=1; it<= taille; it++)
// normalement on ne passe pas ici sauf s'il n'y a pas d'axe
return tab_tcr(1); // pour faire taire le compilateur
};
// indique s'il existe seulement une seule rotation
bool MvtSolide::ExisteUneSeuleRotation()const
{ int nb_rot=0;
int taille = tab_tcr.Taille();
int dima = ParaGlob::Dimension();
for (int it=1; it<= taille; it++)
{ switch (tab_indic(it))
{ case 3: // cas d'une rotation
{ switch (dima)
{case 1: break; // on ne fait rien
case 2 : case 3: nb_rot++;
}
break;
} // fin du cas 3
}; // fin du switch: switch (tab_indic)
}; // fin de la boucle sur tab_indic : for (int it=1; it<= taille; it++)
// retour
return (nb_rot == 1);
};
// application des mouvements solides aux points transmis et retour du point
// transformé
Coordonnee & MvtSolide::AppliqueMvtSolide (Coordonnee & M) const
{ // on passe en revue l'ensemble des transformations
int taille = tab_tcr.Taille();
int dima = ParaGlob::Dimension();
#ifdef MISE_AU_POINT
if (list_coor_centre_noeud.size() != lis_centre_noeud.size())
{ cout << "\n erreur : le nombre de centre noeud disponible "
<< list_coor_centre_noeud.size() << " est inferieur au nombre defini par la condition"
<< " lineaire qui est " << lis_centre_noeud.size() << endl;
Sortie(1);
};
#endif
list <Coordonnee>::const_iterator icoor_centre = list_coor_centre_noeud.begin();
Coordonnee centre(dima); // par défaut le centre
for (int it=1; it<= taille; it++)
{ switch (tab_indic(it))
{ case 1: // cas d'une translation
{ M += tab_tcr(it);
break;
}
case 2: // cas d'une nouvelle définition du centre
{ centre += tab_tcr(it);
break;
}
case 3: // cas d'une rotation
{ switch (dima)
{case 1: break; // on ne fait rien
case 2: // on tourne autour de z
{ double theta = tab_tcr(it)(3);
double costheta = cos(theta);
double sintheta = sin(theta);
// le point initial : M , le centre de rotation C
// le point final : Mnew = rotation de CM + les coordonnées du centre
Coordonnee CM(M-centre); // création de CM
M(1)=CM(1)*costheta + CM(2)*sintheta + centre(1);
M(2)=-CM(1)*sintheta + CM(2)*costheta + centre(2);
break;
}
case 3: // on a trois rotation qui sont successivement suivant x puis y puis z
{ Coordonnee& rot = tab_tcr(it); // pour simplifier
// le point initial : M , le centre de rotation C
// le point final : Mnew = rotation de CM + les coordonnées du centre
for (int i=1;i<=3;i++) // on boucle sur les trois directions
// une rotation autour de xi si l'angle est non nulle
if (!(Dabs(rot(i)) <= ConstMath::trespetit))
{ // on définit 3 index fonctions du i
int ix=1; int iy=2; int iz=3;
switch (i) // uniquement pour 2 et 3, le cas 1 étant celui de l'initialisation
// précédente
{ case 2: ix = 2; iy = 1; iz = 3; break;
case 3: ix = 3; iy = 1; iz = 2; break;
};
Coordonnee CM(M-centre); // création de CM
double theta = rot(i);
double costheta = cos(theta);
double sintheta = sin(theta);
// transformation
M(iy)=CM(iy)*costheta + CM(iz)*sintheta + centre(iy);
M(iz)=-CM(iy)*sintheta + CM(iz)*costheta + centre(iz);
M(ix)=CM(ix) + centre(ix);
};
break;
}
}; //-- fin du case sur la dimension: switch (dima)
break;
} // fin du cas 3
case 4: // cas d'un centre définie par une position de noeud
{ centre = (*icoor_centre);
break;
}
case 5: // on fait une homothétie
{ // on se sert du centre pour le centre de l'homothétie
Coordonnee& scale = tab_tcr(it); // pour simplifier
Coordonnee CM(M-centre); // création de CM
switch (dima)
{case 3: M(3) = centre(3) + CM(3) * scale(3);
case 2: M(2) = centre(2) + CM(2) * scale(2);
case 1: M(1) = centre(1) + CM(1) * scale(1);
};
break;
}
}; // fin du switch: switch (tab_indic)
}; // fin de la boucle sur tab_indic : for (int it=1; it<= taille; it++)
// retour du point transformé
return M;
};
// idem que précédemment, mais avec un coefficient d'intensité
// dans le cas d'une translation, celle-ci est multiplié par le coef
// dans le cas d'un nouveau centre, sa position n'est pas affectée par le coef
// dans le cas d'une rotation, celle-ci est multiplié par le coef
// dans le cas d'une homothétie: celle-ci est multiplié par le coef
Coordonnee & MvtSolide::AppliqueMvtSolide (Coordonnee & M, const double& coef) const
{ // on passe en revue l'ensemble des transformations
int taille = tab_tcr.Taille();
int dima = ParaGlob::Dimension();
#ifdef MISE_AU_POINT
if (list_coor_centre_noeud.size() != lis_centre_noeud.size())
{ cout << "\n erreur : le nombre de centre noeud disponible "
<< list_coor_centre_noeud.size() << " est inferieur au nombre defini par la condition"
<< " lineaire qui est " << lis_centre_noeud.size() << endl;
Sortie(1);
};
#endif
list <Coordonnee>::const_iterator icoor_centre = list_coor_centre_noeud.begin();
Coordonnee centre(dima); // par défaut le centre
for (int it=1; it<= taille; it++)
{ switch (tab_indic(it))
{ case 1: // cas d'une translation
{ M += coef * tab_tcr(it) ;
break;
}
case 2: // cas d'une nouvelle définition du centre
{ centre += tab_tcr(it);
break;
}
case 3: // cas d'une rotation
{ switch (dima)
{case 1: break; // on ne fait rien
case 2: // on tourne autour de z
{ double theta = coef * tab_tcr(it)(3);
double costheta = cos(theta);
double sintheta = sin(theta);
// le point initial : M , le centre de rotation C
// le point final : Mnew = rotation de CM + les coordonnées du centre
Coordonnee CM(M-centre); // création de CM
M(1)=CM(1)*costheta + CM(2)*sintheta + centre(1);
M(2)=-CM(1)*sintheta + CM(2)*costheta + centre(2);
break;
}
case 3: // on a trois rotation qui sont successivement suivant x puis y puis z
{ Coordonnee rot = coef * tab_tcr(it); // pour simplifier
// le point initial : M , le centre de rotation C
// le point final : Mnew = rotation de CM + les coordonnées du centre
for (int i=1;i<=3;i++) // on boucle sur les trois directions
// une rotation autour de xi si l'angle est non nulle
if (!(Dabs(rot(i)) <= ConstMath::trespetit))
{ // on définit 3 index fonctions du i
int ix=1; int iy=2; int iz=3;
switch (i) // uniquement pour 2 et 3, le cas 1 étant celui de l'initialisation
// précédente
{ case 2: ix = 2; iy = 1; iz = 3; break;
case 3: ix = 3; iy = 1; iz = 2; break;
};
Coordonnee CM(M-centre); // création de CM
// double rayon0 = CM.Norme();
double theta = rot(i);
double costheta = cos(theta);
double sintheta = sin(theta);
// transformation
M(iy)=CM(iy)*costheta + CM(iz)*sintheta + centre(iy);
M(iz)=-CM(iy)*sintheta + CM(iz)*costheta + centre(iz);
M(ix)=CM(ix) + centre(ix);
// CM = M-centre;
// double rayon1 = CM.Norme();
// if (Dabs(rayon1-rayon0)>= ConstMath::pasmalpetit)
// cout << "\n rayon1= " << rayon1 << " rayon0= " << rayon0;
};
break;
}
}; //-- fin du case sur la dimension: switch (dima)
break;
} // fin du cas 3
case 4: // cas d'un centre définie par une position de noeud
{ centre = (*icoor_centre);
break;
}
case 5: // on fait une homothétie
{ // on se sert du centre pour le centre de l'homothétie
Coordonnee scale = coef * tab_tcr(it); // pour simplifier
Coordonnee CM(M-centre); // création de CM
switch (dima)
{case 3: M(3) = centre(3) + CM(3) * scale(3);
case 2: M(2) = centre(2) + CM(2) * scale(2);
case 1: M(1) = centre(1) + CM(1) * scale(1);
};
break;
}
}; // fin du switch: switch (tab_indic)
}; // fin de la boucle sur tab_indic : for (int it=1; it<= taille; it++)
// retour du point transformé
return M;
};
// affichage et definition interactive des commandes
void MvtSolide::Info_commande_MvtSolide(ostream & sort)
{ // ---------- définition de rotations et translation solide ----------
//On va proposer un menu
string rep=" ";
sort << " mouvement_solide_ ";
while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
{
try
{
cout
<< "\n (0 ou f) (fin) "
<< "\n (1) translation "
<< "\n (2) rotation "
<< "\n (3) nouveau centre absolu "
<< "\n (4) centre avec un noeud "
<< "\n (5) homothetie "
<< "\n (6 ou ? ) informations "
<< "\n ";
rep = lect_return_defaut(false,"f");
if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie directe
break;
int num = ChangeEntier(rep);
if (Minuscules(rep) == "?")
num = 6;
bool choix_valide=false;
if ((num >= 0)&&(num<=6))
{ choix_valide=true; }
else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
<< "\n redonnez une bonne valeur"
<< "\n ou taper f ou 0 pour arreter le programme";
choix_valide=false;
}
switch (num)
{ case 0: // sortie
{ break;} // normalement cela a déjà été filtré avant
case 1: // translation
{ int dim = ParaGlob::Dimension();
Coordonnee trans(dim);
cout << "\n lecture du vecteur deplacement ("<<dim<<" reels) ? ";
trans.Lecture();
sort << "\n translation_= ";
trans.Affiche(sort,dim);
break;
}
case 2: // rotation
{ int dim = 3; // la dimension est systématiquement 3 ParaGlob::Dimension();
Coordonnee trans(dim);
cout << "\n rotation en radian par defaut, \n voulez vous des degres (rep o ou n) ";
string rop = lect_return_defaut(true,"n");
bool deg = false;
if (rop == "o") deg = true;
// on sépare en fonction de la dimension de l'espace
switch (ParaGlob::Dimension())
{ case 1: {cout << "\n pas de rotation possible en dimension 1 ! "; break;}
case 2: // la rotation est uniquement autour de z
{ cout << "\n lecture de l'angle de rotation autour de z: 1 reels) ? ";
trans(3)=lect_double();
break;
}
case 3:
{cout << "\n lecture du vecteur rotation ("<<dim<<" reels) ? ";
trans.Lecture();
sort << "\n rotation_= ";
trans.Affiche(sort,dim);
break;
}
default: break; // a priori il n'y a pas d'autre cas
};
// affichage
sort << "\n rotation_= ";
trans.Affiche(sort,dim);
if (deg)
sort << " en_degre_ ";
break;
}
case 3: // nouveau centre absolu
{ int dim = ParaGlob::Dimension();
Coordonnee trans(dim);
cout << "\n lecture du nouveau centre absolu ("<<dim<<" reels) ? ";
trans.Lecture();
sort << "\n centre_= ";
trans.Affiche(sort,dim);
break;
}
case 4: // centre avec un noeud
{ cout << "\n lecture du nouveau noeud centre (un numero de noeud) ? ";
int num_noeud=0;
num_noeud=(int)lect_double();
cout << "\n un nom de maillage (si aucune rep: \"_\" ) ? ";
string nom_mail="_";
nom_mail=lect_chaine();
sort << "\n centre_noeud_= ";
if (nom_mail != "_")
sort << " nom_mail= "<< nom_mail<< " ";
sort << num_noeud << " ";
break;
}
case 5: // homothétie
{ int dim = ParaGlob::Dimension();
Coordonnee scale(dim);
cout << "\n lecture du vecteur homothetie ("<<dim<<" reels) ? ";
scale.Lecture();
sort << "\n homothetie_= ";
scale.Affiche(sort,dim);
break;
}
case 6: // information
{ cout << "\n informations sur les mouvements solides";
cout << "\n# --- definition optionnelle de mouvements sodides appliquees au solide ---"
<< "\n mouvement_solide_ # mot cle pour definir le debut des mouvements solides "
<< "\n translation_= 1. 0. 0. # exemple d'une translation sur x "
<< "\n rotation_= 0.1 0. 0.3 # rotation selon x de 0.1 radian, puis selon z (selon y nulle) "
<< "\n rotation_= 0.1 0. 0.3 en_degre_ # idem mais en degre "
<< "\n centre_= 0.1 0.1 0.2 # def d'un nouveau centre de rotation pour les rotations a suivre "
<< "\n centre_noeud_= 3 # idem mais ici le centre de rotation sera le noeud 3 "
<< "\n centre_noeud_= nom_mail= trap 3 # idem avec un nom de maillage (trap) "
<< "\n homothetie_= 0.8 1. 1.1 # dilatation -20% sur x, rien sur y, +10% en z "
<< "\n fin_mouvement_solide_ # mot de fin de mouvement solide \n\n"
<< "\n# -- il est possible d'enchainer plusieurs mouvements solides a suivre qui sont dans ce cas execute dans le"
<< "\n# le meme ordre que la declaration\n"
<< "\n# -- concernant les rotations: "
<< "\n# si l'espace est 1D ==> aucune modification du maillage "
<< "\n# si l'espace est 2D ==> la rotation prise en compte est uniquement autour de z "
<< "\n# si l'espace est 3D ==> rotation (si l'angle est non nulle) suivant x puis suivant y puis suivant z ";
break;
}
default:
cout << "\n le cas "<<rep<<" n'est pas traite !!, bizarre, il faut se plaindre !! ";
};
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
throw (toto);
}
catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
{ cout << "\n Erreur on attendait un des mots cles proposes !!, "
<< "\n redonnez une bonne valeur"
<< "\n ou taper f ou 0 pour sortir ";
};
}; //-- fin du while
sort << "\n fin_mouvement_solide_ ";
};
// effacement du mouvement solide actuel
void MvtSolide::EffaceMvtSolide()
{ tab_tcr.Libere(); tab_indic.Libere();
lis_centre_noeud.erase(lis_centre_noeud.begin(),lis_centre_noeud.end());
list_coor_centre_noeud.erase(list_coor_centre_noeud.begin(),list_coor_centre_noeud.end());
};
// surcharge de l'operateur de lecture typée
istream & operator >> (istream & entree, MvtSolide & mvt)
{ // vérification du type
int taille = 0;
string type;
entree >> type;
if (type != "MvtSolide_")
{ cout << "\n erreur en lecture d'un mouvement solide, on a lue " << type
<< " au lieu de MvtSolide_ ";
Sortie(1);
};
// lecture de la taille, on se sert de type pour passer la chaine Taille:
entree >> type >> taille;
mvt.tab_tcr.Change_taille(taille);
mvt.tab_indic.Change_taille(taille);
for (int it=1; it<= taille; it++)
{ entree >> mvt.tab_indic(it) >> mvt.tab_tcr(it);};
return entree;
};
// surcharge de l'operateur d'ecriture typée
ostream & operator << ( ostream & sort,const MvtSolide & mvt)
{ // tout d'abord un indicateur donnant le type
int taille = mvt.tab_tcr.Taille();
sort << " MvtSolide_ taille: " << taille ;
for (int it=1; it<= taille; it++)
{ sort << " " << mvt.tab_indic(it) << " " << mvt.tab_tcr(it) << " ";};
return sort;
};