unit F_ph_1_1;
{$D-}{$B-}{$N+}
{Overflow check:}
{$Q+}
{Range-Checking:}
{$R-}
{Stack-Checking: (Eventueller Sys-Crash, wenn aus und zu wenig Speicher)}
{$S-}
{Pentium-Bug bei der Fließkommaberechnung Prüfen:}
{$U+}


interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, TabNotBk, ExtCtrls, StdCtrls, ColorGrd, Buttons, Fasttime,
  MPlayer;

const maxWidth=800;
      maxHeight=600;

type Txyz=record
            x, y, z : extended;
          end;
     THaken=record
              Pos    : Txyz;
              length : extended;
            end;
     TAktuell=record
                 Pos      : Txyz;
                 PrevPos  : Txyz;
                 StartPos : Txyz;
                 v        : Txyz;
                 StartV   : Txyz;
                 fw       : Txyz;    {Gesamtkraft}
                 f        : Txyz;
                 a        : Txyz;
                 gewicht  : extended;
                 masse    : extended;
                 schritt  : longint;
               end;
     TMagnet=array[1..5] of record
               Pos   : Txyz;
               Kraft : extended;
             end;
     TUmgebung=record
                 Zeit        : extended;
                 dt          : extended; {Zeit, die während einer Berechnung vergeht}
                 dtp         : extended; {Zeit, die während einer Berechnung real vergeht}
                 Reibung     : extended; {Reibung=konst -> reduziert einfach die Geschwindigkeit}
                 Magnete     : integer; {Anzahl Magnete}
                 MRadius     : extended; {Radius der Magnete, wenn sie im Kreis liegen}
                 Korrektur   : boolean;
               end;
     TStoerung=record
                 time       : extended; {Wann stören, 0 für Tastendruck}
                 done, now  : boolean;  {Schon ausgeführt ?, Im nächsten Schritt stören}
                 f          : Txyz;     {Störended Kraft}
               end;
     TSpur=array[0..500] of record  {[0]=letzte Position}
               x, y : integer;
           end;
     TZeichnen=record
                 {Speed         : integer;  {Faktor, wie schnell die Animation abläuft - delay(1000/speed)}
                 spur          : integer;
                 FarbeSpur     : TColor;
                 FarbeMagnet   : TColor;
                 FarbePendel   : TColor;
                 Hintergrund   : TColor;
                 FarbeAchsen   : TColor;
                 FarbeStoerung : TColor;
                 FarbeRaster   : TColor;
                 SaveSpur      : boolean;
                 Filename      : string;
                 mx, my        : integer;
                 mass          : extended;
                 grafik        : boolean;
               end;
     TWiedergabe=record
                   files    : array[1..3] of file of extended;
                   spur     : array[1..3] of TSpur;
                   active   : array[1..3] of boolean;
                   pos      : array[1..3] of Txyz;
                   previous : array[1..3] of Txyz;
                   schritt  : longint;
                 end;
     TAnalyse=record
                mx, my             : integer;
                Info2 : record
                  counter          : integer;
                  stauchung        : integer; {Zeit-Stauchung für das Info2-Panel}
                  mass1, mass2     : longint; {Masstab für das Info2-Panel}
                end;
                Spur : record
                  size             : integer;
                  Darkness         : integer;
                  PaintTimer       : extended;
                  Files            : array[1..3] of string;
                  Umgebung         : boolean;
                  Dichte           : boolean;
                  Strecke          : boolean;
                end;
                StartP : record
                  x1, x2, y1, y2   : extended;
                  Prop             : boolean;
                  MaxRadius        : extended;
                  Steps            : integer;
                  Minimum          : integer;
                  Grafik           : boolean;
                end;
              end;
     TUsedScreen=array[0..maxWidth] of word;
     TExtFile=file of extended;
     TForm1 = class(TForm)
       TabbedNotebook: TTabbedNotebook;
    GroupBox3: TGroupBox;
    Magnet1: TGroupBox;
    Label7: TLabel;
    Label8: TLabel;
    Magnet1PosX: TEdit;
    Magnet1PosY: TEdit;
    Magnet1PosZ: TEdit;
    Magnet1Kraft: TEdit;
    Label9: TLabel;
    UmgebungMagnete: TEdit;
    Magnet2: TGroupBox;
    Label10: TLabel;
    Label11: TLabel;
    Magnet2Kraft: TEdit;
    Magnet3: TGroupBox;
    Label12: TLabel;
    Label13: TLabel;
    Magnet3Kraft: TEdit;
    Magnet4: TGroupBox;
    Label14: TLabel;
    Label15: TLabel;
    Magnet4Kraft: TEdit;
    Magnet5: TGroupBox;
    Label16: TLabel;
    Label17: TLabel;
    Magnet5Kraft: TEdit;
    Magnet2PosX: TEdit;
    Magnet2PosY: TEdit;
    Magnet2PosZ: TEdit;
    Magnet3PosX: TEdit;
    Magnet3PosY: TEdit;
    Magnet3PosZ: TEdit;
    Magnet4PosX: TEdit;
    Magnet4PosY: TEdit;
    Magnet4PosZ: TEdit;
    Magnet5PosX: TEdit;
    Magnet5PosY: TEdit;
    Magnet5PosZ: TEdit;
    Panel1: TPanel;
    Panel2: TPanel;
    Panel3: TPanel;
    Panel4: TPanel;
    Panel5: TPanel;
    GroupBox7: TGroupBox;
    ScrollBox1: TScrollBox;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    HakenLength: TEdit;
    HakenPosX: TEdit;
    HakenPosY: TEdit;
    HakenPosZ: TEdit;
    GroupBox2: TGroupBox;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    AktuellGewicht: TEdit;
    AktuellMasse: TEdit;
    AktuellPosX: TEdit;
    AktuellPosY: TEdit;
    AktuellPosZ: TEdit;
    AktuellVX: TEdit;
    AktuellVY: TEdit;
    AktuellVZ: TEdit;
    GroupBox4: TGroupBox;
    Label18: TLabel;
    Label19: TLabel;
    Label20: TLabel;
    Umgebungdt: TEdit;
    UmgebungZeit: TEdit;
    UmgebungReibung: TEdit;
    GroupBox5: TGroupBox;
    Label21: TLabel;
    Label22: TLabel;
    Label23: TLabel;
    StoerungTime: TEdit;
    StoerungFX: TEdit;
    StoerungFY: TEdit;
    StoerungFZ: TEdit;
    GroupBox6: TGroupBox;
    Label25: TLabel;
    ZeichnenSpur: TEdit;
    ZeichnenFarbeSpur: TColorGrid;
    Label26: TLabel;
    Label27: TLabel;
    ZeichnenFarbeMagnet: TColorGrid;
    Label28: TLabel;
    ZeichnenFarbePendel: TColorGrid;
    Label29: TLabel;
    ZeichnenHintergrund: TColorGrid;
    Label30: TLabel;
    ZeichnenFarbeAchsen: TColorGrid;
    Label31: TLabel;
    ZeichnenFarbeStoerung: TColorGrid;
    Label32: TLabel;
    ZeichnenMass: TEdit;
    Label34: TLabel;
    ZeichnenFilename: TEdit;
    ZeichnenSaveSpur: TCheckBox;
    EinstellungenResetButton: TPanel;
    Label33: TLabel;
    EinstellungenKreisButton: TPanel;
    Label35: TLabel;
    Label36: TLabel;
    SaveSettings: TPanel;
    Label38: TLabel;
    LoadSettings: TPanel;
    Label37: TLabel;
    StartSzene: TPanel;
    Label39: TLabel;
    Label40: TLabel;
    Label41: TLabel;
    MagneteRadius: TEdit;
    Image_s: TImage;
    Image_K: TImage;
    Image_P: TImage;
    SaveDialog: TSaveDialog;
    OpenDialog: TOpenDialog;
    GroupBox8: TGroupBox;
    Memo1: TMemo;
    KraftBerechnenButton: TButton;
    WelcheKraftPanel: TPanel;
    KraftBeschleunigend: TRadioButton;
    KraftGesamt: TRadioButton;
    ZeichenModusPanel: TPanel;
    KraftPaintMode1: TRadioButton;
    KraftPaintMode2: TRadioButton;
    ShowKraftButtons: TSpeedButton;
    Label42: TLabel;
    ZeichnenFarbeRaster: TColorGrid;
    PotentialBerechnenButton: TButton;
    PotentialHide: TSpeedButton;
    PotentialPanel: TPanel;
    PotentialZeichnen1: TRadioButton;
    PotentialPanel3: TPanel;
    Label43: TLabel;
    GenauigkeitScrollbar: TScrollBar;
    STreifenScrollbar: TScrollBar;
    Label44: TLabel;
    PotentialAufsicht: TRadioButton;
    PotentialZeichnen2: TRadioButton;
    SimulationInfopanel: TPanel;
    Label45: TLabel;
    Label46: TLabel;
    Label47: TLabel;
    Label48: TLabel;
    SimVX: TLabel;
    SimVY: TLabel;
    SimVZ: TLabel;
    SimPZ: TLabel;
    SimPY: TLabel;
    SimPX: TLabel;
    SimFZ: TLabel;
    SimFY: TLabel;
    SimFX: TLabel;
    SimAZ: TLabel;
    SimAY: TLabel;
    SimAX: TLabel;
    SimulationPanel: TPanel;
    StartButton: TButton;
    Voraussetzungen: TButton;
    SimulationPause: TButton;
    SimulationEnde: TButton;
    SimulationHide: TSpeedButton;
    InfoSimulation: TCheckBox;
    MehrBilder: TCheckBox;
    SimulationBildSpeichern: TButton;
    Button1: TButton;
    Button2: TButton;
    StoerungButton: TButton;
    Label49: TLabel;
    TimeLabel: TLabel;
    Label50: TLabel;
    SaveDialogI: TSaveDialog;
    ZeichnenGrafik: TCheckBox;
    SimulationTimer: TFastTimer;
    Label51: TLabel;
    Umgebungdtp: TEdit;
    OpenDialog2: TOpenDialog;
    NotebookAnalyse: TTabbedNotebook;
    Image_L: TImage;
    HideSpurPanel: TSpeedButton;
    SpurPanel: TPanel;
    ClearSpur: TButton;
    AnalyseSpurFiles1: TEdit;
    AnalyseSpurFiles2: TEdit;
    AnalyseSpurFiles3: TEdit;
    AnalyseSpurFiles1B: TButton;
    AnalyseSpurFiles2B: TButton;
    AnalyseSpurFiles3B: TButton;
    SpurenZeichnen: TButton;
    InfoSpurButton: TButton;
    Label52: TLabel;
    AnalyseSpurPaintTimer: TEdit;
    PaintTimer: TFastTimer;
    SpurenPause: TButton;
    SpurZeichnenEnde: TButton;
    SpurBildSpeichern: TButton;
    AnalyseSpurUmgebung: TCheckBox;
    Image_M: TImage;
    StartPunktePanelEin: TSpeedButton;
    StartPunktePanel: TPanel;
    Label53: TLabel;
    Label54: TLabel;
    Label55: TLabel;
    Label56: TLabel;
    AnalyseStartPX1: TEdit;
    AnalyseStartPX2: TEdit;
    AnalyseStartPY1: TEdit;
    AnalyseStartPY2: TEdit;
    AnalyseStartPProp: TCheckBox;
    AnalyseStartPSteps: TScrollBar;
    Label57: TLabel;
    StartPStepsLabel: TLabel;
    Label58: TLabel;
    Label59: TLabel;
    Label60: TLabel;
    AnalyseStartPMinimum: TEdit;
    StartPBerechnung: TButton;
    Label61: TLabel;
    WaitPanel: TPanel;
    Label62: TLabel;
    Label63: TLabel;
    StartPBildSpeichern: TButton;
    Image_M1: TImage;
    AnalyseStartPGrafik: TCheckBox;
    Label64: TLabel;
    Label65: TLabel;
    Label66: TLabel;
    Button3: TButton;
    Button4: TButton;
    AnalyseSpurDichte: TCheckBox;
    DichtePanel: TPanel;
    Label68: TLabel;
    AnalyseSpurSize: TEdit;
    UmgebungReibung2: TEdit;
    Label69: TLabel;
    Label70: TLabel;
    noAnalyse: TPanel;
    ErrorPanel: TPanel;
    ErrorType: TLabel;
    ErrorType1: TLabel;
    Image_Error1: TImage;
    ShowError: TCheckBox;
    Image_Error2: TImage;
    ErrorType2: TLabel;
    Label71: TLabel;
    UmgebungKorrektur: TCheckBox;
    Label72: TLabel;
    AnalyseInfo2Stauchung: TEdit;
    Label67: TLabel;
    AnalyseSpurDarkness: TEdit;
    AnalyseSpurStrecke: TRadioButton;
    AnalyseSpurZeit: TRadioButton;
    AnalyseFarbenButton: TButton;
    Label73: TLabel;
    AnalyseStartPMaxRadius: TEdit;
    Label74: TLabel;
    UmgebungKorrektur2: TCheckBox;
    PotentialColorAddBar: TScrollBar;
    PotentialColorAddLabel: TLabel;
    PotentialColorAdd: TLabel;
    PotentialBunt: TCheckBox;
    Panel6: TPanel;
    UmkehrSuchen: TButton;
    UmkehrFast: TCheckBox;
    UmkehrPaintSpur: TCheckBox;
    UmkehrPoincare: TCheckBox;
    UmkehrPoincare_mass: TScrollBar;
    Label76: TLabel;
    UmkehrGroup_Poincare: TGroupBox;
    UmkehrImage_Poincare: TImage;
    GroupBox9: TGroupBox;
    UmkehrImage_G: TImage;
    GroupBox10: TGroupBox;
    UmkehrImage_Time: TImage;
    Label24: TLabel;
    Geschwindigkeit: TLabel;
    UmkehrPoincarePanel: TPanel;
    UmkehrPunkteDick: TCheckBox;
    Label75: TLabel;
    UmkehrPunkteFarbig: TCheckBox;
    UmkehrSavePoincare: TButton;
    Panel7: TPanel;
    Label77: TLabel;
    UmkehrSaveSpur: TButton;
    UmkehrPaintPoints: TCheckBox;
    UmkehrPaintFarbig: TCheckBox;
    SimulationSaveLabel1: TLabel;
    SimulationSaveLabel2: TLabel;
    StartPRadius: TLabel;
    Label78: TLabel;
    BahnEinSettingsPanel: TPanel;
    BahnEinFileName: TEdit;
    Label79: TLabel;
    Label80: TLabel;
    BahnEinEinlesen: TButton;
    bahnEinEnde: TButton;
    Label81: TLabel;
    Button5: TButton;
    VideoOpenDialog: TOpenDialog;
    BahnEinVideoName: TLabel;
    BahnEinMediaPlayer: TMediaPlayer;
    Panel8: TPanel;
    BahnEinVideoPanel: TPanel;
    Label82: TLabel;
    BahnEinFrames: TEdit;
    BahnEinVideoTimer: TFastTimer;
    BahnEinReadingPanel: TPanel;
    BahnEinAuto: TCheckBox;
    BahnEinX2: TEdit;
    BahnEinVideoBar: TScrollBar;
    BahnEinX1: TEdit;
    BahnEinY2: TEdit;
    BahnEinY1: TEdit;
    BahnEinProp: TButton;
    BahnEinFrameLabel: TLabel;
    BahnEinXImage: TImage;
    BahnEinYImage: TImage;
    BahnEinInfoMemo: TMemo;
    KraftPaintMassScroll: TScrollBar;
    Label83: TLabel;
    CopyrightPanel: TPanel;
    CopyrightImage: TImage;
    CopyrightTimer: TFastTimer;
    CopyrightInfoLabel: TLabel;
    CopyrightMemo: TMemo;
    CopyRightDone: TButton;
    BahnCopyPanel: TPanel;
    Label84: TLabel;
    Label85: TLabel;
    Label86: TLabel;
    BahnCopyGesamt: TEdit;
    BahnCopyStart: TEdit;
    BahnCopyStop: TEdit;
    Label87: TLabel;
    BahnCopyFileName: TEdit;
    BahnCopySource: TLabel;
    Label88: TLabel;
    BahnCopyCut: TButton;
    BahnCopyPlay: TButton;
    BahnCopyImage: TImage;
    procedure FormCreate(Sender: TObject);
    procedure EinstellungenResetButtonClick(Sender: TObject);
    procedure EinstellungenKreisButtonClick(Sender: TObject);
    procedure LoadSettingsClick(Sender: TObject);
    procedure SaveSettingsClick(Sender: TObject);
    procedure StartSzeneClick(Sender: TObject);
    procedure InVariablenSpeichern(Sender: TObject);
    procedure KraftBerechnenButtonClick(Sender: TObject);
    procedure ShowKraftButtonsClick(Sender: TObject);
    procedure PotentialHideClick(Sender: TObject);
    procedure PotentialBerechnenButtonClick(Sender: TObject);
    procedure StartButtonClick(Sender: TObject);
    procedure VoraussetzungenClick(Sender: TObject);
    procedure SimulationTimerTimer(Sender: TObject);
    procedure SimulationPauseClick(Sender: TObject);
    procedure SimulationEndeClick(Sender: TObject);
    procedure SimulationHideClick(Sender: TObject);
    procedure InfoSimulationClick(Sender: TObject);
    procedure StoerungButtonClick(Sender: TObject);
    procedure SimulationBildSpeichernClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure HideSpurPanelClick(Sender: TObject);
    procedure ClearSpurClick(Sender: TObject);
    procedure EditSpurBClick(Sender: TObject);
    procedure SpurenZeichnenClick(Sender: TObject);
    procedure InfoSpurButtonClick(Sender: TObject);
    procedure PaintTimerTimer(Sender: TObject);
    procedure SpurenPauseClick(Sender: TObject);
    procedure SpurZeichnenEndeClick(Sender: TObject);
    procedure SpurBildSpeichernClick(Sender: TObject);
    procedure StartPunktePanelEinClick(Sender: TObject);
    procedure StartPBerechnungClick(Sender: TObject);
    procedure StartPBildSpeichernClick(Sender: TObject);
    procedure AnalyseSpurFiles1Change(Sender: TObject);
    procedure UmgebungReibungChange(Sender: TObject);
    procedure noAnalyseClick(Sender: TObject);
    procedure ShowErrorClick(Sender: TObject);
    procedure AnalyseFarbenButtonClick(Sender: TObject);
    procedure UmgebungKorrektur2Click(Sender: TObject);
    procedure PotentialColorAddBarChange(Sender: TObject);
    procedure PotentialBuntClick(Sender: TObject);
    procedure UmkehrSuchenClick(Sender: TObject);
    procedure UmkehrPoincareClick(Sender: TObject);
    procedure UmkehrSavePoincareClick(Sender: TObject);
    procedure UmkehrSaveSpurClick(Sender: TObject);
    procedure TabbedNotebookChange(Sender: TObject; NewTab: Integer;
      var AllowChange: Boolean);
    procedure BahnEinVideoNameChange(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure BahnEinFramesChange(Sender: TObject);
    procedure BahnEinVideoBarChange(Sender: TObject);
    procedure BahnEinVideoTimerTimer(Sender: TObject);
    procedure BahnEinMediaPlayerClick(Sender: TObject; Button: TMPBtnType;
      var DoDefault: Boolean);
    procedure BahnEinEinlesenClick(Sender: TObject);
    procedure bahnEinEndeClick(Sender: TObject);
    procedure BahnEinVideoPanelMouseUp(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure BahnEinPropClick(Sender: TObject);
    procedure BahnEinXYChange(Sender: TObject);
    procedure CopyrightTimerTimer(Sender: TObject);
    procedure CopyrightImageClick(Sender: TObject);
    procedure CopyrightInfoLabelClick(Sender: TObject);
    procedure CopyRightDoneClick(Sender: TObject);
    procedure NotebookAnalyseChange(Sender: TObject; NewTab: Integer;
      var AllowChange: Boolean);
    procedure BahnCopyPlayClick(Sender: TObject);
    procedure BahnCopyCutClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var Form1    : TForm1;
    SpurFile : file of extended;
    Haken    : THaken;
    Aktuell  : TAktuell;
    Magnet   : TMagnet;
    Umgebung : TUmgebung;
    Stoerung : TStoerung;
    Spur     : TSpur;
    Zeichnen : TZeichnen;
    NoAction : boolean;
    {Grafik}
    hi, low    : TUsedScreen;
    Wiedergabe : TWiedergabe;
    Analyse    : TAnalyse;
    {Codes für Spur-Speicherung}
    versionsCode : extended;
    ProgrammCode : extended;
    CodeStoerung : extended;
    EndeCode     : extended;
    StartDir     : string;

implementation
{$R *.DFM}


{I.Allgemeine Funktionen}

{Extended-Variable zu String / für die Ausgabe}
function ExtToStr(r : extended) : string;
var i : integer;
    t : string;
begin
  str(r:0:30,t);
  i:=length(t);
  while (t[i]='0') and (i>=1) do begin
    delete(t,i,1);
    i:=i-1;
  end;
  i:=length(t);
  if t[i]='.' then delete(t,i,1);
  ExtToStr:=t;
end;

{Integer-Variable zu Extended / zum Speichern}
procedure IntToExt(i : longint; var ext : extended);
begin
  Ext:=i;
end;

function BoolToExt(b : boolean) : extended;
begin
  if b then BoolToext:=1 else BoolToExt:=0;
end;

{Kurzer String zu Extended Variable / zum Speichern}
procedure ShortStrToExt(s : string; var ext : extended); {Bis zu 9 Stellen - kurze Dateinamen}
var c : array[0..9] of char;
    p : ^extended;
    i : byte;
    e : extended;
begin
  for i:=0 to 9 do c[i]:=s[i];
  p:=@c;
  e:=p^;
  ext:=e;
end;
procedure ExtToShortStr(ext : extended; var s : string);
type cArr=array[0..9] of char;
var c : CArr;
    p : ^cArr;
    i : byte;
begin
  p:=@ext;
  c:=p^;
  s:='         ';
  for i:=0 to 9 do s[i]:=c[i];
end;

{Gegenkathete und Ankathete über Tangens zu Winkel umrechnen}
function xyTOrad(g, a : extended) : extended;
var winkel : extended; {zwischen 0..90°}
    quad4  : extended; {Gesamtwinkel = Endergebnis}
begin
  if (a=0) then begin
    if (g>=0) then quad4:=pi/2;
    if (g<0) then quad4:=3*pi/2;
  end else begin
    winkel:=arctan(abs(g/a));
    if (a>=0) and (g>=0) then quad4:=winkel;
    if (a<0) and (g>=0) then quad4:=pi-winkel;
    if (a<0) and (g<0) then quad4:=pi+winkel;
    if (a>=0) and (g<0) then quad4:=2*pi-winkel;
  end;
  xyTOrad:=quad4;
end;

{Prozeduren für die Grafikausgabe}

procedure ColorToRGB(c : TColor; var r, g, b : integer);
var d : longint;
    rr, gg, bb : longint;
begin
  d:=c;
  bb:=d div (256*256);
  d:=d-256*256*bb;
  gg:=d div 256;
  rr:=d-256*gg;
  r:=rr; g:=gg; b:=bb;
end;

function RGBtoColor(r, g, b : integer) : TColor;
var c          : longint;
    rr, gg, bb : longint;
begin
  rr:=r; gg:=g; bb:=b;
  c:=rr+256*gg+256*256*bb;
  RGBtoColor:=c;
end;

{Für Farbauswahl die nächte passende Farbe (Index) auswählen}
{Achtung - bei RGB-Farbe (nicht Standard) funktioniert das nicht !}
{Bis auf Analysen arbeitet das Programm mit 16 vordefinierten Farben}
Procedure NextColor(c : Tcolor; var sender : TColorGrid);
var i, best     : integer;
    diff, bdiff : longint;
begin
  bdiff:=10000000;
  best:=0;
  for i:=0 to 15 do begin
    sender.foregroundIndex:=i;
    diff:=abs(sender.ForeGroundcolor-c);
    if diff<bdiff then begin
      bdiff:=diff;
      best:=i;
    end;
  end;
  sender.foregroundIndex:=best;
end;

{Für 3D-Graphen manchmal benötigt}
procedure ResetGraphArrays;
var i : word;
begin
  for i:=1 to maxWidth do begin
    hi[i]:=0;
    low[i]:=maxHeight;
  end;
end;

{Bild löschen}
procedure ClearImage(image : TImage);
begin
  image.canvas.brush.color:=zeichnen.hintergrund;
  image.canvas.fillrect(rect(0,0,image.width,image.height));
  {Zurücksetzen der Grafik-Arrays}
  ResetGraphArrays;
end;

{Einen Punkt im 3D-Modus zeichnen}
procedure PutPixel3D(x,y,z : integer; mode : byte; c : TColor; canvas : TCanvas);
var xx, yy : integer;
begin
  if mode=1 then begin
    xx:=trunc(x*0.87-y*0.87+zeichnen.mx/2);
    yy:=trunc(zeichnen.my/2-(z+x*0.5+y*0.5));
    if (xx>0) and (xx<zeichnen.mx) and (yy>0) and (yy<zeichnen.my) then
      canvas.pixels[xx,yy]:=c;
  end;
  if mode=2 then begin
    {3D}
    xx:=trunc(x*0.87-y*0.87+3*zeichnen.mx/4);
    yy:=trunc(3*zeichnen.my/4-(z+x*0.5+y*0.5));
    if (xx>0.5*zeichnen.mx) and (xx<zeichnen.mx) and (yy>0.5*zeichnen.my) and (yy<zeichnen.my) then
      canvas.pixels[xx,yy]:=c;
    {X-Y}
    xx:=trunc(x+zeichnen.mx/4);
    yy:=trunc(3*zeichnen.my/4-y);
    if (xx>0) and (xx<zeichnen.mx*0.5) and (yy>0.5*zeichnen.my) and (yy<zeichnen.my) then
      canvas.pixels[xx,yy]:=c;
    {X-Z}
    xx:=trunc(x+zeichnen.mx/4);
    yy:=trunc(zeichnen.my/4-z);
    if (xx>0) and (xx<zeichnen.mx*0.5) and (yy>0) and (yy<0.5*zeichnen.my) then
      canvas.pixels[xx,yy]:=c;
    {Y-Z}
    xx:=trunc(y+3*zeichnen.mx/4);
    yy:=trunc(zeichnen.my/4-z);
    if (xx>zeichnen.mx*0.5) and (xx<zeichnen.mx) and (yy>0) and (yy<0.5*zeichnen.my) then
      canvas.pixels[xx,yy]:=c;
  end;
end;

{Linie mit oder ohne Check für 3D}
procedure Line(x1,y1,x2,y2 : integer; mode : byte; c : TColor; canvas : TCanvas);
{Modus : 1-3 Nur 3D,    1 ohne alles, 2 mit Check und Eintrag, 3 nur Check}
var delta              : integer;
    vx, vy             : extended;
    i                  : integer;
    prev               : integer;
begin
  if mode=1 then begin
    canvas.pen.color:=c;
    canvas.moveto(x1,y1);
    canvas.lineto(x2,y2);
  end;
  if (mode=2) or (mode=3) then begin
    if abs(x2-x1)>abs(y2-y1) then delta:=abs(x2-x1) else delta:=abs(y2-y1);
    if delta<>0 then begin
      vx:=(x2-x1)/delta;
      vy:=(y2-y1)/delta;
      prev:=0;
      for i:=0 to delta do begin
        if (trunc(y1+i*vy)>hi[trunc(x1+i*vx)]) or (trunc(y1+i*vy)<low[trunc(x1+i*vx)]) or
           (trunc(x1+i*vx)=prev) then begin
          prev:=trunc(x1+i*vx);
          canvas.pixels[trunc(x1+i*vx),trunc(y1+i*vy)]:=c;
          if mode=2 then begin
            if trunc(y1+i*vy)>hi[trunc(x1+i*vx)] then hi[trunc(x1+i*vx)]:=trunc(y1+i*vy);
            if trunc(y1+i*vy)<low[trunc(x1+i*vx)] then low[trunc(x1+i*vx)]:=trunc(y1+i*vy);
          end;
        end;
      end;
    end;
  end;
end;

{Eine Linie im 3D-Modus zeichnen}
procedure Line3D(x1,y1,z1,x2,y2,z2 : integer; mode : byte; c : TColor; canvas : TCanvas);
var xx1, yy1, xx2, yy2 : integer;
    i, u, l            : integer;
    doit               : boolean;
begin
  if (mode>=1) and (mode<=3) then begin
    canvas.pen.mode:=pmMask;
    xx1:=trunc(x1*0.87-y1*0.87+zeichnen.mx/2);
    xx2:=trunc(x2*0.87-y2*0.87+zeichnen.mx/2);
    yy1:=trunc(zeichnen.my/2-(z1+x1*0.5+y1*0.5));
    yy2:=trunc(zeichnen.my/2-(z2+x2*0.5+y2*0.5));
    if (xx1>0) and (xx1<zeichnen.mx) and (yy1>0) and (yy1<zeichnen.my) and
       (xx2>0) and (xx2<zeichnen.mx) and (yy2>0) and (yy2<zeichnen.my) then begin
      line(xx1,yy1,xx2,yy2,mode,c,canvas);
    end;
    canvas.pen.mode:=pmCopy;
  end;
  if (mode>=4) and (mode<=6) then begin
    canvas.pen.color:=c;
    canvas.pen.mode:=pmMask;
    {3D}
    xx1:=trunc(x1*0.87-y1*0.87+3*zeichnen.mx/4);
    xx2:=trunc(x2*0.87-y2*0.87+3*zeichnen.mx/4);
    yy1:=trunc(3*zeichnen.my/4-(z1+x1*0.5+y1*0.5));
    yy2:=trunc(3*zeichnen.my/4-(z2+x2*0.5+y2*0.5));
    if (xx1>0.5*zeichnen.mx) and (xx1<zeichnen.mx) and (yy1>0.5*zeichnen.my) and (yy1<zeichnen.my) and
       (xx2>0.5*zeichnen.mx) and (xx2<zeichnen.mx) and (yy2>0.5*zeichnen.my) and (yy2<zeichnen.my) then begin
      line(xx1,yy1,xx2,yy2,mode-3,c,canvas);
    end;
    {X-Y}
    xx1:=trunc(x1+zeichnen.mx/4);
    xx2:=trunc(x2+zeichnen.mx/4);
    yy1:=trunc(3*zeichnen.my/4-y1);
    yy2:=trunc(3*zeichnen.my/4-y2);
    if (xx1>0) and (xx1<zeichnen.mx*0.5) and (yy1>0.5*zeichnen.my) and (yy1<zeichnen.my) and
       (xx2>0) and (xx2<zeichnen.mx*0.5) and (yy2>0.5*zeichnen.my) and (yy2<zeichnen.my) then begin
      line(xx1,yy1,xx2,yy2,1,c,canvas);
    end;
    {X-Z}
    xx1:=trunc(x1+zeichnen.mx/4);
    xx2:=trunc(x2+zeichnen.mx/4);
    yy1:=trunc(zeichnen.my/4-z1);
    yy2:=trunc(zeichnen.my/4-z2);
    if (xx1>0) and (xx1<zeichnen.mx*0.5) and (yy1>0) and (yy1<0.5*zeichnen.my) and
       (xx2>0) and (xx2<zeichnen.mx*0.5) and (yy2>0) and (yy2<0.5*zeichnen.my) then begin
      line(xx1,yy1,xx2,yy2,1,c,canvas);
    end;
    {Y-Z}
    xx1:=trunc(y1+3*zeichnen.mx/4);
    xx2:=trunc(y2+3*zeichnen.mx/4);
    yy1:=trunc(zeichnen.my/4-z1);
    yy2:=trunc(zeichnen.my/4-z2);
    if (xx1>zeichnen.mx*0.5) and (xx1<zeichnen.mx) and (yy1>0) and (yy1<0.5*zeichnen.my) and
       (xx2>zeichnen.mx*0.5) and (xx2<zeichnen.mx) and (yy2>0) and (yy2<0.5*zeichnen.my) then begin
      line(xx1,yy1,xx2,yy2,1,c,canvas);
    end;
    canvas.pen.mode:=pmCopy;
  end;
end;

{Ein kleines Koordinatensystem im 3D-Modus zeichnen}
procedure KoSystem(canvas : TCanvas; mode : byte);
begin
  line3D(0,0,0,100,0,0,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,0,0,0,100,0,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,0,0,0,0,100,mode,zeichnen.FarbeAchsen,canvas);
  {Pfeile}
  {X}
  line3D(100,0,0,85,0,10,mode,zeichnen.FarbeAchsen,canvas);
  line3D(100,0,0,85,0,-10,mode,zeichnen.FarbeAchsen,canvas);
  line3D(100,0,0,85,10,0,mode,zeichnen.FarbeAchsen,canvas);
  line3D(100,0,0,85,-10,0,mode,zeichnen.FarbeAchsen,canvas);
  {Y}
  line3D(0,100,0,0,85,10,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,100,0,0,85,-10,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,100,0,10,85,0,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,100,0,-10,85,0,mode,zeichnen.FarbeAchsen,canvas);
  {Z}
  line3D(0,0,100,10,0,85,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,0,100,-10,0,85,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,0,100,0,10,85,mode,zeichnen.FarbeAchsen,canvas);
  line3D(0,0,100,0,-10,85,mode,zeichnen.FarbeAchsen,canvas);
end;

{Nächte Farbe für die Dichte auswählen. Diese Farben müssen bunt sein, da sich
in Delphi sonst Probleme mit der Anzahl der Graustufen ergeben können}
function IncColor(d : longint; c : integer) : TColor;
var r, g, b : integer;
    e       : longint;
begin
  ColorToRGB(d,r,g,b);
  if (g=255) and (r>c) and (b>c) then begin
    dec(r,c);
    dec(b,c);
  end else
  if (g=255) and (b<=c) and (r<(255-2*c)) then begin
    inc(r,2*c);
  end else
  if (r>=(255-2*c)) and (g>c) and (b<=c) then begin
    dec(g,c);
    r:=255;
  end else
  if (g<=c) and (r=255) and (b<(255-c)) then begin
    inc(b,c);
  end else
  if (r>c) and (b>=(255-c)) and (g<=c) then begin
    dec(r,c);
    b:=255;
  end else
  if (b>c) then dec(b,c);
  e:=RGBtoColor(r,g,b);
  IncColor:=e;
end;

{Für die Dichte-Bestimmung eine Linie im Raster [Size] zeichnen oder
den Punkt x1, y1 im Raster eintragen (ja nach [aktuell.strecke])}
procedure ExtraLine(x1, y1, x2, y2 : Integer; size : integer; canvas : TCanvas);
var vx, vy  : extended;
    i       : integer;
    dx, dy  : integer;
    c, d, e : Longint;
    max     : integer;
    nx, ny  : integer;
    x, y    : integer;
    r, g, b : integer;
begin
  c:=analyse.Spur.darkness;
  canvas.pen.mode:=pmcopy;
  if analyse.spur.strecke then begin
    dx:=x2-x1;
    dy:=y2-y1;
    if abs(dx)>abs(dy) then max:=abs(dx)
                       else max:=abs(dy);
    if not (max=0) then begin
      vx:=dx/max;
      vy:=dy/max;
      for i:=1 to max-1 do begin {Max-1, um den Endpunkt nur einmal zu zeichnen}
        nx:=x1+trunc(vx*i);
        ny:=y1+trunc(vy*i);
        {Rastern}
        nx:=size*trunc(nx/size);
        ny:=size*trunc(ny/size);
        {Und zeichnen}
        d:=canvas.pixels[nx,ny];           {Vorherige Farbe: d}
        e:=IncColor(d,c);                  {"Nächste" Farbe: e}
        for x:=nx to nx+size-1 do begin
          for y:=ny to ny+size-1 do begin
            canvas.pixels[x,y]:=e;
          end;
        end;
      end;
    end;
  end else begin
    {Rastern}
    nx:=x1; ny:=y1;
    nx:=size*trunc(nx/size);
    ny:=size*trunc(ny/size);
    d:=canvas.pixels[nx,ny];
    e:=IncColor(d,c);
    for x:=nx to nx+size-1 do begin
      for y:=ny to ny+size-1 do begin
        canvas.pixels[x,y]:=e;
      end;
    end;
  end;
end;

procedure ExtraPoint(x1, y1 : Integer; size : integer; canvas : TCanvas);
var vx, vy  : extended;
    i       : integer;
    dx, dy  : integer;
    c, d, e : Longint;
    max     : integer;
    nx, ny  : integer;
    x, y    : integer;
    r, g, b : integer;
begin
  c:=analyse.Spur.darkness;
  canvas.pen.mode:=pmcopy;
  begin
    {Rastern}
    nx:=x1; ny:=y1;
    nx:=size*trunc(nx/size);
    ny:=size*trunc(ny/size);
    d:=canvas.pixels[nx,ny];
    e:=IncColor(d,c);
    for x:=nx to nx+size-1 do begin
      for y:=ny to ny+size-1 do begin
        canvas.pixels[x,y]:=e;
      end;
    end;
  end;
end;

procedure UmgebungZeichnen(Image : TImage);
var i, j    : integer;
    x, y    : integer;
    s       : string;
begin
  with Image do begin
    with canvas do begin
      pen.mode:=pmCopy;
      font.name:='Arial';
      font.size:=8;
      font.color:=zeichnen.farbemagnet;
      pen.color:=zeichnen.farbemagnet;
      brush.color:=zeichnen.Hintergrund;
      for i:=1 to umgebung.magnete do with magnet[i] do begin
        x:=trunc(pos.x*zeichnen.mass+zeichnen.mx/2);
        y:=trunc(zeichnen.my/2-pos.y*zeichnen.mass);
        for j:=1 to 100 do begin
          pixels[trunc(x+12*cos(j*2*pi/100)),trunc(y+12*sin(j*2*pi/100))]:=zeichnen.farbeMagnet;
        end;
        str(i,s);
        textout(trunc(x-textwidth(s)/2),trunc(y-textheight(s)/2),s);
      end;
      {Haken}
      font.color:=zeichnen.farbemagnet;
      pen.color:=zeichnen.farbemagnet;
      brush.color:=zeichnen.Hintergrund;
      x:=trunc(haken.pos.x*zeichnen.mass+zeichnen.mx/2);
      y:=trunc(zeichnen.my/2-haken.pos.y*zeichnen.mass);
      rectangle(x-10,y-10,x+10,y+10);
      s:='H';
      textout(trunc(x-textwidth(s)/2),trunc(y-textheight(s)/2),s);
      {Maximaler Radius}
      for i:=1 to 2000 do begin
        x:=trunc(cos(i/1000*pi)*haken.length*zeichnen.mass+zeichnen.mx/2+haken.pos.x*zeichnen.mass);
        y:=trunc(zeichnen.my/2-sin(i/1000*pi)*haken.length*zeichnen.mass-haken.pos.y*zeichnen.mass);
        pixels[x,y]:=zeichnen.FarbeRaster;
      end;
    end;
  end;
end;

{III. Methoden für Einstellungen (laden, speichern, Bildschirm<->Variablen, Reset)}

{Einstellungen - Standardeinstellungen in Variablen speichern}
procedure GetStandard;
var i      : integer;
    rad    : extended;
begin
  with Haken do begin
    with Pos do begin
      x:=0;
      y:=0;
      z:=0.30;
    end;
    length:=0.25;
  end;
  with Aktuell do begin
    with StartPos do begin
      x:=0.1;
      y:=0.1;
      {dx²+dy²+dz²=length²}
      {z²=length²-x²-y²}
      z:=Haken.pos.z-sqrt(Haken.length*haken.length-
         (x-haken.pos.x)*(x-haken.pos.x)-(y-haken.pos.y)*(y-haken.pos.y));
    end;
    Pos:=StartPos;
    Schritt:=0;
    with StartV do begin
      x:=0;
      y:=0;
      z:=0;
    end;
    V:=StartV;
    masse:=0.500;
    gewicht:=9.81*masse;
  end;
  for i:=0 to 2 do with Magnet[i+1] do begin
    with pos do begin
      rad:=2*pi/3*i;
      x:=0.1*cos(rad);
      y:=0.1*sin(rad);
      z:=0;
    end;
    Kraft:=200;
  end;
  for i:=4 to 5 do with magnet[i] do begin
    with pos do begin
      x:=0;
      y:=0;
      z:=0;
    end;
    Kraft:=100;
  end;
  with umgebung do begin
    Zeit:=0;
    dt:=0.008;
    dtp:=0.03;
    Reibung:=0.001;
    Korrektur:=false;
    magnete:=3;
    Mradius:=0.1;
  end;
  with Stoerung do begin
    time:=0;
    done:=false;
    now:=false;
    with f do begin
      x:=0.01;
      y:=0;
      z:=0;
    end;
  end;
  for i:=1 to 500 do with Spur[i] do begin
    x:=0; y:=0;
  end;
  with Zeichnen do begin
    {Speed:=5;}
    spur:=0;
    FarbeSpur:=clred;
    FarbeMagnet:=clfuchsia;
    FarbePendel:=clblue;
    Hintergrund:=clwhite;
    FarbeAchsen:=clblack;
    FarbeStoerung:=clgreen;
    FarbeRaster:=clLime;
    SaveSpur:=false;
    Filename:='';
    mx:=form1.image_s.width;
    my:=form1.image_s.height;
    mass:=800;
    grafik:=true;
  end;
  with Analyse do begin
    mx:=form1.image_l.width;
    my:=form1.image_l.height;
    {Weil mit den Massen von Image_L die Umgebung nicht mit der Spur übereinstimmt !}
    with Info2 do begin
      stauchung:=4;
    end;
    with Spur do begin
      size:=6;
      darkness:=25;
      PaintTimer:=0.05;
      files[1]:=''; files[2]:=''; files[3]:='';
      umgebung:=false;
      dichte:=false;
      strecke:=true;
    end;
    with StartP do begin
      x1:=-0.4; x2:=0.4; y1:=-0.28; y2:=0.28;
      prop:=true;
      MaxRadius:=haken.length;
      Steps:=4;
      Minimum:=300;
      Grafik:=false;
    end;
  end;
  {Pendel unter seiner Aufhängung}
  if aktuell.pos.z>haken.pos.z then begin
    Messagedlg('Das Pendel befindet sich über seiner Aufhängung !'+chr(13)+
               'Programm wird beendet !'+#13+
               'Sie sollten vielleicht die Aufhängung höher einstellen.',mtwarning,[mbok],0);
    halt(1);
  end;
end;

{Einstellungen - Aktuelle Einstellungen auf den Bildschirm}
procedure SetVar;
var i : integer;
begin
  NoAction:=true;
  with form1 do begin
    with haken do begin
      with Pos do begin
        HakenPosX.text:=exttostr(x);
        HakenPosY.text:=exttostr(y);
        HakenPosZ.text:=exttostr(z);
      end;
      HakenLength.text:=exttostr(Length);
      StartPRadius.caption:=exttostr(Length);
    end;
    with Aktuell do begin
      with StartPos do begin
        AktuellPosX.text:=extToStr(x);
        AktuellPosY.text:=extToStr(y);
        AktuellPosZ.text:=extToStr(z);
      end;
      with StartV do begin
        AktuellVX.text:=extToStr(x);
        AktuellVY.text:=extToStr(y);
        AktuellVZ.text:=extToStr(z);
      end;
      AktuellMasse.text:=extToStr(masse);
      AktuellGewicht.text:=extToStr(gewicht);
    end;
    with Magnet[1] do begin
      with Pos do begin
        Magnet1PosX.text:=extToStr(x);
        Magnet1PosY.text:=extToStr(y);
        Magnet1PosZ.text:=extToStr(z);
      end;
      Magnet1Kraft.text:=extToStr(Kraft);
    end;
    with Magnet[2] do begin
      with Pos do begin
        Magnet2PosX.text:=extToStr(x);
        Magnet2PosY.text:=extToStr(y);
        Magnet2PosZ.text:=extToStr(z);
      end;
      Magnet2Kraft.text:=extToStr(Kraft);
    end;
    with Magnet[3] do begin
      with Pos do begin
        Magnet3PosX.text:=extToStr(x);
        Magnet3PosY.text:=extToStr(y);
        Magnet3PosZ.text:=extToStr(z);
      end;
      Magnet3Kraft.text:=extToStr(Kraft);
    end;
    with Magnet[4] do begin
      with Pos do begin
        Magnet4PosX.text:=extToStr(x);
        Magnet4PosY.text:=extToStr(y);
        Magnet4PosZ.text:=extToStr(z);
      end;
      Magnet4Kraft.text:=extToStr(Kraft);
    end;
    with Magnet[5] do begin
      with Pos do begin
        Magnet5PosX.text:=extToStr(x);
        Magnet5PosY.text:=extToStr(y);
        Magnet5PosZ.text:=extToStr(z);
      end;
      Magnet5Kraft.text:=extToStr(Kraft);
    end;
    with Umgebung do begin
      UmgebungZeit.text:=exttostr(Zeit);
      Umgebungdt.text:=exttostr(dt);
      Umgebungdtp.text:=exttostr(dtp);
      UmgebungReibung.text:=exttostr(Reibung);
      UmgebungMagnete.text:=inttostr(Magnete);
      UmgebungKorrektur.checked:=Korrektur;
      UmgebungKorrektur2.checked:=Korrektur;
      if magnete>=1 then Magnet1.visible:=true else Magnet1.visible:=false;
      if magnete>=2 then Magnet2.visible:=true else Magnet2.visible:=false;
      if magnete>=3 then Magnet3.visible:=true else Magnet3.visible:=false;
      if magnete>=4 then Magnet4.visible:=true else Magnet4.visible:=false;
      if magnete>=5 then Magnet5.visible:=true else Magnet5.visible:=false;
      MagneteRadius.text:=exttostr(umgebung.mradius);
    end;
    with Stoerung do begin
      StoerungTime.text:=exttostr(time);
      with f do begin
        StoerungfX.text:=exttostr(x);
        StoerungfY.text:=exttostr(y);
        StoerungfZ.text:=exttostr(z);
      end;
    end;
    with Zeichnen do begin
      {ZeichnenSpeed.text:=inttostr(speed);}
      ZeichnenSpur.text:=inttostr(spur);
      NextColor(FarbeSpur,ZeichnenFarbeSpur);
      NextColor(FarbeMagnet,ZeichnenFarbeMagnet);
      NextColor(FarbePendel,ZeichnenFarbePendel);
      NextColor(Hintergrund,ZeichnenHintergrund);
      NextColor(FarbeAchsen,ZeichnenFarbeAchsen);
      NextColor(FarbeStoerung,ZeichnenFarbeStoerung);
      NextColor(FarbeRaster,ZeichnenFarbeRaster);
      ZeichnenSaveSpur.checked:=SaveSpur;
      if SaveSpur then ZeichnenFilename.enabled:=true else ZeichnenFilename.enabled:=false;
      ZeichnenFilename.text:=filename;
      ZeichnenMass.text:=exttostr(mass);
      ZeichnenGrafik.checked:=grafik;
    end;
    with Analyse do begin
      with Info2 do begin
        AnalyseInfo2Stauchung.text:=inttostr(stauchung);
      end;
      with Spur do begin
        AnalyseSpurSize.text:=inttostr(size);
        AnalyseSpurDarkness.text:=inttostr(darkness);
        AnalyseSpurPaintTimer.text:=exttostr(PaintTimer);
        AnalyseSpurFiles1.text:=files[1];
        AnalyseSpurFiles2.text:=files[2];
        AnalyseSpurFiles2.text:=files[3];
        AnalyseSpurUmgebung.checked:=umgebung;
        AnalyseSpurDichte.checked:=dichte;
        AnalyseSpurStrecke.checked:=strecke;
      end;
      with StartP do begin
        AnalyseStartPx1.text:=exttostr(x1);
        AnalyseStartPy1.text:=exttostr(y1);
        AnalyseStartPx2.text:=exttostr(x2);
        AnalyseStartPy2.text:=exttostr(y2);
        AnalyseStartPProp.checked:=prop;
        AnalyseStartPMaxRadius.text:=exttostr(MaxRadius);
        if (MaxRadius<haken.length) then begin
          AnalyseStartPMaxRadius.color:=clyellow;
          Label74.color:=clyellow;
        end else begin
          AnalyseStartPMaxRadius.color:=clwindow;
          Label74.color:=clwindow;
        end;
        AnalyseStartPSteps.position:=steps;
        StartPStepsLabel.caption:=inttostr(steps+1);
        AnalyseStartPMinimum.text:=exttostr(Minimum);
        AnalyseStartPGrafik.checked:=grafik;
      end;
    end;
  end;
  NoAction:=false;
end;

{Einstellungen - Einstellungen vom Bildschirm übernehmen}
procedure GetVar;
var i          : integer;
    code       : integer;
    dx, dy, dz : extended;
    s          : string;
    tx, ty     : integer;
begin
  if not noAction then with form1 do begin
    with haken do begin
      with pos do begin
        val(HakenPosX.text,x,code);
        val(HakenPosY.text,y,code);
        val(HakenPosZ.text,z,code);
      end;
      val(HakenLength.text,length,code);
    end;
    with Aktuell do begin
      with StartPos do begin
        val(AktuellPosX.text,x,code);
        val(AktuellPosY.text,y,code);
        dx:=x-haken.pos.x;
        dy:=y-haken.pos.y;
        if (dx*dx+dy*dy)<=haken.length*haken.length then begin
          dz:=sqrt(haken.length*haken.length-dx*dx-dy*dy);
          z:=haken.pos.z-dz;
        end else begin
          AktuellPosX.text:='-0';
          AktuellPosX.text:='-0';
          x:=0;
          y:=0;
        end;
        AktuellPosZ.text:=exttostr(z);
      end;
      with StartV do begin
        val(AktuellVX.text,x,code);
        val(AktuellVY.text,y,code);
        val(AktuellVZ.text,z,code);
      end;
      val(AktuellMasse.text,masse,code);
      val(AktuellGewicht.text,gewicht,code);
    end;
    with Magnet[1] do begin
      with Pos do begin
        val(Magnet1PosX.text,x,code);
        val(Magnet1PosY.text,y,code);
        val(Magnet1PosZ.text,z,code);
      end;
      val(Magnet1Kraft.text,Kraft,code);
    end;
    with Magnet[2] do begin
      with Pos do begin
        val(Magnet2PosX.text,x,code);
        val(Magnet2PosY.text,y,code);
        val(Magnet2PosZ.text,z,code);
      end;
      val(Magnet2Kraft.text,Kraft,code);
    end;
    with Magnet[3] do begin
      with Pos do begin
        val(Magnet3PosX.text,x,code);
        val(Magnet3PosY.text,y,code);
        val(Magnet3PosZ.text,z,code);
      end;
      val(Magnet3Kraft.text,Kraft,code);
    end;
    with Magnet[4] do begin
      with Pos do begin
        val(Magnet4PosX.text,x,code);
        val(Magnet4PosY.text,y,code);
        val(Magnet4PosZ.text,z,code);
      end;
      val(Magnet4Kraft.text,Kraft,code);
    end;
    with Magnet[5] do begin
      with Pos do begin
        val(Magnet5PosX.text,x,code);
        val(Magnet5PosY.text,y,code);
        val(Magnet5PosZ.text,z,code);
      end;
      val(Magnet5Kraft.text,Kraft,code);
    end;
    with Umgebung do begin
      val(UmgebungZeit.text,Zeit,code);
      val(Umgebungdt.text,dt,code);
      val(Umgebungdtp.text,dtp,code);
      val(UmgebungReibung.text,Reibung,code);
      Korrektur:=UmgebungKorrektur.checked;
      UmgebungKorrektur2.checked:=Korrektur;
      val(UmgebungMagnete.text,Magnete,code);
      if magnete>=1 then Magnet1.visible:=true else Magnet1.visible:=false;
      if magnete>=2 then Magnet2.visible:=true else Magnet2.visible:=false;
      if magnete>=3 then Magnet3.visible:=true else Magnet3.visible:=false;
      if magnete>=4 then Magnet4.visible:=true else Magnet4.visible:=false;
      if magnete>=5 then Magnet5.visible:=true else Magnet5.visible:=false;
      val(MagneteRadius.text,mradius,code);
    end;
    with Stoerung do begin
      val(StoerungTime.text,time,code);
      with f do begin
        val(StoerungfX.text,x,code);
        val(StoerungfY.text,y,code);
        val(StoerungfZ.text,z,code);
      end;
      StoerungButton.enabled:=(Time=0);
    end;
    with Zeichnen do begin
      {val(ZeichnenSpeed.text,speed,code);}
      val(ZeichnenSpur.text,spur,code);
      if spur>500 then begin spur:=500; ZeichnenSpur.text:='500'; end;
      FarbeSpur:=ZeichnenFarbeSpur.ForeGroundColor;
      FarbeMagnet:=ZeichnenFarbeMagnet.ForeGroundColor;
      FarbePendel:=ZeichnenFarbePendel.ForeGroundColor;
      Hintergrund:=ZeichnenHintergrund.ForeGroundColor;
      FarbeAchsen:=ZeichnenFarbeAchsen.ForeGroundColor;
      FarbeStoerung:=ZeichnenFarbeStoerung.ForeGroundColor;
      FarbeRaster:=ZeichnenFarbeRaster.ForeGroundColor;
      SaveSpur:=ZeichnenSaveSpur.checked;
      if SaveSpur then ZeichnenFilename.enabled:=true else ZeichnenFilename.enabled:=false;
      filename:=ZeichnenFilename.text;
      val(ZeichnenMass.text,mass,code);
      grafik:=zeichnenGrafik.checked;
    end;
    with Analyse do begin
      with Info2 do begin
        val(AnalyseInfo2Stauchung.text,stauchung,code);
        if Stauchung<1 then Stauchung:=1;
      end;
      with Spur do begin
        val(AnalyseSpurSize.text,size,code);
        val(AnalyseSpurDarkness.text,darkness,code);
        val(AnalyseSpurPaintTimer.text,PaintTimer,code);
        files[1]:=AnalyseSpurFiles1.text;
        files[2]:=AnalyseSpurFiles2.text;
        files[3]:=AnalyseSpurFiles3.text;
        umgebung:=AnalyseSpurUmgebung.checked;
        dichte:=AnalyseSpurDichte.checked;
        strecke:=AnalyseSpurStrecke.checked;
        if size<1 then size:=1;
        if Darkness<0 then Darkness:=0;
        if Darkness>255 then Darkness:=255;
        if umgebung then begin
          tx:=zeichnen.mx;
          ty:=zeichnen.my;
          zeichnen.mx:=analyse.mx;
          zeichnen.my:=analyse.my;
          UmgebungZeichnen(Form1.Image_L);
          zeichnen.mx:=tx;
          zeichnen.my:=ty;
        end else
          ClearImage(Form1.Image_L);
        DichtePanel.visible:=dichte;
        AnalyseSpurFiles2.enabled:=not dichte;
        AnalyseSpurFiles3.enabled:=not dichte;
        AnalyseSpurFiles2B.enabled:=not dichte;
        AnalyseSpurFiles3B.enabled:=not dichte;
      end;
      with StartP do begin
        val(AnalyseStartPx1.text,x1,code);
        val(AnalyseStartPy1.text,y1,code);
        val(AnalyseStartPx2.text,x2,code);
        val(AnalyseStartPy2.text,y2,code);
        prop:=AnalyseStartPProp.checked;
        val(AnalyseStartPMaxRadius.text,MaxRadius,code);
        Steps:=AnalyseStartPSteps.position;
        val(AnalyseStartPMinimum.text,Minimum,code);
        Grafik:=AnalyseStartPGrafik.checked;
        if (MaxRadius>haken.length) then begin
          MaxRadius:=haken.length;
          AnalyseStartPMaxRadius.text:=extToStr(MaxRadius);
        end;
        if (MaxRadius<haken.length) then begin
          Label74.color:=clyellow;
          AnalyseStartPMaxRadius.color:=clyellow;
        end else begin
          Label74.color:=clwindow;
          AnalyseStartPMaxRadius.color:=clwindow;
        end;
        If Prop then begin
          AnalyseStartPY2.enabled:=false;
          dx:=abs(x2-x1);
          dy:=my*dx/mx;
          y2:=y1+dy;
          AnalyseStartPY2.text:=exttostr(y2);
        end else AnalyseStartPY2.enabled:=true;
        StartPStepsLabel.caption:=inttostr(steps+1);
      end;
    end;
  end;
end;

{Einstellungen zurücksetzen}
procedure TForm1.EinstellungenResetButtonClick(Sender: TObject);
begin
  GetStandard;
  SetVar;
end;

{Magnete im Kreis anordnen}
procedure TForm1.EinstellungenKreisButtonClick(Sender: TObject);
var i   : integer;
    rad : extended;
begin
  for i:=0 to umgebung.magnete-1 do begin
    rad:=2*pi/umgebung.magnete*i;
    magnet[i+1].pos.x:=umgebung.mradius*cos(rad);
    magnet[i+1].pos.y:=umgebung.mradius*sin(rad);
  end;
  setvar;
end;

{Einstellungen - Laden}
Procedure PLoadSettings(var sfile : TExtFile);
var i        : integer;
    ext      : extended;
    vr       : array[1..3] of extended;
begin
  begin
    begin
      read(sfile,vr[1],vr[2]); {Versionsnummer checken}
      if vr[1]<>versionsCode then messagedlg('Diese Datei ist nicht von'+chr(13)+
                                             'der aktuellen Version gespeichert'+#13+
                                             'worden oder keine Datei, die'+#13+
                                             'Daten für Einstellungen enthält',mtwarning,[mbcancel],0) else begin
          if vr[2]<>ProgrammCode then begin
                                    messagedlg('Diese Datei enthält keine'+#13+
                                               'Einstellungen',mtwarning,[mbcancel],0) end else begin
          with haken do begin
            with Pos do begin
              read(sfile,vr[1],vr[2],vr[3]);
              x:=vr[1]; y:=vr[2]; z:=vr[3];
            end;
            read(sfile,vr[1]);
            length:=vr[1];
          end;
          with Aktuell do begin
            with StartPos do begin
              read(sfile,vr[1],vr[2],vr[3]);
              x:=vr[1]; y:=vr[2]; z:=vr[3];
            end;
            pos:=StartPos;
            with StartV do begin
              read(sfile,vr[1],vr[2],vr[3]);
              x:=vr[1]; y:=vr[2]; z:=vr[3];
            end;
            read(sfile,vr[1]);
            masse:=vr[1];
            read(sfile,vr[1]);
            gewicht:=vr[1];
          end;
          for i:=1 to 5 do with Magnet[i] do begin
            with Pos do begin
              read(sfile,vr[1],vr[2],vr[3]);
              x:=vr[1]; y:=vr[2]; z:=vr[3];
            end;
            read(sfile,vr[1]);
            Kraft:=vr[1];
          end;
          with Umgebung do begin
            read(sfile,vr[1]);
            Zeit:=vr[1];
            read(sfile,vr[1]);
            dt:=vr[1];
            read(sfile,vr[1]);
            dtp:=vr[1];
            read(sfile,vr[1]);
            reibung:=vr[1];
            read(sfile,vr[1]);
            Korrektur:=(vr[1]=1);
            read(sfile,vr[1]);
            magnete:=round(vr[1]);
            read(sfile,vr[1]);
            umgebung.mradius:=vr[1];
          end;
          with Stoerung do begin
            read(sfile,vr[1]);
            time:=vr[1];
            with f do begin
              read(sfile,vr[1],vr[2],vr[3]);
              x:=vr[1]; y:=vr[2]; z:=vr[3];
            end;
            Form1.StoerungButton.enabled:=(Time=0);
          end;
          with Zeichnen do begin
            read(sfile,vr[1]);
            {speed:=round(vr[1]);}
            read(sfile,vr[1]);
            spur:=round(vr[1]);
            read(sfile,vr[1]);
            farbeSpur:=round(vr[1]);
            read(sfile,vr[1]);
            FarbeMagnet:=round(vr[1]);
            read(sfile,vr[1]);
            FarbePendel:=round(vr[1]);
            read(sfile,vr[1]);
            Hintergrund:=round(vr[1]);
            read(sfile,vr[1]);
            FarbeAchsen:=round(vr[1]);
            read(sfile,vr[1]);
            FarbeStoerung:=round(vr[1]);
            read(sfile,vr[1]);
            FarbeRaster:=round(vr[1]);
            read(sfile,vr[1]);
            if vr[1]=1 then savespur:=true else SaveSpur:=false;
            read(sfile,vr[1]);
            ExtToShortStr(vr[1],filename);
            read(sfile,vr[1]);
            mass:=vr[1];
            read(sfile,vr[1]);
            if vr[1]>0 then grafik:=true else grafik:=false;
          end;
          with Analyse do begin
            with Info2 do begin
              read(sfile,vr[1]); stauchung:=round(vr[1]);
              if Stauchung<1 then Stauchung:=1;
            end;
            with Spur do begin
              read(sfile,vr[1]); size:=round(vr[1]);
              read(sfile,vr[1]); darkness:=round(vr[1]);
              read(sfile,vr[1]); PaintTimer:=vr[1];
              read(sfile,vr[1]); exttoShortStr(vr[1],files[1]);
              read(sfile,vr[1]); exttoShortStr(vr[1],files[2]);
              read(sfile,vr[1]); exttoshortStr(vr[1],files[3]);
              read(sfile,vr[1]); umgebung:=(vr[1]=1);
              read(sfile,vr[1]); dichte:=(vr[1]=1);
              read(sfile,vr[1]); strecke:=(vr[1]=1);
              if size<1 then size:=1;
              if Darkness<0 then Darkness:=0;
              if Darkness>255 then Darkness:=255;
            end;
            with StartP do begin
              read(sfile,vr[1]); x1:=vr[1];
              read(sfile,vr[1]); y1:=vr[1];
              read(sfile,vr[1]); x2:=vr[1];
              read(sfile,vr[1]); y2:=vr[1];
              read(sfile,vr[1]); prop:=(vr[1]=1);
              read(sfile,vr[1]); MaxRadius:=vr[1];
              read(sfile,vr[1]); Steps:=round(vr[1]);
              read(sfile,vr[1]); Minimum:=round(vr[1]);
              read(sfile,vr[1]); Grafik:=(vr[1]=1);
            end;
          end;
          read(sfile,vr[1]);
          if ProgrammCode<>vr[1] then begin
            messagedlg('Beim Laden traten Fehler auf !',mtwarning,[mbok],0);
          end;
        end;
      end;
    end;
  end;
end;
procedure TForm1.LoadSettingsClick(Sender: TObject);
var sfile    : TExtFile;
begin
  with form1 do begin
    {Datei festlegen}
    OpenDialog.filename:='*.MPS';
    if OpenDialog.execute then begin
      assignfile(sfile,OpenDialog.filename);
      reset(sfile);
      PLoadSettings(sfile);
      closefile(sfile);
    end;
  end;
  chDir(Startdir);
  SetVar;
end;

{Einstellung - Speichern}
procedure PSaveSettings(var sfile : TExtFile);
var i        : integer;
    ext      : extended;
begin
  begin
    begin
      write(sfile,VersionsCode,ProgrammCode); {Versionsnummer}
      with haken do begin
        with Pos do begin
          write(sfile,x,y,z);
        end;
        write(sfile,length);
      end;
      with Aktuell do begin
        with StartPos do begin
          write(sfile,x,y,z);
        end;
        with StartV do begin
          write(sfile,x,y,z);
        end;
        write(sfile,masse);
        write(sfile,gewicht);
      end;
      for i:=1 to 5 do with Magnet[i] do begin
        with Pos do begin
          write(sfile,x,y,z);
        end;
        write(sfile,Kraft);
      end;
      with Umgebung do begin
        write(sfile,Zeit);
        write(sfile,dt);
        write(sfile,dtp);
        write(sfile,Reibung);
        If Korrektur then ext:=1 else ext:=0;
        write(sfile,ext);
        IntToExt(Magnete,ext);
        write(sfile,ext);
        write(sfile,umgebung.mradius);
      end;
      with Stoerung do begin
        write(sfile,time);
        with f do begin
          write(sfile,x,y,z);
        end;
      end;
      with Zeichnen do begin
        {IntToExt(speed,ext);}
        write(sfile,ext);
        IntToExt(spur,ext);
        write(sfile,ext);
        IntToExt(FarbeSpur,ext);
        write(sfile,ext);
        IntToExt(FarbeMagnet,ext);
        write(sfile,ext);
        IntToExt(FarbePendel,ext);
        write(sfile,ext);
        IntToExt(Hintergrund,ext);
        write(sfile,ext);
        IntToExt(FarbeAchsen,ext);
        write(sfile,ext);
        IntToExt(FarbeStoerung,ext);
        write(sfile,ext);
        IntToExt(FarbeRaster,ext);
        write(sfile,ext);
        if SaveSpur then ext:=1 else ext:=0;
        write(sfile,ext);
        ShortStrToExt(filename,ext);
        write(sfile,ext);
        write(sfile,mass);
        if grafik then ext:=1 else ext:=0;
        write(sfile,ext);
      end;
      with Analyse do begin
        with Info2 do begin
          ext:=stauchung; write(sfile,ext);
        end;
        with Spur do begin
          ext:=size; write(sfile,ext);
          ext:=darkness; write(sfile,ext);
          ext:=PaintTimer; write(sfile,ext);
          ShortStrToext(files[1],ext); write(sfile,ext);
          ShortStrToext(files[2],ext); write(sfile,ext);
          ShortStrToext(files[3],ext); write(sfile,ext);
          ext:=booltoext(umgebung); write(sfile,ext);
          ext:=booltoext(dichte); write(sfile,ext);
          ext:=boolToExt(strecke); write(sfile,ext);
        end;
        with StartP do begin
          ext:=x1; write(sfile,ext);
          ext:=y1; write(sfile,ext);
          ext:=x2; write(sfile,ext);
          ext:=y2; write(sfile,ext);
          ext:=booltoext(prop); write(sfile,ext);
          ext:=MaxRadius; write(sfile,ext);
          ext:=Steps; write(sfile,ext);
          ext:=Minimum; write(sfile,ext);
          ext:=booltoext(Grafik); write(sfile,ext);
        end;
      end;
      write(sfile,ProgrammCode);
    end;
  end;
end;
procedure TForm1.SaveSettingsClick(Sender: TObject);
var sfile    : TExtFile;
begin
  with form1 do begin
    {Datei festlegen}
    SaveDialog.filename:='*.MPS';
    if SaveDialog.execute then begin
      if pos('.',SaveDialog.filename)=0 then SaveDialog.filename:=SaveDialog.filename+'.MPS';
      assignfile(sfile,SaveDialog.filename);
      rewrite(sfile);
      PSaveSettings(sfile);
      closefile(sfile);
    end;
  end;
  chDir(Startdir);
end;

procedure TForm1.InVariablenSpeichern(Sender: TObject);
begin
  GetVar;
end;

{IV. Die Simulation}

procedure TForm1.StartSzeneClick(Sender: TObject);
begin
  {Simulation loslegen}
  TabbedNoteBook.activePage:='Simulation';
  form1.refresh;
  StartButtonClick(sender);
end;

procedure Berechnung;
var fwx, fwy, fwz    : extended;
    fx, fy, fz       : extended;  {Beschleunigende Kräfte}
    dx, dy, dz       : extended;  {  I. Position Magnet relativ zum Pendelkörper
                                    II. Position des Pendelkörpers zur Aufhängung
                                   III. Zur Aufhängung zur Fehlerkerrektur (Correction On)}
    dxyQ             : extended;  {Entfernung² zur Aufhängung in der XY-Ebene (Correction On)}
    distanceQ        : extended;  {Entfernung zum Quadrat}
    dkraft           : extended;  {Kraft in der Entfernung Distance}
    fmx, fmy, fmz    : extended;  {Kraft durch den Magneten}
    fmxy             : extended;  {Kraft in der Draufsicht-Ebene}
    i                : integer;
    alpha, beta      : extended;
    gamma, delta     : extended;
    epsilon, phi     : extended;
    a, b, c, d       : extended;  {Zwischenergebnisse}
    VBetragQ         : extended;  {Quadrat der Geschwindigekeit}
    fcent, freib     : extended;  {Betrag der Zentripetal- und Reibungskraft}
    dvx, dvy, dvz    : extended;  {Geschwindigkeitsänderung}
    dsx, dsy, dsz    : extended;  {Positionsänderung}
    s                : string;
begin
  aktuell.prevPos:=aktuell.pos;
  {I. Kräfte berechnen, die das Pendel beeinflussen}
  fwx:=0; fwy:=0; fwz:=0;
  {1. Die Gewichtskraft}
  fwz:=-aktuell.gewicht;
  {2. Die Kraft durch die Magnete}
  for i:=1 to umgebung.magnete do begin
    with magnet[i] do begin
      dx:=pos.x-aktuell.pos.x;
      dy:=pos.y-aktuell.pos.y;
      dz:=pos.z-aktuell.pos.z;
      distanceQ:=dx*dx+dy*dy+dz*dz;
      if distanceQ<0.0001 then begin
        Form1.SimulationTimer.enabled:=false;
        if messagedlg('Das Pendel schwingt näher als 1 cm an einem Magneten'+#13+
                      +#13+
                      'Da die Kraft jetzt sehr groß wäre, werden'+#13+
                      'vermutlich Berechnungsfehler auftreten !'+#13+
                      'Sie sollten das Pendel eventuell höher aufhängen.'+#13
                      +#13+
                      'Soll das Programm fortfahren ?',mtwarning,[mbyes,mbno],0)=mrno then halt(1);
      end;
      dkraft:=Kraft/(distanceQ*10000);  {DKraft=Kraft/(dist²), dist in cm -> Umrechnung: 1 m²=10000 cm²}
    end;
    {Kraftvektor parallel Richtungsvektor - Berechnungen in der Dokumentation}
    alpha:=xyTOrad(sqrt(dx*dx+dy*dy),-dz);
    fmz:=-sin(alpha)*dkraft;
    beta:=xyTOrad(dy,dx);
    fmxy:=cos(alpha)*dkraft;
    fmx:=cos(beta)*fmxy;
    fmy:=sin(beta)*fmxy;
    fwx:=fwx+fmx;
    fwy:=fwy+fmy;
    fwz:=fwz+fmz;
  end;
  {3.Kraft durch Störungen}
  if (stoerung.now) then begin
    with stoerung do begin
      fwx:=fwx+f.x;
      fwy:=fwy+f.y;
      fwz:=fwz+f.z;
    end;
    stoerung.done:=true;
  end;
  {4.Reibung}
  with aktuell.v do begin
    VBetragQ:=x*x+y*y+z*z;
    if VBetragQ>0 then begin
      epsilon:=xyToRad(y,x);
      phi:=xyToRad(z,sqrt(x*x+y*y));
      fReib:=VBetragQ*umgebung.reibung;
      fwz:=fwz-sin(phi)*fReib;
      fwx:=fwx-cos(phi)*cos(epsilon)*fReib;
      fwy:=fwy-cos(phi)*sin(epsilon)*fReib;
    end;
  end;

  {Weitergeben}
  Aktuell.fw.x:=fwx;
  Aktuell.fw.y:=fwy;
  Aktuell.fw.z:=fwz;

  {II. Ein Teil der Kraft wirkt aber längs dem Pendel}
  fx:=0; fy:=0; fz:=0;
  dx:=aktuell.pos.x-haken.pos.x;
  dy:=aktuell.pos.y-haken.pos.y;
  dz:=aktuell.pos.z-haken.pos.z;
  delta:=xyTOrad(dy,dx);
  gamma:=xyTOrad(sqrt(dx*dx+dy*dy),-dz);
  {1. Die Kraft in X-Richtung}
  a:=cos(delta)*fwx;
  b:=sin(delta)*fwx;
  fx:=fx+sin(delta)*b;
  fy:=fy-cos(delta)*b;
  c:=cos(gamma)*a;
  fz:=fz+sin(gamma)*c;
  d:=cos(gamma)*c;
  fx:=fx+cos(delta)*d;
  fy:=fy+sin(delta)*d;
  {2. Die Kraft in Y-Richtung}
  a:=sin(delta)*fwy;
  b:=cos(delta)*fwy;
  fy:=fy+cos(delta)*b;
  fx:=fx-sin(delta)*b;
  c:=cos(gamma)*a;
  fz:=fz+sin(gamma)*c;
  d:=cos(gamma)*c;
  fx:=fx+cos(delta)*d;
  fy:=fy+sin(delta)*d;
  {3. Die Kraft in Z-Richtung}
  c:=sin(gamma)*fwz;
  fz:=fz+sin(gamma)*c;
  d:=cos(gamma)*c;
  fx:=fx+cos(delta)*d;
  fy:=fy+sin(delta)*d;

  {Zentripetalkraft addieren}
  with aktuell.v do begin
    VBetragQ:=x*x+y*y+z*z;  {Betrag von v zum Quadrat  sqrt(|x|)²=|x|}
  end;
  if VBetragQ>0 then begin
    fcent:=aktuell.masse*VBetragQ/haken.length;
    {Richtung der fcent ist neg. Richtung x1, y1, z1 - siehe Gamma, Delta}
    fz:=fz+cos(gamma)*fcent;
    fx:=fx-sin(gamma)*cos(delta)*fcent;
    fy:=fy-sin(gamma)*sin(delta)*fcent;
  end;
  {Übergeben und neue Position berechnen}
  with aktuell do begin
    f.x:=fx;
    f.y:=fy;
    f.z:=fz;
    a.x:=f.x/masse;
    a.y:=f.y/masse;
    a.z:=f.z/masse;
    dvx:=a.x*umgebung.dt;
    dvy:=a.y*umgebung.dt;
    dvz:=a.z*umgebung.dt;
    v.x:=v.x+dvx;
    v.y:=v.y+dvy;
    v.z:=v.z+dvz;
    dsx:=v.x*umgebung.dt;
    dsy:=v.y*umgebung.dt;
    dsz:=v.z*umgebung.dt;
    pos.x:=pos.x+dsx;
    pos.y:=pos.y+dsy;
    pos.z:=pos.z+dsz;
  end;

  {Part III Die Fehlerdiagnose und -korrektur}

  dx:=aktuell.pos.x-haken.pos.x;
  dy:=aktuell.pos.y-haken.pos.y;
  dz:=haken.pos.z-aktuell.pos.z; {Pendel schwingt unter der Aufhängung lt. Def, dz > 0}

  {Fehlerdiagnose - Infopanel 2}
  if Form1.ShowError.checked then begin
    inc(analyse.info2.counter);
    if analyse.info2.counter>=analyse.info2.Stauchung then analyse.info2.counter:=0;
    if (Analyse.info2.Counter=0) then begin
      if (Umgebung.Korrektur) then begin
        Form1.ErrorType.caption:='Weitere Informationen (Korrektur ein) - Zeitachse 1/'+inttostr(analyse.info2.stauchung);
      end else begin
        Form1.ErrorType.caption:='Weitere Informationen (Korrektur aus) - Zeitachse 1/'+inttostr(analyse.info2.stauchung);
      end;
      Form1.ErrorType1.caption:='Abweichung: Fadenlänge-Pos ('+inttostr(analyse.info2.mass1)+'x  '+
                                exttostr(trunc(15/analyse.info2.mass1/haken.length*100*100)/100)+'%)';
      Form1.ErrorType2.caption:='Geschwindigkeit ('+inttostr(analyse.info2.mass2)+'x)';
    end;
    with Form1 do begin
      with Image_Error1 do with canvas do begin
        If Analyse.info2.Counter=0 then begin
          CopyRect(rect(0,0,width-1,height),canvas,
                   rect(1,0,width,height));
          pen.color:=clwhite;
          pen.mode:=PMCopy;
          moveto(width-1,1); lineto(width-1,height);
          pixels[width-1,round(height/2)]:=clblack;
        end;
        if (abs(analyse.info2.mass1*(sqrt(dx*dx+dy*dy+dz*dz)-haken.length))>height/2) then begin
          pen.color:=clblue;
          moveto(width-1,1); lineto(width-1,height);
          while (abs(analyse.info2.mass1*(sqrt(dx*dx+dy*dy+dz*dz)-haken.length))>height/2) and (analyse.info2.mass1>0) do begin
            analyse.info2.mass1:=trunc(analyse.info2.mass1*0.95);
          end;
        end;
        pixels[width-1,round(height/2)-round(analyse.info2.mass1*(sqrt(dx*dx+dy*dy+dz*dz)-haken.length))+1]:=clgreen;
      end;
      with Image_Error2 do with canvas do begin
        If Analyse.info2.Counter=0 then begin
          CopyRect(rect(0,0,width-1,height),canvas,
                   rect(1,0,width,height));
          pen.color:=clwhite;
          Pen.mode:=PMCOpy;
          moveto(width-1,1); lineto(width-1,height);
          pixels[width-1,round(height/2)]:=clblack;
        end;
        if (abs(analyse.info2.mass2*(aktuell.v.z))>height/2) then begin
          pen.color:=clblue;
          moveto(width-1,1); lineto(width-1,height);
          while (abs(analyse.info2.mass2*(aktuell.v.z))>height/2) and (analyse.info2.mass2>0) do begin
            analyse.info2.mass2:=trunc(analyse.info2.mass2*0.95);
          end;
        end;
        pixels[width-1,round(height/2)-round(analyse.info2.mass2*(aktuell.v.z))+1]:=clgreen;
      end;
    end;
  end;

  {Pendel schwingt außerhalb ? Auf keinen Fall in der Simulation !}
  dxyQ:=dx*dx+dy*dy;
  if ((dxyQ)>(haken.length*haken.length)) and (form1.SimulationTimer.enabled) then begin
    form1.SimulationTimer.enabled:=false;
    if messagedlg('Das Pendel schwingt außerhalb'+#13+
                  'seiner Möglichkeiten !',mtwarning,[mbcancel,mbAbort],0)=mrAbort then halt(1);
  end;

  {Korrektur eingeschalten ?}
  If Umgebung.Korrektur then begin
    {durch Berechnung der Z-Koordinate durch X,Y und Lenght sollen kleine Fehler vermieden werden,}
    {die das Pendel ein kleines Stück außerhalb, bzw. innerhalb der Fadenlänge pendeln lassen !}
    dz:=sqrt(haken.length*haken.length-dxyQ);
    Aktuell.Pos.z:=haken.pos.z-dz;            {Weil darunter}
    {Geschwindigkeit ebenfalls korregieren}
    with aktuell do begin
      v.z:=(Pos.z-PrevPos.z)/umgebung.dt;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i : integer;
begin
  versionsCode:=2.1;
  ProgrammCode:=1603.80;
  CodeStoerung:=54321;
  EndeCode:=10000.001;
  GetDir(0,startDir);
  GetStandard;
  SetVar;
  if (screen.width<1000) or (screen.height<700) then begin
    if messagedlg('Ihr Bildschirm sollte für dieses'+#13+
                  'Programm mindestens eine Auflösung'+#13+
                  'von 1024x768 haben.'+#13+
                  '(Umstellung in Systemsteuerung - Anzeige)'+#13+#13+
                  'Programm trotzdem starten ?',mtwarning,[mbyes,mbno],0)=mrno then halt(0);
  end;
end;

procedure TForm1.KraftBerechnenButtonClick(Sender: TObject);
var x, y, z     : extended;
    dx, dy, dz  : extended;
    xx, yy, zz  : integer;
    hx, hy, hz  : integer;
    mode        : byte;
    x1, y1, z1  : extended; {Jeweils die vorige Koordinate für das Gitter}
    gx, gy, gz  : extended; {Gitter-Werte wie dx...}
    zzz         : integer;  {Gitter}
    first       : boolean;  {Beim ersten Schritt noch keine Gitterstriche}
begin
  waitPanel.visible:=true;
  WaitPanel.refresh;
  clearImage(Image_K);
  if kraftPaintMode1.checked then mode:=1 else mode:=4;
  {Durch Maßstab, mx, my ist die maximale Größe festgelegt}
  image_K.refresh;
  first:=true;
  for xx:=-trunc(zeichnen.mx/20) to trunc(zeichnen.mx/20) do begin
    for yy:=-trunc(zeichnen.my/20) to trunc(zeichnen.my/20) do begin
      x:=xx*10/zeichnen.mass;
      y:=yy*10/zeichnen.mass;
      dx:=x-haken.pos.x;
      dy:=y-haken.pos.y;
      {dx²+dy²+dz²=length²}
      if (dx*dx+dy*dy)<(haken.length*haken.length) then begin
        dz:=sqrt(haken.length*haken.length-dx*dx-dy*dy);
        z:=haken.pos.z-dz; {da das Pendel unter dem Haken schwingt}
        zz:=trunc(zeichnen.mass*z);
        {Gitter, das Meiste wie oben}
        if not first then begin
          x1:=(xx-1)*10/zeichnen.mass;
          y1:=(yy-1)*10/zeichnen.mass;
          gx:=x1-haken.pos.x;
          gy:=y1-haken.pos.y;
          {X ändern}
          if (gx*gx+dy*dy)<(haken.length*haken.length) then begin
            gz:=sqrt(haken.length*haken.length-gx*gx-dy*dy);
            z1:=haken.pos.z-gz;
            zzz:=trunc(zeichnen.mass*z1);
            Image_k.canvas.pen.width:=1;
            Line3D(xx*10,yy*10,zz,xx*10-10,yy*10,zzz,mode+1,zeichnen.FarbeRaster,Image_K.Canvas);
          end;
          {Y ändern}
          if (dx*dx+gy*gy)<(haken.length*haken.length) then begin
            gz:=sqrt(haken.length*haken.length-dx*dx-gy*gy);
            z1:=haken.pos.z-gz;
            zzz:=trunc(zeichnen.mass*z1);
            Image_k.canvas.pen.width:=1;
            Line3D(xx*10,yy*10,zz,xx*10,yy*10-10,zzz,mode+1,zeichnen.FarbeRaster,Image_K.Canvas);
          end;
        end;
        first:=false;
        {Eigentlich Berechnen}
        aktuell.pos.x:=x;
        aktuell.pos.y:=y;
        aktuell.pos.z:=z;
        aktuell.v.x:=0;
        aktuell.v.y:=0;
        aktuell.v.z:=0;
        Berechnung;
        if KraftGesamt.checked then begin
          {Gesamte Kraft}
          hx:=trunc(KraftPaintMassScroll.Position/5*aktuell.fw.x/aktuell.gewicht);
          hy:=trunc(KraftPaintMassScroll.Position/5*aktuell.fw.y/aktuell.gewicht);
          hz:=trunc(KraftPaintMassScroll.Position/5*aktuell.fw.z/aktuell.gewicht);
          Line3D(xx*10,yy*10,zz,xx*10+hx,yy*10+hy,zz+hz,mode,zeichnen.FarbePendel,Image_K.Canvas);
        end;
        if KraftBeschleunigend.checked then begin
          {Beschleunigende Kraft}
          hx:=trunc(KraftPaintMassScroll.Position/5*aktuell.f.x/aktuell.gewicht);
          hy:=trunc(KraftPaintMassScroll.Position/5*aktuell.f.y/aktuell.gewicht);
          hz:=trunc(KraftPaintMassScroll.Position/5*aktuell.f.z/aktuell.gewicht);
          Line3D(xx*10,yy*10,zz,xx*10+hx,yy*10+hy,zz+hz,mode,zeichnen.FarbePendel,Image_K.Canvas);
        end;
        {Koordiantensystem}
        KoSystem(Image_k.canvas,mode);
      end; {Sonst schwingt das Pendel vom Haken weiter entfernt, als der Faden lang ist}
    end;
    if trunc(xx/10)=xx/10 then Image_k.refresh;
  end;
  waitPanel.visible:=false;
end;

procedure TForm1.ShowKraftButtonsClick(Sender: TObject);
begin
  WelcheKraftPanel.visible:=not WelcheKraftPanel.visible;
  ZeichenModusPanel.visible:=not ZeichenModusPanel.visible;
  KraftBerechnenButton.visible:=not KraftBerechnenButton.visible;
end;

procedure TForm1.PotentialHideClick(Sender: TObject);
begin
  PotentialBerechnenButton.visible:=not PotentialBerechnenButton.visible;
  PotentialPanel.visible:=not PotentialPanel.visible;
  PotentialPanel3.visible:=not PotentialPanel3.visible;
end;

procedure TForm1.PotentialBerechnenButtonClick(Sender: TObject);
var number        : integer;
    distance      : extended;
    x1, y1, z1    : extended;
    x2, y2, z2    : extended;
    dx, dy, dz    : extended;
    first         : boolean;
    xx, yy, zz    : integer;
    mx, my, mz    : extended;
    vx, vy        : extended;
    i             : integer;
    potential     : extended;
    Kraftges      : extended;
    height        : integer;
    alpha, beta   : extended;
    px, py        : integer;
    ccolor        : TColor;
    half          : integer;
    xq            : extended;
    pix, streifen : integer;
    max, min      : extended;
    s             : string;
    painter       : integer;
    RectColor     : TColor;
begin
  waitPanel.visible:=true;
  WaitPanel.refresh;
  pix:=8-GenauigkeitScrollbar.position;
  streifen:=StreifenScrollbar.Position;
  max:=-1000000; min:=1000000;
  {Potential berechnen - Siehe auch hier Dokumentation !}
  clearImage(Image_P);
  {Durch Maßstab, mx, my ist die maximale Größe festgelegt}
  image_P.refresh;
  first:=true;
  {/2 Hälfte /pix}
  for xx:=-trunc(zeichnen.mx/pix/2) to trunc(zeichnen.mx/pix/2) do begin
    for yy:=-trunc(zeichnen.my/pix/2) to trunc(zeichnen.my/pix/2) do begin
      {von P(XX|YY) zum Nullpunkt O(0|0)}
      mx:=xx;
      my:=yy;
      number:=trunc(sqrt(mx*mx+my*my))+1; {So viele Schritte, wie Pixels}
      x1:=mx*pix/zeichnen.mass;
      y1:=my*pix/zeichnen.mass;
      dx:=x1-haken.pos.x;
      dy:=y1-haken.pos.y;
      if (dx*dx+dy*dy)<(haken.length*haken.length) then begin
        {Jetzt die Schrittweite}
        vx:=x1/number;
        vy:=y1/number;
        potential:=0;
        for i:=1 to number do begin
          x1:=(i-1)*vx;
          y1:=(i-1)*vy;
          x2:=i*vx;
          y2:=i*vy;
          dx:=x1-haken.pos.x;
          dy:=y1-haken.pos.y;
          dz:=sqrt(haken.length*haken.length-dx*dx-dy*dy);
          z1:=haken.pos.z-dz;
          dx:=x2-haken.pos.x;
          dy:=y2-haken.pos.y;
          dz:=sqrt(haken.length*haken.length-dx*dx-dy*dy);
          z2:=haken.pos.z-dz;
          {Berechnen}
          aktuell.pos.x:=x1;
          aktuell.pos.y:=y1;
          aktuell.pos.z:=z1;
          aktuell.v.x:=0;
          aktuell.v.y:=0;
          aktuell.v.z:=0;
          Berechnung;
          {Entfernung von x2,y2,z2}
          dx:=x2-x1; dy:=y2-y1; dz:=z2-z1; {vx, vy und ein unbekanntes vz}
          distance:=sqrt(dx*dx+dy*dy+dz*dz);
          {Zur Richtung zum Mittelpunkt parallele Anteile berechnen}
          alpha:=xyTOrad(y1,x1);
          beta:=xyTOrad(sqrt(dx*dx+dy*dy),dz);
          KraftGes:=aktuell.f.x*cos(alpha)*sin(beta);
          KraftGes:=KraftGes+aktuell.f.y*sin(alpha)*sin(beta);
          KraftGes:=KraftGes+aktuell.f.z*cos(beta);
          potential:=potential-distance*KraftGes;
        end;
        if potential>max then max:=potential;
        if potential<min then min:=potential;
        height:=trunc(potential*100);
        px:=trunc(pix*mx);
        py:=trunc(pix*my);
        if streifen>0 then begin
          if PotentialBunt.checked then begin
            RectColor:=Clwhite;
            for Painter:=1 to trunc((potential+PotentialColorAddBar.Position/10)*10*streifen) do begin
              RectColor:=IncColor(RectColor,10);
            end;
            CColor:=RectColor;
          end else begin
            if trunc(trunc(streifen*4*potential)/2)=trunc(streifen*4*potential)/2 then ccolor:=clred else ccolor:=clblue;
          end;
        end else ccolor:=clblue;
        half:=trunc(pix/2);
        if potentialZeichnen1.checked then begin
          putpixel3d(px,py,height,2,ccolor,Image_p.canvas);
        end else begin
          if PotentialAufsicht.checked then begin
              Image_P.canvas.brush.color:=CColor;
              Image_P.canvas.fillrect(rect(trunc(px+zeichnen.mx/2),trunc(py+zeichnen.my/2),
                                           trunc(px+zeichnen.mx/2)+pix,trunc(py+zeichnen.my/2)+pix));
          end else begin
            line3d(px-half,py-half,height,px+half-1,py-half,height,2,ccolor,Image_p.canvas);
            line3d(px-half,py+half-1,height,px+half-1,py+half-1,height,2,ccolor,Image_p.canvas);
            line3d(px-half,py-half,height,px-half,py+half-1,height,2,ccolor,Image_p.canvas);
            line3d(px+half-1,py-half,height,px+half-1,py+half-1,height,2,ccolor,Image_p.canvas);
          end;
        end;
      end;
    end;
    if trunc(xx/15)=xx/15 then Image_p.refresh;
  end;
  with Image_P.canvas do begin
    brush.color:=zeichnen.Hintergrund;
    font.name:='Arial';
    font.size:=9;
    font.color:=clblue;
    str(max:0:3,s);
    textOut(10,zeichnen.my-40,'Maximales Potential: '+s+'Joule');
    str(min:0:3,s);
    textOut(10,zeichnen.my-20,'Minimales Potential: '+s+'Joule');
  end;
  waitPanel.visible:=false;
end;

procedure TForm1.StartButtonClick(Sender: TObject);
var dx, dy : integer;
begin
  VoraussetzungenClick(sender);
  Aktuell.Pos:=Aktuell.StartPos;
  Aktuell.V:=Aktuell.StartV;
  Stoerung.Now:=false;
  Stoerung.Done:=false;
  Umgebung.zeit:=0;
  Aktuell.schritt:=0;
  ClearImage(Image_Error1);
  ClearImage(Image_Error2);
  analyse.info2.mass1:=1000000;
  analyse.info2.mass2:=1000000;
  if zeichnen.savespur then begin
    assignfile(spurfile,zeichnen.filename+'.MPP');
    rewrite(spurfile);
  end;
  SimulationPause.enabled:=true;
  SimulationPause.caption:='Pause';
  aktuell.prevPos:=aktuell.pos;
  dx:=trunc(aktuell.pos.x*zeichnen.mass+zeichnen.mx/2);
  dy:=trunc(zeichnen.my/2-aktuell.pos.y*zeichnen.mass);
  with Image_s.canvas do begin
    pen.mode:=pmXor;
    pen.color:=zeichnen.Hintergrund-zeichnen.FarbePendel;
    moveto(dx-7,dy-7);
    lineto(dx+7,dy-7);
    lineto(dx+7,dy+7);
    lineto(dx-7,dy+7);
    lineto(dx-7,dy-7);
  end;
  SimulationTimer.interval:=trunc(1000*umgebung.dtp)+1;
  SimulationEnde.enabled:=true;
  SimulationTimer.enabled:=true;
end;

procedure TForm1.VoraussetzungenClick(Sender: TObject);
begin
  clearImage(Image_S);
  UmgebungZeichnen(Image_S);
end;

Procedure AktualisiereInfoPanel;
begin
  with form1 do begin
    with Umgebung do begin
      timeLabel.caption:=extToStr(zeit);
    end;
    with aktuell do begin
      with Pos do begin
        simPX.caption:=extTostr(x);
        simPY.caption:=extTostr(y);
        simPZ.caption:=extTostr(z);
      end;
      with v do begin
        simVX.caption:=extTostr(x);
        simVY.caption:=extTostr(y);
        simVZ.caption:=extTostr(z);
      end;
      with f do begin
        simFX.caption:=extTostr(x);
        simFY.caption:=extTostr(y);
        simFZ.caption:=extTostr(z);
      end;
      with a do begin
        simAX.caption:=extTostr(x);
        simAY.caption:=extTostr(y);
        simAZ.caption:=extTostr(z);
      end;
    end;
    SimulationInfoPanel.refresh;
  end;
end;

procedure ZeichneStoerung;
var ex, ey : integer;
begin
  ex:=trunc(aktuell.pos.x*zeichnen.mass+zeichnen.mx/2);
  ey:=trunc(zeichnen.my/2-aktuell.pos.y*zeichnen.mass);
  With form1.Image_s.canvas do begin
    pen.mode:=pmCopy;
    pen.color:=zeichnen.FarbeStoerung;
    moveto(ex-7,ey-7);
    lineto(ex+7,ey+7);
    moveto(ex+7,ey-7);
    lineto(ex-7,ey+7);
    moveto(ex-4,ey-4);
    lineto(ex+4,ey-4);
    lineto(ex+4,ey+4);
    lineto(ex-4,ey+4);
    lineto(ex-4,ey-4);
  end;
  if Zeichnen.SaveSpur then write(SpurFile,CodeStoerung,CodeStoerung,CodeStoerung);
end;

procedure NextStep;
var dx, dy        : integer;
    ex, ey        : integer;
    gx, gy, gz    : extended;
    dvx, dvy, dvz : extended;
    dsx, dsy, dsz : extended;
    vx, vy, vz    : extended;
    i             : integer;
    VBetrag       : extended;
    fz            : extended;
    gamma, delta  : extended;
begin
  inc(aktuell.schritt);
  if zeichnen.grafik then if (trunc(aktuell.schritt/250)=aktuell.schritt/250) then begin
    UmgebungZeichnen(Form1.Image_S);
  end;
  {Aktuelle subjektive Zeit}
  umgebung.zeit:=aktuell.schritt*umgebung.dt;
  {Liegt gerade eine Störung vor ?}
  if not stoerung.done then begin
    if (stoerung.time>umgebung.zeit) then begin
      stoerung.now:=true;
      ZeichneStoerung;
    end;
  end;
  {Berechnungen}
  Berechnung;
  {Eventuell Info-Panel aktualisieren}
  if Form1.InfoSimulation.checked then AktualisiereInfoPanel;
  {Zeichnen}
  if zeichnen.grafik then begin
    dx:=trunc(aktuell.prevpos.x*zeichnen.mass+zeichnen.mx/2);
    dy:=trunc(zeichnen.my/2-aktuell.prevpos.y*zeichnen.mass);
    ex:=trunc(aktuell.pos.x*zeichnen.mass+zeichnen.mx/2);
    ey:=trunc(zeichnen.my/2-aktuell.pos.y*zeichnen.mass);
    if Form1.MehrBilder.checked then begin
      putpixel3d(trunc(aktuell.pos.x*zeichnen.mass),
                 trunc(aktuell.pos.y*zeichnen.mass),
                 trunc(aktuell.pos.z*zeichnen.mass),2,clblack,form1.image_s.canvas);
    end;
    With form1.Image_s.canvas do begin
      pen.mode:=pmXor;
      pen.color:=zeichnen.Hintergrund-zeichnen.FarbePendel;
      {Pendel löschen}
      moveto(dx-7,dy-7);
      lineto(dx+7,dy-7);
      lineto(dx+7,dy+7);
      lineto(dx-7,dy+7);
      lineto(dx-7,dy-7);
      {Spur}
      pen.color:=zeichnen.FarbeSpur;
      pen.mode:=pmCopy;
      moveto(dx,dy);
      lineto(ex,ey);
      {Pendel zeichnen}
      pen.mode:=pmXor;
      pen.color:=zeichnen.Hintergrund-zeichnen.FarbePendel;
      moveto(ex-7,ey-7);
      lineto(ex+7,ey-7);
      lineto(ex+7,ey+7);
      lineto(ex-7,ey+7);
      lineto(ex-7,ey-7);
      {Temporär speichern & ggf. löschen}
      if zeichnen.spur>0 then begin
        for i:=1 to zeichnen.spur-1 do spur[i]:=spur[i+1];
        with spur[zeichnen.spur] do begin
          x:=dx;
          y:=dy;
        end;
        pen.color:=zeichnen.Hintergrund;
        pen.mode:=pmCopy;
        with spur[0] do moveto(x,y);
        with spur[1] do lineto(x,y);
        spur[0]:=spur[1];
      end;
    end;
  end;
  {Richtig speichern}
  if zeichnen.SaveSpur then write(spurfile,aktuell.pos.x,aktuell.pos.y,aktuell.pos.z);
end;

procedure TForm1.SimulationTimerTimer(Sender: TObject);
begin
  nextStep;
end;

procedure TForm1.SimulationPauseClick(Sender: TObject);
begin
  if SimulationPause.caption='Pause' then begin
    SimulationTimer.enabled:=false;
    SimulationPause.caption:='Weiter'
  end else begin
    SimulationTimer.enabled:=true;
    SimulationPause.caption:='Pause';
  end;
end;

procedure TForm1.SimulationEndeClick(Sender: TObject);
begin
  SimulationTimer.enabled:=false;
  aktuell.pos:=aktuell.startpos;
  aktuell.v:=aktuell.startv;
  SimulationPause.enabled:=false;
  SimulationPause.caption:='Pause';
  SimulationEnde.enabled:=false;
  if Zeichnen.savespur then write(spurfile,EndeCode,EndeCode,EndeCode);
  if zeichnen.savespur then CloseFile(SpurFile);
end;

procedure TForm1.SimulationHideClick(Sender: TObject);
begin
  SimulationPanel.visible:=not SimulationPanel.visible;
end;

procedure TForm1.InfoSimulationClick(Sender: TObject);
begin
  SimulationInfoPanel.visible:=InfoSimulation.checked;
  AktualisiereInfoPanel;
end;

procedure TForm1.StoerungButtonClick(Sender: TObject);
begin
  stoerung.now:=true;
  ZeichneStoerung;
end;

procedure SavePicture(img : TImage);
begin
  with form1 do begin
    SaveDialogI.filename:='*.BMP';
    if SaveDialogI.execute then begin
      with savedialogI do begin
        if pos('.',filename)=0 then filename:=filename+'.BMP';
        img.picture.savetofile(filename);
      end;
    end;
  end;
  chDir(Startdir);
end;

procedure TForm1.SimulationBildSpeichernClick(Sender: TObject);
var pre : boolean;
begin
  pre:=SimulationTimer.enabled;
  SimulationTimer.enabled:=false;
  savePicture(Image_s);
  SimulationTimer.enabled:=pre;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  savePicture(Image_k);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  savePicture(Image_P);
end;

procedure TForm1.HideSpurPanelClick(Sender: TObject);
begin
  spurPanel.visible:=not spurPanel.visible;
  if analysespurdichte.checked then DichtePanel.visible:=SpurPanel.visible;
end;

procedure TForm1.ClearSpurClick(Sender: TObject);
begin
  clearImage(Image_L);
end;

function UpString(s : string) : string;
var t : string;
    i : integer;
begin
  t:='';
  for i:=1 to length(s) do t:=t+upcase(s[i]);
  UpString:=t;
end;

procedure TForm1.EditSpurBClick(Sender: TObject);
var p : integer;
    t : string;
begin
  openDialog2.filename:='*.MPP';
  if openDialog2.execute then begin
    t:=upstring(openDialog2.filename);
    p:=pos('.MPP',t);
    if p>0 then delete(t,p,4);
    while pos('\',t)>0 do delete(t,1,pos('\',t));
    if Sender=AnalyseSpurFiles1B then AnalyseSpurFiles1.text:=t;
    if Sender=AnalyseSpurFiles2B then AnalyseSpurFiles2.text:=t;
    if Sender=AnalyseSpurFiles3B then AnalyseSpurFiles3.text:=t;
  end;
  chDir(Startdir);
end;

procedure TForm1.SpurenZeichnenClick(Sender: TObject);
var names  : array[1..3] of string;
    i, num : integer;
    tx, ty : integer;
begin
  with analyse.spur do begin
    names[1]:=Files[1]+'.MPP';
    if not Dichte then begin
      names[2]:=Files[2]+'.MPP';
      names[3]:=Files[3]+'.MPP';
      num:=3;
    end else with wiedergabe do begin
      num:=1;
      active[2]:=false;
      active[3]:=false;
    end;
  end;
  for i:=1 to num do begin
    with Wiedergabe do begin
      if fileexists(names[i]) then begin
        active[i]:=true;
        assignfile(files[i],names[i]);
        reset(files[i]);
        with wiedergabe.pos[i] do read(files[i],x,y,z);
      end else begin
        active[i]:=false;
      end;
    end;
  end;
  PaintTimer.interval:=trunc(1000*Analyse.Spur.PaintTimer);
  SpurenPause.caption:='Pause';
  SpurenPause.enabled:=true;
  AnalyseSpurDichte.enabled:=false;
  DichtePanel.enabled:=false;
  SpurZeichnenEnde.enabled:=true;
  wiedergabe.schritt:=0;
  ClearImage(Image_l);
  if Analyse.Spur.Umgebung then begin
    tx:=zeichnen.mx;
    ty:=zeichnen.my;
    zeichnen.mx:=analyse.mx;
    zeichnen.my:=analyse.my;
    UmgebungZeichnen(Form1.Image_L);
    zeichnen.mx:=tx;
    zeichnen.my:=ty;
  end;
  SpurenZeichnen.enabled:=false;
  Form1.AnalyseSpurFiles1.color:=clwindow;
  Form1.AnalyseSpurFiles2.color:=clwindow;
  Form1.AnalyseSpurFiles3.color:=clwindow;
  PaintTimer.enabled:=true;
end;

procedure PaintNextStep;
var dx, dy   : integer;
    ex, ey   : integer;
    spurnum  : integer;
    i        : integer;
    ende     : boolean;
    linesize : integer;
    tx, ty   : integer;
begin
  Ende:=true;
  linesize:=analyse.spur.size;
  with wiedergabe do begin
    for spurnum:=1 to 3 do begin
      if active[spurnum] then begin
        Ende:=false;
        previous[spurnum].x:=pos[spurnum].x;
        previous[spurnum].y:=pos[spurnum].y;
        previous[spurnum].z:=pos[spurnum].z;
        with pos[spurnum] do read(files[spurnum],x,y,z);
        if (pos[spurnum].x=pos[spurnum].y) and (pos[spurnum].y=pos[spurnum].z) and
           (pos[spurnum].z=EndeCode) then begin
          pos[spurnum]:=previous[spurnum];
          active[spurnum]:=false;
          closefile(files[spurnum]);
        end else begin
          if (pos[spurnum].x=pos[spurnum].y) and (pos[spurnum].y=pos[spurnum].z) and
             (pos[spurnum].z=CodeStoerung) then with form1.Image_L.canvas do begin
            pos[spurnum]:=previous[spurnum]; {sonst gibts einen Strich in der Landschaft}
            case spurnum of
              1 : pen.color:=clred;
              2 : pen.color:=clblue;
              3 : pen.color:=clgreen;
            end;
            if not analyse.spur.dichte then begin
              pen.style:=psDot;
              pen.mode:=pmCopy;
              moveto(ex-10,ey-10);
              lineto(ex+10,ey+10);
              moveto(ex+10,ey-10);
              lineto(ex-10,ey+10);
              pen.Style:=psSolid;
            end;
          end else begin
            {Zeichnen}
            inc(schritt);
            if analyse.spur.umgebung and (not analyse.spur.dichte) then begin
              if (trunc(schritt/250)=schritt/250) then begin
                tx:=zeichnen.mx;
                ty:=zeichnen.my;
                zeichnen.mx:=analyse.mx;
                zeichnen.my:=analyse.my;
                UmgebungZeichnen(Form1.Image_L);
                zeichnen.mx:=tx;
                zeichnen.my:=ty;
              end;
            end;
            dx:=trunc(previous[spurnum].x*zeichnen.mass+Analyse.mx/2);
            dy:=trunc(Analyse.my/2-previous[spurnum].y*zeichnen.mass);
            ex:=trunc(pos[spurnum].x*zeichnen.mass+Analyse.mx/2);
            ey:=trunc(Analyse.my/2-pos[spurnum].y*zeichnen.mass);
            With form1.Image_L.canvas do begin
              {Spur}
              if (not analyse.spur.dichte) then begin
                case spurnum of
                  1 : pen.color:=clred;
                  2 : pen.color:=clblue;
                  3 : pen.color:=clgreen;
                end;
                brush.color:=pen.color;
                pen.mode:=pmCopy;
                moveto(dx,dy);
                lineto(ex,ey);
                pen.mode:=pmNotXor;
              end else begin
                ExtraLine(dx,dy,ex,ey,linesize,form1.Image_l.canvas);
              end;
              {Temporär speichern & ggf. löschen}
              if (zeichnen.spur>0) and (not analyse.spur.dichte) then begin
                for i:=1 to zeichnen.spur-1 do spur[spurnum,i]:=spur[spurnum,i+1];
                with spur[spurnum,zeichnen.spur] do begin
                  x:=dx;
                  y:=dy;
                end;
                pen.color:=zeichnen.Hintergrund;
                pen.mode:=pmcopy;
                with spur[spurnum,0] do moveto(x,y);
                with spur[spurnum,1] do lineto(x,y);
                spur[spurnum,0]:=spur[spurnum,1];
              end;
            end;
          end;
        end;
      end;
    end;
    {Aktive Spuren}
    if (not active[1]) and (Form1.AnalyseSpurFiles1.color<>clgray) then begin
      Form1.AnalyseSpurFiles1.color:=clgray;
      Form1.AnalyseSpurFiles1.refresh;
    end;
    if (not active[2]) and (Form1.AnalyseSpurFiles2.color<>clgray) then begin
      Form1.AnalyseSpurFiles2.color:=clgray;
      Form1.AnalyseSpurFiles2.refresh;
    end;
    if (not active[3]) and (Form1.AnalyseSpurFiles3.color<>clgray) then begin
      Form1.AnalyseSpurFiles3.color:=clgray;
      Form1.AnalyseSpurFiles3.refresh;
    end;
  end;
  if Ende then begin
    with Form1 do begin
      PaintTimer.enabled:=false;
      SpurenPause.caption:='Pause';
      SpurenPause.enabled:=false;
      SpurZeichnenEnde.enabled:=false;
      AnalyseSpurDichte.enabled:=true;
      DichtePanel.enabled:=true;
      SpurenZeichnen.enabled:=true;
      AnalyseSpurFiles1.color:=clwindow;
      AnalyseSpurFiles2.color:=clwindow;
      AnalyseSpurFiles3.color:=clwindow;
    end;
  end;
end;

procedure TForm1.PaintTimerTimer(Sender: TObject);
begin
  PaintNextStep;
end;

procedure TForm1.InfoSpurButtonClick(Sender: TObject);
begin
  messagedlg('Diese Spur wird gegebenen Falls'+#13+
             'auch für die Analysen verwendet',mtinformation,[mbok],0);
end;


procedure TForm1.SpurenPauseClick(Sender: TObject);
var i    : integer;
begin
  if SpurenPause.caption='Pause' then begin
    PaintTimer.enabled:=false;
    SpurenPause.caption:='Weiter';
  end else begin
    PaintTimer.interval:=trunc(analyse.spur.PaintTimer*1000);
    PaintTimer.enabled:=true;
    SpurenPause.caption:='Pause';
  end;
end;

procedure TForm1.SpurZeichnenEndeClick(Sender: TObject);
var i : integer;
begin
  for i:=1 to 3 do if wiedergabe.active[i] then begin
    wiedergabe.active[i]:=false;
  end;
  PaintTimer.enabled:=true;
end;

procedure TForm1.SpurBildSpeichernClick(Sender: TObject);
var pre : boolean;
begin
  pre:=PaintTimer.enabled;
  PaintTimer.enabled:=false;
  savePicture(Image_L);
  PaintTimer.enabled:=pre;
end;

procedure TForm1.StartPunktePanelEinClick(Sender: TObject);
begin
  StartPunktePanel.visible:=not StartPunktePanel.visible;
end;

{Startpunkte Berechnen}
procedure TForm1.StartPBerechnungClick(Sender: TObject);
var posx, posy, posz  : extended;
    x, y, i           : integer;
    dx, dy, vx, vy, t : extended;
    hx, hy, hz        : extended;
    stepsn             : integer;
    c, px, py         : integer;
    next              : integer;
    dist, mdist       : extended;
    standing          : record
                          ende   : boolean; {Fertig}
                          number : integer; {Nummer, wo es steht}
                          onit   : integer; {Wie oft schon über dem Ding}
                        end;
    gx, gy, gz        : extended;
    mpx, mpy          : integer;
    error             : boolean;
    dmx, dmy          : extended; {Entfernung zum Magnet}
begin
  waitPanel.visible:=true;
  WaitPanel.refresh;
  ClearImage(Image_M);
  with Analyse do with StartP do begin
    stepsn:=10-steps;
    if x1>x2 then begin
      t:=x1; x1:=x2; x2:=t;
    end;
    if y1>y2 then begin
      t:=y1; y1:=y2; y2:=t;
    end;
    dx:=x2-x1;
    dy:=y2-y1;
    vx:=mx/dx;
    vy:=my/dy;
    if Grafik then begin
      Image_m1.visible:=true;
    end else begin
      Image_m1.visible:=false;
    end;
  end;
  for x:=0 to trunc(analyse.mx/stepsn)-1 do begin
    for y:=0 to trunc(analyse.my/stepsn)-1 do begin
      posx:=analyse.StartP.x1+(x*stepsn)/vx;
      posy:=analyse.StartP.y1+(y*stepsn)/vy;
      hx:=posx-haken.pos.x;
      hy:=posy-haken.pos.y;
      if ((hx*hx+hy*hy)<=(analyse.StartP.MaxRadius*analyse.StartP.MaxRadius)) then
       if ((haken.length*haken.length-hx*hx-hy*hy)>0) then begin
        {Zur Grafik - Die Spur nochmal extra zeichnen}
        if analyse.StartP.grafik then begin
          ClearImage(Image_M1);
          with Image_m1.canvas do begin
            {X-Y}
            pen.color:=clblack;
            moveto(0,trunc(maxheight/8));
            lineto(trunc(maxwidth/4),trunc(maxheight/8));
            moveto(trunc(maxwidth/8),0);
            lineto(trunc(maxwidth/8),trunc(maxheight/4));
            moveto(0,trunc(maxheight/8));
          end;
        end;
        {Zur Berechnung der Bahn}
        hz:=haken.length*haken.length-hx*hx-hy*hy; {Startpunkt auf der Halbkugel}
        {Initialisieren}
        with aktuell.pos do begin
          x:=haken.pos.x+hx;
          y:=haken.pos.y+hy;
          z:=haken.pos.z-hz;
        end;
        with Aktuell.V do begin
          x:=0; y:=0; z:=0;
        end;
        Stoerung.Now:=false;
        Stoerung.Done:=false;
        Aktuell.schritt:=0;
        Umgebung.zeit:=0;
        Standing.Onit:=0;
        {Initialisierung der Messung, was das Pendel am nächsten ist}
        next:=98;
        mdist:=1000;
        {Versuch los}
        repeat
          error:=false;
          try
            berechnung;
            gx:=aktuell.pos.x-haken.pos.x;
            gy:=aktuell.pos.y-haken.pos.y;
            {Sollte das Pendel mal ins Nirvana schwingen...}
            if (gx*gx+gy*gy)>(haken.length*haken.length) then begin
              standing.ende:=true;
              standing.number:=99;
            end else begin
            {Wo am nächsten dran}
            {next: 99   : außerhalb der Möglichkeiten}
            {      98   : Problem bei der Bestimmung}
            {      97   : Fehler}
            {      1..5 : Nummer Magnet}
            {      0    : Kein Magnet}
              next:=98;
              mdist:=1000;
              {Welchem magneten am nächsten ?}
              for i:=1 to umgebung.magnete do begin
                with aktuell.pos do begin
                  dmx:=x-magnet[i].pos.x;
                  dmy:=y-magnet[i].pos.y;
                  dist:=dmx*dmx+dmy*dmy;
                end;
                if dist<mdist then begin
                  mdist:=dist;
                  next:=i;
                end;
              end;
              {Dem Haken am nächsten ?}
              with aktuell.pos do begin
                dmx:=x-haken.pos.x;
                dmy:=y-haken.pos.y;
                dist:=dmx*dmx+dmy*dmy;
              end;
              if dist<mdist then begin
                mdist:=dist;
                next:=0;
              end;
              {Bahn zeichnen}
              if analyse.StartP.grafik then begin
                with Image_m1.canvas do begin
                  mpx:=round(maxwidth/8*(1+aktuell.pos.x*2));
                  mpy:=round(maxheight/8*(1-aktuell.pos.y*2));
                  case standing.number of
                    1 : pen.color:=clred;
                    2 : pen.color:=clblue;
                    3 : pen.color:=clgreen;
                    4 : pen.color:=clyellow;
                    5 : pen.color:=cllime;
                    0 : pen.color:=clblack;
                   99 : pen.color:=clfuchsia;
                  end;
                  lineto(mpx,mpy);
                  Image_m1.refresh;
                end;
              end;
              {Aha ! Schon lang genug über einer Position geblieben ?}
              standing.ende:=false;
              if next=standing.number then begin
                inc(standing.onit);
                if standing.onit>=analyse.StartP.minimum then standing.ende:=true;
              end else begin
                standing.onit:=0;
                standing.number:=next;
                standing.ende:=false;
              end;
            end;
          except
            error:=true;
            next:=97;
          end;
        until standing.ende or error;
        with Image_M.canvas do begin
          case standing.number of
            1 : brush.color:=clred;
            2 : brush.color:=clblue;
            3 : brush.color:=clgreen;
            4 : brush.color:=clyellow;
            5 : brush.color:=cllime;
            0 : brush.color:=clblack;
           97 : brush.color:=claqua;
           98 : brush.color:=claqua;
           99 : brush.color:=clfuchsia;
          end;
          if stepsn=1 then pixels[x*stepsn,y*stepsn]:=brush.color else
            fillrect(rect(    x*stepsn,  analyse.my-     y*stepsn,
                          (x+1)*stepsn,  analyse.my- (y+1)*stepsn));
        end;
      end else begin
        with Image_M.canvas do begin
          brush.color:=clsilver;
          if stepsn=1 then pixels[x*stepsn,y*stepsn]:=brush.color else
            fillrect(rect(x*stepsn,y*stepsn,(x+1)*stepsn,(y+1)*stepsn));
        end;
      end;
    end;
    image_m.refresh;
  end;
  Image_m1.visible:=false;
  waitPanel.visible:=false;
end;

procedure TForm1.StartPBildSpeichernClick(Sender: TObject);
begin
  SavePicture(Image_m);
end;

procedure TForm1.AnalyseSpurFiles1Change(Sender: TObject);
begin
  if fileexists(AnalyseSpurFiles1.text+'.MPP') then begin
    AnalyseSpurFiles1.color:=clyellow;
    noAnalyse.hide;
  end else begin
    AnalyseSpurFiles1.color:=clwhite;
    noAnalyse.show;
  end;
  InVariablenSpeichern(sender);
end;

procedure TForm1.UmgebungReibungChange(Sender: TObject);
var control : TWinControl;
    ss, sl  : integer;
begin
  control:=form1.activecontrol;
  if sender=umgebungReibung then begin
    ss:=umgebungReibung.selstart;
    sl:=umgebungReibung.sellength;
    UmgebungReibung2.enabled:=false;
    umgebungReibung2.text:=umgebungReibung.text;
    UmgebungReibung2.enabled:=true;
    umgebungReibung.selstart:=ss;
    umgebungReibung.sellength:=sl;
  end;
  if sender=umgebungReibung2 then begin
    ss:=umgebungReibung2.selstart;
    sl:=umgebungReibung2.sellength;
    UmgebungReibung.enabled:=false;
    umgebungReibung.text:=umgebungReibung2.text;
    UmgebungReibung.enabled:=true;
    umgebungReibung2.selstart:=ss;
    umgebungReibung2.sellength:=sl;
  end;
  form1.activecontrol:=control;
  InVariablenSpeichern(sender);
end;

procedure TForm1.noAnalyseClick(Sender: TObject);
begin
  NoteBookAnalyse.activePage:='Spur / Dichte';
  editSpurBClick(AnalyseSpurFiles1B);
end;

procedure TForm1.ShowErrorClick(Sender: TObject);
begin
  ErrorPanel.visible:=ShowError.checked;
end;

procedure TForm1.AnalyseFarbenButtonClick(Sender: TObject);
var i, j : integer;
    x, y : integer;
    size : integer;
begin
  size:=analyse.spur.size;
  with Image_L do with canvas do begin
    y:=height-size;
    for i:=1 to trunc(255*5/analyse.spur.darkness) do begin
      x:=i*size+5;
      brush.color:=clwhite;
      fillrect(rect(x,y,x+size-1,y+size-1));
      for j:=1 to i do begin
        extraline(x,y,x+2,y,size,canvas);
      end;
    end;
  end;
end;

procedure TForm1.UmgebungKorrektur2Click(Sender: TObject);
begin
  Umgebung.Korrektur:=UmgebungKorrektur2.checked;
  UmgebungKorrektur.checked:=Umgebung.Korrektur;
end;

procedure TForm1.PotentialColorAddBarChange(Sender: TObject);
begin
  PotentialColorAdd.caption:='+ '+exttostr(PotentialColorAddBar.Position/10)+' Joule';
end;

procedure TForm1.PotentialBuntClick(Sender: TObject);
begin
  PotentialColorAddBar.enabled:=PotentialBunt.checked;
  if not PotentialBunt.checked then begin
    PotentialColorAddLabel.font.color:=clgray;
    PotentialColorAdd.font.color:=clgray;
  end else begin
    PotentialColorAddLabel.font.color:=clblack;
    PotentialColorAdd.font.color:=clblack;
  end;
end;

procedure TForm1.UmkehrSuchenClick(Sender: TObject);
var f                : file of extended;
    fname            : string;
    ende, stoerung   : boolean;
    x, y, z          : extended; {Position des Pendels}
    xp, yp, zp       : extended; {Vorige Position}
    dx, dy, dz       : extended; {proportional zur Geschwindigkeit ist DeltaX,Y,Z}
    dist, distpre    : extended; {Entfernung von der Position (0|0) in der s. Projektion in die x-y-Ebene
                                 - Achtung mit anderen Aufhängungspunkten, als (0|0|z) !!!
                                 - Wegen dem Zusammenhang zwischen x, y, z auf der Kugelschale
                                   wäre auch die z-Koordinate zu Bestimmung der UK-Punkte geeignet}
    ddist, ddistpre  : extended; {DeltaDist zum vorigen, DeltaDist vom vorigen zum vorvorigen
                                  Diese Delta's laufen auf eine Art Ableitung der Entfernung hinaus,
                                  deren Vorzeichenwechsel einen Umkehrpunkt kennzeichnet}
    xz, yz, xzp, yzp : integer;  {Für die Zeichnung jetzige und vorige x, y - Zeichenpunkte}
    mx, my, counter  : integer;  {Counter für die Zeitstauchung}
    rr, gg, bb       : integer;
    temp             : extended; {Für berechnungen}
    alpha, vt        : extended; {Winkel des Pendels beim Umkehrpunkt, Geschwindigkeit tangential}
    pcolor, pgray    : TColor;   {Farbe für die Punkte im Poincare-Diagramm}
    ppx, ppy         : integer;  {Zeichenkoordinaten im P-Schnitt}
begin
  fname:=analyse.spur.Files[1]+'.MPP';
  if (not fileexists(fname)) then begin
    messagedlg('Problem !'+#13+'Datei '+fname+' nicht gefunden !'+#13+#13+
               'Bitte Spur überprüfen', mtwarning, [mbCancel], 0);
  end else begin
    assignfile(f, fname);
    reset(f);
    ende:=false;
    distpre:=codeStoerung;  {Erkennen der 1. Berechnung}
    ddistpre:=codeStoerung; {zum Erkennen der 1. Berechnung}
    xp:=codeStoerung;
    yp:=xp; zp:=xp;
    counter:=0;
    {Zeichnung}
    mx:=UmkehrImage_g.width;
    my:=UmkehrImage_g.height;
    with UmkehrImage_g.canvas do begin
      pen.color:=zeichnen.FarbeSpur;
      brush.color:=zeichnen.Hintergrund;
      fillrect(rect(0,0,mx,my));
    end;
    with UmkehrImage_Time do with canvas do begin
      pen.color:=clblue;
      brush.color:=clwhite;
      fillrect(rect(0,0,width,height));
    end;
    if UmkehrPoincare.checked then begin
      with UmkehrImage_Poincare do with canvas do begin
        pen.color:=clred;
        brush.color:=clwhite;
        fillrect(rect(0,0,width,height));
        moveto(width-15,height-31);
        lineto(width-2,height-23);
        lineto(2,height-23);
        lineto(2,1);
        lineto(10,15);
      end;
    end;
    if UmkehrFast.checked then begin
      waitPanel.show;
      waitpanel.refresh;
    end;
    repeat
      inc(counter);
      read(f,x,y,z);
      stoerung:=false;
      if (x=y) and (y=z) and (z=endeCode) then ende:=true;
      if (x=y) and (y=z) and (z=codeStoerung) then stoerung:=true;
      if not (ende or stoerung) then begin
        dist:=x*x+y*y;
        ddist:=(dist-distPre);
        {Zeichnen}
        xz:=trunc(x*zeichnen.mass*1+mx/2); {ca. 3/4 so gross - egal}
        yz:=trunc(my/2-y*zeichnen.mass*1);
        if not ((xp=yp) and (yp=zp) and (zp=codeStoerung)) then begin
          {Zeichnen}
          if UmkehrPaintSpur.checked then with UmkehrImage_g.canvas do begin
            if UmkehrPaintFarbig.checked then begin
              temp:=abs(dx)*30000;
              rr:=trunc(temp);
              temp:=abs(dy)*30000;
              bb:=trunc(temp);
              if rr>255 then rr:=255;
              if bb>255 then bb:=255;
              gg:=0;
              pen.color:=RGBtoColor(rr, gg, bb);
            end;
            moveto(xzp,yzp);
            lineto(xz,yz);
          end;
          if counter>=Analyse.info2.stauchung then begin
            counter:=0;
            with UmkehrImage_Time do with canvas do begin {Weiterschieben}
              copyrect(rect(0,0,width-1,height),canvas,rect(1,0,width,height));
              pen.color:=clwhite;
              moveto(width-1,0); lineto(width-1,height-1);
              pen.color:=clblue;
            end;
          end;
          {Überprüfen, ob ein Vorzeichnwechsel +/- vorliergt}
          if (ddist<=0) and (ddistpre>0) then begin
            {Vorzeichenwechsel bearbeiten}
            {Zeichnen}
            if UmkehrPaintPoints.checked then with UmkehrImage_g.canvas do begin
              pen.color:=zeichnen.farbeStoerung;
              moveto(xz-5,yz-5);
              lineto(xz+5,yz+5);
              moveto(xz-5,yz+5);
              lineto(xz+5,yz-5);
              pen.color:=zeichnen.farbeSpur;
            end else with UmkehrImage_g.canvas do begin
              pixels[xz,yz]:=zeichnen.farbeStoerung;
              pixels[xz+1,yz]:=zeichnen.farbeStoerung;
              pixels[xz,yz+1]:=zeichnen.farbeStoerung;
            end;
            {Ins Diagramm namens "Poincaré-Schnitt" einzeichnen}
            if UmkehrPoincare.checked then begin
              alpha:=xytorad(y,x);
              vt:=sqrt(dx*dx+dy*dy);
              if UmkehrPunkteFarbig.checked then begin
                pgray:=trunc(150/(10*sqrt(x*x+y*y))+1);
                pcolor:=RGBtoColor(pgray,pgray,pgray);
              end else pcolor:=clblack;
              with UmkehrImage_Poincare do with canvas do begin
                ppx:=trunc(alpha*width/2/pi);
                ppy:=trunc(height-23-vt*1000*UmkehrPoincare_mass.position);
                pixels[ppx, ppy]:=pcolor;
                if UmkehrPunkteDick.checked then begin
                  pixels[ppx+1, ppy]:=pcolor;
                  pixels[ppx, ppy+1]:=pcolor;
                  pixels[ppx+1, ppy+1]:=pcolor;
                end;
              end;
            end;
            {Zeitdiagramm weiterschieben}
            with UmkehrImage_Time do with canvas do begin
              moveto(width-1,counter); lineto(width-1,height-analyse.info2.stauchung+counter-1);
              {je weiter unten, desto später}
            end;
          end;
          if not UmkehrFast.Checked then repaint;
        end else begin
          ddist:=0; {Erste Berechnung}
          dx:=0; dy:=0; dz:=0;
        end;
        ddistpre:=ddist;
        distpre:=dist;
        xzp:=xz; yzp:=yz;
        dx:=x-xp; dy:=y-yp; dz:=z-dz;
        xp:=x; yp:=y; zp:=z;
      end;
    until (ende) or eof(f);
    waitPanel.hide;
    closefile(f);
  end;
end;

procedure TForm1.UmkehrPoincareClick(Sender: TObject);
begin
  UmkehrGroup_Poincare.visible:=UmkehrPoincare.checked;
  UmkehrPoincarePanel.visible:=UmkehrPoincare.checked;
end;

procedure TForm1.UmkehrSavePoincareClick(Sender: TObject);
begin
  savePicture(UmkehrImage_Poincare);
end;

procedure TForm1.UmkehrSaveSpurClick(Sender: TObject);
begin
  savePicture(UmkehrImage_G);
end;

procedure TForm1.TabbedNotebookChange(Sender: TObject; NewTab: Integer;
  var AllowChange: Boolean);
begin
  if (zeichnen.filename='') and zeichnen.savespur then begin
    messagedlg('Um die Spur zu speichern'+#13+
               'bitte einen Dateinamen angeben !',mtwarning,[mbok],0);
    zeichnen.savespur:=false;
  end;
  if zeichnen.saveSpur then begin
    SimulationSaveLabel1.visible:=true;
    SimulationSaveLabel2.caption:=zeichnen.filename;
    SimulationSaveLabel2.visible:=true;
  end else begin
    SimulationSaveLabel1.visible:=false;
    SimulationSaveLabel2.caption:='';
    SimulationSaveLabel2.visible:=false;
  end;
end;

procedure TForm1.BahnEinVideoNameChange(Sender: TObject);
begin
  {if (fileexists(BahnEinVideoname.text)) then begin
  end else begin
  end;}
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  with VideoOpenDialog do begin
    Filename:=BahnEinVideoName.caption;
    filename:='*.AVI';
    BahnEinVideoBar.enabled:=false;
    if VideoOpenDialog.execute then begin
      BahnEinVideoName.caption:=VideoOpenDialog.filename;
      BahnEinMediaPlayer.filename:=filename;
      with BahnEinMediaPlayer do begin
        try
          display:=BahnEinVideoPanel;
          open;
          BahnEinVideoBar.min:=0;
          BahnEinVideoBar.max:=length;
          BahnEinVideoBar.SmallChange:=1;
          BahnEinVideoBar.position:=0;
          BahnEinVideoBar.enabled:=true;
          if BahnEinFrames.text>'' then Frames:=strtoint(BahnEinFrames.text) else Frames:=1;
          BahnEinVideoBar.LargeChange:=Frames;
        except
          messagedlg('Fehler beim Öffnen der Datei',mtwarning,[mbok],0);
        end;
      end;
    end;
  end;
  chDir(startDir);
end;

procedure TForm1.BahnEinFramesChange(Sender: TObject);
begin
  if BahnEinFrames.text>'' then BahnEinMediaPlayer.Frames:=strtoint(BahnEinFrames.text)
                           else BahnEinMediaPlayer.Frames:=1;
  BahnEinVideoBar.LargeChange:=BahnEinMediaPlayer.Frames;
end;

procedure TForm1.BahnEinVideoBarChange(Sender: TObject);
begin
  BahnEinFrameLabel.caption:=inttostr(BahnEinVideoBar.position);
  if (mpCanPlay in BahnEinMediaPlayer.Capabilities) and
     (not (BahnEinMediaPlayer.mode=mpPlaying)) then
    BahnEinMediaPlayer.Position:=BahnEinVideoBar.position;
end;

procedure TForm1.BahnEinVideoTimerTimer(Sender: TObject);
begin
  if not (BahnEinMediaPlayer.Mode=mpPlaying) then BahnEinVideoTimer.enabled:=false;
  BahnEinVideoBar.position:=BahnEinMediaPlayer.position;
end;

procedure TForm1.BahnEinMediaPlayerClick(Sender: TObject;
  Button: TMPBtnType; var DoDefault: Boolean);
begin
  BahnEinVideoTimer.enabled:=true;
end;

procedure TForm1.BahnEinEinlesenClick(Sender: TObject);
begin
  if BahnEinFileName.text>'' then begin
    BahnEinReadingPanel.visible:=true;
    BahnEinInfoMemo.visible:=true;
    assignfile(spurfile,BahnEinFilename.text+'.MPP');
    rewrite(SpurFile);
    BahnEinEinlesen.enabled:=false;
    BahnEinEnde.enabled:=true;
  end;
end;

procedure TForm1.bahnEinEndeClick(Sender: TObject);
begin
  write(spurfile,EndeCode,EndeCode,EndeCode);
  closefile(spurfile);
  BahnEinEnde.enabled:=false;
  BahnEinEinlesen.enabled:=true;
  BahnEinReadingPanel.visible:=false;
  BahnEinInfoMemo.visible:=false;
end;

procedure TForm1.BahnEinVideoPanelMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var px, py, pz     : extended;
    x1, y1, x2, y2 : extended;
    dx, dy         : extended;
    code           : integer;
begin
  if BahnEinReadingPanel.visible then begin
    val(BahnEinX1.text,x1,code);
    val(BahnEinY1.text,y1,code);
    val(BahnEinX2.text,x2,code);
    val(BahnEinY2.text,y2,code);
    dx:=x2-x1;
    dy:=y2-y1;
    px:=x1+dx*x/bahnEinVideoPanel.width;
    py:=y1+dy*y/bahnEinVideoPanel.height;
    if (BahnEinAuto.checked) and (mpCanPlay in BahnEinMediaPlayer.capabilities) then begin
      BahnEinMediaPlayer.stop;
      BahnEinMediaPlayer.step;
      BahnEinVideoBar.position:=BahnEinMediaPlayer.position;
    end;
    pz:=0;
    write(spurFile,px,py,pz);
  end;
end;

procedure TForm1.BahnEinPropClick(Sender: TObject);
var dx, dy, x1, x2, y1, y2 : extended;
    code                   : integer;
begin
  val(BahnEinX1.text,x1,code);
  val(BahnEinX2.text,x2,code);
  val(BahnEinY1.text,y1,code);
  dx:=x2-x1;
  dy:=3/4*dx;
  y2:=y1-dy;
  BahnEinY2.text:=exttostr(y2);
end;

procedure TForm1.BahnEinXYChange(Sender: TObject);
var x1, y1, x2, y2 : extended;
    mx, my         : extended;
    x, y           : integer;
    code           : integer;
begin
  val(BahnEinX1.text,x1,code);
  val(BahnEinY1.text,y1,code);
  val(BahnEinX2.text,x2,code);
  val(BahnEinY2.text,y2,code);
  if (x2-x1)<>0 then mx:=BahnEinVideoPanel.width*(-x1/(x2-x1)) else mx:=0;
  if (y2-y1)<>0 then my:=BahnEinVideoPanel.height*(-y1/(y2-y1)) else my:=0;
  x:=round(mx);
  y:=round(my);
  with BahnEinXImage do with canvas do begin
    brush.color:=clblack;
    fillrect(rect(0,0,width,height));
    pen.color:=cllime;
    moveto(x,0);
    lineto(x,height-1);
  end;
  with BahnEinYImage do with canvas do begin
    brush.color:=clblack;
    fillrect(rect(0,0,width,height));
    pen.color:=cllime;
    moveto(0,y);
    lineto(width-1,y);
  end;
end;

procedure TForm1.CopyrightTimerTimer(Sender: TObject);
begin
  CopyrightTimer.enabled:=false;
  CopyrightPanel.hide;
end;

procedure TForm1.CopyrightImageClick(Sender: TObject);
begin
  CopyRightTimerTimer(sender);
end;

procedure TForm1.CopyrightInfoLabelClick(Sender: TObject);
begin
  CopyrightTimer.enabled:=false;
  CopyrightMemo.visible:=true;
  CopyRightDone.visible:=true;
end;

procedure TForm1.CopyRightDoneClick(Sender: TObject);
begin
  CopyRightMemo.visible:=false;
  CopyRightPanel.visible:=false;
end;

function BahnCopyPaint(start, stop : longint; dosave : boolean) : longint;
var SpurFile : file of extended;
    i        : longint;
    x, y, z  : extended;
    px, py   : integer;
    gx, gy   : integer;
    Ende     : boolean;
    SaveFile : file of extended;
begin
  i:=0;
  if fileexists(Form1.AnalyseSpurFiles1.text+'.MPP') then begin
    if dosave then begin
      assignfile(saveFile,Form1.BahnCopyFilename.text+'.MPP');
      rewrite(saveFile);
    end;
    assignfile(Spurfile,Form1.AnalyseSpurFiles1.text+'.MPP');
    reset(SpurFile);
    i:=-1;
    Ende:=false;
    with Form1.BahnCopyImage do with canvas do begin
      brush.color:=Zeichnen.Hintergrund;
      fillrect(rect(0,0,width,height));
    end;
    repeat
      inc(i);
      read(Spurfile,x,y,z);
      if ((x=y) and (y=z) and (z=EndeCode)) or (eof(Spurfile)) then Ende:=true;
      if not Ende then with Form1.BahnCopyImage do with canvas do begin
        pen.color:=zeichnen.FarbeSpur;
        gx:=px; gy:=py;
        px:=trunc(x*zeichnen.mass+width/2);
        py:=trunc(height/2-y*zeichnen.mass);
        if (i>=start) and (i>0) and (i<=stop) then begin
          moveto(gx,gy);
          lineto(px,py);
          if dosave then begin
            write(savefile,x,y,z);
          end;
        end;
      end;
    until Ende;
    if not ((x=y) and (y=z) and (z=EndeCode)) then inc(i);
    closefile(spurfile);
    if dosave then begin
      write(savefile,EndeCode,EndeCode,EndeCode);
      closefile(savefile);
    end;
  end else begin
    messagedlg('Leider kann die Bahn'+#13+Form1.AnalyseSpurFiles1.text+'.MPP'+#13+'nicht geladen werden !',
               mtwarning,[mbcancel],0);
  end;
  BahnCopyPaint:=i;
end;

procedure TForm1.NotebookAnalyseChange(Sender: TObject; NewTab: Integer;
  var AllowChange: Boolean);
var counter : longint;
begin
  if NewTab=4 then begin
    if fileexists(AnalyseSpurFiles1.text+'.MPP') then begin
      BahnCopyPanel.visible:=true;
      WaitPanel.show;
      WaitPanel.refresh;
      BahnCopyPanel.refresh;
      BahnCopySource.caption:=AnalyseSpurFiles1.text;
      counter:=BahnCopyPaint(0,10000000,false);
      BahnCopyGesamt.text:=inttostr(counter);
      BahnCopyStart.text:='1';
      BahnCopyStop.text:=inttostr(counter);
      WaitPanel.hide;
    end else begin
      BahnCopyPanel.visible:=false;
    end;
  end;
end;

procedure TForm1.BahnCopyPlayClick(Sender: TObject);
var start, stop : longint;
    code        : integer;
begin
  val(BahnCopyStart.text,start,code);
  val(BahnCopyStop.text,stop,code);
  BahnCopyPaint(start,stop,false);
end;

procedure TForm1.BahnCopyCutClick(Sender: TObject);
var start, stop : longint;
    code        : integer;
begin
  val(BahnCopyStart.text,start,code);
  val(BahnCopyStop.text,stop,code);
  BahnCopyPaint(start,stop,true);
end;

end.





