unit BB.Math.Vector;
interface
uses
BB.Types, BB.Math.Matrix;
const
V_RIGHT = 0;
V_UP = 1;
V_PN = 2;
type
PVector = ^TVector;
TVector = record
private
FX,
FY,
FZ,
FW: TFloat;
function GetIndex(aIndex: integer): TFloat;
procedure SetIndex(aIndex: integer; const aValue: TFloat);
procedure SetX(aValue: TFloat); inline;
procedure SetY(aValue: TFloat); inline;
procedure SetZ(aValue: TFloat); inline;
procedure SetW(aValue: TFloat); inline;
public
constructor Create(aX, aY, aZ: TFloat); overload;
constructor Create(const aVector: TVector); overload;
class operator Add(const aU, aV: TVector): TVector; inline;
class operator Subtract(const aU, aV: TVector): TVector; inline;
class operator Divide(const aVector: TVector; aFactor: TFloat): TVector; inline;
class operator Multiply(const aVector: TVector; aFactor: TFloat): TVector; overload; inline;
class operator Multiply(const aU, aV: TVector): TVector; overload; inline;
class operator Negative(const aVector: TVector): TVector; inline;
class operator Equal(const aU, aV: TVector): boolean; inline;
class operator NotEqual(const aU, aV: TVector): boolean; inline;
class operator GreaterThan(const aU, aV: TVector): boolean; inline;
class operator GreaterThanOrEqual(const aU, b: TVector): boolean; inline;
class operator LessThan(const a, b: TVector): boolean; inline;
class operator LessThanOrEqual(const a, b: TVector): boolean; inline;
class function Compare(const u, v: TVector): integer; static;
class function DotProduct(const u, v: TVector): TFloat; static;
class function Distance(const u, v: TVector): TFloat; static;
class function AngleBetween(const u, v: TVector): TFloat; static;
class function Angle(const u, v: TVector): TFloat; static;
class function DotUnit(const u, v: TVector): TFloat; static;
procedure Rotate(const aVector: TVector; const aMatrix: TMatrix);
procedure CrossProduct(const u, v: TVector);
procedure Normal(const v1, v2, v3: TVector);
function IsEmpty: boolean; inline;
procedure Clear; inline;
function Length: TFloat;
procedure Normalize; inline;
function Max: TFloat; inline;
function Min: TFloat; inline;
procedure Abs;
procedure Random(aMin, aMax: TFloat);
class function Null: TVector; static;
property Points[index: integer]: TFloat read GetIndex write SetIndex; default;
property Pitch: TFloat read FX write SetX;
property Yaw: TFloat read FY write SetY;
property Roll: TFloat read FZ write SetZ;
property X: TFloat read FX write SetX;
property Y: TFloat read FY write SetY;
property Z: TFloat read FZ write SetZ;
property W: TFloat read FW write SetW;
end;
implementation
uses
Math,
BB.Math;
{ TVector }
procedure TVector.Abs;
begin
FX := System.Abs(FX);
FY := System.Abs(FY);
FZ := System.Abs(FZ);
end;
class operator TVector.Add(const aU, aV: TVector): TVector;
begin
result.FX := aU.FX + aV.FX;
result.FY := aU.FY + aV.FY;
result.FZ := aU.FZ + aV.FZ;
end;
class function TVector.Angle(const u, v: TVector): TFloat;
var
length: TFloat;
begin
length := u.Length * v.Length;
Result := DotProduct(u, v) / length;
end;
class function TVector.AngleBetween(const u, v: TVector): TFloat;
var
m, dot: TFloat;
begin
dot := DotProduct(u, v);
m := u.Length * v.Length;
Result := ArcCos(dot / m);
if IsNan(Result) then
Result := 0;
end;
constructor TVector.Create(aX, aY, aZ: TFloat);
begin
FX := aX;
FY := aY;
FZ := aZ;
FW := 1;
end;
class function TVector.Compare(const u, v: TVector): integer;
var
d1, d2: TFloat;
begin
d1 := u.Length;
d2 := v.Length;
if d2 > d1 then
result := -1
else
if d1 > d2 then
result := 1
else
result := 0;
end;
constructor TVector.Create(const aVector: TVector);
begin
FX := aVector.FX;
FY := aVector.FY;
FZ := aVector.FZ;
FW := aVector.FW;
end;
procedure TVector.CrossProduct(const u, v: TVector);
begin
FX := (u.FY * v.FZ) - (u.FZ * v.FY);
FY := (u.FZ * v.FX) - (u.FX * v.FZ);
FZ := (u.FX * v.FY) - (u.FY * v.FX);
end;
class function TVector.Distance(const u, v: TVector): TFloat;
var
c: TVector;
begin
c := u - v;
result := c.Length;
end;
class operator TVector.Divide(const aVector: TVector; aFactor: TFloat): TVector;
var
inv: TFloat;
begin
inv := 1 / aFactor;
Result.FX := aVector.FX * inv;
Result.FY := aVector.FY * inv;
Result.FZ := aVector.FZ * inv;
end;
class function TVector.DotProduct(const u, v: TVector): TFloat;
begin
result := (u.FX * v.FX) + (u.FY * v.FY) + (u.FZ * v.FZ);
end;
class function TVector.DotUnit(const u, v: TVector): TFloat;
var
length: TFloat;
begin
length := u.Length * v.Length;
result := TVector.DotProduct(u, v) * (1 / length);
end;
function TVector.IsEmpty: boolean;
begin
result := (FX = 0) and (FY = 0) and (FZ = 0);
end;
class operator TVector.Equal(const aU, aV: TVector): boolean;
begin
result := (aU.FX = aV.FX) and (aU.FY = aV.FY) and (aU.FZ = aV.FZ);
end;
function TVector.GetIndex(aIndex: integer): TFloat;
begin
case aIndex of
0: result := FX;
1: result := FY;
2: result := FZ;
3: result := FW;
else
result := 0;
end;
end;
class operator TVector.GreaterThan(const aU, aV: TVector): boolean;
begin
result := aU.Length > aV.Length;
end;
class operator TVector.GreaterThanOrEqual(const aU, b: TVector): boolean;
begin
result := aU.Length >= b.Length;
end;
function TVector.Length: TFloat;
begin
Result := Sqrt(Sqr(FX) + Sqr(FY) + Sqr(FZ));
if Result = 0 then
Result := 0.00001;
end;
class operator TVector.LessThan(const a, b: TVector): boolean;
begin
result := a.Length < b.Length;
end;
class operator TVector.LessThanOrEqual(const a, b: TVector): boolean;
begin
result := a.Length <= b.Length;
end;
function TVector.Max: TFloat;
begin
Result := FX;
if FY > Result then
Result := FY;
if FZ > Result then
Result := FZ;
end;
function TVector.Min: TFloat;
begin
Result := FX;
if FY < Result then
Result := FY;
if FZ < Result then
Result := FZ;
end;
class operator TVector.Multiply(const aU, aV: TVector): TVector;
begin
result.FX := aU.FX * aV.FX;
result.FY := aU.FY * aV.FY;
result.FZ := aU.FZ * aV.FZ;
end;
class operator TVector.Multiply(const aVector: TVector; aFactor: TFloat): TVector;
begin
result.FX := aVector.FX * aFactor;
result.FY := aVector.FY * aFactor;
result.FZ := aVector.FZ * aFactor;
end;
class operator TVector.Negative(const aVector: TVector): TVector;
begin
result.FX := -result.FX;
result.FY := -result.FY;
result.FZ := -result.FZ;
end;
procedure TVector.Normal(const v1, v2, v3: TVector);
begin
CrossProduct(v2 - v1, v3 - v1);
end;
procedure TVector.Normalize;
var
l: TFloat;
begin
l := 1 / Length;
FX := FX * l;
FY := FY * l;
FZ := FZ * l;
// W := W * l;
end;
class operator TVector.NotEqual(const aU, aV: TVector): boolean;
begin
result := (aU.FX <> aV.FX) or (aU.FY <> aV.FY) or (aU.FZ <> aV.FZ);
end;
class function TVector.Null: TVector;
begin
result.Clear;
end;
procedure TVector.Random(aMin, aMax: TFloat);
begin
FX := Rnd(aMin, aMax);
FY := Rnd(aMin, aMax);
FZ := Rnd(aMin, aMax);
end;
procedure TVector.Rotate(const aVector: TVector; const aMatrix: TMatrix);
begin
FX := DotProduct(aVector, TVector(aMatrix._4x4[0]));
FY := DotProduct(aVector, TVector(aMatrix._4x4[1]));
FZ := DotProduct(aVector, TVector(aMatrix._4x4[2]));
end;
procedure TVector.SetIndex(aIndex: integer; const aValue: TFloat);
begin
case aIndex of
0: FX := aValue;
1: FY := aValue;
2: FZ := aValue;
3: FW := aValue;
end;
end;
procedure TVector.SetW(aValue: TFloat);
begin
FW := aValue;
end;
procedure TVector.SetX(aValue: TFloat);
begin
FX := aValue;
end;
procedure TVector.SetY(aValue: TFloat);
begin
FY := aValue;
end;
procedure TVector.SetZ(aValue: TFloat);
begin
FZ := aValue;
end;
class operator TVector.Subtract(const aU, aV: TVector): TVector;
begin
result.FX := aU.FX - aV.FX;
result.FY := aU.FY - aV.FY;
result.FZ := aU.FZ - aV.FZ;
end;
procedure TVector.Clear;
begin
FX := 0;
FY := 0;
FZ := 0;
FW := 1;
end;
end.
All cameras, rotations, lights, etc uses this unit
No comments:
Post a Comment