// FICHIER : Coordonnee.h
// 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-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.

// La classe Coordonnee sert a la localisation dans l'espace des objets tels que les
// noeuds ou les elements. Une instance de cette classe est caracterisee par le nombre
// de coordonnees et par la valeur de celles-ci.
// Les valeurs des coordonnees sont de type double et sont stockees dans un tableau 
// dont la taille depend de la dimension du probleme.
                                                    

#ifndef COORDONNEE_H
#define COORDONNEE_H


//#include "Debug.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include "Sortie.h"

class Vecteur;  // declare a la fin du fichier, car vecteur utilise aussi coordonnees

class Coordonnee
{ 
   // surcharge de l'operator de lecture
   friend istream & operator >> (istream &, Coordonnee &);
   // surcharge de l'operator d'ecriture
   friend ostream & operator << (ostream &, const Coordonnee &);
   // Surcharge de l'operateur * : multiplication entre un scalaire et des coordonnees
   inline friend Coordonnee operator* (double val,Coordonnee& c)
      { return (c*val); };

	public :
		// CONSTRUCTEURS :
		
		// Constructeur par defaut
		Coordonnee ();		
		// Constructeur fonction de la dimension du probleme
		// les coordonnees sont initialise a zero
		Coordonnee (int dimension);		
		// Constructeur pour une localisation unidimensionnelle
		Coordonnee (double x);		
		// Constructeur pour une localisation bidimensionnelle
		Coordonnee (double x,double y);		
		// Constructeur pour une localisation tridimensionnelle
		Coordonnee (double x,double y,double 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.
		Coordonnee (int dimension,double* t);						
		// Constructeur fonction d'un vecteur qui doit avoir une dim = 1 ou 2 ou 3
		Coordonnee ( const Vecteur& vec);
		// Constructeur de copie
		Coordonnee (const Coordonnee& c);
				
		// DESTRUCTEUR :
		~Coordonnee ();
				
		// METHODES :
		
		inline int Dimension () const 
		// Renvoie le nombre de coordonnees
		{	return dim; };		
		inline void Libere ()
		// Desallocation de la place memoire allouee
		{	if ( dim>0 )
				delete [] coord; 
			else
			{if ( coord!=NULL )
				{	cout << "\nErreur de liberation de la place memoire\n";
					cout << "COORDONNEE::LIBERE () \n";
					Sortie(1);
				}
			}	
			coord=NULL;
			dim=0; 	
		};		

   // Renvoie la ieme coordonnee
   inline double& 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
   inline double 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];
	};
		
		// Surcharge de l'operateur = : realise l'affectation entre deux points 
		Coordonnee& operator= (const Coordonnee& c);
		
		// Surcharge de l'operateur = avec un vecteur		
		Coordonnee& operator= ( const  Vecteur& c);

		inline Coordonnee operator- () const 
		// Surcharge de l'operateur - : renvoie l'oppose d'un point
		{	Coordonnee result(dim);
			for (int i=0;i<dim;i++)
				result.coord[i]=-coord[i];
			return result;			
		};
		
		inline Coordonnee operator- (const Coordonnee& c) const 
		// Surcharge de l'operateur - : realise la soustraction des
		// coordonnees de deux points
		{ 
         #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);
			for (int i=0;i<dim;i++)
				result.coord[i]=coord[i]-c.coord[i];
			return result;			
		};
		
		inline Coordonnee operator+ (const Coordonnee& c) const 
		// Surcharge de l'operateur + : realise l'addition des 
		// coordonnees de deux points
		{	
          #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);
			for (int i=0;i<dim;i++)
				result.coord[i]=coord[i]+c.coord[i];
			return result;		
		};
		
		inline void operator+= (const Coordonnee& c)
		// Surcharge de l'operateur += 
		{
          #ifdef MISE_AU_POINT		
			if ( dim!=c.dim )
			{	cout << "\nErreur : dimensions non egales !\n";
				cout << "COORDONNEE::OPERATOR+= (Coordonnee ) \n";
				Sortie(1);
			};
          #endif
			for (int i=0;i<dim;i++)
				coord[i]+=c.coord[i];
		};

		inline void operator-= (const Coordonnee& c)
		// Surcharge de l'operateur -= 
		{ 
          #ifdef MISE_AU_POINT		
		   if ( dim!=c.dim )
			{
				cout << "\nErreur : dimensions non egales !\n";
				cout << "COORDONNEE::OPERATOR-= (Coordonnee ) \n";
				Sortie(1);
			};
          #endif
			for (int i=0;i<dim;i++)
				coord[i]-=c.coord[i];
		};		

		inline void operator*= (double val)
		// Surcharge de l'operateur *= 
		{	for (int i=0;i<dim;i++)
				coord[i]*=val;
		};	
		
		inline Coordonnee operator* (double val) const 
		// Surcharge de l'operateur * : multiplication de coordonnees par un scalaire
		{   Coordonnee result(dim);
			for (int i=0;i<dim;i++)
				result.coord[i]=val*coord[i];
			return result;
		};
		
		// Surcharge de l'operateur / : division de coordonnees par un scalaire
		Coordonnee operator/ (double val) const  ;
		
		// Surcharge de l'operateur /= : division de coordonnees par un scalaire
		void operator/= (double val) ;

		inline int operator== (const Coordonnee& c) const 
		// Surcharge de l'operateur == : test d'egalite 
		// Renvoie 1 si les deux positions sont identiques
		// Renvoie 0 sinon
		{   if ( c.dim!=dim )
				return 0;
			else
			{   for (int i=0;i<dim;i++)
				{	if ( c.coord[i]!=coord[i] )
						return 0;
				};
				return 1;
			};
		};
		
		inline int operator!= (const Coordonnee& c) const 
		// Surcharge de l'operateur !=
		// Renvoie 1 si les deux positions ne sont pas identiques
		// Renvoie 0 sinon
		{	if ( (*this)==c )
				return 0;
			else 
				return 1; 
		};
	
		inline void Affiche () const 
		// Affiche les coordonnees du point à l'écran
		{	cout << "\t{  ";
			for (int i=1;i<=dim;i++)
				cout << (*this)(i) << "  ";
			cout << "}\n";
		};
		inline void Affiche (ostream& sort) const 
		// Affiche les coordonnees du point dans sort
		{	sort << "\t{  " ;
			for (int i=1;i<=dim;i++)
				sort << (*this)(i) << "  " ;
			sort << "}\n" ;
		};
		// 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`
		void Change_dim(int dim);		

  //  conversion en Vecteur
  Vecteur Vect() const ;
        
        // mise a zero des coordonnées
		inline void Zero() 
		 { for (int i=0;i<dim;i++)
		     coord[i] =0.;
		  };   
  
		
	protected :
	
		int dim;
		double* coord;
		
};

#include "Vecteur.hc"

#endif