```unit AdvancedMathUnit;

interface

uses
Math;

const
{---Math Pre-Calculations---}
Pi                 = 3.1415926535897932384626433832795;
Pi_Div_180         = Pi / 180;       {Multiply by this for Convertion to Radians}
Pi_Div_180_Mul_360 = 360 * Pi / 180; {360 Degrees in Radians}

var
{--- Trig Lookup Tables ---}
getSIN,
getCOS,
getTAN: Array[-360 .. 360] of Extended;

{Pre-Calculate SIN and COS Tables}
procedure PreCalculate_Trig;

function GetDistance(X1, Y1, X2, Y2: Extended): Extended;

{Angle of Dest Point in Degrees and Radians}
function GetAngleToDestinationDeg(OriginX, OriginY, DestX, DestY: Extended): Integer;
function GetAngleToDestinationRad(OriginX, OriginY, DestX, DestY: Extended): Extended;

{X/Y 2-D Rotation for Degrees and Radians}
function RotateXDeg(oX, oY: Extended; AngleinDegrees: Integer): Extended;
function RotateYDeg(oX, oY: Extended; AngleinDegrees: Integer): Extended;

implementation

{Pre-Calculate SIN, COS & TAN Tables}
procedure PreCalculate_Trig;
var i: Integer;
begin
// Sine
for i := Low(getSIN) to High(getSIN) do
getSIN[i] := sin(i * Pi_Div_180);
// Cosine
for i := Low(getCOS) to High(getCOS) do
getCOS[i] := cos(i * Pi_Div_180);
// Tangent
for i := Low(getTAN) to High(getTAN) do
getTAN[i] := tan(i * Pi_Div_180);
end;

{Get Distance of two Points}
function GetDistance(X1, Y1, X2, Y2: Extended): Extended;
begin
Result := sqrt((X2 - X1) * (X2 - X1) + (Y2 - Y1) * (Y2 - Y1));
end;

{Angle of Dest Point in Degrees and Radians}
function GetAngleToDestinationDeg(OriginX, OriginY, DestX, DestY: Extended): Integer;
var XDiff: Extended;
begin
if (OriginX = DestX) and (OriginY = DestY) then
begin
Result := 0;
Exit;
end;

XDiff := DestX - OriginX;
if (XDiff = 0) then
XDiff := 0.0001; // XDiff Cannot be Zero!

if (OriginY > DestY) then
Result := Round(360 - RadToDeg(ArcCos(XDiff / GetDistance(OriginX, OriginY, DestX, DestY))))
else
Result := Round(RadToDeg(ArcCos(XDiff / GetDistance(OriginX, OriginY, DestX, DestY))));
end;
function GetAngleToDestinationRad(OriginX, OriginY, DestX, DestY: Extended): Extended;
var XDiff: Extended;
begin
if (OriginX = DestX) and (OriginY = DestY) then
begin
Result := 0;
Exit;
end;

XDiff := DestX - OriginX;
if (XDiff = 0) then
XDiff := 0.0001; // XDiff Cannot be Zero!

if (OriginY > DestY) then
Result := Pi_Div_180_Mul_360 - ArcCos(XDiff / GetDistance(OriginX, OriginY, DestX, DestY))
else
Result := ArcCos(XDiff / GetDistance(OriginX, OriginY, DestX, DestY));
end;

{X/Y 2-D Rotation for Degrees and Radians}
{X Only}
function RotateXDeg(oX, oY: Extended; AngleinDegrees: Integer): Extended;
begin
Result := oX * getCOS[AngleinDegrees] - oY * getSIN[AngleinDegrees];
end;
begin
end;
{Y Only}
function RotateYDeg(oX, oY: Extended; AngleinDegrees: Integer): Extended;
begin
Result := oX * getSIN[AngleinDegrees] + oY * getCOS[AngleinDegrees];
end;