{$mode objfpc}
unit dvector2f;

interface

uses
  dmath,
  dvector2i;

type
TFloat = Single;

PVec2f = ^TVec2f;
TVec2f = packed record
case Integer of
  0: (X, Y: TFloat);
  1: (Arr: array[0..1] of TFloat);
end;

const
  Zero2f: TVec2f = (X: 0; Y: 0);

function Vec2f(X, Y: TFloat): TVec2f; inline;
function Vec2f(const V: TVec2i): TVec2f; inline;
function Add2f(const A, B: TVec2f): TVec2f; inline;
function Sub2f(const A, B: TVec2f): TVec2f; inline;
function Neg2f(const V: TVec2f): TVec2f; inline;
function Mul2f(const A, B: TVec2f): TVec2f; inline;
function Mul2f(const V: TVec2f; F: TFloat): TVec2f; inline;
function Dot2f(const A, B: TVec2f): TFloat; inline;
function QLen2f(const V: TVec2f): TFloat; inline;
function Len2f(const V: TVec2f): TFloat; inline;
function QDist2f(const A, B: TVec2f): TFloat; inline;
function Dist2f(const A, B: TVec2f): TFloat; inline;
function Norm2f(const V: TVec2f): TVec2f; inline;
function Rot2f(const V: TVec2f; Angle: TFloat): TVec2f; inline;
function Rot2f(const V: TVec2f; S, C: TFloat): TVec2f; inline;
function Mir2f(const V, D: TVec2f): TVec2f; inline;
function Normal2f(const V: TVec2f): TVec2f; inline; // TODO inverse!
function Normal2f(const A, B: TVec2f): TVec2f; inline; // TODO inverse!
function Rand2f(L, R, B, T: TFloat): TVec2f; inline;
function Rand2f(D: TFloat): TVec2f; inline;
function Round2f(const V: TVec2f): TVec2i; inline;
function Cut2f(const V: TVec2f; Limit: TFloat): TVec2f; inline;
function Cross2f(const A, B: TVec2f): TFloat; inline;
function Clockwise2f(const A, B: TVec2f): Boolean; inline;
// 0------------------------->
// |                       x
// |
// |
// | y
// v

operator + (const A, B: TVec2f): TVec2f; inline;
operator - (const A, B: TVec2f): TVec2f; inline;
operator - (const A: TVec2f): TVec2f; inline;
operator * (const A, B: TVec2f): TVec2f; inline;
operator * (F: Single; const V: TVec2f): TVec2f; inline;
operator / (const V: TVec2f; F: Single): TVec2f; inline;

implementation

function Vec2f(X, Y: TFloat): TVec2f;
begin
  Result.X := X;
  Result.Y := Y;
end;

function Vec2f(const V: TVec2i): TVec2f;
begin
  Result := Vec2f(V.X, V.Y);
end;

function Add2f(const A, B: TVec2f): TVec2f;
begin
  Result.X := A.X + B.X;
  Result.Y := A.Y + B.Y;
end;

function Sub2f(const A, B: TVec2f): TVec2f;
begin
  Result.X := A.X - B.X;
  Result.Y := A.Y - B.Y;
end;

function Neg2f(const V: TVec2f): TVec2f;
begin
  Result.X := - V.X;
  Result.Y := - V.Y;
end;

function Mul2f(const A, B: TVec2f): TVec2f;
begin
  Result.X := A.X * B.X;
  Result.Y := A.Y * B.Y;
end;

function Mul2f(const V: TVec2f; F: TFloat): TVec2f;
begin
  Result.X := V.X * F;
  Result.Y := V.Y * F;
end;

function Dot2f(const A, B: TVec2f): TFloat;
begin
  Result := A.X * B.X + A.Y * B.Y;
end;

function QLen2f(const V: TVec2f): TFloat;
begin
  Result := V.X * V.X + V.Y * V.Y;
end;

function Len2f(const V: TVec2f): TFloat;
begin
  Result := sqrt(V.X * V.X + V.Y * V.Y);
end;

function QDist2f(const A, B: TVec2f): TFloat;
begin
  Result := QLen2f(Sub2f(A, B));
end;

function Dist2f(const A, B: TVec2f): TFloat;
begin
  Result := Len2f(Sub2f(A, B));
end;

function Norm2f(const V: TVec2f): TVec2f;
var
  L: TFloat;
begin
  L := Len2f(V);
  if (Abs(L) < EPS) then
      Result := Zero2f
  else
      Result := Vec2f(V.X/L, V.Y/L);
end;

function Rot2f(const V: TVec2f; Angle: TFloat): TVec2f;
begin
  Result := Rot2f(V, Sin(Angle), Cos(Angle));
end;

function Rot2f(const V: TVec2f; S, C: TFloat): TVec2f;
begin
  Result := Vec2f(C * V.X - S * V.Y, C * V.Y + S * V.X);
end;

function Mir2f(const V, D: TVec2f): TVec2f;
begin
  Result := Add2f(V, Mul2f(Sub2f(Mul2f(D, Dot2f(V, D)), V), 2));
end;

function Normal2f(const V: TVec2f): TVec2f;
begin
  Result := Vec2f(- V.Y, V.X);
end;

function Normal2f(const A, B: TVec2f): TVec2f;
begin
  Result := Vec2f(A.Y - B.Y, B.X - A.X);
end;

function Rand2f(L, R, B, T: TFloat): TVec2f;
begin
  Result.X := Random * (R - L) + L;
  Result.Y := Random * (T - B) + B;
end;

function Rand2f(D: TFloat): TVec2f;
var
  A: TFloat;
begin
  A := 2 * Pi * Random;
  D := Random * D;
  Result := Rot2f(Vec2f(D, 0), A);
end;

function Round2f(const V: TVec2f): TVec2i;
begin
  Result := Vec2i(Round(V.X), Round(V.Y));
end;

function Cut2f(const V: TVec2f; Limit: TFloat): TVec2f;
begin
  if V.X > Limit then begin
    Result.X := Limit
  end else if V.X < -Limit then begin
    Result.X := -Limit
  end else
    Result.X := V.X;
  if V.Y > Limit then begin
    Result.Y := Limit
  end else if V.Y < -Limit then begin
    Result.Y := -Limit
  end else
    Result.Y := V.Y;
end;

function Cross2f(const A, B: TVec2f): TFloat; inline;
begin
  Result := A.X * B.Y - B.X * A.Y;
end;

function Clockwise2f(const A, B: TVec2f): Boolean; inline;
begin
  Result := A.X * B.Y - B.X * A.Y > 0;
end;

operator + (const A, B: TVec2f): TVec2f;
begin
  Result := Add2f(A, B);
end;

operator - (const A, B: TVec2f): TVec2f;
begin
  Result := Sub2f(A, B);
end;

operator - (const A: TVec2f): TVec2f;
begin
  Result := Neg2f(A);
end;

operator * (const A, B: TVec2f): TVec2f;
begin
  Result := Mul2f(A, B);
end;

operator * (F: Single; const V: TVec2f): TVec2f;
begin
  Result := Mul2f(V, F);
end;

operator / (const V: TVec2f; F: Single): TVec2f;
begin
  Result := Mul2f(V, 1/F);
end;

end.
