Herezh_dev/contact/Cercle.cc
2023-05-03 17:23:49 +02:00

416 lines
14 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 "Cercle.h"
#include "MathUtil.h"
#include "ParaGlob.h"
// CONSTRUCTEURS :
// par defaut
Cercle::Cercle () :
centre(),rayon(0.),N(NULL)
{ if (ParaGlob::Dimension()== 1)
{ cout << "\nErreur : la dimension est 1 et on veut utiliser un cercle ??? ";
cout << "\nCercle::Cercle ()" << endl;
Sortie(1);
};
};
// avec les datas
Cercle::Cercle ( const Coordonnee& B, const double& r , const Coordonnee* No):
centre(B),rayon(r),N(NULL)
{ if (ParaGlob::Dimension()== 1)
{ cout << "\nErreur : la dimension est 1 et on veut utiliser un cercle ??? ";
cout << "\nCercle::Cercle ()" << endl;
Sortie(1);
};
if (rayon < 0.)
{ cout << "\n erreur dans la construction d'un Cercle, le rayon " << rayon
<< " est negatif !! ";
Sortie(1);
};
if (ParaGlob::Dimension() == 3)
if (No != NULL)
{ N = new Coordonnee(*No);
double norme = N->Norme();
if (norme < ConstMath::petit)
{ cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
<< " a une norme (=" << norme <<") trop petite !! " ;
Sortie(1);
};
(*N) /= norme; // on normalise le vecteur
};
// sinon la normale n'existe pas, il faudra la définir
};
// avec la dimension
Cercle::Cercle (int dim):
centre(dim),rayon(0.),N(NULL)
{ if (ParaGlob::Dimension()== 1)
{ cout << "\nErreur : la dimension est 1 et on veut utiliser un cercle ??? ";
cout << "\nCercle::Cercle ()" << endl;
Sortie(1);
};
};
// de copie
Cercle::Cercle ( const Cercle& a):
centre(a.centre),rayon(a.rayon),N(NULL)
{ if (ParaGlob::Dimension() == 3)
if (a.N != NULL) // a priori il est normé
{ N = new Coordonnee(*(a.N));};
// sinon la normale n'existe pas, il faudra la définir
};
// DESTRUCTEUR :
Cercle::~Cercle ()
{ if (N != NULL)
{delete N;N=NULL;};
};
// surcharge des operator
Cercle& Cercle::operator = ( const Cercle & cer)
{ centre = cer.centre; rayon = cer.rayon;
if (ParaGlob::Dimension() == 3)
if (cer.N != NULL) // a priori la normale est normée
{ N = new Coordonnee(*(cer.N));};
// sinon la normale n'existe pas, il faudra la définir
return *this;
};
// METHODES PUBLIQUES :
// change le centre du Cercle
void Cercle::Change_centre( const Coordonnee& B)
{
#ifdef MISE_AU_POINT
if (B.Dimension() != centre.Dimension())
{ cout << "\nErreur : les dimensions du centre et du vecteur ne sont pas identique !";
cout <<"\ndim B = " <<B.Dimension() <<", dim centre =" << centre.Dimension();
cout << "\nCercle::Change_centre( const Coordonnee& B)" << endl;
Sortie(1);
};
#endif
centre = B;
};
// change le rayon du Cercle
void Cercle::Change_rayon( const double & r)
{if (r < 0.)
{ cout << "\n erreur dans la construction d'un Cercle, le rayon " << r
<< " est negatif !! "
<< "\n Cercle::Change_rayon( const double & r) ";
};
rayon = r;
};
// change la normale au Cercle en 3D, sinon c'est inutile, warning
void Cercle::Change_Normale( const Coordonnee& No)
{ if (ParaGlob::Dimension() != 3)
{ cout << "\nwarning : on n'est pas en 3D, la normale n'est pas utile pour le cercle !";
cout << "\nCercle::Change_Normale( const Coordonnee& No)" << endl;
}
else
{
#ifdef MISE_AU_POINT
if (No.Dimension() != 3)
{ cout << "\nErreur : la dimension de la normale devrait etre 3 alors qu'elle est : "
<< No.Dimension() <<" ";
cout << "\nCercle::Change_Normale( const Coordonnee& No)" << endl;
Sortie(1);
};
#endif
if (N == NULL)
{ N = new Coordonnee (No);}
else
{ *N = No;};
double norme = N->Norme();
if (norme < ConstMath::petit)
{ cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
<< " a une norme (=" << norme <<") trop petite !! " ;
cout << "\nCercle::Change_Normale( const Coordonnee& No)" << endl;
Sortie(1);
};
(*N) /= norme; // on normalise le vecteur
};
};
// change toutes les donnees
void Cercle::change_donnees( const Coordonnee& B, const double& r,const Coordonnee* No)
{
#ifdef MISE_AU_POINT
if (B.Dimension() != centre.Dimension())
{ cout << "\nErreur : les dimensions du centre et du vecteur ne sont pas identique !";
cout <<"\ndim B = " <<B.Dimension() <<", dim centre =" << centre.Dimension();
cout << "\nCercle::change_donnees( const Coordonnee& B, const double& r)" << endl;
Sortie(1);
};
#endif
centre = B;
if (r < 0.)
{ cout << "\n erreur dans la construction d'un Cercle, le rayon " << r
<< " est negatif !! "
<< "\n Cercle::change_donnees( ) ";
};
rayon = r;
// maintenant cas de la normale
if ((ParaGlob::Dimension() != 3) && (No != NULL))
{ cout << "\nwarning : on n'est pas en 3D, la normale n'est pas utile pour le cercle !";
cout << "\nCercle::change_donnees( const Coordonnee& No)" << endl;
}
else if ((ParaGlob::Dimension() == 3) && (No == NULL))
{ cout << "\nwarning : la normale au cercle n'est pas defini !";
cout << "\nCercle::change_donnees()" << endl;
if (N != NULL)
delete N;
}
else if (ParaGlob::Dimension() == 3) // cas de la dimension 3 et No non null
{
#ifdef MISE_AU_POINT
if (No->Dimension() != 3)
{ cout << "\nErreur : la dimension de la normale devrait etre 3 alors qu'elle est : "
<<No->Dimension() <<" ";
cout << "\nCercle::change_donnees()" << endl;
Sortie(1);
};
#endif
if (N == NULL)
{ N = new Coordonnee (*No);}
else
{ *N = *No;};
double norme = N->Norme();
if (norme < ConstMath::petit)
{ cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
<< " a une norme (=" << norme <<") trop petite !! " ;
cout << "\nCercle::change_donnees(.." << endl;
Sortie(1);
};
(*N) /= norme; // on normalise le vecteur
};
};
// calcul les deux intercections M1 et M2 d'une droite avec le Cercle,
// ramene 0 s'il n'y a pas d'intersection, ramene -1 si l'intersection
// ne peut pas etre calculee
// et 1 s'il y a deux points d'intercection
int Cercle::Intersection( const Droite & dr,Coordonnee& M1, Coordonnee& M2)
{switch (ParaGlob::Dimension())
{case 2:
{// C le centre du cercle, H la projection de C sur la droite
// M1 et M2 les deux intersections potentielles
const Coordonnee& A = dr.PointDroite(); // pour simplifier
const Coordonnee& U = dr.VecDroite();
Coordonnee CA = A - centre;
double ah = - CA * U;
Coordonnee CH = CA + ah * U;
double ch_2 = CH * CH;
if (sqrt(ch_2) > rayon)
return 0; // cas pas d'intersection
// sinon
double hm = sqrt(rayon*rayon - ch_2);
M1 = centre + CH + hm * U;
M2 = centre + CH - hm * U;
return 1;
break;
}
case 3:
{
#ifdef MISE_AU_POINT
if (N==NULL)
{ cout << "\nErreur : la normale au cercle n'est pas defini, "
<< " on ne peut pas calculer la distance au cercle ";
cout << "\nCercle::Distance_au_Cercle()" << endl;
Sortie(1);
};
#endif
// on calcul le projeté sur le plan d'un point de la droite
const Coordonnee& A = dr.PointDroite(); // pour simplifier
const Coordonnee& U = dr.VecDroite();
Coordonnee CA = A-centre;
double ha = CA*(*N); // distance du point au plan du cercle
if (ha > ConstMath::pasmalpetit)
return 0; // cas pas d'intersection
// sinon le point appartient au plan: même procédure qu'en 2D
// C le centre du cercle, H la projection de C sur la droite
// M1 et M2 les deux intersections potentielles
double ah = - CA * U;
Coordonnee CH = CA + ah * U;
double ch_2 = CH * CH;
if (sqrt(ch_2) > rayon)
return 0; // cas pas d'intersection
// sinon
double hm = sqrt(rayon*rayon - ch_2);
M1 = centre + CH + hm * U;
M2 = centre + CH - hm * U;
return 1;
break;
}
case 1:
{ cout << "\nErreur : la dimension est 1 et on utilise un cercle ??? ";
cout << "\nCercle::Intersection(.." << endl;
Sortie(1);
};
};
// normalement on n'arrive jamais ici
return -1;
};
// calcul la distance d'un point au Cercle
double Cercle::Distance_au_Cercle(const Coordonnee& M) const
{ switch (ParaGlob::Dimension())
{case 2:
return Dabs((centre - M).Norme()-rayon);break;
case 3:
{
#ifdef MISE_AU_POINT
if (N==NULL)
{ cout << "\nErreur : la normale au cercle n'est pas defini, "
<< " on ne peut pas calculer la distance au cercle ";
cout << "\nCercle::Distance_au_Cercle()" << endl;
Sortie(1);
};
#endif
// on calcul le projeté sur le plan
Coordonnee CM = M-centre;
double cm = (CM*(*N));
Coordonnee CH = CM - cm * (*N);
// calcul du point intersection CH avec le cercle -> E
double ch = CH.Norme();
if (ch < ConstMath::trespetit)
{ // cela veut dire que le point M est sur l'axe du cercle
return (sqrt(cm*cm + rayon*rayon));
}
else
{ Coordonnee CE = CH * (rayon/ch);
return (CM-CE).Norme();
};
break;
}
case 1:
{ cout << "\nErreur : la dimension est 1 et on utilise un cercle ??? ";
cout << "\nCercle::Distance_au_Cercle()" << endl;
Sortie(1);
};
};
// normalement on n'arrive jamais ici
return ConstMath::tresgrand;
};
// calcul du projeté d'un point sur le plan
Coordonnee Cercle::Projete(const Coordonnee& M) const
{ switch (ParaGlob::Dimension())
{case 2: // le projeté est directement M
return M;break;
case 3:
{
#ifdef MISE_AU_POINT
if (N==NULL)
{ cout << "\nErreur : la normale au cercle n'est pas defini, "
<< " on ne peut pas calculer la distance au cercle ";
cout << "\nCercle::Projete(.." << endl;
Sortie(1);
};
#endif
// on calcul le projeté sur le plan
return (M - ((M-centre)* (*N))* (*N));
break;
}
case 1:
{ cout << "\nErreur : la dimension est 1 et on utilise un cercle ??? ";
cout << "\nCercle::Projete(.." << endl;
Sortie(1);
};
};
// normalement on n'arrive jamais ici
Coordonnee toto; // on fait en deux fois pour la version linux
return (toto);
};
// fonction valable uniquement en 2D, sinon erreur
// ramène true si le point est à l'intérieur du cercle, false sinon
bool Cercle::Dedans(const Coordonnee& M)const
{ if (ParaGlob::Dimension() == 2)
{ return ((M-centre).Norme() < rayon);}
else
{ cout << "\n erreur, la fonction Cercle::Dedans(... n'est utilisable "
<< " qu'en dimension 2D, alors que l'on est en " << ParaGlob::Dimension() << " ";
Sortie(1);
return false; // pour éviter un warning
};
};
// surcharge de l'operateur de lecture
istream & operator >> (istream & entree, Cercle & cer)
{ // vérification du type
string nom;
entree >> nom;
#ifdef MISE_AU_POINT
if (nom != "_cercle_")
{ cout << "\nErreur, en lecture d'une instance cercle "
<< " on attendait _cercle_ et on a lue: " << nom ;
cout << "istream & operator >> (istream & entree, Cercle & cer)\n";
Sortie(1);
};
#endif
// puis lecture des différents éléments
entree >> nom >> cer.centre >> nom >> cer.rayon;
bool existe_N;
entree >> existe_N;
if (existe_N)
{ if (cer.N == NULL)
cer.N = new Coordonnee(ParaGlob::Dimension());
entree >> (*(cer.N));
double norme = cer.N->Norme();
if (norme < ConstMath::petit)
{ cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
<< " a une norme (=" << norme <<") trop petite !! " ;
cout << "\nCercle::change_donnees(.." << endl;
Sortie(1);
};
(*cer.N) /= norme; // on normalise le vecteur
}
else
{ if (cer.N != NULL)
delete cer.N;
};
return entree;
};
// surcharge de l'operateur d'ecriture
ostream & operator << ( ostream & sort,const Cercle & cer)
{ // tout d'abord un indicateur donnant le type
sort << " _cercle_ " ;
// puis les différents éléments
sort << "\n C= " << cer.centre << " r= " << cer.rayon << " ";
if (cer.N == NULL)
{ sort << 0 ;}
else
{ sort << 1 << (*(cer.N)) << " " ;}
return sort;
};