
// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2021 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.

//#include "debug.h"
#include "Base.h"
#include "Util.h"

#ifndef  BASE_HetB_deja_inclus

//===============================================================
// Les base covariantes et absolus
//===============================================================

    
    // CONSTRUCTEURS :
// par defaut, defini la Base absolu en dimension 3    
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::BaseB ()  : 
  dimension(3), nb_vecteur(3), v(3), v_sans(3) 
  { v(1).Change_dim(3); v(1)(1) = 1.;   
    v(2).Change_dim(3); v(2)(2) = 1.;   
    v(3).Change_dim(3); v(3)(3) = 1.;   
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };
  
// defini la Base absolu en dimension dim    
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::BaseB (int dim) :
   dimension(dim) , nb_vecteur(dim), v(dim), v_sans(dim)  
  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(dimension); v(3)(3) = 1.; 
       case 2: v(2).Change_dim(dimension); v(2)(2) = 1.; 
       case 1: v(1).Change_dim(dimension); v(1)(1) = 1.;
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseB::BaseB (int dim)";
           Sortie(1);
          } 
     };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };
  
// defini une Base relative v1(dim) 
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::BaseB (int dim,const Tableau<CoordonneeB > & v1) :
   dimension(dim) ,nb_vecteur(v1.Taille()), v(v1.Taille()), v_sans(v1.Taille()) 

  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(v1(3).Dimension()); v(3) = v1(3); 
       case 2: v(2).Change_dim(v1(2).Dimension()); v(2) = v1(2); 
       case 1: v(1).Change_dim(v1(1).Dimension()); v(1) = v1(1); 
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseB::BaseB (int dim,const Tableau<CoordonneeB > & v1)";
           Sortie(1);
          } 
     };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// defini une Base locale absolu en dimension dim de n vecteurs   
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::BaseB (int dim,int n) :
   dimension(dim) , nb_vecteur(n), v(n), v_sans(n)  
  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(dimension); v(3)(3) = 1.; 
       case 2: v(2).Change_dim(dimension); v(2)(2) = 1.; 
       case 1: v(1).Change_dim(dimension); v(1)(1) = 1.; 
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseB::BaseB (int dim,int n)";
           Sortie(1);
          } 
     };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// idem dessus mais avec toutes les composantes = s    
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::BaseB (int dim,int n,double s) :
   dimension(dim) , nb_vecteur(n), v(n) , v_sans(n) 
  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(dimension);  
       case 2: v(2).Change_dim(dimension);  
       case 1: v(1).Change_dim(dimension);  
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseB::BaseB (int dim,int n,double s)";
           Sortie(1);
          } 
     };
    if (s != 0.)
      for (int i=1; i<=nb_vecteur;i++)
         for (int j =1; j<= dimension; j++)
            v(i)(j) = s;  
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// DESTRUCTEUR :
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::~BaseB ()
  { };
 
// constructeur de copie 
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::BaseB (const BaseB & b) :
   dimension(b.dimension) , nb_vecteur(b.nb_vecteur), v(b.v), v_sans(b.v_sans)    
  { // on va définir les v_sans associé, stocké au même endroit
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  } ; 
   
// defini une Base relative v1(dim) de n vecteurs
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB::BaseB (int dim,int n,const Tableau<CoordonneeB> & v1) :
   dimension(dim) , nb_vecteur(n), v(n), v_sans(n)  
   {
     #ifdef MISE_AU_POINT
     if (nb_vecteur > v1.Taille())
        { cout << "\nErreur : la taille relative est > a la taille du tableau  !\n";
          cout << " nb_vevteur = " << nb_vecteur
           << " v1.Taille = " << v1.Taille() << '\n';
          cout << "BaseB::BaseB (int dim,int n,Tableau<CoordonneeB >  v1) \n";
          Sortie(1);
        };
     #endif 
     switch (nb_vecteur)
      { case 3: v(3).Change_dim(v1(3).Dimension()); v(3) = v1(3);
        case 2: v(2).Change_dim(v1(2).Dimension()); v(2) = v1(2);
        case 1: v(1).Change_dim(v1(1).Dimension()); v(1) = v1(1);
        break;
        default:
          { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                 << "\n BaseB::BaseB (int dim,int n)";
            Sortie(1);
          };
      };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// surcharge de l'affectation
#ifndef MISE_AU_POINT
  inline 
#endif
BaseB & BaseB::operator = (const BaseB & aB)
  { dimension = aB.dimension;
    nb_vecteur = aB.nb_vecteur;
    // on affecte directement
    v = aB.v; // il y aura redimentionnement automatique
    // on va définir les v_sans associé, stocké au même endroit
    v_sans.Change_taille(aB.v_sans.Taille());
    Meme_place_coordonnee();
    return *this;   
  };

#ifndef MISE_AU_POINT
  inline 
#endif
const CoordonneeB & BaseB::operator () (int i) const
  {
     #ifdef MISE_AU_POINT
       if  ((i < 1) || (i > dimension))
        { cout << "\nErreur : composante inexistante !\n";
          cout << " i = " << i << '\n';
          cout << "BaseB::OPERATOR() (int ) const \n";
          Sortie(1);
        };
     #endif
     return v(i); 
  }; 
    
#ifndef MISE_AU_POINT
  inline 
#endif
CoordonneeB&  BaseB::CoordoB(int i)    // retourne  le i ieme vecteurs en I/O
  {
    #ifdef MISE_AU_POINT
    if  ((i < 1) || (i > dimension))
       { cout << "\nErreur : composante inexistante !\n";
         cout << " i = " << i << '\n';
         cout << "BaseB::CoordoB(i) \n";
         Sortie(1);
       };
    #endif 
    return v(i);
  };   

// acces contrôlé à des vecteurs sans variance: uniquement en lecture
#ifndef MISE_AU_POINT
  inline 
#endif
const Coordonnee & BaseB::Coordo(int i) const 
  {
#ifdef MISE_AU_POINT	 	 
	 if  ((i < 1) || (i > dimension))
			{ cout << "\nErreur : composante inexistante !\n";
			  cout << " i = " << i << '\n';
			  cout << "BaseB::Coordo(int i) \n";
			  Sortie(1);
			};
#endif
     // on est obligé d'appliquer Meme_place, car comme on peut accèder directement à v,
     // et que via les opérations sur v, on peut changer son pointeur!!
     // dans le cas où c'est déjà à la même place, il n'y a aucune action (juste un test)
     // donc normalement ce n'est pas "trop" couteux, en tout cas c'est moins que de créer
     // un coordonnee intermédiaire.
     v_sans(i).Meme_place(v(i));  
     return v_sans(i); 
  };

// affichage à l'écran des infos
#ifndef MISE_AU_POINT
  inline
#endif
void BaseB::Affiche() const
  { // écriture du type, de la dimension et du nombre de vecteur
    cout << "\n BaseB  dimension: " << dimension << " nombre de vecteurs : " << nb_vecteur << " ";
    // les data
    cout << "\n les vecteurs de la base: ";
    v.Sortir_sansRet(cout);
   
  };

    // changement de base
    // on suppose que this(i) correspond aux coordonnées dans un premier repère I_a
    // IpH correspond aux coordonnées dans I_a d'un nouveau repère
    // en sortie: apB(i) correspond aux coordonnées dans ipB de this(i)
#ifndef MISE_AU_POINT
  inline
#endif
void BaseB::Change_repere(const BaseH& IpH, BaseB& apB)
 {
  #ifdef MISE_AU_POINT
  if  (dimension != IpH.Dimension())
     { cout << "\nErreur : dimension de this "<< dimension
            << " est differente de celle de la nouvelle base  " << IpH.Dimension()
            << " !\n";
       cout << "BaseB::Change_repere(... \n";
       Sortie(1);
     };
  if  (nb_vecteur != apB.NbVecteur())
     { cout << "\nErreur : le nombre de vecteur de this "<< nb_vecteur
            << " est different de celui de la base que l'on cherche a calculer " << apB.NbVecteur()
            << " !\n";
       cout << "BaseB::Change_repere(... \n";
       Sortie(1);
     };
  #endif
  for (int i=1;i<= nb_vecteur;i++)
   for (int j=1;j<=dimension;j++)
    apB.CoordoB(i)(j) = v(i) * IpH(j);
 };

    // affectation trans_variance: utile pour une recopie de mêmes valeurs
    // mais ici l'appel est explicite donc a priori on sait ce que l'on fait
    // il n'y a pas de redimensionnement, donc la dimension et le nombre des vecteurs
    // doivent être identiques
#ifndef MISE_AU_POINT
  inline
#endif
void BaseB::Affectation_trans_variance(const BaseH& aH)
  {
    #ifdef MISE_AU_POINT
      if  ((dimension != aH.Dimension()) || (nb_vecteur !=  aH.NbVecteur()))
       { cout << "\nErreur : dimension de this "<< dimension
              << " difference de celle de la base a affecter: " << aH.Dimension()
              << " ou nombre de vecteur de this " << nb_vecteur
              << " different de celle de la base a affecter: " << aH.NbVecteur()
              << " !\n";
         cout << "BaseB::Affectation_trans_variance(... \n";
         Sortie(1);
       };
    #endif
    // on affecte directement
    for (int i=1;i<=nb_vecteur;i++)
      v_sans(i) = aH.Coordo(i); // pas de redimensionnent car même dimension et même nombre
    //return *this;
   };


    // la méthode qui suit a pour objectif de calcul les vecteurs de la base naturelle finale
    // associée à un paramétrage cartésien initiale
    // donc soit  connue une base naturelle \hat g_i associée à un paramétrage theta^i
    // \hat g_i est représenté par les vecteurs de this, et représente la situation déformée
    // soit la base duale de g_i : gammaH^i = g^i c-à-d la base duale en situation non déformée
    // maintenant: si on considère les coordonnées initiales X^i on cherche
    // les vecteurs des bases naturelles associées à X^i avant g'_i et après déformation \hat g'_i
    // on a (cf. annexe dans le document théorique d'Herezh)
    // g'_i = I_i par définition et
    // \hat g'_i =  (\vec I_i . \vec g^j) ~\hat g_j c-a-d
    // \hat g'_i = gammaH^j(i) * (*this)(j)
    // c'est le résultat de la méthode qui suit

    // si

// changement de base: retourne apB(a) = (*this)(j) . gamma^j_a
    // il faut que le nombre de vecteur de apB soit identique à la dimension de gammaH
    // et que le nombre de vecteur de gammaH soit identique au nombre de vecteur de this
    // et que la dimension de apB soit identique à la dimension de this
#ifndef MISE_AU_POINT
  inline 
#endif
void BaseB::ChangeBase_theta_vers_Xi(BaseB& apB, const BaseH& gammaH)
{ int apB_nbVecteur = apB.NbVecteur();
  #ifdef MISE_AU_POINT
   if (apB.Dimension()!= dimension)
    { cout << "\n erreur en changement de base , la dimension des vecteurs de la base resultante "
           << apB.Dimension() << " est differente de celle initiale " << dimension
           << "\n BaseB::ChangeBase_theta_vers_Xi(BaseB& apB, const BaseH& gammaH)";
      Sortie(1);
    };
   if (gammaH.NbVecteur()!= nb_vecteur)
   	{ cout << "\n erreur en changement de base , le nombre de vecteur de this et gammaH est different"
   	       << "\n BaseB::ChangeBase_theta_vers_Xi(BaseB& apB, const BaseH& gammaH)";
   	  Sortie(1);     
   	};
  #endif
  for (int a=1; a<= apB_nbVecteur; a++)
  	{apB.CoordoB(a).Zero();
  	 for (int j=1;j<= nb_vecteur; j++)
      apB.CoordoB(a) += gammaH(j)(a) * v(j);
  	}; 		
};


    // calcul des composantes de coordonnées locales  dans la base absolue
    // en argument : A -> une reference sur les coordonnées résultat qui peut avoir une dimension
    // différente des coordonnées locale,  retour d'une reference sur A
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee & BaseB::BaseAbsolue(Coordonnee & A,const CoordonneeH & B)  const
 {
  #ifdef MISE_AU_POINT
   if (B.Dimension()!= nb_vecteur)
   	{ cout << "\n erreur, le nombre de vecteur de la base: " << nb_vecteur << ",  est different du nombre de coordonnee "
           << " de B : "<< B.Dimension()
   	       << "\n BaseB::BaseAbsolue(Coordonnee & A,const CoordonneeH & B)";
   	  Sortie(1);     
   	};
   if (A.Dimension()!= dimension )
   	{ cout << "\n erreur, la dimension de A : " << A.Dimension() << ",  est differente de la dimension "
           << " des vecteurs de la base  : "<< dimension
   	       << "\n BaseB::BaseAbsolue(Coordonnee & A,const CoordonneeH & B)";
   	  Sortie(1);     
   	};
  #endif
   A.Zero();
   for (int i=1; i<=nb_vecteur;i++)
      A += B(i) * v_sans(i);
   return A;
 };

// une partie des vecteurs de B est affectée à this, 
// si this contient plus de vecteur que B, les autres vecteurs sont mis à 0 ou non
// suivant la valeur de  plusZero: = false: les autres vecteurs  sont inchangées, 
// plusZero = true: les autres vecteurs sont mis à 0 
#ifndef MISE_AU_POINT
  inline 
#endif
void BaseB::Affectation_partielle(int nb_vecteur_a_affecter, const BaseB & B,bool plusZero)
{ // on commence par vérifier si tout est ok (en débug)
  #ifdef MISE_AU_POINT
	 if ((nb_vecteur_a_affecter > nb_vecteur) || (nb_vecteur_a_affecter > B.nb_vecteur))
	  {cout << "\n*** affectation partielle impossible: nb_vecteur_a_affecter = "<< nb_vecteur_a_affecter
			      << " et nb_vecteur = " << nb_vecteur << " et B.nb_vecteur = " << B.nb_vecteur
			      << "\n BaseB::Affectation_partielle(int nb_vecteur_a_affecter,... ";
	   Sortie(1);
   };  
  #endif
  switch (nb_vecteur_a_affecter) 
   { case 3: v(3) = B.v(3);
	    case 2: v(2) = B.v(2);
	    case 1: v(1) = B.v(1);
	  };
  if ((plusZero) && (nb_vecteur_a_affecter < nb_vecteur))
   { switch (nb_vecteur)
    { case 3: {switch (nb_vecteur_a_affecter) { case 1: v(2).Zero(); case 2: v(3).Zero();}break;}
      case 2: {switch (nb_vecteur_a_affecter) {case 1: v(2).Zero();} break;}
	   };
   };

};  

// surcharge de l'operateur de lecture
#ifndef MISE_AU_POINT
  inline 
#endif
istream & operator >> ( istream & ent, BaseB & ba)
  { // lecture du type et vérification
    string nomtype; ent >> nomtype;
    if (nomtype != "BaseB")
      { Sortie(1);
        return ent;
       } 
    // lecture de la dimension et du nombre de vecteur
    ent >> ba.dimension >> ba.nb_vecteur ;
    // les data 
    ba.v.Entree(ent);
    // on met à la même place les v_sans que les v
    ba.v_sans.Change_taille(ba.v.Taille());
    ba.Meme_place_coordonnee();
    return ent;      
  };

// surcharge de l'operateur d'ecriture
#ifndef MISE_AU_POINT
  inline 
#endif
ostream & operator << ( ostream & sort,const  BaseB & ba)
  { // écriture du type, de la dimension et du nombre de vecteur
    sort << "BaseB  " << ba.dimension << " " << ba.nb_vecteur << " ";
    // les data
    ba.v.Sortir_sansRet(sort); 
//    sort << ba.v; 
    return sort;      
  };
  
//----------------------------- fonctions internes protégées ---------------
// on met à la même place les v_sans que les v
#ifndef MISE_AU_POINT
  inline 
#endif
void BaseB::Meme_place_coordonnee()
  { switch (nb_vecteur) 
     { case 3: v_sans(3).Meme_place(v(3));
       case 2: v_sans(2).Meme_place(v(2));    
       case 1: v_sans(1).Meme_place(v(1));    
     };
   };

 
//===============================================================
// Les base duales
//===============================================================
    
    
    // CONSTRUCTEURS :
// par defaut, defini la Base absolu en dimension 3    
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::BaseH ()  : 
  dimension(3), nb_vecteur(3), v(3) , v_sans(3)
  { v(1).Change_dim(3); v(1)(1) = 1.;   
    v(2).Change_dim(3); v(2)(2) = 1.;   
    v(3).Change_dim(3); v(3)(3) = 1.;   
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// defini la Base absolu en dimension dim    
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::BaseH (int dim) :
   dimension(dim) , nb_vecteur(dim), v(dim), v_sans(dim)  
  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(dimension); v(3)(3) = 1.; 
       case 2: v(2).Change_dim(dimension); v(2)(2) = 1.; 
       case 1: v(1).Change_dim(dimension); v(1)(1) = 1.; 
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseH::BaseH (int dim)";
           Sortie(1);
          } 
     };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// defini une Base relative v1(dim) 
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::BaseH (int dim,const Tableau<CoordonneeH >& v1) :
   dimension(dim) ,nb_vecteur(v1.Taille()), v(v1.Taille()), v_sans(v1.Taille()) 

  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(v1(3).Dimension()); v(3) = v1(3); 
       case 2: v(2).Change_dim(v1(2).Dimension()); v(2) = v1(2); 
       case 1: v(1).Change_dim(v1(1).Dimension()); v(1) = v1(1); 
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseH::BaseH (int dim,const Tableau<CoordonneeH > & v1)";
           Sortie(1);
          } 
     };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// defini une Base locale absolu en dimension dim de n vecteurs   
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::BaseH (int dim,int n) :
   dimension(dim) , nb_vecteur(n), v(n), v_sans(n)  
  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(dimension); v(3)(3) = 1.; 
       case 2: v(2).Change_dim(dimension); v(2)(2) = 1.; 
       case 1: v(1).Change_dim(dimension); v(1)(1) = 1.; 
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseH::BaseH (int dim,int n)";
           Sortie(1);
          } 
     };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// idem dessus mais avec toutes les composantes = s    
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::BaseH (int dim,int n,double s) :
   dimension(dim) , nb_vecteur(n), v(n) , v_sans(n) 
  { switch (nb_vecteur) 
     { case 3: v(3).Change_dim(dimension);  
       case 2: v(2).Change_dim(dimension);  
       case 1: v(1).Change_dim(dimension);  
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseH::BaseH (int dim,int n,double s)";
           Sortie(1);
          } 
     };
    if (s != 0.)
      for (int i=1; i<=nb_vecteur;i++)
         for (int j =1; j<= dimension; j++)
            v(i)(j) = s;  
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };
    
// DESTRUCTEUR :
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::~BaseH ()
  { };
 
// constructeur de copie 
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::BaseH (const BaseH & b) :
   dimension(b.dimension) , nb_vecteur(b.nb_vecteur), v(b.v), v_sans(b.v_sans)    
  { // on va définir les v_sans associé, stocké au même endroit
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  } ; 
   
// defini une Base relative v1(dim) de n vecteurs
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH::BaseH (int dim,int n,const Tableau<CoordonneeH > & v1) :
   dimension(dim) , nb_vecteur(n), v(n), v_sans(n)  
   {
     #ifdef MISE_AU_POINT
      if (nb_vecteur > v1.Taille())
			{ cout << "\nErreur : la taille relative est > a la taille du tableau  !\n";
			  cout << " nb_vevteur = " << nb_vecteur 
			   << " v1.Taille = " << v1.Taille() << '\n';
			  cout << "BaseH::BaseH (int dim,int n,Tableau<CoordonneeH >  v1) \n";
			  Sortie(1);
			};
     #endif 
    switch (nb_vecteur) 
     { case 3: v(3).Change_dim(v1(3).Dimension()); v(3) = v1(3); 
       case 2: v(2).Change_dim(v1(2).Dimension()); v(2) = v1(2); 
       case 1: v(1).Change_dim(v1(1).Dimension()); v(1) = v1(1); 
       break; 
       default:
         { cout << "\n ** erreur en dimensionnement d'une base, le nombre de vecteur = 0"
                << "\n BaseH::BaseH (int dim,int n)";
           Sortie(1);
          } 
     };
    // on va définir les v_sans associé, stocké au même endroit
    Meme_place_coordonnee();
  };

// surcharge de l'affectation
#ifndef MISE_AU_POINT
  inline 
#endif
BaseH & BaseH::operator = (const BaseH & aH)
  { dimension = aH.dimension;
    nb_vecteur = aH.nb_vecteur;
    // on affecte directement
    v = aH.v; // il y aura redimentionnement automatique
    // on va définir les v_sans associé, stocké au même endroit
    v_sans.Change_taille(aH.v_sans.Taille());
    Meme_place_coordonnee();
    return *this;   
   };

#ifndef MISE_AU_POINT
  inline 
#endif
const CoordonneeH & BaseH::operator () (int i) const
  {
#ifdef MISE_AU_POINT	 	 
	 if  ((i < 1) || (i > dimension))
			{ cout << "\nErreur : composante inexistante !\n";
			  cout << " i = " << i << '\n';
			  cout << "BaseH::OPERATOR() (int i) const \n";
			  Sortie(1);
			};
#endif 
     return v(i); 
  };   
#ifndef MISE_AU_POINT
  inline 
#endif
CoordonneeH&  BaseH::CoordoH(int i)    // retourne  le i ieme vecteurs en I/0
  {
    #ifdef MISE_AU_POINT
    if  ((i < 1) || (i > dimension))
      { cout << "\nErreur : composante inexistante !\n";
        cout << " i = " << i << '\n';
        cout << "BaseH::CoordoH(i)  \n";
        Sortie(1);
      };
    #endif
    return v(i);
  }; 

// acces contrôlé à des vecteurs sans variance: uniquement en lecture
#ifndef MISE_AU_POINT
  inline 
#endif
const Coordonnee & BaseH::Coordo(int i) const 
  {
#ifdef MISE_AU_POINT	 	 
	 if  ((i < 1) || (i > dimension))
			{ cout << "\nErreur : composante inexistante !\n";
			  cout << " i = " << i << '\n';
			  cout << "BaseH::Coordo(int i) \n";
			  Sortie(1);
			};
#endif 
     // on est obligé d'appliquer Meme_place, car comme on peut accèder directement à v,
     // et que via les opérations sur v, on peut changer son pointeur!!
     // dans le cas où c'est déjà à la même place, il n'y a aucune action (juste un test)
     // donc normalement ce n'est pas "trop" couteux, en tout cas c'est moins que de créer
     // un coordonnee intermédiaire.
     v_sans(i).Meme_place(v(i));  
     return v_sans(i); 
  };

    // affectation trans_variance: utile pour une recopie de mêmes valeurs
    // mais ici l'appel est explicite donc a priori on sait ce que l'on fait
    // il n'y a pas de redimensionnement, donc la dimension et le nombre des vecteurs
    // doivent être identiques
#ifndef MISE_AU_POINT
  inline
#endif
void BaseH::Affectation_trans_variance(const BaseB& aB)
  {
    #ifdef MISE_AU_POINT
      if  ((dimension != aB.Dimension()) || (nb_vecteur !=  aB.NbVecteur()))
       { cout << "\nErreur : dimension de this "<< dimension
              << " difference de celle de la base a affecter: " << aB.Dimension()
              << " ou nombre de vecteur de this " << nb_vecteur
              << " different de celle de la base a affecter: " << aB.NbVecteur()
              << " !\n";
         cout << "BaseH::Affectation_trans_variance(... \n";
         Sortie(1);
       };
    #endif
    // on affecte directement
    for (int i=1;i<=nb_vecteur;i++)
      v_sans(i) = aB.Coordo(i); // pas de redimensionnent car même dimension et même nombre
    //return *this;
   };


// affichage à l'écran des infos
#ifndef MISE_AU_POINT
  inline
#endif
void BaseH::Affiche() const
  { // écriture du type, de la dimension et du nombre de vecteur
    cout << "\n BaseH  dimension: " << dimension << " nombre de vecteurs : " << nb_vecteur << " ";
    // les data
    cout << "\n les vecteurs de la base: ";
    v.Sortir_sansRet(cout);
   
  };

    // changement de base
    // on suppose que this(i) correspond aux coordonnées dans un premier repère I_a
    // IpB correspond aux coordonnées dans I_a d'un nouveau repère
    // en sortie: apH(i) correspond aux coordonnées dans ipH de this(i)
#ifndef MISE_AU_POINT
  inline
#endif
void BaseH::Change_repere(const BaseB& IpB, BaseH& apH)
 {
  #ifdef MISE_AU_POINT
  if  (dimension != IpB.Dimension())
     { cout << "\nErreur : dimension de this "<< dimension
            << " est differente de celle de la nouvelle base  " << IpB.Dimension()
            << " !\n";
       cout << "BaseH::Change_repere(... \n";
       Sortie(1);
     };
  if  (nb_vecteur != apH.NbVecteur())
     { cout << "\nErreur : le nombre de vecteur de this "<< nb_vecteur
            << " est different de celui de la base que l'on cherche a calculer " << apH.NbVecteur()
            << " !\n";
       cout << "BaseH::Change_repere(... \n";
       Sortie(1);
     };
  #endif
  for (int i=1;i<= nb_vecteur;i++)
   for (int j=1;j<=dimension;j++)
    apH.CoordoH(i)(j) = v(i) * IpB(j);
 };

    // la méthode qui suit a pour objectif de calcul les vecteurs de la base naturelle finale
    // associée à un paramétrage cartésien initiale
    // donc soit  connue une base duale \hat g^i associée à un paramétrage theta^i
    // \hat g^i est représenté par les vecteurs de this, et représente la situation déformée
    // soit la base naturel de g_i : betaB_i = g_i c-à-d la base naturelle en situation non déformée
    // maintenant: si on considère les coordonnées initiales X^i on cherche
    // les vecteurs des bases duales associées à X^i avant g'^i et après déformation \hat g'^i
    // on a (cf. annexe dans le document théorique d'Herezh)
    // g'^i = g'_i =  I_i = I^i par définition et
    // \hat g'^i =  (\vec I_i . \vec g_j) ~\hat g^j c-a-d
    // \hat g'^i = betaB^j(i) * (*this)(j)
    // c'est le résultat de la méthode qui suit

// changement de base: retourne apH(a) = (*this)(j) . beta_j^a
    // il faut que le nombre de vecteur de apH soit identique à la dimension de betaB
    // et que le nombre de vecteur de betaB soit identique au nombre de vecteur de this
    // et que la dimension de apB soit identique à la dimension de this
#ifndef MISE_AU_POINT
  inline 
#endif
void BaseH::ChangeBase_theta_vers_Xi(BaseH& apH, const BaseB& betaB)
{ int apH_nbVecteur = apH.NbVecteur();
  #ifdef MISE_AU_POINT
   if (apH.Dimension()!= dimension)
    { cout << "\n erreur en changement de base , la dimension des vecteurs de la base resultante "
           << apH.Dimension() << " est differente de celle initiale " << dimension
           << "\n BaseH::ChangeBase_theta_vers_Xi(BaseH& apH, const BaseB& gammaB)";
      Sortie(1);
    };
   if (betaB.NbVecteur()!= nb_vecteur)
   	{ cout << "\n erreur en changement de base , le nombre de vecteur de this et betaB est different"
   	       << "\n BaseH::ChangeBase_theta_vers_Xi(BaseB& apH, const BaseH& betaB)";
   	  Sortie(1);     
   	};
  #endif
  for (int a=1; a<= apH_nbVecteur; a++)
  	{apH.CoordoH(a).Zero();
  	 for (int j=1;j<= nb_vecteur; j++)
      apH.CoordoH(a) += betaB(j)(a) * v(j);
  	}; 		
};


    // calcul des composantes de coordonnées locales  dans la base absolue
    // en argument : A -> une reference sur les coordonnées résultat qui peut avoir une dimension
    // différente des coordonnées locale,  retour d'une reference sur A
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee & BaseH::BaseAbsolue(Coordonnee & A,const CoordonneeB & B)  const
 {
  #ifdef MISE_AU_POINT
   if (B.Dimension()!= nb_vecteur)
   	{ cout << "\n erreur, le nombre de vecteur de la base: " << nb_vecteur << ",  est different du nombre de coordonnee "
           << " de B : "<< B.Dimension()
   	       << "\n BaseH::BaseAbsolue(Coordonnee & A,const CoordonneeB & B)";
   	  Sortie(1);     
   	};
   if (A.Dimension()!= dimension )
   	{ cout << "\n erreur, la dimension de A : " << A.Dimension() << ",  est differente de la dimension "
           << " des vecteurs de la base  : "<< dimension
   	       << "\n BaseH::BaseAbsolue(Coordonnee & A,const CoordonneeB & B)";
   	  Sortie(1);     
   	};
  #endif
   A.Zero();
   for (int i=1; i<=nb_vecteur;i++)
      A += B(i) * v_sans(i);
   return A;
 };

// une partie des vecteurs de B est affectée à this,
// si this contient plus de vecteur que B, les autres vecteurs sont mis à 0 ou non
// suivant la valeur de  plusZero: = false: les autres vecteurs  sont inchangées, 
// plusZero = true: les autres vecteurs sont mis à 0 
#ifndef MISE_AU_POINT
  inline 
#endif
void BaseH::Affectation_partielle(int nb_vecteur_a_affecter, const BaseH & B,bool plusZero)
{ // on commence par vérifier si tout est ok (en débug)
#ifdef MISE_AU_POINT
	if ((nb_vecteur_a_affecter > nb_vecteur) || (nb_vecteur_a_affecter > B.nb_vecteur))
	{cout << "\n*** affectation partielle impossible: nb_vecteur_a_affecter = "<< nb_vecteur_a_affecter
			<< " et nb_vecteur = " << nb_vecteur << " et B.nb_vecteur = " << B.nb_vecteur 
			<< "\n BaseH::Affectation_partielle(int nb_vecteur_a_affecter,... ";
	 Sortie(1);		 
   };  
#endif
  switch (nb_vecteur_a_affecter) 
   { case 3: v(3) = B.v(3);
	  case 2: v(2) = B.v(2);
	  case 1: v(1) = B.v(1);
	};
 if ((plusZero) && (nb_vecteur_a_affecter < nb_vecteur))
  { switch (nb_vecteur)
    { case 3: {switch (nb_vecteur_a_affecter) { case 1: v(2).Zero(); case 2: v(3).Zero();}break;}
      case 2: {switch (nb_vecteur_a_affecter) {case 1: v(2).Zero();} break;}
	 };
  };	 	

};  

// surcharge de l'operateur de lecture
#ifndef MISE_AU_POINT
  inline 
#endif
istream & operator >> ( istream & ent, BaseH & ba)
  { // lecture du type et vérification
    string nomtype; ent >> nomtype;
    if (nomtype != "BaseH")
      { Sortie(1);
        return ent;
       } 
    // lecture de la dimension et du nombre de vecteur
    ent >> ba.dimension >> ba.nb_vecteur ;
    // on met à la même place les v_sans que les v
    ba.v_sans.Change_taille(ba.v.Taille());
    ba.Meme_place_coordonnee();
    ent >> ba.v;
    return ent;      
  };

// surcharge de l'operateur d'ecriture
#ifndef MISE_AU_POINT
  inline 
#endif
ostream & operator << ( ostream & sort,const  BaseH & ba)
  { // écriture du type, de la dimension et du nombre de vecteur
    sort << "BaseH  " << ba.dimension << " " << ba.nb_vecteur << " ";
    // les data
//    ba.v.Sortir_sansRet(sort); 
    sort << ba.v; 
    return sort;      
  };
  
//----------------------------- fonctions internes protégées ---------------
// on met à la même place les v_sans que les v
#ifndef MISE_AU_POINT
  inline 
#endif
void BaseH::Meme_place_coordonnee()
  { switch (nb_vecteur) 
     { case 3: v_sans(3).Meme_place(v(3));
       case 2: v_sans(2).Meme_place(v(2));    
       case 1: v_sans(1).Meme_place(v(1));    
     };
   };



#endif
