Unit RadarEB;

Interface

Uses
  Windows, Classes, Graphics, extctrls, Math;


{==============================================================================}
{                                }Const {                                      }
{==============================================================================}
  BORDER = 10;
  NUMBER_OF_TRACE = 15;
  PI_DIV_180 = Pi / 180; //Convertion Degres en Radian
{==============================================================================}
{                                }Type {                                       }
{==============================================================================}
  TLine2D = Record
    Pt1: TPoint;
    Pt2: TPoint;
    Color: TColor;
  End;

  TRadar = Class(TThread)
  private
    { Private declarations }
    bmpRadar: TBitmap;
    ImgRadar: TImage;
    CenterXYRadar: TPoint;
    Angle: extended;
    AnglePitch: extended;
    Radius: integer;
    MinusColor: Integer;
    RadarTrace: Array[0..NUMBER_OF_TRACE] Of TLine2D;
    TraceColor: Array[0..NUMBER_OF_TRACE] Of TColor;
    ShowEcho:TPoint;
    EchoDetected: integer;
    Procedure RadarUpdate();
  public
    BackGroundColor: TColor;
    LineColor: TColor;
    Echo: TPoint;
    { Public declarations }
    Constructor Create(ImageRadar: TImage);
    Procedure Execute(); override;
    Destructor Destroy(); override;
  End;


{==============================================================================}
{                            }Implementation {                                 }
{==============================================================================}

////////////////////////////////////////////////////////////////////////////////
//Determine if a given point is on a given line.                              //
//Written by Dr Steve Evans (steve@lociuk.com)                                //
//You can use this code however you like providing the above credits remain   //
////////////////////////////////////////////////////////////////////////////////
//****************************************************************************//
// Determines if a given point (xc,yc) is on a line.                          //
// S*L = Distance of point from line.                                         //
//****************************************************************************//
Function PtIsOnLine(Pt: TPoint; Line: TLine2D; Tolerance: Extended): Boolean;
Var
  L, R, S: Double;
  XA, YA, XB, YB, XC, YC: Extended;
Begin
  XA := Line.Pt1.x;
  YA := Line.Pt1.Y;
  XB := Line.Pt2.x;
  YB := Line.Pt2.Y;
  XC := Pt.x;
  YC := Pt.y;
  Result := FALSE;
  L := SQRT(((XB - XA) * (XB - XA) + (YB - YA) * (YB - YA)));
  If l <> 0 Then
  Begin
    R := ((YA - YC) * (YA - YB) - (XA - XC) * (XB - XA)) / (L * L);
    S := ((YA - YC) * (XB - XA) - (XA - XC) * (YB - YA)) / (L * L);
    If (r > 0) And (r < 1) Then
      If Abs(S * L) <= Tolerance Then Result := TRUE; //s*l=distance
  End;
End;





//=============================================================================
//== Constructor
//=============================================================================
Constructor TRadar.Create(ImageRadar: TImage);
Var
  i: integer;
  sd: integer;
Begin
  //== Création du Thread en suspend ==
  Inherited Create(TRUE);
  Self.FreeOnTerminate := False;


  //== Memorise l'objet sur lequel nous allons dessiner le radar ==
  ImgRadar := ImageRadar;

  //== Bitmap sur lequel nous allons tjrs dessiner... ==
  //== Force la dimension du bitmap pour que ce soit carré ==
  //== Sinon, notre radar ne sera par rond ==
  sd := Min(ImgRadar.Width, ImgRadar.Height);
  bmpRadar := TBitmap.Create;
  bmpRadar.Width := sd;
  bmpRadar.Height := sd;

  bmpRadar.PixelFormat := pf24bit;

  //== Calcule le Centre du radar ==
  CenterXYRadar.X := sd Div 2;
  CenterXYRadar.Y := CenterXYRadar.X;

  //== Calcule le Rayon de notre Radar ==
  Radius := Min(CenterXYRadar.X, CenterXYRadar.Y) - BORDER;

  //== On Démarre le radar à l'angle 0 ==
  Angle := 0;

  //== Calcule l'angle pour effectuer un déplacement de 1 pixel sur la ==
  //== circonférence du cercle que forme la rotation de notre radar    ==
  AnglePitch := (180 / (Pi * Radius));

  //== Ici les couleurs...j'aime bien un radar vert...  ==
  //== On devrait utiliser le                           ==
  //== codage HSV pour être plus générique              ==
  BackGroundColor := RGB(0, 120, 0);
  LineColor := RGB(0, 220, 0);
  MinusColor := (220 - 120) Div NUMBER_OF_TRACE - 1;

  //== Initialisation des Traces au centre ==
  //== Calcules les dégradés de vert       ==
  For i := 0 To NUMBER_OF_TRACE Do
  Begin
    RadarTrace[i].Pt1 := CenterXYRadar;
    RadarTrace[i].Pt2 := CenterXYRadar;
    RadarTrace[i].Color := BackGroundColor;
    TraceColor[i] := RGB(0, 220 - (I * MinusColor), 0);
  End;

  bmpRadar.Canvas.Brush.Color := BackGroundColor;
  bmpRadar.Canvas.Brush.Style := bsSolid;
  bmpRadar.Canvas.Pen.Color := LineColor; 
  //== Maintenant que tout est prêt... on Lance le Thread ==
  Self.Resume;
End;


//=============================================================================
//== Destructor
//=============================================================================
Destructor TRadar.Destroy();
Begin
  bmpRadar.Free;
End;


//=============================================================================
//== Execute()
//=============================================================================
Procedure TRadar.Execute();
Begin
  While (Not Terminated) Do
  Begin
    Synchronize(RadarUpdate);
    sleep(5);
  End;
End;

Procedure TRadar.RadarUpdate();
Var
  i: integer;
  CircleRect: TRect;
Begin
  Angle := Angle - AnglePitch;
  If Angle < 0 Then Angle := 360;

  bmpRadar.Canvas.FillRect(bmpRadar.Canvas.ClipRect);
  //== Dessine le cercle du radar ==
  bmpRadar.Canvas.Pen.Width := 1;
  CircleRect := bmpRadar.Canvas.ClipRect;
  CircleRect := Bounds(CircleRect.TopLeft.x + BORDER Div 2
    , CircleRect.TopLeft.y + Border Div 2
    , CircleRect.Right - CircleRect.Left - BORDER
    , CircleRect.Bottom - CircleRect.Top - BORDER);
  bmpRadar.Canvas.Ellipse(CircleRect);

  bmpRadar.Canvas.Pen.Width := 2;

  //== Decale les ligne qui fond une trace derière la ligne du radar ==
  For i := High(RadarTrace) Downto 1 Do
  Begin
    RadarTrace[i].Pt2 := RadarTrace[i - 1].Pt2;
    RadarTrace[i].Color := TraceColor[i];
  End;

  //== Calcule la nouvelle position du radar ==
  RadarTrace[0].Pt1 := CenterXYRadar;
  RadarTrace[0].Pt2.X := Round(CenterXYRadar.X + (Sin(Angle * PI_DIV_180) * Radius));
  RadarTrace[0].Pt2.y := Round(CenterXYRadar.Y + (Cos(Angle * PI_DIV_180) * Radius));
  RadarTrace[0].Color := LineColor;

  //== Dessine les traces du radar
  For i := high(RadarTrace) Downto 0 Do
  Begin
    bmpRadar.Canvas.Pen.Color := RadarTrace[i].Color;
    bmpRadar.Canvas.MoveTo(RadarTrace[i].Pt1.X, RadarTrace[i].Pt1.Y);
    bmpRadar.Canvas.LineTo(RadarTrace[i].Pt2.X, RadarTrace[i].Pt2.y);
  End;

  //== Evite de déplacer l'Echo lorsqu'une detection est déjà en cours
  if ( EchoDetected = 0 )and ((ShowEcho.x<> Echo.x) or (ShowEcho.y<>Echo.y)) then
  begin
    ShowEcho.x:=Echo.x;
    ShowEcho.y:=Echo.y;
  end;

  //== Draw Echo location for debug... ===
  bmpRadar.Canvas.Pixels[Echo.x, Echo.y] := RGB(255, 255, 255);

  //== ok ici RadarTrace[0] détermine la nouvelle trace du radar  ==
  //== Verifie si l'écho est prêt de la ligne  ==
  If PtIsOnLine(ShowEcho, RadarTrace[0], 1) Then EchoDetected := NUMBER_OF_TRACE * 5;

  //== Dessine l'echo ==
  If EchoDetected > 0 Then
  Begin
    For i := (EchoDetected Div 5) Downto 0 Do
    Begin
      Case i Div 3 Of
        0: Begin
            bmpRadar.Canvas.Pen.Color := LineColor;
            CircleRect := Bounds(ShowEcho.X - 1, ShowEcho.y - 1, 2, 2);
            bmpRadar.Canvas.Pixels[ShowEcho.x, ShowEcho.y] := RGB(255, 255, 255);
          End;
        1: Begin
            bmpRadar.Canvas.Pen.Color := TraceColor[i];
            CircleRect := Bounds(ShowEcho.X - 2, ShowEcho.y - 2, 4, 4);
          End;
        2: Begin
            bmpRadar.Canvas.Pen.Color := TraceColor[i];
            CircleRect := Bounds(ShowEcho.X - 3, ShowEcho.y - 3, 6, 6);
          End;
        3: Begin
            bmpRadar.Canvas.Pen.Color := TraceColor[i];
            CircleRect := Bounds(ShowEcho.X - 4, ShowEcho.y - 4, 8, 8);
          End;
      Else Begin
          bmpRadar.Canvas.Pen.Color := TraceColor[i];
          CircleRect := Bounds(ShowEcho.X - 5, ShowEcho.y - 5, 10, 10);
        End;
      End;

      bmpRadar.Canvas.Ellipse(CircleRect);
    End;
    //== Reduit le temps d'affichage de l'echo ==
    EchoDetected := EchoDetected - 1;
  End;

  //== Mise a jour de l'image...à l'écran ==
  ImgRadar.Canvas.CopyRect(  bmpRadar.Canvas.ClipRect
                           , bmpRadar.Canvas
                           , bmpRadar.Canvas.ClipRect);
end;



End.

