// FICHIER : Coordonnee.cc
// CLASSE : Coordonnee

// 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 <iostream>
using namespace std;  //introduces namespace std
#include <stdlib.h>
#include "Sortie.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include <iomanip>
#include "ParaGlob.h"
#include <limits>


#include "Coordonnee.h"

#ifndef  COORDONNEE_H_deja_inclus

// Constructeur par defaut 
// avant ->// N.B. : la dimension est affectee a 3 et les valeurs a 0	
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::Coordonnee () :
  dim (0) , coord (NULL),memoire(true)
{};

// Constructeur utile si le nombre de coordonnees est connue
// N.B. : les valeurs sont affectees a 0.
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::Coordonnee (int dimension) :
 dim ((short)dimension), memoire(true),coord (NULL)
{  if (dim == 0) return;
    #ifdef MISE_AU_POINT	
	  if ( (dimension<0) || (dimension>3) )
	   {
     cout << "\nErreur de dimension !\n";
     cout << "COORDONNEE::COORDONNEE (int ) \n";
     Sortie(1);
	   };
    #endif
	  coord=new double [dim];
    switch (dim)
    	{case 3:  coord[2]=0.0;
    	 case 2:  coord[1]=0.0;
    	 case 1:  coord[0]=0.0;
    	};		
};

// Constructeur pour un point a une dimension
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::Coordonnee (double x) :
 dim (1),memoire(true)
{	coord=new double [1];
	 coord[0]=x;
};

// Constructeur pour un point a deux dimensions
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::Coordonnee (double x,double y) :
 dim (2),memoire(true)
{	coord=new double [2];
	 coord[0]=x;
	 coord[1]=y;
};	

// Constructeur pour un point a trois dimensions
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::Coordonnee (double x,double y,double z) :
 dim (3) ,memoire(true)
{	coord=new double [3];
	 coord[0]=x;
	 coord[1]=y;
	 coord[2]=z;	
};

// constructeur fonction d'une adresse memoire ou sont stockee les coordonnees
// et d'une dimension ( l'existance de la place mémoire est a la charge
//  de l'utilisateur.
// DANS CE CAS IL N'Y A  PAS DE CREATION DE MEMOIRE !!
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::Coordonnee (int dimension,double* t) :
 dim ((short) dimension),coord (t),memoire(false)
  {};  						

// Constructeur de copie
// mais là on construit systématiquement un vrai coordonnée
// même si la mémoire est fausse, car on ne veut pas que plusieur
// coordonnée pointes sur les mêmes valeurs, sans précautions supplémentaires
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::Coordonnee (const Coordonnee& c) :
 dim (c.dim),memoire(true)
{ if ( dim==0 )
		coord=NULL;
	else
		// copie des coordonnees
	{	coord=new double [dim];
        switch (dim)
   	    {case 3:  coord[2]=c.coord[2];
   	     case 2:  coord[1]=c.coord[1];
   	     case 1:  coord[0]=c.coord[0];
       	};
	};		
};

// Destructeur
// Desallocation de la place memoire allouee
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee::~Coordonnee ()
{if (memoire)
   { if  (dim > 0) 
	  { delete [] coord;
	    coord=NULL;
	    dim=0;
	   }
    #ifdef MISE_AU_POINT
 else
  {if ( coord!=NULL )
  		{	cout << "\nErreur de liberation de la place memoire\n";
  			cout << "COORDONNEE::LIBERE () \n";
  			Sortie(1);
  		 }
  	}	
    #endif
    }
};

// fonction équivalente au constructeur: changement pour une place externe via un pointeur
// ( l'existance de la place mémoire est a la charge
//  de l'utilisateur et ne sera pas détruite par le destructeur.)
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Change_place(int dimension,double* t)
 { // on commence par libérer la place
   Libere();
   // création en fonction de la dimension
   dim = dimension;
   switch (dim)
   	{ case 0: memoire = true; break; // on met à true, car de toute manière il n'y a pas de mémoire
   	  case 1: case 2: case 3: { memoire = false; coord = t; break;} // cas normal
      default:
       	{ cout << "\n erreur la dimension n'est entre 0 et 3 : " << dimension
       	       << "\n Coordonnee::Change_place(int dimension,double* t)";
       	  Sortie(1);
       	 }
   	};
 };

// changement des coordonnees
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Change_Coordonnee(int dimension, double x)	  // dimension 1					
{ if (dim == dimension) { coord[0] = x; }
  else { Change_dim(dimension); coord[0] = x; };
};

// changement des coordonnees
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Change_Coordonnee(int dimension, double x,double y)	  // dimension 2					
{  if (dim != dimension) Change_dim(dimension);
   coord[0] = x; coord[1] = y;
};

// changement des coordonnees
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Change_Coordonnee(int dimension, double x,double y,double z)	  // dimension 3					
{  if (dim != dimension) Change_dim(dimension);
   coord[0] = x; coord[1] = y; coord[2] = z;
};

// Renvoie le nombre de coordonnees
#ifndef MISE_AU_POINT
  inline 
#endif
int Coordonnee::Dimension () const 
   {	return dim; };
				
// Desallocation de la place memoire allouee
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Libere ()
{if (memoire)
   { if  (dim > 0) 
	  { delete [] coord;
	    coord=NULL;
	    dim=0;
	   }
   };
 coord=NULL;
 dim=0; 	
};		

// Renvoie la ieme coordonnee
#ifndef MISE_AU_POINT
  inline 
#endif
double& Coordonnee::operator() (int i)
	{
       #ifdef MISE_AU_POINT
		 if ( (i<1) || (i>dim) )
			{   cout << "\nErreur de dimension !\n";
				cout << "COORDONNEE::OPERATOR() (int ) \n";
				Sortie(1);
			};
       #endif
	   return coord[i-1];
	};
	
// Renvoie une copie de la ieme coordonnee
#ifndef MISE_AU_POINT
  inline 
#endif
double Coordonnee::operator() (int i) const 
	{
       #ifdef MISE_AU_POINT
		 if ( (i<1) || (i>dim) )
			{   cout << "\nErreur de dimension !\n";
				cout << "COORDONNEE::OPERATOR() (int ) \n";
				Sortie(1);
			};
       #endif
	   return coord[i-1];
	};

// changement de la dimension
// dans le cas d'une nouvelle dimension inferieur on supprime les dernieres coord
// dans le cas d'une dimension superieur, on ajoute des coord initialisees a zero`
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Change_dim(int dimen)
  { if (dimen == dim) return; // même dimension, on ne fait rien
    #ifdef MISE_AU_POINT
       if ((dimen<0) || (dimen>3))
         { cout << "\n erreur, la nouvelle dimension doit etre comprise entre 0 et 3 ! ";
           cout << "\n dim voulue = " << dimen ;
           cout << "\nCoordonnee::Change_dim(int dim) " << endl;
           Sortie(1);
          } 
    #endif
    
    double * sauve = coord;
    if (dimen == 0)
     { // comme on a déjà passé le cas où dimen == dim, cela veut dire que dim est non nulle
       Libere();
     }
    else if (dim < dimen) // cas où la nouvelle dimension est supérieur
      {// dans le cas où il n'y a pas eu allocation, donc que la mémoire n'est
       // pas gérée par l'objet, on ne peut pas changer de dimension
       if (!memoire)
        { cout << "\n erreur, l'objet ne gere pas sa memoire, donc le changement de dim "
               << " n'est pas possible !! ";
          cout << "\n dim voulue = " << dimen << " ancienne dimension: " << dim ;
          cout << "\nCoordonnee::Change_dim(int dim) " << endl;
          Sortie(1);
         };
        // donc pour la suite on considère que l'élément gère sa mémoire
        // les dimensions sont 1 ou 2 ou 3 
        // et le cas même dimension a déjà été réglé, donc ici il y a forcément 
        // une différence 
        if (dim ==0 ) // cas où rien n'exitait et dimen > 0
          { coord = new double [dimen]; dim = dimen;
            switch (dim)
             {case 3:  coord[2]=0.0;
              case 2:  coord[1]=0.0;
              case 1:  coord[0]=0.0;
              };		
      	   	}
         else // cas où dim est différent de 0
           {switch (dimen - dim)
             {case 2: // là obligatoirement: dimen=3 et dim = 1
               { coord = new double [dimen]; dim = (short)dimen;
                 coord[2]=0.;coord[1]=0.;coord[0]=sauve[0];
                 delete [] sauve;
                 break;
                }
              case 1: // dim ne peut avoir comme dimension que 2 ou 1
               { coord = new double [dimen];
                 switch (dim)
                  {case 2: // dimen = 3
                     { coord[2]=0.;coord[1]=sauve[1];coord[0]=sauve[0];
                        break;
                     }
       	  		       case 1: // dimen = 2
                    { coord[1]=0.;coord[0]=sauve[0];
                      break;
                    }
       	  		      };
                 dim = (short)dimen;
	               delete [] sauve;
       	  	    }
       	     };
           }
      }
    else if (dim > dimen) // nouvelle dimension non nulle, plus petite
      { coord = new double [dimen];
        switch (dimen)
         {case 3:  coord[2]=sauve[2];
          case 2:  coord[1]=sauve[1];
          case 1:  coord[0]=sauve[0];
         };
        if (dim > 0) delete [] sauve;
        dim = (short) dimen;
       }
  };
  
// Surcharge de l'operateur = : realise l'affectation entre deux points 
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee& Coordonnee::operator= (const Coordonnee& c)
{	if (dim==c.dim)
	    { switch (dim)
       	{case 3:  coord[2]=c.coord[2];
       	 case 2:  coord[1]=c.coord[1];
       	 case 1:  coord[0]=c.coord[0];
 //      	 case 0:   on ne fait rien
       	};
		     return (*this);
	    }
	 else if ( c.dim==0 )
	   { Libere();}
	 else
	   { if (!memoire)
        { cout << "\n erreur, l'objet ne gere pas sa memoire, donc le changement de dim "
               << " n'est pas possible !! ";
          cout << "\n dim voulue = " << c.dim << " ancienne dimension: " << dim ;
          cout << "\nCoordonnee::operator= (const Coordonnee& c) " << endl;
          Sortie(1);
        };

      #ifdef MISE_AU_POINT
      if (dim != 0)
          cout << "\n attention, on change la dimension du point !!!"
               << " de "<<dim<<" a "<<c.dim
               << " Coordonnee::operator= (const Coordonnee& c) " << endl;
      #endif
      Libere();
      dim=c.dim;
      coord=new double [dim];
      switch (dim)
         {case 3:  coord[2]=c.coord[2];
          case 2:  coord[1]=c.coord[1];
          case 1:  coord[0]=c.coord[0];
  //      	 case 0:   ne peut pas arriver
         };
    };
	 return (*this);			
};
  		

// Surcharge de l'operateur - : renvoie l'oppose d'un point
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee Coordonnee::operator- () const 
{	Coordonnee result(dim);
	switch (dim)
       	{case 3:  result.coord[2]=-coord[2];
       	 case 2:  result.coord[1]=-coord[1];
       	 case 1:  result.coord[0]=-coord[0];
       	 case 0: ; // on fait rien
       	};
    return result;   	
};
		
// Surcharge de l'operateur - : realise la soustraction des
// coordonnees de deux points
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee Coordonnee::operator- (const Coordonnee& c) const 
{ 
  #ifdef MISE_AU_POINT		
    if ( dim!=c.dim )
	{
		cout << "\nErreur : dimensions non egales !\n";
		cout << "COORDONNEE::OPERATOR- (Coordonnee ) \n";
		Sortie(1);
	};
  #endif
	Coordonnee result(dim);
	switch (dim)
       	{case 3:  result.coord[2]=coord[2]-c.coord[2];
       	 case 2:  result.coord[1]=coord[1]-c.coord[1];
       	 case 1:  result.coord[0]=coord[0]-c.coord[0];
       	 case 0: ; // on fait rien
       	};
    return result;   	
};

// Surcharge de l'operateur + : realise l'addition des 
// coordonnees de deux points
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee Coordonnee::operator+ (const Coordonnee& c) const 
{	
  #ifdef MISE_AU_POINT		
    if ( dim!=c.dim )
	{	cout << "\nErreur : dimensions non egales !\n";
		cout << "COORDONNEE::OPERATOR+ (Coordonnee ) \n";
		Sortie(1);
	};
  #endif
	Coordonnee result(dim);
	switch (dim)
       	{case 3:  result.coord[2]=coord[2]+c.coord[2];
       	 case 2:  result.coord[1]=coord[1]+c.coord[1];
       	 case 1:  result.coord[0]=coord[0]+c.coord[0];
       	 case 0: ; // on fait rien
       	};
	return result;		
};
		
// Surcharge de l'operateur += 
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::operator+= (const Coordonnee& c)
{
  #ifdef MISE_AU_POINT		
	if ( dim!=c.dim )
	{	cout << "\nErreur : dimensions non egales !\n";
		cout << "COORDONNEE::OPERATOR+= (Coordonnee ) \n";
		Sortie(1);
	};
  #endif
	switch (dim)
       	{case 3:  coord[2]+=c.coord[2];
       	 case 2:  coord[1]+=c.coord[1];
       	 case 1:  coord[0]+=c.coord[0];
       	 case 0: ; // on fait rien
       	};
};

// Surcharge de l'operateur -= 
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::operator-= (const Coordonnee& c)
{ 
  #ifdef MISE_AU_POINT		
   if ( dim!=c.dim )
	{   cout << "\nErreur : dimensions non egales !\n";
		cout << "COORDONNEE::OPERATOR-= (Coordonnee ) \n";
		Sortie(1);
	};
  #endif
	switch (dim)
       	{case 3:  coord[2]-=c.coord[2];
       	 case 2:  coord[1]-=c.coord[1];
       	 case 1:  coord[0]-=c.coord[0];
       	 case 0: ; // on fait rien
       	};
};

// Surcharge de l'operateur *= 
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::operator*= (double val)
{  switch (dim)
       	{case 3:  coord[2]*=val;
       	 case 2:  coord[1]*=val;
       	 case 1:  coord[0]*=val;
       	 case 0: ; // on fait rien
       	};
};	
// Surcharge de l'operateur * : multiplication de coordonnees par un scalaire
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee Coordonnee::operator* (double val) const 
{   Coordonnee result(dim);
	switch (dim)
       	{case 3:  result.coord[2]=val*coord[2];
       	 case 2:  result.coord[1]=val*coord[1];
       	 case 1:  result.coord[0]=val*coord[0];
       	 case 0: ; // on fait rien
       	};
	return result;
};
				
// Surcharge de l'operateur * : produit scalaire entre coordonnees 
#ifndef MISE_AU_POINT
  inline 
#endif
double Coordonnee::operator* (const Coordonnee& c) const 
{	double res=0.0;
	switch (dim)
       	{case 3:  res += coord[2] * c.coord[2];
       	 case 2:  res += coord[1] * c.coord[1];
       	 case 1:  res += coord[0] * c.coord[0];
       	 case 0: ; // on fait rien
       	};
	return res;	
};
		
// Surcharge de l'operateur / : division de coordonnees par un scalaire
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee Coordonnee::operator/ (double val) const 
 {
   #ifdef MISE_AU_POINT
    if(Dabs(val) <= ConstMath::trespetit)
    { cout << "\n erreur, division par zero ";
      cout << "\nCoordonnee::operator/ (double val) " << endl;
      Sortie (1);
     }
   #endif
    Coordonnee result(dim);
	switch (dim)
       	{case 3:  result.coord[2]=coord[2] / val;
       	 case 2:  result.coord[1]=coord[1] / val;
       	 case 1:  result.coord[0]=coord[0] / val;
       	 case 0: ; // on fait rien
       	};
	return result;
};
		
// Surcharge de l'operateur /= : division de coordonnees par un scalaire
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::operator/= (double val)
 {
  #ifdef MISE_AU_POINT
   if(Dabs(val) <= ConstMath::trespetit)
    { cout << "\n erreur, division par zero ";
      cout << "\nCoordonnee::operator/= (double val) " << endl;
      Sortie (1);
     }
  #endif
   switch (dim)
       	{case 3:  coord[2]/=val;
       	 case 2:  coord[1]/=val;
       	 case 1:  coord[0]/=val;
       	 case 0: ; // on fait rien
       	};
  };

// Surcharge de l'operateur == : test d'egalite 
// Renvoie 1 si les deux positions sont identiques
// Renvoie 0 sinon
#ifndef MISE_AU_POINT
  inline 
#endif
int Coordonnee::operator== (const Coordonnee& c) const 
		{   if ( c.dim!=dim )
				return 0;
			else
			{   for (int i=0;i<dim;i++)
				{	if ( c.coord[i]!=coord[i] )
						return 0;
				};
				return 1;
			};
		};
		
// Surcharge de l'operateur !=
// Renvoie 1 si les deux positions ne sont pas identiques
// Renvoie 0 sinon
#ifndef MISE_AU_POINT
  inline 
#endif
int Coordonnee::operator!= (const Coordonnee& c) const 
		{	if ( (*this)==c )
				return 0;
			else 
				return 1; 
		};
	
// Affiche les coordonnees du point à l'écran entre accolades
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Affiche () const 
		{ cout << "\t{  ";
          switch (dim)
           	{case 0: break; // on fait rien
           	 case 1:  cout << coord[0] << " "; break;
           	 case 2:  cout << coord[0] << " "<< coord[1] << " " ;break;
           	 case 3:  cout << coord[0] << " "<< coord[1] << " "<< coord[2] << " " ;break;
           	 };
			cout << "}\n";
		};

// Affiche les coordonnees du point dans sort entre accolades
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Affiche (ostream& sort) const 
{  sort << "\t{  " ;
   switch (dim)
       	{case 0: break; // on fait rien
       	 case 1:  sort << coord[0] << " "; break;
       	 case 2:  sort << coord[0] << " "<< coord[1] << " " ;break;
       	 case 3:  sort << coord[0] << " "<< coord[1] << " "<< coord[2] << " " ;break;
       	 };
   sort << "}\n" ;
};

// Affiche les coordonnees du point dans sort sur nb digit plus un blanc
// et rien d'autre
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Affiche (ostream& sort,int nb) const 
 {  switch (dim)
       	{case 0:  break; // on fait rien
       	 case 1:  sort << setprecision(nb) << coord[0] << " "; break;
       	 case 2:  sort << setprecision(nb) << coord[0] << " "
       	               << setprecision(nb) << coord[1] << " " ;break;
       	 case 3:  sort << setprecision(nb) << coord[0] << " "
                       << setprecision(nb) << coord[1] << " "
       	               << setprecision(nb) << coord[2] << " " ;break;
       	 };
  };
// Affiche les coordonnees du point dans sort
// et rien d'autre (pas d'accolade)
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Affiche_1(ostream& sort) const
{  switch (dim)
       	{case 0: break; // on fait rien
       	 case 1:  sort << coord[0] << " "; break;
       	 case 2:  sort << coord[0] << " "<< coord[1] << " " ;break;
       	 case 3:  sort << coord[0] << " "<< coord[1] << " "<< coord[2] << " " ;break;
       	 };
};


// mise a zero des coordonnées
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Zero() 
{    switch (dim)
        	{case 3:  coord[2]=0.;
        	 case 2:  coord[1]=0.;
        	 case 1:  coord[0]=0.;
       	     case 0: ; // on fait rien
        	};
};
   
// surcharge de l'operateur de lecture dans la mémoire
#ifndef MISE_AU_POINT
  inline 
#endif
// lecture brut des coordonnées sans la dimension
void Coordonnee::Lecture (UtilLecture& entreePrinc)
  { // 4mars2014 : suppression des deux lignes qui suivent qui ne servent à rien
    //int dim = Dimension (); // il n'y a jamais de dimension 0
    //this->Change_dim(dim);
    switch (dim)
      { case 3 : {*(entreePrinc.entree) >> coord[0] >> coord[1] >> coord[2] ; break;}
        case 2 : {*(entreePrinc.entree) >> coord[0] >> coord[1]  ; break;}
        case 1 : {*(entreePrinc.entree) >> coord[0]  ; break;}
      };
  };
  
// lecture brut des coordonnées sans la dimension dans le flux par défaut
#ifndef MISE_AU_POINT
  inline 
#endif
// lecture brut des coordonnées sans la dimension
void Coordonnee::Lecture ()
  { // 4mars2014 : suppression des deux lignes qui suivent qui ne servent à rien
    // int dim = Dimension (); // il n'y a jamais de dimension 0
    // this->Change_dim(dim);
    switch (dim)
      { case 3 : {cin >> coord[0] >> coord[1] >> coord[2] ; break;}
        case 2 : {cin >> coord[0] >> coord[1]  ; break;}
        case 1 : {cin >> coord[0]  ; break;}
      };
    std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
  };

// surcharge de l'operateur de lecture
#ifndef MISE_AU_POINT
  inline 
#endif
istream & operator >> ( istream & ent, Coordonnee & coo)
  { // lecture du type et vérification
    string nomtype; ent >> nomtype;
    if (nomtype != "Coordonnee")
      { cout << "\n *** erreur en lecture: on attendait le mot cle Coordonne et on a lue "
             << nomtype
             << "\n operator >> ( istream & ent, Coordonnee & coo)";
        Sortie(1);
        return ent;
      };
    // lecture de la dimension
	   int dim;
    ent >> nomtype >> dim;
	   // on redimensionne éventuellement la taille
    if (coo.dim != dim)
     { if (coo.memoire) // cas ou c'est un vrai point
         { if (coo.coord != NULL) { delete [] coo.coord;}
           coo.coord = new double [dim];
           coo.dim = dim;
         }
       else
         { cout << "\n erreur en lecture la dimension du point conteneur "<< dim << " est differente de celle lue	"
                << dim << " et memoire est faux, donc on ne peut pas changer la dimension "
                << "\n operator >> ( istream & ent, Coordonnee & coo) " << endl ;
           Sortie(2);
         };
	    };
    // les data 
    switch (coo.dim)
      { case 3 : {ent >> coo.coord[0] >> coo.coord[1] >> coo.coord[2] ; break;}
        case 2 : {ent >> coo.coord[0] >> coo.coord[1]  ; break;}
        case 1 : {ent >> coo.coord[0]  ; break;}
      	 case 0 : break; // on ne fait rien
      };
    return ent;      
  };

// surcharge de l'operateur d'ecriture
#ifndef MISE_AU_POINT
  inline 
#endif
ostream & operator << ( ostream & sort,const  Coordonnee & coo)
  { // écriture du type et de la dimension
    sort << "Coordonnee  dim= " << coo.dim << " ";
    // les data 
    switch (coo.dim)
      { case 3 : {sort  << setprecision(ParaGlob::NbdigdoCA()) <<  coo.coord[0] << " "
                        << setprecision(ParaGlob::NbdigdoCA()) <<  coo.coord[1] << " "
                        << setprecision(ParaGlob::NbdigdoCA()) <<  coo.coord[2] << " "; break;}
        case 2 : {sort  << setprecision(ParaGlob::NbdigdoCA()) <<  coo.coord[0] << " "
                        << setprecision(ParaGlob::NbdigdoCA()) <<  coo.coord[1] << " "; break;}
        case 1 : {sort  << setprecision(ParaGlob::NbdigdoCA()) <<  coo.coord[0] << " "; break;}
      	 case 0 : break; // on ne fait rien
      };
    return sort;      
  };


// Calcul de la norme euclidienne des composantes du point
#ifndef MISE_AU_POINT
  inline 
#endif
double Coordonnee::Norme ()  const 
{	double norme=0.0;
	 switch (dim)
       	{case 3:  norme+=coord[2] * coord[2];
       	 case 2:  norme+=coord[1] * coord[1];
       	 case 1:  norme+=coord[0] * coord[0];
       	 case 0:  ;
       	};
	 return sqrt(norme);
//	norme=sqrt((double)norme); // calcul de la norme
//	return norme;	
};

// norme le vecteur coordonnée
#ifndef MISE_AU_POINT
  inline 
#endif
Coordonnee& Coordonnee::Normer ()
 { double norme = this->Norme();
   #ifdef MISE_AU_POINT
   if(Dabs(norme) <= ConstMath::trespetit)
    { cout << "\n erreur, division par zero ";
      cout << "\nCoordonnee3::Normer () " << endl;
      Sortie (1);
    };
  #endif
  *this /=  norme;
  return *this ;
 };

#ifndef MISE_AU_POINT
  inline 
#endif
// Retourne le maximum en valeur absolue des composantes 
double Coordonnee::Max_val_abs () const 
{	double maxi=0.;
  switch (dim)
    	{ case 3: maxi=DabsMaX(maxi,coord[2]);
    	  case 2: maxi=DabsMaX(maxi,coord[1]);
    	  case 1: maxi=DabsMaX(maxi,coord[0]);
    	  case 0: break;	
    	};
	return maxi;	
};


#ifndef MISE_AU_POINT
  inline 
#endif
// ramène l'indice du maxi en valeur absolu
int Coordonnee::Indice_max_val_abs() const
{	double maxi=Dabs(coord[dim-1 ]);int indice=dim;
  switch (dim)
    	{ case 3: if (maxi < Dabs(coord[2])) {maxi = Dabs(coord[2]),indice = 3;}
    	  case 2: if (maxi < Dabs(coord[1])) {maxi = Dabs(coord[1]),indice = 2;}
    	  case 1: if (maxi < Dabs(coord[0])) {maxi = Dabs(coord[0]),indice = 1;}
    	  case 0: break;	
    	};
	return maxi;	
};


#ifndef MISE_AU_POINT
  inline 
#endif
// Retourne le maximum en valeur absolue des composantes  et l'indice correspondant
double Coordonnee::Max_val_abs (int& in) const 
{	double maxi=0.;
	 in = 0;
  switch (dim)
    	{ case 3: if (maxi < Dabs(coord[2])) {maxi=coord[2]; in=3;}
    	  case 2: if (maxi < Dabs(coord[1])) {maxi=coord[1]; in=2;}
    	  case 1: if (maxi < Dabs(coord[0])) {maxi=coord[0]; in=1;}
    	  case 0: break;	
    	};
	return maxi;	
};

#ifndef MISE_AU_POINT
  inline 
#endif
// Retourne le maximum en valeur absolue des composantes du Coordonnee
// mais ramène la grandeur signée (avec son signe)
double Coordonnee::Max_val_abs_signe () const 
{	double maxi=0.;
	 int in = 0;
  switch (dim)
    	{ case 3: if (maxi < Dabs(coord[2])) {maxi=coord[2]; in=3;}
    	  case 2: if (maxi < Dabs(coord[1])) {maxi=coord[1]; in=2;}
    	  case 1: if (maxi < Dabs(coord[0])) {maxi=coord[0]; in=1;}
    	  case 0: break;	
    	};
	if (in != 0) {return coord[in-1];}
	else         {return maxi;};
};

#ifndef MISE_AU_POINT
  inline 
#endif
// Retourne le maximum en valeur absolue des composantes du Coordonnee
// mais ramène la grandeur signée (avec son signe) et l'indice
double Coordonnee::Max_val_abs_signe (int& in) const 
{	double maxi=0.;
	 in = 0;
  switch (dim)
    	{ case 3: if (maxi < Dabs(coord[2])) {maxi=coord[2]; in=3;}
    	  case 2: if (maxi < Dabs(coord[1])) {maxi=coord[1]; in=2;}
    	  case 1: if (maxi < Dabs(coord[0])) {maxi=coord[0]; in=1;}
    	  case 0: break;	
    	};
	if (in != 0) {return coord[in-1];}
	else         {return maxi;};
};


#ifndef MISE_AU_POINT
  inline 
#endif
// modifie éventuellement les coordonnées de this pour quelles soient supérieures ou égales
// aux coordonnées en paramètre 
void Coordonnee::Modif_en_max(const Coordonnee& v)
 {
   #ifdef MISE_AU_POINT
    if ( dim!=v.dim )
	     {   cout << "\nErreur : dimensions non egales !\n";
		        cout << " Coordonnee::Modif_en_max(const Coordonnee& v) \n";
		        Sortie(1);
	     };
   #endif
   switch (dim)
    	{ case 3: if (coord[2] < v.coord[2]) coord[2]=v.coord[2];
    	  case 2: if (coord[1] < v.coord[1]) coord[1]=v.coord[1];
    	  case 1: if (coord[0] < v.coord[0]) coord[0]=v.coord[0];
    	  case 0: break;	
    	};
 };

#ifndef MISE_AU_POINT
  inline 
#endif
// modifie éventuellement les coordonnées de this pour quelles soient inférieures ou égales
// aux coordonnées en paramètre 
void Coordonnee::Modif_en_min(const Coordonnee& v)
 {
  #ifdef MISE_AU_POINT		
   if ( dim!=v.dim )
	   {   cout << "\nErreur : dimensions non egales !\n";
		      cout << " Coordonnee::Modif_en_min(const Coordonnee& v) \n";
		      Sortie(1);
	   };
  #endif
   switch (dim)
    	{ case 3: if (coord[2] > v.coord[2]) coord[2]=v.coord[2];
    	  case 2: if (coord[1] > v.coord[1]) coord[1]=v.coord[1];
    	  case 1: if (coord[0] > v.coord[0]) coord[0]=v.coord[0];
    	  case 0: break;	
    	};
 };
   
#ifndef MISE_AU_POINT
  inline 
#endif
// ajoute une même valeur à tous les coordonnées
void Coordonnee::Ajout_meme_valeur(double val)
{	 switch (dim)
       	{case 3:  coord[2] += val;
       	 case 2:  coord[1] += val;
       	 case 1:  coord[0] += val;
       	 case 0:  ;
       	};
   };

#ifndef MISE_AU_POINT
  inline 
#endif
    // sortie du schemaXML: en fonction de enu 
void Coordonnee::SchemaXML_Coordonnee(ofstream& sort,const Enum_IO_XML enu)
  {
	switch (enu)
	{ case XML_TYPE_GLOBAUX :
  	   {sort << "\n <!--  *************************** Coordonnee ***************************  -->"
  	         << "\n<xs:complexType name=\"COORDONNEE\" >"
  	         << "\n    <xs:annotation>"
  	         << "\n      <xs:documentation> coordonnee de dimension 1 ou 2 ou 3: elements: "
  	         << "\n          un entier (dim) donnant la dimension, et dim reels "
  	         << "\n      </xs:documentation>"
  	         << "\n    </xs:annotation>"
  	         << "\n    <xs:sequence>"
  	         << "\n        <xs:element name=\"dimension\" type=\"xs:double\" />"
  	         << "\n        <xs:element name=\"coordonnees\" >"
  	         << "\n            <xs:simpleType>"
  	         << "\n          	 <xs:restriction base=\"liste_de_reels\">"
  	         << "\n                <xs:minLength value=\"1\" />"
  	         << "\n                <xs:maxLength value=\"3\" />"
  	         << "\n              </xs:restriction>"  
  	         << "\n            </xs:simpleType>"
  	         << "\n        </xs:element>"
  	         << "\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;
		}
	};		
  };

// définit des coordonnées sans variance à la même place que des coordonnées avec variances
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Meme_place(CoordonneeB& vB)
 { // on regarde s'il faut faire quelque chose pour optimiser
   if (coord != vB.coord)
   { // on commence par libérer la place
     Libere();
     // création en fonction de la dimension
     dim = vB.dim;
     switch (dim)
     	{ case 0: memoire = true; break; // on met à true, car de toute manière il n'y a pas de mémoire
        default:
         	{ memoire = false; coord = vB.coord;}
     	};
   };
 };


// définit des coordonnées sans variance à la même place que des coordonnées avec variances
#ifndef MISE_AU_POINT
  inline 
#endif
void Coordonnee::Meme_place(CoordonneeH& vH)
 { // on regarde s'il faut faire quelque chose pour optimiser
   if (coord != vH.coord)
   { // on commence par libérer la place
     Libere();
     // création en fonction de la dimension
     dim = vH.dim;
     switch (dim)
     	{ case 0: memoire = true; break; // on met à true, car de toute manière il n'y a pas de mémoire
        default:
         	{ memoire = false; coord = vH.coord;}
     	};
   };
 };





#endif



