// 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 "F_union_1D.h"
#include "Sortie.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "CharUtil.h"


    // CONSTRUCTEURS :
F_union_1D::F_union_1D(string nom) :
 Courbe1D(nom,F_UNION_1D),Fi(),Xi(),nom_courbei(),indice_precedant(1)
  {};
    
    // de copie
F_union_1D::F_union_1D(const F_union_1D& Co) :
 Courbe1D(Co),indice_precedant(Co.indice_precedant)
 ,Fi(Co.Fi),Xi(Co.Xi),nom_courbei(Co.nom_courbei)
  { // création des courbes locales que si elles étaient déjà locales
    int tai = Fi.Taille();
    for (int i=1;i<= tai; i++)
      if (Co.Fi(i)->NomCourbe() == "_") 
         {Fi(i)=Courbe1D::New_Courbe1D(*(Co.Fi(i)));}; 
    };
    
    // de copie à partir d'une instance générale
F_union_1D::F_union_1D(const Courbe1D& Coo) :
 Courbe1D(Coo)
  { if (Coo.Type_courbe() != F_UNION_1D)
      { cout << "\n erreur dans le constructeur de copie pour une courbe F_UNION_1D "
             << " a partir d'une instance générale ";
        cout << "\n F_union_1D::F_union_1D(const Courbe1D& Co) ";
           Sortie(1);          
          };
    // définition des données
    F_union_1D & Co = (F_union_1D&) Coo;
    indice_precedant=Co.indice_precedant;
    Fi=Co.Fi;
    Xi=Co.Xi;
    nom_courbei = Co.nom_courbei;
    int tai = Fi.Taille();
    // création des courbes locales que si elles étaient déjà locales
    for (int i=1;i<= tai; i++)
      if (Co.Fi(i)->NomCourbe() == "_") 
         {Fi(i)=Courbe1D::New_Courbe1D(*(Co.Fi(i)));}; 
  };

    // DESTRUCTEUR :
F_union_1D::~F_union_1D() 
  { // on efface les courbes que si c'est des courbes locales
    int tai = Fi.Taille();
    for (int i=1;i<= tai; i++)
      if ((Fi(i) != NULL)&&(nom_courbei(i)=="i_interne_i")) delete Fi(i);
  };
    
    // METHODES PUBLIQUES :
    
    // --------- virtuelles ---------
    
    // affichage de la courbe
void F_union_1D::Affiche() const 
  { cout << "\n courbe composee : F_union_1D : nom_ref= " << nom_ref;
    int tai = Fi.Taille();
    // on parcours toutes les courbes
    for (int i=1;i<= tai; i++)
      { cout << "\n intervalle: [" << Xi(i) <<","<<Xi(i+1)<<"] ";
        // si c'est une courbe interne on l'affiche globalement
        // si c'est une courbe globale, on n'affiche que son nom
        cout << ", fonction de base: " << i << " ";
        if (Fi(i)->NomCourbe() == "_")  {Fi(i)->Affiche();}
        else  {cout << Fi(i)->NomCourbe() << " ";};
      };
    cout << "\n permet_affichage: " << permet_affichage;
    cout << "\n ----- fin fonction F_union_1D ----- ";
   };

    // vérification que tout est ok, pres à l'emploi
    // ramène true si ok, false sinon
bool F_union_1D::Complet_courbe()const
 { bool ret = Complet_var(); // on regarde du coté de la classe mère tout d'abord
   // puis les variables propres, il faut au moins une courbe
   if (Fi.Taille() == 0)
       ret = false;
   if (!ret && (ParaGlob::NiveauImpression() >0))
      { cout << "\n ***** la courbe n'est pas complete (aucune courbe de base n'existe) ";
        this->Affiche();
        };
   return ret;
  } ;

// dans le cas où les courbes membres sont des  courbes externes
// fonction pour les définir
// les courbes sont défini en interne que si les courbes argument sont elles même
// des courbes locales. c'est-à-dire si FFi(i)->NomCourbe() ="_" alors on recrée une courbe
// interne avec new pour Fi(i), sinon Fi(i)=FFi(i) et pas de création; 
// dans le cas où FFi(i) est NULL on passe, pas de traitement pour ce pointeur
void F_union_1D::DefCourbesMembres(Tableau <Courbe1D* >& FFi)
{  // l'objectif est 
   // 1) d'adapter le nombre de courbe à celui de FFi
   // 2) de ne changer que celle qui sont non nul dans FFi
   int tai = Fi.Taille(); // taille existante
   int taii = FFi.Taille(); // taille du nouveau tableau
   // on commence par effacer les courbes existantes supérieur à taii
   if (taii < tai)
     for (int i=taii;i<= tai; i++)
         if ((Fi(i) != NULL)&&(nom_courbei(i)=="i_interne_i")) 
           { delete Fi(i);Fi(i)=NULL;};
   // on change de taille
   Fi.Change_taille(taii);
   tai = taii;
   for (int i=1;i<= tai; i++)   
    { // création d'une courbe locale que si elle était déjà locales
      if (FFi(i) != NULL)
       {if (FFi(i)->NomCourbe() == "_") // cas où FFi(i) est une courbe non globale
           { if (Fi(i)==NULL)
               // cas où la courbe locale n'est pas défini mais on veut une courbe interne
               { Fi(i)=Courbe1D::New_Courbe1D(*(FFi(i)));nom_courbei(i)="i_interne_i";}
             else if (Fi(i)->NomCourbe() == "_")
               // cas où la courbe F1 est local et on veut la remplacer par une nouvelle locale
               { delete Fi(i);
                 Fi(i)=Courbe1D::New_Courbe1D(*(FFi(i)));nom_courbei(i)="i_interne_i";
                }
             else
              // cas où la courbe Fi(i est global et on veut la remplacer par une locale
               { Fi(i)=Courbe1D::New_Courbe1D(*(FFi(i)));nom_courbei(i)="i_interne_i";};
           }
        else // cas ou FFi(i) est une courbe globale
           { if (Fi(i)==NULL)
                // cas où la courbe locale n'est pas défini
                { Fi(i)=FFi(i);nom_courbei(i)="e_externe_e";}
             else if (Fi(i)->NomCourbe() == "_")
          // cas où la courbe Fi(i) est local et on veut la remplacer par une globale
                { delete Fi(i);
                  Fi(i)=FFi(i);nom_courbei(i)="e_externe_e";
                 }
             else
          // cas où la courbe Fi(i) est global et on veut la remplacer par une globale
                { Fi(i)=FFi(i);nom_courbei(i)="e_externe_e";};
           };
       }; 
    };
};

   // Lecture des donnees de la classe sur fichier
    // le nom passé en paramètre est le nom de la courbe
    // s'il est vide c-a-d = "", la methode commence par lire le nom sinon
    // ce nom remplace le nom actuel
void F_union_1D::LectDonnParticulieres_courbes(const string& nom,UtilLecture * entreePrinc)
  { // entête de la courbe
    if (nom == "")  { *(entreePrinc->entree) >> nom_ref;}
    else {nom_ref=nom;};
    // lecture de la  courbe interne
    entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
    // on lit les courbes et les intervalles à suivre jusqu'au mot de fin de courbe
    list < Courbe1D* > li_Fi; // un liste intermédiaire pour faciliter la lecture
    list <double > li_Xi;
    list <string > li_nom_courbei;
    // on commence par lire éventuellement la borne inférieure du domaine de définition
    string toto;
    double xmin=-ConstMath::tresgrand; // par défaut
    if(strstr(entreePrinc->tablcar,"Xmin=")!=0)
      { *(entreePrinc->entree) >> toto >> xmin;
        if (toto != "Xmin=")
         { cout << "\n erreur en lecture de la borne inferieure  "
                << " on attendait la chaine: Xmin= et on a lue: " << toto;
           entreePrinc->MessageBuffer("**erreur F_union_1D::LectureDonneesParticulieres**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          };
      };
    li_Xi.push_back(xmin); // enregistrement  
    // maintenant lecture courante
    string nom_indicateur;
    do
     { // tout d'abord lecture de la courbe
       string toto,nom_lu,nom_courbe;
       Courbe1D*  F=NULL;      
       *(entreePrinc->entree) >> nom_indicateur >> nom_lu; 
       // vérif
       if (nom_indicateur != "courbe=" )   
         { cout << "\n erreur en lecture du nom de courbe  "
                << " on attendait la chaine: courbe= et on a lue: " << nom_indicateur;
           entreePrinc->MessageBuffer("**erreur F_union_1D::LectureDonneesParticulieres**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          };
       // on regarde si la courbe1 existe, si oui on récupère la référence 
       if (Type_EnumCourbe1D_existe(nom_lu)) 
        // cas ou c'est un nom de type de courbe -> lecture directe
        { nom_courbe = "_"; // on signale que c'est une courbe interne
          F = Courbe1D::New_Courbe1D(nom_courbe,Id_Nom_Courbe1D (nom_lu.c_str()));
          // lecture de la courbe
          F->LectDonnParticulieres_courbes (nom_courbe,entreePrinc);
          nom_courbe="i_interne_i";
          entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
         } 
       else
        // sinon on retiend le nom pour une complétion future   
        {nom_courbe = nom_lu;};
        // stockage
       li_Fi.push_back(F); li_nom_courbei.push_back(nom_courbe);
       // lecture maintenant de la fin de l'intervalle
       double xmax=ConstMath::tresgrand; // par défaut
       bool fin_lecture=false;
       if (strstr(entreePrinc->tablcar,"Xmax=")!=0)
        {*(entreePrinc->entree) >> nom_indicateur >> xmax; 
         // vérif
         if (nom_indicateur != "Xmax=" )   
         { cout << "\n erreur en lecture de la borne maxi de l'intervalle  "
                << " on attendait la chaine: Xmax= et on a lue: " << nom_indicateur;
           entreePrinc->MessageBuffer("**erreur F_union_1D::LectureDonneesParticulieres**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          }
        }
       else // sinon ça doit-être la dernière lecture
         {fin_lecture = true;};   
       li_Xi.push_back(xmax); // enregistrement
      
       // on passe une ligne si on n'est pas déjà à la fin et on vérifie que ce n'est pas finie
       if (strstr(entreePrinc->tablcar,"fin_courbe_union")==0)
          entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
       // on regarde s'il n'y a pas un niveau d'affichage particulier
       if (strstr(entreePrinc->tablcar,"permet_affichage_")!=0)
         { int val_defaut = 0;int min=10;int max=0; // min > max -> pas pris en compte
           string nom_class_methode("F_union_1D::LectureDonneesParticulieres");
           string mot_cle("permet_affichage_");
           if (entreePrinc->Lecture_un_parametre_int(val_defaut,nom_class_methode
                              ,min,max,mot_cle,permet_affichage))
              entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
         };
       if (fin_lecture && (strstr(entreePrinc->tablcar,"fin_courbe_union")==0))
         { cout << "\n erreur en lecture de la borne maxi de l'intervalle  "
                << " le mot cle Xmax= est obligatoire sauf pour la derniere fonction ";
           entreePrinc->MessageBuffer("**erreur F_union_1D::LectureDonneesParticulieres**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
         };
     } while (strstr(entreePrinc->tablcar,"fin_courbe_union")==0);
   
    // on met en tableau
    int tai = li_Fi.size();
    Fi.Change_taille(tai);
    Xi.Change_taille(tai+1);
    nom_courbei.Change_taille(tai);
    
    list < Courbe1D* >::iterator ili,ilifin= li_Fi.end();
    list <double >::iterator xli= li_Xi.begin();
    Xi(1)=*xli;xli++; //la borne inférieure
    list <string >::iterator sli= li_nom_courbei.begin();
    int ia=1;
    for (ili=li_Fi.begin();ili!=ilifin;ili++,xli++,sli++,ia++)
      {Fi(ia)=*ili;Xi(ia+1)=*xli;nom_courbei(ia)=*sli;}
   };

// 1) renseigne si la courbe dépend d'autre courbe ou non
bool F_union_1D::DependAutreCourbes() const
 { bool ret=false;
   int tai = Fi.Taille();
   for (int i=1;i<=tai;i++)
     if(Fi(i) == NULL) {ret=true;}
     else if (nom_courbei(i)!="i_interne_i") {ret=true;};
   return ret;
  };
  
// 2) retourne une liste de nom correspondant aux noms de courbes dont dépend *this
list <string>& F_union_1D::ListDependanceCourbes(list <string>& lico) const
 { // tout d'abord on vide la liste passée en paramètres
   if (lico.size() != 0) lico.erase(lico.begin(),lico.end());
   // on remplit en fonction de l'état
   int tai = Fi.Taille();
   for (int i=1;i<=tai;i++)
     if(Fi(i) == NULL)  lico.push_back(nom_courbei(i));
   return lico;
  };
   
// 3) établit la connection entre la demande de *this et les courbes passées en paramètres
void F_union_1D::Lien_entre_courbe (list <Courbe1D *>&  liptco)
 { int tai = Fi.Taille();
   Tableau <Courbe1D *> tab_Fi(tai); // def à null par défaut
   for (int i=1;i<=tai;i++)
     if(Fi(i) == NULL)  
     	{list <Courbe1D *>::iterator ili,ilifin=liptco.end();
         for (ili=liptco.begin();ili!=ilifin;ili++)
           if ((*ili)->NomCourbe() == nom_courbei(i)) 
             {tab_Fi(i)=(*ili);break;};
     	}
      else // sinon la courbe existe déjà, on met le pointeur à Null
       tab_Fi(i)=NULL;  	
   // et on définit les courbes
   this->DefCourbesMembres(tab_Fi);  
  };
    
// def info fichier de commande
void F_union_1D::Info_commande_Courbes1D(UtilLecture & entreePrinc) 
  {  
     ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
     sort << "\n#............................................"
          << "\n#   il s'agit d'une fonction qui agglomere plusieurs fonctions deja existantes"
          << "\n#   chaque fonction est defini sur un intervalle disjoint des autres "
          << "\n#   Les intervalles doivent se suivre "
          << "\n#   Xmin= precise la borne inferieur de definition de la fonction"
          << "\n#         c'est un parametre facultatif, s'il manque, la borne inf est - l'infini"
          << "\n#   ensuite il y a une liste de courbes: "
          << "\n#           suivi chacune de la fin de l'intervalle correspondant"
          << "\n#   ici cf1 est pour x appartenant a [-10,0[, cf2 est pour x appartenant a [0,10["
          << "\n#       cf3 est pour x appartenant a [10,20["
          << "\n    courbe_exemple    F_UNION_1D  "
          << "\n#     Xmin= -10  courbe= cf1 Xmax= 0"
          << "\n#                courbe= cf2 Xmax= 10"
          << "\n#                courbe= cf3 Xmax= 20"
          << "\n#     fin_courbe_union"
          << "\n#   "
          << "\n#   pour la dernier courbe il est possible de ne pas faire figurer Xmax=, dans"
          << "\n#   ce cas, cela signifie que la borne finale est l'infini"
          << "\n#   enfin, si la valeur de x est en dehors de l'intervalle, on applique la premiere"
          << "\n    (x<Xmin) ou la derniere fonction (x>Xmax)   "
          << endl;
   };
        
    // ramène la valeur 
double F_union_1D::Valeur(double x)  
  { // on commence par chercher l'intervalle qui contient x
    //tout d'abord on regarde s'il est en dehors des bornes
    // si oui on lui donne 
    if (x < Xi(1)) 
       {indice_precedant=1;
        return Fi(1)->Valeur(x);
       };
    int tai = Fi.Taille();
    int taiPlusUn = tai + 1;
    if (x > Xi(taiPlusUn))
       {indice_precedant=1; // comme c'est le dernier intervalle on met à 1 car 
        // de toute manière cela ne sert à rien de continuer
        return Fi(tai)->Valeur(x);
       };
    // maintenant on cherche le couple de xi qui encadre le x
    int indice=0;bool trouve=false;
    // on commence tout d'abord à chercher à partir du précédent indice
    // s'il est supérieur au xi de l'indice existant, l'algo qui suit est ok
    if (x >= Xi(indice_precedant))
      {for (int indic=indice_precedant;indic < taiPlusUn;indic++)
         if (x < Xi(indic+1)) {trouve=true;indice=indic; break;};
      }
    else // sinon il est inférieur
      {for (int indic = 1; indic <indice_precedant;indic++)
         if (x < Xi(indic+1)) {trouve=true;indice = indic; break;};
      };
//
//
//    // sinon cela veut dire qu'il se trouve dans les xi plus bas que l'indice
//    // on repart à partir de 0  !! ***** a optimiser par dichotomie *****
//    if (!trouve)
//     { // cas où on n'a pas trouver après l'indice
//       for (int indic = 1; indic <indice_precedant;indic++)
//       if (x <= Xi(indic+1)) {trouve=true;indice = indic; break;};
//     };
    // gestion d'erreur
    if (!trouve)
     { cout << "\n erreur : on ne trouve pas la valeur demandee a l'aide de la courbe F_union_1D "
            << "\n x demandee: " << x
            << "\n  double F_union_1D::Valeur(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du y
    indice_precedant = indice;
    return Fi(indice)->Valeur(x);
  };

    // ramène la valeur et la dérivée en paramètre
Courbe1D::ValDer F_union_1D::Valeur_Et_derivee(double x)  
  { // on commence par chercher l'intervalle qui contient x
    //tout d'abord on regarde s'il est en dehors des bornes
    // si oui on lui donne 
    if (x < Xi(1)) 
       {indice_precedant=1;
        return Fi(1)->Valeur_Et_derivee(x);
       };
    int tai = Fi.Taille();   
    if (x > Xi(tai+1))
       {indice_precedant=1; // comme c'est le dernier intervalle on met à 1 car 
        // de toute manière cela ne sert à rien de continuer
        return Fi(tai)->Valeur_Et_derivee(x);
       };
    // maintenant on cherche le couple de xi qui encadre le x
    int indice=0;bool trouve=false;
    // on commence tout d'abord à chercher à partir du précédent indice
    // s'il est supérieur au xi de l'indice existant, l'algo qui suit est ok
    if (x >= Xi(indice_precedant))
      for (int indic=indice_precedant;indic<=tai;indic++)
       if (x < Xi(indic+1)) {trouve=true;indice=indic; break;};
    // sinon cela veut dire qu'il se trouve dans les xi plus bas que l'indice
    // on repart à partir de 0  !! ***** a optimiser par dichotomie *****  
    if (!trouve)
     { // cas où on n'a pas trouver après l'indice
       for (int indic = 1; indic <indice_precedant;indic++)
       if (x <= Xi(indic+1)) {trouve=true;indice = indic; break;};
     };
    // gestion d'erreur 
    if (!trouve)
     { cout << "\n erreur : on ne trouve pas la valeur demandee a l'aide de la courbe F_union_1D "
            << "\n x demandee: " << x
            << "\n  Courbe1D::ValDer F_union_1D::Valeur_Et_derivee(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du retour
    indice_precedant = indice;
    return Fi(indice)->Valeur_Et_derivee(x);
  };  
      
    // ramène la dérivée 
double F_union_1D::Derivee(double x)  
  { // on commence par chercher l'intervalle qui contient x
    //tout d'abord on regarde s'il est en dehors des bornes
    // si oui on lui donne 
    if (x < Xi(1)) 
       {indice_precedant=1;
        return Fi(1)->Derivee(x);
       };
    int tai = Fi.Taille();   
    if (x > Xi(tai+1))
       {indice_precedant=1; // comme c'est le dernier intervalle on met à 1 car 
        // de toute manière cela ne sert à rien de continuer
        return Fi(tai)->Derivee(x);
       };
    // maintenant on cherche le couple de xi qui encadre le x
    int indice=0;bool trouve=false;
    // on commence tout d'abord à chercher à partir du précédent indice
    // s'il est supérieur au xi de l'indice existant, l'algo qui suit est ok
    if (x >= Xi(indice_precedant))
      for (int indic=indice_precedant;indic<=tai;indic++)
       if (x < Xi(indic+1)) {trouve=true;indice=indic; break;};
    // sinon cela veut dire qu'il se trouve dans les xi plus bas que l'indice
    // on repart à partir de 0  !! ***** a optimiser par dichotomie *****  
    if (!trouve)
     { // cas où on n'a pas trouver après l'indice
       for (int indic = 1; indic <indice_precedant;indic++)
       if (x <= Xi(indic+1)) {trouve=true;indice = indic; break;};
     };
    // gestion d'erreur 
    if (!trouve)
     { cout << "\n erreur : on ne trouve pas la valeur demandee a l'aide de la courbe F_union_1D "
            << "\n x demandee: " << x
            << "\n  double F_union_1D::Derivee(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du retour
    indice_precedant = indice;
    return Fi(indice)->Derivee(x);
  };  
        
    // ramène la valeur et les dérivées première et seconde en paramètre
Courbe1D::ValDer2 F_union_1D::Valeur_Et_der12(double x)
  { // on commence par chercher l'intervalle qui contient x
    //tout d'abord on regarde s'il est en dehors des bornes
    // si oui on lui donne 
    if (x < Xi(1)) 
       {indice_precedant=1;
        return Fi(1)->Valeur_Et_der12(x);
       };
    int tai = Fi.Taille();   
    if (x > Xi(tai+1))
       {indice_precedant=1; // comme c'est le dernier intervalle on met à 1 car 
        // de toute manière cela ne sert à rien de continuer
        return Fi(tai)->Valeur_Et_der12(x);
       };
    // maintenant on cherche le couple de xi qui encadre le x
    int indice=0;bool trouve=false;
    // on commence tout d'abord à chercher à partir du précédent indice
    // s'il est supérieur au xi de l'indice existant, l'algo qui suit est ok
    if (x >= Xi(indice_precedant))
      for (int indic=indice_precedant;indic<=tai;indic++)
       if (x < Xi(indic+1)) {trouve=true;indice=indic; break;};
    // sinon cela veut dire qu'il se trouve dans les xi plus bas que l'indice
    // on repart à partir de 0  !! ***** a optimiser par dichotomie *****  
    if (!trouve)
     { // cas où on n'a pas trouver après l'indice
       for (int indic = 1; indic <indice_precedant;indic++)
       if (x <= Xi(indic+1)) {trouve=true;indice = indic; break;};
     };
    // gestion d'erreur 
    if (!trouve)
     { cout << "\n erreur : on ne trouve pas la valeur demandee a l'aide de la courbe F_union_1D "
            << "\n x demandee: " << x
            << "\n  Courbe1D::ValDer F_union_1D::Valeur_Et_derivee(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du retour
    indice_precedant = indice;
    return Fi(indice)->Valeur_Et_der12(x);
  };  
        
    // ramène la dérivée seconde
double F_union_1D::Der_sec(double x)
  { // on commence par chercher l'intervalle qui contient x
    //tout d'abord on regarde s'il est en dehors des bornes
    // si oui on lui donne 
    if (x < Xi(1)) 
       {indice_precedant=1;
        return Fi(1)->Der_sec(x);
       };
    int tai = Fi.Taille();   
    if (x > Xi(tai+1))
       {indice_precedant=1; // comme c'est le dernier intervalle on met à 1 car 
        // de toute manière cela ne sert à rien de continuer
        return Fi(tai)->Der_sec(x);
       };
    // maintenant on cherche le couple de xi qui encadre le x
    int indice=0;bool trouve=false;
    // on commence tout d'abord à chercher à partir du précédent indice
    // s'il est supérieur au xi de l'indice existant, l'algo qui suit est ok
    if (x >= Xi(indice_precedant))
      for (int indic=indice_precedant;indic<=tai;indic++)
       if (x < Xi(indic+1)) {trouve=true;indice=indic; break;};
    // sinon cela veut dire qu'il se trouve dans les xi plus bas que l'indice
    // on repart à partir de 0  !! ***** a optimiser par dichotomie *****  
    if (!trouve)
     { // cas où on n'a pas trouver après l'indice
       for (int indic = 1; indic <indice_precedant;indic++)
       if (x <= Xi(indic+1)) {trouve=true;indice = indic; break;};
     };
    // gestion d'erreur 
    if (!trouve)
     { cout << "\n erreur : on ne trouve pas la valeur demandee a l'aide de la courbe F_union_1D "
            << "\n x demandee: " << x
            << "\n  double F_union_1D::Derivee(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du retour
    indice_precedant = indice;
    return Fi(indice)->Der_sec(x);
  };  
    
    // ramène la valeur si dans le domaine strictement de définition
    // si c'est inférieur au x mini, ramène la valeur minimale possible de y
    // si supérieur au x maxi , ramène le valeur maximale possible de y
Courbe1D::Valbool  F_union_1D::Valeur_stricte(double x)  
  { // on commence par chercher l'intervalle qui contient x
    //tout d'abord on regarde s'il est en dehors des bornes
    // si oui on lui donne 
    if (x < Xi(1)) 
       {indice_precedant=1;
        Valbool ret = Fi(1)->Valeur_stricte(x);
        ret.dedans = false;
        return ret;
       };
    int tai = Fi.Taille();   
    if (x > Xi(tai+1))
       {indice_precedant=1; // comme c'est le dernier intervalle on met à 1 car 
        // de toute manière cela ne sert à rien de continuer
        Valbool ret = Fi(tai)->Valeur_stricte(x);
        ret.dedans = false;
        return ret;
       };
    // maintenant on cherche le couple de xi qui encadre le x
    int indice=0;bool trouve=false;
    // on commence tout d'abord à chercher à partir du précédent indice
    // s'il est supérieur au xi de l'indice existant, l'algo qui suit est ok
    if (x >= Xi(indice_precedant))
      for (int indic=indice_precedant;indic<=tai;indic++)
       if (x < Xi(indic+1)) {trouve=true;indice=indic; break;};
    // sinon cela veut dire qu'il se trouve dans les xi plus bas que l'indice
    // on repart à partir de 0  !! ***** a optimiser par dichotomie *****  
    if (!trouve)
     { // cas où on n'a pas trouver après l'indice
       for (int indic = 1; indic <indice_precedant;indic++)
       if (x <= Xi(indic+1)) {trouve=true;indice = indic; break;};
     };
    // gestion d'erreur 
    if (!trouve)
     { cout << "\n erreur : on ne trouve pas la valeur demandee a l'aide de la courbe F_union_1D "
            << "\n x demandee: " << x
            << "\n  double F_union_1D::Derivee(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du retour
    indice_precedant = indice;
    Valbool ret = Fi(indice)->Valeur_stricte(x);
    ret.dedans = true;
    return ret;
  };  
    
    // ramène la valeur et la dérivée si dans le domaine strictement de définition
    // si c'est inférieur au x mini, ramène la valeur minimale possible de y et Y' correspondant
    // si supérieur au x maxi , ramène le valeur maximale possible de y et Y' correspondant
Courbe1D::ValDerbool  F_union_1D::Valeur_Et_derivee_stricte(double x)  
  { // on commence par chercher l'intervalle qui contient x
    //tout d'abord on regarde s'il est en dehors des bornes
    // si oui on lui donne 
    if (x < Xi(1)) 
       {indice_precedant=1;
        ValDerbool ret = Fi(1)->Valeur_Et_derivee_stricte(x);
        ret.dedans = false;
        return ret;
       };
    int tai = Fi.Taille();   
    if (x > Xi(tai+1))
       {indice_precedant=1; // comme c'est le dernier intervalle on met à 1 car 
        // de toute manière cela ne sert à rien de continuer
        ValDerbool ret = Fi(tai)->Valeur_Et_derivee_stricte(x);
        ret.dedans = false;
        return ret;
       };
    // maintenant on cherche le couple de xi qui encadre le x
    int indice=0;bool trouve=false;
    // on commence tout d'abord à chercher à partir du précédent indice
    // s'il est supérieur au xi de l'indice existant, l'algo qui suit est ok
    if (x >= Xi(indice_precedant))
      for (int indic=indice_precedant;indic<=tai;indic++)
       if (x < Xi(indic+1)) {trouve=true;indice=indic; break;};
    // sinon cela veut dire qu'il se trouve dans les xi plus bas que l'indice
    // on repart à partir de 0  !! ***** a optimiser par dichotomie *****  
    if (!trouve)
     { // cas où on n'a pas trouver après l'indice
       for (int indic = 1; indic <indice_precedant;indic++)
       if (x <= Xi(indic+1)) {trouve=true;indice = indic; break;};
     };
    // gestion d'erreur 
    if (!trouve)
     { cout << "\n erreur : on ne trouve pas la valeur demandee a l'aide de la courbe F_union_1D "
            << "\n x demandee: " << x
            << "\n  F_union_1D::Valeur_Et_derivee_stricte(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du retour
    indice_precedant = indice;
    ValDerbool ret = Fi(indice)->Valeur_Et_derivee_stricte(x);
    ret.dedans = true;
    return ret;
  };  
    
	//----- lecture écriture de restart -----
	// cas donne le niveau de la récupération
    // = 1 : on récupère tout
    // = 2 : on récupère uniquement les données variables (supposées comme telles)
void F_union_1D::Lecture_base_info(ifstream& ent,const int cas)
  { // on n'a que des grandeurs constantes
    if (cas == 1)
      { string nom;
        ent >> nom;  // "\n <F_UNION_1D>  "
 //       string nom1=nom.substr(nom.find(<)+1,nom.find(>)-1);
        // lecture et vérification de l'entête
        string type_courbe_a_lire('<'+Nom_Courbe1D(this->Type_courbe())+'>');
        if (nom != type_courbe_a_lire) //"F_union_1D")
         { cout << "\n erreur dans la verification du type de courbe lue ";
           cout << "\n courbe en lecture: " << type_courbe_a_lire;    
           cout << "\n F_union_1D::Lecture_base_info(... ";
           Sortie(1); 
           } 
        // lecture du nombre de courbe
        int tai=0;
        ent >> nom >> tai;
        Fi.Change_taille(tai);
        Xi.Change_taille(tai+1);
        nom_courbei.Change_taille(tai);
        // lecture de la borne inf
        ent >> nom >> Xi(1);
        // lecture des courbes et des bornes
        string nom1,nom2,nom3;
        for (int i=1;i<=tai;i++) 
        	{  // lecture de la courbe
        	   ent >> nom1 >> nom2 >> nom3;
               if (nom1 != "courbe=")
                { cout << "\n erreur dans la verification du type, on attendait le mot cle courbe= "
                       << " et on a lu " << nom1 << " ";
                  cout << "\n F1_rond_F2::Lecture_base_info(... ";
                  Sortie(1); 
                 }
               else
                { if (nom2 == "COURBE_INTERNE")
                   {// cas d'une courbe en interne
                    // 1) on commence par effacer la courbe existante si nécessaire
                    if (Fi(i) != NULL) {if (Fi(i)->NomCourbe() == "_") delete Fi(i);};
                    // 2) on crée la courbe adoc
                    nom2="_";
                    Fi(i) = Courbe1D::New_Courbe1D(nom2,Id_Nom_Courbe1D (nom3.c_str()));
                    // 3) on lit les données particulières
                    Fi(i)->Lecture_base_info(ent,cas);
                    nom_courbei(i)="i_interne_i";
                    }
                  else
                   {// cas d'une courbe externe on lit le nom
                    nom_courbei(i) = nom2; 
                    };
                };    
               // lecture de la borne max pour la fonction i
               ent >> nom1 >> Xi(i+1);
        	};
        // lecture du niveau d'affichage
        ent >> nom >> permet_affichage;
        // on lit le tag de fin de définition
        ent >> nom; //  <F_UNION_1D> 
      }
   };

    // cas donne le niveau de sauvegarde
    // = 1 : on sauvegarde tout
    // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void F_union_1D::Ecriture_base_info(ofstream& sort,const int cas)
  { // on n'a que des grandeurs constantes
    if (cas == 1)
      { sort << "\n <F_UNION_1D>  ";
        int tai = Fi.Taille();
        sort << " nbcourbe= " << tai << " "; // le nombre de courbes
        // la borne mini
        sort << " Xmin= " << Xi(1)<< " ";
        // on balaie les courbes
        for (int i=1;i<=tai;i++)
         {if (Fi(i)->NomCourbe() == "_")
           {// cas d'une courbe interne
            sort << "\n courbe=  COURBE_INTERNE " << Fi(i)->Type_courbe();
            Fi(i)->Ecriture_base_info(sort,cas);
            }
          else
            // cas d'une courbe externe
           {sort << "\n courbe= " <<  Fi(i)->NomCourbe() << " " << Fi(i)->Type_courbe();};
          // la borne max pour la fonction i
          sort << " Xmax= " << Xi(i+1) << " ";
         };
         sort << "\n permet_affichage: " << permet_affichage;

        sort << "\n </F_UNION_1D>  ";
       }
   };
     
    // sortie du schemaXML: en fonction de enu 
void F_union_1D::SchemaXML_Courbes1D(ofstream& ,const Enum_IO_XML enu)
  {
	switch (enu)
	{ case XML_TYPE_GLOBAUX :
  	   {/*sort << "\n <!--  *************************** F_UNION_1D ***************************  -->"
  	         << "\n <!--  def d'un type contenant une valeur et un boolean  -->"
  	         << "\n    <xs:complexType name=\"valeurPlusBooleen\">"
  	         << "\n       <xs:simpleContent>"
  	         << "\n          <xs:extension base=\"xs:double\">" 
  	         << "\n              <xs:attribute name=\"present\" type=\"xs:boolean\"  />" 
  	         << "\n          </xs:extension>" 
  	         << "\n       </xs:simpleContent> "
  	         << "\n    </xs:complexType>"
  	         << "\n <!--  maintenant le type de la courbe  -->"
  	         << "\n<xs:complexType name=\"F_UNION_1D\" >"
  	         << "\n    <xs:annotation>"
  	         << "\n      <xs:documentation> courbe F_UNION_1D constituee de N points </xs:documentation>"
  	         << "\n    </xs:annotation>"
  	         << "\n    <xs:sequence>"
  	         << "\n        <xs:element  name=\"derivee_initiale_\"  type=\"valeurPlusBooleen\" />"
  	         << "\n        <xs:element  name=\"derivee_finale_\" type=\"valeurPlusBooleen\" />"
   	         << "\n        <xs:element  name=\"les_points\" type=\"COORDONNEE_2\"  minOccurs='0' maxOccurs=\"unbounded\" />"
  	         << "\n    </xs:sequence>"
  	         << "\n</xs:complexType>";*/
		 break;
		}
		case XML_IO_POINT_INFO :
		{
		 break;
		}
		case XML_IO_POINT_BI :
		{
		 break;
		}
		case XML_IO_ELEMENT_FINI :
		{
		 break;
		}
	};		
  };
