// 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/>.

/************************************************************************
 *     DATE:        23/01/97                                            *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:   Classe generique des elements frontieres.                 *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
#ifndef ELFRONTIERE_H
#define ELFRONTIERE_H

#include "Tableau_T.h"
#include "Noeud.h"
#include "string.h"
// #include "bool.h"
#include "DdlElement.h"
#include "Plan.h"
#include "ElemGeomC0.h"
#include "Met_abstraite.h"
#include "Enum_type_geom.h"
#include "Enum_dure.h"

/** @defgroup Les_Elements_de_frontiere
*
*     BUT:   groupe concernant les éléments géométriques définissant les frontières 1D, 2D, 3D
*
* \author    Gérard Rio
* \version   1.0
* \date       23/01/97
* \brief       groupe concernant les éléments géométriques définissant les frontières 1D, 2D, 3D
*
*/

         
/// @addtogroup Les_Elements_de_frontiere
///  @{
///


class ElFrontiere
{
  public :
    // CONSTRUCTEURS :
    // par defaut
    ElFrontiere ();
    // fonction du tableau des noeuds sommet, des ddlElements
    ElFrontiere (const Tableau <Noeud *>& tab,const DdlElement& ddlElem);
    // nbnoeud permet de faire les verifications de tailles de tableau en debug
    // par les classe derivees
    ElFrontiere (const Tableau <Noeud *>& tab,const DdlElement& ddlElem,int nbnoeud);
    ElFrontiere(const ElFrontiere& a);  // de copie
    // DESTRUCTEUR : défini dans les classes dérivées
    virtual ~ElFrontiere () ;
    
    // METHODES PUBLIQUES :
    // surcharge de l'affectation
    virtual ElFrontiere& operator = (const ElFrontiere& a);
    // retourne le type de l'element frontiere
    virtual string TypeFrontiere() const  = 0;
    // retourne le type de géométrie de l'élément frontière: POINT_G, LIGNE ou SURFACE
    Enum_type_geom Type_geom_front() const
       {return Type_geom_generique(ElementGeometrique().TypeGeometrie());};
    // retourne l'élément géométrique attaché à l'élément frontière
    virtual  ElemGeomC0  & ElementGeometrique() const = 0;
    // surcharge des tests
    // ========================================================================
    //      IMPORTANT !!!
    // le test d'egalite ne concerne que les noeuds , pas
    // les donnees particulieres des elements derivees, qui en faites sont
    // sujet a variation, donc pas discriminant¨
    // ========================================================================
    virtual bool operator == (const ElFrontiere& a) const;
    bool operator != (const ElFrontiere& a) const 
      { if (*this == a) return false; else return true; };
      
    // test de relation d'ordre : on utilise uniquement
    // les numéros de noeuds et de maillage
    // l'idée est d'avoir un moyen de classer les frontières entres elles
    // pour ensuite par exemple, pouvoir classer des listes de frontières
    inline bool operator < (const ElFrontiere& a) const;
      
    // retourne le tableau de noeud en lecture seulement
    inline const Tableau <Noeud *>& TabNoeud_const() const  { return tabNoeud;} ;
    // retourne le tableau de noeud en lecture lecture/écriture
    inline Tableau <Noeud *>& TabNoeud()   { return tabNoeud;} ;
    // retourne les ddl elements en lecture / écriture
    inline DdlElement& DdlElem()  { return ddlElem;} ;
    // retourne les ddl elements en lecture seulement
    inline const DdlElement& DdlElem_const() const  { return ddlElem;} ;
    // retourne le tableau d'element frontiere en lecture / écriture
    inline Tableau <ElFrontiere*>& TabFront() { return tabfront;};
    // retourne le tableau d'element frontiere en lecture uniquement
    inline const Tableau <ElFrontiere*>& TabFront_const() const { return tabfront;};
    // creation d'un nouvelle element frontiere identique
    virtual ElFrontiere * NevezElemFront() const = 0; 
    // creation d'un nouvelle element frontiere de meme type mais
    // avec des donnees differentes
    virtual ElFrontiere * NevezElemFront
       ( const Tableau <Noeud *>& tab, const DdlElement& ddlElem) const  = 0; 
    // cree et retourne un element frontiere ayant une orientation opposee
    virtual ElFrontiere * Oppose() const; 
    
    // ramene et calcul les coordonnees du point de reference de l'element
    virtual Coordonnee Ref()   = 0;
    // calcul éventuel de la normale à un noeud
    // ce calcul existe pour les éléments 2D, 1D axi, et aussi pour les éléments 1D
    // qui possède un repère d'orientation
    // en retour coor = la normale si coor.Dimension() est = à la dimension de l'espace
    // si le calcul n'existe pas -->  coor.Dimension() = 0
    // ramène un entier :
    //    == 1 : calcul normal
    //    == 0 : problème de calcul -> coor.Dimension() = 0
    //    == 2 : indique que le calcul n'est pas licite pour le noeud passé en paramètre
    //           mais il n'y a pas d'erreur, c'est seulement que l'élément n'est pas ad hoc pour
    //           calculer la normale à ce noeud là
    // temps: indique  à quel moment on veut le calcul
    int CalculNormale_noeud(Enum_dure temps,const Noeud& noe,Coordonnee& coor);

    // ramene un plan tangent ou une droite tangente au point de reference
    // si indic = 1 -> une droite, =2 -> un plan
    // ces infos sont stocke et sauvegardees dans l'element de frontiere
    virtual void TangentRef(Droite& dr, Plan& pl, int& indic) = 0;
    // M est un point appartenant au  dernier plan tangent,  sauvegarde dans l'element frontiere
    //  - calcul du point M1 correspondant sur la surface, M1 est stocke
    //  _ calcul et retour du plan tangent (ou une droite tangente) au point M1
    // si indic = 1 -> une droite, =2 -> un plan
    // ces infos sont stocke et sauvegardees dans l'element de frontiere
    virtual void Tangent(const Coordonnee& M,Coordonnee& M1, Droite& dr, Plan& pl, int& indic) = 0;
    // ramene un autre plan tangent ou une droite tangente genere de maniere pseudo aleatoire
    // si indic = 1 -> une droite, =2 -> un plan
    // ces infos sont stocke et sauvegardees dans l'element de frontiere
    virtual void AutreTangent(Droite& dr, Plan& pl, int& indic) = 0;
    // ramene true si le dernier point M1 est dans l'element , sinon false
    // le calcul est fait à eps relatif près
    virtual bool InSurf(const double& eps) const  = 0;
    // actualise , puis ramene le dernier plan tangent (ou  droite tangente) calcule
    // dans le cas 1D, ramene un point
    // en sortie : si indic =0 -> un point, indic = 1 -> une droite, indic = 2 -> un plan
    // ramène éventuellement la variation du vecteur normale pour un plan en 3D ou une ligne en 2D
	   // dans le cas d'une ligne en 3D ramène la variation du vecteur tangent: si var_normale = true, sinon ramène NULL
    virtual Tableau <Coordonnee >*  DernierTangent(Droite& dr, Plan& pl, int& indic,bool avec_var=false) = 0;	 
    // affichage des infos de l'elements frontiere
    virtual void Affiche(Enum_dure temp = TEMPS_tdt)  const = 0;
    // test si la position d'un point est du bon cote ( c-a-d hors matiere) ou non
    // si le point est sur la surface, ramène false
    // ramene true si hors matiere, sinon false
    // le test  sur a est executer uniquement dans les cas suivants :
    // dimension 3D et  frontiere 2D
    // dimension 3D axi et frontière 1D
    // dimension 2D et frontiere 1D
    // ->>> dimension 3D et frontiere 1D, pas de verif
    // ->>> autre cas ne doivent pas arriver normalement !!
    // retour de r = distance du point à la surface, ligne 
    virtual bool BonCote_t( const Coordonnee& a,double& r) const  = 0; // cas ou on utilise la frontiere a t
    virtual bool BonCote_tdt( const Coordonnee& a,double& r)  const = 0; // cas ou on utilise la frontiere a tdt
    // calcul les fonctions d'interpolation au dernier point de projection sauvegarde
    virtual const Vecteur& Phi() = 0;
    
    // creation et ramene des pointeurs sur les frontieres de l'element frontiere
    // au premier appel il y a construction, ensuite on ne fait que ramener le tableau
    // à moins qu'il soit effacé
    virtual Tableau <ElFrontiere*>& Frontiere() = 0;
    // effacement de la place memoire des frontieres de l'element frontiere
    virtual void EffaceFrontiere();
    
    // ramène la métrique associée à l'élément
    virtual Met_abstraite * Metrique() =0;
	   // cas d'un élément frontière surface:
    // ramène une surface approximative de l'élément (toujours > 0) : calculée à l'aide
    // d'une triangulation, puis des produits vectoriels
    // ramène une valeur nulle, s'il n'y a pas de surface
    double SurfaceApprox();
    // cas d'un élément frontière ligne:
    // ramène, une longueur approximative de l'élément (toujours > 0) : calculée à l'aide
    // de la ligne représentée par une suite de segments rejoignants les noeuds 
    // ramène une valeur nulle, s'il n'y a pas de ligne 
    virtual double LongueurApprox() { return 0; };
    // ramène la distance maxi entre deux noeuds de l'élément à tdt
    double MaxDiagonale_tdt();
    
    // ramène l'encombrement de l'élément sous forme du point ayant les coordonnées mini
    // et le point ayant les coordonnées les maxi
    const Coordonnee& Encom_mini() {return encomb_min;};
    const Coordonnee& Encom_maxi() {return encomb_max;};
    // met à jour la boite d'encombrement 
    void AjourBoiteEncombrement();
 
    // calcul de la projection normale d'un point sur la frontière
    // ramène true si la projection est effective, si elle est hors de l'élément
    // ramène false
    // P : retour du point projeté (s'il existe)
    bool Projection_normale(const Coordonnee& M, Coordonnee& P);
	 
    //----- lecture écriture de restart -----
    // ceci concerne uniquement les informations de la classe générique
    void Lecture_base_info_ElFrontiere(istream& ent);
    void Ecriture_base_info_ElFrontiere(ostream& sort);
    // ceci concerne uniquement les informations spécifiques des classes dérivées
    // dans le cas de l'utilisation de la frontière pour la projection d'un point sur la frontière
    // il s'agit donc d'un cas particulier 
    virtual void Lecture_base_info_ElFrontiere_pour_projection(istream& ent) = 0;
    virtual void Ecriture_base_info_ElFrontiere_pour_projection(ostream& sort) = 0;
 
  protected :  
    // VARIABLES PROTEGEES :
    Tableau <Noeud *> tabNoeud; // le tableau de noeud associe a l'element frontiere
    DdlElement ddlElem; // les ddl specifiques aux noeuds de l'element frontiere
    Tableau <ElFrontiere*> tabfront; // frontiere de l'element frontiere
    Coordonnee  encomb_min,encomb_max; // boite d'encombrement des noeuds de l'élément 
    
    static unsigned int nrand ; // pour la generation de nombre aleatoire
    
    // METHODES PROTEGEES :
    // test si le point passé en argument appartient à la boite d'encombrement de la frontière
    // fonction interne pour faciliter les tests, mais c'est celle de Front qui est a utiliser
    bool In_boite_emcombrement(const Coordonnee& M) const;

 };
 /// @}  // end of group

#endif