unit editdata;
{dernieres modifs
8/08/00: Edouard :modification de Tdataeditform.ComboBox1DropDown
18/10/00: Edouard : ajout des procedures spectre.savetoPAXY et spectre.readfromPAXY }
{ MODIFICATIONS                                                                     }
{ mise a jour le 31.10.2000                                                         }
{ 13.12.00, FO : ajout d'une procédure "litSpectre1D" et "litSpectre2D" pour lire un spectre a partir du disque dur }
{ 13.12.00, FO : ajout d'une variable "integrale" pour l'integrale du spectre entre les deux curseurs                 }
{ 12.01.01: FO : déclaration const sreg='\PilotageManip';                                                             }
{                déclaration indexFichierKey='indexFichier';                                                          }
{                deux nouvelles procédures function GetIndexFichierCrt:integer;
{                                          procedure IncIndexFichierCrt;                                     }
{ 17.01.01: EL : petite modif sur spectre.readfromfile}
{ 18.02.01: FO : upgrade du type POINTS : ajot de l'information temporelle ou lambda                         }
{                modification du type spectre : data devient un tableau 3D: X,Y,LT                           }
{ conséquences : modif de spectre.clear                                                                      }
{                modif de spectre.total : somme pour toutes les LT                                           }
{                modif de spectre.minmax : ne rend mnimax que pour LT = 0                                    }
{                      il faut prévoir un upgrade pour rendre minmax sur une tranche prédéfinie              }
{                spectlist.addspectre(nom:string;X:integer;Y:integer;LT:integer):integer; **LT** doit etre indiqué }
{ 02.03.01: CL : ajout des opérations arithmétiques pas encore fini+correction à faire}
{ 05.03.01 : FO : ajout des opérations de coupes :
{                function CoupeHSpectre2D(name:string;yy :double) :spectre; { coupe horizontale suivant la droite d'ordonnée y }
{                function CoupeVSpectre2D(name:string;xx :double) :spectre ; { coupe verticale suivant la droite d'ordonnée x }
{                ainsi que des opérations de projection et intégrales                                                                  }
{                function ProjectionHSpectre2D(name:string;x1,x2 :double):spectre; { projection horizontale entre les droite x1 et x2 }
{                function ProjectionVSpectre2D(name:string;y1,y2 :double):spectre; { projection verticale suivant la droite d'ordonnée x }
{                function IntegraleSpectre1D(x1,x2:double) :double; { somme entre les abscisses definies par x1 et x2 }
{                function IntegraleSpectre2D(x1,y1,x2,y2 :double) :double; { somme entre le rectangle defini par x1,y1 ,x2,y2 }
{                POUR LE MOMENT ne marche qu'avec les types 'raw'
{29.03.01 : EL   Nouvelle procedure de sauvegarde pour tous les spectres :                                 }
{                definition de nouveaux types: experimentalCondType et spectsave                           }
{                modification du Type spectre: + champs moniteur et ExpCondNbr + tableau  experimentalConditions }
{                creation de spectre.save et spectre.open                                                              }
{13.06.01 : EL : mise en conformité avec la version Traitement :
                 ajout des masques cir Ext et int
                 ajout de savetoASCII
                 ajout de spect[i].ExpCondNbr:=0; dans addspectre
{14.06.01: EL :  Modification de spectlist.add pour tenir compte du changement du format spectre.                      }
{15.06.01: EL :  petites Modifs dans les fonctions de masquage
{15.06.01: FO et EL : Unification des Editdata de pilotage et traitement,
                    - introduction de consigne de compilation,
                    - 2 Tdataeditform : 1 pour le pilotage et une pour le traitement sans F1book
                 Modification de spectlist.indexof : il n'y a plus de difference Majuscule/Minuscule   }
{10.07.01 : EL : création de la procedure spectre.masquesecteur                 }
{21.09.01 : EL : correction des opérations de coupes (oublie de la troisième dim)
{30.10.01 : FO : correction d'une erreur dans les fonctions de projection (PH)  }
{08.02.02 : EL : Petites modifs dans les procédures PAXY                        }
{05.04.02 : FO : procedure "sqrt"                                               }
{22.08.02 : FO : on repasse tout en "real" après l'expérience malencontreuse des singles }
{07.03.03 : FO : les masques fonctionnent à nouveau, au moins sur les data brutes       }
{ ======================================================================================================== }
{ A FAIRE                                                                                                  }
{ * les masques n'utilisent pas les champs .x et .y ; ils ne peuvent etre utilisé que sur des data brutes }
{ * implémenter les spectres complexes                                          }
{   utiliser le standard NeXuS pour cela                                        }
{ * dans les operations arithmetiques, on suppose que le specttre de sortie n'existe pas ?! }
{   pourquoi?                                                                   }
{ * il faut une fonction de copie d'un spectre à l'autre                        }
{ RENOMMER les procedure AddSpectre et add pour eviter les confusions => NewSpectre et TransfertSpectre    }
{ * faire le ménage dans les méthodes de spectList                       }
{ * Probleme avec AddSpectre, verifier la compatibilte des tailles sinon message d'erreur }
{ * ecrire une procedure qui rend la valeur d'un champ des conditions experimentales a partir du nom du champ }
{   GetPara(string):value                                                       }
{ * une fonction qui permettent de redimensionner une spectre serait bienvenues }

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  filectrl,StdCtrls, ExtCtrls, AxCtrls, OleCtrls, vcf1, Parser10, Buttons, registry,
  Spin,math, Grids, BaseGrid, AdvGrid, MtxVec, NexusCoreDelphiAPI, NexusUtilityDelphiAPI, math387;

const
  sreg='\LLB_programs';
  indexFichierKey='indexFichier';

const totalspectre = 99;
      NmaxSpectres2D = 100;

type  {utilisé pour l'enregistrement au format PAXY}
    PaXY=record
    entete:array[0..255] of char;
    data:array [0..127,0..127] of word; end;

    PaXE=record
    entete:array[0..255] of char;
    data:array [0..63,0..63] of word; end;

type
   ValuesVector =array[1..20] of double;


{ type point élémentaire contenant toutes les informations possibles }
type
    points=record
                mon:double;      { moniteur }
                x:double;        { coordonnée X, qui peut etre un angle ou un vecteur qx }
                y:double;        { coordonnée Y, qui peut etre un angle ou un vecteur qx }
                lt:double;       { coordonnée temporelle : longueur d'onde ou temps      }
                z:double;        { en général intensité mesurée                          }
                end;

type
    pspectsav=^spectsav;
    spectsav=record
    X:integer;
    Y:integer;
    nom:string[20];
    com:string[100];
    typX:string[6];
    typY:string[6];
    indexX:integer;
    indexY:integer;

end;
{**********************************
    NOUVEAUX TYPES POUR SAUVEGARDE}
Type
    experimentalCondType=record
                           name:string[20];
                           value:double;
                           end;
Type
    spectsave=record  {en-tete du nouveau format de sauvegarde}
    nom:string[20];
    comment:string[255];
    moniteur:double;
    X,Y,LT:integer; { tailles des différentes dimensions }
    ExpCondNbr:integer;  { nbr de cond exp. }
    typeX,typeY,typeLT:string[6];
    end;

type
    spectre=class(tobject)
    private
    fX:integer;fY:integer;fLT:integer;
    fnom:string;
    fcom:string;
    ftypX:string;ftypY:string;ftypLT:string;
    { Déclarations privées }
    protected
    public
    data:array of array of array of points;
    moniteur:double; {moniteur du spectre}
    indexX,indexY,indexLT:integer;         { que représentent ces paramètres ??? }
    ExpCondNbr:integer;  { nombre de cond exp. }
    experimentalConditions:array of ExperimentalCondType;   {champs libres pour conditions experimentales}
    property X:integer read fx write fx;           { taille de data dimension 1 }
    property Y:integer read fy write fy;           { taille de data dimension 2 }
    property LT:integer read flt write flt;        { taille de data dimension 3 }
    property Nom:string read fnom write fnom;
    property Comment:string read fcom write fcom;
    property typeX:string read ftypX write ftypX;  { raw OU mm OU nm-1 OU deg }
    property typeY:string read ftypY write ftypY;  { raw OU mm OU nm-1 OU deg }
    property typeLT:string read ftypLT write ftypLT; { nm OU sec } { lambda en nm ou temps en secondes }
    // ==================================== //
    // gestion des spectres
    procedure clear; { mise à zéro de tous les points du spectre }
    procedure minmax(var min:double;var max:double);
    function  interpolate(v:double):double;
    function  interpolate2D(u,v:double):double;        
    procedure savetofile(filename:string);
    procedure save(FileName:string);
    procedure open(FileName:string);
    procedure readfromfile(filename:string);
    procedure savetoPAXY(path,titre,nom,date,heure,temps:string;index:integer);
    procedure savetoPAXYfree(filename:string);
    procedure readfromPAXY(filename :string;var titre,nom,date,heure,temps:string);
    procedure readfromPAXE(filename :string;var titre,nom,date,heure,temps:string);
    procedure saveToASCII_2col(FileName:string);
    procedure saveToASCII_3col(FileName:string);
    procedure saveToASCII_4col(FileName:string);
    procedure SetExpCond(nom:string;valeur:double);
    procedure SaveToHDF(filename:string);
    procedure SaveToNexus(filename:string);
    procedure ReadFromNexus(filename:string);
    procedure ReadFromNexusLLB(filename:string);
    procedure ReadFromUXD(filename:string);
    procedure ReadFromG41dat(filename:string);
    // ==================================== //
    // opérations de projection
    function CoupeHSpectre2D(name:string;yy :double) :spectre; { coupe horizontale suivant la droite d'ordonnée y }
    function CoupeVSpectre2D(name:string;xx :double) :spectre ; { coupe verticale suivant la droite d'ordonnée x }
    function ProjectionHSpectre2D(name:string;x1,x2 :double):spectre; { projection horizontale entre les droite x1 et x2 }
    function ProjectionVSpectre2D(name:string;y1,y2 :double):spectre; { projection verticale suivant la droite d'ordonnée x }
    function IntegraleSpectre1D(x1,x2:double) :double; { somme entre les abscisses definies par x1 et x2 }
    function IntegraleSpectre2D(x1,y1,x2,y2 :double) :double; { somme entre le rectangle defini par x1,y1 ,x2,y2 }
    { renommer } function total:double;
    Function SommeCirculaireSpectre2D(name:string;x0,y0,pas :double) :spectre; { somme circulaire }
    function CoupeCirculaireSpectre2D(name:string;x0,y0,rayon:double) :spectre; { coupe circulaire }    
    function SommePetitsAngles(name,nomMasque:string;x0,y0,npoints,lambda,delta,dist:double):spectre; { somme circulaire }
    procedure FlipUD; { flipping des data UP - DOWN }
    procedure FlipLR; { flipping des data UP - DOWN }
    function  FFTshift: boolean;
    // ==================================== //
    //masques de spectres
    function MasqueRectInt(x1,y1,x2,y2 :double;name: string) :spectre ; { masque de rectangle intérieur }
    function MasqueRectExt(x1,y1,x2,y2 :double;name: string) :spectre ; { masque de rectangle extérieur }
    function MasqueCircInt(x0,y0,x1,y1 :double;name: string) :spectre ;
    function MasqueCircExt(x0,y0,x1,y1 :double;name: string) :spectre ;
    function MasqueSecteur(xc,yc,thetasym,thetaouv :double;name:string) :spectre ;
    // ==================================== //
end;

type    { liste de spectres }
    spectlist=class(tobject)
    protected
    procedure free; { verifier si c'est bien ecrit }
    public
    spect:array[1..totalspectre] of spectre;
    procedure createframe;   { A FAIRE DISPARAITRE }
    { CHANGER LE NOM }
    function addspectre(nom:string;X:integer;Y:integer;LT:integer):integer; { CREATION d'un nouveau spectre dans la liste et suppression si il existe deja un spectre de meme nom }
    { CHANGER LE NOM }
    procedure add(spec:spectre);          { ajout d'un spectre daje existant à la lsite des spectres }
    { ameliorer la cohérence des noms des procédures }
    { de débarrasser de deleteSpectre ou la passer en private au moins }
    procedure deletespectre(ind:integer); { suppression d'un spectre de la liste }
    procedure delete(nom:string); { suppression d'un spectre de la liste avec comme paramètre d'entrée le nom string du spectre }
    procedure clear(nom:string);          { suppression d'un spectre de la liste }
    function indexof(nom:string):integer; { rend l'indice d'un spectre à partir de son nom string }
    procedure saveall;
    { cette procedure devrait etre une methode de spectre par de spectList !!!! }
    procedure addpt(nom:string;x,y,lt,z,mon:extended);
    { function obscure }
    { commentaires incompréhensibles ! }
    { quoi rentre, quoi sort ?!?     }
    function parsechaine(s:string):boolean;{traite la chaîne du type nom3=f(nom1,nom2)}
    //---------------------------------------------------------------//
    // opérations arithmétiques sur les spectres
    function Addition(nom1,nom2,nom3:string):boolean;{nom1+nom2=nom3}
    function Soustraction(nom1,nom2,nom3:string):boolean;{nom1-nom2=nom3}
    function Multiplication(nom1,nom2,nom3:string):boolean;{nom1*nom2=nom3, point par point}
    function Division(nom1,nom2,nom3:string):boolean;{nom1/nom2=nom3, point par point}
    function ScalAdd(scalaire:double;nom1,nom2: string): boolean; {nom2=nom1+scalaire}
    function ScalSub(scalaire:double;nom1,nom2: string): boolean; {nom2=nom1-scalaire}
    function ScalMult(scalaire:double;nom1,nom2: string): boolean;{nom2=nom1*scalaire}
    function ScalDiv(scalaire:double;nom1,nom2: string): boolean; {nom2=nom1/scalaire}
    function SquareRoot(nom1,nom2:string):boolean;                    {nom2=sqrt(nom1) }
    function Positif(nom1,nom2:string):boolean;                    {nom2=sqrt(nom1) }     { met toutes les valeurs negatives d'un spectre à zero, pour éviter d'avoir des neutrons "négatifs" après traitement }
    function FFT(nom1:string;a,l:integer;nom2: string): boolean; { complex FFT }
    function FFT2(nom1:string;a,l,b,m:integer;nom2: string): boolean;
    function Module1D(nom1:string;nom2: string): boolean;          { module du vecteur complex }
    function Module2D(nom1:string;nom2: string): boolean;          { module du vecteur complex }
    //--------------------------------------------------------------//

    //--------------------------------------------------------------//
end;

type
  Tdataeditform = class(TForm)
    {F1Book1: TF1Book;}
    Panel1: TPanel;
    ComboBox1: TComboBox;
    Parser1: TParser;
    Edit1: TEdit;
    CHoix1D2D: TRadioGroup;
    SpeedButton2: TSpeedButton;
    SpeedButton3: TSpeedButton;
    SpeedButton4: TSpeedButton;
    SpeedButton5: TSpeedButton;
    OpenDialog1: TOpenDialog;
    X: TLabel;
    EditX: TEdit;
    Label1: TLabel;
    EditY: TEdit;
    Label2: TLabel;
    EdittypX: TEdit;
    Label3: TLabel;
    EdittypY: TEdit;
    Label4: TLabel;
    Editnom: TEdit;
    Label5: TLabel;
    Editcom: TEdit;
    Label6: TLabel;
    GridMesData: TAdvStringGrid;
    procedure ComboBox1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Edit1KeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure CHoix1D2DClick(Sender: TObject);
    procedure SpeedButton2Click(Sender: TObject);
    procedure SpeedButton3Click(Sender: TObject);
    procedure SpeedButton5Click(Sender: TObject);
    procedure SpeedButton4Click(Sender: TObject);
    procedure EdittypXChange(Sender: TObject);
    procedure EdittypYChange(Sender: TObject);
    procedure EditnomChange(Sender: TObject);
    procedure EditcomChange(Sender: TObject);
    procedure ComboBox1DropDown(Sender: TObject);


  private
    { Déclarations privées}
    unddeud:boolean;
  public
  procedure traitchaine(s:string);
  procedure sauve(i:integer;nom:string);
  procedure litSpectre1D(s:string);
  procedure litSpectre2D(s:string);

    { Déclarations publiques}
  end;

function fexis(nomf:string):boolean;
function GetIndexFichierCrt:integer;
procedure IncIndexFichierCrt;
function processFileName(s:string):string;
function processString(s:string):valuesVector;
function GetExtension(s:string):string;

var
  SourceDirectory:string;
  dataeditform: Tdataeditform;
  und:spectlist;    { liste de spectres 1D }
  deuxd:spectlist;  { liste de spectres 2D }
  troisd:spectlist; { liste de spectres 3D }
{ index frame doit disparaitre a terme }
  indexframe: array[1..16] of integer; {fait la correspondance entre le numero de frame et l'index du spectre}
  integrale:string; { integale du spectre en cours entre les curseurs }
  regis:tregistry;  { pointeur sur la base de registre }

implementation

uses BoiteNoire;


function maxi(a,b:double):double;
begin
   if a>b then maxi:=a else maxi:=b;
end;
function mini(a,b:double):double;
begin
   if a<b then mini:=a else mini:=b;
end;

{ verificatiuon si un fiochier existe deja sur le disque }
{ INPUT : nom complet du fichier avec chemin             }
{ OUPUT : oui/non                                        }
function fexis(nomf:string):boolean;
        var
        fich:file;
        begin
        {$I-}
        assignfile(fich,nomf);
        reset(fich);
        closefile(fich);
        {$I+}
        fexis:=(IOresult=0) and (nomf<>'');
        end;

{ lecture de l'index courant du spectre à sauvegarder }
{ INPUT : none                                        }
{ OUTPUT : l'index du dernier spectre sauvegardé      }
{ REM    : pas de modif de la base de registre        }
function GetIndexFichierCrt:integer;
var tf:boolean;
    id:integer;
begin
   id:=-1;
   regis:=tregistry.create;
   regis.RootKey := HKEY_CURRENT_USER;
   tf:=regis.KeyExists(sreg);
   if not tf then begin tf:=regis.openkey(sreg,true);regis.WriteInteger('IndexFichier',9999); end;
   tf:=regis.openkey(sreg,true);
   if tf then
   begin
      id:=regis.readinteger(indexFichierKey);
   end;
   regis.free;
   result:=id
end;

{ INPUT : chemin complet de fichier        }
{ OUTPUT : le nom du fichier sans son extension }
function processFileName(s:string):string;
var l:integer;
    nom,ext:string;
begin
   l:=length(s)+1;
   ext:='';
   repeat
   l:=l-1;
   ext:=s[l]+ext;
   until s[l]='.';
   l:=l-1;
   nom:=ext;
   nom:=''; { on fait sauter l'extension }
   repeat
   nom:=s[l]+nom;
   l:=l-1;
   until s[l]='\';
   result:=nom;
end;

{ INPUT : chemin complet de fichier        }
{ OUTPUT : le nom du fichier sans son extension }
function GetExtension(s:string):string;
var l:integer;
    nom,ext:string;
begin
   l:=length(s)+1;
   ext:='';
   repeat
   l:=l-1;
   ext:=s[l]+ext;
   until s[l]='.';
   result:=ext;
end;

{ procedure de traitement d'un chaine de caractère pour en extraire les valeurs numériques }
function processString(s:string):valuesVector;
var n,indiceValeur,errorCode:integer;
    s1:string;
    aux:double;
    finChaine:boolean;
    valeurs:valuesVector;
begin
    S1:='';n:=1;finChaine:=false;indiceValeur:=1;
    if s<>''
    then begin
        while not FinChaine do
        begin
             while (S[n]=' ') do inc(n);
             s1:='';
             while (S[n]<>#9) and (S[n]<>',') and (S[n]<>' ') and (n<=length(S)) do {#9 est un caractère tab , #10 est LF} { on lit jusqu'à un TAB, une virgule ou un espace }
             begin
                  s1:=s1+s[n];inc(n);
             end;
             if n>length(S) then FinChaine:=true;
             inc(n);{ on saute le tab ou la virgule }
             val(s1,aux,ErrorCode);valeurs[indiceValeur]:=aux;
             indiceValeur:=indiceValeur+1;
        end;
        end
    else valeurs[1]:=-9999;
    result:=Valeurs;
end;

{ incrémentation de l'index courant du spectre à sauvegarder }
{ le comptage boucle de 1000 à 9999                          }
{ on laisse tomber 1 à 999 pour ne pas à avoir à formater    }
{ INPUT : none                                        }
{ OUTPUT : l'index du fichier est incrémenté          }
{ REM    : si l'index arrive à 10000 on revient à 1000}
{          on garde toujours un nombre à 4 chiffres pour des problèmes de formatage }
procedure IncIndexFichierCrt;
var tf:boolean;
    id:integer;
begin
   regis:=tregistry.create;
   tf:=regis.openkey(sreg,true);
   if tf then
   begin
      id:=regis.readinteger(indexFichierKey);
      inc(id);if id=100000 then id:=10000;
      regis.writeinteger(indexFichierKey,id);
   end;
   regis.free;
end;

{$R *.DFM}

{ =============================================== }
{ opérations de gestion des SPECTRES              }

{---------------spectre---------------------------}
{ mise a zero de tous les points                  }
{ pas de changement de taille                     }
procedure spectre.clear;
var
i,j,k:integer;
begin
for i:=0 to X-1 do
for j:=0 to Y-1 do
for k:=0 to LT-1 do begin
data[i,j,k].x:=i;data[i,j,k].y:=j;data[i,j,k].lt:=k;data[i,j,k].z:=0;data[i,j,k].mon:=1;
end;
indexX:=0;indexY:=0;indexLT:=0
end;


{ *************************************** }
{ rend minmax d'un spectre 1D ou 2D       }
{ mais uniquement pour la tranche LT = 0  }
procedure spectre.minmax(var min:double;var max:double);
var
  i,j:integer;
begin
  min:=data[0,0,0].z;max:=data[0,0,0].z;
  for i:=0 to X-1 do
  for j:=0 to Y-1 do begin
  if min>data[i,j,0].z then min:=data[i,j,0].z;
  if max<data[i,j,0].z then max:=data[i,j,0].z;
  end;
end;

{ procedure d'interpolation                                                     }
{ INPUT : le point ou on veut déterminer la valeur                              }
{ OUTPUT : la valeur interpolée f(v)                                            }
{ A CORRIGER : cette procedure d'interpolation ne supporte pas que la graduation }
{ des abscisses soit négative                                                   }
function spectre.interpolate(v:double):double;
var i:integer;
    vmin,vmax,vaux,Iinf,Isup:double;
begin
   vmin:=data[0,0,0].x;vmax:=data[X-1,0,0].x;
   if vmax>vmin
   then begin
        i:=0;
        if v<=vmin
        then Result:=data[0,0,0].z
        else if v>vmax
             then Result:=data[X-1,0,0].z
             else begin
             while (data[i,0,0].x)<v do inc(i);
             Iinf:=data[i-1,0,0].z;Isup:=data[i,0,0].z;
             Result:=Iinf+(Isup-Iinf)/(data[i,0,0].x-data[i-1,0,0].x)*(v-data[i-1,0,0].x);
             end;
        end
   else begin { cas ou les abscisses sont décroissantes }
        vaux:=vmax;vmax:=vmin;vmin:=vaux;
        i:=0;
        if v<=vmin
        then Result:=data[X-1,0,0].z
        else if v>vmax
             then Result:=data[0,0,0].z
             else begin
                  while (data[i,0,0].x)>v do inc(i);
                  Iinf:=data[i-1,0,0].z;Isup:=data[i,0,0].z;
                  Result:=Iinf+(Isup-Iinf)/(data[i,0,0].x-data[i-1,0,0].x)*(v-data[i-1,0,0].x);
             end;
        end
end;

{ procedure d'interpolation                                                     }
{ modèle bilinéaire                                                             }
{ INPUT : le point ou on veut déterminer la valeur                              }
{ OUTPUT : la valeur interpolée f(u,v)                                            }
{ A CORRIGER : cette procedure d'interpolation ne supporte pas que la graduation }
{ des abscisses soit négative                                                   }
function spectre.interpolate2D(u,v:double):double;
var i,j,Iinf,Isup,Jinf,Jsup:integer;
    umin,umax,ustep,vmin,vmax,vstep:double;
    R11,R12,R21,R22,x11,y11,xx,yy:double;
begin
   umin:=data[0,0,0].x;umax:=data[X-1,0,0].x;ustep:=data[1,0,0].x-data[0,0,0].x;
   vmin:=data[0,0,0].y;vmax:=data[0,Y-1,0].y;vstep:=data[0,1,0].y-data[0,0,0].y;
   if (vmax>vmin) and (umax>umin)
   then begin
        i:=0;j:=0;
        { recherche des 4 points encadrants }
        if u<=umin
        then begin Iinf:=0;Isup:=1; end
        else if u>umax
             then begin Iinf:=X-2;Isup:=X-1; end
             else begin while (data[i,0,0].x)<u do inc(i);Isup:=i;Iinf:=i-1; end;
        if v<=vmin
        then begin Jinf:=0;Jsup:=1; end
        else if v>vmax
             then begin Jinf:=Y-2;Jsup:=Y-1; end
             else begin while (data[0,j,0].y)<v do inc(j);Jsup:=j;Jinf:=j-1; end;
        { calcul de l'interpolation entre les 4 points }
        R11:=data[Iinf,Jinf,0].z;R21:=data[Isup,Jinf,0].z;
        R22:=data[Isup,Jsup,0].z;R12:=data[Iinf,Jsup,0].z;
        x11:=data[Iinf,Jinf,0].x;y11:=data[Iinf,Jinf,0].y;
        xx:=(u-x11)/ustep;yy:=(v-y11)/vstep;
        Result:=(1-xX)*(1-yy)*R11+(1-xx)*yy*R12+xx*(1-yy)*R21+xx*yy*R22;
        end
{   else begin
        vaux:=vmax;vmax:=vmin;vmin:=vaux;
        i:=0;
        if v<=vmin
        then Result:=data[X-1,0,0].z
        else if v>vmax
             then Result:=data[0,0,0].z
             else begin
                  while (data[i,0,0].x)>v do inc(i);
                  Iinf:=data[i-1,0,0].z;Isup:=data[i,0,0].z;
                  Result:=Iinf+(Isup-Iinf)/(data[i,0,0].x-data[i-1,0,0].x)*(v-data[i-1,0,0].x);
             end;
        end }
end;


{***************************************
modifié le 8/06
filename = chemin+nom sans extension}
{ AMELIORER LA SUAVEGARDE AVEC LT<>0                  }
{ pour le moement ne sauvegarde que la tranche LT = 0 }
procedure spectre.SaveToFile(FileName: string);
var
fa:pspectsav;
fich:file of spectsav;
fich1:file of points;
fich2:file of double;
p:points;
i,j:integer;
filetot:string;
u:double;
begin
fa:=new(pspectsav);
fa.X:=X;fa.Y:=Y;
fa.indexX:=indexX;fa.indexY:=indexY;
fa.com:=comment;fa.nom:=nom;
fa.typX:=typeX;fa.typY:=typeY;
p.mon:=1;p.x:=0;p.y:=0;p.z:=0;u:=0;
if typex<>'raw' then
   begin
   filetot:=filename+'.spe';
   if fexis(filetot) then
      begin
      i:=1;
      filetot:=filename+inttostr(i)+'.spe';
      while fexis(filetot)do
            begin
            i:=i+1;
            filetot:=filename+inttostr(i)+'.spe';
            end;
      end;
   assignfile(fich,filetot);
   assignfile(fich1,filetot);
   rewrite(fich1);
   for i:=1 to 200 do write(fich1,p);{blanc}
   for i:=0 to X-1 do
   for j:=0 to Y-1 do write(fich1,data[i,j,0]);
   boitnoir.receivetext('sauvegarde sous '+filetot);
   closefile(fich1);
   reset(fich);
   write(fich,fa^);
   closefile(fich);
   end
else
    begin
    filetot:=filename+'.raw';
    if fexis(filetot) then
       begin
       i:=1;
       filetot:=filename+inttostr(i)+'.spe';
       while fexis(filetot)do
          begin
          i:=i+1;
          filetot:=filename+inttostr(i)+'.spe';
          end;
       end;
    assignfile(fich,filetot);
    assignfile(fich2,filetot);
    rewrite(fich2);
    for i:=1  to 200 do write(fich2,u);{blanc}
    for i:=0 to X-1 do
    for j:=0 to Y-1 do write(fich2,data[i,j,0].z);
    closefile(fich2);
    reset(fich);
    write(fich,fa^);
    closefile(fich);
    end;
dispose(fa);
end;

{***************************************}
{ ne lit que les spectres avec LT = 0    }
{ A AMELIORER                            }
procedure spectre.readfromfile(filename:string);
var
fa:pspectsav;
fich:file of spectsav;
fich1:file of points;
fich2:file of double;
p:points;
i,j:integer;
u:double;
begin
fa:=new(pspectsav);
assignfile(fich,filename);
assignfile(fich1,filename);
assignfile(fich2,filename);
reset(fich);
read(fich,fa^);
X:=fa.X;Y:=fa.Y;
comment:=fa.com;{nom:=fa.nom;}
typeX:=fa.typX;typeY:=fa.typY;
indexX:=fa.indexX;indexY:=fa.indexY;
setlength(data,X,Y,1);
closefile(fich);
if typeX<>'raw' then begin
reset(fich1);
for i:=1 to 200 do read(fich1,p);{blanc}
for i:=0 to X-1 do
for j:=0 to Y-1 do read(fich1,data[i,j,0]);
closefile(fich1);
end else begin
reset(fich2);
for i:=1 to 200 do read(fich2,u);{blanc}
for i:=0 to X-1 do
for j:=0 to Y-1 do read(fich2,data[i,j,0].z);
closefile(fich2);
{ATTENTION : format raw : indexX sert abusivement pour sauvegarder le moniteur!!}
data[0,0,0].mon:=indexX;
Lt:=1;
ExpCondNbr:=0;
setlength(experimentalConditions,ExpCondNbr);

end;
dispose(fa);
end;
{************************************* **************************************************************
NOUVELLE procedure de sauvegarde pour tous les spectres
En-tete : fichier Specsave,
+ suite de experimentalCondType
+ suite de real
principe: on ouvre un fichier de real, on ecrit des real sans importances pour laisser de la place a l'en-tete (322 octets)
et aux experimentalCondType. Puis on ferme le fichier de real et on ecrit par dessus les experimentalCondType
apres avoir laisse de la place pour l'en-tete
ATTENTION : par convention l'extension du fichier doit etre du type : 1Dxx, 2Dxx, 3Dxx selon la dim du spectre et l'etat de spin}
procedure spectre.save(FileName:string);
var temp:spectsave;
    fspec:file of spectsave;
    fdat:file of double;
    u:double;
    fcond:file of experimentalCondType;
    blanc:experimentalCondType;
    i,j,k:integer;
begin
{initialisation temp}
temp.nom:=nom;
temp.comment:=comment;
temp.moniteur:=moniteur;
temp.X:=X;
temp.Y:=Y;
temp.Lt:=Lt;
temp.typeX:=typeX;
temp.typeY:=typeY;
temp.typeLt:=typeLt;
temp.ExpCondNbr:=ExpCondNbr;
assignfile(fspec,Filename);
assignfile(fdat,Filename);
assignfile(fcond,FileName);
rewrite(fdat);

{** ecriture des Data}
{blanc en-tete (50 real = 400 octets)}
for i:=0 to 50 do write(fdat,u);
{blanc conditions experimentales (29 octets par condition/8 octets par real plus marge de secu}
for i:=0 to (round(ExpCondNbr*3.7)+10) do write(fdat,u);
{ecriture des echelles}
for i:=0 to X-1 do
    write(fdat,data[i,0,0].x);
for i:=0 to Y-1 do
    write(fdat,data[0,i,0].y);
for i:=0 to Lt-1 do
    write(fdat,data[0,0,i].Lt);
{ecriture des Datas}
for i:=0 to X-1 do
    for j:=0 to Y-1 do
        for k:=0 to Lt-1 do
        write(fdat,data[i,j,k].z);
closefile(fdat);

{** ecriture des conditions experimentales}
reset(fcond);
{blanc en-tete: 13*29=377 octets}
for i:=0 to 13 do write(fcond,blanc);
for i:=0 to ExpCondNbr-1 do
    write(fcond,experimentalConditions[i]);
closefile(fcond);
{** ecriture en-tete}
reset(fspec);
write(fspec,temp);
closefile(fspec);
end;
{************************************* **************************************************************
NOUVELLE Procedure de lecture de spectre :
le nom du spectre n'est pas charge (le spectre appellant cette methode garde son propre nom
initialisation des tailles de tableau et des champs x, y et lt}
procedure spectre.open(FileName:string);
var temp:spectsave;
    fspec:file of spectsave;
    fdat:file of double;
    u:double;
    fcond:file of experimentalCondType;
    blanc:experimentalCondType;
    i,j,k:integer;
begin
assignfile(fspec,FileName);
assignfile(fdat,FileName);
assignfile(fcond,FileName);
{** lecture en tete}
reset(fspec);
read(fspec,temp);
closefile(fspec);
{nom:=temp.nom;}
comment:=temp.comment;
moniteur:=temp.moniteur;
X:=temp.X;
Y:=temp.Y;
Lt:=temp.Lt;
typeX:=temp.typeX;
typeY:=temp.typeY;
typeLt:=temp.typeLt;
ExpCondNbr:=temp.ExpCondNbr;
{***lecture Datas}
setlength(data,X,Y,Lt);
reset(fdat);
{blanc en tete}
for i:=0 to 50 do read(fdat,u);
{blanc conditions experimentales}
for i:=0 to (round(ExpCondNbr*3.7)+10) do read(fdat,u);
{lecture Datas}
for i:=0 to X-1 do
    read(fdat,data[i,0,0].x);
for i:=0 to Y-1 do
    read(fdat,data[0,i,0].y);
for i:=0 to Lt-1 do
    read(fdat,data[0,0,i].Lt);
for i:=0 to X-1 do
    for j:=0 to Y-1 do
        for k:=0 to Lt-1 do
        read(fdat,data[i,j,k].z);
closefile(fdat);
{** lecture conditions experimentales}
setlength(experimentalConditions,ExpCondNbr);
reset(fcond);
{blanc en tete}
for i:=0 to 13 do read(fcond,blanc);
for i:=0 to ExpCondNbr-1 do
    read(fcond,experimentalConditions[i]);
closefile(fcond);
{remplissage des echelles}
for i:=0 to X-1 do
    for j:=0 to Y-1 do
        for k:=0 to Lt-1 do
            begin
            data[i,j,k].x:=data[i,0,0].x;
            data[i,j,k].y:=data[0,j,0].y;
            data[i,j,k].lt:=data[0,0,k].lt;
            data[i,j,k].mon:=1;
            end;
end;
{***********************************************
enregistre une spectre 2D Raw 128*128 (format PAPOL) au format paxy
path: chemin complet terminé par \
titre : titre de la manip 6 caractères,
nom : nom de l'echantillon 6 caractères,
date : 10 caractères
heure : 8 caractères
temps : temps de comptage 6 caractères
index : numero du fichier PAXY 4 caractères}
procedure spectre.savetoPAXY(path,titre,nom,date,heure,temps:string;index:integer);
var i,j,dataint:integer;
    temp,filename:string;
    f:file of paxy;
    dbyte:word;
    fort,faible:byte;
    paxytemp:paxy;
begin
{******  creation de la tete du fichier PAXY}
{initialisation}
for i:=0 to 255 do paxytemp.entete[i]:='1';
{n° fichier}
paxytemp.entete[0]:='X';paxytemp.entete[1]:='Y';
temp:=inttostr(9999);
for j:=2 to 5 do
    if j<= 5-length(temp) then
       paxytemp.entete[j]:='0'
    else  paxytemp.entete[j]:=temp[j+length(temp)-5];
{titre manip}
for j:=1 to 6 do
    if j>length(titre)
    then paxytemp.entete[j+5]:=' '
    else paxytemp.entete[j+5]:=titre[j];
{nom echantillon}
for j:=1 to 12 do
    if j>length(nom)
    then paxytemp.entete[j+11]:=' '
    else paxytemp.entete[j+11]:=nom[j];
{temps de comptage}
for j:=1 to 6 do
    if j>length(temps)
    then paxytemp.entete[j+23]:=' '
    else paxytemp.entete[j+23]:=temps[j];
{moniteur}
temp:=inttostr(trunc(moniteur));
for j:=1 to 8 do
    if j<=8-length(temp)
    then paxytemp.entete[29+j]:='0'
    else paxytemp.entete[29+j]:=temp[length(temp)-8+j];
{date}
for j:=1 to 10 do
    if j>length(date)
    then paxytemp.entete[j+37]:=' '
    else paxytemp.entete[j+37]:=date[j];
{heure}
for j:=1 to 8 do
    if j>length(heure)
    then paxytemp.entete[j+47]:=' '
    else paxytemp.entete[j+47]:=heure[j];
{commentaires}
for j:=67 to 255 do
    if (j-66)>length(comment)
    then paxytemp.entete[j]:=' '
    else paxytemp.entete[j]:=comment[j-66];


{******  sauvegarde des datas avec inversion poids fort poids faible}
for i:=0 to 127 do
	for j:=0 to 127 do
	begin
	dataint:=trunc(data[j,127-i,0].Z);
        fort:=dataint div 256;
        faible:=dataint mod 256;
        dbyte:=faible*256+fort;
	paxytemp.data[i,j]:=dbyte;
	end ;
{****** enregistrement}
filename:=path+copy(paxytemp.entete,0,6)+'.dat';
assignfile(f,filename);
rewrite(f);
write(f,paxytemp);
closefile(f);
end;

{***********************************************
enregistre une spectre 2D Raw 128*128 (format PAPOL) au format paxy
en format libre en particulier pour le nom du fichier
path: chemin complet terminé par \
titre : titre de la manip 6 caractères,
nom : nom de l'echantillon 6 caractères,
date : 10 caractères
heure : 8 caractères
temps : temps de comptage 6 caractères
index : numero du fichier PAXY 4 caractères}
procedure spectre.savetoPAXYfree(filename:string);
var i,j,dataint:integer;
    temp:string;
    f:file of paxy;
    dbyte:word;
    fort,faible:byte;
    paxytemp:paxy;
    index:integer;
    titre,temps,date,heure:string;
begin
   temp:='XY0000titre MySample    0999991111111117/09/200419:41:4600855042300';
   for i:=0 to 66 do paxytemp.entete[i]:=temp[i+1];

{******  sauvegarde des datas avec inversion poids fort poids faible}
for i:=0 to 127 do
	for j:=0 to 127 do
	begin
	dataint:=trunc(data[j,127-i,0].Z);
        fort:=dataint div 256;
        faible:=dataint mod 256;
        dbyte:=faible*256+fort;
	paxytemp.data[i,j]:=dbyte;
	end ;
{****** enregistrement}
assignfile(f,filename);
rewrite(f);
write(f,paxytemp);
closefile(f);
end;


{***********************************************
lit un spectre au format PAXY}
procedure spectre.readfromPAXY(filename :string;var titre,nom,date,heure,temps:string);
var i,j,dataint:integer;
    temp:string;
    f:file of paxy;
    dbyte:word;
    fort,faible:byte;
    paxytemp:paxy;
begin
if fexis(filename) then
begin
{***** lecture}
assignfile(f,filename);
reset(f);
read(f,paxytemp);
closefile(f);
{**** extraction tete et enregistrement dans le spectre}
titre:=copy(paxytemp.entete,7,6);
nom:=copy(paxytemp.entete,13,12);
temps:=copy(paxytemp.entete,25,6);
temp:=copy(paxytemp.entete,31,8);
moniteur:=strtofloat(temp);
date:=copy(paxytemp.entete,39,10);
heure:=copy(paxytemp.entete,49,8);
comment:=copy(paxytemp.entete,68,189);
{**** extraction data}
for i:=0 to 127 do
	for j:=0 to 127 do
	begin
        dataint:=paxytemp.data[i,j];
        fort:=dataint div 256;
        faible:=dataint mod 256;
        dbyte:=faible*256+fort;
{        data[j,127-i,0].X:=i;data[j,127-i,0].Y:=j;data[j,127-i,0].Z:=dbyte; }
        data[j,i,0].X:=j;data[j,i,0].Y:=i;data[j,i,0].Z:=dbyte;
	end ;
typeX:='raw';
typeY:='raw';
X:=128;Y:=128;LT:=1;
end;
end;

{***********************************************
lit un spectre au format PAXY}
procedure spectre.readfromPAXE(filename :string;var titre,nom,date,heure,temps:string);
var i,j,dataint:integer;
    temp:string;
    f:file of paxe;
    dbyte:word;
    fort,faible:byte;
    paxytemp:paxe;
begin
if fexis(filename) then
begin
{***** lecture}
assignfile(f,filename);
reset(f);
read(f,paxytemp);
closefile(f);
{**** extraction tete et enregistrement dans le spectre}
titre:=copy(paxytemp.entete,7,6);
nom:=copy(paxytemp.entete,13,12);
temps:=copy(paxytemp.entete,25,6);
temp:=copy(paxytemp.entete,31,8);
moniteur:=strtofloat(temp);
date:=copy(paxytemp.entete,39,10);
heure:=copy(paxytemp.entete,49,8);
comment:=copy(paxytemp.entete,68,189);
{**** extraction data}
for i:=0 to 63 do
	for j:=0 to 63 do
	begin
        dataint:=paxytemp.data[i,j];
        fort:=dataint div 256;
        faible:=dataint mod 256;
        dbyte:=faible*256+fort;
{        data[j,127-i,0].X:=i;data[j,127-i,0].Y:=j;data[j,127-i,0].Z:=dbyte; }
        data[j,i,0].X:=j;data[j,i,0].Y:=i;data[j,i,0].Z:=dbyte;
	end ;
typeX:='raw';
typeY:='raw';
X:=64;Y:=64;LT:=1;
end;
end;


{************************************* ************************************************************* }
{ NOUVELLE procedure de sauvegarde en fichier ASCII                                                  }
{ INPUT : un nom de fichier pour la suavegarde sur le disque dur                                     }
{         une ligne de commentaire                                                                   }
{ OUTPUT : le format text basique X Y LT intensity                                                   }
{         si le format est 'raw' on sauvegarde les indices sinon les vraies valeurs de X,Y,LT        }
procedure spectre.saveToASCII_2col(FileName:string);
var i,j,k:integer;
    fich:text;
    s:string;
begin
    assignfile(fich,FileName);
    rewrite(fich);
    writeln(fich,comment); { ecriture d'un commentaire en première ligne }
    writeln(fich,FloatToStr(X)); { ecriture de la longeur du spectre 1D en deuxième ligne }
    j:=0;k:=0;
    for i:=0 to X-1 do
         begin
             s:='';
             s:=FloatToStr(data[i,j,k].x)+#9;
             writeln(fich,s+FloatToStr(data[i,j,k].z));
         end;
    closefile(fich);
end;
{************************************* ************************************************************* }
{ NOUVELLE procedure de sauvegarde en fichier ASCII                                                  }
{ INPUT : un nom de fichier pour la suavegarde sur le disque dur                                     }
{         une ligne de commentaire                                                                   }
{ OUTPUT : le format text basique X Y LT intensity                                                   }
{         si le format est 'raw' on sauvegarde les indices sinon les vraies valeurs de X,Y,LT        }
procedure spectre.saveToASCII_3col(FileName:string);
var i,j,k:integer;
    fich:text;
    s:string;
begin
    assignfile(fich,FileName);
    rewrite(fich);
    writeln(fich,comment); { ecriture d'un commentaire en première ligne }
    writeln(fich,FloatToStr(X)); { ecriture de la longeur du spectre 1D en deuxième ligne }
    writeln(fich,FloatToStr(Y)); { ecriture de la longeur du spectre 1D en deuxième ligne }
    k:=0;
    for i:=0 to X-1 do
      for j:=0 to Y-1 do
         begin
             s:='';
             s:=FloatToStr(data[i,j,k].x)+#9;
             s:=s+FloatToStr(data[i,j,k].y)+#9;
             writeln(fich,s+FloatToStr(data[i,j,k].z));
         end;
    closefile(fich);
end;

{************************************* ************************************************************* }
{ NOUVELLE procedure de sauvegarde en fichier ASCII                                                  }
{ INPUT : un nom de fichier pour la suavegarde sur le disque dur                                     }
{         une ligne de commentaire                                                                   }
{ OUTPUT : le format text basique X Y LT intensity                                                   }
{         si le format est 'raw' on sauvegarde les indices sinon les vraies valeurs de X,Y,LT        }
procedure spectre.saveToASCII_4col(FileName:string);
var i,j,k:integer;
    fich:text;
    s:string;
begin
    assignfile(fich,FileName);
    rewrite(fich);
    writeln(fich,comment); { ecriture d'un commentaire en première ligne }
    writeln(fich,FloatToStr(X)); { ecriture de la longeur du spectre 1D en deuxième ligne }
    writeln(fich,FloatToStr(Y)); { ecriture de la longeur du spectre 1D en deuxième ligne }
    writeln(fich,FloatToStr(LT)); { ecriture de la longeur du spectre 1D en deuxième ligne }
    for i:=0 to X-1 do
      for j:=0 to Y-1 do
         for k:=0 to LT-1 do
         begin
             s:='';
             s:=FloatToStr(data[i,j,k].x)+#9;
             s:=s+FloatToStr(data[i,j,k].y)+#9;
             s:=s+FloatToStr(data[i,j,k].lt)+#9;
             writeln(fich,s+FloatToStr(data[i,j,k].z));
         end;
    closefile(fich);
end;


{***********************************************
Modifie la liste de conditions expérimentales, avec creation du champ si il n'existe pas
INPUT : nom : nom de la condition expérimentalle
        valeur : valeur a affecter
OUPUT : tableau experimentalConditions
        entier ExpCondNbr}
procedure spectre.SetExpCond(nom:string;valeur:double);
var i,index:integer;
begin
index:=-1;
if ExpCondNbr<>0 then  {recherche du champ nom}
   for i:=0 to ExpCondNbr-1 do
       if experimentalConditions[i].name=nom then index:=i;
if index=-1 then
   begin  {le champ nom n'existe pas : creation}
   ExpCondNbr:=ExpCondNbr+1;
   setlength(experimentalConditions,ExpCondNbr);
   index:=ExpCondNbr-1;
   experimentalConditions[index].name:=nom;
   end;
{affectation de la nouvelle valeur}
experimentalConditions[index].value:=valeur;
end;

{ ============================================================================= }
{ reading / writing of files in the Nexus format                                }
{ the Nexus Convention is followed i.e. a NX entry group (named entry)          }
{ is systematically created                                                     }
procedure spectre.SaveToNexus(filename:string);
var status,i,j,file_id:integer;
    xaxis,yaxis,zdata:TDynArrayFloat64;
    zdata2D:TDynArray2DFloat64;
    s:string;
begin
   if fileExists(fileName)
   then begin NXOpen(StrToPChar(filename),NXACC_RDWR,file_id);  { this splitting between opengroup and write group should idsappear when writeGroup Works properly }
              NXopenGroup(file_id,'entry','NXentry');
              NXopenGroup(file_id,'data','NXdata'); end
   else begin NXOpen(StrToPChar(filename),NXACC_CREATE,file_id);
              NXUwriteGroup(file_id,'entry','NXentry');
              NXUwriteGroup(file_id,'data','NXdata'); end;
   if Y=1
   then begin { sauvegarde d'un fichier sous la forme 1D }
        { the data must be processed in order to be saved }
        setLength(xaxis,X);setLength(zdata,X);
        for i:=0 to X-1 do begin xaxis[i]:=data[i,0,0].x;zdata[i]:=data[i,0,0].z; end;
        NXUWriteData(file_id,'xaxis',xaxis,typeX);
        NXputAttr(file_id,'primary',1);
        NXputAttr(file_id,'axis',1); { identifies the main axis }
        NXUWriteData(file_id,'z',zdata,'raw');
        NXputAttr(file_id,'signal',1); { identifies the signal }
        for i:=0 to ExpCondNbr-1 do
          begin s:=experimentalConditions[i].name;status:=NXPutAttr(file_id,s,experimentalConditions[i].value); end;
        end
   else begin { sauvegarde d'un fichier sous la forme 1D }
        { the data must be processed in order to be saved }
        NXUsetcompress(file_id,NX_COMP_LZW,100);
        setLength(xaxis,X);setLength(yaxis,Y);
        setLength2D(zdata2D,X,Y);
        for i:=0 to X-1 do xaxis[i]:=data[i,0,0].x;
        for i:=0 to Y-1 do yaxis[i]:=data[0,i,0].y;
        for i:=0 to X-1 do
           for j:=0 to Y-1 do zdata2D[i,j]:=data[i,j,0].z;
        NXUWriteData(file_id,'xaxis',xaxis,typeX);
        NXputAttr(file_id,'primary',1);
        NXputAttr(file_id,'axis',1); { identifies the main axis }
        NXUWriteData(file_id,'yaxis',yaxis,typeY);
        NXputAttr(file_id,'primary',1);
        NXputAttr(file_id,'axis',2); { identifies the main axis }
        NXUWriteData(file_id,'z',zdata2D,'raw');
        NXputAttr(file_id,'signal',1); { identifies the signal }
        for i:=0 to ExpCondNbr-1 do
          begin s:=experimentalConditions[i].name;status:=NXPutAttr(file_id,s,experimentalConditions[i].value); end;
        end;
   NXClose(file_id);
end;

{ ============================================================================= }
{ reading / writing of files in the Nexus format                                }
{ the Nexus Convention is followed i.e. a NX entry group (named entry)          }
{ is systematically created                                                     }
procedure spectre.SaveToHDF(filename:string);
var status,i,j,file_id:integer;
    xaxis,yaxis,zdata:TDynArrayFloat64;
    zdata2D:TDynArray2DFloat64;
    s:string;
begin
   if fileExists(fileName)
   then begin NXOpen(StrToPChar(filename),NXACC_RDWR,file_id);  { this splitting between opengroup and write group should idsappear when writeGroup Works properly }
{              NXopenGroup(file_id,'entry','NXentry');
              NXopenGroup(file_id,'data','NXdata'); } end
   else begin NXOpen(StrToPChar(filename),NXACC_CREATE,file_id);
{              NXUwriteGroup(file_id,'entry','NXentry');
              NXUwriteGroup(file_id,'data','NXdata'); } end;
   if Y=1
   then begin { sauvegarde d'un fichier sous la forme 1D }
        { the data must be processed in order to be saved }
        setLength(xaxis,X);setLength(zdata,X);
        for i:=0 to X-1 do begin xaxis[i]:=data[i,0,0].x;zdata[i]:=data[i,0,0].z; end;
        NXUWriteData(file_id,'xaxis',xaxis,typeX);
        NXputAttr(file_id,'primary',1);
        NXputAttr(file_id,'axis',1); { identifies the main axis }
        NXUWriteData(file_id,'z',zdata,'raw');
        NXputAttr(file_id,'signal',1); { identifies the signal }
        for i:=0 to ExpCondNbr-1 do
          begin s:=experimentalConditions[i].name;status:=NXPutAttr(file_id,s,experimentalConditions[i].value); end;
        end
   else begin { sauvegarde d'un fichier sous la forme 1D }
        { the data must be processed in order to be saved }
        NXUsetcompress(file_id,NX_COMP_LZW,100);
        setLength(xaxis,X);setLength(yaxis,Y);
        setLength2D(zdata2D,X,Y);
        for i:=0 to X-1 do xaxis[i]:=data[i,0,0].x;
        for i:=0 to Y-1 do yaxis[i]:=data[0,i,0].y;
        for i:=0 to X-1 do
           for j:=0 to Y-1 do zdata2D[i,j]:=data[i,j,0].z;
        NXUWriteData(file_id,'xaxis',xaxis,typeX);
        NXputAttr(file_id,'primary',1);
        NXputAttr(file_id,'axis',1); { identifies the main axis }
        NXUWriteData(file_id,'yaxis',yaxis,typeY);
        NXputAttr(file_id,'primary',1);
        NXputAttr(file_id,'axis',2); { identifies the main axis }
        NXUWriteData(file_id,'z',zdata2D,'raw');
        NXputAttr(file_id,'signal',1); { identifies the signal }
        for i:=0 to ExpCondNbr-1 do
          begin s:=experimentalConditions[i].name;status:=NXPutAttr(file_id,s,experimentalConditions[i].value); end;
        end;
   NXClose(file_id);
end;


{ Requirement : the structure follows : 'entry' main group                      }
{ the data must be in the group 'data' for the moment                           }
{ INPUT : filename }
procedure spectre.ReadFromNexus(filename:string);
var i,j,file_id,status:integer;
    xaxis,yaxis,zdata:TDynArrayFloat64;
    zdata2D:TDynArray2DFloat64;
    rank,data_type,Xsize,Ysize,find_index,axis_dim:integer;
    Xunits,Yunits,Zunits:string;
    NXdims:dimensions;
    data_name,group_name,axis1_name,axis2_name:string;
begin
 if not fileExists(fileName)
 then MessageDlg('File does not exist', mtInformation,[mbOk], 0)
 else begin
      status:=NXOpen(StrToPChar(filename),NXACC_READ,file_id);
      status:=NXUfindClass(file_id,'NXentry',group_name,1);
      status:=NXopenGroup(file_id,StrToPChar(group_name),'NXentry');
      status:=NXUfindClass(file_id,'NXdata',group_name,1);
      status:=NXopenGroup(file_id,StrToPChar(group_name),'NXdata');
      status:=NXUfindSignal(file_id,1,data_name,rank,data_type,NXdims);
{      status:=NXopenData(file_id,'z');
      status:=NXgetInfo(file_id,rank,NXdims,data_type); }
      if rank = 1
      then begin
           status:=NXUfindAxis(file_id,1,1,axis1_name,rank,data_type,axis_dim);
           status:=NXUreaddata(file_id,axis1_name,xaxis,Xunits); { the procedure initialises the sizes }
           status:=NXUreaddata(file_id,data_name,zdata,Zunits);
           { copie des data dans le spectre }
           Xsize:=high(xaxis)+1;X:=Xsize;Y:=1;LT:=1;
           setlength(data,xsize,1,1); { SHOULD NOT WORK IN PRINCIPLE; NOT DOCUMENTED !! }
           for i:=0 to Xsize-1 do begin data[i,0,0].x:=xaxis[i];data[i,0,0].z:=zdata[i] end;
           typeX:=Xunits;
           end;
      if rank = 2
      then begin
           setLength(zdata2D,1,1); { so that a size is available } { No very nice }
           status:=NXUfindAxis(file_id,1,1,axis1_name,rank,data_type,axis_dim);
           status:=NXUfindAxis(file_id,2,1,axis2_name,rank,data_type,axis_dim);
           status:=NXUreaddata(file_id,axis1_name,xaxis,Xunits);
           status:=NXUreaddata(file_id,axis2_name,yaxis,Yunits);
           status:=NXUreaddata(file_id,data_name,zdata2D,Zunits);
           { copie des data dans le spectre }
           Xsize:=high(xaxis)+1;Ysize:=high(yaxis)+1;
           X:=Xsize;Y:=Ysize;LT:=1;
           setlength(data,Xsize,Ysize,1);
           for i:=0 to Xsize-1 do
             for j:=0 to Ysize-1 do
                begin data[i,j,0].x:=xaxis[i];data[i,j,0].y:=yaxis[j];data[i,j,0].z:=zdata2D[i,j] end;
           typeX:=Xunits;typeY:=Yunits;
           end;
      end;
   NXClose(file_id);
end;

{ Requirement : the structure follows : 'entry' main group                      }
{ the data must be in the group 'data' for the moment                           }
{ INPUT : filename }
{ procedure spéciale LLB parce que le format n'est pas NeXuS compliant }
procedure spectre.ReadFromNexusLLB(filename:string);
var i,j,file_id,status:integer;
    monitorCounts:integer;
    xaxis,yaxis,zdata:TDynArrayFloat64;
    xaxis2D,yaxis2D,zdata2D:TDynArray2DFloat32;
    rank,data_type,Xsize,Ysize,find_index,axis_dim:integer;
    Xunits,Yunits,Zunits:string;
    NXdims:dimensions;
    data_name,group_name,axis1_name,axis2_name:string;
begin
 if not fileExists(fileName)
 then MessageDlg('File does not exist', mtInformation,[mbOk], 0)
 else begin
      status:=NXOpen(StrToPChar(filename),NXACC_READ,file_id);
      status:=NXUfindClass(file_id,'NXentry',group_name,1);
      status:=NXopenGroup(file_id,StrToPChar(group_name),'NXentry');

      status:=NXUfindClass(file_id,'NXmonitor',group_name,1);
      status:=NXopenGroup(file_id,StrToPChar(group_name),'NXmonitor');
      status:=NXopendata(file_id, StrToPChar('monitor'));
      status:=NXgetdata(file_id, monitorCounts);
      status:=NXcloseGroup(file_id);
      moniteur:=monitorCounts;

      status:=NXUfindClass(file_id,'NXdata',group_name,1);
      status:=NXopenGroup(file_id,StrToPChar(group_name),'NXdata');
      status:=NXUfindSignal(file_id,1,data_name,rank,data_type,NXdims);
      if NXdims[2]=1 then rank:=1;
{      status:=NXopenData(file_id,'z');
      status:=NXgetInfo(file_id,rank,NXdims,data_type); }
      if rank = 1
      then begin
{           status:=NXUfindAxis(file_id,1,1,axis1_name,rank,data_type,axis_dim); }
{           status:=NXUreaddata(file_id,'x_axis',xaxis,Xunits); { the procedure initialises the sizes }
{           status:=NXUreaddata(file_id,data_name,zdata,Zunits); }
           status:=NXOpenData(file_id,StrToPChar('x_axis'));
           status:=NXgetdata(file_id, xaxis2D);
           status:=NXOpenData(file_id,StrToPChar(data_name));
           status:=NXgetdata(file_id, zdata2D);
           Xunits:='raw';Yunits:='raw';Zunits:='raw';
           { copie des data dans le spectre }
           Xsize:=high(xaxis2D)+1;X:=Xsize;Y:=1;LT:=1;
           setlength(data,xsize,1,1); { SHOULD NOT WORK IN PRINCIPLE; NOT DOCUMENTED !! }
           for i:=0 to Xsize-1 do begin data[i,0,0].x:=xaxis2D[i,0];data[i,0,0].z:=zdata2D[i,0] end;
           typeX:=Xunits;
           end;
      if rank = 2
      then begin
           setLength(zdata2D,1,1);setLength(xaxis2D,1,1);setLength(yaxis2D,1,1); { so that a size is available } { No very nice }
{           status:=NXUfindAxis(file_id,1,1,axis1_name,rank,data_type,axis_dim);
           status:=NXUfindAxis(file_id,2,1,axis2_name,rank,data_type,axis_dim); }
           status := NXOpenData(file_id,StrToPChar(data_name));
           status:=NXgetdata(file_id, zdata2D);
           status:=NXUreaddata(file_id,'x_axis',xaxis2D,Xunits);
           status:=NXUreaddata(file_id,'y_axis',yaxis2D,Yunits);
{           status:=NXUreaddata(file_id,data_name,zdata2D,Zunits); }
           Xunits:='raw';Yunits:='raw';Zunits:='raw';
           { copie des data dans le spectre }
           Xsize:=high(xaxis2D)+1;Ysize:=high(yaxis2D)+1;
           X:=Xsize;Y:=Ysize;LT:=1;
           setlength(data,Xsize,Ysize,1);
           for i:=0 to Xsize-1 do
             for j:=0 to Ysize-1 do
                begin data[i,j,0].x:=xaxis2D[i,0];data[i,j,0].y:=yaxis2D[j,0];data[i,j,0].z:=zdata2D[i,j] end;
           typeX:=Xunits;typeY:=Yunits;
           end;
      end;
   NXClose(file_id);
end;



procedure spectre.ReadFromUXD(filename:string);
var
  i,j:integer;
  F1, F2: TextFile;
  S, S1, S2, S3, S4,s5,s6: string[255];
  name:string;
  stepsize,startangle,dataj:double;
  nbrpts:integer;
  datx,datz:Tvec;
begin
AssignFile(F1,Filename);
Reset(F1);
Readln(F1,S);
Readln(F1,S);
Readln(F1,S);
i:=1;
while s[i]<>#39 do
        begin
        s1:='';
        inc(i);
        end;
inc(i); {on passe au caractere suivant pour sauter '}
while i<=(length(s)-1) do
        begin
        s1:=s1+s[i];
        inc(i);
        end;
s5:=uppercase(s1);
name:=s5;
s1:='';
for i:=1 to 13 do Readln(F1,S); {on saute 13 lignes pour lire le stepsize}
{lecture du pas}
i:=1;
while s[i]<>' ' do
        begin
        s1:='';
        inc(i);
        end;
while i<=length(s) do
        begin
        while s[i]=' ' do begin s1:='';inc(i);end;
        s1:=s1+s[i];
        inc(i);
        end;
s2:=uppercase(s1);
stepsize:=strtofloat(s2);
s1:='';
Readln(F1,S);
Readln(F1,S);
{lecture de l'angle de depart}
i:=1;
while s[i]<>'=' do
        begin
        s1:='';
        inc(i);
        end;
while i<=length(s) do
        begin
        while s[i]=' ' do begin s1:='';inc(i);end;
        s1:=s1+s[i];
        inc(i);
        end;
s3:=uppercase(s1);
startangle:=strtofloat(s3);
s1:='';
for i:=1 to 11 do Readln(F1,S); {on saute 10 lignes pour lire le nombre de points}
{lecture du nombre de points}
i:=1;
while s[i]<>'=' do
        begin
        s1:='';
        inc(i);
        end;
while i<=length(s) do
        begin
        while s[i]=' ' do begin s1:='';inc(i);end;
        s1:=s1+s[i];
        inc(i);
        end;
s4:=uppercase(s1);
nbrpts:=strtoint(s4);

i:=1;
readln(F1,S);
readln(F1,S);
{lecture des datas}
createit(datz);datz.size(nbrpts,false);
createit(datx);datx.size(nbrpts,false);
j:=0;
while j<nbrpts do
begin
while s[i]=' ' do begin s1:='';inc(i);end;
while i<length(s) do
        begin
        while s[i]<>'.' do begin s1:=s1+s[i];inc(i);end;
        s6:=uppercase(s1);
        datx.values[j]:=startangle+j*stepsize;
        datz.values[j]:=strtoint(s6);
        inc(i); {on saute le point}
        inc(j);
        s1:='';
        end;
readln(F1,S); {on passe a la ligne suivante}
i:=1;
end;

CloseFile(F1);

{ stockage dans le vecteur }
setlength(data,nbrPts,1,1); { SHOULD NOT WORK IN PRINCIPLE; NOT DOCUMENTED !! }
X:=nbrPts;Y:=1;LT:=1;
for i:=0 to X-1 do begin data[i,0,0].x:=datx[i];data[i,0,0].z:=datz[i] end;
typeX:='deg';

freeit(datx,datz);

end;

procedure spectre.ReadFromG41dat(filename:string);
var
  i,j:integer;
  F1, F2: TextFile;
  S, S1, S2, S3, S4,s5,s6: string[255];
  name:string;
  stepsize,startangle,endangle,dataj:double;
  nbrpts:integer;
  datx,datz:Tvec;
begin
AssignFile(F1,Filename);
Reset(F1);
Readln(F1,S);comment:=s;
Readln(F1,S);
Readln(F1,S);
Readln(F1,S);
Readln(F1,S);
{ lecture des angles de debut step et fin }
s1:='';
i:=1;while s[i]=' ' do begin inc(i);end;
while s[i]<>' ' do begin s1:=s1+s[i];inc(i);end;
startAngle:=strtofloat(s1);
s1:='';while s[i]=' ' do begin inc(i);end;
while s[i]<>' ' do begin s1:=s1+s[i];inc(i);end;
stepSize:=strtofloat(s1);
s1:='';while s[i]=' ' do begin inc(i);end;
while s[i]<>' ' do begin s1:=s1+s[i];inc(i);end;
endAngle:=strtofloat(s1);
nbrPts:=round((EndAngle-StartAngle)/StepSize);
{lecture des datas}
createit(datz);datz.size(nbrpts,false);
createit(datx);datx.size(nbrpts,false);
j:=0;
while j<(nbrpts) do
begin
readln(F1,S);
i:=1;
while s[i]=' ' do begin s1:='';inc(i);end;
while i<length(s) do
        begin
        while s[i]=' ' do begin inc(i);end;
        while s[i]<>' ' do begin s1:=s1+s[i];inc(i);end;
        s6:=uppercase(s1);
        datx.values[j]:=startangle+j*stepsize;
        datz.values[j]:=strtoFloat(s6);
        inc(i); {on saute le point}
        inc(j);
        s1:='';
        end;
end;

CloseFile(F1);

{ stockage dans le vecteur }
setlength(data,nbrPts,1,1); { SHOULD NOT WORK IN PRINCIPLE; NOT DOCUMENTED !! }
X:=nbrPts;Y:=1;LT:=1;
for i:=0 to X-1 do begin data[i,0,0].x:=datx[i];data[i,0,0].z:=datz[i] end;
typeX:='deg';

freeit(datx,datz);

end;


// ==================================== //
// opérations de projection

{ INPUT : valeur de l'ordonnée de la coupe }
{ OUTPUT : un spectre
{ REM : version definitive : vraie valeur y                 }
{       + il faut verifier si on a affaire à un spectre 2D ! }
{ on prend toujours la coupe en LT = 0                      }
{ il y a des problèmes parce que les champs .x et .y ne sont parfois pas bien initialisés }
function spectre.CoupeHSpectre2D(name:string;yy :double) :spectre; { coupe horizontale suivant la droite d'ordonnée y }
var coupe:spectre;
    i, j:integer;
begin
   coupe:=spectre.create;
   coupe.nom:=name;
   coupe.X:=X;coupe.Y:=1;coupe.LT:=1;
   coupe.typeX:=typeX;
   setlength(coupe.data,X,1,1);
   Coupe.ExpCondNbr:=0;
   coupe.clear;
   { determination de la ligne correspondant à l'ordonnée yy }
   { on suppose que le graph est orthonormé }
   j:=round((Y-1)*(yy-data[0,0,0].y)/(data[0,Y-1,0].y-data[0,0,0].y));
   for i:=0 to X-1 do
      begin
         coupe.data[i,0,0].x:=data[i,j,0].x;
         coupe.data[i,0,0].z:=data[i,j,0].z;
         coupe.data[i,0,0].mon:=data[i,j,0].mon;
      end;
   result:=coupe;
end;
{**************
}
function spectre.CoupeVSpectre2D(name:string;xx :double) :spectre ; { coupe verticale suivant la droite d'ordonnée x }
var coupe:spectre;
    i,j:integer;
begin
   coupe:=spectre.create;
   coupe.nom:=name;
   coupe.X:=Y;coupe.Y:=1;coupe.LT:=1;
   coupe.typeX:=typeX;
   Coupe.ExpCondNbr:=0;
   setlength(coupe.data,Y,1,1);
   coupe.clear;
   j:=round((X-1)*(xx-data[0,0,0].x)/(data[X-1,0,0].x-data[0,0,0].x));
   for i:=0 to Y-1 do
      begin
         coupe.data[i,0,0].x:=data[j,i,0].y;
         coupe.data[i,0,0].z:=data[j,i,0].z;
         coupe.data[i,0,0].mon:=data[j,i,0].mon;
      end;
   result:=coupe;
end;
{**************
}
function spectre.ProjectionHSpectre2D(name:string;x1,x2 :double):spectre; { projection horizontale entre les droite x1 et x2 }
var coupe:spectre;
    i,j:integer;
begin
   coupe:=spectre.create;
   coupe.nom:=name;
   coupe.X:=Y;coupe.Y:=1;coupe.LT:=1;
   coupe.typeX:=typeX;
   setlength(coupe.data,Y,1,1);
   Coupe.ExpCondNbr:=0;
   coupe.clear;
   for i:=0 to Y-1 do
     begin
        coupe.data[i,0,0].x:=data[0,i,0].y;
        for j:=0 to X-1 do
           if (data[j,i,0].x>=x1) and (data[j,i,0].x<=x2) then
           begin coupe.data[i,0,0].z:=coupe.data[i,0,0].z+data[j,i,0].z;
                 coupe.data[i,0,0].mon:=coupe.data[i,0,0].mon+data[j,i,0].mon; end
     end;
   result:=coupe;
end;
{**************
}
function spectre.ProjectionVSpectre2D(name:string;y1,y2 :double):spectre; { projection verticale suivant la droite d'ordonnée x }
var coupe:spectre;
    i,j:integer;
begin
   coupe:=spectre.create;
   coupe.nom:=name;
   coupe.X:=X;coupe.Y:=1;coupe.LT:=1;
   coupe.typeX:=typeX;
   setlength(coupe.data,X,1,1);
   Coupe.ExpCondNbr:=0;
   coupe.clear;
   for i:=0 to X-1 do
   begin
      coupe.data[i,0,0].x:=data[i,0,0].x;
      for j:=0 to Y-1 do
          if (data[i,j,0].y>=y1) and (data[i,j,0].y<=y2) then
          begin coupe.data[i,0,0].z:=coupe.data[i,0,0].z+data[i,j,0].z;
                coupe.data[i,0,0].mon:=coupe.data[i,0,0].mon+data[i,j,0].mon; end
   end;
   result:=coupe;
end;

{ INPUT: 2 intervalles d'intégration [x1,x2] et [y1,y2]  }
{        ces indices réfèrent a l'indice de data si le type du spectre est 'raw'       }
{        sinon ils réfèrent aux vrais indices dat.x et data.y          }
{ OUTPUT : l'integrale des coups                                       }

function spectre.IntegraleSpectre1D(x1,x2:double) :double; { somme entre les abscisses definies par x1 et x2 }
var i,j:integer;
    somme:double;
begin
     somme:=0;
     for i:=0 to X-1 do
          if (data[i,0,0].x>=x1) and (data[i,0,0].x<=x2) then somme:=somme+data[i,0,0].z;
     result:=somme;
end;

{ INPUT: 2 intervalles d'intégration [x1,x2] et [y1,y2]  }
{        ces indices réfèrent a l'indice de data si le type du spectre est 'raw'       }
{        sinon ils réfèrent aux vrais indices dat.x et data.y          }
{ OUTPUT : l'integrale des coups                                       }
function spectre.IntegraleSpectre2D(x1,y1,x2,y2 :double) :double; { somme entre le rectangle defini par x1,y1 ,x2,y2 }
var i,j:integer;
    somme:double;
begin
     somme:=0;
     for i:=0 to X-1 do
        for j:=0 to Y-1 do
           if (data[i,j,0].x>=x1) and (data[i,j,0].x<=x2) and (data[i,j,0].y>=y1) and (data[i,j,0].y<=y2)
           then somme:=somme+data[i,j,0].z;
     result:=somme;
end;

{procédure de calcul circulaire                         }
{ INPUT: le nom du spectre , le centre du cercle, et le }
{        facteurd'échelle                               }
{OUTPUT: un spectre und                                 }
{ norm n'est pas initialisé à 0                         }
function spectre.SommeCirculaireSpectre2D(name:string;x0,y0,pas:double) :spectre; { somme circulaire }
var coupe:spectre;
    i,j:integer;
    xcrt,ycrt,R,x1,x2,y1,y2: double;
    norm:array of integer;
    taille:integer;
    xmin,xmax,ymin,ymax,Rmax:double;
begin

   xmin:=mini(data[0,0,0].x,data[X-1,Y-1,0].x);
   xmax:=maxi(data[0,0,0].x,data[X-1,Y-1,0].x);
   ymin:=mini(data[0,0,0].y,data[X-1,Y-1,0].y);
   ymax:=maxi(data[0,0,0].y,data[X-1,Y-1,0].y);

   { taille maximale du fichier de la somme circulaire }
   taille:=round(sqrt(sqr(xmax-xmin)+sqr(ymax-ymin))/pas);
   setlength(norm,taille);
   for i:=0 to taille-1 do norm[i]:=0;
   coupe:=spectre.create;
   coupe.nom:=name;
   coupe.typeX:=typeX;
   coupe.ExpCondNbr:=0;
   setlength(coupe.data,taille,1,1);
   coupe.clear;

   Rmax:=0; {taille reel du resultat}
   if (x0>=xmin) and (x0<=Xmax) and (y0>=ymin) and (y0<=ymax) then
   begin
     for i:=0 to X-1 do
       for j:=0 to Y-1 do
         begin
           xcrt:=data[i,j,0].x;ycrt:=data[i,j,0].y;
           R:=sqrt(sqr(xcrt-x0)+sqr(ycrt-y0)); { distance % centre de la somme circulaire }
           { determination du point de la coupe }
           coupe.data[round(R/pas),0,0].x:=round(R/pas)*pas; { cette valeur peut fluctuer un peu }
           if R>Rmax then Rmax:=R;
           if data[i,j,0].z>0 { il ne s'agit pas d'un point sous le masque }
           then begin
                inc(norm[round(R/pas)]);
                coupe.data[round(R/pas),0,0].z:=coupe.data[round(R/pas),0,0].z+data[i,j,0].z;
                coupe.data[round(R/pas),0,0].mon:=coupe.data[round(R/pas),0,0].mon+data[i,j,0].mon;
                end;
         end;
     for i:=0 to round(Rmax/pas)-1 do
       begin
       if norm[i]<>0 then begin coupe.data[i,0,0].z:=coupe.data[i,0,0].z/norm[i];
                                coupe.data[i,0,0].mon:=coupe.data[i,0,0].mon/norm[i]; end;
       end;
   End;
   setlength(coupe.data,round(Rmax/pas),1,1);
   coupe.X:=round(Rmax/pas);
   coupe.Y:=1;
   coupe.Lt:=1;
   result:=coupe;
end;

{procédure de calcul circulaire                         }
{ INPUT: le nom du spectre , le centre du cercle, et le }
{        facteurd'échelle                               }
{OUTPUT: un spectre und                                 }
{ norm n'est pas initialisé à 0                         }
function spectre.CoupeCirculaireSpectre2D(name:string;x0,y0,rayon:double) :spectre; { coupe circulaire }
var coupe:spectre;
    i,j:integer;
    taille:integer;
    theta,xx,yy:double;
begin
   { taille maximale du fichier de la somme circulaire }
   taille:=360;
   coupe:=spectre.create;
   coupe.nom:=name;
   coupe.typeX:=typeX;
   coupe.ExpCondNbr:=0;
   setlength(coupe.data,taille,1,1);
   coupe.X:=360;coupe.Y:=1;coupe.LT:=1;
   coupe.clear;

   for i:=0 to taille-1 do
   begin
     Theta:=i;
     coupe.data[i,0,0].x:=theta;
     xx:=rayon*cos(theta*pi/180)+x0;yy:=rayon*sin(theta*pi/180)+y0;
     coupe.data[i,0,0].z:=interpolate2D(xx,yy);
   end;
   result:=coupe;
end;

{procédure de calcul Pour Diffusion aux petits angles                         }
{ INPUT: le nom du spectre 1D, le centre du cercle, le nombre de points pour l'integration,
         la Longueur  d'onde (PAPOL=8), la taille des pixels en metre (PAPOL=0.005), la distance echantillon detecteur}
{le Calcul de q est fait sans approximation et corrige le tilt du detecteur. Il suppose que le detecteur tourne autour de l'echantillon,
l'angle de tilt peut donc etre calcule par les coordonnees du faisceau directe.                                    }
{OUTPUT: un spectre und                                 }

function spectre.SommePetitsAngles(name,nomMasque:string;x0,y0,npoints,lambda,delta,dist:double):spectre;
var coupe:spectre;
    i,j,vindM:integer;
    qmax,qvar,resol:double;
    norm:array of integer;
    Xmax:integer;

    {fonction calcul de q en fonction des coordonnees du pixel
    INPUT : coordonnees du pixel
    OUTPUT : q en 1/A si lambda est donne en A}
    function q(i,j:integer):double;
       var angle,calcos:double;
       begin
          {calcul du cosinus de l'angle de diffusion}
          calcos:=((i-X/2)*(x0-X/2)*sqr(delta)+sqr(dist))/
          (sqrt(sqr((x0-X/2)*delta)+sqr(dist))*sqrt(sqr((i-X/2)*delta)+sqr((j-y0)*delta)+sqr(dist)));
          if calcos>1 then calcos:=1; {IMPORTANT : evite calcos>1 suite a Arrondis de calcul}
          angle:=arccos(calcos);
          result:=4*pi*sin(angle/2)/lambda; {calcul de q}
       end;


begin
{calcul du qmax}
qmax:=maxi(maxi(q(0,0),q(0,Y-1)),maxi(q(X-1,0),q(X-1,Y-1)));
resol:=npoints/qmax;
VindM:=deuxd.indexof(nomMasque);
{Calcul de la taille max du resultat}
Xmax:=round(qmax*resol)+2;
setlength(norm,Xmax);
coupe:=spectre.create;
coupe.nom:=name;
coupe.typeX:='q';
coupe.ExpCondNbr:=0;
coupe.comment:='Somme PA de : '+nom+', masque : '+nomMasque;
coupe.SetExpCond('X0',x0);
coupe.SetExpCond('Y0',y0);
coupe.SetExpCond('dist Ech/detect',dist);
coupe.SetExpCond('Masque',VindM);
coupe.SetExpCond('lambda',lambda);
coupe.SetExpCond('delta',delta);
setlength(coupe.data,Xmax,1,1);
coupe.clear;
Xmax:=1;
if (x0>=0) and (x0<=X) and (y0>=0) and (y0<=Y) then   {verification du centre}
   begin
   for i:=0 to X-1 do
       for j:=0 to Y-1 do
         if typeX='raw' then
         begin
           if (VindM<>-1)then
             begin
             if deuxd.spect[vindM].data[i,j,0].z=1 then
               begin
               qvar:=q(i,j);
               if round(qvar*resol)>Xmax then Xmax:=round(qvar*resol); {calcul de la taille effective du resultat}
               coupe.data[round(qvar*resol),0,0].x:=round(qvar*resol)/resol;
               inc(norm[round(qvar*resol)]);
               coupe.data[round(qvar*resol),0,0].z:=coupe.data[round(qvar*resol),0,0].z+data[i,j,0].z;
               coupe.data[round(qvar*resol),0,0].mon:=coupe.data[round(qvar*resol),0,0].mon+data[i,j,0].mon;
               end;
             end
           else
             begin
             qvar:=q(i,j);
             if round(qvar*resol)>Xmax then Xmax:=round(qvar*resol); {calcul de la taille effective du resultat}
             coupe.data[round(qvar*resol),0,0].x:=round(qvar*resol)/resol;
             inc(norm[round(qvar*resol)]);
             coupe.data[round(qvar*resol),0,0].z:=coupe.data[round(qvar*resol),0,0].z+data[i,j,0].z;
             coupe.data[round(qvar*resol),0,0].mon:=coupe.data[round(qvar*resol),0,0].mon+data[i,j,0].mon;
             end;
         end
         else begin
              end;
   inc(Xmax);
   {normalisation par pixel}
   for i:=0 to Xmax-1 do
       begin
       if norm[i]<>0
       then begin coupe.data[i,0,0].z:=coupe.data[i,0,0].z/norm[i];
                  coupe.data[i,0,0].mon:=coupe.data[i,0,0].mon/norm[i]; end;
       end;
   End;
   {setup resultat}
   setlength(coupe.data,Xmax,1,1);
   coupe.X:=Xmax;
   coupe.Y:=1;
   coupe.Lt:=1;
   result:=coupe;
end;

procedure spectre.FlipUD; { flipping des data UP - DOWN }
var temp:spectre;
    i,j:integer;
begin
   temp:=spectre.create;
   temp.nom:='temp';
   temp.X:=X;temp.Y:=Y;temp.LT:=1;
   setlength(temp.data,X,Y,LT);
   temp.clear;
   { réalisation du flipping }
   for i:=0 to X-1 do
      for j:=0 to Y-1 do
         begin
{            temp.data[i,(Y-1-j),0].X:=data[i,j,0].X;
            temp.data[i,(Y-1-j),0].Y:=data[i,j,0].Y; }
            temp.data[i,(Y-1-j),0].Z:=data[i,j,0].Z;
            temp.data[i,(Y-1-j),0].mon:=data[i,j,0].mon;
         end;
   { transfert dans le spectre d'origine }
   for i:=0 to X-1 do
      for j:=0 to Y-1 do
         begin
{            data[i,j,0].X:=temp.data[i,j,0].X;
            data[i,j,0].Y:=temp.data[i,j,0].Y; }
            data[i,j,0].Z:=temp.data[i,j,0].Z;
            data[i,j,0].mon:=temp.data[i,j,0].mon;
         end;
   temp.free;
end;

procedure spectre.FlipLR; { flipping des data UP - DOWN }
var temp:spectre;
    i,j:integer;
begin
   temp:=spectre.create;
   temp.nom:='temp';
   temp.X:=X;temp.Y:=Y;temp.LT:=1;
   setlength(temp.data,X,Y,LT);
   temp.clear;
   { réalisation du flipping }
   for i:=0 to X-1 do
      for j:=0 to Y-1 do
         begin
{            temp.data[(X-1-i),j,0].X:=data[i,j,0].X;
            temp.data[(X-1-i),j,0].Y:=data[i,j,0].Y; }
            temp.data[(X-1-i),j,0].Z:=data[i,j,0].Z;
            temp.data[(X-1-i),j,0].mon:=data[i,j,0].mon;
         end;
   { transfert dans le spectre d'origine }
   for i:=0 to X-1 do
      for j:=0 to Y-1 do
         begin
{            data[i,j,0].X:=temp.data[i,j,0].X;
            data[i,j,0].Y:=temp.data[i,j,0].Y; }
            data[i,j,0].Z:=temp.data[i,j,0].Z;
            data[i,j,0].mon:=temp.data[i,j,0].mon;
         end;
   temp.free;
end;


//================================
//masques de spectres
{retourne un spectre de meme dim X,Y que le spectre source mais avec LT =1}
{1= point compté, 0=point masqué     }
function spectre.MasqueRectInt(x1,y1,x2,y2 :double;name: string) :spectre ;
var
   mask: spectre;
   i,j : integer;
   Xg,Xp: integer; // X le plus grand et X le plus petit
   Yg,Yp: integer; // Y le plus grand et Y le plus petit
begin
  mask:=spectre.create;
  mask.ExpCondNbr:=0;
  mask.nom:=name;
  mask.X:=X;mask.Y:=Y;mask.LT:=1;
  mask.typeX:=typeX;mask.typeY:=typeY;
  setlength(mask.data,X,Y,1);
  mask.clear;

  if (x1<x2)then
  begin
  Xp:=trunc(x1);Xg:=trunc(x2);end
  else begin
  Xp:=trunc(x2);Xg:=trunc(x1);end;
  if (y1<y2)then begin Yp:=trunc(y1);Yg:=trunc(y2);end
  else begin
  Yp:=trunc(y2);Yg:=trunc(y1);end;
  for i:=0 to X-1 do
    for j:=0 to Y-1 do begin
      mask.data[i,j,0].x:=data[i,j,0].x;mask.data[i,j,0].y:=data[i,j,0].y;
      mask.data[i,j,0].z:=1;mask.data[i,j,0].mon:=1;
    end;
  for i:=Xp to Xg do
   for j:=Yp to Yg do begin
     mask.data[i,j,0].z:=0;
     mask.data[i,j,0].mon:=0; { le champ mon à zéro indique que la zone est masquée }
   end;
  result:=mask;
end;

{****************}
function spectre.MasqueRectExt(x1,y1,x2,y2 :double;name: string) :spectre ;
var
   mask: spectre;
   i,j : integer;
   Xg,Xp: integer; // X le plus grand et X le plus petit
   Yg,Yp: integer; // Y le plus grand et Y le plus petit
begin
  mask:=spectre.create;
  mask.nom:=name;
  mask.ExpCondNbr:=0;
  mask.X:=X;mask.Y:=Y;mask.LT:=1;
  mask.typeX:=typeX;mask.typeY:=typeY;
  setlength(mask.data,X,Y,1);
  mask.clear;

  if (x1<x2)then
  begin
  Xp:=trunc(x1);Xg:=trunc(x2);end
  else begin
  Xp:=trunc(x2);Xg:=trunc(x1);end;
  if (y1<y2)then begin Yp:=trunc(y1);Yg:=trunc(y2);end
  else begin
  Yp:=trunc(y2);Yg:=trunc(y1);end;
  for i:=0 to X-1 do
    for j:=0 to Y-1 do begin
      mask.data[i,j,0].x:=data[i,j,0].x;mask.data[i,j,0].y:=data[i,j,0].y;
      mask.data[i,j,0].z:=0;
      mask.data[i,j,0].mon:=0; { le champ mon à zéro indique que la zone est masquée }
    end;
  for i:=Xp to Xg do
   for j:=Yp to Yg do begin
     mask.data[i,j,0].z:=1;
     mask.data[i,j,0].mon:=1; { le champ mon à zéro indique que la zone est masquée }
   end;
  result:=mask;
end;
{****************}
function spectre.MasqueCircInt(x0,y0,x1,y1 :double;name: string) :spectre ;
var
   mask: spectre;
   i,j : integer;
   R: double;
begin
  mask:=spectre.create;
  mask.nom:=name;
  mask.ExpCondNbr:=0;
  mask.X:=X;mask.Y:=Y;mask.LT:=1;
  mask.typeX:=typeX;mask.typeY:=typeY;
  setlength(mask.data,X,Y,1);
  mask.clear;
  R:=sqrt(sqr(x1-x0)+sqr(y1-y0));
  for i:=0 to X-1 do
    for j:=0 to Y-1 do begin
         mask.data[i,j,0].x:=data[i,j,0].x;mask.data[i,j,0].y:=data[i,j,0].y;
         mask.data[i,j,0].z:=1;mask.data[i,j,0].mon:=1;
      if(sqrt(sqr(i-x0)+sqr(j-y0))<=R)then
         begin mask.data[i,j,0].z:=0;mask.data[i,j,0].mon:=0; end;
      end;
  result:=mask;
end;
{****************}
function spectre.MasqueCircExt(x0,y0,x1,y1 :double;name: string) :spectre ;
var
   mask: spectre;
   i,j : integer;
   R: double;
begin
  mask:=spectre.create;
  mask.nom:=name;
  mask.ExpCondNbr:=0;
  mask.X:=X;mask.Y:=Y;mask.LT:=1;
  mask.typeX:=typeX;mask.typeY:=typeY;
  setlength(mask.data,X,Y,1);
  mask.clear;
  R:=sqrt(sqr(x1-x0)+sqr(y1-y0));
  for i:=0 to X-1 do
    for j:=0 to Y-1 do begin
      mask.data[i,j,0].x:=data[i,j,0].x;mask.data[i,j,0].y:=data[i,j,0].y;
      mask.data[i,j,0].z:=1;mask.data[i,j,0].mon:=1; { le champ mon à zéro indique que la zone est masquée }
      if(sqrt(sqr(i-x0)+sqr(j-y0))>R)then
         begin mask.data[i,j,0].z:=0;mask.data[i,j,0].mon:=0; end;
    end;
  result:=mask;
end;
{****************
cette fonction masque (initialise a 0) un secteur d'ouverture total thetaouv}
{INPUT : xc,yc: centre du secteur
         thetasym : angle median du secteur en convention geographique: 0 a midi, 90 a 3H, 180 a 6H, 270 a 9H
         thetaouv : angle total d'ouverture du secteur (plus ou moins thetaouv/2)}
function spectre.MasqueSecteur(xc,yc,thetasym,thetaouv :double;name:string) :spectre ;
var
   i,j : integer;
   angle,calcos,calsin: double;
   mask:spectre;

   function compangle(x1,x,x2:double):boolean;
   begin
   {conversion en Geographique 0->360°}
   x:=90-180*x/pi;
   if x<0 then x:=x+360;
   if x1<0 then x1:=x1+360; if x1>360 then x1:=x1-360;
   if x2<0 then x2:=x2+360; if x2>360 then x2:=x2-360;
   if x1<x2
   then result:=(x1<=x) and (x<=x2)
   else result:=((0<=x) and (x<=x2)) or ((x1<=x) and (x<=360));
   end;

begin
  mask:=spectre.create;
  mask.nom:=name;
  mask.ExpCondNbr:=0;
  mask.X:=X;mask.Y:=Y;mask.LT:=1;
  mask.typeX:=typeX;mask.typeY:=typeY;
  setlength(mask.data,X,Y,1);
  mask.clear;
  for i:=0 to X-1 do
    for j:=0 to Y-1 do
    begin
       mask.data[i,j,0].x:=data[i,j,0].x;mask.data[i,j,0].y:=data[i,j,0].y;
       if (sqr(i-Xc)+sqr(j-Yc)) <>0 then
       begin
         calcos:=(i-Xc)/sqrt(sqr(i-Xc)+sqr(j-Yc));
         calsin:=-(j-Yc)/sqrt(sqr(i-Xc)+sqr(j-Yc));
         if calcos>1 then calcos:=1;
         angle:=arccos(calcos);
         if calsin<0 then angle:=-angle;
         if compangle(thetasym-thetaouv/2,angle,thetasym+thetaouv/2)
         then begin mask.data[i,j,0].z:=1;mask.data[i,j,0].mon:=1; end
         else begin mask.data[i,j,0].z:=0;mask.data[i,j,0].mon:=0 end;
       end;
    end;
  result:=mask;
end;

{ *************************************** }
{ intégrale des coups sur le spectre      }
{ sur toutes les coordonnées              }
function spectre.total:double;
var i,j,k:integer;
    tota:double;
begin
tota:=0;
for i:=0 to X-1 do
  for j:=0 to Y-1 do
    for k:=0 to LT-1 do begin tota:=data[i,j,k].z+tota; end;
result:=tota;
end;

{ ================================================= }
{ opérations de gestion des listes de spectres      }

{----------------spectrelist------------------------}

{***********************************************
crée les 16 spectres frame}
{ PROCEDURE DEVANT DISPARATRE A TERME => UTILISER LE TYPE 3D }
procedure spectlist.createframe;
var i:integer;
begin
{creation de 16 spectres }
for i:=1 to 16 do
    begin
    indexframe[i]:=deuxd.addspectre('ACF'+inttostr(i),128,128,1);
    deuxd.spect[indexframe[i]].comment:='spectre frame';
    deuxd.spect[indexframe[i]].typex:='raw';
    deuxd.spect[indexframe[i]].typey:='raw';
    end;
end;

{ ***************************************
{ cree un nouveau spectre dans la liste des spectres }
{ OUTPUT : i1 index du spectre cree                                 }
{ si le spectre existe deja dans la liste,
il est supprimé et remplacé par ce nouveau spectre  }
function spectlist.addspectre(nom:string;X:integer;Y:integer;LT:integer):integer;
var
i:integer;
i1:integer;
tf:boolean;
begin
i:=1;i1:=-1;tf:=false;
deletespectre(indexof(nom));
  while (i<=totalspectre) and (not tf) do begin
  if spect[i]=nil
  then begin
  spect[i]:=spectre.create;
  spect[i].nom:=nom;
  spect[i].X:=X;
  spect[i].Y:=Y;
  spect[i].LT:=LT;
  spect[i].ExpCondNbr:=0;
  setlength(spect[i].data,X,Y,LT);
  i1:=i;tf:=true;
  spect[i].clear;
  end;
  i:=i+1;
  end;
result:=i1;
end;

{***************************************
{ cree un nouveau spectre et effectue le chargement}
{ INPUT : spec, le spectre a ajouter dans la liste  }
{ OUTPUT : le spectre est ajouté a la liste         }
{ REM : pas de vérifications de compatibilté 1D 2D ou 3D}
procedure spectlist.add(spec:spectre);
var
i,k,l,m:integer;
begin
i:=addspectre(spec.nom,spec.X,spec.Y,spec.LT);
if i>=1 then
begin
  spect[i].comment:=spec.comment;
  spect[i].typeX:=spec.typeX;
  spect[i].typeY:=spec.typeY;
  spect[i].typeLT:=spec.typeLT;
  spect[i].indexX:=spec.indexX;
  spect[i].indexY:=spec.indexY;
  spect[i].indexLT:=spec.indexLT;
  spect[i].moniteur:=spec.moniteur;
  spect[i].ExpCondNbr:=spec.ExpCondNbr;
  {chargement des datas}
  for k:=0 to spec.X-1 do
    for l:=0 to spec.Y-1 do
        for m:=0 to spec.LT-1 do
        spect[i].data[k,l,m]:=spec.data[k,l,m];
  {chargement des conditions expérimentales}
  if spect[i].ExpCondNbr>0 then
     begin
     setlength(spect[i].experimentalConditions,spect[i].ExpCondNbr);
     for k:=0 to spect[i].ExpCondNbr-1 do
         spect[i].experimentalConditions[k]:=spec.experimentalConditions[k];
     end;
end;
end;

{***************************************}
{ destruction d'un spectre dans la lsite des spectres }
{ INPUT : ind, l'indice du spectre dans la liste      }
procedure spectlist.deletespectre(ind:integer);
begin
if (ind>=1) and (ind<=totalspectre) then
if spect[ind]<>nil then begin
spect[ind].free;
spect[ind]:=nil;
end;
end;

{***************************************}
{ destruction d'un spectre dans la lsite des spectres }
{ INPUT : ind, l'indice du spectre dans la liste      }
procedure spectlist.delete(nom:string);
begin
     deletespectre(indexof(nom));
end;

{*************************************** }
{ simplement mise a zero du spectre  }
{ INPUT : nom, le nom (string) du spectre dans la liste }
procedure spectlist.clear(nom:string);
var
ind:integer;
begin
ind:=indexof(nom);
if ind>=0 then spect[ind].clear;
end;

{***************************************}
{ destruction de tous les pointeurs de spectres d'une liste de spectres }
procedure spectlist.free;
var
i:integer;
begin
for i:=1 to totalspectre do spect[i].free;
end;


{ *************************************** }
{ ajout d'un point dans la liste          }
{ indexX et indexY permettent une initialisation point apres point. lorsque indexX=X-1 (fin de ligne)
on passe à la ligne suivante. Suppose que le spectre a la dim correcte...   }
procedure spectlist.addpt(nom:string;x,y,lt,z,mon:extended);
var
i:integer;
tf:boolean;
begin
i:=indexof(nom);tf:=false;
if i>=0
then begin
     if spect[i].indexX>=spect[i].X-1 then begin spect[i].indexY:=spect[i].indexY+1;
     if spect[i].indexY<spect[i].Y-1 then begin  spect[i].indexX:=0;tf:=true;end;
     end
else begin
     tf:=true;
     spect[i].indexX:=spect[i].indexX+1;
     end;
if tf then begin
spect[i].data[spect[i].indexX,spect[i].indexY,spect[i].indexLT].x:=x;
spect[i].data[spect[i].indexX,spect[i].indexY,spect[i].indexLT].y:=y;
spect[i].data[spect[i].indexX,spect[i].indexY,spect[i].indexLT].lt:=lt;
spect[i].data[spect[i].indexX,spect[i].indexY,spect[i].indexLT].z:=z;
spect[i].data[spect[i].indexX,spect[i].indexY,spect[i].indexLT].mon:=mon;
end;
end;
end;

{***************************************
{  retourne l'index du spectre ou -1 si le spectre n'existe pas}
function spectlist.indexof(nom:string):integer;
var
i:integer;
i1:integer;
begin
i:=1;i1:=-1;
while (i<=totalspectre) and (i1=-1) do begin
if spect[i]<>nil then
if comparetext(spect[i].nom,nom)=0 then i1:=i;
i:=i+1;
end;
result:=i1;
end;

{ Opérations arithmétiques sur les spectres}
{INPUT: nom1 et nom2 : string, qui peuvent être des spectres de dimensions
quelconques 1 2 ou 3                                                      }
{OUTPUT: mon3 le spectre résultat est rajouté dans la liste des spectes }
{REM: Message box en cas d'opérations sur les spectres incompatibles en taille}
{on inclu mon3 dedans sinon on ne peut pas l'ajouter directement dans spectlist}
{+}
function spectlist.Addition(nom1,nom2,nom3:string):boolean;{nom3=nom2+nom1}
var i,j,k,i1,i2,i3,iAux:integer;
    tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
if (i1>=1) and (i2>=1) then
   if (spect[i1].x=spect[i2].x) and (spect[i1].y=spect[i2].y) and (spect[i1].lt=spect[i2].lt)then
     begin
     iAux:=addspectre('temp',spect[i1].x,spect[i1].y,spect[i1].lt); { spectre temporaire de sortie des data }
     for i:=0 to spect[i1].x-1 do
       for j:=0 to spect[i1].y-1 do
         for k:=0 to spect[i1].lt-1 do
           begin
           spect[iAux].data[i,j,k].x:=spect[i1].data[i,j,k].x;
           spect[iAux].data[i,j,k].y:=spect[i1].data[i,j,k].y;
           spect[iAux].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
           spect[iAux].data[i,j,k].z:=spect[i1].data[i,j,k].z+spect[i2].data[i,j,k].z;
           spect[iAux].data[i,j,k].mon:=spect[i1].data[i,j,k].mon+spect[i2].data[i,j,k].mon;
         end;
     spect[iAux].moniteur:=spect[i1].moniteur+spect[i2].moniteur;
     { recopie du spectre calculé dans le spectre "nom3" }
     { et on écrase au passage l'ancien spectre si c'etait un des spectres d'entrée }
     i3:=addspectre(nom3,spect[i1].x,spect[i1].y,spect[i1].lt); { spectre temporaire de sortie des data }
     spect[i3].x:=spect[i1].x;
     spect[i3].y:=spect[i1].y;
     spect[i3].lt:=spect[i1].lt;
     spect[i3].typex:=spect[i1].typex;
     spect[i3].typey:=spect[i1].typey;
     spect[i3].typeLT:=spect[i1].typeLT;
     for i:=0 to spect[i1].x-1 do
       for j:=0 to spect[i1].y-1 do
         for k:=0 to spect[i1].lt-1 do
           begin
           spect[i3].data[i,j,k].x:=spect[iAux].data[i,j,k].x;
           spect[i3].data[i,j,k].y:=spect[iAux].data[i,j,k].y;
           spect[i3].data[i,j,k].lt:=spect[iAux].data[i,j,k].lt;
           spect[i3].data[i,j,k].z:=spect[iAux].data[i,j,k].z;
           spect[i3].data[i,j,k].mon:=spect[iAux].data[i,j,k].mon;
         end;
     spect[i3].moniteur:=spect[iAux].moniteur;
     tf:=true;
     deleteSpectre(iAux); { destruction du spectre temporaire }
     end;
result:=tf;
end;

{-}
function spectlist.Soustraction(nom1,nom2,nom3:string):boolean;{nom3=nom1-nom2}
var
i,j,k,i1,i2,i3:integer;
tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
i3:=indexof(nom3);
if (i1>=1) and (i2>=1) then
   if (spect[i1].x=spect[i2].x) and (spect[i1].y=spect[i2].y) and (spect[i1].lt=spect[i2].lt)then
     begin
     if i3<1 then
       i3:=addspectre(nom3,spect[i1].x,spect[i1].y,spect[i1].lt);

     spect[i3].x:=spect[i1].x;
     spect[i3].y:=spect[i1].y;
     spect[i3].lt:=spect[i1].lt;
     setlength(spect[i3].data,spect[i3].X,spect[i3].Y,spect[i3].LT);
     spect[i3].typex:=spect[i1].typex;
     spect[i3].typey:=spect[i1].typey;
     spect[i3].typeLT:=spect[i1].typeLT;
     for i:=0 to spect[i1].x-1 do
       for j:=0 to spect[i1].y-1 do
         for k:=0 to spect[i1].lt-1 do
           begin
           spect[i3].data[i,j,k].x:=spect[i1].data[i,j,k].x;
           spect[i3].data[i,j,k].y:=spect[i1].data[i,j,k].y;
           spect[i3].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
           spect[i3].data[i,j,k].z:=spect[i1].data[i,j,k].z-spect[i2].data[i,j,k].z;
           {spect[i3].data[i,j,k].mon:=spect[i1].data[i,j,k].mon-spect[i2].data[i,j,k].mon; }
         end;
     spect[i3].moniteur:=spect[i1].moniteur;
     tf:=true;
     end;

result:=tf;
end;
{*}
function spectlist.Multiplication(nom1,nom2,nom3:string):boolean;{nom1*nom2=nom3}
var
i,j,k,i1,i2,i3:integer;
tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
i3:=indexof(nom3);
if (i1>=1) and (i2>=1) then
   if (spect[i1].x=spect[i2].x) and (spect[i1].y=spect[i2].y) and (spect[i1].lt=spect[i2].lt)then
     begin
     if i3<1 then
       i3:=addspectre(nom3,spect[i1].x,spect[i1].y,spect[i1].lt);

     spect[i3].x:=spect[i1].x;
     spect[i3].y:=spect[i1].y;
     spect[i3].lt:=spect[i1].lt;
     setlength(spect[i3].data,spect[i3].X,spect[i3].Y,spect[i3].LT);
     spect[i3].typex:=spect[i1].typex;
     spect[i3].typey:=spect[i1].typey;
     spect[i3].typeLT:=spect[i1].typeLT;
     for i:=0 to spect[i1].x-1 do
       for j:=0 to spect[i1].y-1 do
         for k:=0 to spect[i1].lt-1 do
           begin
           spect[i3].data[i,j,k].x:=spect[i1].data[i,j,k].x;
           spect[i3].data[i,j,k].y:=spect[i1].data[i,j,k].y;
           spect[i3].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
           spect[i3].data[i,j,k].z:=spect[i1].data[i,j,k].z*spect[i2].data[i,j,k].z;
           spect[i3].data[i,j,k].mon:=spect[i1].data[i,j,k].mon*spect[i2].data[i,j,k].mon;
         end;
     spect[i3].moniteur:=spect[i1].moniteur;
     tf:=true;
     end;

result:=tf;
end;
{/}
function spectlist.Division(nom1,nom2,nom3:string):boolean;{nom1/nom2=nom3}
var
i,j,k,i1,i2,i3:integer;
tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
i3:=indexof(nom3);
if (i1>=1) and (i2>=1) then
   if (spect[i1].x=spect[i2].x) and (spect[i1].y=spect[i2].y) and (spect[i1].lt=spect[i2].lt)then
     begin
     if i3<1 then i3:=addspectre(nom3,spect[i1].x,spect[i1].y,spect[i1].lt);

     spect[i3].x:=spect[i1].x;
     spect[i3].y:=spect[i1].y;
     spect[i3].lt:=spect[i1].lt;
     setlength(spect[i3].data,spect[i3].X,spect[i3].Y,spect[i3].LT);
     spect[i3].typex:=spect[i1].typex;
     spect[i3].typey:=spect[i1].typey;
     spect[i3].typeLT:=spect[i1].typeLT;
     for i:=0 to spect[i1].x-1 do
       for j:=0 to spect[i1].y-1 do
         for k:=0 to spect[i1].lt-1 do
           begin
           spect[i3].data[i,j,k].x:=spect[i1].data[i,j,k].x;
           spect[i3].data[i,j,k].y:=spect[i1].data[i,j,k].y;
           spect[i3].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
           if (spect[i2].data[i,j,k].z<>0)then // pensez à mettre un else
             spect[i3].data[i,j,k].z:=spect[i1].data[i,j,k].z/spect[i2].data[i,j,k].z
           else
             spect[i3].data[i,j,k].z:=0;
           {if (spect[i2].data[i,j,k].mon<>0)then //idem
             spect[i3].data[i,j,0].mon:=spect[i1].data[i,j,k].mon/spect[i2].data[i,j,k].mon; }
         end;
     spect[i3].moniteur:=spect[i1].moniteur;
     tf:=true;
     end;

result:=tf;
end;
{*scalaire}
function spectlist.ScalMult(scalaire:double;nom1,nom2: string): boolean; {nom2=nom1*scalaire}
var
i,j,k,i1,i2:integer;
tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
  if (i1>=1)then
  begin
     if i2<1 then
       i2:=addspectre(nom2,spect[i1].x,spect[i1].y,spect[i1].lt);
       spect[i2].x:=spect[i1].x;
       spect[i2].y:=spect[i1].y;
       spect[i2].lt:=spect[i1].lt;
       setlength(spect[i2].data,spect[i2].X,spect[i2].Y,spect[i2].LT);
       spect[i2].typex:=spect[i1].typex;
       spect[i2].typey:=spect[i1].typey;
       spect[i2].typeLT:=spect[i1].typeLT;
       for i:=0 to spect[i1].x-1 do
         for j:=0 to spect[i1].y-1 do
           for k:=0 to spect[i1].lt-1 do
           begin
             spect[i2].data[i,j,k].x:=spect[i1].data[i,j,k].x;
             spect[i2].data[i,j,k].y:=spect[i1].data[i,j,k].y;
             spect[i2].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
             spect[i2].data[i,j,k].z:=spect[i1].data[i,j,k].z*scalaire;
             spect[i2].data[i,j,k].mon:=spect[i1].data[i,j,k].mon*scalaire;
          end;
      spect[i2].moniteur:=spect[i1].moniteur*scalaire;
      tf:=true;
     end;
result:=tf;
end;
{/scalaire}
function Spectlist.ScalDiv(scalaire:double;nom1,nom2: string): boolean; {nom2=nom1/scalaire}
var
i,j,k,i1,i2:integer;
tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
if (scalaire<>0)then
  if (i1>=1)then
  begin
     if i2<1 then
       i2:=addspectre(nom2,spect[i1].x,spect[i1].y,spect[i1].lt);
       spect[i2].x:=spect[i1].x;
       spect[i2].y:=spect[i1].y;
       spect[i2].lt:=spect[i1].lt;
       setlength(spect[i2].data,spect[i2].X,spect[i2].Y,spect[i2].LT);
       spect[i2].typex:=spect[i1].typex;
       spect[i2].typey:=spect[i1].typey;
       spect[i2].typeLT:=spect[i1].typeLT;
       for i:=0 to spect[i1].x-1 do
         for j:=0 to spect[i1].y-1 do
           for k:=0 to spect[i1].lt-1 do
           begin
             spect[i2].data[i,j,k].x:=spect[i1].data[i,j,k].x;
             spect[i2].data[i,j,k].y:=spect[i1].data[i,j,k].y;
             spect[i2].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
             spect[i2].data[i,j,k].z:=spect[i1].data[i,j,k].z/scalaire;
             spect[i2].data[i,j,k].mon:=spect[i1].data[i,j,k].mon/scalaire;
          end;
      spect[i2].moniteur:=spect[i1].moniteur/scalaire;
      tf:=true;
     end;
result:=tf;
end;
{+scalaire}
function Spectlist.ScalAdd(scalaire:double;nom1,nom2: string): boolean; {nom2=nom1+scalaire}
var
i,j,k,i1,i2:integer;
tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
  if (i1>=1)then
  begin
     if i2<1 then
       i2:=addspectre(nom2,spect[i1].x,spect[i1].y,spect[i1].lt);
       spect[i2].x:=spect[i1].x;
       spect[i2].y:=spect[i1].y;
       spect[i2].lt:=spect[i1].lt;
       setlength(spect[i2].data,spect[i2].X,spect[i2].Y,spect[i2].LT);
       spect[i2].typex:=spect[i1].typex;
       spect[i2].typey:=spect[i1].typey;
       spect[i2].typeLT:=spect[i1].typeLT;
       for i:=0 to spect[i1].x-1 do
         for j:=0 to spect[i1].y-1 do
           for k:=0 to spect[i1].lt-1 do
           begin
             spect[i2].data[i,j,k].x:=spect[i1].data[i,j,k].x;
             spect[i2].data[i,j,k].y:=spect[i1].data[i,j,k].y;
             spect[i2].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
             spect[i2].data[i,j,k].z:=spect[i1].data[i,j,k].z+scalaire;
             spect[i2].data[i,j,k].mon:=spect[i1].data[i,j,k].mon{+scalaire;???};
          end;
      tf:=true;
      spect[i2].moniteur:=spect[i1].moniteur;
     end;
result:=tf;
end;
{-scalaire}
function Spectlist.ScalSub(scalaire:double;nom1,nom2: string): boolean; {nom2=nom1-scalaire}
var
i,j,k,i1,i2:integer;
tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);
i2:=indexof(nom2);
  if (i1>=1)then
  begin
     if i2<1 then
       i2:=addspectre(nom2,spect[i1].x,spect[i1].y,spect[i1].lt);
       spect[i2].x:=spect[i1].x;
       spect[i2].y:=spect[i1].y;
       spect[i2].lt:=spect[i1].lt;
       setlength(spect[i2].data,spect[i2].X,spect[i2].Y,spect[i2].LT);
       spect[i2].typex:=spect[i1].typex;
       spect[i2].typey:=spect[i1].typey;
       spect[i2].typeLT:=spect[i1].typeLT;
       for i:=0 to spect[i1].x-1 do
         for j:=0 to spect[i1].y-1 do
           for k:=0 to spect[i1].lt-1 do
           begin
             spect[i2].data[i,j,k].x:=spect[i1].data[i,j,k].x;
             spect[i2].data[i,j,k].y:=spect[i1].data[i,j,k].y;
             spect[i2].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
             spect[i2].data[i,j,k].z:=spect[i1].data[i,j,k].z-scalaire;
             spect[i2].data[i,j,k].mon:=spect[i1].data[i,j,k].mon{-scalaire;???};
          end;
      tf:=true;
     end;
result:=tf;
end;

{sqrt}
function Spectlist.SquareRoot(nom1,nom2: string): boolean; {nom2=nom1-scalaire}
var i,j,k,i1,i2:integer;
    tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);i2:=indexof(nom2);
  if (i1>=1)then
  begin
     if i2<1 then
       i2:=addspectre(nom2,spect[i1].x,spect[i1].y,spect[i1].lt);
       spect[i2].x:=spect[i1].x;
       spect[i2].y:=spect[i1].y;
       spect[i2].lt:=spect[i1].lt;
       setlength(spect[i2].data,spect[i2].X,spect[i2].Y,spect[i2].LT);
       spect[i2].typex:=spect[i1].typex;
       spect[i2].typey:=spect[i1].typey;
       spect[i2].typeLT:=spect[i1].typeLT;
       for i:=0 to spect[i1].x-1 do
         for j:=0 to spect[i1].y-1 do
           for k:=0 to spect[i1].lt-1 do
           begin
             spect[i2].data[i,j,k].x:=spect[i1].data[i,j,k].x;
             spect[i2].data[i,j,k].y:=spect[i1].data[i,j,k].y;
             spect[i2].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
             spect[i2].data[i,j,k].z:=sqrt(spect[i1].data[i,j,k].z);
             spect[i2].data[i,j,k].mon:=spect[i1].data[i,j,k].mon{-scalaire;???};
          end;
      tf:=true;
     end;
result:=tf;
end;

{ mets les valeurs négatives d'un spectre à 0}
function Spectlist.Positif(nom1,nom2: string): boolean; {nom2=nom1-scalaire}
var i,j,k,i1,i2:integer;
    tf:boolean;
begin
tf:=false;
i1:=indexof(nom1);i2:=indexof(nom2);
  if (i1>=1)then
  begin
     if i2<1 then
       i2:=addspectre(nom2,spect[i1].x,spect[i1].y,spect[i1].lt);
       spect[i2].x:=spect[i1].x;
       spect[i2].y:=spect[i1].y;
       spect[i2].lt:=spect[i1].lt;
       setlength(spect[i2].data,spect[i2].X,spect[i2].Y,spect[i2].LT);
       spect[i2].typex:=spect[i1].typex;
       spect[i2].typey:=spect[i1].typey;
       spect[i2].typeLT:=spect[i1].typeLT;
       for i:=0 to spect[i1].x-1 do
         for j:=0 to spect[i1].y-1 do
           for k:=0 to spect[i1].lt-1 do
           begin
             spect[i2].data[i,j,k].x:=spect[i1].data[i,j,k].x;
             spect[i2].data[i,j,k].y:=spect[i1].data[i,j,k].y;
             spect[i2].data[i,j,k].lt:=spect[i1].data[i,j,k].lt;
             if spect[i1].data[i,j,k].z<0
             then spect[i2].data[i,j,k].z:=0
             else spect[i2].data[i,j,k].z:=spect[i1].data[i,j,k].z;
             spect[i2].data[i,j,k].mon:=spect[i1].data[i,j,k].mon{-scalaire;???};
          end;
      tf:=true;
     end;
result:=tf;
end;


{ calcul de la transformée de FOurier }
{ INPUT : nom1 nom du spectre (pour le moment 1D par defaut }
{         a le premier point, l, la longueur du sub-vecteur a transformer }
{ OUTPUT : les spectres transformés sont sorties en MySpectre_FFT }
function SpectList.FFT(nom1:string;a,l:integer;nom2: string): boolean;
var i,vind,vind2:integer;
      MyVec,MyVec_FFT:Tvec;
begin
      CreateIt(MyVec,MyVec_FFT);
      MyVec.size(l,true);
      vind:=und.indexof(nom1);
      { remplissage du vecteur a transformer }
      for i:=0 to l-1 do
      begin
          MyVec.Cvalues[i].re:=und.spect[vind].data[i+a,0,0].z;
          MyVec.Cvalues[i].im:=und.spect[vind].data[i+a,0,0].mon;
      end;
      MyVec_FFT.fft(MyVec);
      { remplissage du nouveau vecteur FFT }
      vind2:=und.AddSpectre(nom2,l,1,1);
      und.Spect[vind2].typeX:=und.Spect[vind].typeX;
      und.Spect[vind2].SetExpCond('Complex',1);
      for i:=0 to l-1 do
      begin
          und.spect[vind2].data[i,0,0].x:=i;
          und.spect[vind2].data[i,0,0].z:=MyVec_FFT.Cvalues[i].re;
          und.spect[vind2].data[i,0,0].mon:=MyVec_FFT.Cvalues[i].im;
      end;
      freeIt(MyVec,MyVec_FFT);
end;

{ calcul de la transformée de FOurier }
{ INPUT : nom1 nom du spectre (pour le moment 1D par defaut }
{         a le premier point, l, la longueur du sub-vecteur a transformer }
{ OUTPUT : les spectres transformés sont sorties en MySpectre_FFT }
function SpectList.FFT2(nom1:string;a,l,b,m:integer;nom2: string): boolean;
var i,j,vind,vind2,vind3,l2,m2:integer;
      MyMtx,MyMtx_FFT:TMtx;
begin
      CreateIt(MyMtx,MyMtx_FFT);
      MyMtx.size(l,m,true);
      vind:=deuxd.indexof(nom1);
      { remplissage du vecteur a transformer }
      for i:=0 to l-1 do
        for j:=0 to m-1 do
          begin
            MyMtx.Cvalues[i,j].re:=deuxd.spect[vind].data[i+a,j+b,0].z;
            MyMtx.Cvalues[i,j].im:=deuxd.spect[vind].data[i+a,j+b,0].mon;
          end;
      MyMtx_FFT.copy(MyMtx);
      MyMtx_FFT.fft;
      { remplissage du nouveau vecteur FFT }
      vind2:=deuxd.AddSpectre(nom2,l,m,1);
      vind3:=deuxd.AddSpectre(nom2+'mod',l,m,1);
      deuxd.Spect[vind2].typeX:=deuxd.Spect[vind].typeX;
      deuxd.Spect[vind2].typeY:=deuxd.Spect[vind].typeY;
      deuxd.Spect[vind2].SetExpCond('Complex',1);


      { on applique le FFTSHIFT d'office                                        }
      l2:=l div 2;m2:=m div 2;
      for i:=0 to l2-1 do
        for j:=0 to m2-1 do
        begin
          deuxd.spect[vind2].data[i+l2,j+m2,0].z:=MyMtx_FFT.Cvalues[i,j].re;
          deuxd.spect[vind2].data[i+l2,j+m2,0].mon:=MyMtx_FFT.Cvalues[i,j].im;
          deuxd.spect[vind3].data[i+l2,j+m2,0].z:=Cabs(MyMtx_FFT.Cvalues[i,j]);
        end;
      for i:=l2 to l-1 do
        for j:=m2 to m-1 do
        begin
          deuxd.spect[vind2].data[i-l2,j-m2,0].z:=MyMtx_FFT.Cvalues[i,j].re;
          deuxd.spect[vind2].data[i-l2,j-m2,0].mon:=MyMtx_FFT.Cvalues[i,j].im;
          deuxd.spect[vind3].data[i-l2,j-m2,0].z:=Cabs(MyMtx_FFT.Cvalues[i,j]);
        end;
      for i:=0 to l2-1 do
        for j:=m2 to m-1 do
        begin
          deuxd.spect[vind2].data[i+l2,j-m2,0].z:=MyMtx_FFT.Cvalues[i,j].re;
          deuxd.spect[vind2].data[i+l2,j-m2,0].mon:=MyMtx_FFT.Cvalues[i,j].im;
          deuxd.spect[vind3].data[i+l2,j-m2,0].z:=Cabs(MyMtx_FFT.Cvalues[i,j]);
        end;
      for i:=l2 to l-1 do
        for j:=0 to m2-1 do
        begin
          deuxd.spect[vind2].data[i-l2,j+m2,0].z:=MyMtx_FFT.Cvalues[i,j].re;
          deuxd.spect[vind2].data[i-l2,j+m2,0].mon:=MyMtx_FFT.Cvalues[i,j].im;
          deuxd.spect[vind3].data[i-l2,j+m2,0].z:=Cabs(MyMtx_FFT.Cvalues[i,j]);
        end;
      deuxd.spect[vind3].data[l2,m2,0].z:=0;

      freeIt(MyMtx,MyMtx_FFT);
end;

{ fftshift }
{ ATTENTION : ne marche que pour les spectres REELS (pas complexes)             }
{ INPUT : nom1 nom du spectre (pour le moment 1D par defaut }
{         a le premier point, l, la longueur du sub-vecteur a transformer }
{ OUTPUT : les spectres transformés sont sorties en MySpectre_FFT }
function Spectre.FFTshift: boolean;
var i,j,ind,indA,l,m,l2,m2:integer;
begin
   l:=X;m:=Y;
   indA:=deuxd.addSpectre('temp',l,m,1);
   for i:=0 to l-1 do
     for j:=0 to m-1 do deuxd.spect[indA].data[i,j,0].z:=data[i,j,0].z;

   l2:=l div 2;m2:=m div 2;
      for i:=0 to l2-1 do
        for j:=0 to m2-1 do
        begin
          data[i+l2,j+m2,0].z:=deuxd.spect[indA].data[i,j,0].z;
        end;
      for i:=l2 to l-1 do
        for j:=m2 to m-1 do
        begin
          data[i-l2,j-m2,0].z:=deuxd.spect[indA].data[i,j,0].z;
        end;
      for i:=0 to l2-1 do
        for j:=m2 to m-1 do
        begin
          data[i+l2,j-m2,0].z:=deuxd.spect[indA].data[i,j,0].z;
        end;
      for i:=l2 to l-1 do
        for j:=0 to m2-1 do
        begin
          data[i-l2,j+m2,0].z:=deuxd.spect[indA].data[i,j,0].z;
        end;
   data[l2,m2,0].z:=0;
   deuxd.delete('temp');
end;


function SPectList.Module1D(nom1:string;nom2: string): boolean;          { module du vecteur complex }
var i,l,vind1,vind2:integer;
begin
   vind1:=und.indexof(nom1);
   l:=und.spect[vind1].X;
   vind2:=und.AddSpectre(nom2,l,1,1);
   for i:=0 to l-1 do
   begin
      und.spect[vind2].data[i,0,0].x:=und.spect[vind1].data[i,0,0].x;
      und.spect[vind2].data[i,0,0].z:=sqrt(sqr(und.spect[vind1].data[i,0,0].z)+sqr(und.spect[vind1].data[i,0,0].mon));
   end;
   und.spect[vind2].typeX:=und.spect[vind1].typeX;
end;

function SPectList.Module2D(nom1:string;nom2: string): boolean;          { module du vecteur complex }
var i,j,l,m,vind1,vind2:integer;
begin
   vind1:=deuxd.indexof(nom1);
   l:=deuxd.spect[vind1].X;m:=deuxd.spect[vind1].Y;
   vind2:=deuxd.AddSpectre(nom2,l,1,1);
   for i:=0 to l-1 do
   for j:=0 to m-1 do
   begin
      deuxd.spect[vind2].data[i,j,0].x:=deuxd.spect[vind1].data[i,j,0].x;
      deuxd.spect[vind2].data[i,j,0].y:=deuxd.spect[vind1].data[i,j,0].y;
      deuxd.spect[vind2].data[i,j,0].z:=sqrt(sqr(deuxd.spect[vind1].data[i,j,0].z)+sqr(deuxd.spect[vind1].data[i,j,0].mon));
   end;
   deuxd.spect[vind2].typeX:=deuxd.spect[vind1].typeX;
end;

{on se sert du parser en remplacant les variables par la
valeur dans la chaîne
pour chaque chaîne on rentre le nom (remplacé par [i,j])
on peut rentrer le nommon (remplacé par le moniteur) ou le
nomtemps remplacé par le temps}
function spectlist.parsechaine(s:string):boolean;{traite la chaîne du type nom3=f(nom1,nom2)}
var
  s2,s1:string;
  s3:array[1..10] of string;
  uu3:array[1..10] of integer;
  m,i,j,x,y,lt,k,l:integer;
  i1:integer;
  typx,typy:string;
  a:double;
begin
for i:=1 to 10 do s3[i]:='';
j:=1;x:=0;y:=0;lt:=0;
for i:=1 to totalspectre do
if spect[i]<>nil then
  if pos(spect[i].nom,s)>0 then begin
  s3[j]:=spect[i].nom;uu3[j]:=i;j:=j+1;
  x:=spect[i].x;y:=spect[i].y;lt:=spect[i].lt;
  typx:=spect[i].typex;typy:=spect[i].typey;
 end;
if (pos('=',s)>0) and (x>0) and (y>0) then begin
s2:=copy(s,pos('=',s)+1,length(s));
s1:=copy(s,1,pos('=',s)-1);
i1:=indexof(s1);
if i1<0 then begin
i1:=addspectre(s1,x,y,lt);
spect[i1].typex:=typx;
spect[i1].typey:=typy;
end;
for k:=0 to x-1 do
  for l:=0 to y-1 do
  begin
  dataeditform.parser1.setvariable('i',k);
  dataeditform.parser1.setvariable('j',l);
  for m:=0 to 9 do
    begin
    i:=m+1;
    if s3[i]<>'' then begin
        dataeditform.parser1.setvariable(s3[i],spect[uu3[i]].data[k,l,0].z);
        dataeditform.parser1.setvariable(s3[i]+'mon',spect[uu3[i]].data[k,l,0].mon);
        end;
    end;
  dataeditform.parser1.expression:=s2;
  a:=dataeditform.parser1.value;
  if (a<1e18) and (a>-1e18)
  then spect[i1].data[k,l,0].z:=a;
  end;
  end;
{ initialisation des abscisses }
{ DANGER : on suppose que l'equation est HOMOGENE !!! }
for k:=0 to x-1 do
  for l:=0 to y-1 do
  begin
    i:=1;
    while s3[i]=s1 do inc(i);
    spect[i1].data[k,l,0].x:=spect[indexOf(s3[i])].data[k,l,0].x;
    spect[i1].data[k,l,0].y:=spect[indexOf(s3[i])].data[k,l,0].y;
    spect[i1].data[k,l,0].lt:=0;
  end;

result:=true;
end;

procedure spectlist.saveall;
var
i:integer;
begin
i:=1;
while (i<=totalspectre)do begin
if spect[i]<>nil then spect[i].savetofile(spect[i].nom);
i:=i+1;
end;
end;

{ ===================================================== }
{ PROCEDURES LIEES A LA GESTION DE LA FENETRE           }
{----------------------tdataeditform--------------------}
procedure Tdataeditform.ComboBox1Change(Sender: TObject);
var
ind,i,j:integer;
begin
if unddeud=false then begin
ind:=deuxd.indexof(combobox1.text);
if ind>=1 then begin
editX.text:=inttostr(deuxd.spect[ind].X);
editY.text:=inttostr(deuxd.spect[ind].Y);
edittypx.text:=deuxd.spect[ind].typeX;
edittypy.text:=deuxd.spect[ind].typeY;
editnom.text:=deuxd.spect[ind].nom;
editcom.text:=deuxd.spect[ind].comment;
end;
end else begin
ind:=und.indexof(combobox1.text);
if ind>=1 then begin
editX.text:=inttostr(und.spect[ind].X);
editY.text:=inttostr(und.spect[ind].Y);
edittypx.text:=und.spect[ind].typeX;
edittypy.text:=und.spect[ind].typeY;
editnom.text:=und.spect[ind].nom;
editcom.text:=und.spect[ind].comment;
end;
end;
{ ======================================================== }
{ ci-dessus ancienne version                               }
{ nouvelle version utilisant TMS GRID                      }
if choix1D2D.itemIndex=0
then begin { cas 1D }
     ind:=und.indexof(combobox1.text);
     GridMesData.ColCount:=4;
     GridMesData.RowCount:=und.spect[ind].X+1;
     GridMesData.cells[1,0]:='X';GridMesData.cells[2,0]:='Z';GridMesData.cells[3,0]:='Mon';
     for i:=0 to und.spect[ind].X-1 do
       begin
        with GridMesData do
         begin cells[0,i+1]:=intToStr(i);floats[1,i+1]:=und.spect[ind].data[i,0,0].X;
               floats[2,i+1]:=und.spect[ind].data[i,0,0].Z;floats[3,i+1]:=und.spect[ind].data[i,0,0].mon; end;
       end
     end
else begin { cas 2D }
     ind:=deuxd.indexof(combobox1.text);
     GridMesData.ColCount:=deuxd.spect[ind].X+1;
     GridMesData.RowCount:=deuxd.spect[ind].Y+1;
     for i:=0 to deuxd.spect[ind].X-1 do
     begin
      GridMesData.cells[i+1,0]:=intToStr(i);
      for j:=0 to deuxd.spect[ind].Y-1 do
       begin
         with GridMesData do
         begin cells[0,j+1]:=intToStr(j);floats[i+1,j+1]:=deuxd.spect[ind].data[i,j,0].Z; end;
       end
     end;
     end;
end;

procedure Tdataeditform.FormCreate(Sender: TObject);
var
i:integer;
begin
unddeud:=true;
for i:=1 to totalspectre do
if und.spect[i]<>nil then
begin
combobox1.items.add(und.spect[i].nom);
end;
left:=0;top:=0;width:=520;height:=270;
WindowState:=wsMinimized;
update;
end;

procedure Tdataeditform.Edit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if key=13 then traitchaine(edit1.text);
end;

procedure Tdataeditform.traitchaine(s:string);
var
i:integer;
begin
if unddeud=true then begin
und.parsechaine(s);
combobox1.clear;
for i:=1 to totalspectre do
if und.spect[i]<>nil then
combobox1.items.add(und.spect[i].nom);
end else begin
deuxd.parsechaine(s);
combobox1.clear;
for i:=1 to totalspectre do
if deuxd.spect[i]<>nil then
combobox1.items.add(deuxd.spect[i].nom);
end;
end;

procedure Tdataeditform.CHoix1D2DClick(Sender: TObject);
var
i:integer;
begin
if choix1D2D.itemindex=0 then unddeud:=true else unddeud:=false;
if unddeud=true then begin
combobox1.clear;
for i:=1 to totalspectre do
if und.spect[i]<>nil then
combobox1.items.add(und.spect[i].nom);
end else begin
combobox1.clear;
for i:=1 to totalspectre do
if deuxd.spect[i]<>nil then
combobox1.items.add(deuxd.spect[i].nom);
end;
combobox1.itemindex:=0;
end;

procedure Tdataeditform.sauve(i:integer;nom:string);
begin
if (nom<>'tout') then begin
if i=1 then
if und.indexof(nom)>=0 then
und.spect[und.indexof(nom)].savetofile(nom);
if i=2 then
if deuxd.indexof(nom)>=0 then
deuxd.spect[deuxd.indexof(nom)].savetofile(nom);
end else begin
if i=1 then und.saveall;
if i=2 then deuxd.saveall;
end;
end;

{procédure de lecture d'un spectre à partir du disque dur }
{ INPUT : le nom du fichier                               }
procedure TdataEditForm.litSpectre1D(s:string);
begin
und.spect[1].readfromfile(boitnoir.RepertoireManip.text+'\'+s);
end;

procedure TdataEditForm.litSpectre2D(s:string);
begin
deuxd.spect[1].readfromfile(boitnoir.RepertoireManip.text+'\'+s);
end;

procedure Tdataeditform.SpeedButton2Click(Sender: TObject);
begin
if unddeud then sauve(1,combobox1.text)
else sauve(2,combobox1.text);
end;

procedure Tdataeditform.SpeedButton3Click(Sender: TObject);
begin
if unddeud then sauve(1,'tout')
else sauve(2,'tout');
end;

procedure Tdataeditform.SpeedButton5Click(Sender: TObject);
begin
if unddeud then und.deletespectre(und.indexof(combobox1.text))
else deuxd.deletespectre(deuxd.indexof(combobox1.text));
choix1D2Dclick(Sender);
end;

procedure Tdataeditform.SpeedButton4Click(Sender: TObject);
var
spec:spectre;
begin
spec:=spectre.create;
opendialog1.initialdir:=defaultdir;
if opendialog1.execute then
begin
spec.readfromfile(opendialog1.filename);
if spec.typey='double' then und.add(spec) else deuxd.add(spec);
end;
spec.Destroy;
end;

procedure Tdataeditform.EdittypXChange(Sender: TObject);
begin
if unddeud then und.spect[und.indexof(combobox1.text)].typeX:=edittypX.text
else deuxd.spect[deuxd.indexof(combobox1.text)].typeX:=edittypX.text;
end;

procedure Tdataeditform.EdittypYChange(Sender: TObject);
begin
if unddeud then und.spect[und.indexof(combobox1.text)].typeY:=edittypY.text
else deuxd.spect[deuxd.indexof(combobox1.text)].typeY:=edittypY.text;
end;

procedure Tdataeditform.EditnomChange(Sender: TObject);
begin
if unddeud then und.spect[und.indexof(combobox1.text)].nom:=editnom.text
else deuxd.spect[deuxd.indexof(combobox1.text)].nom:=editnom.text;
ComboBox1Change(Sender);
end;

procedure Tdataeditform.EditcomChange(Sender: TObject);
begin
if unddeud then und.spect[und.indexof(combobox1.text)].comment:=editcom.text
else deuxd.spect[deuxd.indexof(combobox1.text)].comment:=editcom.text;
end;

procedure Tdataeditform.ComboBox1DropDown(Sender: TObject);
var i:integer;
begin
{reinitialisation des items a chaque ouverture du combo}
combobox1.items.clear;

for i:=1 to totalspectre do
begin
if deuxd<>nil then
if deuxd.spect[i]<>nil then
   combobox1.items.add(deuxd.spect[i].nom);

if und<>nil then
if und.spect[i]<>nil then
   combobox1.items.add(und.spect[i].nom);
end;
end;


end.
