//Advanced Delphi Systems Code: ads_Canvas
unit ads_Canvas;
{Copyright(c)2016 Advanced Delphi Systems

 Richard Maley
 Advanced Delphi Systems
 12613 Maidens Bower Drive
 Potomac, MD 20854 USA
 phone 301-840-1554
 dickmaley@advdelphisys.com

 The code herein can be used or modified by anyone.  Please retain references
 to Richard Maley at Advanced Delphi Systems.  If you make improvements to the
 code please send your improvements to dickmaley@advdelphisys.com so that the
 entire Delphi community can benefit.  All comments are welcome.
}
(*
UnitIndex Master Index Implementation Section Download Units
Description: ads_Canvas.pas
This unit contains the following routines.

Circle_1   Circle_2   Circle_3   DistanceFromAxis   DistanceTweenPoints  Ellipse   EllipseDrawHalf   G0DistanceOnLine_1   G0DistanceOnLine_2   GetEllipseHalfChord  GetEllipsePoint   Heart   MarkPoint  

*)
interface
Uses Graphics, Dialogs, SysUtils,Windows, Math;

procedure Heart(
  Canvas : TCanvas;
  Top    : Integer;
  Left   : Integer;
  Height : Integer;
  Width  : Integer
  );

Function Ellipse(
  Canvas      : TCanvas;
  Apogeex     : Integer;
  Apogeey     : Integer;
  Perigeex    : Integer;
  Perigeey    : Integer;
  Width       : Integer;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor): Boolean;

Procedure Circle(
  Canvas      : TCanvas;
  DiameterPt1 : TPoint;
  DiameterPt2 : TPoint;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor); OverLoad;

Procedure Circle(
  Canvas      : TCanvas;
  Center      : TPoint;
  Width       : Extended;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor); OverLoad;

Procedure Circle(
  Canvas      : TCanvas;
  DiameterPt1x: Integer;
  DiameterPt1y: Integer;
  DiameterPt2x: Integer;
  DiameterPt2y: Integer;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor); OverLoad;

Function EllipseDrawHalf(
  Canvas    : TCanvas;
  Apogee    : TPoint;
  Perigee   : TPoint;
  Width     : Extended;
  LeftHalf  : Boolean): TPoint;

Function G0DistanceOnLine(StartPoint : TPoint; Slope: Extended;Distance: Extended;Plusx:Boolean): TPoint;Overload;

Function G0DistanceOnLine(
  StartPoint : TPoint;
  Distance   : Extended;
  Angle      : Extended): TPoint; OverLoad;

Function DistanceFromAxis(CurrentPoint,FocusPoint: TPoint; Slope,a: Extended;Plusx:Boolean): TPoint;

Function DistanceTweenPoints(Point1,Point2: TPoint): Extended;

Procedure MarkPoint(Canvas : TCanvas;Point : TPoint);

Function GetEllipseHalfChord(
  Length : Extended;
  Width  : Extended;
  Section: Extended): Extended;

Function GetEllipsePoint(
  AxisPt : TPoint;
  Length : Extended;
  Width  : Extended;
  Section: Extended;
  Slope  : Extended;
  ToLeft : Boolean): TPoint;

implementation


//
Unit Description UnitIndex Master Index
Function G0DistanceOnLine(StartPoint : TPoint; Slope: Extended;Distance: Extended;Plusx:Boolean): TPoint;
Var
  inCounter : Integer;
  Dist      : Extended;
  NewPoint  : TPoint;
  NewPointx : Extended;
  NewPointy : Extended;
  Intercept : Extended;
  Lowx      : Extended;
  Highx     : Extended;
  Curx      : Extended;
  Quality   : Extended;
Begin
  NewPoint.x := StartPoint.x;
  NewPoint.y := StartPoint.y;
  If Distance = 0.0 Then Exit;
  If Plusx Then
  Begin
    Lowx       := StartPoint.x;
    Highx      := StartPoint.x+Distance;
  End
  Else
  Begin
    Lowx       := StartPoint.x-Distance;
    Highx      := StartPoint.x;
  End;
  Curx       := Lowx+((Highx-Lowx)/2);
  Intercept  := StartPoint.y-(Slope*StartPoint.x);
  If Slope <> 0 Then
  Begin
    For inCounter := 1 To 1000 Do
    Begin
      NewPointx := Curx;
      NewPointy := (Slope*NewPointx)+ Intercept;
      Dist      :=
        Sqrt(
          ((StartPoint.x-NewPointx)*(StartPoint.x-NewPointx))+
          ((StartPoint.y-NewPointy)*(StartPoint.y-NewPointy)));
      Quality := (Abs(Distance-Dist)/Distance);
      If Quality < 0.00001 Then
      Begin
        NewPoint.x := StrToInt(FloatToStr(Int(NewPointx)));
        NewPoint.y := StrToInt(FloatToStr(Int(NewPointy)));
        Break;
      End;
      If Dist > Distance Then
      Begin
        If Plusx Then
          Highx := Curx
        Else
          Lowx := Curx;
      End
      Else
      Begin
        If Plusx Then
          Lowx := Curx
        Else
          Highx := Curx;
      End;
      Curx       := Lowx+((Highx-Lowx)/2);
    End;
  End
  Else
  Begin
    If Plusx Then
    Begin
      Lowx       := StartPoint.y;
      Highx      := StartPoint.y+Distance;
    End
    Else
    Begin
      Lowx       := StartPoint.y-Distance;
      Highx      := StartPoint.y;
    End;
    Curx       := Lowx+((Highx-Lowx)/2);
    For inCounter := 1 To 1000 Do
    Begin
      NewPointx := StartPoint.x;
      NewPointy := Curx;
      Dist      :=
        Sqrt(
          ((StartPoint.x-NewPointx)*(StartPoint.x-NewPointx))+
          ((StartPoint.y-NewPointy)*(StartPoint.y-NewPointy)));
      Quality := (Abs(Distance-Dist)/Distance);
      If Quality < 0.00001 Then
      Begin
        NewPoint.x := StrToInt(FloatToStr(Int(NewPointx)));
        NewPoint.y := StrToInt(FloatToStr(Int(NewPointy)));
        Break;
      End;
      If Dist > Distance Then
      Begin
        If Plusx Then
          Highx := Curx
        Else
          Lowx := Curx;
      End
      Else
      Begin
        If Plusx Then
          Lowx := Curx
        Else
          Highx := Curx;
      End;
      Curx       := Lowx+((Highx-Lowx)/2);
    End;
  End;
  Result := NewPoint;
End;

//
Unit Description UnitIndex Master Index
Function Ellipse(
  Canvas      : TCanvas;
  Apogeex     : Integer;
  Apogeey     : Integer;
  Perigeex    : Integer;
  Perigeey    : Integer;
  Width       : Integer;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor): Boolean;
Var
  Apogee     : TPoint;
  Perigee    : TPoint;
  Temp1      : TPoint;
  Temp2      : TPoint;
  Center     : TPoint;
  End1       : TPoint;
  End2       : TPoint;
Begin
  Result := True;
  Try
    Apogee.x  := Apogeex;
    Apogee.y  := Apogeey;
    Perigee.x := Perigeex;
    Perigee.y := Perigeey;
    If Apogee.x > Perigee.x Then
    Begin
      Temp1  := Apogee;
      Temp2  := Perigee;
      Apogee := Temp2;
      Perigee:= Temp1;
    End;
    If Apogee.x > Perigee.x Then
      Center.x  := ((Apogee.x - Perigee.x) div 2) + Perigee.x
      Else
      Center.x  := ((Perigee.x - Apogee.x) div 2) + Apogee.x;
    If Apogee.y > Perigee.y Then
      Center.y  := ((Apogee.y - Perigee.y) div 2) + Perigee.y
      Else
      Center.y  := ((Perigee.y - Apogee.y) div 2) + Apogee.y;
    Canvas.Pen.Color := BorderColor;
    End1 :=
      EllipseDrawHalf(
        Canvas , //Canvas    : TCanvas;
        Apogee , //Apogee    : TPoint;
        Perigee, //Perigee   : TPoint;
        Width  , //Width     : Extended;
        True   );//LeftHalf  : Boolean);
    End2 :=
      EllipseDrawHalf(
        Canvas , //Canvas    : TCanvas;
        Apogee , //Apogee    : TPoint;
        Perigee, //Perigee   : TPoint;
        Width  , //Width     : Extended;
        False  );//LeftHalf  : Boolean);
    With Canvas Do
    Begin
      MoveTo(End1.x,End1.y);
      LineTo(Perigee.x,Perigee.y);
      LineTo(End2.x,End2.y);
      If Fill Then
      Begin
        Brush.Color := FillColor;
        FloodFill(
          center.x,
          center.y,
          BorderColor,
          fsBorder);
      End;
      Refresh;
    End;
  Except
    Result := False;
  End;
End;

//
Unit Description UnitIndex Master Index
Function DistanceFromAxis(CurrentPoint,FocusPoint: TPoint; Slope,a: Extended;Plusx:Boolean): TPoint;
Var
  AxisX     : Extended;
  HalfChord : Extended;
  HafChord  : Integer;
  rlSlope   : Extended;
Begin
  AxisX     := DistanceTweenPoints(CurrentPoint,FocusPoint);
  HalfChord :=
    sqrt(
      ((((2*a)+(AxisX*AxisX))*((2*a)+(AxisX*AxisX)))-(AxisX*AxisX))
         );
  HafChord  := StrToInt(FloatToStr(Int(HalfChord)));
  If Slope = 0 Then
  Begin
    rlSlope := 1;
  End
  Else
  Begin
    rlSlope := -1/Slope;
  End;
  Result    :=
    G0DistanceOnLine(
      CurrentPoint, //StartPoint : TPoint;
      rlSlope     , //Slope: Extended;
      HafChord    , //Distance: Integer;
      PlusX       );//Plusx:Boolean): TPoint;
End;

//
Unit Description UnitIndex Master Index
Function DistanceTweenPoints(Point1,Point2: TPoint): Extended;
Begin
  Try
    Result     :=
      sqrt(
        ((Point1.x-Point2.x)*(Point1.x-Point2.x))
        +
        ((Point1.y-Point2.y)*(Point1.y-Point2.y)));
  Except
    Result := 0.00;
  End;
End;

//
Unit Description UnitIndex Master Index
Procedure MarkPoint(Canvas : TCanvas;Point : TPoint);
Begin
  With Canvas Do
  Begin
    MoveTo(Point.x,Point.y);
    LineTo(Point.x-5,Point.y);
    MoveTo(Point.x,Point.y);
    LineTo(Point.x+5,Point.y);
    MoveTo(Point.x,Point.y);
    LineTo(Point.x,Point.y-5);
    MoveTo(Point.x,Point.y);
    LineTo(Point.x,Point.y+5);
  End;
End;

//
Unit Description UnitIndex Master Index
Function GetEllipseHalfChord(
  Length : Extended;
  Width  : Extended;
  Section: Extended): Extended;
Var
  a      : Extended;
  b      : Extended;
  x      : Extended;
  xx     : Extended;
  aa     : Extended;
  bb     : Extended;
Begin
  Result := 0.0;
  a      := Length/2;
  b      := Width/2;
  If Section > Length Then Section := Length;
  If Section < 0.0    Then Section := 0.0;
  x      := Section-a;
  xx     := (x*x);
  aa     := (a*a);
  bb     := (b*b);
  If a = 0.0 Then Exit;
  Result :=
    sqrt(
      (1-((xx)/(aa)))*(bb)
         );
End;

//
Unit Description UnitIndex Master Index
Function GetEllipsePoint(
  AxisPt : TPoint;
  Length : Extended;
  Width  : Extended;
  Section: Extended;
  Slope  : Extended;
  ToLeft : Boolean): TPoint;
Var
  Dist   : Extended;
  inDist : Integer;
  rlSlope: Extended;
Begin
  Dist   :=
    GetEllipseHalfChord(
      Length , //Length : Extended;
      Width  , //Width  : Extended;
      Section);//Section: Extended): Extended;
  inDist := StrToInt(FloatToStr(Int(Dist)));
  If Slope = 0 Then
  Begin
    rlSlope := 1;
  End
  Else
  Begin
    rlSlope := -1/Slope;
  End;

  Result    :=
    G0DistanceOnLine(
      AxisPt      , //StartPoint : TPoint;
      rlSlope     , //Slope: Extended;
      inDist      , //Distance: Integer;
      ToLeft      );//Plusx:Boolean): TPoint;
End;

//
Unit Description UnitIndex Master Index
Function EllipseDrawHalf(
  Canvas    : TCanvas;
  Apogee    : TPoint;
  Perigee   : TPoint;
  Width     : Extended;
  LeftHalf  : Boolean): TPoint;
Var
  Slope     : Extended;
  LastAxis  : TPoint;
  LastPoint : TPoint;
  CurAxis   : TPoint;
  AxisDelta : Integer;
  AxisCum   : Integer;
  NewPoint  : TPoint;
  a         : Extended;
  Length    : Extended;
Begin
  Result    := Apogee;
  Length    := DistanceTweenPoints(Apogee,Perigee);
  If Length = 0 Then Exit;
  If Width  = 0 Then Exit;
  If (Apogee.x-Perigee.x) = 0.00 Then
    Slope := 999999.0
  Else
    slope := (Apogee.y-Perigee.y)/(Apogee.x-Perigee.x);
  a         := Length / 2;
  With Canvas Do
  Begin
    MoveTo(Apogee.x,Apogee.y);
    LastAxis   := Apogee;
    LastPoint  := Apogee;
    AxisDelta  := 1;
    AxisCum    := 0;
    While True Do
    Begin
      AxisCum    := AxisCum + AxisDelta;
      If AxisCum > 2*a Then
      Begin
        CurAxis    := Perigee;
      End
      Else
      Begin
        If (Abs(Slope) > 0) And (Abs(Slope) < 999999.0) Then
        Begin
          CurAxis    := G0DistanceOnLine(Apogee,Slope,AxisCum,True);
          If LeftHalf Then
            NewPoint   :=
              GetEllipsePoint(
                CurAxis, //AxisPt : TPoint;
                2*a    , //Length : Extended;
                Width  , //Width  : Extended;
                AxisCum, //Section: Extended;
                Slope  , //Slope  : Extended;
                True   )//ToLeft : Boolean): TPoint;
          Else
            NewPoint   :=
              GetEllipsePoint(
                CurAxis, //AxisPt : TPoint;
                2*a    , //Length : Extended;
                Width  , //Width  : Extended;
                AxisCum, //Section: Extended;
                Slope  , //Slope  : Extended;
                False  );//ToLeft : Boolean): TPoint;
        End
        Else
        Begin
          If Slope = 0 Then
          Begin
            CurAxis    := Apogee;
            CurAxis.x  := Apogee.x+AxisCum;
            NewPoint   := CurAxis;
            If LeftHalf Then
              NewPoint.y :=
                NewPoint.y +
                StrToInt(FloatToStr(Int(
                GetEllipseHalfChord(
                  2*a,
                  Width,
                  AxisCum)
                  )))
            Else
              NewPoint.y :=
                NewPoint.y -
                StrToInt(FloatToStr(Int(
                GetEllipseHalfChord(
                  2*a,
                  Width,
                  AxisCum)
                  )));
          End
          Else
          Begin
            CurAxis    := Apogee;
            CurAxis.y  := Apogee.y+AxisCum;
            NewPoint   := CurAxis;
            If LeftHalf Then
              NewPoint.x :=
                NewPoint.x +
                StrToInt(FloatToStr(Int(
                GetEllipseHalfChord(
                  2*a,
                  Width,
                  AxisCum)
                  )))
            Else
              NewPoint.x :=
                NewPoint.x -
                StrToInt(FloatToStr(Int(
                GetEllipseHalfChord(
                  2*a,
                  Width,
                  AxisCum)
                  )));
          End;
        End;
      End;
      MoveTo(LastPoint.x,LastPoint.y);
      Result := LastPoint;
      LineTo(NewPoint.x,NewPoint.y);
      LastPoint := NewPoint;
      LastAxis := CurAxis;
      If AxisCum > 2*a Then
      Begin
        MoveTo(NewPoint.x,NewPoint.y);
        LineTo(Perigee.x,Perigee.y);
        If Slope = 0 Then
        Begin
          LineTo(Perigee.x,Perigee.y+3);
          LineTo(Perigee.x,Perigee.y-6);
        End
        Else
        Begin
          If Abs(Slope) > 9999 Then
          Begin
            LineTo(Perigee.x+3,Perigee.y);
            LineTo(Perigee.x-6,Perigee.y);
          End;
        End;
        Break;
      End;
    End;
  End;
End;

//
Unit Description UnitIndex Master Index
procedure Heart(
  Canvas : TCanvas;
  Top    : Integer;
  Left   : Integer;
  Height : Integer;
  Width  : Integer
  );
Var
  BoxLeftx  : integer;
  BoxLefty  : integer;
  BoxRightx : integer;
  BoxRighty : integer;
  ArcStartx : integer;
  ArcStarty : integer;
  ArcEndx   : integer;
  ArcEndy   : integer;
begin
  Top    := 100;
  Left   := 100;
  Height := 300;
  Width  := 100;
  With Canvas Do
  Begin
    BoxLeftx  := Left+(width div 2);
    BoxLefty  := Top;
    BoxRightx := Left+Width;
    BoxRighty := Top+Height;
    ArcStartx := BoxRightx;
    ArcStarty := Top+(Height div 2);
    ArcEndx   := BoxLeftx;
    ArcEndy   := ArcStarty;
    MoveTo(ArcStartx,ArcStarty);
    Arc(
      BoxLeftx,
      BoxLefty,
      BoxRightx,
      BoxRighty,
      ArcStartx,
      ArcStarty,
      ArcEndx,
      ArcEndy);
    BoxLeftx  := Left;
    BoxLefty  := Top;
    BoxRightx := Left+(Width div 2);
    BoxRighty := Top+Height;
    ArcStartx := BoxRightx;
    ArcStarty := Top+(Height div 2);
    ArcEndx   := BoxLeftx;
    ArcEndy   := ArcStarty;
    MoveTo(ArcStartx,ArcStarty);
    Arc(
      BoxLeftx,
      BoxLefty,
      BoxRightx,
      BoxRighty,
      ArcStartx,
      ArcStarty,
      ArcEndx,
      ArcEndy);

    BoxLeftx  := Left-(17*Width);
    BoxLefty  := Top-Height;
    BoxRightx := Left+Width;
    BoxRighty := Top+(Height*2);
    ArcStartx := Left+(Width div 2);
    ArcStarty := Top+Height-2;
    ArcEndx   := Left+Width;
    ArcEndy   := Top+(Height div 2);
    Arc(
      BoxLeftx,
      BoxLefty,
      BoxRightx,
      BoxRighty,
      ArcStartx,
      ArcStarty,
      ArcEndx,
      ArcEndy);

    BoxLeftx  := Left;
    BoxLefty  := Top-Height;
    BoxRightx := Left+Width+(17*Width);
    BoxRighty := Top+(Height*2);
    ArcStartx := Left;
    ArcStarty := Top+(Height div 2);
    ArcEndx   := Left+(Width div 2);
    ArcEndy   := Top+Height-2;
    Arc(
      BoxLeftx,
      BoxLefty,
      BoxRightx,
      BoxRighty,
      ArcStartx,
      ArcStarty,
      ArcEndx,
      ArcEndy);
    Brush.Color := clRed;
    FloodFill(
      Left+(width div 2),
      Top+height-(height div 4),
      clBlack,
      fsBorder);
  End;
end;

//
Unit Description UnitIndex Master Index
Procedure Circle(
  Canvas      : TCanvas;
  DiameterPt1 : TPoint;
  DiameterPt2 : TPoint;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor);
Var
  Width       : Integer;
  Apogeex     : Integer;
  Apogeey     : Integer;
  Perigeex    : Integer;
  Perigeey    : Integer;
Begin
  Width       := StrToInt(FloatToStr(Int(DistanceTweenPoints(DiameterPt1,DiameterPt2))));
  Apogeex     := DiameterPt1.x;
  Apogeey     := DiameterPt1.y;
  Perigeex    := DiameterPt2.x;
  Perigeey    := DiameterPt2.y;

  Ellipse(
    Canvas      , //Canvas      : TCanvas;
    Apogeex     , //Apogeex     : Integer;
    Apogeey     , //Apogeey     : Integer;
    Perigeex    , //Perigeex    : Integer;
    Perigeey    , //Perigeey    : Integer;
    Width       , //Width       : Integer;
    Fill        , //Fill        : Boolean;
    FillColor   , //FillColor   : TColor;
    BorderColor );//BorderColor : TColor): Boolean;
End;

//
Unit Description UnitIndex Master Index
Procedure Circle(
  Canvas      : TCanvas;
  DiameterPt1x: Integer;
  DiameterPt1y: Integer;
  DiameterPt2x: Integer;
  DiameterPt2y: Integer;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor); OverLoad;
Var
  DiameterPt1 : TPoint;
  DiameterPt2 : TPoint;
Begin
  DiameterPt1.x := DiameterPt1x;
  DiameterPt1.y := DiameterPt1y;
  DiameterPt2.x := DiameterPt2x;
  DiameterPt2.y := DiameterPt2y;
  Circle(
    Canvas      , //Canvas      : TCanvas;
    DiameterPt1 , //DiameterPt1 : TPoint;
    DiameterPt2 , //DiameterPt2 : TPoint;
    Fill        , //Fill        : Boolean;
    FillColor   , //FillColor   : TColor;
    BorderColor );//BorderColor : TColor);
End;

//
Unit Description UnitIndex Master Index
Procedure Circle(
  Canvas      : TCanvas;
  Center      : TPoint;
  Width       : Extended;
  Fill        : Boolean;
  FillColor   : TColor;
  BorderColor : TColor); OverLoad;
Var
  DiameterPt1 : TPoint;
  DiameterPt2 : TPoint;
  Radius      : Extended;
Begin
  Radius      := Width/2;
  DiameterPt1 :=
    G0DistanceOnLine(
      Center, //StartPoint    : TPoint;
      0     , //Slope         : Extended;
      Radius, //Distance      : Extended;
      False );//Plusx:Boolean): TPoint;
  DiameterPt2 :=
    G0DistanceOnLine(
      Center, //StartPoint    : TPoint;
      0     , //Slope         : Extended;
      Radius, //Distance      : Extended;
      True );//Plusx:Boolean): TPoint;
  Circle(
    Canvas      , //Canvas      : TCanvas;
    DiameterPt1 , //DiameterPt1 : TPoint;
    DiameterPt2 , //DiameterPt2 : TPoint;
    Fill        , //Fill        : Boolean;
    FillColor   , //FillColor   : TColor;
    BorderColor );//BorderColor : TColor);
End;

//
Unit Description UnitIndex Master Index
Function G0DistanceOnLine(
  StartPoint : TPoint;
  Distance   : Extended;
  Angle      : Extended): TPoint; OverLoad;
Var
  Slope      : Extended;
  Plusx      : Boolean;
Begin
  If (Angle >= (90-2)) And (Angle <= (90+2)) Then
  Begin
    Slope := 999;
  End
  Else
  Begin
    If (Angle >= (270-2)) And (Angle <= (270+2)) Then
    Begin
      Slope := 999;
    End
    Else
    Begin
      If Angle = 0.0 Then
      Begin
        Slope := 0.00001;
      End
      Else
      Begin
        Slope      := Tan(Angle*(pi/180))*-1;
      End;
    End;
  End;
  Plusx      := (((Angle >= 0 ) And (Angle < 90)) Or ((Angle > 270 ) And (Angle <= 360)));
  If (Angle >= (90-2)) And (Angle <= (90+2)) Then Plusx := False;
  If (Angle >= (270-2)) And (Angle <= (270+2)) Then Plusx := True;
  Result     :=
    G0DistanceOnLine(
      StartPoint, //StartPoint : TPoint;
      Slope     , //Slope: Extended;
      Distance  , //Distance: Extended;
      Plusx     );//Plusx:Boolean): TPoint;Overload;
End;


end.
//