249 lines
10 KiB
C++
249 lines
10 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-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 <https://www.gnu.org/licenses/>.
|
||
|
//
|
||
|
// For more information, please consult: <https://herezh.irdl.fr/>.
|
||
|
|
||
|
//#include "Debug.h"
|
||
|
|
||
|
#include "GeomPentaCom.h"
|
||
|
#include <math.h>
|
||
|
#include "GeomSeg.h"
|
||
|
#include "GeomQuadrangle.h"
|
||
|
#include "GeomTriangle.h"
|
||
|
#include "MathUtil.h"
|
||
|
|
||
|
// constructeur
|
||
|
// le constructeur par défaut ne doit pas être utilisé
|
||
|
GeomPentaCom::GeomPentaCom()
|
||
|
{ cout << "\n erreur le constructeur par defaut ne doit pas être utilise " ;
|
||
|
cout << "\nGeomPentaCom::GeomPentaCom() " << endl;
|
||
|
Sortie(1);
|
||
|
};
|
||
|
|
||
|
// la dimension est 3, on a nbi pt d'integration, nbn noeuds et 5 faces, 9 aretes
|
||
|
GeomPentaCom::GeomPentaCom(int nbi , int nbn, Enum_interpol interpol) :
|
||
|
ElemGeomC0(3,nbi,nbn,5,9,PENTAEDRE,interpol)
|
||
|
{
|
||
|
// coordonnees des points d'integration
|
||
|
// ceux-ci sont obtenues par assemblage des points de surface et ceux d'épaisseur
|
||
|
int nbil,nbis;
|
||
|
switch (nbi)
|
||
|
{ case 1 : nbil = 1; nbis = 1; break;
|
||
|
case 2 : nbil = 2; nbis = 1; break;
|
||
|
case 3 : nbil = 3; nbis = 1; break;
|
||
|
case 6 : nbil = 2; nbis = 3; break;
|
||
|
case 8 : nbil = 2; nbis = 4; break;
|
||
|
case 9 : nbil = 3; nbis = 3; break;
|
||
|
case 12 : nbil = 3; nbis = 4; break;
|
||
|
case 18 : nbil = 3; nbis = 6; break;
|
||
|
default :
|
||
|
{cout << "\n erreur le pentaedre de nombre de point d'integration = " << nbi
|
||
|
<< "\n n\'est pas implante !! ";
|
||
|
cout << "\nGeomPentaCom::GeomPentaCom(int nbi) " << endl;
|
||
|
Sortie(1);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// un segment de base avec deux noeuds
|
||
|
GeomSeg segbase(nbil,2);
|
||
|
// un triangle de base avec 3 noeuds
|
||
|
// dans le cas de 3 pt d'integ de surface, on choisit des pt d'integ près des noeuds
|
||
|
// et non au milieu des arrêtes d'où nbis_tri pour ce choix
|
||
|
int nbis_tri(nbis); if (nbis == 3) nbis_tri = 1000+nbis;
|
||
|
GeomTriangle triabase(nbis_tri,3);
|
||
|
// on reconstitue les coordonnées en trois dimension
|
||
|
// et on calcul les poids d'intégration
|
||
|
int npi=1;
|
||
|
for (int niil=1;niil<=nbil;niil++)
|
||
|
for (int nis=1;nis<=nbis;nis++,npi++)
|
||
|
{ ptInteg(npi) = Coordonnee
|
||
|
((triabase.CoorPtInteg(nis))(1)
|
||
|
,(triabase.CoorPtInteg(nis))(2)
|
||
|
,(segbase.CoorPtInteg(niil))(1));
|
||
|
// les poids d'integration sont obtenus par produit de ceux de surface
|
||
|
// et ceux de hauteur
|
||
|
WI(npi)=triabase.Wi(nis) * segbase.Wi(niil);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// destructeur
|
||
|
GeomPentaCom::~GeomPentaCom()
|
||
|
{
|
||
|
};
|
||
|
// constructeur de copie
|
||
|
GeomPentaCom::GeomPentaCom(const GeomPentaCom& a) :
|
||
|
ElemGeomC0(a)
|
||
|
{
|
||
|
};
|
||
|
|
||
|
// en fonction de coordonnees locales, retourne true si le point est a l'interieur
|
||
|
// de l'element, false sinon
|
||
|
bool GeomPentaCom::Interieur(const Coordonnee& M)
|
||
|
{ if ((seg(1)->Interieur(M(3))) &&(face(1)->Interieur(Coordonnee(M(1),M(2)))))
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
// en fonction de coordonnees locales, retourne le point local P, maximum intérieur à l'élément, donc sur la frontière
|
||
|
// dont les coordonnées sont sur la droite GM: c-a-d GP = alpha GM, avec apha maxi et P appartenant à la frontière
|
||
|
// de l'élément, G étant le centre de gravité, sauf si GM est nul, dans ce cas retour de M
|
||
|
Coordonnee GeomPentaCom::Maxi_Coor_dans_directionGM(const Coordonnee& M)
|
||
|
{ // on décompose la recherche en segment et facette
|
||
|
double x=M(1); double y=M(2); double z=M(3);
|
||
|
// tout d'abord on calcul le point maxi dans le plan 1 2 et dans z indépendemment
|
||
|
Coordonnee XY(x,y); Coordonnee Z(z);
|
||
|
Coordonnee Pxy= face(1)->Maxi_Coor_dans_directionGM(XY);
|
||
|
Coordonnee Pz = seg(1)->Maxi_Coor_dans_directionGM(Z);
|
||
|
Coordonnee P(0.,0.,0.); // le retour
|
||
|
|
||
|
// G le centre de gravité: il a la cote nulle et il est centre de gravité du triangle médian
|
||
|
double untiers = 1./3.;
|
||
|
Coordonnee G(untiers,untiers,0.);
|
||
|
Coordonnee Gxy(untiers,untiers); // en 2D xy
|
||
|
|
||
|
// le pb est de savoir si on sort sur une des faces triangulaires, ou sur une des faces rectangulaires
|
||
|
// Si le point maxi P sort par une face quadrangulaire, cela signifie que z_P est compris entre 1 et -1
|
||
|
// --- on va donc commencer par calculer le z_P
|
||
|
// on considère les points: G (z_G=0), Pxy dont la côte est également nulle, M, et z_P ?
|
||
|
// soit un plan vertical (normale à Oxy) passant par G,M,Pxy. Il passe également par P. On note Mxy la projection
|
||
|
// de M sur le plan Oxy. Dans le plan verticale on peut faire une régle de trois:
|
||
|
// on a z_P/z_M = GPxy/GMxy d'où z_P = z_M * (GPxy/GMxy)
|
||
|
// NB: si ||GMxy|| = 0, là c'est sur ça ne sort pas par un quadrangle
|
||
|
|
||
|
|
||
|
// 1)-----
|
||
|
Coordonnee GMxy(x-untiers,y-untiers); // en 2D xy
|
||
|
int fin_traitement = false; // par défaut
|
||
|
double gmxy = GMxy.Norme();
|
||
|
if (gmxy > ConstMath::trespetit)
|
||
|
{ double z_P = z * ( (Pxy-Gxy).Norme()) / gmxy;
|
||
|
if (Abs(z_P) <= 1.) // là c'est ok on sort par un rectangle
|
||
|
{P(1)=Pxy(1); P(2)=Pxy(2); P(3)=z_P;
|
||
|
fin_traitement = true;// pour indiquer que c'est ok
|
||
|
};
|
||
|
};
|
||
|
// 2)----
|
||
|
// dans le cas où fin_traitement est toujours faux, cela signifie que le cas sortie par un quadrangle n'a pas marché
|
||
|
// donc cela signifie que le point P est sur la face sup ou inf. En fait cela dépend de z_M si c'est positif alors
|
||
|
// c'est la face sup donc z_P=1 sinon c'est la face inf donc z_P=-1
|
||
|
// on considère un plan vertical qui passe par G, M et P . On a GMxy/z_M = GPxy/z_P avec z_P connu
|
||
|
// d'où GPxy = z_P * GMxy/z_M = e (en module) d'où \vec{GPxy} = e * \vec{GMxy)/||GMxy|| = z_P / z_M * \vec{GMxy) d'où P
|
||
|
if (! fin_traitement)
|
||
|
{ if (z > ConstMath::trespetit)
|
||
|
{ // cas d'une sortie par la facette supérieure, z_P = 1.
|
||
|
Coordonnee GPxy = GMxy / z;
|
||
|
P(1) = untiers + GPxy(1); P(2) = untiers + GPxy(2); P(3) = 1.;
|
||
|
fin_traitement = true;// pour indiquer que c'est ok
|
||
|
}
|
||
|
else if (z < -ConstMath::trespetit)
|
||
|
{ // cas d'une sortie par la facette inférieure, z_P = -1.
|
||
|
Coordonnee GPxy = (-1./z) * GMxy ;
|
||
|
P(1) = untiers + GPxy(1); P(2) = untiers + GPxy(2); P(3) = -1.;
|
||
|
fin_traitement = true;// pour indiquer que c'est ok
|
||
|
}
|
||
|
else
|
||
|
// arrivée ici, cela veut dire que z est quasiment nulle, et pourtant due au 1)---
|
||
|
// - soit Abs(z_P) est > 1 , ce qui n'est pas possible car on vient de trouver z quasiment nulle
|
||
|
// - soit gmxy est également quasiment nulle : dans ce cas on choisit arbitrairement P(0,0,0)
|
||
|
{ P.Zero();};
|
||
|
};
|
||
|
|
||
|
#ifdef MISE_AU_POINT
|
||
|
if ((P(1) + P(2)) > (1. + ConstMath::petit))
|
||
|
{ cout << "\n petit soucis, le point maxi calcule n'est pas correcte ";
|
||
|
P.Affiche(cout);
|
||
|
cout << "\n GeomPentaCom::Maxi_Coor_dans_directionGM(.." << endl;
|
||
|
};
|
||
|
#endif
|
||
|
/*
|
||
|
|
||
|
// en fait il y a un pb, car la suite à l'air correcte si on cherche l'intersection de OM avec la frontière
|
||
|
// mais ce qu'il nous faut c'est GM avec la frontière, il faut donc quelques modifs !!
|
||
|
cout << "\n ***************** GeomPentaCom::Maxi_Coor_dans_directionGM( a revoir ******" << endl;
|
||
|
|
||
|
if ((Dabs(x) <= ConstMath::petit) && (Dabs(y) <= ConstMath::petit))
|
||
|
{ // cas où x et y transformées sont quasi nulles, il ne reste plus qu'à examiner le cas de z
|
||
|
if (Dabs(z) <= ConstMath::petit)
|
||
|
{ // cas où toutes les coordonnées sont nulles, retour de M
|
||
|
// on met les coordonnées en x, y strictement à 0. pour éviter d'être légèrement à l'extérieur
|
||
|
return Coordonnee (0.,0.,z);
|
||
|
}
|
||
|
else // cas où l'on modifie suivant z (le point est sur le triangle sup ou inf)
|
||
|
{ return Coordonnee (0.,0.,Pz(1));
|
||
|
}
|
||
|
}
|
||
|
else // cas où x ou/et y sont non nulles
|
||
|
{// on calcul de facteur de réduction suivant xy
|
||
|
double facteurxy=0.;
|
||
|
if (Dabs(x) <= ConstMath::petit) // donc y est non nulle
|
||
|
{// cas donc où seule y a peut-être variée
|
||
|
facteurxy = Pxy(2)/y;
|
||
|
}
|
||
|
else if (Dabs(y) <= ConstMath::petit) // donc x est non nulle
|
||
|
{// cas donc où seule x a peut-être variée
|
||
|
facteurxy = Pxy(1)/x;
|
||
|
}
|
||
|
else // cas où x et y sont non nulles
|
||
|
{// cas donc où x et y x ont peut-être variées
|
||
|
facteurxy = MiN(Pxy(1)/x,Pxy(2)/y);
|
||
|
}
|
||
|
// on regarde maintenant du coté de z
|
||
|
if (Dabs(z) <= ConstMath::petit)
|
||
|
{ // z ne participe pas car nulle
|
||
|
return Coordonnee (Pxy(1),Pxy(2),z);
|
||
|
}
|
||
|
else // cas où la modification est possible suivant z
|
||
|
{ double facteurz= Pz(1)/z;
|
||
|
// on prend le plus petit des deux facteurs
|
||
|
if (facteurxy <= facteurz)
|
||
|
{ // c'est le facteur dans le plan qui agit
|
||
|
return Coordonnee (Pxy(1),Pxy(2),facteurxy*z);
|
||
|
}
|
||
|
else
|
||
|
{ // c'est le facteur suivant z qui agit
|
||
|
return Coordonnee (facteurz*x,facteurz*y,Pz(1));
|
||
|
}
|
||
|
}
|
||
|
} //-- fin du cas où x ou/et y sont non nulles
|
||
|
// cas qui ne doit jamais arriver car on se situe forcément dans un des trois secteurs
|
||
|
// précédemment étudiés
|
||
|
cout << "\n erreur inconnue !!"
|
||
|
<< "\n GeomPentaCom::Maxi_Coor_dans_directionGM(..";
|
||
|
Sortie(1); */
|
||
|
return M; // pour éviter un warning
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|