// 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-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 . // // For more information, please consult: . #include "MvtSolide.h" #include "ParaGlob.h" #include #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 ::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 list_tcr; // liste des translations, centres et rotation list 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 ::iterator il,ilfin=list_tcr.end(); list ::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 ::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 ::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 ("< 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 "<> (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; };