unit _math;
//----------------------------------------------------------------------------------------------------------------------
// Alex 'Shirson' Nevskiy 2012-09
//----------------------------------------------------------------------------------------------------------------------
interface
uses LevelSys;

const
  pi180=0.01745329251;

function  GetAngle(x0,y0,x1,y1:integer):single;
procedure BLine(x0, y0, x1, y1:integer; out Line: TPointsAr);
procedure BCircle (Center:TPoint; Radius:integer; out Circle: TPointsAr);
procedure BEllipse(CX, CY, XRadius, YRadius:integer; out Ellipse: TPointsAr);
function  Dist(x0, y0, x1, y1:integer):single;
procedure Trajectory(x0, y0:integer; var x1, y1:integer; Deviation:single); overload;
procedure Trajectory(x0, y0, x1, y1:integer; var dx, dy:single; Deviation:single); overload;

implementation
uses _var;

//----------------------------------------------------------------------------------------------------------------------

function GetAngle(x0,y0,x1,y1:integer):single;
var xx,yy: integer;
    res:single;
begin
  xx:=x1-x0;
  yy:=y1-y0;
  Result:=180;
  if (xx=0) and (yy>0) then exit;
  Result:=0;
  if (xx=0) and (yy<0) then exit;
  res:=abs(arctan(yy/xx)/pi180);
  if (xx>0) and (yy>0) then res:=90+res;
  if (xx<0) and (yy>0) then res:=-1*(90+res);
  if (xx<0) and (yy<0) then res:=-1*(90-res);
  if (xx>0) and (yy<0) then res:=90-res;
  if (xx>0) and (yy=0) then res:=90;
  if (xx<0) and (yy=0) then res:=-90;

  result:=res;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure BLine(x0, y0, x1, y1:integer; out Line: TPointsAr);
var e2, err, sx, sy, dx, dy:integer;
begin
  SetLength(Line, 0);
  dx := abs(x1-x0);
  dy := abs(y1-y0);
  if x0 < x1 then sx := 1 else sx := -1;
  if y0 < y1 then sy := 1 else sy := -1;
  err:= dx-dy;
  repeat
    SetLength(Line, High(Line)+2);
    Line[High(Line)].x:=x0;
    Line[High(Line)].y:=y0;
    if ((x0 = x1) and (y0 = y1)) then exit;
    e2 := 2*err;
    if e2 > -dy then
    begin
      err := err - dy;
      x0 := x0 + sx;
    end;
    if e2 < dx then
    begin
      err := err + dx;
      y0 := y0 + sy;
    end
  until false;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure BCircle (Center:TPoint; Radius:integer; out Circle: TPointsAr);
var F, ddF_X, ddF_Y, X, Y: integer;
    rX:single;

    procedure AddPoint(x0,y0:integer; var Circle: TPointsAr);
    begin
      SetLength(Circle, High(Circle)+2);
      Circle[High(Circle)].X:=x0;
      Circle[High(Circle)].y:=y0;
    end;

begin
   F:= 1 - Radius;
   ddF_X:= 0;  ddF_Y:= -2 * Radius;
   x:=0; Y:=radius;
   rX:=0;

   AddPoint(Center.X, Center.Y + Radius, Circle);
   AddPoint(Center.X, Center.Y - Radius, Circle);
   AddPoint(Center.X + Radius, Center.Y, Circle);
   AddPoint(Center.X - Radius, Center.Y, Circle);
   while X < Y do
   begin
      if F >= 0 then
      begin
         Y := Y - 1;
         ddF_Y := ddF_Y + 2;
         F := F + ddF_Y;
      end;
      rX:=rX+1;
      x:=trunc(Rx*PixelP);
      //X := X + 1;
      ddF_X := ddF_X + 2;
      F := F + ddF_X + 1;
      AddPoint(Center.X + X, Center.Y + Y, Circle);
      AddPoint(Center.X - X, Center.Y + Y, Circle);
      AddPoint(Center.X + X, Center.Y - Y, Circle);
      AddPoint(Center.X - X, Center.Y - Y, Circle);
      AddPoint(Center.X + Y, Center.Y + X, Circle);
      AddPoint(Center.X - Y, Center.Y + X, Circle);
      AddPoint(Center.X + Y, Center.Y - X, Circle);
      AddPoint(Center.X - Y, Center.Y - X, Circle);
   end;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure BEllipse(CX, CY, XRadius, YRadius:integer; out Ellipse: TPointsAr);
var X, Y : longint;
  XChange, YChange : longint;
  EllipseError : longint;
  TwoASquare, TwoBSquare : longint;
  StoppingX, StoppingY : longint;

    procedure AddPoint(x0,y0:integer; var Ellipse: TPointsAr);
    begin
      SetLength(Ellipse, High(Ellipse)+2);
      Ellipse[High(Ellipse)].X:=x0;
      Ellipse[High(Ellipse)].y:=y0;
    end;

    procedure Plot4EllipsePoints(X,Y:integer);
    begin
      AddPoint(CX+X, CY+Y, Ellipse); {point in quadrant 1}
      AddPoint(CX-X, CY+Y, Ellipse); {point in quadrant 2}
      AddPoint(CX-X, CY-Y, Ellipse); {point in quadrant 3}
      AddPoint(CX+X, CY-Y, Ellipse); {point in quadrant 4}
    end;

begin
  TwoASquare := 2*XRadius*XRadius;
  TwoBSquare := 2*YRadius*YRadius;
  X := XRadius;
  Y := 0;
  XChange := YRadius*YRadius*(1-2*XRadius);
  YChange := XRadius*XRadius;
  EllipseError := 0;
  StoppingX := TwoBSquare*XRadius;
  StoppingY := 0;
  while ( StoppingX >= StoppingY ) do
  begin
    Plot4EllipsePoints(X,Y);
    inc(Y);
    inc(StoppingY, TwoASquare);
    inc(EllipseError, YChange);
    inc(YChange, TwoASquare);
    if ((2*EllipseError + XChange) > 0 ) then
    begin
      dec(X);
      dec(StoppingX, TwoBSquare);
      inc(EllipseError, XChange);
      inc(XChange,TwoBSquare)
    end
  end;

  X := 0;
  Y := YRadius;
  XChange := YRadius*YRadius;
  YChange := XRadius*XRadius*(1-2*YRadius);
  EllipseError := 0;
  StoppingX := 0;
  StoppingY := TwoASquare*YRadius;
  while ( StoppingX <= StoppingY ) do {2nd set of points, yw< ƒñ1}
  begin
    Plot4EllipsePoints(X,Y); {subroutine appears later}
    inc(X);
    inc(StoppingX, TwoBSquare);
    inc(EllipseError, XChange);
    inc(XChange,TwoBSquare);
    if ((2*EllipseError + YChange) > 0 ) then
    begin
      dec(Y);
      dec(StoppingY, TwoASquare);
      inc(EllipseError, YChange);
      inc(YChange,TwoASquare)
    end
  end
end; {procedure PlotEllipse}

//----------------------------------------------------------------------------------------------------------------------

function Dist(x0, y0, x1, y1:integer):single;
begin
  result:=sqrt(sqr((x0-x1)/PixelP) + sqr(y0-y1));
end;

//----------------------------------------------------------------------------------------------------------------------

procedure Trajectory(x0, y0:integer; var x1, y1:integer; Deviation:single); overload;
var Ang:single;
begin
  Ang:=GetAngle(x0, y0, x1, y1);
  Ang:=Ang + random * (Deviation * 2) - Deviation;
  x1:=trunc(AimDist*sin(Ang*pi180));
  y1:=trunc(AimDist*cos(Ang*pi180));
  x1:=x0 + x1;
  y1:=y0 - y1;
end;

//----------------------------------------------------------------------------------------------------------------------

procedure Trajectory(x0, y0, x1, y1:integer; var dx, dy:single; Deviation:single); overload;
var Ang:single;
begin
  Ang:=GetAngle(x0, y0, x1, y1);
  Ang:=Ang + random * (Deviation * 2) - Deviation;
  dx:=trunc(AimDist*sin(Ang*pi180));
  dy:=trunc(AimDist*cos(Ang*pi180));
end;

//----------------------------------------------------------------------------------------------------------------------

end.
