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

#include <iomanip>
#include <algorithm>
#include "CharUtil.h"
#include "Coordonnee2.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "Banniere.h"
#include <limits>

    // CONSTRUCTEURS :
// par defaut
Isovaleurs_vrml::Isovaleurs_vrml () :
   OrdreVisu("........................................isovaleurs"
             ,"visualisation des isovaleurs","iso")
   ,choix_peau(true),choix_legende(true),choix_min_max(1)
   ,pour_legende_min(0),pour_legende_max(100)
   ,valMini(0.),valMaxi(0.)
   ,tabnoeud_type_ddl(),type_ddl_retenu(),choix_var_ddl()
   ,tabelement_type_ddl()
   ,spectre_coul(),nb_iso_val()
   ,couleurs_noeud(),val_noeud(),num_mail_incr()
   ,absolue(true)
     {// par défaut le nombre d'isovaleur vaut le nombre de couleur du spectre
      nb_iso_val=spectre_coul.NbCouleurBaseSpectre(); 
      }; 
     
     // constructeur de copie 
Isovaleurs_vrml::Isovaleurs_vrml (const Isovaleurs_vrml& ord) :
    OrdreVisu(ord) 
   ,choix_peau(ord.choix_peau),choix_legende(ord.choix_legende)
   ,choix_min_max(ord.choix_min_max)
   ,pour_legende_min(ord.pour_legende_min),pour_legende_max(ord.pour_legende_max)
   ,valMini(ord.valMini),valMaxi(ord.valMaxi)
   ,tabnoeud_type_ddl(ord.tabnoeud_type_ddl)
   ,type_ddl_retenu(ord.type_ddl_retenu),choix_var_ddl(ord.choix_var_ddl)
   ,tabelement_type_ddl(ord.tabelement_type_ddl)
   ,spectre_coul(ord.spectre_coul),nb_iso_val(ord.nb_iso_val)
   ,couleurs_noeud(ord.couleurs_noeud),val_noeud(ord.val_noeud)
   ,num_mail_incr(ord.num_mail_incr)
   ,absolue(ord.absolue)
     { };
               
    // DESTRUCTEUR :
Isovaleurs_vrml::~Isovaleurs_vrml () 
     {  };  
    
    // METHODES PUBLIQUES :
// execution de l'ordre
// tab_mail : donne les numéros de maillage concerné
// incre : numéro d'incrément qui en cours
// type_incre : indique si c'est le premier le dernier ou l'incrément courant a visualiser ou pas
// animation : indique si l'on est en animation ou pas
// unseul_incre : indique si oui ou non il y a un seul increment à visualiser
void Isovaleurs_vrml::ExeOrdre(ParaGlob * ,const Tableau <int>& tab_mail,LesMaillages * lesMail,bool ,LesReferences*
                      ,LesLoisDeComp* ,DiversStockage*,Charge*,LesCondLim*
                      ,LesContacts*,Resultats*,UtilLecture & entreePrinc,OrdreVisu::EnumTypeIncre type_incre,int incre
                      ,bool animation,const map < string, const double * , std::less <string> >&
                      ,const List_io < TypeQuelconque >& listeVecGlob)
 {// visualisation du maillage pointé si actif
  if (actif)
  {// on boucle sur les maillages
   int nbmail = tab_mail.Taille();
   for (int im=1;im<=nbmail;im++)
    { int numMail=tab_mail(im);
      // dans le cas où il n'y a aucun type de ddl retenu on arrête tout de suite
      if (type_ddl_retenu.Taille() == 0)
       { cout << "\n *** aucun type de ddl n'est defini en sortie, on ne fait rien \n";
         }
      else  // cas où il y a des ddl défini   
      {// en fait on se contente de définir les couleurs aux noeuds par rapport à l'échelle 
       // actuelle des couleurs
       // actualisation du conteneur du résultat
       if (type_incre==PREMIER_INCRE)
         { // au premier increment on commence par ré-initialiser les conteneurs
           couleurs_noeud.erase(couleurs_noeud.begin(),couleurs_noeud.end());
           num_mail_incr.erase(num_mail_incr.begin(),num_mail_incr.end());
           val_noeud.erase(val_noeud.begin(),val_noeud.end());
           // dans le cas d'un calcul de mini max  automatique on initialise
           if ((choix_min_max == 1)||(choix_min_max==3)) // cas d'un seul min max
            { valMini=0.;valMaxi=0.;};
          };
          
       // on définit deux variables intermédiaires
       // qui serviront ensuite à complèter les deux listes
       int nbmaxinoeud = lesMail->Nombre_noeud(numMail);
       Tableau < double > v_noeuds(nbmaxinoeud);
       Deuxentiers deuxi; deuxi.mail = numMail; deuxi.incr=incre;
       
       // on balaie tous les noeuds du maillage
       list <Coordonnee > listcoor; // une liste intermédiaire
       for (int numNoeud=1; numNoeud<= nbmaxinoeud;numNoeud++) 
          { // recup du noeud
            Noeud & noe = lesMail->Noeud_LesMaille(numMail,numNoeud);
            // recup de la valeur du ddl
            double val_ddl = noe.Valeur_tdt(type_ddl_retenu(numMail).Enum());
            if (!choix_var_ddl(numMail))
              val_ddl -= noe.Valeur_0(type_ddl_retenu(numMail).Enum());
            // enregistrement de la valeur
            v_noeuds(numNoeud)=val_ddl;
            // dans le cas on l'on utilise un mini max global automatique 
            // on le met à jour
            if ((choix_min_max == 1)||(choix_min_max==3)) // cas d'un seul min max
              { if (val_ddl > valMaxi) valMaxi = val_ddl;
                if (val_ddl < valMini) valMini = val_ddl;
               };
           };       
           
       // on sauvegarde les grandeurs intermédiaires
       num_mail_incr.push_back(deuxi);   
       val_noeud.push_back(v_noeuds);                          

       // cas du dernier incrément ou du premier sans animation, se qui signifie que c'est également le dernier
       if ((type_incre==DERNIER_INCRE)||( (type_incre==PREMIER_INCRE) && (!animation) ))
        {  // dans le cas du dernier incrément on met les valeurs à la bonne échelle
           // si c'est une échelle automatique
           if ((choix_min_max == 1) || (choix_min_max==3))
            { //on regarde si l'échelle n'est pas nulle si oui on la met à une valeur arbitraire de 1
              if ( Dabs(valMaxi - valMini) <= ConstMath::petit)
                { cout << "\n *** attention la valeur mini "<< valMini <<" et maxi " << valMaxi 
                       << " sont trop rapprochees pour le calcul de la plage d'isovaleur"
                       << "\n le mini et le maxi sont mis arbitrairement a 0 et 1";
                  valMaxi = 1.; valMini= 0.;     
                 }
             if (choix_min_max == 1)  // cas d'un min max normal automatique   
               {spectre_coul.Change_min_max(valMini,valMaxi) ;}
             else if (choix_min_max == 3)  // cas d'un min max automatique en %
               {// on applique les %
                double leg_min=valMini + (valMaxi-valMini) * pour_legende_min/100.;
                double leg_max=valMini + (valMaxi-valMini) * pour_legende_max/100.;
                spectre_coul.Change_min_max(leg_min,leg_max) ;
                }
            } 
          // maintenant on défini les couleurs
          // on passe en revue toutes les valeurs enregistrées
          list < Tableau < double > >::iterator it,itfin=val_noeud.end();
          for (it=val_noeud.begin();it!= itfin;it++)
           { int taimax=(*it).Taille();
             Tableau < Rgb > coul_noeuds(taimax);
             Tableau < double > & tab = (*it); // par facilité
             // dans le cas ou le min max varie à chaque incrément il faut d'abord le calculer
             if (choix_min_max==2)
              { valMini = 0.; valMaxi = 0.; // init
                double val_ddl;
                for (int j=1;j<=taimax;j++)
                 { val_ddl=tab(j);
                   if (val_ddl > valMaxi) valMaxi = val_ddl;
                   if (val_ddl < valMini) valMini = val_ddl;
                   }
                //on regarde si l'échelle n'est pas nulle si oui on la met à une valeur arbitraire de 1
                if ( Dabs(valMaxi - valMini) <= ConstMath::petit)
                { cout << "\n *** attention (2) la valeur mini "<< valMini <<" et maxi " << valMaxi 
                       << " sont trop rapprochees pour le calcul de la plage d'isovaleur"
                       << "\n le mini et le maxi sont mis arbitrairement a 0 et 1";
                  valMaxi = 1.; valMini= 0.;     
                 } 
                // maintenant on applique les %
                double leg_min=valMini + (valMaxi-valMini) * pour_legende_min/100.;
                double leg_max=valMini + (valMaxi-valMini) * pour_legende_max/100.;
                spectre_coul.Change_min_max(leg_min,leg_max) ;
               }; 
             // maintenant on calcul les couleurs            
             for (int i=1;i<=taimax;i++)
                coul_noeuds(i)=spectre_coul.CouleurVal(tab(i));
             couleurs_noeud.push_back(coul_noeuds);
             }
          // on dessine la légende au dernier  passage
          // car c'est seulement à la fin que l'on connait exactement l'échelle (dans le cas d'un
          // calcul automatique de l'échelle)
          // dans les autres cas la légende ne concerne que le dernier cas
          Sortie_dessin_legende(entreePrinc);
          if (choix_min_max==2)
            { cout << "\n *** attention ici la legende ne concerne que le dernier increment !!";}; 
         }
        }; //-- fin du choix où il y a ou pas des ddl actifs definis
    }; //-- fin de la boucle sur les maillages
  };//-- fin du choix actf ou pas  

 };

// choix de l'ordre, cet méthode peut entraîner la demande d'informations
// supplémentaires si nécessaire. qui sont ensuite gérer par la classe elle même
void Isovaleurs_vrml::ChoixOrdre()
 { bool choix_valide = false;
   cout << "\n ---- isovaleurs ---- ";
   string rep;
   while (!choix_valide)
      {
       try 
        { 
          cout 
          << "\n (0 ou f ou fin) fin modif"
          << "\n (1) definition des parametres generaux "
          << "\n (2) choix de l'isovaleur "
          << "\n (3) transferts aux noeuds de grandeurs existantes aux points d'integration";
          cout << "\n \n reponse ? ";
          rep = lect_return_defaut(false,"f");
          if (rep == "fin_prog") Sortie(1);
          // sinon
          int num = ChangeEntier(rep);
          if ((rep == "0")||(rep == "f")||(rep == "fin")) 
            { choix_valide=true; }
          else if ((num >= 1)&&(num<=3)) 
           { choix_valide=false;
             switch (num)
              { case 1:  //"definition des parametres generaux"
                { ParametresGeneraux(); break;}
                case 2:  // "choix de l'isovaleur"
                 {ChoixIsovaleur(); break;}
                case 3:  // "transferts aux noeuds de grandeurs existantes aux points d'integration"
                { TransfertGrandeursPtIntegAuNoeud(); break;}
               }
             } 
          else { cout << "\n Erreur on attendait un entier entre 0 et 3 !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper fin_prog pour arreter le programme"; 
              choix_valide=false;
             }
         }    
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)// erreur de lecture
       {  cout << "\n Erreur on attendait un des mots cles proposés !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper fin_prog pour arreter le programme"; 
              choix_valide=false;
        }
       } //-- fin du while
   // appel de la méthode de la classe mère
   OrdreVisu::ChoixOrdre();    
  };     
            
// initialisation : permet d'initialiser les différents paramètres de l'ordre
// lors d'un premier passage des différents incréments
// en virtuelle, a priori est défini si nécessaire dans les classes dérivées
void Isovaleurs_vrml::Initialisation(ParaGlob * paraGlob,LesMaillages * lesmail,LesReferences* lesRef
                      ,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,Charge* charge
                      ,LesCondLim* lesCondLim,LesContacts* lesContacts
                      ,Resultats* resultats,EnumTypeIncre type_incre,int incre
                      ,const map < string, const double * , std::less <string> >& listeVarGlob
                      ,const List_io < TypeQuelconque >& listeVecGlob
                      ,bool fil_calcul) 
   { // initialisation de la liste des différentes isovaleurs possibles
     // uniquement lors du premier et du dernier passage pour économiser 
     if ((type_incre == OrdreVisu::DERNIER_INCRE) || (type_incre == OrdreVisu::PREMIER_INCRE))
      {Init_liste_isovaleur(lesmail,lesContacts);}
     //appel de l'ordre d'initialisation de la classe mère
     OrdreVisu::Initialisation(paraGlob,lesmail,lesRef,lesLoisDeComp,diversStockage,charge
                      ,lesCondLim,lesContacts,resultats,type_incre,incre
                      ,listeVarGlob,listeVecGlob,fil_calcul);
     choix_var_ddl.Change_taille(lesmail->NbMaillage());                  
   };
            
// initialisation de la liste des différentes isovaleurs possibles
void Isovaleurs_vrml::Init_liste_isovaleur(LesMaillages * lesMail,LesContacts* lesContacts)
   { // récupération des ddl présents dans les maillages aux noeuds
	    tabnoeud_type_ddl = lesMail->Les_type_de_ddl_par_noeud(absolue);
	    tabelement_type_ddl = lesMail->Les_type_de_ddl_par_element(absolue);
   }; 
   
// lecture des paramètres de l'ordre dans un flux
void Isovaleurs_vrml::Lecture_parametres_OrdreVisu(UtilLecture & entreePrinc)
 { // si dans le flot il existe l'identificateur adoc on lit sinon on passe
   if (strstr(entreePrinc.tablcarCVisu,"debut_isovaleur_vrml")!=NULL)
     {// sauvegarde des parametres actuels
      bool choix_peau_s=choix_peau; bool choix_legende_s=choix_legende; int choix_min_max_s=choix_min_max;
      double valMini_s=valMini; double valMaxi_s=valMaxi; int nb_iso_val_s=nb_iso_val;
      Tableau < Ddl_enum_etendu>  type_ddl_retenu_s(type_ddl_retenu);
      // essaie de lecture
      try 
        { string nom,nom1; 
          (*entreePrinc.entCVisu)  >> nom ;
          if (nom != "debut_isovaleur_vrml")
            { cout << "\n Erreur en lecture des parametres pour les isovaleurs a partir d'un fichier .CVisu,"
                   << " le premier enregistrement doit etre le mot clef: debut_isovaleur_vrml "
                   << " on ne tiens pas compte  des parametres fournis !! ";
              }
          else
           { // appel de l'ordre de la classe mère
             OrdreVisu::Lect_para_OrdreVisu_general(entreePrinc);
             // puis lecture des parametres propres
             // lecture  du type de sortie des tenseurs
             if (strstr(entreePrinc.tablcarCVisu,"tenseur_en_absolue_")!=NULL)
               {(*entreePrinc.entCVisu) >> nom >> absolue;
					           if (nom != "tenseur_en_absolue_")
					            { cout << "\n lecture de l'indicateur de type de tensue, on a lue ( "<< nom
								                << " ) et on attendait tenseur_en_absolue_"
								                << " la suite de la lecture du .CVisu risque d'etre completement fausse, on arrete !!" ; 
						             cout << "\n Isovaleurs_Gmsh::Lecture_parametres_OrdreVisu(... ";     
                   UtilLecture::ErrNouvelEnregCVisu sortie(-1) ; throw (sortie);
						           }
					           else // sinon c'est ok
					            {entreePrinc.NouvelleDonneeCVisu();}; // on passe un enregistrement
               };
             int nb_maillage = tabnoeud_type_ddl.Taille(); 
             
             while (strstr(entreePrinc.tablcarCVisu,"fin_isovaleur_vrml")==NULL)
              { (*entreePrinc.entCVisu) >> nom; // lecture du numero de maillage
                if (nom == "choix_peau") (*entreePrinc.entCVisu) >> choix_peau;
                if (nom == "choix_legende") (*entreePrinc.entCVisu) >> choix_legende;
                if (nom == "choix_min_max") (*entreePrinc.entCVisu) >> choix_min_max;
                if (nom == "valMini") (*entreePrinc.entCVisu) >> valMini;
                if (nom == "valMaxi") (*entreePrinc.entCVisu) >> valMaxi;
                if (nom == "pour_legende_min") (*entreePrinc.entCVisu) >> pour_legende_min;
                if (nom == "pour_legende_max") (*entreePrinc.entCVisu) >> pour_legende_max;
                if (nom == "nb_iso_val") (*entreePrinc.entCVisu) >> nb_iso_val;
                if (nom == "debut_tableau_ddl") 
                  { (*entreePrinc.entCVisu) >> nom1;
                    if (nom1 != "fin_tableau_ddl")
                     { type_ddl_retenu.Change_taille(nb_maillage);
                       choix_var_ddl.Change_taille(nb_maillage); 
                       type_ddl_retenu(1) = Ddl_enum_etendu(nom1);
                       for (int i=2;i<= nb_maillage; i++) 
                         { (*entreePrinc.entCVisu) >> type_ddl_retenu(i);
                           (*entreePrinc.entCVisu) >> choix_var_ddl(i);
                          } 
                      }
                   }    
                entreePrinc.NouvelleDonneeCVisu(); // on passe un enregistrement                   
               }        
             entreePrinc.NouvelleDonneeCVisu(); // on passe un enregistrement
            } // -- fin du if then else sur "debut_isovaleur_vrml"       
         } // -- fin du try    
      catch (ErrSortieFinale)
           // cas d'une direction voulue vers la sortie
           // on relance l'interuption pour le niveau supérieur
         { ErrSortieFinale toto;
           throw (toto);
         }
      catch (...)// erreur de lecture
       {  cout << "\n Erreur en lecture des parametres pour les isovaleurs a partir d'un fichier .CVisu,"
               << " on ne tiens pas compte  des parametres fournis !! ";
          // récup des  parametres sauvées
          choix_peau=choix_peau_s; choix_legende=choix_legende_s; choix_min_max=choix_min_max_s;
          valMini=valMini_s; valMaxi=valMaxi_s; nb_iso_val=nb_iso_val_s;
          type_ddl_retenu = type_ddl_retenu_s;
          if (ParaGlob::NiveauImpression() >= 4)     
             cout  << "\n Isovaleurs_vrml::Lecture_parametres_OrdreVisu(..";
        }
      }  
  };

// écriture des paramètres de l'ordre dans un flux
void Isovaleurs_vrml::Ecriture_parametres_OrdreVisu(UtilLecture & entreePrinc)
 { // récup du flot  
   ostream & sort = (*(entreePrinc.Sort_CommandeVisu()));
   // on commente le fonctionnement
   sort << "\n #  ----------------------------- definition des parametres pour les isovaleurs : ---------------- ";
   // mot clé de démarrage
   sort << "\n debut_isovaleur_vrml         # mot cle de debut des parametres pour les isovaleurs"; 
   // appel de l'ordre de la classe mère
   OrdreVisu::Ecrit_para_OrdreVisu_general(entreePrinc);
   // le type de sortie des tenseurs
   sort << "\n# un parametre indiquant si les tenseurs sont en absolue (rep 1) ou suivant un repere ad hoc"
        << "\n# (tangent pour les coques, suivant la fibre moyenne pour les element 1D ) ";
   sort << "\n tenseur_en_absolue_  " <<  absolue;
   // puis les paramètres
   sort << "\n choix_peau " << choix_peau << "  # <0 ou 1> si 1 visualisation uniquement de la peau";
   sort << "\n choix_legende " << choix_legende << "  # <0 ou 1> si 1  affichage de la legende";
   sort << "\n choix_min_max " << choix_min_max << "  # <0 ou 1 ou 2> si 1 min max calcule automatiquement, 2 auto en % par incre";
   sort << "\n valMini " << valMini << "  # mini  <un reel> utilises si choix_min_max = 0";
   sort << "\n valMaxi " << valMaxi << "  # maxi  <un reel> utilises si choix_min_max = 0";
   sort << "\n pour_legende_min " << pour_legende_min << "  # mini  <un reel> utilises si choix_min_max = 2";
   sort << "\n pour_legende_max " << pour_legende_max << "  # maxi  <un reel> utilises si choix_min_max = 2";
   sort << "\n nb_iso_val " << nb_iso_val << "  # <un entier> nombre d'isovaleurs dans la legende";
   // ---- les ddl a visualiser
   sort << "\n #   tableau de ddl a visualiser, un par maillage";
   int nb_mail = type_ddl_retenu.Taille();
   sort << "\n debut_tableau_ddl " ;
   for (int i=1;i<= nb_mail;i++) 
      { sort << type_ddl_retenu(i) << " " << choix_var_ddl(i) << " ";};
   sort << " fin_tableau_ddl " ;
   // mot clé de fin
   sort << "\n fin_isovaleur_vrml         # mot cle de fin des parametres pour les isovaleurs \n";
  };

// ======================================== méthodes privées =====================================
                           
// sortie du dessin de la légende
void Isovaleurs_vrml::Sortie_dessin_legende(UtilLecture & entreePrinc)
  {ostream &sort = entreePrinc.Sort_legende_vrml();
   // écriture de l'entête
   sort << "#VRML V2.0 utf8\n";
   // le titre
   sort << "WorldInfo {\n"
        << "title \" Légende pour isovaleurs du calcul éléments finis : Herezh++ V" << ParaGlob::NbVersion()
                                                               << " \" \n"
 //       << "info [ \"Copyright (c) 1997-2003, Gérard Rio (gerard.rio@univ-ubs.fr) http://www-lg2m.univ-ubs.fr\" ]\n"
        << "info [ \" " << Banniere::CopiPirate << " \" ]\n"
        << "}\n";
   sort << "NavigationInfo {\n"
        << "type [ \"EXAMINE\", \"ANY\" ] \n"
        << "headlight TRUE \n"
        << "}\n";
   // on définit un rectangle pour chaque niveau d'isovaleur 
   // globalement on définit le rectangle global par les points extrèmes
   Coordonnee2 ptdeb(0.,0.); Coordonnee2 ptfin(10.,200.);
   // on définit le deltax et le delta y
   Coordonnee2 deltax(10.,0.);Coordonnee2 deltay(0.,200./(nb_iso_val-1.));  
   // définition des points de vue avec l'angle adoc
   // l'objectif est de positionner les viewpoints relativement à la legende
   // pour l'instant pb avec maclookat donc on simplifie        
 /*  Vecteur diag = ptfin - ptdeb;
   double lmax = diag.Norme();
   Vecteur centre = (ptfin + ptdeb)/2.;
   // si la dimension est différente de 3 on force à 3 
   // d'où les autres coordonnées sont nulles
   centre.Change_taille(3);
   // def de la distance d'observation grande pour minimiser la déformation
   double dist = 5.*lmax;
   // calcul de l'angle du cone de vue
   double angle = 1.25*atan(lmax/dist); 
   int i1= std::abs( centre(1));
   int i2= std::abs( centre(2)); 
   int i3= std::abs( centre(3)+ dist); 
   sort << "\n Viewpoint {"
        << "\n position " << i1 <<" "<< i2 <<" "<< i3
        << "\n fieldOfView " << angle
        << "\n description \"suivant Z \""
        << "\n }";
*/
   sort << "\n Viewpoint {"
        << "\n position " << " 5       100      1000 "
        << "\n fieldOfView " << 0.25
        << "\n description \"suivant Z \""
        << "\n }";
   // definition du tableau des points de la legende
   Tableau <Coordonnee2> tab_pt(2*nb_iso_val,ptdeb);
   for (int i=1;i<= nb_iso_val;i++)
     { tab_pt(i) += (i-1) * deltay;
       tab_pt(i+nb_iso_val) = tab_pt(i) + deltax;
      }  
   // on  ecrit la liste des points 
   // def de l'entité forme
   sort << "\n Shape { "
   << "\n  appearance Appearance {}";
   // création des points
   // tout d'abord le nom
   ostrstream tab_out;
   tab_out << "Coordonnees"  << ends;
   string nom_coordinate = tab_out.str() ;  // le nom
   // on utilise une géométrie de face indexée bien qu'aucune face soit définit 
   sort << "\n  geometry IndexedFaceSet {"
        << "\n     coord DEF " << nom_coordinate <<  " Coordinate {"
        << "\n                   point [ \n";
   int deux_nb_iso_val = 2*nb_iso_val;    
   for (int i=1;i<= deux_nb_iso_val;i++)
     { sort <<"\n                        "
                   << setw (4);  
       tab_pt(i).Affiche(sort,16);
       sort << setw (16) << 0 <<" "; // pour etre en 3D
      } 
   // fermeture du groupe point, coordinate, de la géométrie et de la forme
   sort << "\n                     ] } } }";
   // maintenant les facettes:  def de l'entité forme
   sort << "\n Shape { "
        << "\n   appearance Appearance {}";
   // def de la géométrie
   sort << "\n     geometry IndexedFaceSet {"
   // utilisation des points déjà défini
           << "\n     coord USE Coordonnees" ;
   // def des facettes
   sort << "\n                 coordIndex [";
   for (int i=0;i< nb_iso_val-1;i++)
     { // on definit deux triangle pour chaque facette,
       sort << "\n                    "; //début de la face 1
       sort << i << ", " << i+nb_iso_val << ", " << i+1 << ", -1,";
       sort << "\n                    "; //début de la face 2
       sort << i+nb_iso_val << ", " << i+nb_iso_val+1 << ", " << i+1 << ", -1,";
       }
   // fin pour les faces 
   sort << "\n                ]";
   // definition des couleurs aux noeuds 
   // on sauvegarde puis modifie les min max pour les adapter au tracé de la légende
   double legende_min = spectre_coul.Valeur_mini();
   double legende_max = spectre_coul.Valeur_maxi();
   spectre_coul.Change_min_max(ptdeb(2),ptfin(2)) ;
   sort << "\n                 color Color {"
        << "\n                     color [";
   for (int i=1;i<= nb_iso_val;i++)
     { // récup de la couleur
       Rgb rgb = spectre_coul.CouleurVal(tab_pt(i)(2));
       sort << "\n                     " <<  rgb << ", ";
      } 
   for (int i=1;i<= nb_iso_val;i++)
     { // récup de la couleur
       Rgb rgb = spectre_coul.CouleurVal(tab_pt(i+nb_iso_val)(2));
       sort << "\n                     " <<  rgb << " , ";
      } 
    sort    << "\n                     ]"
            << "\n                 }";
    // remise normale du min max du spectre
    spectre_coul.Change_min_max(legende_min,legende_max) ;
            
    // on signal que l'on utilise une couleur par noeud (vertex)
    sort    << "\n                 colorPerVertex  TRUE";
    // on signal que l'on peut voir des deux cotés des facettes
    sort    << "\n                 solid FALSE";
   sort << "\n            }";
    // fin: on ferme l'entité forme
    sort << "\n         }";
    
    // maintenant on définit les valeurs de la légende
    // def d'un décalage suivant x de la légende couleur
    double decax = (ptfin(1) - ptdeb(1))/ 5.;        
    // on boucle sur les isovals
    double delta_val_y=(legende_max-legende_min)/(nb_iso_val-1);
    double val_iso=legende_min;
    for (int i=1;i<= nb_iso_val;i++)
     { // creation de la chaine de caractère qui contient la valeur de l'isovaleur
       ostrstream tab_out;
       #ifndef ENLINUX_STREAM
            tab_out.setf(ios_base::scientific);
       #else  
            tab_out.setf(ios::scientific); 
       #endif
       tab_out << setprecision(6) << val_iso << ends;
       // on définit une entité déplacé qui permet de ce positionner
       // aux coordonnées que l'on veut 
       sort << "\n        Transform {  #           X                   Y                 Z ";
       sort <<"\n              translation "
            << setw (16) << (tab_pt(i+nb_iso_val)(1) + decax) << " " 
            << setw (16) << tab_pt(i+nb_iso_val)(2) << " " 
            << setw (16) << 0 << " "; 
       // écrit la valeur
       sort   << "\n                children [";
       // def de l'entité forme
       sort << "\n          Shape { "
            << "\n                appearance Appearance {"
            << "\n                  material Material { }"
            << "\n                             }"
            << "\n             geometry Text {"
            << "\n             string \"" << tab_out.str() <<"\""
            << "\n               fontStyle FontStyle {size 10} "
            << "\n                 }} ] }";
       val_iso += delta_val_y;     
      }
   // définition du titre du travail
   sort << "\n        Transform {  #           X                   Y                 Z ";
   sort <<"\n              translation "
            << setw (16) << -10 << " " 
            << setw (16) << -10<< " " 
            << setw (16) << 0 << " "; 
   // écrit le texte
   sort   << "\n                children [";
   // def de l'entité forme
   sort << "\n          Shape { "
            << "\n                appearance Appearance {"
            << "\n                  material Material { }"
            << "\n                             }"
            << "\n             geometry Text {"
            << "\n             string \"" << "Herezh++  V" << ParaGlob::NbVersion()<<" \""
            << "\n               fontStyle FontStyle {size 10} "
            << "\n                 }} ] }";
    // définition du nom del'isovaleur
   sort << "\n        Transform {  #           X                   Y                 Z ";
   sort <<"\n              translation "
            << setw (16) << -28 << " " 
            << setw (16) << -18<< " " 
            << setw (16) << 0 << " "; 
   // écrit le texte
   sort   << "\n                children [";
   // def de l'entité forme
   sort << "\n          Shape { "
            << "\n                appearance Appearance {"
            << "\n                  material Material { }"
            << "\n                             }"
            << "\n             geometry Text {"
            << "\n             string \"" << "isovaleur de " ;
    if (type_ddl_retenu.Taille() != 0) 
             sort << type_ddl_retenu(1); //.Nom();            
    sort    << " \""
            << "\n               fontStyle FontStyle {size 10} "
            << "\n                 }} ] }";
       
  // et on vide le buffer de sortie
  sort << endl; 
  };
  
    
// définition interactives des paramètres généraux des isovaleurs
void Isovaleurs_vrml::ParametresGeneraux()
 { bool choix_valide = false;
   cout << "\n ----> preparation de la visualisation des isovaleurs"
        << "\n  parametre par defaut ? : affichage de la peau par facettes triangulaires,"
        << "\n                           ajout de la legende avec min_max automatique,"
        << "\n                           spectre standart, "
        << "   (rep 'o') pour accepter ces parametres sinon autre ";
   string rep;
   cout << "\n reponse ? "; rep = lect_return_defaut(true,"o");
   if (rep != "o") 
    {// cas d'un choix autre que standart
     while (!choix_valide)
      {
       try 
        { 
          cout 
          << "\n (0) fin modif"
          << "\n (1) plus visualisation interne             (2) calcul NON automatique des min max de la legende "
          << "\n (3) visualisation que des peaux            (4) calcul auto global des min max de la legende"
          << "\n (5) autres spectres                        (6) % auto sur l'incr des min max de la legende"
          << "\n (7) spectre standart                       (8) % auto sur tous les incr des min max de la legende"
          << "\n (9) nombre isovaleurs "
          << "\n (10) sortie des tenseurs dans le repere absolu (par defaut) "
          << "\n (11) sortie des tenseurs dans un repere ad hoc, qui depend du type d'element ";
          cout << "\n \n reponse ? ";
          rep = lect_return_defaut(false,"0");
          if (rep == "fin_prog") Sortie(1);
//          if ((rep == "0")||(rep == "f")||(rep == "fin")) return;
          // sinon
          int num = ChangeEntier(rep);
          if (num == 0) choix_valide=true;
          else if ((num >= 1)&&(num<=11))
           { choix_valide=false;
             switch (num)
              { case 1:  //"visualisation interne")
                { choix_peau = true; break;}
                case 2:  // "calcul NON automatique des min max de la légende")
                 {bool choixvalideLoc = false;
                  while (!choixvalideLoc)
                   {// on récupère les mini et maxi de la légende
                    cout << "\n actuellement les mini/maxi sont: " 
                         << " mini= " << spectre_coul.Valeur_mini() 
                         << " maxi= " << spectre_coul.Valeur_maxi();
                    cout << "\n differentes methodes pour modifier les extremes: "
                         << "\n donnez les valeurs explicitements des extremes   (rep 1)"
                         << "\n donnez en % de la plage actuelle des mini et maxi  (rep 2)"
                         << "\n    (dans ce dernier cas, modif a chaque increment)        "
                         << "\n laisser tel quel                                   (rep f ou 0 ou fin)";
                    cout << "\n \n reponse ? ";
                    string reploc; reploc = lect_return_defaut(false,"f");
                    if (reploc == "1")
                     {cout << "\n donner le mini et le maxi de la legende (2 reels)  ";
                      double legende_min,legende_max; // min max de la légende
                      cin >> legende_min >> legende_max;
                      std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
                      if ( legende_max < legende_min)
                        {cout << "\n donnees non valides, le maxi doit etre superieur au mini !! ";
                         choixvalideLoc=false;
                         }
                      else  
                       {choix_min_max = 0;
                        spectre_coul.Change_min_max(legende_min,legende_max) ;
                        choixvalideLoc = true;
                        };
                       }
                    else if (reploc == "2")    
                      {cout << "\n donner le mini et le maxi en % de la plage (2 reels)  ";
                      double pr_legende_min,pr_legende_max; // min max de la légende
                      cin >> pr_legende_min >> pr_legende_max;
                      std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
                      if ( pr_legende_max < pr_legende_min)
                        {cout << "\n donnees non valides, le maxi doit etre superieur au mini !! ";
                         choixvalideLoc=false;
                         }
                      else  
                       {choix_min_max = 0;
                        double leg_min=spectre_coul.Valeur_mini() + 
                                       (spectre_coul.Valeur_maxi()-spectre_coul.Valeur_mini())
                                         * pr_legende_min/100.;
                        double leg_max=spectre_coul.Valeur_mini() + 
                                       (spectre_coul.Valeur_maxi()-spectre_coul.Valeur_mini())
                                         * pr_legende_max/100.;
                        spectre_coul.Change_min_max(leg_min,leg_max) ;
                        cout << "\n nouvelles valeurs: mini= " <<leg_min << " maxi= " <<leg_max <<" ";  
                        choixvalideLoc=true;
                        };
                       } 
                     else if ((reploc == "f")||(reploc == "0")||(reploc == "fin"))
                       { choixvalideLoc=true;}
                     else 
                       { cout << "\n erreur d'entree, recommencez ";
                         choixvalideLoc=false;
                         };
                     };       
                    break;
                  }
                case 3:  // "visualisation que des peaux")
                { choix_peau = false; break;}
                case 4:  // "calcul automatique des min max de la légende")
                { choix_min_max = 1; break;}
                case 5:  // "autres spectres")
                { // on récupère les différents spectres
                  const Tableau <string> & tab_spectre = Spectre::Description_spectres_disponibles();
                  int nb_spectre= tab_spectre.Taille();
                  bool choix_val = false;
                  cout << "\n donner un choix de spectre";
                  while (!choix_val)
                   { 
                    try 
                     { cout << "\n (0) fin modif spectre";
                       for (int i=1;i<=nb_spectre;i++)
                         cout << "\n ("<<i<<")  " << tab_spectre(i);
                       cout << "\n \n reponse ? ";
                       rep = lect_return_defaut(false,"0");
                       if (rep == "fin_prog") Sortie(1);
                       // sinon
                       int nim = ChangeEntier(rep);
                       if (nim == 0) choix_val=true;
                       else if ((nim >= 1)&&(nim<=nb_spectre)) 
                         { choix_val=false;
                           spectre_coul.Change_spectre_courant(Spectre::EnumType_spectre(nim));
                          } 
                       else
                          {  cout << "\n ERREUR *** choix non valide :on attendait un nombre entre  0 et "<< nb_spectre
                                  << "\n redonnez une bonne valeur ****** \n \n ";
                             choix_val=false;
                           }                          
                       }
                    catch (ErrSortieFinale)
                         // cas d'une direction voulue vers la sortie
                         // on relance l'interuption pour le niveau supérieur
                       { ErrSortieFinale toto;
                         throw (toto);
                       }
                    catch (...)// erreur en lecture
                     {  cout << "\n Erreur on attendait un des mots cles proposes !!, "
                             << "\n redonnez une bonne valeur"
                             << "\n ou taper fin_prog pour arreter le programme"; 
                        choix_val=false;
                      }
                    } //-- fin du while  
                 break;}
                case 6:  // "calcul automatique en % pour chaque incre des min max de la légende")
                { cout << "\n donner le mini et le maxi en % de la plage de l'increment (2 reels)  ";
                  double pr_legende_min,pr_legende_max; // min max de la légende
                  cin >> pr_legende_min >> pr_legende_max;
                  std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
                  if ( pr_legende_max < pr_legende_min)
                      {cout << "\n donnees non valides, le maxi doit etre superieur au mini !! ";}
                  else  
                       {choix_min_max = 2;
                        pour_legende_min=pr_legende_min;pour_legende_max=pr_legende_max;
                        cout << "\n %lu (util pour chaque incr): mini= " <<pour_legende_min 
                             << " maxi= " <<pour_legende_max <<" ";  
                        };
                  break;
                  }
                case 7:  // "spectre standart")
                { spectre_coul.Change_spectre_courant(Spectre::EnumType_spectre(1));
                  break;}
                case 8:  // "calcul automatique en % global des min max de la légende")
                { cout << "\n donner le mini et le maxi en % de la plage de l'increment (2 reels)  ";
                  double pr_legende_min,pr_legende_max; // min max de la légende
                  cin >> pr_legende_min >> pr_legende_max;
                  std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
                  if ( pr_legende_max < pr_legende_min)
                      {cout << "\n donnees non valides, le maxi doit etre superieur au mini !! ";}
                  else  
                       {choix_min_max = 3;
                        pour_legende_min=pr_legende_min;pour_legende_max=pr_legende_max;
                        cout << "\n %lu (util pour tous les incr): mini= " <<pour_legende_min 
                             << " maxi= " <<pour_legende_max <<" ";  
                        };
                  break;
                  }
                case 9:  // "nombre d'isovaleurs")
                { bool choix_val = false;
                  int inter_int;
                  cout << "\n le nombre actuel est : " << nb_iso_val;
                  while (!choix_val)
                   { 
                    try 
                     { cout << "\n donnez une nouvelle valeur entre 2 et 100 ou 0  pour laisser en l'etat";
                       cout << "\n \n valeur ? ";
                       inter_int=(int)lect_double();
                       if (inter_int == 0) choix_val = true;
                       // sinon
                       else if ((inter_int <= 2) || (inter_int > 100)) 
                         cout << "\n le nombre d'isovaleur doit etre strictement superieur a 2 et"
                              << "inferieur ou egal a 100";
                       else {nb_iso_val = inter_int;choix_val = true;}
                       }
                    catch (ErrSortieFinale)
                         // cas d'une direction voulue vers la sortie
                         // on relance l'interuption pour le niveau supérieur
                       { ErrSortieFinale toto;
                         throw (toto);
                       }
                    catch (...)// erreur en lecture
                     {  cout << "\n Erreur on attendait soit 0 pour garder la valeur precedente"
                             << " ou un nombre entre 2 et 100 !!, "
                             << "\n redonnez une bonne valeur";
                        choix_val=false;
                      }
                    } //-- fin du while  
                 break;}
			             case 10: { absolue = true; break;}
			             case 11: { absolue = false; break;}
              }
             } 
          else { cout << "\n Erreur on attendait un entier entre 0 et 9 !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper fin_prog pour arreter le programme"; 
              choix_valide=false;
             }
         }    
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)// erreur de lecture
       {  cout << "\n Erreur on attendait un des mots cles proposés !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper fin_prog pour arreter le programme"; 
              choix_valide=false;
        }
       } //-- fin du while
    }      
  };

// choix de l'isovaleur à visualiser
void Isovaleurs_vrml::ChoixIsovaleur()
 { bool choix_valide = false;
   string rep;
   cout << "\n  choix de l'isovaleur a visualiser, on choisit une isovaleur maxi par maillage";
   int nbmail = tabnoeud_type_ddl.Taille();
   // update du tableau de ddl à visualiser si nécessaire
   if (type_ddl_retenu.Taille() != nbmail)
       type_ddl_retenu.Change_taille(nbmail);

   for (int imail = 1;imail<=nbmail;imail++)
     {choix_valide=false;
      while (!choix_valide) // premier while
      {
       try 
        { 
          cout << "\n (0 ou f ou fin) fin choix ddl ";
          cout << "\n listes de type de ddl a visualiser ";
          cout << "\n Maillage nb: " << imail << " liste des types de ddl disponibles "
                                     << "\n" << tabnoeud_type_ddl(imail);
          cout << "\n donner le ddl a visulaliser "
               << "\n reponse ?  ";
          rep = lect_return_defaut(false,"f");
          if (rep == "fin_prog") Sortie(1);
          // sinon
          if ((rep == "0") || (rep == "f") || (rep == "fin")) 
              choix_valide=true;
          else if (ExisteEnum_ddl(rep.c_str())) // test pour savoir si c'est vraiment un ddl
            { Enum_ddl enum_d = Id_nom_ddl(rep.c_str());
              Ddl_enum_etendu ddl_enu_etendue(enum_d);
              // on vérifie si le ddl existe dans la liste proposée
              if (Ddl_enum_etendu::Existe_dans_la_liste(tabnoeud_type_ddl(imail),ddl_enu_etendue))
                 {type_ddl_retenu(imail) = ddl_enu_etendue;}
              else
                 {cout << "\n ddl inexistant dans la liste proposee, recommencez";
                  choix_valide=false;
                  }
             }     
          }
        catch (ErrSortieFinale)
             // cas d'une direction voulue vers la sortie
             // on relance l'interuption pour le niveau supérieur
           { ErrSortieFinale toto;
             throw (toto);
           }
        catch (...)// erreur en lecture
          {  cout << "\n Erreur dans la lecture de ddl !!, "
                  << "\n redonnez une bonne valeur"
                  << "\n ou taper fin_prog pour arreter le programme"; 
             choix_valide=false;
           }
      } //-- fin du premier while 
     choix_valide=false; 
     while (!choix_valide)
      {
       try 
        { cout << "\n valeur du ddl ou variation entre t=0 et t (rep 1 ou 0 ) ? \n"
               << "\n reponse ?  ";
          rep = lect_1_0(false);
          if (rep == "1") {choix_var_ddl(imail)=true;choix_valide=true;}
          else if (rep == "0") {choix_var_ddl(imail)=false;choix_valide=true;}
          else 
           {cout << "\n mauvais choix, recommencez";choix_valide=false;}
          }
        catch (ErrSortieFinale)
             // cas d'une direction voulue vers la sortie
             // on relance l'interuption pour le niveau supérieur
           { ErrSortieFinale toto;
             throw (toto);
           }
        catch (...)// erreur en lecture
          {  cout << "\n Erreur dans le choix de la variation ou non des ddl !!, "
                  << "\n redonnez une bonne valeur";
             choix_valide=false;
           }
      } //-- fin du second while      
     }//-- fin de la boucle sur les maillages   
  };
  
// choix de grandeur existantes aux points d'intégrations et à ramener aux noeuds
// pour préparer une visualisation d'isovaleurs
void Isovaleurs_vrml::TransfertGrandeursPtIntegAuNoeud()
 { /*bool choix_valide = false;
   string rep;
   while (!choix_valide)
      {try 
        { cout 
          << "\n (0 ou f ou fin) fin modif"
          << "\n (1) definition des parametres generaux "
          << "\n (2) choix de l'isovaleur "
          << "\n (3) transferts aux noeuds de grandeurs existantes aux points d'integration";
          cout << "\n \n reponse ? ";
          cin >> rep;
          if (rep == "fin_prog") Sortie(1);
          // sinon
          int num = ChangeEntier(rep);
          if ((rep == "0")||(rep == "f")||(rep == "fin")) 
            { choix_valide=true; }
          else if ((num >= 1)&&(num<=3)) 
           { choix_valide=false;
             switch (num)
              { case 1:  //"definition des parametres generaux"
                { ParametresGeneraux(); break;}
                case 2:  // "choix de l'isovaleur"
                 {ChoixIsovaleur(); break;}
                case 3:  // "transferts aux noeuds de grandeurs existantes aux points d'integration"
                { choix_peau = false; break;}
                case 4:  // "calcul automatique des min max de la légende")
                { TransfertGrandeursPtIntegAuNoeud(); break;}
               }
             } 
          else { cout << "\n Erreur on attendait un entier entre 0 et 3 !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper fin_prog pour arreter le programme"; 
              choix_valide=false;
             }
         }    
       catch (...)// erreur de lecture
       {  cout << "\n Erreur on attendait un des mots cles proposés !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper fin_prog pour arreter le programme"; 
              choix_valide=false;
        }
       } //-- fin du while*/
  };     
