// 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 "CourbePolyHermite1D.h"

#include <list>
#include "ConstMath.h"
#include "MathUtil.h"

    // CONSTRUCTEURS :
    
// constructeur par défaut 
CourbePolyHermite1D::CourbePolyHermite1D(string nom) :
 Courbe1D(nom,COURBEPOLYHERMITE_1_D)
 ,points(),indice_precedant(1)
  {};
        
// fonction d'un tableau de points
CourbePolyHermite1D::CourbePolyHermite1D(Tableau <Coordonnee3>& pt,string nom):
 Courbe1D(nom,COURBEPOLYHERMITE_1_D)
 ,points(pt),indice_precedant(1)
  {  // On vérifie que la dérivée n'est pas infinie c'est-à-dire que 
     // deux abscices ne sont pas identiques 
     // on vérifie également par la même que les absisses sont croissantes
     int taille = points.Taille();
     for (int i=1;i<taille;i++)
      {if ((points(i+1)(1)-points(i)(1)) < ConstMath::pasmalpetit)
         { cout << "\n erreur en definition des pointss pour une courbe poly PolyHermite1D "
                << " la distance entre les abscisses de deux points consecutifs est"
                << " trop faible ";
           cout << " \n points 1 : " << points(i+1) << ", point 2 : " << points(i);    
           cout << "\n CourbePolyHermite1D::CourbePolyHermite1D(Tableau <Coordonnee3> pt,string nom) "
                << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1); 
         };
      };
  };

// constructeur protégé, utilisable par les classes dérivées   
CourbePolyHermite1D::CourbePolyHermite1D(string nom,EnumCourbe1D typ) :
  Courbe1D(nom,typ)
 ,points(),indice_precedant(1)
  {};
    
    // de copie
CourbePolyHermite1D::CourbePolyHermite1D(const CourbePolyHermite1D& Co) :
 Courbe1D(Co)
 ,points(Co.points),indice_precedant(Co.indice_precedant)
  {};
    // de copie à partir d'une instance générale
CourbePolyHermite1D::CourbePolyHermite1D(const Courbe1D& Coo) :
 Courbe1D(Coo),indice_precedant(1)
  { if (Coo.Type_courbe() != COURBEPOLYHERMITE_1_D)
      { cout << "\n erreur dans le constructeur de copie pour une courbe polyHermite1D "
             << " a partir d'une instance generale ";
        cout << "\n CourbePolyHermite1D::CourbePolyHermite1D(const Courbe1D& Co) ";
           Sortie(1);          
          };
    // définition des données
    CourbePolyHermite1D & Co = (CourbePolyHermite1D&) Coo;
    points = Co.points;
  };

    // DESTRUCTEUR :
CourbePolyHermite1D::~CourbePolyHermite1D()
  {};
    
    // METHODES PUBLIQUES :
    
    // --------- virtuelles ---------
    
    // affichage de la courbe
void CourbePolyHermite1D::Affiche() const
  { cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; // CourbePolyHermite1D ";
    cout << "\n Debut_des_coordonnees_des_points (x,y,y')";
    int taille = points.Taille();
    for (int i=1;i<=taille;i++)
      cout << points(i);
    cout << "\nFin_des_coordonnees_des_points ";
   };

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

    // 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 CourbePolyHermite1D::LectDonnParticulieres_courbes(const string& nom,UtilLecture * entreePrinc)
  {  if (nom == "")  { *(entreePrinc->entree) >> nom_ref;}
     else {nom_ref=nom;};
     entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
     // on regarde s'il n'y a pas un décalage initiale
     double decalx=0; double decaly=0.; 
     if((strstr(entreePrinc->tablcar,"decalageX_=")!=0) 
        || (strstr(entreePrinc->tablcar,"decalageY_=") != 0))    
      { string nom_lu;
        if(strstr(entreePrinc->tablcar,"decalageX_=")!=0)
        // cas ou on veut définir un décalage initiale
         { *(entreePrinc->entree) >> nom_lu >> decalx;
           if (nom_lu != "decalageX_=")
           { cout << "\n erreur en lecture du decalage en x initiale  "
                  << " on attendait la chaine: decalageX_= et on a lue " << nom_lu;
             entreePrinc->MessageBuffer("**erreur1 CourbePolyHermite1D::LectureDonneesParticulieres**");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);          
           };
         };
        if(strstr(entreePrinc->tablcar,"decalageY_=")!=0)
        // cas ou on veut définir un décalage initiale
         { *(entreePrinc->entree) >> nom_lu >> decaly;
           if (nom_lu != "decalageY_=")
            { cout << "\n erreur en lecture du decalage en y initiale  "
                   << " on attendait la chaine: decalageY_= et on a lue " << nom_lu;
              entreePrinc->MessageBuffer("**erreur1 CourbePolyHermite1D::LectureDonneesParticulieres**");
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);          
             };
          };
        // si on a lue on passe une nouvelle ligne  
        entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
      };
     // on définit une liste pour la lecture des coordonnées
     list<Coordonnee3> pointlec;
     // un indicateur pour la fin de la lecture
     int fin_lecture = 0;
     // on lit l'entête
     if(strstr(entreePrinc->tablcar,"Debut_des_coordonnees_des_points")==0)
         { cout << "\n erreur en lecture des points pour une courbe poly lineaire "
                << " la chaine : Debut_des_coordonnees_des_points n'est pas presente ";
           entreePrinc->MessageBuffer(" ");     
           cout << "\n CourbePolyHermite1D::LectureDonneesParticulieres "
                << "(UtilLecture * entreePrinc) " << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          }
     entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
     // la boucle de lecture des points
     while (fin_lecture == 0)
       { // lecture
//         entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
         if(strstr(entreePrinc->tablcar,"Fin_des_coordonnees_des_points")==0)
           // cas ou ce n'est pas la fin de la lecture des coordonnées
           { Coordonnee3 M;
             *(entreePrinc->entree) >> M;
             // comme le décalage doit-être soustrait à x, on ajoute le décalage au point
             M(1) += decalx;
             // idem pour y car le décalage est en sortie
             M(2) += decaly;
             pointlec.push_back(M); 
             entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
            }
         else
           // on est à la fin de la lecture des coordonnées  
           fin_lecture = 1;
        }
     // écriture dans le tableau
     points.Change_taille((int)pointlec.size());
     list<Coordonnee3>::iterator indice,indice_fin;
     indice_fin = pointlec.end();
     int if1;
     for (indice = pointlec.begin(),if1=1; indice!= indice_fin; indice++,if1++)
       points(if1)= *indice;
     // On vérifie que la dérivée n'est pas infinie c'est-à-dire que 
     // deux abscices ne sont pas identiques 
     // on vérifie également par la même que les absisses sont croissantes
     int taille = points.Taille();
     for (int i=1;i<taille;i++)
       if ((points(i+1)(1)-points(i)(1)) < ConstMath::pasmalpetit)
         { cout << "\n erreur en definition des points pour une courbe PolyHermite1D "
                << " la distance entre les abscisses de deux points consecutifs est"
                << " trop faible ";
           cout << " \n points 1 : " << points(i+1) << ", point 2 : " << points(i);    
           cout << "\n CourbePolyHermite1D::LectureDonneesParticulieres "
                << "(UtilLecture * entreePrinc) " << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1); 
           }         
   };
    
// def info fichier de commande
void CourbePolyHermite1D::Info_commande_Courbes1D(UtilLecture & entreePrinc)
  {  
     ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
     sort << "\n#............................................"
          << "\n# exemple de definition d'une courbe CourbePolyHermite1D|"
          << "\n#"
          << "\n courbe_de_charge    COURBEPOLYHERMITE_1_D  # nom de la courbe puis le type de la courbe"
          << "\n      # def des points constituants la courbe "
          << "\n          Debut_des_coordonnees_des_points"
          << "\n           Coordonnee dim= 3 0. 1. 0. # chaque point est defini par le mot cle Coordonnee"
          << "\n           Coordonnee dim= 3 1. 1. 0. # puis la dimension, ici 3 , puis l'absisse, l'ordonnee, et la derivee"
          << "\n          Fin_des_coordonnees_des_points "
          << "\n#   Il est egalement possible d'introduire un decalage en x et y. Le decalage en x "
          << "\n#   est soustrait a la valeur courante de x, tandis que le decalage en y est ajoute "
          << "\n#   a la valeur finale de la fonction. Autre exemple de syntaxe avec decalage "
          << "\n courbe_2    COURBEPOLYHERMITE_1_D  # nom de la courbe puis le type de la courbe"
          << "\n      decalageX_= 10. decalageY_= 3. "
          << "\n      # def des points constituants la courbe "
          << "\n          Debut_des_coordonnees_des_points"
          << "\n           Coordonnee dim= 3 0. 0. 0. "
          << "\n           Coordonnee dim= 3 1. 0.5 0. "
          << "\n          Fin_des_coordonnees_des_points "
        << endl;
   };        
    
    // ramène la valeur 
double CourbePolyHermite1D::Valeur(double x)
  { //tout d'abord on regarde s'il est en dehors des bornes
    if (x <= points(1)(1))
       // si on est inférieur au premier point, on étend en utilisant la dérivée
       {indice_precedant=1;
        return (points(1)(2) + (x-points(1)(1))*points(1)(3));
       };
    int taille = points.Taille();   
    if (x >= points(taille)(1))
       // si on est supérieur au dernier point, on étend en utilisant la dérivée
       {indice_precedant=taille;
        return (points(taille)(2) + (x-points(taille)(1))*points(taille)(3));
       };
    // 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 >= points(indice_precedant)(1))
     { for (int indic=indice_precedant;indic<taille;indic++)
       // on ne peut pas avoir indice_precedant == taille sinon, cela voudrait dire
       // que x >= points(taille)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x <= points(indic+1)(1)) {trouve=true;indice=indic; break;};
     }
    else // sinon cela veut que x < points(indice_precedant)(1)
         // on cherche en descendant
     {for (int indic=indice_precedant-1;indic>0;indic--)
       // on ne peut pas avoir indice_precedant == 1, sinon cela voudrait dire que
       // x < points(1)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x >= points(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 CourbePolyHermite1D "
            << "\n x demandee: " << x
            << "\n  double CourbePolyHermite1D::Valeur(double x) ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du y
    indice_precedant = indice;
    // pour simplifier
    double x1=points(indice)(1); double x2=points(indice+1)(1);
    double y1=points(indice)(2); double y2=points(indice+1)(2);
    double d1=points(indice)(3); double d2=points(indice+1)(3);
    // les polynômes de base
    double Q1_x = Sqr(x-x2);
    double Q2_x = Sqr(x-x1);
    double Q1_x1 = Sqr(x1-x2);
    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
    double Qp1_x1 = 2.*(x1-x2);
    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
    // l'interpolation
    double y =   Q1_x/Q1_x1 * ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Q2_x/Q2_x2 * ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
////--debug
//{
//    // pour simplifier
//    double x1=points(indice)(1); double x2=points(indice+1)(1);
//    double y1=points(indice)(2); double y2=points(indice+1)(2);
//    double d1=points(indice)(3); double d2=points(indice+1)(3);
//    // les polynômes de base
//    double Q1_x = Sqr(x-x2);
//    double Q2_x = Sqr(x-x1);
//    double Q1_x1 = Sqr(x1-x2);
//    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
//    double Qp1_x = 2.*(x-x2);
//    double Qp2_x = 2.*(x-x1);
//    double Qp1_x1 = 2.*(x1-x2);
//    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
//    // l'interpolation
//    double inter1= ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1);
//    double inter2= ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
//    double derivee = Qp1_x/Q1_x1 * inter1 //((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
//               + Qp2_x/Q2_x2 * inter2 //((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2)
//               + Q1_x/Q1_x1 * (-Qp1_x1/Q1_x1*y1 + d1)
//               + Q2_x/Q2_x2 * (-Qp2_x2/Q2_x2*y2 + d2);
//    cout << "\n debug CourbePolyHermite1D::Valeur:derivee= " << derivee << endl;
//}
//
////--fin debug

    // le retour
    return y;
  };

    // ramène la valeur et la dérivée en paramètre
Courbe1D::ValDer CourbePolyHermite1D::Valeur_Et_derivee(double x)
  {  ValDer ret; // def de la valeur de retour
    //tout d'abord on regarde s'il est en dehors des bornes
    if (x <= points(1)(1))
       { ret.valeur = (points(1)(2) + (x-points(1)(1))*points(1)(3));
         ret.derivee = points(1)(3);
         indice_precedant=1;
         return ret;
        } 
    int taille = points.Taille();   
    if (x >= points(taille)(1))
       { ret.valeur = (points(taille)(2) + (x-points(taille)(1))*points(taille)(3));
         ret.derivee = points(taille)(3);
         indice_precedant=taille;
         return ret;
        } 
    // maintenant on cherche le couple de xi qui encadre le x
    int indice;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 >= points(indice_precedant)(1))
     { for (int indic=indice_precedant;indic<taille;indic++)
       // on ne peut pas avoir indice_precedant == taille sinon, cela voudrait dire
       // que x >= points(taille)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x <= points(indic+1)(1)) {trouve=true;indice=indic; break;};
     }
    else // sinon cela veut que x < points(indice_precedant)(1)
         // on cherche en descendant
     {for (int indic=indice_precedant-1;indic>0;indic--)
       // on ne peut pas avoir indice_precedant == 1, sinon cela voudrait dire que
       // x < points(1)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x >= points(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 CourbePolyHermite1D "
            << "\n x demandee: " << x
            << "\n  double CourbePolyHermite1D::Valeur_Et_derivee(... ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du y et y'
    indice_precedant = indice;
    // pour simplifier
    double x1=points(indice)(1); double x2=points(indice+1)(1);
    double y1=points(indice)(2); double y2=points(indice+1)(2);
    double d1=points(indice)(3); double d2=points(indice+1)(3);
    // les polynômes de base
    double Q1_x = Sqr(x-x2);
    double Q2_x = Sqr(x-x1);
    double Q1_x1 = Sqr(x1-x2);
    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
    double Qp1_x = 2.*(x-x2);
    double Qp2_x = 2.*(x-x1);
    double Qp1_x1 = 2.*(x1-x2);
    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
    // l'interpolation
    double inter1= ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1);
    double inter2= ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    ret.valeur = Q1_x/Q1_x1 * inter1 //((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Q2_x/Q2_x2 * inter2; //((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    ret.derivee = Qp1_x/Q1_x1 * inter1 //((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Qp2_x/Q2_x2 * inter2 //((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2)
               + Q1_x/Q1_x1 * (-Qp1_x1/Q1_x1*y1 + d1)
               + Q2_x/Q2_x2 * (-Qp2_x2/Q2_x2*y2 + d2);
    return ret;
   };
    
    // ramène la dérivée 
double CourbePolyHermite1D::Derivee(double x)
  { //tout d'abord on regarde s'il est en dehors des bornes
    if (x <= points(1)(1))
       // si on est inférieur au premier point, on étend en utilisant la dérivée
       {indice_precedant=1;
        return points(1)(3);
       };
    int taille = points.Taille();   
    if (x >= points(taille)(1))
       // si on est supérieur au dernier point, on étend en utilisant la dérivée
       {indice_precedant=taille;
        return points(taille)(3);
       };
    // 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 >= points(indice_precedant)(1))
     { for (int indic=indice_precedant;indic<taille;indic++)
       // on ne peut pas avoir indice_precedant == taille sinon, cela voudrait dire
       // que x >= points(taille)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x <= points(indic+1)(1)) {trouve=true;indice=indic; break;};
     }
    else // sinon cela veut que x < points(indice_precedant)(1)
         // on cherche en descendant
     {for (int indic=indice_precedant-1;indic>0;indic--)
       // on ne peut pas avoir indice_precedant == 1, sinon cela voudrait dire que
       // x < points(1)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x >= points(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 CourbePolyHermite1D "
            << "\n x demandee: " << x
            << "\n  double CourbePolyHermite1D::Derivee(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    indice_precedant = indice;   
    // calcul du y'
    indice_precedant = indice;
    // pour simplifier
    double x1=points(indice)(1); double x2=points(indice+1)(1);
    double y1=points(indice)(2); double y2=points(indice+1)(2);
    double d1=points(indice)(3); double d2=points(indice+1)(3);
    // les polynômes de base
    double Q1_x = Sqr(x-x2);
    double Q2_x = Sqr(x-x1);
    double Q1_x1 = Sqr(x1-x2);
    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
    double Qp1_x = 2.*(x-x2);
    double Qp2_x = 2.*(x-x1);
    double Qp1_x1 = 2.*(x1-x2);
    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
    // l'interpolation
    double derivee = Qp1_x/Q1_x1 * ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Qp2_x/Q2_x2 * ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2)
               + Q1_x/Q1_x1 * (-Qp1_x1/Q1_x1*y1 + d1)
               + Q2_x/Q2_x2 * (-Qp2_x2/Q2_x2*y2 + d2);

    return derivee;
   };
        
  // ramène la valeur et les dérivées première et seconde en paramètre
  Courbe1D::ValDer2 CourbePolyHermite1D::Valeur_Et_der12(double x)
   {Courbe1D::ValDer2 ret;
    //tout d'abord on regarde s'il est en dehors des bornes
    // on considère qu'en dehors des bornes la dérivée seconde est nulle
    if (x <= points(1)(1))
       { ret.valeur = (points(1)(2) + (x-points(1)(1))*points(1)(3));
         ret.derivee = points(1)(3);
         ret.der_sec = 0.;
         indice_precedant=1;
         return ret;
        } 
    int taille = points.Taille();   
    if (x >= points(taille)(1))
       { ret.valeur = (points(taille)(2) + (x-points(taille)(1))*points(taille)(3));
         ret.derivee = points(taille)(3);
         ret.der_sec = 0.;
         indice_precedant=taille;
         return ret;
        } 
    // maintenant on cherche le couple de xi qui encadre le x
    int indice;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 >= points(indice_precedant)(1))
     { for (int indic=indice_precedant;indic<taille;indic++)
       // on ne peut pas avoir indice_precedant == taille sinon, cela voudrait dire
       // que x >= points(taille)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x <= points(indic+1)(1)) {trouve=true;indice=indic; break;};
     }
    else // sinon cela veut que x < points(indice_precedant)(1)
         // on cherche en descendant
     {for (int indic=indice_precedant-1;indic>0;indic--)
       // on ne peut pas avoir indice_precedant == 1, sinon cela voudrait dire que
       // x < points(1)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x >= points(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 CourbePolyHermite1D "
            << "\n x demandee: " << x
            << "\n  double CourbePolyHermite1D::Valeur_Et_der12(... ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du y, y' et y''
    indice_precedant = indice;
    // pour simplifier
    double x1=points(indice)(1); double x2=points(indice+1)(1);
    double y1=points(indice)(2); double y2=points(indice+1)(2);
    double d1=points(indice)(3); double d2=points(indice+1)(3);
    // les polynômes de base
    double Q1_x = Sqr(x-x2);
    double Q2_x = Sqr(x-x1);
    double Q1_x1 = Sqr(x1-x2);
    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
    double Qp1_x = 2.*(x-x2);
    double Qp2_x = 2.*(x-x1);
    double Qp1_x1 = 2.*(x1-x2);
    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
    // l'interpolation
    double inter1= ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1);
    double inter2= ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    double d_inter1= (-Qp1_x1/Q1_x1*y1 + d1);
    double d_inter2= (-Qp2_x2/Q2_x2*y2 + d2);
    ret.valeur = Q1_x/Q1_x1 * inter1 // ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Q2_x/Q2_x2 * inter2; // ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    ret.derivee = Qp1_x/Q1_x1 * inter1 // ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Qp2_x/Q2_x2 * inter2 // ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2)
               + Q1_x/Q1_x1 * d_inter1 // (-Qp1_x1/Q1_x1*y1 + d1)
               + Q2_x/Q2_x2 * d_inter2; // (-Qp2_x2/Q2_x2*y2 + d2);
      
    ret.der_sec =
                 2./Q1_x1 * inter1
               + 2./Q2_x2 * inter2

               + 2. * Qp1_x/Q1_x1 * d_inter1
               + 2. * Qp2_x/Q2_x2 * d_inter2

               + Q1_x/Q1_x1 * (-2./Q1_x1*y1)
               + Q2_x/Q2_x2 * (-2/Q2_x2*y2);

    return ret;
   };

    // ramène la dérivée seconde
    double CourbePolyHermite1D::Der_sec(double x)
   {//tout d'abord on regarde s'il est en dehors des bornes
    // on considère qu'en dehors des bornes la dérivée seconde est nulle
    if (x <= points(1)(1))
       { indice_precedant=1;
         return 0.;
        } 
    int taille = points.Taille();   
    if (x >= points(taille)(1))
       { indice_precedant=taille;
         return 0.;
        } 
    // maintenant on cherche le couple de xi qui encadre le x
    int indice;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 >= points(indice_precedant)(1))
     { for (int indic=indice_precedant;indic<taille;indic++)
       // on ne peut pas avoir indice_precedant == taille sinon, cela voudrait dire
       // que x >= points(taille)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x <= points(indic+1)(1)) {trouve=true;indice=indic; break;};
     }
    else // sinon cela veut que x < points(indice_precedant)(1)
         // on cherche en descendant
     {for (int indic=indice_precedant-1;indic>0;indic--)
       // on ne peut pas avoir indice_precedant == 1, sinon cela voudrait dire que
       // x < points(1)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x >= points(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 CourbePolyHermite1D "
            << "\n x demandee: " << x
            << "\n  double CourbePolyHermite1D::Der_sec(... ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul de y''
    indice_precedant = indice;
    // pour simplifier
    double x1=points(indice)(1); double x2=points(indice+1)(1);
    double y1=points(indice)(2); double y2=points(indice+1)(2);
    double d1=points(indice)(3); double d2=points(indice+1)(3);
    // les polynômes de base
    double Q1_x = Sqr(x-x2);
    double Q2_x = Sqr(x-x1);
    double Q1_x1 = Sqr(x1-x2);
    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
    double Qp1_x = 2.*(x-x2);
    double Qp2_x = 2.*(x-x1);
    double Qp1_x1 = 2.*(x1-x2);
    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
    // l'interpolation
    double inter1= ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1);
    double inter2= ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    double d_inter1= (-Qp1_x1/Q1_x1*y1 + d1);
    double d_inter2= (-Qp2_x2/Q2_x2*y2 + d2);
    
    double der_sec =
                 2./Q1_x1 * inter1
               + 2./Q2_x2 * inter2

               + 2. * Qp1_x/Q1_x1 * d_inter1
               + 2. * Qp2_x/Q2_x2 * d_inter2

               + Q1_x/Q1_x1 * (-2./Q1_x1*y1)
               + Q2_x/Q2_x2 * (-2/Q2_x2*y2);

    return der_sec;
   };


    // 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  CourbePolyHermite1D::Valeur_stricte(double x)
  { Valbool ret; // def de la valeur de retour
    //tout d'abord on regarde s'il est en dehors des bornes
    if (x <= points(1)(1))
       { ret.valeur = points(1)(1);
         ret.dedans = false;indice_precedant=1;
         return ret;
        };
    int taille = points.Taille();
    if (x > points(taille)(1))
       { ret.valeur = points(taille)(1);
         ret.dedans = false;indice_precedant=taille;
         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 >= points(indice_precedant)(1))
     { for (int indic=indice_precedant;indic<taille;indic++)
       // on ne peut pas avoir indice_precedant == taille sinon, cela voudrait dire
       // que x >= points(taille)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x <= points(indic+1)(1)) {trouve=true;indice=indic; break;};
     }
    else // sinon cela veut que x < points(indice_precedant)(1)
         // on cherche en descendant
     {for (int indic=indice_precedant-1;indic>0;indic--)
       // on ne peut pas avoir indice_precedant == 1, sinon cela voudrait dire que
       // x < points(1)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x >= points(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 CourbePolyHermite1D "
            << "\n x demandee: " << x
            << "\n  double CourbePolyHermite1D::Valeur_stricte(double x) ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    // calcul du y
    indice_precedant = indice;
    // pour simplifier
    double x1=points(indice)(1); double x2=points(indice+1)(1);
    double y1=points(indice)(2); double y2=points(indice+1)(2);
    double d1=points(indice)(3); double d2=points(indice+1)(3);
    // les polynômes de base
    double Q1_x = Sqr(x-x2);
    double Q2_x = Sqr(x-x1);
    double Q1_x1 = Sqr(x1-x2);
    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
    double Qp1_x1 = 2.*(x1-x2);
    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
    // l'interpolation
    ret.valeur =   Q1_x/Q1_x1 * ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Q2_x/Q2_x2 * ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    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  CourbePolyHermite1D::Valeur_Et_derivee_stricte(double x)
  { ValDerbool ret; // def de la valeur de retour
    //tout d'abord on regarde s'il est en dehors des bornes
    if (x <= points(1)(1))
       { ret.valeur = points(1)(1);
         ret.derivee = points(1)(3);
         ret.dedans = false;indice_precedant=1;
         return ret;
        } 
    int taille = points.Taille();   
    if (x >= points(taille)(1))
       { ret.valeur = points(taille)(1);
         ret.derivee = points(taille)(3);
         ret.dedans = false;indice_precedant=taille;
         return ret;
        } 
    // maintenant on cherche le couple de xi qui encadre le x
    int indice;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 >= points(indice_precedant)(1))
     { for (int indic=indice_precedant;indic<taille;indic++)
       // on ne peut pas avoir indice_precedant == taille sinon, cela voudrait dire
       // que x >= points(taille)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x <= points(indic+1)(1)) {trouve=true;indice=indic; break;};
     }
    else // sinon cela veut que x < points(indice_precedant)(1)
         // on cherche en descendant
     {for (int indic=indice_precedant-1;indic>0;indic--)
       // on ne peut pas avoir indice_precedant == 1, sinon cela voudrait dire que
       // x < points(1)(1), or ce cas a déjà été testé
       // donc la boucle qui suit est toujours valide
       if (x >= points(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 CourbePolyHermite1D "
            << "\n x demandee: " << x
            << "\n  double CourbePolyHermite1D::Valeur_Et_derivee_stricte(double x)  ";
       cout << "\n" << Nom_Courbe1D(this->Type_courbe()) << " : nom_ref= " << nom_ref; 
       Sortie(1);           
      };
    indice_precedant = indice;
    // calcul du y et y'
    indice_precedant = indice;
    // pour simplifier
    double x1=points(indice)(1); double x2=points(indice+1)(1);
    double y1=points(indice)(2); double y2=points(indice+1)(2);
    double d1=points(indice)(3); double d2=points(indice+1)(3);
    // les polynômes de base
    double Q1_x = Sqr(x-x2);
    double Q2_x = Sqr(x-x1);
    double Q1_x1 = Sqr(x1-x2);
    double Q2_x2 = Q1_x1; // = Sqr(x2-x1);  donc ils sont identiques
    double Qp1_x = 2.*(x-x2);
    double Qp2_x = 2.*(x-x1);
    double Qp1_x1 = 2.*(x1-x2);
    double Qp2_x2 = -Qp1_x1; // = 2.*(x1-x2); donc ils sont inverses en signe
    // l'interpolation
    double inter1= ((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1);
    double inter2= ((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    ret.valeur = Q1_x/Q1_x1 * inter1 //((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Q2_x/Q2_x2 * inter2; //((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2);
    ret.derivee = Qp1_x/Q1_x1 * inter1 //((1.-(x-x1)*Qp1_x1/Q1_x1)*y1 + (x-x1)*d1)
               + Qp2_x/Q2_x2 * inter2 //((1.-(x-x2)*Qp2_x2/Q2_x2)*y2 + (x-x2)*d2)
               + Q1_x/Q1_x1 * (-Qp1_x1/Q1_x1*y1 + d1)
               + Q2_x/Q2_x2 * (-Qp2_x2/Q2_x2*y2 + d2);
    ret.dedans = true;
    return ret;
   };
    
// méthode pour changer le tableau de points associé
void CourbePolyHermite1D::Change_tabPoints(Tableau <Coordonnee3>& pt)
  {  // changement des points
     points = pt;
     // On vérifie que la dérivée n'est pas infinie c'est-à-dire que 
     // deux abscices ne sont pas identiques 
     // on vérifie également par la même que les absisses sont croissantes
     int taille = points.Taille();
     for (int i=1;i<taille;i++)
       {if ((points(i+1)(1)-points(i)(1)) < ConstMath::pasmalpetit)
         { cout << "\n erreur en definition des pointss pour une courbe poly PolyHermite1D "
                << " la distance entre les abscisses de deux points consecutifs est"
                << " trop faible ";
           cout << " \n points 1 : " << points(i+1) << ", point 2 : " << points(i);    
           cout << "\n CourbePolyHermite1D::CourbePolyHermite1D(Tableau<Coordonnee3> pt,string nom) "
                << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1); 
         };
       };
  };
    
    
	//----- 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 CourbePolyHermite1D::Lecture_base_info(ifstream& ent,const int cas)
  { // on n'a que des grandeurs constantes
    if (cas == 1)
      { string nom;
        ent >> nom;  // "\n <COURBEPOLYHERMITE_1_D>  "
 //       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) //"CourbePolyHermite1D")
         { cout << "\n erreur dans la verification du type de courbe lue ";
           cout << "\n courbe en lecture: " << type_courbe_a_lire;    
           cout << "\n CourbePolyHermite1D::Lecture_base_info(... ";
           Sortie(1); 
           } 
        ent >> nom; // "\n </COURBEPOLYHERMITE_1_D>  "
        // lecture des infos
        ent >> nom ;
        ent >> nom >>  points;
       }
   };

    // cas donne le niveau de sauvegarde
    // = 1 : on sauvegarde tout
    // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void CourbePolyHermite1D::Ecriture_base_info(ofstream& sort,const int cas)
  { // on n'a que des grandeurs constantes
    if (cas == 1)
      { sort << "\n <COURBEPOLYHERMITE_1_D>  ";
        sort << "\n les_points_: " << points;
        sort << "\n </COURBEPOLYHERMITE_1_D>  ";
       }
   };
     
    // sortie du schemaXML: en fonction de enu 
void CourbePolyHermite1D::SchemaXML_Courbes1D(ofstream& sort,const Enum_IO_XML enu)
  {
	switch (enu)
	{ case XML_TYPE_GLOBAUX :
  	   {sort << "\n <!--  *************************** COURBEPOLYHERMITE_1_D ***************************  -->"
  	         << "\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=\"COURBEPOLYHERMITE_1_D\" >"
  	         << "\n    <xs:annotation>"
  	         << "\n      <xs:documentation> courbe CourbePolyHermite1D 1D constituee de N points </xs:documentation>"
  	         << "\n    </xs:annotation>"
  	         << "\n    <xs:sequence>"
   	         << "\n        <xs:element  name=\"les_points\" type=\"COORDONNEE_3\"  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;
		}
	};		
  };
