unit graph2D;
{le 22/02/01: Claire
Adaptation de Graph2D en cours avec le composant TImgView
pb: image est noire à l'allumage, la fiche s'appelle boite
    noire pendant l'éxécution, si l'on prend un spectre plus
    petit, on des pb aléaoires quand on veux afficherles droite
    de coupes (selon qu'on l'affiche en premier ou en second) }
{ BUGS : attention avec les curseurs il faut qu'ils se calent sur les tailles max du graph affiché }
{ sinon sérieux crash lors du clacul de la somme                              }
{ 21.01.01 : FO : ajout de fonctions de projection                                         }
{                 procedure TSpectre3DForm.ReplotButtonClick(Sender: TObject);             }
{ 21.01.01 : FO : lecture de fichiers 4 colonnes                                           }
{                 procedure TSpectre3DForm.Lecturefichier4colonnesClick(Sender: TObject);  }
{ 28.01.01 : FO : vind a disparu en tant que variable globale                              }
{            FO : checkbox "echelle automatique en z"                                      }
{ 06.03.01 : FO : mise a jour de la gestion des échelles                                   }
{                 test sytématique de la position des curseurs (In or OUT le graph pour eviter les plantages }
{                 utilisation de la méthode intégrale pour calculer "somme"                }
{                 passage du type Tedit à TeditNum pour moniteur et somme                  }
{                 calcul systématique des coupes C1H C1V C2H C2V et des porjection PH et PV lorsque }
{                 la position des curseurs change                                                   }
{                 Les résultats sont mis à jour sur le "graph1DForm" par défaut (à préciser dans le futur ex. gr2D[1] -> gr1D[1] }
{                 Les temps de calculs ne sont pas perceptibles                             }
{ 14.03.01 : FO : lecture des fichier HADAS 256x256                                         }
{                 A CORRIGER : le nom interne du spectre est defini d'une manière HORRIBLE (il faut que les spctres soient dans d:\temp }
{                 sinon la definition du nom ne marche pas ?!?      }
{ 15.03.01: CL : lorsque on supprime un spectre son nom disparait de la combo }
{                lorsqu'on charge un fichier HADAS il apparait directement et son nom est sélectionné dans la combo }
{ 20.03.01 : FO : les curseurs supportent maintenant que le bitmap soit shifté    }
{                 Nouvelle procédure de mise a jour de la liste des spectres dans la combo ChoixSpectre    }
{                 Cette procédure doit servir a remplacer les bricolages successifs                        }
{                 Il faut appeler cette procedure a chaque fois qu'il y a création ou destruction de spectre }
{27.03.01 : EL : Modif provisoir: ajout d'un message redessiner L 77 et 705.
                 attention: pilotagemanipmainform ajouté en uses pour message redessiner!!!                 }
{28.03.01:FO+EL: suppression des Tax et Tay, correction buggs                                                 }
{29.03.01 : EL : Ajout de Save2D, Save3D et open dans le menu + procedure Click associee pour appeller
                 les nouvelles procedures de sauvegarde}
{13.06.01 : EL : Création de la procedure AddHint pour mettre les commentaires en Hint.
                 modification de GensampleData pour appelle de AddHint
                 création de choixspectreDropDown pour mise a jour de la liste des spectres a chaque ouverture de la combo                           }
{11.07.01 : EL : Petites modifs pour visualisation des sommes sur spectre 2D (dont somme total)}
{18.09.01 : EL : Correction petit buggs + reactualisation de la combo choixspectre3D}
{19.09.01 : EL : modification de la procedure Slicenumberchange: cette procedure ne fait plus qu'initialiser les echelles
                 ltminproj et ltmaxproj puis appelle replot}
{20.09.01 : EL : debuggage divers (appelle de spectre inexistant),
{08.02.02 : EL : Modifs sur la fonction read from PAXY}
{11.03.02 : FO : ******* passage sous Delphi 6; c'est irréversible *********    }
{                rajout d'une echelle des couleurs                              }
{                echelles pour le minigraph1D                                   }
{ 20.03.02 : FO : mise ajour de l'autoscale                                     }
{ 24.03.02 : FO : possibilité de lire des fichier LAMP crées par D17            }
{ 25.03.02 : FO : disparition des variables locales zmin et zmax                }
{                 ca force la cohérence des échelles et il n'y a plus deproblème }
{                 lors du passage aux échelles LOG                              }
{ 24.05.02 : FO : possibilité de lire les spectres TPA (format bitmap de L'image plate) }
{ 17.07.02 : FO : * upgrade très serieux des palettes                           }
{                 * nouvelle procedre CursorsReplot (tracé des curseurs au meme }
{                   endroit après changement de spctre (très utile en pratique) }
{                   MAIS il reste un bug si les spectres ne sont pas de meme taille }
{                 * nouvelle fonction d'extraction des data                     }
{ 12.09.02 : FO : * amélioration de la gestion des coupes                       }
{ 08.12.02 : FO : * amélioration de la lecture des fichiers TPA                 }
{                   petit doute sur le point initila des coordonnées (0 ou 1?)  }
{                   les deux semblent marcher ?!                                }
{ 12.12.02 : FO : possibilité de faire des rotations (non interpolées)          }
{ 16.12.02 : FO : * il n'est plus possible d'ecraser un fichier NeXuS           }
{                   ca créait de toute facon des problèmes                      }
{                 * la destruction des spectres 2D ne crée plus d'erreur        }
{ 17.12.02 : FO : * amélioration de la gestion des extensions des fichiers      }
{                 * cursorReplot après chargement d'un spectre                  }
{ 17.02.03 : FO : * le graph est centré sur la croix rouge quand on zoom        }
{ 22.12.03 : FO : * lecture automatique d'un fichier a partir de son numero     }
{ ============================================================================= }
{ A NOTER                                                                       }
{ * le programme ne supporte plus qu'on ne lui donne pas typeX et typeY !!!     }
{   Il faut donc bien initialiser ces paramètres !!!                            }
{ ============================================================================= }
{ version A JOUR le 25.09.01                                                    }
{ ============================================================================= }
{ A FAIRE                                                                       }
{ * quand on lit des fichiers textes, etre plus "tolerant" sur le format des nombres le lignes et de colonnes }
{   des TAB excédentaires font planter le programme                             }
{ * préciser l'ordre de défilement des data dans le fichier X d'abord ou Y d'abord      } 
{ * management des derniers chemins de lecture/ecriture des fichiers            }
{ * déplacement des curseurs pixel par pixel au clavier                         }
{ * la rotation sur les spectres TPA ne fonctionne pas bien                     }
{ * après rotation, les spectres ne sont plus ok a 100%                         }
{ * mettre au clair les valeurs de Xcursor1 Xcurrent Xpos etc                   }
{   ca^pose des petits problemes lors de l'extraction des data ou des replots   }
{   Que représente-ils exactement?                                              }
{ * verifier ce que calcule somme box (strictement à l'interieur des curseurs, curseus ciompris ou un peu des deud ?
{ * la projection horizontale perd des neutrons !!!                             }
{   (compare avec la somme totale)                                              }
{ VERIFIER les bornes dans slice                                                }
{ afficher une box "out of limits" si necessaire                                }
{ changer l'evenement auquel repond SliceSpinEdit : ca mene a des plantages                }
{ afficher quelque part les dimensions en cours (X et Y du plot 2D                         }
{ mettre les ranges d'intégration aux valeurs min et max (lors du chargement du spectre    }
{ quel sytème de coordonées faut(il utiliser???   }
{ sauvegarder les coupes en diagonales dan un spectre affichable par Graph1D        }
{ l'utilisation systématique du type 'raw' semble poser qqes problèmes    }
{ quand on lit un fichier, on l'ouvre, a la création de la strcuture ca plante et le fichier n'est pas refermé }
{ mettre a jour la liste des fonctions disponibles }
{ *** procedure d'orthonormalisation de la fenetre graphique *** }
{ pour le moment c'est le NOMBRE de pixels en X et Y qui fixe la taille de la fenetre }
{ il faut que ce soit la taille xmax-xmin et ymax-ymin qui fixe la taille de l'image }
{ * mettre a jour les coupes en diagonale                                       }
{ les coupes en diagonales n'utilsent pas encore les vraies coordonnées .X et .Y }
{ * un truc sympa serait de pouvoir zoomer autour d'une position particulière   }
{ * coupe 1D ne se rafraichit pas automatiquement                               }
{  + fixer les min et max des axes                                              }

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  EditReal, StdCtrls, Spin, GR32, GR32_Bytemaps, GR32_Image, GR32_Layers,
  GR32_RangeBars, GR32_Filters, GR32_Transforms, GR32_Polygons, ExtCtrls,
  Menus, math, editdata, xyGraph, ComCtrls, lectureTPAOptions, Clipbrd,
  JvComponent, FileCtrl, JvDriveCtrls, StrUtils,FilesIO, JvFormPlace,
  Buttons;

const
    wm_redessine=$403+wm_user;
    wm_fermeture=$400+wm_user;
    wm_redessiner=$401+wm_user;

const
  coupeHorz1 = 1; { indices des graphes pour les différentes coupes }
  coupeVert1 = 2;
  coupeHorz2 = 3;
  coupeVert2 = 4;
  coupeDiagX  = 5;
  coupeDiagY  = 6;


type
  Tgraph2DForm = class(TForm)
    OpenDialog1: TOpenDialog;
    MainMenu1: TMainMenu;
    Opration1: TMenuItem;
    surmoniteur: TMenuItem;
    SaveDialog1: TSaveDialog;
    Panel4: TPanel;
    Panel5: TPanel;
    PnlPos: TPanel;
    Label9: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    Xpos1: TEditReal;
    Xpos2: TEditReal;
    Ypos2: TEditReal;
    Ypos1: TEditReal;
    Zval1: TEditReal;
    Zval2: TEditReal;
    Panel3: TPanel;
    N1: TMenuItem;
    Loupe: TMenuItem;
    PrintForm: TMenuItem;
    PrintDialog1: TPrintDialog;
    PageControl1: TPageControl;
    Sums: TTabSheet;
    moniteur: TEditReal;
    Label4: TLabel;
    Label5: TLabel;
    somme: TEditReal;
    TabSheet1: TTabSheet;
    Scale: TPageControl;
    TabSheet2: TTabSheet;
    TabSheet3: TTabSheet;
    palettecombo: TComboBox;
    ImageInterpolate: TCheckBox;
    ScaleBar: TGaugeBar;
    ScaleCombo: TComboBox;
    StretchButton: TButton;
    ZminBox: TEditReal;
    Label6: TLabel;
    ZmaxBox: TEditReal;
    ZlogCheckBox: TCheckBox;
    AutoScaleCheckBox: TCheckBox;
    TabSheet4: TTabSheet;
    TypeGraphCombo: TComboBox;
    NomMaskEdit: TEdit;
    TypeMaskCombo: TComboBox;
    MaskButton: TButton;
    Label1: TLabel;
    Label13: TLabel;
    sommetotal: TEditReal;
    ColorScale: TImage32;
    scale5: TLabel;
    scale1: TLabel;
    scale2: TLabel;
    scale3: TLabel;
    scale4: TLabel;
    Z1DMaxBox: TEditReal;
    Z1DMinBox: TEditReal;
    Label14: TLabel;
    N3: TMenuItem;
    File1: TMenuItem;
    Oldversion1: TMenuItem;
    lireenTEXTE1: TMenuItem;
    Sauverlebitmap1: TMenuItem;
    Sauverlespectreoldversion1: TMenuItem;
    Lireunspectreoldversion1: TMenuItem;
    N4: TMenuItem;
    SavetoFile1: TMenuItem;
    SavetoPAXY1: TMenuItem;
    SavetoBitmap1: TMenuItem;
    SaveToBinarysigned32bits1: TMenuItem;
    SavetoASCII1: TMenuItem;
    ReadfromFile1: TMenuItem;
    ReadfromPAXY1: TMenuItem;
    LectureTPAOptions1: TMenuItem;
    LectureTPA1: TMenuItem;
    LectureLAMPD171: TMenuItem;
    LectureFichierHADAS1: TMenuItem;
    LectureFichier4Colonnes1: TMenuItem;
    N5: TMenuItem;
    Save3D1: TMenuItem;
    Save2D1: TMenuItem;
    Open1: TMenuItem;
    Supprimer2D2: TMenuItem;
    Supprimer3D2: TMenuItem;
    Graph2D: TMenuItem;
    HGaugeBar: TGaugeBar;
    Label18: TLabel;
    Label19: TLabel;
    Label20: TLabel;
    SGaugeBar: TGaugeBar;
    LGaugeBar: TGaugeBar;
    H2GaugeBar: TGaugeBar;
    S2GaugeBar: TGaugeBar;
    L2GaugeBar: TGaugeBar;
    Scalar1: TMenuItem;
    Addition1: TMenuItem;
    Soustraction2: TMenuItem;
    Multiplication1: TMenuItem;
    Division1: TMenuItem;
    Betweenspectra1: TMenuItem;
    Addition2: TMenuItem;
    Soustraction3: TMenuItem;
    Multiplication2: TMenuItem;
    Division2: TMenuItem;
    Extractselection1: TMenuItem;
    EraseCursorsButton: TButton;
    XcrtBox: TEditReal;
    YCrtBox: TEditReal;
    ZCrtBox: TEditReal;
    SavetoNeXuS1: TMenuItem;
    N2: TMenuItem;
    ReadfromNeXus1: TMenuItem;
    ReadfromNeXusLLB1: TMenuItem;
    Panel6: TPanel;
    Panel7: TPanel;
    MiniParserBox: TEdit;
    SavetoHDF1: TMenuItem;
    InvertCheckBox: TCheckBox;
    PageControl2: TPageControl;
    TabSheet5: TTabSheet;
    TicksCheckBox: TCheckBox;
    N6: TMenuItem;
    CopyBitmapToClipboard1: TMenuItem;
    XTickStepBox: TEditReal;
    YtickStepBox: TEditReal;
    Label21: TLabel;
    Label22: TLabel;
    PlotTicksButton: TButton;
    TabSheet6: TTabSheet;
    ScaleSx: TGaugeBar;
    ScaleSy: TGaugeBar;
    RotationAngleBox: TEditReal;
    Label23: TLabel;
    Rotation1: TMenuItem;
    ImgView32Dst: TImgView32;
    Panel8: TPanel;
    Panel9: TPanel;
    ChoixSpectre: TComboBox;
    Circularsum1: TMenuItem;
    SANScircularsum1: TMenuItem;
    GetFileButton: TButton;
    FileListBox: TJvFileListBox;
    FileNrSpinEdit: TSpinEdit;
    Label24: TLabel;
    Read3columnsfileXYI1: TMenuItem;
    ReadfreeXYZ1: TMenuItem;
    CheckBoxMasks: TCheckBox;
    SymmetryBox: TRadioGroup;
    Panel1: TPanel;
    ParamLabel1: TLabel;
    ParamLabel6: TLabel;
    ParamLabel5: TLabel;
    ParamLabel4: TLabel;
    ParamLabel3: TLabel;
    ParamLabel2: TLabel;
    ParamBox1: TEditReal;
    ParamBox2: TEditReal;
    paramBox3: TEditReal;
    ParamBox4: TEditReal;
    ParamBox5: TEditReal;
    ParamBox6: TEditReal;
    TabSheet7: TTabSheet;
    Xprojection: TRadioGroup;
    Yprojection: TRadioGroup;
    Label3: TLabel;
    XminProj: TEditReal;
    Label2: TLabel;
    XmaxProj: TEditReal;
    YmaxProj: TEditReal;
    YminProj: TEditReal;
    Label15: TLabel;
    Label16: TLabel;
    ltMinProj: TEditReal;
    ltMaxProj: TEditReal;
    ReplotButton: TButton;
    SliceNumber: TSpinEdit;
    Label7: TLabel;
    Label8: TLabel;
    ChoixSpectre3D: TComboBox;
    GroupBox1: TGroupBox;
    Label12: TLabel;
    Xcen: TEditReal;
    Ycen: TEditReal;
    Label17: TLabel;
    CalculateCircularSumButton: TButton;
    FileTypeButton: TButton;
    JvFormPlace1: TJvFormPlace;
    ReadHADASglatt1: TMenuItem;
    ReadfromPAXE1: TMenuItem;
    ReadformMatlab1: TMenuItem;
    Read3columnsXYZSDMS1: TMenuItem;
    N7: TMenuItem;
    N8: TMenuItem;
    N9: TMenuItem;
    BinningStepBox: TEditReal;
    ImgView: TImgView32;
    SpeedButton2: TSpeedButton;
    procedure StretchButtonClick(Sender: TObject);
    procedure ScaleComboChange(Sender: TObject);
    procedure AddHint(Cible: TComboBox);
    procedure FormCreate(Sender: TObject);
    procedure LivePaletteUpdate(Sender: TObject);
{    procedure ImgMouseEvent(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); }
    procedure Nouveau1Click(Sender: TObject);
    procedure choixspectreChange(Sender: TObject);
    procedure Supprimer2DClick(Sender: TObject);
    procedure sauvegarderClick(Sender: TObject);
    procedure openspectreClick(Sender: TObject);
    procedure openClick(Sender: TObject);
    procedure palettecomboChange(Sender: TObject);
    procedure Effacer1Click(Sender: TObject);
    procedure AdditionClick(Sender: TObject);
    procedure Soustraction1Click(Sender: TObject);
    procedure surmoniteurClick(Sender: TObject);
    procedure SavetoPAXY1Click(Sender: TObject);
    procedure save2DClick(Sender: TObject);
    procedure save3DClick(Sender: TObject);
    procedure ReadfromPAXY1Click(Sender: TObject);
    procedure readW31Click(Sender: TObject);
    procedure TypeGraphComboChange(Sender: TObject);
    procedure ImageInterpolateClick(Sender: TObject);
    procedure ZlogCheckBoxClick(Sender: TObject);
    procedure ZminBoxExit(Sender: TObject);
    procedure ZmaxBoxExit(Sender: TObject);
    procedure ReplotButtonClick(Sender: TObject);
    procedure SliceNumberChange(Sender: TObject);
    procedure ChoixSpectre3DChange(Sender: TObject);
    procedure Panel9Click(Sender: TObject);
    procedure ProjectionButtonClick(Sender: TObject);
    procedure LectureFichierHadasMenuClick(Sender: TObject);
    procedure YcenExit(Sender: TObject);
    procedure XcenExit(Sender: TObject);
    procedure PrintGraphClick(Sender: TObject);
    procedure PrintFormClick(Sender: TObject);
    procedure ReScaleButtonClick(Sender: TObject);
    procedure TypeMaskComboChange(Sender: TObject);
    procedure MultiplicationClick(Sender: TObject);
    procedure DivisionClick(Sender: TObject);
    procedure MaskButtonClick(Sender: TObject);
    procedure SaveToASCIIClick(Sender: TObject);
    procedure choixspectreDropDown(Sender: TObject);
    procedure Supprimer3DClick(Sender: TObject);
    procedure ColorScaleResize(Sender: TObject);
    procedure ImgViewMouseDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
    procedure ZminBoxChange(Sender: TObject);
    procedure ZmaxBoxChange(Sender: TObject);
    procedure ZmaxBoxKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure ZminBoxKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure AutoScaleCheckBoxClick(Sender: TObject);
    procedure CursorsReplot;

    procedure LectureLAMPD171Click(Sender: TObject);
    procedure LectureTPA1Click(Sender: TObject);
    procedure LectureTPAOptions1Click(Sender: TObject);
    procedure BinningStepBoxChange(Sender: TObject);
    procedure SaveToBinary32bitssignedClick(Sender: TObject);
    procedure SavetoBitmap1Click(Sender: TObject);
    procedure ScaleBarChange(Sender: TObject);
    procedure Addition1Click(Sender: TObject);
    procedure Soustraction2Click(Sender: TObject);
    procedure Multiplication1Click(Sender: TObject);
    procedure Division1Click(Sender: TObject);
    procedure FileTypeButtonClick(Sender: TObject);
    procedure Extractselection1Click(Sender: TObject);
    procedure EraseCursorsButtonClick(Sender: TObject);
    procedure ImgViewMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer; Layer: TCustomLayer);
    procedure Lireunspectreoldversion1Click(Sender: TObject);
    procedure Sauverlespectreoldversion1Click(Sender: TObject);
    procedure SavetoNeXuS1Click(Sender: TObject);
    procedure ReadfromNeXus1Click(Sender: TObject);
    procedure ReadfromNeXusLLB1Click(Sender: TObject);
    procedure MiniParserBoxKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure traitchaine(s:string);
    procedure LectureFichierHADAS1Click(Sender: TObject);
    procedure LectureFichier4Colonnes1Click(Sender: TObject);
    procedure SavetoHDF1Click(Sender: TObject);
    procedure SavetoASCII1Click(Sender: TObject);
    procedure SaveToBinarysigned32bits1Click(Sender: TObject);
    procedure InvertCheckBoxClick(Sender: TObject);
    procedure CopyBitmapToClipboard1Click(Sender: TObject); {Ne fonctionne pas bien ???}
    procedure UpdateTicks;
    procedure PlotTicksButtonClick(Sender: TObject);
    procedure savetostream(f:TStream; savedata:boolean);
    procedure FillMetafile(wmf:TMetafile);
    procedure FillBitmap(bmp:TBitmap);    
    procedure CopyToClipboard;
    procedure ZminBoxEnter(Sender: TObject);
    procedure ZmaxBoxEnter(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure ScaleSxChange(Sender: TObject);
    procedure ScaleSyChange(Sender: TObject);
    procedure Rotation1Click(Sender: TObject);
    procedure ImgViewMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
    procedure ImgViewMouseWheelDown(Sender: TObject; Shift: TShiftState;
      MousePos: TPoint; var Handled: Boolean);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure GetFileButtonClick(Sender: TObject);
    procedure Read3columnsfileXYI1Click(Sender: TObject);
    procedure ReadfreeXYZ1Click(Sender: TObject);
    procedure CheckBoxMasksClick(Sender: TObject);
    procedure Circularsum1Click(Sender: TObject);
    procedure CalculateCircularSumButtonClick(Sender: TObject);
    procedure ReadHADASglatt1Click(Sender: TObject);
    procedure ReadfromPAXE1Click(Sender: TObject);
    procedure ReadformMatlab1Click(Sender: TObject);
    procedure Read3columnsXYZSDMS1Click(Sender: TObject);
    procedure SpeedButton2Click(Sender: TObject);
   // procedure LoupeClick(Sender: TObject);

  private
{    taX,tay:integer; } { pas de variables semi-globales sauf necessité absolue !!! }
    { Déclarations privées}
    procedure wmredessiner(var msg:tmessage); message wm_redessiner;
  protected
  //function CreatePositionedLayer: TPositionedLayer;
  public
    { Déclarations publiques}
    CurrentScale: double;
    DataSet: TByteMap;
    DataSetAux: TByteMap;
    ColorBar:TByteMap; { barre de couleurs pour savoir quoi est quoi }
    CurrentX,CurrentY: integer;
    Xcursor1, Ycursor1, Xcursor2, Ycursor2:integer;
    xmin,xmax,ymin,ymax:double;
{    Zmin,Zmax:double; }
    PolygonH1, PolygonV1, PolygonH2, PolygonV2, PolygonD: TPolygon32;
    palGrayscale: TPalette32;
    palGreens: TPalette32;
    palReds: TPalette32;
    palRainbow: TPalette32;
    palMultiColor: TPalette32;
    palBlues: TPalette32;
    palPurple: TPalette32;
    palCustom:Tpalette32;
{ matrice de transformation }
    AT: TAffineTransformation;
    TT: TTransformation;

    procedure openFile(fileName:string);
    procedure openFileNexus(fileName:string);
    procedure openFileNexusLLB(fileName:string);
    procedure openFilePAXY(fileName:string);     
    procedure MiseAjourChoixSpectre(var ListeDeSpectres:spectList);
    procedure MiseAjourChoixSpectre3D(var ListeDeSpectres:spectList);
    procedure AutoScale(var spec:spectre);
    procedure GenPalettes;
    procedure GenSampleData(name:string);
    procedure PaintData;
    procedure draw;
    procedure UpdateCourbesAafficher;
    constructor Create(AOwner: TComponent;X:integer;Y:integer);reintroduce;
    procedure ReScale(echx,echy,alpha: Single);
    procedure DoTransform(Sx,Sy:double);
  end;

var
  graph2DForm: Tgraph2DForm;

implementation

uses BoiteNoire, dialogAddSpectrum, dialogScalAddSpectrum, MainForm;

{$R *.DFM}
{*************************************************************}

constructor Tgraph2DForm.Create(AOwner: TComponent;X:integer;Y:integer);
begin
 inherited create(Aowner);
{ taX:=X;
 taY:=Y; }
 imgview.Options := [pboautofocus ] 
end;

procedure Tgraph2dform.wmredessiner(var msg:tmessage);
var vind:integer;
begin
  vind:=deuxd.indexof(choixspectre.text);
  if vind>=1 then
  begin
    AutoScale(deuxd.spect[vind]);
    GenSampleData(choixspectre.text);
    PaintData;
    draw;
  end;
end;

{ mise a jour de la combo ChoixSpectre à partir de la liste des spectres 2D }
{ INPUT: la liste de spectres "deuxd" en général                            }
{        a passer en var parce que la taille risque de devenir gigantesque  }
procedure Tgraph2DForm.MiseAjourChoixSpectre(var ListeDeSpectres:spectList);
var i:integer;
begin
{reinitialisation des items a chaque ouverture du combo}
   choixSpectre.items.clear;
   for i:=1 to totalspectre do
   begin
      if ListeDeSpectres<>nil then
      if deuxd.spect[i]<>nil then
      choixSpectre.items.add(ListeDeSpectres.spect[i].nom);
   end;
end;

{ mise a jour de la combo ChoixSpectre3D à partir de la liste des spectres 3D }
{ INPUT: la liste de spectres "troisd" en général                            }
{        a passer en var parce que la taille risque de devenir gigantesque  }
procedure Tgraph2DForm.MiseAjourChoixSpectre3D(var ListeDeSpectres:spectList);
var i:integer;
begin
{reinitialisation des items a chaque ouverture du combo}
   choixSpectre3D.items.clear;
   for i:=1 to totalspectre do
   begin
      if ListeDeSpectres<>nil then
      if troisd.spect[i]<>nil then
      choixSpectre3d.items.add(ListeDeSpectres.spect[i].nom);
   end;

end;
{************************
Ajoute commentaire et conditions exp en Hint}
procedure TGraph2DForm.AddHint(Cible: TComboBox);
var s:string;
    vind,i:integer;
begin
vind:=deuxd.indexof(Cible.text);
s:=deuxd.spect[vind].comment;
if deuxd.spect[vind].ExpCondNbr >0 then
   for i:=0 to deuxd.spect[vind].ExpCondNbr-1 do
       s:=s+#10+deuxd.spect[vind].experimentalConditions[i].name+' : '+floattostr(deuxd.spect[vind].experimentalConditions[i].value);
cible.showHint:=true;
cible.hint:=s;
end;
{************************
}
procedure TGraph2DForm.AutoScale(var spec:spectre);
var min,max:double;
begin
   if (AutoScaleCheckBox.checked=true) then
   begin
        spec.minmax(min,max);
        ZminBox.value:=min;ZmaxBox.value:=max;
        if (ZlogCheckBox.checked=true) and (Zminbox.value<=0)
        then Zminbox.value:=(Zmaxbox.value-Zminbox.value)/100;
   end;
end;

{************************************************************}
{Procédure qui remplit des palettes : grise, verte et rainbow }
{INPUT: rien                                                  }
{OUTPUT: initialisation des palettes                          }
{REM: Origine Surface2D                                       }
{ on peut envisager d'en rajouter autant qu'on veut           }
procedure Tgraph2DForm.GenPalettes;
var
  i: Integer;
  f: Single;
  a,b,c,a2,b2,c2:double;
begin
  a:=HgaugeBar.position/100;b:=SgaugeBar.position/100;c:=LgaugeBar.position/100;
  a2:=H2gaugeBar.position/100;b2:=S2gaugeBar.position/100;c2:=L2gaugeBar.position/100;
  if InvertCheckBox.checked=false then
  for i:=0 to 255 do
  begin
    f := i / 255;
    palGrayscale[i] :=HSLtoRGB(0, 0, f );
    palGreens[i] := HSLtoRGB(f * 0.4, 0.5, f * 0.4 + 0.2);
    palReds[i] := HSLtoRGB(0.8 + f * 0.3 , 0.7 + f * 0.3, f * 0.85 + 0.1);
    palMultiColor[i] := HSLtoRGB(f * 1.2, 0.6, f * 0.8 + 0.2);
    palRainbow[i] := HSLtoRGB(0.9*f, 1, 0.5);
    palBlues[i] := HSLtoRGB(0.7, f, f);
    palPurple[i] := HSLtoRGB(0.9, f, f);
    palCustom[i] := HSLtoRGB(a*f+a2, b*f+b2, c*f+c2);
  end;
  if InvertCheckBox.checked=true then
  for i:=0 to 255 do
  begin
    f := i / 255;
    palGrayscale[i] :=HSLtoRGB(0, 0, 1-(f));
    palGreens[i] := HSLtoRGB(1-(f * 0.4), 0.5, 1-(f * 0.4 + 0.2));
    palReds[i] := HSLtoRGB(1-(0.8 + f * 0.3) , 1-(0.7 + f * 0.3), 1-(f * 0.85 + 0.1));
    palMultiColor[i] := HSLtoRGB(1-f * 1.2, 0.6, 1-f * 0.8 + 0.2);
    palRainbow[i] := HSLtoRGB(1-0.9*f, 1, 0.5);
    palBlues[i] := HSLtoRGB(0.7, 1-f, 1-f);
    palPurple[i] := HSLtoRGB(0.9, 1-f, 1-f);
    palCustom[i] := HSLtoRGB((a*f+a2), 1-(b*f+b2), 1-(c*f+c2));
  end;
end;

{************************************************************}
{Procédure qui initialise dataset avec le spectre            }
{ cette procédure remappe les data pour les mettre sur une echelle de 0 à 255 }
{INPUT: le nom du spectre à ramapper                         }
{OUTPUT: Dataset est mis a jour                              }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.GenSampleData(name:string);
var
  i, j, vind: Integer;
  W,H,tailleX,tailleY:integer;
  aux,aux1:double;
  zmax,zmin:double;

  function Clamp(FloatVal: Extended): Byte;
  begin
    if FloatVal <= 0 then Result := 0
    else if FloatVal >= 1 then Result := 255
    else Result := Round(FloatVal * 255);
  end;

begin
  {affiche les comentaires en Hint}
  AddHint(choixspectre);
  zmax:=zmaxbox.value;zmin:=zminbox.value;
  vind:=deuxd.indexof(name);
  W:=deuxd.spect[vind].X;
  H:=deuxd.spect[vind].Y;
  if ZlogCheckBox.checked=false
  then begin
     aux:=Zmax-Zmin;
     if aux=0 then aux:=1;
     DataSet.SetSize(W, H);

     for j := 0 to H - 1 do
         for i := 0 to W - 1 do
         begin
         // just some noise
         DataSet[i, j] := Clamp((deuxd.spect[vind].data[i,j,0].z-Zmin)/aux);
         end;
  end
  else begin
     aux:=Log10(Zmax)-Log10(Zmin);
     if aux=0 then aux:=1;
     DataSet.SetSize(W, H);
     for j := 0 to H - 1 do
         for i := 0 to W - 1 do
         begin
         // just some noise
         aux1:=deuxd.spect[vind].data[i,j,0].z;
         if aux1>0
         then DataSet[i, j] := Clamp((log10(aux1)-log10(zmin))/aux)
         else DataSet[i, j] := 0;
         end;
     end;
  { Affichage moniteur}
  moniteur.value:=deuxd.spect[vind].moniteur;
  sommetotal.value:=deuxd.spect[vind].total;
  tailleX:=deuxd.spect[vind].X;tailleY:=deuxd.spect[vind].Y;
  if  (Xpos1.value>=min(deuxd.spect[vind].data[0,0,0].X,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].X))
  and (Xpos2.value>=min(deuxd.spect[vind].data[0,0,0].X,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].X))
  and (Ypos1.value>=min(deuxd.spect[vind].data[0,0,0].Y,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].Y))
  and (Ypos2.value>=min(deuxd.spect[vind].data[0,0,0].Y,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].Y))
  and (Xpos1.value<=max(deuxd.spect[vind].data[0,0,0].X,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].X))
  and (Xpos2.value<=max(deuxd.spect[vind].data[0,0,0].X,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].X))
  and (Ypos1.value<=max(deuxd.spect[vind].data[0,0,0].Y,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].Y))
  and (Ypos2.value<=max(deuxd.spect[vind].data[0,0,0].Y,deuxd.spect[vind].data[tailleX-1,tailleY-1,0].Y))
  then somme.value:=deuxd.spect[vind].IntegraleSpectre2D(min(Xpos1.value,Xpos2.value),min(Ypos1.value,Ypos2.value),max(Xpos1.value,Xpos2.value),max(Ypos1.value,Ypos2.value))
  else somme.value:=0;
end;

{************************************************************}
{Procédure qui paint l'image grâce à DataSet                 }
{INPUT: rien                                                 }
{OUTPUT: l'image est rafraichie a partir de dataSet          }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.PaintData;
var
  P: PPalette32;
  zmin,zmax:double;
begin
  zmin:=zminBox.value;zmax:=zmaxBox.value;
  case PaletteCombo.ItemIndex of
    0: P := @palGrayScale;
    1: P := @palRainbow;
    2: P := @palMultiColor;
    3: P := @palReds;
    4: P := @palGreens;
    5: P := @palBlues;
    6: P := @palPurple;
  else
    P := @palCustom;
  end;
  DataSet.WriteTo(ImgView.Bitmap, P^);
  DataSet.WriteTo(ImgView32Dst.Bitmap, P^);
  DoTransform(ScaleSx.Position/100,ScaleSy.Position/100);

{ echelle des couleurs }
  ColorBar.writeTo(ColorScale.bitmap, P^);
{ ecriture des graduations  sur l'échelle de couleur}
{ mise en place des labels aux bons endroits }
   scale5.Top:=colorScale.Top;
   scale4.Top:=colorScale.Top+round(0.75*colorScale.height)-3;
   scale3.Top:=colorScale.Top+round(0.5*colorScale.height)-6;
   scale2.Top:=colorScale.Top+round(0.25*colorScale.height)-9;
   scale1.Top:=colorScale.Top+colorScale.height-12;
{ cas d'une echelle lineaire }
if ZlogCheckBox.checked=false then
begin
   scale5.caption:=FloatToStrF(zmax,ffGeneral,1,3);
   scale1.caption:=FloatToStrF(zmin,ffGeneral,1,3);
   scale2.caption:=FloatToStrF((zmax-zmin)/4+zmin,ffGeneral,1,3);
   scale3.caption:=FloatToStrF((zmax+zmin)/2,ffGeneral,1,3);
   scale4.caption:=FloatToStrF(3*(zmax-zmin)/4+zmin,ffGeneral,1,3);
end;
{ cas d'une echelle logarithmique }
if ZlogCheckBox.checked=true then
begin
   scale5.caption:=FloatToStrF(zmax,ffGeneral,1,3);
   scale1.caption:=FloatToStrF(zmin,ffGeneral,1,3);
   scale2.caption:=FloatToStrF(power(10,(log10(zmax)-log10(zmin))/4+log10(zmin)),ffGeneral,1,3);
   scale3.caption:=FloatToStrF(power(10,(log10(zmax)-log10(zmin))/2+log10(zmin)),ffGeneral,1,3);
   scale4.caption:=FloatToStrF(power(10,3*(log10(zmax)-log10(zmin))/4+log10(zmin)),ffGeneral,1,3);
end;


end;

{************************************************************}
{Procédure qui crée Tspectre2Dform                           }
{INPUT: Tobject                                              }
{OUTPUT: initialisation du spectre, Zmin(Box),Zmax(Box),
         xmin, xmax, zmin, zmax,création de Dataset,
         création des curseurs, lancement de procédures...   }

{REM: Origine graph2D oldversion amélioré                    }
procedure Tgraph2DForm.FormCreate(Sender: TObject);
var
  i,vind:integer;
begin
{ positionnement par défaut de la fénétre }
  WindowState:=wsMinimized;
  left:=521;top:=0;width:=495;height:=670;
{ echelle de couleurs }
  ColorBar := TByteMap.Create;
  ColorBar.setSize(1,256);
  for i:=0 to 255 do ColorBar[0,i]:=255-i; { echelle lineaire }
  ColorScale.ScaleMode := SmStretch;   { ne fonctionne pas en ImgView32 ?!? }

  MiseAJourChoixSpectre(deuxd);
  DataSet := TByteMap.Create;
  DataSetAux := TByteMap.Create;
  AT := TAffineTransformation.Create;
  TT := AT;
  GenPalettes;
  {GenSampleData(choixSpectre.text);
   xmin:= 0;xmax:= deuxd.spect[vind].X-1;ymin:= 0;ymax:= deuxd.spect[vind].Y-1; }
  GenSampleData(choixspectre.text);
  PaintData;
  PaletteCombo.ItemIndex := 3;
  CurrentScale:=1;
  { création des curseurs }
  PolygonH1 := TPolygon32.Create;
  PolygonV1 := TPolygon32.Create;
  PolygonH2 := TPolygon32.Create;
  PolygonV2 := TPolygon32.Create;
  PolygonD := TPolygon32.Create;
  UpdateCourbesAafficher;
  { on dessine le premier spectre }
  vind:=deuxd.indexof(choixspectre.text);
  if vind>=1 then
  begin
    AutoScale(deuxd.spect[vind]);
    GenSampleData(choixspectre.text);
    PaintData;
    CursorsReplot;
  end;
  { bitmaps manipulations }
  ImgView32Dst.SetupBitmap; // set the destination bitmap size to match the image size
  // make the border pixels transparent while keeping their RGB components
{  SetBorderTransparent(Image32Src.Bitmap,Rect(0, 0, Image32Src.Bitmap.Width - 1, Image32Src.Bitmap.Height - 1)); }
  DoTransform(1,1);
end;

procedure TGraph2DForm.DoTransform(Sx,Sy:double);
var
  p:PPalette32;
  vind:integer;
  W,H:integer;
  i, j: Integer;
  Pcol:Pcolor32;
begin
  vind:=deuxd.indexof(choixSpectre.text);
  W:=deuxd.spect[vind].X;H:=deuxd.spect[vind].Y;
  DataSetAux.SetSize(round(W*Sx),round(H*Sy));
  case PaletteCombo.ItemIndex of
    0: P := @palGrayScale;
    1: P := @palRainbow;
    2: P := @palMultiColor;
    3: P := @palReds;
    4: P := @palGreens;
    5: P := @palBlues;
    6: P := @palPurple;
  else
    P := @palCustom;
  end;
//  DataSetAux.WriteTo(ImgView32Dst.Bitmap, P^);
  DataSetAux.WriteTo(ImgView.Bitmap, P^);
//  TT.SrcRect := FloatRect(0, 0, ImgView.Bitmap.Width - 1, ImgView.Bitmap.Height - 1);
  TT.SrcRect := FloatRect(0, 0, ImgView32Dst.Bitmap.Width - 1, ImgView32Dst.Bitmap.Height - 1);
  AT.Clear;AT.Scale(Sx, Sy);

//  ImgView32Dst.BeginUpdate;
  ImgView.BeginUpdate;
  // Fill Dst with checkerboard pattern
{  Pcol := ImgView32Dst.Bitmap.PixelPtr[0, 0];
  for j := 0 to ImgView32Dst.Bitmap.Height - 1 do
    for i := 0 to ImgView32Dst.Bitmap.Width - 1 do
    begin
      if Odd(i shr 4) = Odd(j shr 4) then Pcol^ := clGray32
      else Pcol^ := clWhite32;
      Inc(Pcol);
    end;  }
//  Transform(ImgView32Dst.Bitmap, Image32Src.Bitmap, TT);
// Transform(ImgView32Dst.Bitmap, ImgView.Bitmap, TT);
//  ImgView32Dst.EndUpdate;
//  ImgView32Dst.Repaint;
  Transform(ImgView.Bitmap, ImgView32Dst.Bitmap, TT);
  ImgView.EndUpdate;
  ImgView.Repaint;

end;

{************************************************************}
{Procédure qui réagit au cochement de Zlog Scale             }
{INPUT: Tobject                                              }
{OUTPUT:renvoie un graphique à l'échelle log10 selon zmin et
        zmax                                                 }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.ZlogCheckBoxClick(Sender: TObject);
begin
     if (zminbox.value>0) and (zmaxbox.value>0)
     then begin
          GenSampleData(choixSpectre.text);PaintData;
          end
     else begin
          zminBox.value:=zmaxBox.Value/100;
{          ZlogCheckBox.checked:=false;ZlogCheckBox.update;
          MessageDlg('You need a positive Z range',mtError,[mbOk],0); }
          GenSampleData(choixSpectre.text);PaintData;
          end;
end;
{************************************************************}
{Procédure qui réagit aprés avoir quitté ZminBox (modifier)  }
{INPUT: Tobject                                              }
{OUTPUT:renvoie un graphique selon les valeurs de zmin et
        zmax                                                 }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.ZminBoxExit(Sender: TObject);
begin
  GenSampleData(choixSpectre.text);
  paintdata;
  CursorsReplot;
end;
{************************************************************}
{Procédure qui réagit aprés avoir quitté ZmaxBox (modifier)  }
{INPUT: Tobject                                              }
{OUTPUT:renvoie un graphique selon les valeurs de zmin et
        zmax                                                 }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.ZmaxBoxExit(Sender: TObject);
begin
  GenSampleData(choixSpectre.text);
  paintdata;CursorsReplot;
end;
{************************************************************}
{Procédure étire l'image au maximum dans la fenêtre visible  }
{INPUT: Tobject                                              }
{OUTPUT:image étirée                                         }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.StretchButtonClick(Sender: TObject);
var
  NewScale1,NewScale2: Single;
  vind:integer;
begin
  vind:=deuxd.indexof(choixSpectre.text);
  NewScale1:=abs(ImgView.GetViewPortRect.Left-ImgView.GetViewPortRect.Right)/deuxd.spect[vind].X;
  NewScale2:=abs(ImgView.GetViewPortRect.Top-ImgView.GetViewPortRect.Bottom)/deuxd.spect[vind].Y;
  CurrentScale:=min(NewScale1,NewScale2);
  ImgView.ScaleMode := SmScale;ImgView.Scale := CurrentScale;
{  ImgView.ScaleMode := SmStretch;   { ne fonctionne pas en ImgView32 ?!? }
{  ImgView.scale(CurrentScale,CurrentScale*aspectRatio.value); }
//  NewScale1:=abs(ImgView32Dst.GetViewPortRect.Left-ImgView32Dst.GetViewPortRect.Right)/deuxd.spect[vind].X;
//  NewScale2:=abs(ImgView32Dst.GetViewPortRect.Top-ImgView32Dst.GetViewPortRect.Bottom)/deuxd.spect[vind].Y;
//  CurrentScale:=min(NewScale1,NewScale2);
  ImgView32Dst.ScaleMode := SmScale;ImgView32Dst.Scale := CurrentScale;
//  ScaleBar.Position:=trunc(100*log10(CurrentScale));
end;
{************************************************************}
{Procédure qui change l'échelle de l'image                   }
{INPUT: Tobject                                              }
{OUTPUT:image à l'échèlle demandé                            }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.ScaleComboChange(Sender: TObject);
var
  S: string;
  I: Integer;
begin
  S := ScaleCombo.Text;
  S := StringReplace(S, '%', '', [rfReplaceAll]);
  S := StringReplace(S, ' ', '', [rfReplaceAll]);
  if S = '' then Exit;
  I := StrToIntDef(S, -1);
  if (I < 1) or (I > 2000) then I := Round(ImgView.Scale * 100)
  else begin
       ImgView.Scale := I / 100; currentScale:=I/100;
       end;
  ScaleCombo.Text := IntToStr(I) + '%';
  ScaleCombo.SelStart := Length(ScaleCombo.Text) - 1;
  ScaleBar.Position:=round(Log10(I/100)*100);ScaleBar.Repaint;
end;

{************************************************************}
{Procédure qui change l'échelle de l'image                   }
{INPUT: Tobject                                              }
{OUTPUT:image à l'échèlle demandé selon le déplacement dans
        la barre                                             }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.ScaleBarChange(Sender: TObject);
var
  NewScale: Single;
begin
  NewScale := Power(10, (ScaleBar.Position) / 100);
  CurrentScale:=NewScale;
  ScaleBar.Repaint;
  ImgView.ScaleMode := SmScale;
  ImgView.Scale := NewScale;
  ImgView32Dst.ScaleMode := SmScale;
  ImgView32Dst.Scale := NewScale;

  ImgView.ScrollToCenter(currentX,currentY);
end;

{************************************************************}
{Procédure permettant de dessiner les droites de coupes      }
{INPUT: rien                                                 }
{OUTPUT:dessine les droites de coupes                        }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.Draw;
begin
  ImgView.Bitmap.BeginUpdate;
  ImgView.Bitmap.Clear(clWhite32);
{  ImgView.Bitmap.Draw(50, 50, BitmapList.Bitmaps[0].Bitmap); } { cette ligne ne marche pas }
{ on essaie ca }  PaintData;
  PolygonH1.Antialiased := false; {Antialiase.Checked; }
  PolygonV1.Antialiased := false; {Antialiase.Checked; }
  PolygonH1.DrawFill(ImgView.Bitmap, SetAlpha(clGreen32, 255));
  PolygonV1.DrawFill(ImgView.Bitmap, SetAlpha(clGreen32, 255));
  PolygonH1.DrawEdge(ImgView.Bitmap, SetAlpha(clMaroon32, 255));
  PolygonV1.DrawEdge(ImgView.Bitmap, SetAlpha(clRed32, 255));
  PolygonH2.Antialiased := false; {Antialiase.Checked; }
  PolygonV2.Antialiased := false; {Antialiase.Checked; }
  PolygonH2.DrawFill(ImgView.Bitmap, SetAlpha(clGreen32, 255));
  PolygonV2.DrawFill(ImgView.Bitmap, SetAlpha(clGreen32, 255));
  PolygonH2.DrawEdge(ImgView.Bitmap, SetAlpha(clNavy32, 255));
  PolygonV2.DrawEdge(ImgView.Bitmap, SetAlpha(clBlue32, 255));

  PolygonD.Antialiased := false; {Antialiase.Checked; }
  PolygonD.DrawEdge(ImgView.Bitmap, SetAlpha(clGreen32, 255));

  ImgView.Bitmap.EndUpdate;
  ImgView.Bitmap.Changed;
  ImgView.Refresh; // force repaint
end;
{************************************************************}
{Procédure réagissant aux changements de spectre             }
{INPUT: Sender                                               }
{OUTPUT:un nouveau spectre apparait                          }
{REM: Origine Graph2D oldversion amélioré                    }
procedure Tgraph2DForm.choixspectreChange(Sender: TObject);
var
  vind:integer;
begin
  vind:=deuxd.indexof(choixspectre.text);
  if vind>=1 then
  begin
    AutoScale(deuxd.spect[vind]);
    GenSampleData(choixspectre.text);
    PaintData;
    CursorsReplot;
  end;
end;
                    // LE MENU //
{************************************************************}
{Procédure réagissant clic sur nouveau                       }
{INPUT: Sender                                               }
{OUTPUT:ouvre un nouveau spectre                             }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.Nouveau1Click(Sender: TObject);
{ var
  i:integer; }
begin
{ Il n'y a pas de raison de creer un spectre vide: ils sont cree par ouverture de fichier ou par des operations....
enterdlg.editeur.text:='';
  enterdlg.editeur.maxlength:=15;
  if enterdlg.showmodal=mrOK then
    if enterdlg.editeur.text<>'' then begin
      deuxd.addspectre(enterdlg.editeur.text,tax,tay,1);
      i:=choixspectre.items.add(enterdlg.editeur.text);
      choixspectre.itemindex:=i;
      choixspectrechange(sender);
    end; }
end;
{************************************************************}
{Procédure réagissant clic sur supprimer2D                     }
{INPUT: Sender                                               }
{OUTPUT:ouvre le spectre 1                            }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.Supprimer2DClick(Sender: TObject);
var i,vind:integer;
begin
  vind:=deuxd.indexof(choixSpectre.text);
  if vind>0 then deuxd.deletespectre(vind);
  choixspectre.items.delete(choixSpectre.itemindex);
  i:=NmaxSpectres2D;while deuxd.spect[i]=nil do dec(i);
  choixspectre.text:=deuxd.spect[i].nom;
  choixspectreChange(Sender);
end;
{************************************************************}
{Procédure réagissant clic sur supprimer3D                     }
{INPUT: Sender                                               }
{OUTPUT:ouvre le spectre en cours                            }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.Supprimer3DClick(Sender: TObject);
var i,vind:integer;
begin
vind:=troisd.indexof(choixSpectre3D.text);
if vind>0 then troisd.deletespectre(vind);
choixspectre3D.items.delete(choixSpectre3D.itemindex);
i:=1;while troisd.spect[i]=nil do inc(i);
choixspectre3D.text:=troisd.spect[i].nom;
choixspectre3DChange(Sender);
end;
{************************************************************}
{Procédure réagissant clic sur sauver le spectre 2D en cours à l'aide de la Nouvelle procedure de sauvegarde            }
{INPUT: Sender                                               }
{OUTPUT:sauve le spectre 2D en cours                            }
procedure Tgraph2DForm.save2DClick(Sender: TObject);
var vind:integer;
begin
 vind:=deuxd.indexof(choixSPectre.text);
 if vind>0 then
 begin
{ savedialog1.initialDir:=boitnoir.RepertoireManip.text; }
 savedialog1.defaultext:='*.2D';
 savedialog1.filter:='*.2D|*.2D';
 savedialog1.filename:=choixSPectre.text;
 if savedialog1.execute then
    deuxd.spect[vind].save(savedialog1.filename);
 end;
end;
{************************************************************}
{Procédure réagissant clic sur sauver le spectre 3D en cours à l'aide de la Nouvelle procedure de sauvegarde             }
{INPUT: Sender                                               }
{OUTPUT:sauve le spectre 3D en cours                            }
procedure Tgraph2DForm.save3DClick(Sender: TObject);
var vind:integer;
begin
 vind:=troisd.indexof(choixSPectre3D.text);
 if vind>0 then
 begin
{ savedialog1.initialDir:=boitnoir.RepertoireManip.text; }
 savedialog1.defaultext:='3D';
 if savedialog1.execute then
    troisd.spect[vind].save(savedialog1.filename);
 end;
end;
{************************************************************}
{Procédure réagissant clic sur sauver un spectre             }
{INPUT: Sender                                               }
{OUTPUT:sauve le spectre en cours                            }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.sauvegarderClick(Sender: TObject);
var vind:integer;
begin
 vind:=deuxd.indexof(choixSPectre.text);
 savedialog1.initialDir:=boitnoir.RepertoireManip.text;
 if savedialog1.execute then
    deuxd.spect[vind].savetofile(savedialog1.filename);
end;

{ ouverture d'un fichier .2D }
{ INPUT : le nom complet du fichier incluant le chemin }
procedure Tgraph2DForm.openFile(fileName:string);
var vind,l:integer;
    nom,ext:string;
begin
   {extraction de l'extension}
   nom:=ProcessFileName(filename);
   ext:=GetExtension(filename);
   if ext[2]='2' then
      begin {le spectre est un spectre 2D}
      vind:=deuxd.indexof(nom);
      if vind=-1 then vind:=deuxd.addspectre(nom,1,1,1); {creation avec taille arbitraire, le spectre prendra ensuite la taille du fichier}
      deuxd.spect[vind].open(filename);
      MiseAjourChoixSpectre(deuxd);
      choixspectre.Text:=nom;
      AutoScale(deuxd.spect[vind]);
      GenSampleData(choixspectre.text);
      PaintData;
      CursorsReplot;
      end;
   if ext[2]='3' then
      begin  {le spectre est un spectre 3D}
      vind:=troisd.indexof(nom);
      if vind=-1 then vind:=troisd.addspectre(nom,1,1,1);{creation avec taille arbitraire, le spectre prendra ensuite la taille du fichier}
      troisd.spect[vind].open(filename);
      {manque mise a jour et redessiner}
      end;
   paintdata;
end;

procedure Tgraph2DForm.openFileNexus(fileName:string);
var vind,l:integer;
    nom,ext:string;
begin
   nom:=ProcessFileName(filename);
   vind:=deuxd.indexof(nom);
   if vind=-1 then vind:=deuxd.addspectre(nom,1,1,1); {creation avec taille arbitraire, le spectre prendra ensuite la taille du fichier}
   deuxd.spect[vind].ReadFromNexus(filename);
   MiseAjourChoixSpectre(deuxd);
   choixspectre.Text:=nom;
   GenSampleData(nom);
   AutoScale(deuxd.spect[vind]);
   paintdata;
   CursorsReplot;
end;

procedure Tgraph2DForm.openFileNexusLLB(fileName:string);
var vind,l:integer;
    nom,ext:string;
begin
   nom:=ProcessFileName(filename);
   vind:=deuxd.indexof(nom);
   if vind=-1 then vind:=deuxd.addspectre(nom,1,1,1); {creation avec taille arbitraire, le spectre prendra ensuite la taille du fichier}
   deuxd.spect[vind].ReadFromNexusLLB(filename);
   MiseAjourChoixSpectre(deuxd);
   choixspectre.Text:=nom;
   GenSampleData(nom);
   AutoScale(deuxd.spect[vind]);
   paintdata;
   CursorsReplot;
end;


procedure Tgraph2DForm.openFilePAXY(fileName:string);
var titre,date,heure,temps,ext,nomspectre,nom:string;
    vind,l:integer;
begin
   {extraction de l'extension}
   nomSpectre:=ProcessFileName(filename);
   vind:=deuxd.indexof(nomspectre);
   if vind=-1 then vind:=deuxd.addspectre(nomspectre,128,128,1);
   deuxd.spect[vind].readfromPAXY(filename,titre,nom,date,heure,temps);
   MiseAjourChoixSpectre(deuxd);
   choixspectre.Text:=nomspectre;
   GenSampleData(nomspectre);
   paintdata;
   CursorsReplot;
end;

{************************************************************}
{Procédure réagissant clic sur lire un spectre 2D ou 3D avec la nouvelle procedure de sauvegarde              }
{le spectre prend automatiquement le nom+ext du fichier ouvert}
{si l'extension commence par 2 le spectre est stocke dans la liste deuxd, et si elle commence par 3 : dans troisd }
{INPUT: Sender                                               }
{OUTPUT:ouvre un spectre enregistré de type *.raw, *.spe     }

procedure Tgraph2DForm.openClick(Sender: TObject);
var vind,l:integer;
    nom,ext:string;
begin
{  opendialog1.initialDir:=boitnoir.RepertoireManip.text; }
  opendialog1.defaultExt:='*.2D*|*.3D*';
  opendialog1.filter:='Fichiers 2D (*.2Du, *.2Dd)|*.2D*';
  if opendialog1.execute then
      begin
      openFile(opendialog1.filename);
      end;
end;
{************************************************************}
{Procédure réagissant clic sur lire un spectre               }
{INPUT: Sender                                               }
{OUTPUT:ouvre un spectre enregistré de type *.raw, *.spe     }
{REM: Origine Graph2D oldversion adaptée                     }
procedure Tgraph2DForm.openspectreClick(Sender: TObject);
var vind:integer;
begin
vind:=deuxd.indexof(choixSPectre.text);
opendialog1.initialDir:=boitnoir.RepertoireManip.text;
if opendialog1.execute then begin
deuxd.spect[vind].readfromfile(opendialog1.filename);
GenSampleData(choixspectre.text);
paintdata;
end;
end;
{************************************************************}
{Procédure réagissant clic sur fermer                        }
{INPUT: Sender                                               }
{OUTPUT:ferme la fenêtre Graph2D                             }
{REM: Origine Graph2D oldversion                             }
{procedure Tgraph2DForm.fermer1Click(Sender: TObject);
begin
  release;
end; }
{************************************************************}
{Procédure réagissant clic sur effacer                       }
{INPUT: Sender                                               }
{OUTPUT:efface le spectre en cours                           }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.Effacer1Click(Sender: TObject);
var vind:integer;
begin
  vind:=deuxd.indexof(choixspectre.text);
  deuxd.spect[vind].clear;
end;
{************************************************************}
{Procédure qui cree une fenetre dialogaddform pour l'addition}
{INPUT: Sender                                               }
{OUTPUT:une fenetre dialogaddform pour l'addition est créée  }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.AdditionClick(Sender: TObject);
begin
{Application.CreateForm(Tdialogaddform, dialogaddform); }
  dialogaddform.windowState:=wsnormal;
  dialogaddform.operation.text:='+';
end;
{************************************************************}
{Procédure qui cree une fenetre dialogaddform pour la soustraction}
{INPUT: Sender                                               }
{OUTPUT:une fenetre dialogaddform pour la soustraction est créée}
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.Soustraction1Click(Sender: TObject);
begin
{Application.CreateForm(Tdialogaddform, dialogaddform); }
  dialogaddform.windowState:=wsnormal;
dialogaddform.operation.text:='-';
end;
{************************************************************}
{Procédure qui cree une fenetre dialogaddform pour la soustraction}
{INPUT: Sender                                               }
{OUTPUT:une fenetre dialogaddform pour la multiplication est créée}
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.MultiplicationClick(Sender: TObject);
begin
{Application.CreateForm(Tdialogaddform, dialogaddform); }
  dialogaddform.windowState:=wsnormal;
dialogaddform.operation.text:='*';
end;
{************************************************************}
{Procédure qui cree une fenetre dialogaddform pour la soustraction}
{INPUT: Sender                                               }
{OUTPUT:une fenetre dialogaddform pour la division est créée}
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.DivisionClick(Sender: TObject);
begin
{Application.CreateForm(Tdialogaddform, dialogaddform); }
  dialogaddform.windowState:=wsnormal;
dialogaddform.operation.text:='/';
end;
{************************************************************}
{Procédure qui divise le spectre en cours par moniteur.text
           et mise du moniteur a 1                           }
{INPUT: Sender                                               }
{OUTPUT:le spectre est divisé par le moniteur                }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.surmoniteurClick(Sender: TObject);
var i,j:integer;
    vind:integer;
begin
vind:=deuxd.indexof(ChoixSpectre.text);
for i:=0 to 127 do
    for j:=0 to 127 do
    deuxd.spect[vind].data[i,j,0].Z:=deuxd.spect[vind].data[i,j,0].Z/strtofloat(moniteur.text);

deuxd.spect[vind].moniteur:=1;
end;

{************************************************************}
{Procédure qui sauvegarde le spectre en cours au format PAXY }
{INPUT: Sender                                               }
{OUTPUT:le spectre est sauvé sous le format PAXY             }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.SavetoPAXY1Click(Sender: TObject);
var vind:integer;
begin
   vind:=deuxd.indexof(choixSpectre.text);
   savedialog1.initialDir:=boitnoir.RepertoireManip.text;
   savedialog1.defaultExt:='*.dat';
   savedialog1.filter:='*.dat|*.dat';
   if savedialog1.execute then
     deuxd.spect[vind].savetoPAXYfree(savedialog1.filename);
end;

{************************************************************}
{Procédure qui lit un spectre au format PAXY                 }
{INPUT: Sender                                               }
{OUTPUT:le spectre est lu au format PAXY                     }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.ReadfromPAXY1Click(Sender: TObject);
var titre,date,heure,temps,ext,nomspectre,nom:string;
    vind,l:integer;
begin
opendialog1.initialDir:=boitnoir.RepertoireManip.text;
opendialog1.defaultExt:='*.dat';
opendialog1.filter:='*.dat|*.dat';
if opendialog1.execute then
   begin
   {extraction de l'extension}
   nomSpectre:=ProcessFileName(opendialog1.filename);
   vind:=deuxd.indexof(nomspectre);
   if vind=-1 then vind:=deuxd.addspectre(nomspectre,128,128,1);
   deuxd.spect[vind].readfromPAXY(opendialog1.filename,titre,nom,date,heure,temps);
   MiseAjourChoixSpectre(deuxd);
   choixspectre.Text:=nomspectre;
   GenSampleData(nomspectre);
   paintdata;
   CursorsReplot;
   end;

end;

{************************************************************}
{Procedure de lecture des anciens fichiers format texte      }
{INPUT: Sender                                               }
{OUTPUT:le spectre est lu au format texte                    }
{REM: Origine Graph2D oldversion, je ne sais pas si ça
      marche encore                                          }
procedure Tgraph2DForm.readW31Click(Sender: TObject);
var i,j,len,k:integer;
    f: textfile;
    temp,data:string;

begin
opendialog1.initialdir:='a:\';
if opendialog1.execute then
   begin
   assignfile(f,opendialog1.filename);
   reset(f);
   for i:=0 to 127 do
       for j:=0 to 127 do
           begin
           if (i<>127) or (j<>127) then
           begin
           readln(f,temp);
           len:=length(temp);
           k:=0;
           repeat
           k:=k+1;
           until temp[k]=#9;
           repeat
           k:=k+1;
           until temp[k]<>' ';
           data:='';
           repeat
           data:=data+temp[k];
           k:=k+1;
           until temp[k]=#9;
           deuxd.spect[1].data[j,i,0].Z:=strtofloat(data);
           repeat
           k:=k+1;
           until temp[k]<>' ';
           data:='';
           repeat
           data:=data+temp[k];
           k:=k+1;
           until k=len+1;
           deuxd.spect[2].data[j,i,0].Z:=strtofloat(data);
           end
           else
           begin
           deuxd.spect[1].data[i,j,0].Z:=0;
           deuxd.spect[2].data[i,j,0].Z:=0;
           end;
           end;

   closefile(f);
   end;
end;
                       //FIN DU MENU//

{************************************************************}
{Procedure de changement de palette                          }
{INPUT: Sender                                               }
{OUTPUT:la couleur du spectre à changé                       }
{REM: Origine Graph2D oldversion adaptées                    }
procedure Tgraph2DForm.palettecomboChange(Sender: TObject);
begin
  color:=palettecombo.itemindex;
  paintdata;
end;
{************************************************************}
{Procedure pour mettre à jour les champs des courbes a afficher}
{INPUT: rien                                                 }
{OUTPUT: les coubes sont affiché selon ce qu'il ya dans
         TypeGraphCombo                                      }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.UpdateCourbesAafficher;
begin
{  if (typeGraphCombo.text='Horizontales')
  then begin
       xyCoupe[CoupeHorz1].active:=true;
       xyCoupe[CoupeHorz2].active:=true;
       xyCoupe[CoupeVert1].active:=false;
       xyCoupe[CoupeVert2].active:=false;
       xyCoupe[CoupeDiagX].active:=false;
       xyCoupe[CoupeDiagY].active:=false;
       end;
  if (typeGraphCombo.text='Curseur 1')
  then begin
       xyCoupe[CoupeHorz1].active:=true;
       xyCoupe[CoupeHorz2].active:=false;
       xyCoupe[CoupeVert1].active:=true;
       xyCoupe[CoupeVert2].active:=false;
       xyCoupe[CoupeDiagX].active:=false;
       xyCoupe[CoupeDiagY].active:=false;
       end;
  if (typeGraphCombo.text='Verticales')
  then begin
       xyCoupe[CoupeHorz1].active:=false;
       xyCoupe[CoupeHorz2].active:=false;
       xyCoupe[CoupeVert1].active:=true;
       xyCoupe[CoupeVert2].active:=true;
       xyCoupe[CoupeDiagX].active:=false;
       xyCoupe[CoupeDiagY].active:=false;
       end;
  if (typeGraphCombo.text='Curseur 2')
  then begin
       xyCoupe[CoupeHorz1].active:=false;
       xyCoupe[CoupeHorz2].active:=true;
       xyCoupe[CoupeVert1].active:=false;
       xyCoupe[CoupeVert2].active:=true;
       xyCoupe[CoupeDiagX].active:=false;
       xyCoupe[CoupeDiagY].active:=false;
       end;
  if (typeGraphCombo.text='DiagonaleX')
  then begin
       xyCoupe[CoupeHorz1].active:=false;
       xyCoupe[CoupeHorz2].active:=false;
       xyCoupe[CoupeVert1].active:=false;
       xyCoupe[CoupeVert2].active:=false;
       xyCoupe[CoupeDiagX].active:=true;
       xyCoupe[CoupeDiagY].active:=false;
       end;
  if (typeGraphCombo.text='DiagonaleY')
  then begin
       xyCoupe[CoupeHorz1].active:=false;
       xyCoupe[CoupeHorz2].active:=false;
       xyCoupe[CoupeVert1].active:=false;
       xyCoupe[CoupeVert2].active:=false;
       xyCoupe[CoupeDiagX].active:=false;
       xyCoupe[CoupeDiagY].active:=true;
       end; }
end;
{************************************************************}
{Procedure de modification du combo: TypeGraphCombo          }
{INPUT: Sender                                               }
{OUTPUT: les coubes sont affiché selon ce qu'il ya dans
         TypeGraphCombo                                      }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.TypeGraphComboChange(Sender: TObject);
begin
  UpdateCourbesAafficher;
end;
{************************************************************}
{Procedure de lissage de l'image                             }
{INPUT: Sender                                               }
{OUTPUT: le spectre est lissé                                }
{REM: Origine Surface2D                                      }
procedure Tgraph2DForm.ImageInterpolateClick(Sender: TObject);
const
  STRETCH_FILTER: array [Boolean] of TStretchFilter = (sfNearest, sfLinear);
begin
  ImgView.Bitmap.StretchFilter := STRETCH_FILTER[ImageInterpolate.Checked];
  ImgView32Dst.Bitmap.StretchFilter := STRETCH_FILTER[ImageInterpolate.Checked];
end;
{************************************************************}
{Procedure qui défini le centre pour un coupe circulaire     }
{INPUT: Sender                                               }
{OUTPUT: le sectre circulaire est initialisé avec la nouvelle}
{        valeur de Xcen et Ycen                              }
{REM: Procédure définis dans editdata                        }
procedure Tgraph2DForm.YcenExit(Sender: TObject);
begin
 unD.add(deuxd.spect[deuxd.indexof(choixspectre.text)].SommeCirculaireSpectre2D('SC',Round(Xcen.value),Round(Ycen.value),binningStepBox.value));
 sendmessage(principalform.handle,wm_redessine,0,0);
end;

procedure Tgraph2DForm.XcenExit(Sender: TObject);
begin
 unD.add(deuxd.spect[deuxd.indexof(choixspectre.text)].SommeCirculaireSpectre2D('SC',Round(Xcen.value),Round(Ycen.value),binningStepBox.value));
 sendmessage(principalform.handle,wm_redessine,0,0);
end;

procedure Tgraph2DForm.BinningStepBoxChange(Sender: TObject);
begin
 unD.add(deuxd.spect[deuxd.indexof(choixspectre.text)].SommeCirculaireSpectre2D('SC',Round(Xcen.value),Round(Ycen.value),binningStepBox.value));
 sendmessage(principalform.handle,wm_redessine,0,0);
end;


{ ============================================================================ }
{ AJOUTS SPECIFIQUES AUX GRAPH3D                                               }
{ ============================================================================ }

{ lecture d'un fichier 4 colonnes (EROS)                                       }
{ INPUT : fichier 4 colonnes X,Y,lambda, intensité                             }
{ OUTPUT : on le stocke                                                        }
{ REM : pour le moement on utilise une structure 3D spécifique                 }
{ a terme cette structure doit etre intégrée à spectre                         }
{ NB : il faut réféchier au problème du zonage                                 }
procedure Tgraph2DForm.Lecturefichier4colonnes1Click(Sender: TObject);
var
  i,j,k,n,errorcode:integer;
  indiceValeur:integer; { indice de la valeur dans la ligne de texte }
  F: TextFile;
  S,S1: string[255];
  aux:double;
  valeurs:valuesVector; { valeurs numériques lues sur la ligne }
  finChaine:boolean;
  X,Y,LT:integer;
  comment:string;
  vind:integer;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
    AssignFile(F, OpenDialog1.FileName);{ Fichier sélectionné dans la boîte de dialogue }
    Reset(F);
    { lecture de l'entete }
    readln(F,comment);
    { lecture des tailles X,Y,LT }
    readln(F,s);
    X:=strToInt(s);
    readln(F,s);
    Y:=strToInt(s);
    readln(F,s);
    LT:=strToInt(s);
    { il faut redimensionner le spectre 3D et réallouer la memoire }
    vind:=troisd.addspectre('data3D',X,Y,LT); { addspectre detruit automatiquement le spectre s'il existait deja }
    troisd.spect[vind].ExpCondNbr:=0;
    troisd.spect[vind].comment:=comment;
    for i:=0 to X-1 do
    for j:=0 to Y-1 do
    for k:=0 to LT-1 do
    begin
        Readln(F, S);    { Lecture de la première ligne du fichier }
        { traitement de la chaine pour en extraire les nombres }
        valeurs:=ProcessString(s);
        troisd.spect[vind].data[i,j,k].x:=Valeurs[1];
        troisd.spect[vind].data[i,j,k].y:=Valeurs[2];
        troisd.spect[vind].data[i,j,k].lt:=Valeurs[3];
        troisd.spect[vind].data[i,j,k].z:=Valeurs[4];
    end;
    CloseFile(F);
    troisd.spect[vind].ExpCondNbr:=0;
  end;
end;



{ calcul de la coupe et stockage dans le spectre courant (validé dans la combo box) }
{ pour les coupes sans intégration on peut grandement accélerer le processus        }
{ inventer un truc pour les coupes sans intégration                                 }
{ INPUT : implicite : le spectre 3D et les bornes de l'intégration                  }
{ OUTPUT : le résultat de la projection est stocké dans le graph en cours           }
{          sélectionné dans la combBox                                              }
procedure Tgraph2DForm.ReplotButtonClick(Sender: TObject);
var  i,j,k:integer;
     indexSpectre:integer; { index du spectre courant }
     idxSpect3D:integer;  { spectre 3D sélectionnée dans la combo }
     min,max:real;
     spect2Dname:string;
     X,Y,LT:integer;
     xMinP,xMaxP,yMinP,yMaxP,ltMinP,ltMaxP:double; { variables locales pour les intervalles de projection }
begin
  xMinP:=xMinProj.value;xMaxP:=xMaxProj.value;
  yMinP:=yMinProj.value;yMaxP:=yMaxProj.value;
  ltMinP:=ltMinProj.value;ltMaxP:=ltMaxProj.value;
  idxSpect3D:=troisd.indexof(choixspectre3D.text);
if idxSpect3D>0 then
  begin
  X:=troisd.spect[idxSpect3D].X;
  Y:=troisd.spect[idxSpect3D].Y;
  LT:=troisd.spect[idxSpect3D].LT;
  end;
{ on va stocker la projection dans le spectre sélectionné dans la combo }
  spect2Dname:=choixspectre.text;
  indexSpectre:=deuxd.indexof(spect2Dname);
{ ACHTUNG :on ne peut redimensionner un spectre  sans réallouer la meoire !!!! **** }
if (indexSpectre>0) and (idxSpect3D>0) then
begin
{ ***** projection correspondant aux radiobuttons ***** }
{ c'est pas écrit de manière très élégante              }
{ projection suivant une gamme en lambda  X en abscisse Y en ordonnée }
If (XProjection.itemIndex=0) and (YProjection.itemIndex=1)
then begin
     deuxd.addspectre(spect2Dname,X,Y,1);
     for i:=0 to X-1 do
     for j:=0 to Y-1 do
       begin
       deuxd.spect[indexSpectre].data[i,j,0].x:=troisd.spect[idxSpect3D].data[i,j,0].x;
       deuxd.spect[indexSpectre].data[i,j,0].y:=troisd.spect[idxSpect3D].data[i,j,0].y;
       deuxd.spect[indexSpectre].data[i,j,0].z:=0;
       for k:=0 to LT-1 do
           if (troisd.spect[idxSpect3D].data[i,j,k].lt>=ltMinP) and (troisd.spect[idxSpect3D].data[i,j,k].lt<=ltMaxP)
           then deuxd.spect[indexSpectre].data[i,j,0].z:=deuxd.spect[indexSpectre].data[i,j,0].z+troisd.spect[idxSpect3D].data[i,j,k].z;
       end;
     end;
{ projection suivant une gamme en Y,  X en abscisse LT en ordonnée }
If (XProjection.itemIndex=0) and (YProjection.itemIndex=2)
then begin
     deuxd.addspectre(spect2Dname,X,LT,1);
     for i:=0 to X-1 do
     for j:=0 to LT-1 do
       begin
       deuxd.spect[indexSpectre].data[i,j,0].x:=troisd.spect[idxSpect3D].data[i,0,j].x;
       deuxd.spect[indexSpectre].data[i,j,0].y:=troisd.spect[idxSpect3D].data[i,0,j].lt;
       deuxd.spect[indexSpectre].data[i,j,0].z:=0;
       for k:=0 to Y-1 do
           if (troisd.spect[idxSpect3D].data[i,k,j].y>=yMinP) and (troisd.spect[idxSpect3D].data[i,k,j].y<=yMaxP)
           then deuxd.spect[indexSpectre].data[i,j,0].z:=deuxd.spect[indexSpectre].data[i,j,0].z+troisd.spect[idxSpect3D].data[i,k,j].z;
       end;
     end;
{ projection suivant une gamme en lambda  Y en abscisse X en ordonnée }
If (XProjection.itemIndex=1) and (YProjection.itemIndex=0)
then begin
     deuxd.addspectre(spect2Dname,Y,X,1);
     for i:=0 to Y-1 do
     for j:=0 to X-1 do
       begin
       deuxd.spect[indexSpectre].data[i,j,0].x:=troisd.spect[idxSpect3D].data[j,i,0].y;
       deuxd.spect[indexSpectre].data[i,j,0].y:=troisd.spect[idxSpect3D].data[j,i,0].x;
       deuxd.spect[indexSpectre].data[i,j,0].z:=0;
       for k:=0 to LT-1 do
           if (troisd.spect[idxSpect3D].data[j,i,k].lt>=ltMinP) and (troisd.spect[idxSpect3D].data[j,i,k].lt<=ltMaxP)
           then deuxd.spect[indexSpectre].data[i,j,0].z:=deuxd.spect[indexSpectre].data[i,j,0].z+troisd.spect[idxSpect3D].data[j,i,k].z;
       end;
     end;
{ projection suivant X avec Y en abscisse et lambda en ordonnée }
If (XProjection.itemIndex=1) and (YProjection.itemIndex=2)
then begin
     deuxd.addspectre(spect2Dname,Y,LT,1);
     for i:=0 to Y-1 do
     for j:=0 to LT-1 do
       begin
       deuxd.spect[indexSpectre].data[i,j,0].x:=troisd.spect[idxSpect3D].data[0,i,j].y;
       deuxd.spect[indexSpectre].data[i,j,0].y:=troisd.spect[idxSpect3D].data[0,i,j].lt;
       deuxd.spect[indexSpectre].data[i,j,0].z:=0;
       for k:=0 to X-1 do
           if (troisd.spect[idxSpect3D].data[k,i,j].x>=xMinP) and (troisd.spect[idxSpect3D].data[k,i,j].x<=xMaxP)
           then deuxd.spect[indexSpectre].data[i,j,0].z:=deuxd.spect[indexSpectre].data[i,j,0].z+troisd.spect[idxSpect3D].data[k,i,j].z;
       end;
     end;
{ projection suivant Y avec lambda  en abscisse X en ordonnée }
If (XProjection.itemIndex=2) and (YProjection.itemIndex=0)
then begin
     deuxd.addspectre(spect2Dname,LT,X,1);
     for i:=0 to LT-1 do
     for j:=0 to X-1 do
       begin
       deuxd.spect[indexSpectre].data[i,j,0].x:=troisd.spect[idxSpect3D].data[j,0,i].lt;
       deuxd.spect[indexSpectre].data[i,j,0].y:=troisd.spect[idxSpect3D].data[j,0,i].x;
       deuxd.spect[indexSpectre].data[i,j,0].z:=0;
       for k:=0 to Y-1 do
           if (troisd.spect[idxSpect3D].data[j,k,i].y>=yMinP) and (troisd.spect[idxSpect3D].data[j,k,i].y<=yMaxP)
           then deuxd.spect[indexSpectre].data[i,j,0].z:=deuxd.spect[indexSpectre].data[i,j,0].z+troisd.spect[idxSpect3D].data[j,k,i].z;
       end;
     end;
{ projection suivant X avec lambda  en abscisse Y en ordonnée }
If (XProjection.itemIndex=2) and (YProjection.itemIndex=1)
then begin
     deuxd.addspectre(spect2Dname,LT,Y,1);
     for i:=0 to LT-1 do
     for j:=0 to Y-1 do
       begin
       deuxd.spect[indexSpectre].data[i,j,0].x:=troisd.spect[idxSpect3D].data[0,j,i].lt;
       deuxd.spect[indexSpectre].data[i,j,0].y:=troisd.spect[idxSpect3D].data[0,j,i].y;
       deuxd.spect[indexSpectre].data[i,j,0].z:=0;
       for k:=0 to X-1 do
           if (troisd.spect[idxSpect3D].data[k,j,i].x>=xMinP) and (troisd.spect[idxSpect3D].data[k,j,i].x<=xMaxP)
           then deuxd.spect[indexSpectre].data[i,j,0].z:=deuxd.spect[indexSpectre].data[i,j,0].z+troisd.spect[idxSpect3D].data[k,j,i].z;
       end;
     end;

{ réaffichage du spectre de la projection }
{  indexSpectre:=deuxd.indexof(choixspectre.text); }
    deuxd.spect[indexSpectre].moniteur:=troisd.spect[idxSpect3D].moniteur; {initialisation du moniteur à la valeur globale du spectre 3D}
    AutoScale(deuxd.spect[indexSpectre]);
    genSampleData(spect2Dname);
    paintData;
end;

end;

{ réaffichage du spectre trois3D quand la sélection de la comboBox change }
procedure Tgraph2DForm.ChoixSpectre3DChange(Sender: TObject);
var
  vind:integer;
begin
  vind:=troisd.indexof(choixspectre3D.text);
  if vind>=1 then
  begin
    SliceNumber.maxvalue:=troisd.spect[vind].LT;
    AutoScale(troisd.spect[vind]);
    ReplotButtonClick(ChoixSpectre3D);
{    GenSampleData(taX,taY);
    paintData; }
  end;
end;

{ on fait defiler les tranches successives }
procedure Tgraph2DForm.SliceNumberChange(Sender: TObject);
var snbr:integer; { slice number }
    X,Y,LT:integer;
    idxSpect3D:integer;
    spect2Dname:string;
begin
  snbr:=SliceNumber.value-1; { physiquement le stockage des data commence a l'indice 0 }
                             { en pratique, on indice les cellules a partir de 1     }
  idxSpect3D:=troisd.indexof(choixspectre3D.text);
if idxSpect3D>0 then
begin
  X:=troisd.spect[idxSpect3D].X;
  Y:=troisd.spect[idxSpect3D].Y;
  LT:=troisd.spect[idxSpect3D].LT;
{initialisation de l'echelle ltminproj}
if snbr>0 then
 ltminproj.value:=troisd.spect[idxSpect3D].data[0,0,snbr-1].lt+0.01
else
 ltminproj.value:=0;
{initialisation de l'echelle ltmaxproj}
ltmaxproj.value:=troisd.spect[idxSpect3D].data[0,0,snbr].lt;


ReplotButtonClick(SliceNumber);
end;

{ on va stocker la projection dans le spectre sélectionné dans la combo }
{#  spect2Dname:=choixspectre.text;
  indexSpectre:=deuxd.indexof(spect2Dname);

{#if (indexSpectre>=1) and (snbr>=0) then
begin
{ ***** projection correspondant aux radiobuttons ***** }
{ c'est pas écrit de manière très élégante              }
{ projection suivant une gamme en lambda  X en abscisse Y en ordonnée }
{#If (XProjection.itemIndex=0) and (YProjection.itemIndex=1) and (snbr<LT)
then begin
     deuxd.addspectre(spect2Dname,X,Y,1);
     for i:=0 to X-1 do
     for j:=0 to Y-1 do
       deuxd.spect[indexSpectre].data[i,j,0].z:=troisd.spect[idxSpect3D].data[i,j,snbr].z;
     end;
{ projection suivant une gamme en Y:  X en abscisse lambda en ordonnée }
{#If (XProjection.itemIndex=0) and (YProjection.itemIndex=2) and (snbr<Y)
then begin
     deuxd.addspectre(spect2Dname,X,LT,1);
     for i:=0 to X-1 do
     for j:=0 to LT-1 do
       deuxd.spect[indexSpectre].data[i,j,0].z:=troisd.spect[idxSpect3D].data[i,snbr,j].z;
     end;
{ projection suivant une gamme en lambda  Y en abscisse X en ordonnée }
{#If (XProjection.itemIndex=1) and (YProjection.itemIndex=0) and (snbr<LT)
then begin
     deuxd.addspectre(spect2Dname,Y,X,1);
     for i:=0 to Y-1 do
     for j:=0 to X-1 do
       deuxd.spect[indexSpectre].data[i,j,0].z:=troisd.spect[idxSpect3D].data[j,i,snbr].z;
     end;
{ projection suivant X avec Y en abscisse et lambda en ordonnée }
{#If (XProjection.itemIndex=1) and (YProjection.itemIndex=2) and (snbr<X)
then begin
     deuxd.addspectre(spect2Dname,Y,LT,1);
     for i:=0 to Y-1 do
     for j:=0 to LT-1 do
       deuxd.spect[indexSpectre].data[i,j,0].z:=troisd.spect[idxSpect3D].data[snbr,i,j].z;
     end;
{ projection suivant X avec lambda  en abscisse Y en ordonnée }
{#If (XProjection.itemIndex=2) and (YProjection.itemIndex=1) and (snbr<X)
then begin
     deuxd.addspectre(spect2Dname,LT,Y,1);
     for i:=0 to LT-1 do
     for j:=0 to Y-1 do
       deuxd.spect[indexSpectre].data[i,j,0].z:=troisd.spect[idxSpect3D].data[snbr,j,i].z;
     end;
{ projection suivant Y avec lambda  en abscisse X en ordonnée }
{#If (XProjection.itemIndex=2) and (YProjection.itemIndex=0) and (snbr<Y)
then begin
     deuxd.addspectre(spect2Dname,LT,X,1);
     for i:=0 to LT-1 do
     for j:=0 to X-1 do
       deuxd.spect[indexSpectre].data[i,j,0].z:=troisd.spect[idxSpect3D].data[j,snbr,i].z;
     end;

{ réaffichage du spectre de la projection }
{  indexSpectre:=deuxd.indexof(choixspectre.text); }
{#    AutoScale(deuxd.spect[indexSpectre]);
    GenSampleData(spect2Dname);
    paintData; 
end;            #}

end;


procedure Tgraph2DForm.Panel9Click(Sender: TObject);
begin
{     If ProjectionPanel.height>18
     then ProjectionPanel.height:=18
     else ProjectionPanel.height:=243; }
end;

{ projection du spectre 2D sur les direction horizontale et verticales }
procedure Tgraph2DForm.ProjectionButtonClick(Sender: TObject);
var vind:integer;
begin
  vind:=deuxd.indexof(choixSpectre.text);
  unD.add(deuxd.spect[vind].ProjectionVSpectre2D('PV',min(Xpos1.value,Xpos2.value),max(Xpos1.value,Xpos2.value)));
  unD.add(deuxd.spect[vind].ProjectionHSpectre2D('PH',min(Ypos1.value,Ypos2.value),max(Ypos1.value,Ypos2.value)));
end;


{ la gestion de snoms est catastrophique }
procedure Tgraph2DForm.LectureFichierHadasMenuClick(Sender: TObject);
var nom:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
       nom:=OpenDialog1.FileName;
       LectureFichierHADAS(nom);{ Fichier sélectionné dans la boîte de dialogue }
{       nom:=copy(nom,9,length(nom));
       choixspectre.items.add(nom);
       choixspectre.text:=nom;
       choixspectreChange(Sender); }
  end;
  MiseAJourChoixSpectre(deuxd);
end;

procedure Tgraph2DForm.PrintGraphClick(Sender: TObject);
begin
     graph2DForm.print;
end;

procedure Tgraph2DForm.PrintFormClick(Sender: TObject);
begin
     if PrintDialog1.execute then graph2DForm.print;
end;

{ appliation d'une transformation affine }
procedure Tgraph2DForm.ReScale(echx,echy,alpha: Single);
var
  SrcR: Integer;
  SrcB: Integer;
  T: TAffineTransformation;
  Sx, Sy, Scale: Single;
begin
  SrcR := ImgView.Bitmap.Width - 1;
  SrcB := ImgView.Bitmap.Height - 1;
  T := TAffineTransformation.Create;
  T.SrcRect := FloatRect(0, 0, SrcR + 1, SrcB + 1);
  try
    // shift the origin
    T.Clear;
    // move the origin to a center for scaling and rotation
    T.Translate(-SrcR / 2, -SrcB / 2);
    T.Rotate(0, 0, Alpha);
    Alpha := Alpha * pi / 180;
    // get the width and height of rotated image (without scaling)
    Sx := Abs(SrcR * Cos(Alpha)) + Abs(SrcB * Sin(Alpha));
    Sy := Abs(SrcR * Sin(Alpha)) + Abs(SrcB * Cos(Alpha));
    // calculate a new scale so that the image fits in original boundaries
    Sx := ImgView.Bitmap.Width / Sx;
    Sy := ImgView.Bitmap.Height / Sy;
    scale := Min(Sx, Sy);

    T.Scale(Scale*echX, Scale*echY);

    // move the origin back
    T.Translate(SrcR / 2, SrcB / 2);
    // transform the bitmap
    ImgView.BeginUpdate;
    ImgView.Bitmap.Clear(clGray32);
    Transform(ImgView.Bitmap, ImgView.Bitmap, T);
    ImgView.EndUpdate;
    ImgView.Repaint;
  finally
    T.Free;
  end;
end;


procedure Tgraph2DForm.ReScaleButtonClick(Sender: TObject);
begin
{   ReScale(1,1,scaleX.value); }
end;
//-------------------procédures de masques------------------

procedure Tgraph2DForm.TypeMaskComboChange(Sender: TObject);
begin
{ case TypeMaskCombo.Itemindex of
    0: ExpliLabel.caption:='Les curseurs représentent les coins du rectangle, les points intérieurs sont masqués';
    1: ExpliLabel.caption:='Les curseurs représentent les coins du rectangle, les points extérieurs sont masqués';
    2: ExpliLabel.caption:='Le curseur rouge représente le centre du cercle, le curseur bleu un point du cercle';
    3: ExpliLabel.caption:='Le curseur rouge représente le centre du cercle, le curseur bleu un point du cercle';
  end;  }
  case TypeMaskCombo.Itemindex of
{ rectangle }   0:begin paramLabel1.Caption:='Xmin';paramLabel2.Caption:='Ymin';paramLabel3.Caption:='Xmax';paramLabel4.Caption:='Ymax';paramLabel5.Caption:='';paramLabel6.Caption:=''; end;
{ rect. slit }  1:begin paramLabel1.Caption:='Xmin';paramLabel2.Caption:='Ymin';paramLabel3.Caption:='Xmax';paramLabel4.Caption:='Ymax';paramLabel5.Caption:='';paramLabel6.Caption:=''; end;
{ circle }      2:begin paramLabel1.Caption:='Xcenter';paramLabel2.Caption:='Ycenter';paramLabel3.Caption:='Radius';paramLabel4.Caption:='';paramLabel5.Caption:='';paramLabel6.Caption:=''; end;
{ circle hole } 3:begin paramLabel1.Caption:='Xcenter';paramLabel2.Caption:='Ycenter';paramLabel3.Caption:='Radius';paramLabel4.Caption:='';paramLabel5.Caption:='';paramLabel6.Caption:=''; end;
{ ring }        4:begin paramLabel1.Caption:='Xcenter';paramLabel2.Caption:='Ycenter';paramLabel3.Caption:='Rmin';paramLabel4.Caption:='Rmax';paramLabel5.Caption:='';paramLabel6.Caption:=''; end;
{ sector}       5:begin paramLabel1.Caption:='Xcenter';paramLabel2.Caption:='Ycenter';paramLabel3.Caption:='Ang. pos. (°)';paramLabel4.Caption:='Opening (°)';paramLabel5.Caption:='';paramLabel6.Caption:=''; end;
{ ring-sector}  6:begin paramLabel1.Caption:='Xcenter';paramLabel2.Caption:='Ycenter';paramLabel3.Caption:='Amin';paramLabel4.Caption:='Amax';paramLabel5.Caption:='Rmin';paramLabel6.Caption:='Rmax'; end;
  end;
end;

{************************
appelle des fonctions de masquage def dans editdata
INPUT  : le spectre en cours de choixspectre
OUTPUT : spectre NomMaskEdit = multiplication de la nouvelle forme avec le masque précédent
         spectre NomMaskEdit_Z =masque précédent}
procedure Tgraph2DForm.MaskButtonClick(Sender: TObject);

          procedure addMask(spect:spectre);
          {effectue la sauvegarde de l'etape precedente dans NomMaskEdit_Z (si le masque existe ),
           calcul le nouveau masque et le charge dans deuxd,
           efectue la multiplication avec l'etape precedente si elle existe}
          var indM:integer;
          begin
          indM:=deuxd.indexof(NomMaskEdit.text);
          if deuxd.indexof(NomMaskEdit.text+'_Z') <>-1 then
             deuxd.delete(NomMaskEdit.text+'_Z');
          if indM <>-1 then
             deuxd.spect[indM].nom:=deuxd.spect[indM].nom+'_Z';
          deuxd.add(spect);
          if deuxd.indexof(NomMaskEdit.text+'_Z') <>-1 then
             deuxd.Multiplication(NomMaskEdit.text+'_Z',NomMaskEdit.text,NomMaskEdit.text);
          end;

begin
 if  CheckBoxMasks.checked
 then begin
     { definition à partir des positons du curseur }
     if (TypeMaskCombo.text='rectangle')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueRectExt(Xpos1.value,Ypos1.value,Xpos2.value,Ypos2.value,NomMaskEdit.text));
     if (TypeMaskCombo.text='rectangle (slit)')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueRectInt(Xpos1.value,Ypos1.value,Xpos2.value,Ypos2.value,NomMaskEdit.text));
     if (TypeMaskCombo.text='circle')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueCircExt(Xpos1.value,Ypos1.value,Xpos2.value,Ypos2.value,NomMaskEdit.text));
     if (TypeMaskCombo.text='circle (hole)')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueCircInt(Xpos1.value,Ypos1.value,Xpos2.value,Ypos2.value,NomMaskEdit.text));
 end
 else begin
     { definition à partir des boites numériques }
     if (TypeMaskCombo.text='rectangle')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueRectExt(ParamBox1.value,ParamBox2.value,ParamBox3.value,ParamBox4.value,NomMaskEdit.text));
     if (TypeMaskCombo.text='rectangle (slit)')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueRectInt(ParamBox1.value,ParamBox2.value,ParamBox3.value,ParamBox4.value,NomMaskEdit.text));
     if (TypeMaskCombo.text='circle')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueCircExt(ParamBox1.value,ParamBox2.value,ParamBox1.value+ParamBox3.value,ParamBox2.value,NomMaskEdit.text));
     if (TypeMaskCombo.text='circle (hole)')
     then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueCircInt(ParamBox1.value,ParamBox2.value,ParamBox1.value+ParamBox3.value,ParamBox2.value,NomMaskEdit.text));
     if (TypeMaskCombo.text='ring')
     then begin
          addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueCircInt(ParamBox1.value,ParamBox2.value,ParamBox1.value+ParamBox3.value,ParamBox2.value,NomMaskEdit.text));
          addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueCircExt(ParamBox1.value,ParamBox2.value,ParamBox1.value+ParamBox4.value,ParamBox2.value,NomMaskEdit.text));
          deuxd.delete(NomMaskEdit.text+'_Z');
          end;
     if (TypeMaskCombo.text='sector')
     then begin
          if symmetryBox.itemindex=0
          then addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueSecteur(ParamBox1.value,ParamBox2.value,ParamBox3.value,ParamBox4.value,NomMaskEdit.text));
          if symmetryBox.itemindex=1
          then begin
               addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueSecteur(ParamBox1.value,ParamBox2.value,ParamBox3.value,ParamBox4.value,NomMaskEdit.text+'a'));
               addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueSecteur(ParamBox1.value,ParamBox2.value,ParamBox3.value+180,ParamBox4.value,NomMaskEdit.text+'b'));
               deuxd.addition(NomMaskEdit.text+'a',NomMaskEdit.text+'b',NomMaskEdit.text);
               deuxd.delete(NomMaskEdit.text+'a');deuxd.delete(NomMaskEdit.text+'b');
               end;
          if symmetryBox.itemindex=2
          then begin
               addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueSecteur(ParamBox1.value,ParamBox2.value,ParamBox3.value,ParamBox4.value,NomMaskEdit.text+'a'));
               addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueSecteur(ParamBox1.value,ParamBox2.value,ParamBox3.value+90,ParamBox4.value,NomMaskEdit.text+'b'));
               addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueSecteur(ParamBox1.value,ParamBox2.value,ParamBox3.value+180,ParamBox4.value,NomMaskEdit.text+'c'));
               addMask(deuxd.spect[deuxd.indexof(choixSpectre.text)].MasqueSecteur(ParamBox1.value,ParamBox2.value,ParamBox3.value+270,ParamBox4.value,NomMaskEdit.text+'d')); end;
               deuxd.addition(NomMaskEdit.text+'a',NomMaskEdit.text+'b',NomMaskEdit.text+'e');
               deuxd.addition(NomMaskEdit.text+'c',NomMaskEdit.text+'d',NomMaskEdit.text+'f');
               deuxd.addition(NomMaskEdit.text+'e',NomMaskEdit.text+'f',NomMaskEdit.text);
               deuxd.delete(NomMaskEdit.text+'a');deuxd.delete(NomMaskEdit.text+'b');deuxd.delete(NomMaskEdit.text+'c');deuxd.delete(NomMaskEdit.text+'d');deuxd.delete(NomMaskEdit.text+'e');deuxd.delete(NomMaskEdit.text+'f');
          end;
     if (TypeMaskCombo.text='ringed-sector')
     then ;
     end;

end;


procedure Tgraph2DForm.SaveToASCIIClick(Sender: TObject);
var vind:integer;
begin
   vind:=deuxd.indexof(choixSpectre.text);
   savedialog1.initialDir:=boitnoir.RepertoireManip.text;
   if savedialog1.execute then
     deuxd.spect[vind].saveToASCII_3col(savedialog1.filename);
end;


{mise à jour de choixspectre}
procedure Tgraph2DForm.choixspectreDropDown(Sender: TObject);
begin
if sender=choixspectre then
MiseAjourChoixSpectre(deuxd);
if sender=choixspectre3D then
MiseAjourChoixSpectre3D(troisd);
end;

procedure Tgraph2DForm.ColorScaleResize(Sender: TObject);
begin
   PaintData
end;

procedure Tgraph2DForm.ImgViewMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer;
  Layer: TCustomLayer);
var largeur,hauteur:double;
    i,aux,tailleX,tailleY:integer;
    H,V:TFixedPoint;
    vind:integer;
    aux1,aux2:double;
    posScrollH,posScrollV:double;
    aux1X,aux1Y,aux2X,aux2Y:double;
    Sx,Sy:double;
begin
  Sx:=ScaleSx.position/100;Sy:=ScaleSy.position/100;
  vind:=deuxd.indexof(choixSpectre.text);
  //Selection := nil; { what is it ? }
  { conversion d'une position en pixel vers une position en absolue du graph }
  { ****** on suppose que le bitmap est toujours centré sur la fenetre ImgView ******* }
  { Taille de la fenetre graphique                                          }
if (vind>-1) then begin   // si un spectre est sélectionné dans la combo
  largeur:=abs(ImgView.GetViewPortRect.Left-ImgView.GetViewPortRect.Right);
  hauteur:=abs(ImgView.GetViewPortRect.Top-ImgView.GetViewPortRect.Bottom);
  aux1:=(X-ImgView.OffsetHorz)/CurrentScale/Sx; { sont-ce les coordonnée réelles ou les coordonnées en pixels }
  aux2:=(Y-ImgView.OffsetVert)/CurrentScale/Sy;
  { tracé des coupes sur le graph 2D }
  if Button = mbLeft then { si boutton souris gauche }
  begin
     { calcul de la position du curseur sur le bitmap }
     CurrentX:=floor(aux1);XCursor1:=CurrentX;
     CurrentY:=floor(aux2);YCursor1:=CurrentY;
     { test si on a cliqué sur une zone du graph }
     if (aux1>=0) and (aux1<deuxd.spect[vind].X) and (aux2>=0) and (aux2<deuxd.spect[vind].Y)
     then begin
          Xpos1.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].X;
          Ypos1.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Y;
          Zval1.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Z;
          { stockage des coupes dans les spectres 1D prédéfinis pour affichage dans la fenetre 1D }
          unD.add(deuxd.spect[vind].CoupeHSpectre2D('C1H',Ypos1.value));
          unD.add(deuxd.spect[vind].CoupeVSpectre2D('C1V',Xpos1.value));
          unD.spect[unD.indexof('C1H')].typeX:=deuxd.spect[vind].typeX;
          unD.spect[unD.indexof('C1V')].typeX:=deuxd.spect[vind].typeY;
{          unD.add(deuxd.spect[vind].SommeCirculaireSpectre2D('Circulaire',Floor(Xcen.value),Floor(Ycen.value),2.0)); }
          end;
  end;
  if Button = mbRight then { si boutton souris droit }
  begin
     CurrentX:=floor(aux1);XCursor2:=CurrentX;
     CurrentY:=floor(aux2);YCursor2:=CurrentY;
     if (aux1>0) and (aux1<=deuxd.spect[vind].X) and (aux2>0) and (aux2<=deuxd.spect[vind].Y)
     then begin
          Xpos2.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].X;
          Ypos2.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Y;
          Zval2.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Z;
          { stockage des coupes dans les spectres 1D prédéfinis pour affichage dans la fenetre 1D }
          unD.add(deuxd.spect[vind].CoupeHSpectre2D('C2H',Ypos2.value));
          unD.add(deuxd.spect[vind].CoupeVSpectre2D('C2V',Xpos2.value));
          unD.spect[unD.indexof('C2H')].typeX:=deuxd.spect[vind].typeX;
          unD.spect[unD.indexof('C2V')].typeX:=deuxd.spect[vind].typeY;
          end;
  end;

  tailleX:=deuxd.spect[vind].X;tailleY:=deuxd.spect[vind].Y;
  { calcul des projections correspondants aux positions des curseurs }
  { test si les positions des curseurs sont ok }
  aux1X:=deuxd.spect[vind].data[0,0,0].X;aux2X:=deuxd.spect[vind].data[tailleX-1,tailleY-1,0].X;
  aux1Y:=deuxd.spect[vind].data[0,0,0].Y;aux2Y:=deuxd.spect[vind].data[tailleX-1,tailleY-1,0].Y;
  if  (Xpos1.value>=min(aux1X,aux2X)) and (Xpos2.value>=min(aux1X,aux2X))
  and (Ypos1.value>=min(aux1Y,aux2Y)) and (Ypos2.value>=min(aux1Y,aux2Y))
  and (Xpos1.value<=max(aux1X,aux2X)) and (Xpos2.value<=max(aux1X,aux2X))
  and (Ypos1.value<=max(aux1Y,aux2Y)) and (Ypos2.value<=max(aux1Y,aux2Y))
  then begin
       unD.add(deuxd.spect[vind].ProjectionHSpectre2D('PV',min(Xpos1.value,Xpos2.value),max(Xpos1.value,Xpos2.value)));
       unD.add(deuxd.spect[vind].ProjectionVSpectre2D('PH',min(Ypos1.value,Ypos2.value),max(Ypos1.value,Ypos2.value)));
       somme.value:=deuxd.spect[vind].IntegraleSpectre2D(min(Xpos1.value,Xpos2.value),min(Ypos1.value,Ypos2.value),max(Xpos1.value,Xpos2.value),max(Ypos1.value,Ypos2.value));
       unD.spect[unD.indexof('PH')].typeX:=deuxd.spect[vind].typeY;
       unD.spect[unD.indexof('PV')].typeX:=deuxd.spect[vind].typeX;
       end;

  { essai de tracé de polygones sur l'image }
{  if Button = mbLeft then
  begin
      PolygonH1.Clear;
      PolygonH1.Add(FixedPoint(0, CurrentY*Sy));PolygonH1.Add(FixedPoint(deuxd.spect[vind].X*Sx, CurrentY*Sy));
      PolygonV1.Clear;
      PolygonV1.Add(FixedPoint(CurrentX*Sx, 0));PolygonV1.Add(FixedPoint(CurrentX*Sx, deuxd.spect[vind].Y*Sy));
  end;
  if Button = mbRight then
  begin
      PolygonH2.Clear;
      PolygonH2.Add(FixedPoint(0, CurrentY*Sy));PolygonH2.Add(FixedPoint(deuxd.spect[vind].X*Sx, CurrentY*Sy));
      PolygonV2.Clear;
      PolygonV2.Add(FixedPoint(CurrentX*Sx, 0));PolygonV2.Add(FixedPoint(CurrentX*Sx, deuxd.spect[vind].Y*Sy));
  end; }
  if Button = mbLeft then
  begin
      PolygonH1.Clear;
      PolygonH1.Add(FixedPoint(0, (aux2-0.5)*Sy));PolygonH1.Add(FixedPoint(deuxd.spect[vind].X*Sx, (aux2-0.5)*Sy));
      PolygonV1.Clear;
      PolygonV1.Add(FixedPoint((aux1-0.5)*Sx, 0));PolygonV1.Add(FixedPoint((aux1-0.5)*Sx, deuxd.spect[vind].Y*Sy));
  end;
  if Button = mbRight then
  begin
      PolygonH2.Clear;
      PolygonH2.Add(FixedPoint(0, aux2*Sy));PolygonH2.Add(FixedPoint(deuxd.spect[vind].X*Sx, aux2*Sy));
      PolygonV2.Clear;
      PolygonV2.Add(FixedPoint(aux1*Sx, 0));PolygonV2.Add(FixedPoint(aux1*Sx, deuxd.spect[vind].Y*Sy));
  end;

  PolygonD.Clear;
  { création de la coupe en diagonale }
  if (typeGraphCombo.text='DiagonaleX') or (typeGraphCombo.text='DiagonaleY') then
  begin PolygonD.Add(FixedPoint(Xcursor1,Ycursor1));PolygonD.Add(FixedPoint(Xcursor2,Ycursor2));end;
{  draw; }
  sendmessage(principalform.handle,wm_redessine,0,0);
  {Graph1DForm.redessiner; { verifier que graph1D EXISTE !! }

  { sauvegarde des positions des curseurs pour les definitions des masques }
  if CheckBoxMasks.Checked
  then begin
       ParamBox1.value:=Xpos1.value;ParamBox2.value:=Ypos1.value;ParamBox3.value:=Xpos2.value;ParamBox4.value:=Ypos2.value;
       end;

 end;
end;

procedure Tgraph2DForm.ZminBoxChange(Sender: TObject);
begin
  GenSampleData(choixSpectre.text);
  paintdata;
end;

procedure Tgraph2DForm.ZmaxBoxChange(Sender: TObject);
begin
  GenSampleData(choixSpectre.text);
  paintdata;
end;

procedure Tgraph2DForm.ZmaxBoxKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (key=13) or (key=38) or (key=40) then
  begin
     GenSampleData(choixSpectre.text);
     paintdata;CursorsReplot;
  end;
end;

procedure Tgraph2DForm.ZminBoxKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (key=13) or (key=38) or (key=40) then
  begin
    GenSampleData(choixSpectre.text);
    paintdata;CursorsReplot;
  end;
end;

procedure Tgraph2DForm.AutoScaleCheckBoxClick(Sender: TObject);
var vind:integer;
begin
  if (AutoScaleCheckBox.checked=true) then
  begin
     vind:=deuxd.indexof(choixspectre.text);
     if vind>=1 then
        begin
        AutoScale(deuxd.spect[vind]);
        GenSampleData(choixspectre.text);
        PaintData;CursorsReplot;
        end;
  end;
end;

{ lecture d'un spectre de format LAMP crée par D17 }
{ on lit les data uniquement : spectre de 143500 data }
{ 500 canaux de temps de vol et 287 canaux de position }
{ on laisse tomber le sinfor!mations sur le spectromètre }
procedure Tgraph2DForm.LectureLAMPD171Click(Sender: TObject);
var l:integer;
    nom,ext:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
   {extraction de l'extension}
   nom:=ProcessFileName(opendialog1.filename);
   LectureLAMPD17File(OpenDialog1.FileName,nom);
   MiseAjourChoixSpectre(deuxd);
   choixspectre.Text:=nom;
   GenSampleData(nom);
   paintdata;
  end;
end;


procedure Tgraph2DForm.LectureTPA1Click(Sender: TObject);
var l:integer;
    nom,ext:string;
begin
  opendialog1.defaultExt:='*.image';
  opendialog1.filter:='*.image|*.image';
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
     {extraction de l'extension}
     nom:=ProcessFileName(opendialog1.filename);
     LectureTPAFile(OpenDialog1.FileName,nom);
     MiseAjourChoixSpectre(deuxd);
     choixspectre.Text:=nom;
     GenSampleData(nom);
     paintdata;
  end;

end;

procedure Tgraph2DForm.LectureTPAOptions1Click(Sender: TObject);
begin
   LectureTPAoptionsForm.windowState:=wsnormal;
end;

procedure Tgraph2DForm.SaveToBinary32bitssignedClick(Sender: TObject);
var f:file of LongInt;
    i,j:integer;
    xmax,ymax:integer;
    vind:integer;
    aux:longInt;
begin
 if savedialog1.execute then
 begin
   AssignFile(F, savedialog1.filename);{ Fichier sélectionné dans la boîte de dialogue }
   Rewrite(F);
   vind:=deuxd.indexof(choixSpectre.text);
   xmax:=deuxd.spect[vind].X;ymax:=deuxd.spect[vind].Y;
   { determination de lal taille de la matrice binaire }
   for i:=0 to xmax-1 do
      for j:=0 to ymax-1 do
      begin
         aux:=round(deuxd.spect[vind].data[i,j,0].Z);
         write(f,aux);
      end;
   CloseFile(F);
 end
end;

procedure Tgraph2DForm.SavetoBitmap1Click(Sender: TObject);
var bitmap:Tbitmap;
begin
 savedialog1.DefaultExt:='bmp';
 if savedialog1.execute then
 begin
   ImgView.Bitmap.SaveToFile(savedialog1.filename);{ Fichier sélectionné dans la boîte de dialogue }
 end
end;

procedure Tgraph2DForm.LivePaletteUpdate;
begin
   genPalettes;
   color:=palettecombo.itemindex;
   paintdata;
end;

{ ============================================================================= }
procedure Tgraph2DForm.Addition1Click(Sender: TObject);
begin
{  Application.CreateForm(TdialogScaladdform, dialogScaladdform); }
  dialogScaladdform.windowState:=wsnormal;
  dialogscaladdform.operation.text:='+';
end;

procedure Tgraph2DForm.Soustraction2Click(Sender: TObject);
begin
{  Application.CreateForm(TdialogScaladdform, dialogScaladdform); }
  dialogScaladdform.windowState:=wsnormal;
  dialogscaladdform.operation.text:='-';
end;

procedure Tgraph2DForm.Multiplication1Click(Sender: TObject);
begin
{  Application.CreateForm(TdialogScaladdform, dialogScaladdform);   }
  dialogScaladdform.windowState:=wsnormal;
  dialogscaladdform.operation.text:='*';
end;

procedure Tgraph2DForm.Division1Click(Sender: TObject);
begin
{  Application.CreateForm(TdialogScaladdform, dialogScaladdform); }
  dialogScaladdform.windowState:=wsnormal;
  dialogscaladdform.operation.text:='/';
end;

procedure Tgraph2DForm.CursorsReplot;
var largeur,hauteur:double;
    i,aux,tailleX,tailleY:integer;
    H,V:TFixedPoint;
    vind:integer;
    aux1,aux2:double;
    posScrollH,posScrollV:double;
    X,Y:integer;
    aux1X,aux1Y,aux2X,aux2Y,Sx,Sy:double;
begin
  Sx:=ScaleSx.position/100;Sy:=ScaleSy.position/100;
  vind:=deuxd.indexof(choixSpectre.text);
  { on suppose que les positions Xcursor et Ycursor contiennent bien les positions actuelles des curseurs }
  { conversion d'une position en pixel vers une position en absolue du graph }
  { ****** on suppose que le bitmap est toujours centré sur la fenetre ImgView ******* }
  { Taille de la fenetre graphique                                          }
if (vind>-1) then begin   // si un spectre est sélectionné dans la combo
  largeur:=abs(ImgView.GetViewPortRect.Left-ImgView.GetViewPortRect.Right);
  hauteur:=abs(ImgView.GetViewPortRect.Top-ImgView.GetViewPortRect.Bottom);
  { tracé des coupes sur le graph 2D }
  begin
     { test si on a cliqué sur une zone du graph }
     aux1:=Xcursor1;aux2:=Ycursor1;
     if (aux1>=0) and (aux1<=deuxd.spect[vind].X) and (aux2>=0) and (aux2<=deuxd.spect[vind].Y)
     then begin
          Xpos1.value:=deuxd.spect[vind].data[Xcursor1,Ycursor1,0].X;
          Ypos1.value:=deuxd.spect[vind].data[Xcursor1,Ycursor1,0].Y;
          Zval1.value:=deuxd.spect[vind].data[Xcursor1,Ycursor1,0].Z;
          { stockage des coupes dans les spectres 1D prédéfinis pour affichage dans la fenetre 1D }
          unD.add(deuxd.spect[vind].CoupeHSpectre2D('C1H',Ypos1.value));
          unD.add(deuxd.spect[vind].CoupeVSpectre2D('C1V',Xpos1.value));
          unD.spect[unD.indexof('C1H')].typeX:=deuxd.spect[vind].typeX;
          unD.spect[unD.indexof('C1V')].typeX:=deuxd.spect[vind].typeY;
{          unD.add(deuxd.spect[vind].SommeCirculaireSpectre2D('Circulaire',Floor(Xcen.value),Floor(Ycen.value),2.0)); }
          end;
  end;
  begin
     aux1:=Xcursor2;aux2:=Ycursor2;
     if (aux1>0) and (aux1<=deuxd.spect[vind].X) and (aux2>0) and (aux2<=deuxd.spect[vind].Y)
     then begin
          Xpos2.value:=deuxd.spect[vind].data[Xcursor2,Ycursor2,0].X;
          Ypos2.value:=deuxd.spect[vind].data[Xcursor2,Ycursor2,0].Y;
          Zval2.value:=deuxd.spect[vind].data[Xcursor2,Ycursor2,0].Z;
          { stockage des coupes dans les spectres 1D prédéfinis pour affichage dans la fenetre 1D }
          unD.add(deuxd.spect[vind].CoupeHSpectre2D('C2H',Ypos2.value));
          unD.add(deuxd.spect[vind].CoupeVSpectre2D('C2V',Xpos2.value));
          unD.spect[unD.indexof('C2H')].typeX:=deuxd.spect[vind].typeX;
          unD.spect[unD.indexof('C2V')].typeX:=deuxd.spect[vind].typeY;
          end;
  end;

  tailleX:=deuxd.spect[vind].X;tailleY:=deuxd.spect[vind].Y;
  { calcul des projections correspondants aux positions des curseurs }
  { test si les positions des curseurs sont ok }
  aux1X:=deuxd.spect[vind].data[0,0,0].X;aux2X:=deuxd.spect[vind].data[tailleX-1,tailleY-1,0].X;
  aux1Y:=deuxd.spect[vind].data[0,0,0].Y;aux2Y:=deuxd.spect[vind].data[tailleX-1,tailleY-1,0].Y;
  if  (Xpos1.value>=min(aux1X,aux2X)) and (Xpos2.value>=min(aux1X,aux2X))
  and (Ypos1.value>=min(aux1Y,aux2Y)) and (Ypos2.value>=min(aux1Y,aux2Y))
  and (Xpos1.value<=max(aux1X,aux2X)) and (Xpos2.value<=max(aux1X,aux2X))
  and (Ypos1.value<=max(aux1Y,aux2Y)) and (Ypos2.value<=max(aux1Y,aux2Y))
  then begin
       unD.add(deuxd.spect[vind].ProjectionHSpectre2D('PV',min(Xpos1.value,Xpos2.value),max(Xpos1.value,Xpos2.value)));
       unD.add(deuxd.spect[vind].ProjectionVSpectre2D('PH',min(Ypos1.value,Ypos2.value),max(Ypos1.value,Ypos2.value)));
       somme.value:=deuxd.spect[vind].IntegraleSpectre2D(min(Xpos1.value,Xpos2.value),min(Ypos1.value,Ypos2.value),max(Xpos1.value,Xpos2.value),max(Ypos1.value,Ypos2.value));
       unD.spect[unD.indexof('PH')].typeX:=deuxd.spect[vind].typeY;
       unD.spect[unD.indexof('PV')].typeX:=deuxd.spect[vind].typeX;
       end;

  { tracé de polygones sur l'image }
      PolygonH1.Clear;
      PolygonH1.Add(FixedPoint(0, Ycursor1*Sy));PolygonH1.Add(FixedPoint(deuxd.spect[vind].X*Sx, Ycursor1*Sy));
      PolygonV1.Clear;
      PolygonV1.Add(FixedPoint(Xcursor1*Sx, 0));PolygonV1.Add(FixedPoint(Xcursor1*Sx, deuxd.spect[vind].Y*Sy));
      PolygonH2.Clear;
      PolygonH2.Add(FixedPoint(0, Ycursor2*Sy));PolygonH2.Add(FixedPoint(deuxd.spect[vind].X*Sx, Ycursor2*Sy));
      PolygonV2.Clear;
      PolygonV2.Add(FixedPoint(Xcursor2*Sx, 0));PolygonV2.Add(FixedPoint(Xcursor2*Sx, deuxd.spect[vind].Y*Sy));

  PolygonD.Clear;
  { création de la coupe en diagonale }
  if (typeGraphCombo.text='DiagonaleX') or (typeGraphCombo.text='DiagonaleY') then
  begin PolygonD.Add(FixedPoint(Xcursor1,Ycursor1));PolygonD.Add(FixedPoint(Xcursor2,Ycursor2));end;
{  draw; }
  sendmessage(principalform.handle,wm_redessine,0,0);
  {Graph1DForm.redessiner; { verifier que graph1D EXISTE !! }
 end;

 { mise en place de ticks }
 if TicksCheckBox.Checked=true then  UpdateTicks;

end;


procedure Tgraph2DForm.FileTypeButtonClick(Sender: TObject);
begin
   if FileTypeButton.caption='.nex' then FileTypeButton.caption:='.nxs'
   else if FileTypeButton.caption='.nxs' then FileTypeButton.caption:='.dat'
        else if FileTypeButton.caption='.dat' then FileTypeButton.caption:='.2D'
             else if FileTypeButton.caption='.2D' then FileTypeButton.caption:='.nex'
end;

{ procedure Tgraph2DForm.FileTypeButtonClick(Sender: TObject);
var vind,W,H:integer;
    P:PPalette32;
begin
  vind:=deuxd.indexof(choixSpectre.text);
  W:=deuxd.spect[vind].X;
  H:=deuxd.spect[vind].Y;
  DataSetAux.SetSize(round(W*ScaleSx.Position/100),round(H*ScaleSy.position/100));
  case PaletteCombo.ItemIndex of
    0: P := @palGrayScale;
    1: P := @palRainbow;
    2: P := @palMultiColor;
    3: P := @palReds;
    4: P := @palGreens;
    5: P := @palBlues;
    6: P := @palPurple;
  else
    P := @palCustom;
  end;
  DataSetAux.WriteTo(ImgView32Dst.Bitmap, P^);
end; }

{ extraction de la zone sélectionnnée sur le graph par les deux curseurs }
procedure Tgraph2DForm.Extractselection1Click(Sender: TObject);
var i,j:integer;
    tailleX1,tailleY1,tailleX2,tailleY2,idx1,idx2:integer;
    xmin1,xmax1,ymin1,ymax1,xstep1,ystep1,xaux,yaux,zaux:double;
    xmin_e,xmax_e,ymin_e,ymax_e:double;
begin
       { soit a determiner la taille du spectre de sortie }
       idx1:=deuxd.indexof(choixSpectre.text);
       tailleX1:=deuxd.spect[idx1].X;tailleY1:=deuxd.spect[idx1].Y;
       Xmin1:=min(deuxd.spect[idx1].data[0,0,0].X,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].X);
       Xmax1:=max(deuxd.spect[idx1].data[0,0,0].X,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].X);
       Ymin1:=min(deuxd.spect[idx1].data[0,0,0].Y,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].Y);
       Ymax1:=max(deuxd.spect[idx1].data[0,0,0].Y,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].Y);
       Xstep1:=(Xmax1-Xmin1)/(tailleX1-1);Ystep1:=(Ymax1-Ymin1)/(tailleY1-1);
       { creation du nouveau spectre }
       xmin_e:=min(Xpos1.value,Xpos2.value);xmax_e:=max(Xpos1.value,Xpos2.value);
       ymin_e:=min(Ypos1.value,Ypos2.value);ymax_e:=max(Ypos1.value,Ypos2.value);
       tailleX2:=round((xmax_e-xmin_e)/XStep1+1);
       tailleY2:=round((ymax_e-ymin_e)/YStep1+1);
       { determination de la taille du nouveau spectre et initialisation }
       idx2:=deuxd.addSpectre(choixSpectre.text+'_e',TailleX2,TailleY2,1);
       deuxd.spect[idx2].typeX:=deuxd.spect[idx1].typeX;deuxd.spect[idx2].typeY:=deuxd.spect[idx1].typeY;
       { remplissage du nouveau spectre }
       { scan du premier spectre }
       for i:=0 to TailleX1-1 do
        for j:=0 to TailleY1-1 do
          begin
            xaux:=deuxd.spect[idx1].data[i,j,0].x;
            yaux:=deuxd.spect[idx1].data[i,j,0].y;
            zaux:=deuxd.spect[idx1].data[i,j,0].z;
            if (xaux>=xmin_e) and (xaux<=xmax_e) and (yaux>=ymin_e) and (yaux<=ymax_e) then
            begin
            deuxd.spect[idx2].data[round((xaux-xmin_e)/xstep1),round((yaux-ymin_e)/ystep1),0].X:=xaux;
            deuxd.spect[idx2].data[round((xaux-xmin_e)/xstep1),round((yaux-ymin_e)/ystep1),0].Y:=yaux;
            deuxd.spect[idx2].data[round((xaux-xmin_e)/xstep1),round((yaux-ymin_e)/ystep1),0].Z:=zaux;
            end;
          end;
       Xcursor1:=0;Ycursor1:=0;
       Xcursor2:=TailleX2-1;Ycursor2:=TailleY2-1;
end;


{ rotate the picture on the graph }
procedure Tgraph2DForm.Rotation1Click(Sender: TObject);
var i,j:integer;
    tailleX1,tailleY1,tailleX2,tailleY2,idx1,idx2:integer;
    xmin1,xmax1,ymin1,ymax1,xstep1,ystep1,xaux,yaux,zaux,xaux2,yaux2:double;
    x1,y1,x2,y2,xmin2,xmax2,ymin2,ymax2,xc2,yc2:double;
    xc,yc,xmin_e,xmax_e,ymin_e,ymax_e:double;
    theta:double;
    xaux2_low,yaux2_low,xx,yy:integer;
begin
   theta:=RotationAngleBox.value*pi/180;
   { soit a determiner la taille du spectre de sortie }
   idx1:=deuxd.indexof(choixSpectre.text);
   tailleX1:=deuxd.spect[idx1].X;tailleY1:=deuxd.spect[idx1].Y;
   Xmin1:=min(deuxd.spect[idx1].data[0,0,0].X,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].X);
   Xmax1:=max(deuxd.spect[idx1].data[0,0,0].X,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].X);
   Ymin1:=min(deuxd.spect[idx1].data[0,0,0].Y,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].Y);
   Ymax1:=max(deuxd.spect[idx1].data[0,0,0].Y,deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].Y);
   Xstep1:=(Xmax1-Xmin1)/(tailleX1-1);Ystep1:=(Ymax1-Ymin1)/(tailleY1-1);
   Xc:=(Xmax1+Xmin1)/2;Yc:=(Ymax1+Ymin1)/2;
   { creation du nouveau spectre }
   Xmin2:=+1e20;Xmax2:=-1e20;
   Ymin2:=+1e20;Ymax2:=-1e20;
   { determination des bords extremes du nouveau spectre }
   Xaux:=(Xmin1-Xc)*cos(theta)-(Ymin1-Yc)*sin(theta)+Xc;Yaux:=(Xmin1-Xc)*sin(theta)+(Ymin1-Yc)*cos(theta)+Yc;
   if Xaux<Xmin2 then Xmin2:=Xaux;if Xaux>Xmax2 then Xmax2:=Xaux;
   if Yaux<Ymin2 then Ymin2:=Yaux;if Yaux>Ymax2 then Ymax2:=Yaux;
   Xaux:=(Xmax1-Xc)*cos(theta)-(Ymin1-Yc)*sin(theta)+Xc;Yaux:=(Xmax1-Xc)*sin(theta)+(Ymin1-Yc)*cos(theta)+Yc;
   if Xaux<Xmin2 then Xmin2:=Xaux;if Xaux>Xmax2 then Xmax2:=Xaux;
   if Yaux<Ymin2 then Ymin2:=Yaux;if Yaux>Ymax2 then Ymax2:=Yaux;
   Xaux:=(Xmax1-Xc)*cos(theta)-(Ymax1-Yc)*sin(theta)+Xc;Yaux:=(Xmax1-Xc)*sin(theta)+(Ymax1-Yc)*cos(theta)+Yc;
   if Xaux<Xmin2 then Xmin2:=Xaux;if Xaux>Xmax2 then Xmax2:=Xaux;
   if Yaux<Ymin2 then Ymin2:=Yaux;if Yaux>Ymax2 then Ymax2:=Yaux;
   Xaux:=(Xmin1-Xc)*cos(theta)-(Ymax1-Yc)*sin(theta)+Xc;Yaux:=(Xmin1-Xc)*sin(theta)+(Ymax1-Yc)*cos(theta)+Yc;
   if Xaux<Xmin2 then Xmin2:=Xaux;if Xaux>Xmax2 then Xmax2:=Xaux;
   if Yaux<Ymin2 then Ymin2:=Yaux;if Yaux>Ymax2 then Ymax2:=Yaux;
   { creation du nouveau spectre }
   xmin2:=round(xmin2);xmax2:=round(xmax2); { attention coordonnée entières !!! }
   ymin2:=round(ymin2);ymax2:=round(ymax2);
   Xc2:=round((Xmax2+Xmin2)/2);Yc2:=round((Ymax2+Ymin2)/2);
   tailleX2:=round((xmax2-xmin2)/XStep1+1);tailleY2:=round((ymax2-ymin2)/YStep1+1);
   idx2:=deuxd.addSpectre(choixSpectre.text+'_r',TailleX2,TailleY2,1);
   deuxd.spect[idx2].typeX:=deuxd.spect[idx1].typeX;deuxd.spect[idx2].typeY:=deuxd.spect[idx1].typeY;
   { remplissage du nouveau spectre rotated X,Y, Z=0}
   for i:=0 to TailleX2-1 do
      for j:=0 to TailleY2-1 do
         begin
            x2:=xmin2+i*Xstep1;y2:=ymin2+j*Ystep1;
            deuxd.spect[idx2].data[i,j,0].X:=x2;
            deuxd.spect[idx2].data[i,j,0].Y:=y2;
            { remplissage de l'élévation }
            { détermination de l'image inverse du point (xx,yy) }
            x1:=(x2-xc2)*cos(theta)+(y2-yc2)*sin(theta)+Xc2;
            y1:=-(x2-xc2)*sin(theta)+(y2-yc2)*cos(theta)+Yc2;
            if (x1>=xmin1) and (x1<=xmax1) and (y1>=ymin1) and (y1<=ymax1)
            then deuxd.spect[idx2].data[i,j,0].Z:=deuxd.spect[idx1].interpolate2D(x1,y1)
            else deuxd.spect[idx2].data[i,j,0].Z:=0;
         end;
end;

procedure Tgraph2DForm.EraseCursorsButtonClick(Sender: TObject);
var
  vind:integer;
begin
  vind:=deuxd.indexof(choixspectre.text);
  if vind>=1 then
  begin
    AutoScale(deuxd.spect[vind]);
    GenSampleData(choixspectre.text);
    PaintData;
  end;
end;

procedure Tgraph2DForm.ImgViewMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
var largeur,hauteur:double;
    i,aux,tailleX,tailleY:integer;
    H,V:TFixedPoint;
    vind,CX,CY:integer;
    aux1,aux2:double;
    posScrollH,posScrollV,Sx,Sy:double;
begin
  Sx:=ScaleSx.position/100;Sy:=ScaleSy.position/100;
  vind:=deuxd.indexof(choixSpectre.text);
  if (vind>-1)
  then begin
     { calcul de la position du curseur sur le bitmap }
     { il manque l'offset }
     aux1:=(X-ImgView.OffsetHorz)/CurrentScale/Sx;
     aux2:=(Y-ImgView.OffsetVert)/CurrentScale/Sy;
     CX:=Floor(aux1);CY:=Floor(aux2);
     { test si on a cliqué sur une zone du graph }
     if (aux1>=0) and (aux1<deuxd.spect[vind].X) and (aux2>=0) and (aux2<deuxd.spect[vind].Y)
     then begin
          XCrtBox.value:=deuxd.spect[vind].data[CX,CY,0].X;
          YCrtBox.value:=deuxd.spect[vind].data[CX,CY,0].Y;
          ZCrtBox.value:=deuxd.spect[vind].data[CX,CY,0].Z;
          end
     else begin XCrtBox.value:=0;YCrtBox.value:=0; end;
     end
end;

procedure Tgraph2DForm.Lireunspectreoldversion1Click(Sender: TObject);
var vind,l,i,j:integer;
    ext,nom:string;
begin
opendialog1.initialDir:=boitnoir.RepertoireManip.text;
if opendialog1.execute then
   begin
   {extraction de l'extension}
   nom:=ProcessFileName(opendialog1.filename);
      vind:=deuxd.indexof(nom);
      if vind=-1 then vind:=deuxd.addspectre(nom,1,1,1); {creation avec taille arbitraire, le spectre prendra ensuite la taille du fichier}
{      deuxd.spect[vind].open(opendialog1.filename);        }
      deuxd.spect[vind].readfromfile(opendialog1.filename); { ancienne version }
      {il faut mettre a jour les champs .x et .Y qui sont devenus obligatoires }
      for i:=0 to deuxd.spect[vind].X-1 do
        for j:=0 to deuxd.spect[vind].Y-1 do
             begin deuxd.spect[vind].data[i,j,0].X:=i;deuxd.spect[vind].data[i,j,0].Y:=j; end;
      MiseAjourChoixSpectre(deuxd);
      choixspectre.Text:=nom;
      GenSampleData(nom);
   end;
   paintdata;
end;

procedure Tgraph2DForm.Sauverlespectreoldversion1Click(Sender: TObject);
var vind:integer;
begin
 vind:=deuxd.indexof(choixSPectre.text);
 savedialog1.initialDir:=boitnoir.RepertoireManip.text;
 if savedialog1.execute then
    deuxd.spect[vind].savetofile(savedialog1.filename);
end;

procedure Tgraph2DForm.SavetoNeXuS1Click(Sender: TObject);
var vind:integer;
begin
 vind:=deuxd.indexof(choixSPectre.text);
 if vind>0 then
 begin
 savedialog1.initialDir:=boitnoir.RepertoireManip.text;
 savedialog1.defaultExt:='*.nxs';
 savedialog1.filter:='*.nxs|*.nxs';
 savedialog1.filename:=choixSPectre.text;
 if savedialog1.execute then
    if fileExists(savedialog1.filename)
    then MessageDlg('The file already exists',mtWarning,[mbOk],0)
    else deuxd.spect[vind].saveToNexus(savedialog1.filename);
 end;
end;

procedure Tgraph2DForm.ReadfromNeXus1Click(Sender: TObject);
var vind,l:integer;
    nom,ext:string;
begin
  opendialog1.initialDir:=boitnoir.RepertoireManip.text;
  opendialog1.defaultExt:='*.nxs';
  opendialog1.filter:='*.nxs|*.nxs';
  if opendialog1.execute
  then begin {le spectre est un spectre 2D}
     {extraction de l'extension}
     nom:=ProcessFileName(opendialog1.filename);
      vind:=deuxd.indexof(nom);
      if vind=-1 then vind:=deuxd.addspectre(nom,1,1,1); {creation avec taille arbitraire, le spectre prendra ensuite la taille du fichier}
      deuxd.spect[vind].ReadFromNexus(opendialog1.filename);
      MiseAjourChoixSpectre(deuxd);
      choixspectre.Text:=nom;
      GenSampleData(nom);
      paintdata;
      CursorsReplot;
      end;
end;

procedure Tgraph2DForm.ReadfromNeXusLLB1Click(Sender: TObject);
var vind,l:integer;
    nom,ext:string;
begin
  opendialog1.initialDir:=boitnoir.RepertoireManip.text;
  if opendialog1.execute
  then begin {le spectre est un spectre 2D}
     {extraction de l'extension}
     Nom:=ProcessFileName(opendialog1.filename);
      vind:=deuxd.indexof(nom);
      if vind=-1 then vind:=deuxd.addspectre(nom,1,1,1); {creation avec taille arbitraire, le spectre prendra ensuite la taille du fichier}
      deuxd.spect[vind].ReadFromNexusLLB(opendialog1.filename);
      MiseAjourChoixSpectre(deuxd);
      choixspectre.Text:=nom;
      GenSampleData(nom);
      paintdata;
      CursorsReplot; 
      end;
end;

procedure Tgraph2DForm.MiniParserBoxKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
   if key=13 then
   begin traitchaine(MiniParserBox.text) {;redessiner } end;
end;

procedure Tgraph2dform.traitchaine(s:string); {Ne fonctionne pas bien ???}
var
i:integer;
begin
 deuxd.parsechaine(s);
{  i:=1;
while und.spect[i]<>nil do inc(i);
dec(i);
cocourbe1.items.add(und.spect[i].nom);
cocourbe2.items.add(und.spect[i].nom);
cocourbe3.items.add(und.spect[i].nom);
cocourbe4.items.add(und.spect[i].nom); }
end;

procedure Tgraph2DForm.LectureFichierHADAS1Click(Sender: TObject);
var nom:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
       nom:=OpenDialog1.FileName;
       LectureFichierHADAS(nom);{ Fichier sélectionné dans la boîte de dialogue }
{       nom:=copy(nom,9,length(nom));
       choixspectre.items.add(nom);
       choixspectre.text:=nom;
       choixspectreChange(Sender); }
  end;
  MiseAJourChoixSpectre(deuxd);
end;

procedure Tgraph2DForm.SavetoHDF1Click(Sender: TObject);
var vind:integer;
begin
 vind:=deuxd.indexof(choixSPectre.text);
 if vind>0 then
 begin
 savedialog1.initialDir:=boitnoir.RepertoireManip.text;
 savedialog1.defaultExt:='*.hdf';
 savedialog1.filter:='*.hdf|*.hdf';
 if savedialog1.execute then
    deuxd.spect[vind].saveToHDF(savedialog1.filename);
 end;
end;

procedure Tgraph2DForm.SavetoASCII1Click(Sender: TObject);
var vind:integer;
begin
   vind:=deuxd.indexof(choixSpectre.text);
   savedialog1.initialDir:=boitnoir.RepertoireManip.text;
   savedialog1.defaultExt:='*.txt';
   savedialog1.filter:='*.txt|*.txt';
   deuxd.spect[vind].comment:=choixSpectre.text;
   if savedialog1.execute then
     deuxd.spect[vind].saveToASCII_3col(savedialog1.filename);
end;

procedure Tgraph2DForm.SaveToBinarysigned32bits1Click(Sender: TObject);
var f:file of LongInt;
    i,j:integer;
    xmax,ymax:integer;
    vind:integer;
    aux:longInt;
begin
 if savedialog1.execute then
 begin
   AssignFile(F, savedialog1.filename);{ Fichier sélectionné dans la boîte de dialogue }
   Rewrite(F);
   vind:=deuxd.indexof(choixSpectre.text);
   xmax:=deuxd.spect[vind].X;ymax:=deuxd.spect[vind].Y;
   { determination de lal taille de la matrice binaire }
   for i:=0 to xmax-1 do
      for j:=0 to ymax-1 do
      begin
         aux:=round(deuxd.spect[vind].data[i,j,0].Z);
         write(f,aux);
      end;
   CloseFile(F);
 end
end;

procedure Tgraph2DForm.InvertCheckBoxClick(Sender: TObject);
begin
   genPalettes;
   color:=palettecombo.itemindex;
   paintdata;
end;

procedure Tgraph2DForm.CopyBitmapToClipboard1Click(Sender: TObject);
begin
   Clipboard.Assign(ImgView.Bitmap);
end;

procedure Tgraph2DForm.UpdateTicks;
var  i,idx1:integer;
     tailleX1,tailleY1:integer;
     xTickStep,yTickStep,xStepPix,YstepPix:double;
     xmin1,xmax1,ymin1,ymax1,Xcrt,Ycrt:double;
     BmpRect:Trect;
     TextSize:Tsize;
begin
   xTickStep:=xTickStepBox.value;yTickStep:=yTickStepBox.value;
   idx1:=deuxd.indexof(choixSpectre.text);
   BmpRect:=ImgView.GetBitmapRect;
   tailleX1:=deuxd.spect[idx1].X;tailleY1:=deuxd.spect[idx1].Y;
   Xmin1:=deuxd.spect[idx1].data[0,0,0].X;Ymin1:=deuxd.spect[idx1].data[0,0,0].Y;
   Xmax1:=deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].X;Ymax1:=deuxd.spect[idx1].data[tailleX1-1,tailleY1-1,0].Y;
   XstepPix:=xTickStep*(BmpRect.Right-BmpRect.Left)/(Xmax1-Xmin1); { pas en pixels par Xtick}
   YstepPix:=yTickStep*(BmpRect.Bottom-BmpRect.Top)/(Ymax1-Ymin1); { pas en pixels }
   Xcrt:=Xmin1;i:=0;
   while Xcrt<Xmax1 do
   begin
     with ImgView.Canvas do
     begin
        MoveTo(round(BmpRect.Left+i*XstepPix),BmpRect.Bottom);
        LineTo(round(BmpRect.Left+i*XstepPix),BmpRect.Bottom+3);
        TextSize:=TextExtent(FloatToStr(Xcrt));
        textOut(round(BmpRect.Left+i*XstepPix-TextSize.cx/2),BmpRect.Bottom+4,FloatToStr(Xcrt));
     end;
     inc(i);Xcrt:=Xcrt+xTickStep;
   end;
   Ycrt:=Ymin1;i:=0;
   while Ycrt<Ymax1 do
   begin
     with ImgView.Canvas do
     begin
        MoveTo(BmpRect.Left,round(BmpRect.Top+i*XstepPix));
        LineTo(BmpRect.Left-3,round(BmpRect.Top+i*XstepPix));
        TextSize:=TextExtent(FloatToStr(Ycrt));
        textOut(BmpRect.Left-TextSize.cx-4,round(BmpRect.Top+i*XstepPix-TextSize.cy/2),FloatToStr(Ycrt));
     end;
     inc(i);Ycrt:=Ycrt+yTickStep;
   end
end;


procedure Tgraph2DForm.PlotTicksButtonClick(Sender: TObject);
begin
   UpdateTicks;
end;


procedure Tgraph2DForm.savetostream(f:TStream; savedata:boolean);
var { w:TxyWriter; }
    t, pos1, pos2, xlen1:longint;
begin
{  FSaveData := savedata;
  w := TxyWriter.create(f,4096);
  try
    w.writeString(xyGraphFileSig + xyGraphFileVersion + versionstamp);
    FAppearance.WriteToStream(w);
    FDimensions.WriteToStream(w);
    FXAxis.WriteToStream(w);
    FYAxis.WriteToStream(w);
    FYAXis2.WriteToStream(w);
    FLegend.WriteToStream(w);
    WriteseriesCount(w);
    writeMarkCount(w);
  finally
    w.free;
  end;
  if FFilingSeriesCount > 0 then WriteAllSeries(f);
  if FFilingMarksCount > 0 then WriteAllMarks(f);
  // write number of bytes left for versions prior to v3.1
  pos1 := f.Position;
  t := 0;
  f.write(t,4);
  w := TxyWriter.create(f,4096);
  try
    WriteAnnotationsCount(w);
  finally;
    w.free;
  end;
  if FFilingAnnotationsCount <> 0 then WriteAllAnnotations(f);
  pos2 := f.position;
  xlen1 := pos2 - pos1;
  t := 0;
  f.write(t,4);
  f.position := pos1;
  f.write(xlen1, 4);
  f.position := pos2; }
end;

{ ============================================================================== }
{fill metafile requires a valid TMetafile to be supplied to it -
 resource allocation/deallocation issues. The internally created
 metafile is produced first, and then copied into the external one}
procedure Tgraph2DForm.FillMetafile(wmf:TMetafile);
{thanks to the following people for their help with the Metafiles
 routine: Frank Schmidt, John Biddiscombe, Hendrik Levsen }
var
    metafile   : TMetaFile;
    metaCanvas : TMetaFileCanvas;
begin
  metafile := TMetaFile.Create;
  metafile.Height := height;
  metafile.width := width;
{  FCurrWidth := width;
  FCurrHeight := height; }
  metaCanvas := TMetafileCanvas.Create(metafile, 0);
{  Fcanvas := metaCanvas; }
  try
{    PaintGraph(true); }
    try
{      If assigned(FOnPaintEnd) then FOnPaintEnd(self, FCanvas); }
    except
    end;
  finally
    metaCanvas.Free;
    try
{      wmf.Assign(metafile); }
    finally
     metafile.free;
{     FCanvas := Canvas; }
    end;
  end;
end;

procedure Tgraph2DForm.FillBitmap(bmp:TBitmap);
var iBmp:TBitmap;
begin
  iBmp := TBitmap.create;
  ibmp.width := bmp.width;
  ibmp.height := bmp.height;
{  FCurrWidth := bmp.width; }
{  FCurrHeight := bmp.height; }
{  FCanvas:= iBmp.Canvas; }
{  FAltCanvas := iBmp.Canvas; }
  try
{    PaintGraph(true); }
    try
{      If assigned(FOnPaintEnd) then FOnPaintEnd(self, FCanvas); }
    except
    end;
    bmp.Assign(iBmp);
  finally
{    FCanvas := Canvas; }
{    FAltCanvas := Canvas; }
  end;
end;

{copy and paste routines modelled on Delphi Developers Guide,
 Pacheco & Teixeira p 352}
procedure Tgraph2DForm.CopyToClipboard;
var
    metafile:TMetafile;

    strm:TMemoryStream;
    p:pointer;
    h:Thandle;

    bmp:TBitmap;
    Format: Word;
    Data: THandle;
    Palette: HPALETTE;

begin
  CF_xyGraphFmt := RegisterClipboardFormat('Internal xyGraph Format');
  metafile := TMetafile.create;
  try
    strm := TMemoryStream.create;
    try
      bmp := TBitmap.create;
      try
        FillMetafile(metafile);
        FillBitmap(bmp);
        savetostream(strm,true);
        h := GlobalAlloc(GMEM_Moveable, strm.size);
        try
          p := GlobalLock(h);
          try
            move(strm.memory^, p^, strm.size);
            clipboard.open;
            Clipboard.SetAsHandle(CF_xyGraphFmt, h);
            bmp.SaveToClipboardFormat(Format, Data, Palette);
            Clipboard.SetAsHandle(Format, Data);
            if Palette <> 0 then Clipboard.SetAsHandle(CF_PALETTE, Palette);
            Clipboard.assign(metafile);
            Clipboard.Close;
          finally
            GlobalUnLock(h);
          end;
        except
          Globalfree(h);
          raise;
        end;
      finally
        bmp.free;
      end;
    finally
      strm.free;
    end;
  finally
    metafile.free;
  end;
end;

{ desactivation de l'autoscale }
procedure Tgraph2DForm.ZminBoxEnter(Sender: TObject);
begin
  AutoScaleCheckBox.checked:=false;
end;

procedure Tgraph2DForm.ZmaxBoxEnter(Sender: TObject);
begin
  AutoScaleCheckBox.checked:=false;
end;

procedure Tgraph2DForm.Button2Click(Sender: TObject);
var P:PPalette32;
    vind:integer;
    W,H:integer;
begin
   DoTransform(ScaleSx.Position/100,ScaleSy.Position/100);
end;

procedure Tgraph2DForm.ScaleSxChange(Sender: TObject);
begin
   DoTransform(ScaleSx.Position/100,ScaleSy.Position/100);
   CursorsReplot;
end;

procedure Tgraph2DForm.ScaleSyChange(Sender: TObject);
begin
   DoTransform(ScaleSx.Position/100,ScaleSy.Position/100);
   CursorsReplot;
end;

{ réponse à la rotation de la wheel de la souris pour faire le zoom de l'image }
procedure Tgraph2DForm.ImgViewMouseWheel(Sender: TObject;
  Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
  var Handled: Boolean);
var
  OldScale,NewScale: Single;
begin
  OldScale:=Power(10, (ScaleBar.Position) / 100);
  NewScale:=OldScale*Power(1.1, WheelDelta/120);
  CurrentScale:=NewScale;
  ScaleBar.Repaint;
  ImgView.ScaleMode := SmScale;
  ImgView.Scale := NewScale;
  ImgView32Dst.ScaleMode := SmScale;
  ImgView32Dst.Scale := NewScale;
end;

procedure Tgraph2DForm.ImgViewMouseWheelDown(Sender: TObject;
  Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
var
  OldScale,NewScale: Single;
begin
  OldScale:=Power(10, (ScaleBar.Position) / 100);

  CurrentScale:=NewScale;
  ScaleBar.Repaint;
  ImgView.ScaleMode := SmScale;
  ImgView.Scale := NewScale;
  ImgView32Dst.ScaleMode := SmScale;
  ImgView32Dst.Scale := NewScale;
end;

procedure Tgraph2DForm.FormKeyPress(Sender: TObject; var Key: Char);
var largeur,hauteur:double;
    i,aux,tailleX,tailleY:integer;
    H,V:TFixedPoint;
    vind:integer;
    aux1,aux2:double;
    posScrollH,posScrollV:double;
    aux1X,aux1Y,aux2X,aux2Y:double;
    Sx,Sy:double;
    x,y:double;
    Button: TMouseButton;
begin
if (key='j') or (key='k')
then begin
  Button:=mbLeft;
  if key='j' then CurrentX:=CurrentX-1;X:=CurrentX;
  if key='k' then CurrentX:=CurrentX+1;X:=CurrentX;
  Sx:=ScaleSx.position/100;Sy:=ScaleSy.position/100;
  vind:=deuxd.indexof(choixSpectre.text);
  //Selection := nil; { what is it ? }
  { conversion d'une position en pixel vers une position en absolue du graph }
  { ****** on suppose que le bitmap est toujours centré sur la fenetre ImgView ******* }
  { Taille de la fenetre graphique                                          }
if (vind>-1) then begin   // si un spectre est sélectionné dans la combo
  largeur:=abs(ImgView.GetViewPortRect.Left-ImgView.GetViewPortRect.Right);
  hauteur:=abs(ImgView.GetViewPortRect.Top-ImgView.GetViewPortRect.Bottom);
  aux1:=(X-ImgView.OffsetHorz)/CurrentScale/Sx; { sont-ce les coordonnée réelles ou les coordonnées en pixels }
  aux2:=(Y-ImgView.OffsetVert)/CurrentScale/Sy;
  { tracé des coupes sur le graph 2D }
  if Button = mbLeft then { si boutton souris gauche }
  begin
     { calcul de la position du curseur sur le bitmap }
     CurrentX:=floor(aux1);XCursor1:=CurrentX;
     CurrentY:=floor(aux2);YCursor1:=CurrentY;
     { test si on a cliqué sur une zone du graph }
     if (aux1>=0) and (aux1<deuxd.spect[vind].X) and (aux2>=0) and (aux2<deuxd.spect[vind].Y)
     then begin
          Xpos1.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].X;
          Ypos1.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Y;
          Zval1.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Z;
          { stockage des coupes dans les spectres 1D prédéfinis pour affichage dans la fenetre 1D }
          unD.add(deuxd.spect[vind].CoupeHSpectre2D('C1H',Ypos1.value));
          unD.add(deuxd.spect[vind].CoupeVSpectre2D('C1V',Xpos1.value));
          unD.spect[unD.indexof('C1H')].typeX:=deuxd.spect[vind].typeX;
          unD.spect[unD.indexof('C1V')].typeX:=deuxd.spect[vind].typeY;
{          unD.add(deuxd.spect[vind].SommeCirculaireSpectre2D('Circulaire',Floor(Xcen.value),Floor(Ycen.value),2.0)); }
          end;
  end;
  if Button = mbRight then { si boutton souris droit }
  begin
     CurrentX:=floor(aux1);XCursor2:=CurrentX;
     CurrentY:=floor(aux2);YCursor2:=CurrentY;
     if (aux1>0) and (aux1<=deuxd.spect[vind].X) and (aux2>0) and (aux2<=deuxd.spect[vind].Y)
     then begin
          Xpos2.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].X;
          Ypos2.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Y;
          Zval2.value:=deuxd.spect[vind].data[CurrentX,CurrentY,0].Z;
          { stockage des coupes dans les spectres 1D prédéfinis pour affichage dans la fenetre 1D }
          unD.add(deuxd.spect[vind].CoupeHSpectre2D('C2H',Ypos2.value));
          unD.add(deuxd.spect[vind].CoupeVSpectre2D('C2V',Xpos2.value));
          unD.spect[unD.indexof('C2H')].typeX:=deuxd.spect[vind].typeX;
          unD.spect[unD.indexof('C2V')].typeX:=deuxd.spect[vind].typeY;
          end;
  end;

  tailleX:=deuxd.spect[vind].X;tailleY:=deuxd.spect[vind].Y;
  { calcul des projections correspondants aux positions des curseurs }
  { test si les positions des curseurs sont ok }
  aux1X:=deuxd.spect[vind].data[0,0,0].X;aux2X:=deuxd.spect[vind].data[tailleX-1,tailleY-1,0].X;
  aux1Y:=deuxd.spect[vind].data[0,0,0].Y;aux2Y:=deuxd.spect[vind].data[tailleX-1,tailleY-1,0].Y;
  if  (Xpos1.value>=min(aux1X,aux2X)) and (Xpos2.value>=min(aux1X,aux2X))
  and (Ypos1.value>=min(aux1Y,aux2Y)) and (Ypos2.value>=min(aux1Y,aux2Y))
  and (Xpos1.value<=max(aux1X,aux2X)) and (Xpos2.value<=max(aux1X,aux2X))
  and (Ypos1.value<=max(aux1Y,aux2Y)) and (Ypos2.value<=max(aux1Y,aux2Y))
  then begin
       unD.add(deuxd.spect[vind].ProjectionHSpectre2D('PV',min(Xpos1.value,Xpos2.value),max(Xpos1.value,Xpos2.value)));
       unD.add(deuxd.spect[vind].ProjectionVSpectre2D('PH',min(Ypos1.value,Ypos2.value),max(Ypos1.value,Ypos2.value)));
       somme.value:=deuxd.spect[vind].IntegraleSpectre2D(min(Xpos1.value,Xpos2.value),min(Ypos1.value,Ypos2.value),max(Xpos1.value,Xpos2.value),max(Ypos1.value,Ypos2.value));
       unD.spect[unD.indexof('PH')].typeX:=deuxd.spect[vind].typeY;
       unD.spect[unD.indexof('PV')].typeX:=deuxd.spect[vind].typeX;
       end;

  { essai de tracé de polygones sur l'image }
{  if Button = mbLeft then
  begin
      PolygonH1.Clear;
      PolygonH1.Add(FixedPoint(0, CurrentY*Sy));PolygonH1.Add(FixedPoint(deuxd.spect[vind].X*Sx, CurrentY*Sy));
      PolygonV1.Clear;
      PolygonV1.Add(FixedPoint(CurrentX*Sx, 0));PolygonV1.Add(FixedPoint(CurrentX*Sx, deuxd.spect[vind].Y*Sy));
  end;
  if Button = mbRight then
  begin
      PolygonH2.Clear;
      PolygonH2.Add(FixedPoint(0, CurrentY*Sy));PolygonH2.Add(FixedPoint(deuxd.spect[vind].X*Sx, CurrentY*Sy));
      PolygonV2.Clear;
      PolygonV2.Add(FixedPoint(CurrentX*Sx, 0));PolygonV2.Add(FixedPoint(CurrentX*Sx, deuxd.spect[vind].Y*Sy));
  end; }
  if Button = mbLeft then
  begin
      PolygonH1.Clear;
      PolygonH1.Add(FixedPoint(0, (aux2-0.5)*Sy));PolygonH1.Add(FixedPoint(deuxd.spect[vind].X*Sx, (aux2-0.5)*Sy));
      PolygonV1.Clear;
      PolygonV1.Add(FixedPoint((aux1-0.5)*Sx, 0));PolygonV1.Add(FixedPoint((aux1-0.5)*Sx, deuxd.spect[vind].Y*Sy));
  end;
  if Button = mbRight then
  begin
      PolygonH2.Clear;
      PolygonH2.Add(FixedPoint(0, aux2*Sy));PolygonH2.Add(FixedPoint(deuxd.spect[vind].X*Sx, aux2*Sy));
      PolygonV2.Clear;
      PolygonV2.Add(FixedPoint(aux1*Sx, 0));PolygonV2.Add(FixedPoint(aux1*Sx, deuxd.spect[vind].Y*Sy));
  end;

  PolygonD.Clear;
  { création de la coupe en diagonale }
  if (typeGraphCombo.text='DiagonaleX') or (typeGraphCombo.text='DiagonaleY') then
  begin PolygonD.Add(FixedPoint(Xcursor1,Ycursor1));PolygonD.Add(FixedPoint(Xcursor2,Ycursor2));end;
{  draw; }
  sendmessage(principalform.handle,wm_redessine,0,0);
  {Graph1DForm.redessiner; { verifier que graph1D EXISTE !! }
 end;
 end;
end;

{ lecture d'un fichier à partir de son numéro           }
{ INPUT : numéro du fichier à partir d'une boite texte  }
{ OUTPUT : on lit le fichier correspondant              }
procedure Tgraph2DForm.GetFileButtonClick(Sender: TObject);
var i,imax:integer;
    s,FileNr,directory:string;
    FileFound:boolean;
begin
   FileFound:=false;
   FileNr:=IntToStr(FileNrSpinEdit.Value);
   directory:=boitnoir.RepertoireManip.text;
   FileListBox.Directory:=directory;
   imax:=FileListBox.Items.Count;
   for i:=0 to imax do
   begin
      s:=FileListBox.Items[i];
      if AnsiContainsStr(s,FileNr)
      then begin
           FileFound:=true;
           { ouverture du fichier proprement dite }
           if FileTypeButton.caption='.2D' then openFile(directory+'\'+s);
           if FileTypeButton.caption='.nxs' then openFileNexus(directory+'\'+s);
           if FileTypeButton.caption='.dat' then openFilePAXY(directory+'\'+s);
           if FileTypeButton.caption='.nex' then openFileNeXuSLLB(directory+'\'+s);
           break;
           end;
   end;
   If not FileFound then MessageDlg('File not Found', mtInformation,[mbOk], 0);
end;

{ lecture d'un fichier 3 colonnes (EROS)                                       }
procedure Tgraph2DForm.Read3columnsfileXYI1Click(Sender: TObject);
var F: TextFile;
    nom:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
    nom:=ProcessFileName(opendialog1.filename);
    Read3columnsfileXYZ(OpenDialog1.FileName,nom);
    MiseAjourChoixSpectre(deuxd);
    choixspectre.Text:=nom;
    GenSampleData(nom);
  end;
  paintdata;
end;

{ lecture de points (X,Y,Z) qu'on rentre dans une matrice                       }
{ particularité de la procédure : les points n'ont pas besoin d'être "rangé"    }
{ la matrice peut être creuse  !!                                               }
{ INPUT : ligne 1 : commentaire                                                 }
{         ligne 2 : xmin, xpas, xmax                                            }
{         ligne 3 : ymin, ypas, ymax                                            }
{         ligne 4 : les points peuvent commencer                                }
{ on remplit la matrice au fur et à mesure                                      }
{ on ne fait pas de remplissage dans les trous                                  }
procedure Tgraph2DForm.ReadfreeXYZ1Click(Sender: TObject);
var F: TextFile;
    nom:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
    nom:=ProcessFileName(Opendialog1.filename);
    ReadfreeXYZ(Opendialog1.filename,nom);
    MiseAjourChoixSpectre(deuxd);
    choixspectre.Text:=nom;
    GenSampleData(nom);
  end;
  paintdata;
end;


procedure Tgraph2DForm.CheckBoxMasksClick(Sender: TObject);
begin
  if checkBoxMasks.checked
  then begin paramBox1.Enabled:=false;paramBox2.Enabled:=false;paramBox3.Enabled:=false;paramBox4.Enabled:=false;paramBox5.Enabled:=false;paramBox6.Enabled:=false end
  else begin paramBox1.Enabled:=true;paramBox2.Enabled:=true;paramBox3.Enabled:=true;paramBox4.Enabled:=true;paramBox5.Enabled:=true;paramBox6.enabled:=true end
end;

procedure Tgraph2DForm.Circularsum1Click(Sender: TObject);
var ind,ind1D:integer;
begin
   ind:=deuxd.indexof(ChoixSpectre.text);
   ind1D:=und.addspectre('SC',1,1,1);
   und.spect[ind1D]:=deuxd.spect[ind].SommeCirculaireSpectre2D('SC',Xcen.value,Ycen.value,BinningStepBox.value);
   sendmessage(principalform.handle,wm_redessine,0,0);
end;

procedure Tgraph2DForm.CalculateCircularSumButtonClick(Sender: TObject);
var ind,ind1D:integer;
begin
   ind:=deuxd.indexof(ChoixSpectre.text);
   ind1D:=und.addspectre('SC',1,1,1);
   und.spect[ind1D]:=deuxd.spect[ind].SommeCirculaireSpectre2D('SC',Xcen.value,Ycen.value,BinningStepBox.value);
   sendmessage(principalform.handle,wm_redessine,0,0);
end;

{ lecture des feuilles Glatt des data de HADAS }
procedure Tgraph2DForm.ReadHADASglatt1Click(Sender: TObject);
var F: textfile;
    nom:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
    nom:=ProcessFileName(Opendialog1.filename);
    ReadHADASglatt(OpenDialog1.FileName,nom);
    MiseAjourChoixSpectre(deuxd);
    choixspectre.Text:=nom;
    GenSampleData(nom);
  end;
  paintdata;
end;

{************************************************************}
{Procédure qui lit un spectre au format PAXE                }
{INPUT: Sender                                               }
{OUTPUT:le spectre est lu au format PAXE                     }
{REM: Origine Graph2D oldversion                             }
procedure Tgraph2DForm.ReadfromPAXE1Click(Sender: TObject);
var titre,date,heure,temps,ext,nomspectre,nom:string;
    vind,l:integer;
begin
opendialog1.initialDir:=boitnoir.RepertoireManip.text;
opendialog1.defaultExt:='*.dat';
opendialog1.filter:='*.dat|*.dat';
if opendialog1.execute then
   begin
   {extraction de l'extension}
   nomSpectre:=ProcessFileName(opendialog1.filename);
   vind:=deuxd.indexof(nomspectre);
   if vind=-1 then vind:=deuxd.addspectre(nomspectre,64,64,1);
   deuxd.spect[vind].readfromPAXE(opendialog1.filename,titre,nom,date,heure,temps);
   MiseAjourChoixSpectre(deuxd);
   choixspectre.Text:=nomspectre;
   GenSampleData(nomspectre);
   paintdata;
   CursorsReplot;
   end;
end;

{ lecture d'un fichier 3 colonnes (MATLAB                                      }
{ INPUT : fichier 3 colonnes X,Y,intensité                                     }
{ OUTPUT : on le stocke                                                        }
procedure Tgraph2DForm.ReadformMatlab1Click(Sender: TObject);
var F: TextFile;
    nom:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
    nom:=ProcessFileName(opendialog1.filename);
    ReadFromMatlab(opendialog1.filename,nom);
    MiseAjourChoixSpectre(deuxd);
    choixspectre.Text:=nom;
    GenSampleData(nom);
  end;
  paintdata;
end;

{ lecture des fichiers calculées par SMDS }
{ le probleme est qu'on a pas les tailles en X et Y                             }
{ solution "basique" : compter le nombres de lignes et prendre la racine carrée }
procedure Tgraph2DForm.Read3columnsXYZSDMS1Click(Sender: TObject);
var
  F: TextFile;
  nom:string;
begin
  if OpenDialog1.Execute then  { Affichage de la boîte de dialogue d'ouverture }
  begin
    nom:=ProcessFileName(opendialog1.filename);
    Read3columnsXYZ_SDMSfile(OpenDialog1.FileName,nom);
    MiseAjourChoixSpectre(deuxd);
    choixspectre.Text:=nom;
    GenSampleData(nom);
  end;
  paintdata;
end;

procedure Tgraph2DForm.SpeedButton2Click(Sender: TObject);
begin
    PaintData;
end;

end.


