
// 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/>.

#include "spectre.h"


// ----------------  def des grandeurs statiques ----------------  
Rgb Spectre::spectre[7][8] = {
    /*Standard */ {Bleu, Cyan, Vert, Jaune, Rouge},
    /*ArcEnCiel*/ {Violet, Bleu, Cyan, Vert, Jaune, Rouge},
    /*Thermique*/ {Noir, Bleu, Magenta, Rouge, Jaune, Blanc},
    /*Maximum  */ {Noir, Mag, Bleu2, Cyan2, Vert2, Jaune, Rouge, Blanc},
    /*NoirBlanc*/ {Noir, Blanc},
    /*Geo      */ {Noir, Bleu, Cyan, Vert, Jaune, Rouge, Blanc, Noir},
    /*Phaser   */ {Bleu3, Cyan, Vert, Jaune, Rouge}};
    
Spectre::Initialisation_description_spectre::Initialisation_description_spectre()
 { description_spectre.Change_taille(7);
   description_spectre(1) = " SPECTRE_STANDART:  Bleu, Cyan, Vert, Jaune, Rouge ";
   description_spectre(2) = " SPECTRE_ARCENCIEL: Violet, Bleu, Cyan, Vert, Jaune, Rouge ";
   description_spectre(3) = " SPECTRE_THERMIQUE: Noir, Bleu, Magenta, Rouge, Jaune, Blanc ";
   description_spectre(4) = " SPECTRE_MAXIMUM:   Noir, Mag, Bleu2, Cyan2, Vert2, Jaune, Rouge, Blanc ";
   description_spectre(5) = " SPECTRE_NOIRBLANC: Noir, Blanc ";
   description_spectre(6) = " SSPECTRE_GEO:      Noir, Bleu, Cyan, Vert, Jaune, Rouge, Blanc, Noir ";
   description_spectre(7) = " SPECTRE_PHASER:    Bleu3, Cyan, Vert, Jaune, Rouge ";
  }   
Tableau <string> Spectre::description_spectre; // initialisation par défaut de la description des spectres
Spectre::Initialisation_description_spectre Spectre::inti_spectre; // remplissage de la description des spectres

// ---------------- fin de l'intialisation des variables statiques ------------------

// constructeur par défaut
Spectre::Spectre() :
  spectre_courant(5)	// initialisations par défaut au spectre standart
  ,type_spectre(SPECTRE_STANDART)
  ,val_des_coul(5)
{ val_des_coul(1)=0.; val_des_coul(5)=1.;
  delta_val= (val_des_coul(5)-val_des_coul(1))/4.; 
  double val_inter=val_des_coul(1); 
  for (int i=1;i<=5;i++)
   {spectre_courant(i)=spectre[0][i-1]; val_des_coul(i)= val_inter; val_inter +=delta_val;}
}

// constructeur fonction d'un énuméré
Spectre::Spectre(EnumType_spectre type_spect,double val_min,double val_max) :
  spectre_courant(),val_des_coul()	
  ,type_spectre(type_spect)
{ int i1,j1max; // le premier indice de spectre et le maxi des éléments du spectre
  switch (type_spectre)
   { case SPECTRE_STANDART:   { i1=0;j1max=5;break;}
     case SPECTRE_ARCENCIEL:  { i1=1;j1max=6;break;}
     case SPECTRE_THERMIQUE:  { i1=2;j1max=6;break;}
     case SPECTRE_MAXIMUM:    { i1=3;j1max=8;break;}
     case SPECTRE_NOIRBLANCN: { i1=4;j1max=2;break;}
     case SPECTRE_GEO:        { i1=5;j1max=8;break;}
     case SPECTRE_PHASER:     { i1=6;j1max=5;break;}
     }
  // def du spectre
  spectre_courant.Change_taille(j1max);val_des_coul.Change_taille(j1max);
  val_des_coul(1)=val_min;val_des_coul(j1max)=val_max;
  delta_val= (val_max-val_min)/((double) (j1max-1)); 
  double val_inter=val_des_coul(1);
  for (int i=1;i<=j1max;i++)
    {spectre_courant(i)=spectre[i1][i-1]; val_des_coul(i)= val_inter; val_inter +=delta_val;}
};

// constructeur de copie
Spectre::Spectre(const Spectre& spect) :
  spectre_courant(spect.spectre_courant)
  ,type_spectre(spect.type_spectre)
  ,val_des_coul(spect.val_des_coul)
  ,delta_val(spect.delta_val)
    {};

// ------------ Méthodes --------------------
   
   // changement des valeurs min et max
void Spectre::Change_min_max(const double& val_min,const double& val_max) 
  {  if (val_min > val_max)
       { cout << "\n erreur, la valeur minimale " << val_min <<" est supérieur à la valeur maxi " << val_max
              << "\n Spectre::Change_min_max(double& val_min,double& val_max)";
         Sortie(1);
         }
     int j1max= spectre_courant.Taille();    
     val_des_coul(1)=val_min;val_des_coul(j1max)=val_max;
     delta_val= (val_max-val_min)/((double) (j1max-1)); double val_inter=val_min;
     for (int i=1;i<=j1max;i++)
       {val_des_coul(i)= val_inter; val_inter +=delta_val;}
   };
   
   // changement du spectre courant
void Spectre::Change_spectre_courant(EnumType_spectre type_spectre)
{ int i1,j1max; // le premier indice de spectre et le maxi des éléments du spectre
  switch (type_spectre)
   { case SPECTRE_STANDART:   { i1=0;j1max=5;break;}
     case SPECTRE_ARCENCIEL:  { i1=1;j1max=6;break;}
     case SPECTRE_THERMIQUE:  { i1=2;j1max=6;break;}
     case SPECTRE_MAXIMUM:    { i1=3;j1max=8;break;}
     case SPECTRE_NOIRBLANCN: { i1=4;j1max=2;break;}
     case SPECTRE_GEO:        { i1=5;j1max=8;break;}
     case SPECTRE_PHASER:     { i1=6;j1max=5;break;}
     }
  // def du spectre
  double val_min = val_des_coul(1); // sauve du mini
  double val_max = val_des_coul(val_des_coul.Taille()); // sauv du maxi
  spectre_courant.Change_taille(j1max);val_des_coul.Change_taille(j1max);
  val_des_coul(1)=val_min;val_des_coul(j1max)=val_max;
  delta_val= (val_max-val_min)/((double) (j1max-1)); 
  double val_inter=val_des_coul(1);
  for (int i=1;i<=j1max;i++)
    {spectre_courant(i)=spectre[i1][i-1]; val_des_coul(i)= val_inter; val_inter +=delta_val;}
};

// Retourne le nom d'un type de spectre a partir de son identificateur de
// type enumere id_Type_spectre correspondant
string Spectre::Nom_Type_Spectre (const Spectre::EnumType_spectre id_nom)
{string result="";
	switch (id_nom)
	{   case SPECTRE_STANDART :    result="SPECTRE_STANDART";break;
		case SPECTRE_ARCENCIEL :    result="SPECTRE_ARCENCIEL";break;
		case SPECTRE_THERMIQUE :    result="SPECTRE_THERMIQUE";break;
		case SPECTRE_MAXIMUM : result="SPECTRE_MAXIMUM";break;
		case SPECTRE_NOIRBLANCN :  result="SPECTRE_NOIRBLANCN";break;
		case SPECTRE_GEO :    result="SPECTRE_GEO";break;
		case SPECTRE_PHASER :    result="SPECTRE_PHASER";break;
		default :
		   {cout << "\nErreur : valeur incorrecte du type EnumType_spectre !\n";
			cout << "Spectre::Nom_Type_Spectre (const Spectre::EnumType_spectre id_nom) \n";
			Sortie(1);}
	};
	return result;
};

// Retourne l'identificateur de type enumere associe au nom du type de spectre
Spectre::EnumType_spectre Spectre::Id_nom_TypeSpectre (const char* nom)
{   EnumType_spectre result;
	if ( strcmp(nom,"SPECTRE_STANDART")==0 )result=SPECTRE_STANDART;
	else if ( strcmp(nom,"SPECTRE_ARCENCIEL")==0 )result=SPECTRE_ARCENCIEL;
	else if ( strcmp(nom,"SPECTRE_THERMIQUE")==0 )result=SPECTRE_THERMIQUE;
	else if ( strcmp(nom,"SPECTRE_MAXIMUM")==0 )result=SPECTRE_MAXIMUM;
	else if ( strcmp(nom,"SPECTRE_NOIRBLANCN")==0 )result=SPECTRE_NOIRBLANCN;
	else if ( strcmp(nom,"SPECTRE_GEO")==0 )result=SPECTRE_GEO;
	else if ( strcmp(nom,"SPECTRE_PHASER")==0 )result=SPECTRE_PHASER;
    else
	{  cout << "\nErreur : nom du degre de type de spectre inconnu ! ("
		     << nom << ") \n";
		cout << "EnumType_spectre Spectre::Id_nom_TypeSpectre (const char* nom_TypeSpectre) \n";
		Sortie(1);
	};
	return result;
};	

      
// définition d'une couleur en fonction d'une valeur numérique
// si la valeur est inférieure à la valeur mini du spectre, on retourne la valeur mini
// si la valeur est supérieure à la valeur maxi du spectre, on retourne la valeur maxi
Rgb Spectre::CouleurVal(const double& valx) const 
  { int nbval=spectre_courant.Taille();
    // traitement des extrèmes
//    int ix = std::abs((valx-val_des_coul(1))/delta_val) + 1; 
    int ix = ((valx-val_des_coul(1))/delta_val) + 1; 
    if (ix < 1) return  spectre_courant(1);
    if (ix >= nbval) return spectre_courant(nbval);
    // cas entre min et max
    // la valeur est entre la couleur ix et ix+1
    Rgb ret = (  (valx-val_des_coul(ix))/delta_val* spectre_courant(ix+1)
                  + (val_des_coul(ix+1)-valx)/delta_val* spectre_courant(ix) );
    return ret;           
   };

