unit ugluVectorExHelper; {$mode objfpc}{$H+} {$modeswitch typehelpers} interface uses Classes, SysUtils; type generic TgluVectorHelper = class public type TBaseType = T; PBaseType = ^TBaseType; TVector2 = array[0..1] of T; TVector3 = array[0..2] of T; TVector4 = array[0..3] of T; PVector2 = ^TVector2; PVector3 = ^TVector3; PVector4 = ^TVector4; public class function Vector2(const x, y: T): TVector2; overload; inline; class function Vector3(const x, y, z: T): TVector3; overload; inline; class function Vector4(const x, y, z, w: T): TVector4; overload; inline; class function Equals(const v1: TVector2; const v2: TVector2): Boolean; overload; inline; class function Equals(const v1: TVector3; const v2: TVector3): Boolean; overload; inline; class function Equals(const v1: TVector4; const v2: TVector4): Boolean; overload; inline; class function ToString(const v: TVector2; const aRound: Integer = -3): String; overload; class function ToString(const v: TVector3; const aRound: Integer = -3): String; overload; class function ToString(const v: TVector4; const aRound: Integer = -3): String; overload; class function TryFromString(const s: String; out v: TVector2): Boolean; overload; inline; class function TryFromString(const s: String; out v: TVector3): Boolean; overload; inline; class function TryFromString(const s: String; out v: TVector4): Boolean; overload; inline; class function TryFromString(const s: String; p: PBaseType; aCount: Integer): Boolean; end; generic TgluVectorHelperI = class(specialize TgluVectorHelper) public class function Length(const v: TVector2): Double; overload; inline; class function Length(const v: TVector3): Double; overload; inline; class function Length(const v: TVector4): Double; overload; inline; class function SqrLength(const v: TVector2): Double; overload; inline; class function SqrLength(const v: TVector3): Double; overload; inline; class function SqrLength(const v: TVector4): Double; overload; inline; class function Multiply(const v: TVector2; const a: T): TVector2; overload; inline; class function Multiply(const v: TVector3; const a: T): TVector3; overload; inline; class function Multiply(const v: TVector4; const a: T): TVector4; overload; inline; class function Multiply(const v1, v2: TVector2): TVector2; overload; inline; class function Multiply(const v1, v2: TVector3): TVector3; overload; inline; class function Multiply(const v1, v2: TVector4): TVector4; overload; inline; class function Add(const v1, v2: TVector2): TVector2; overload; inline; class function Add(const v1, v2: TVector3): TVector3; overload; inline; class function Add(const v1, v2: TVector4): TVector4; overload; inline; class function Sub(const v1, v2: TVector2): TVector2; overload; inline; class function Sub(const v1, v2: TVector3): TVector3; overload; inline; class function Sub(const v1, v2: TVector4): TVector4; overload; inline; class function ClampVal(const v, aMin, aMax: T): T; overload; inline; class function Clamp(const v, aMin, aMax: TVector2): TVector2; overload; inline; class function Clamp(const v, aMin, aMax: TVector3): TVector3; overload; inline; class function Clamp(const v, aMin, aMax: TVector4): TVector4; overload; inline; class function Clamp(const v: TVector2; const aMin, aMax: T): TVector2; overload; inline; class function Clamp(const v: TVector3; const aMin, aMax: T): TVector3; overload; inline; class function Clamp(const v: TVector4; const aMin, aMax: T): TVector4; overload; inline; end; generic TgluVectorHelperF = class(specialize TgluVectorHelperI) public class function Normalize(const v: TVector2): TVector2; overload; inline; class function Normalize(const v: TVector3): TVector3; overload; inline; class function Normalize(const v: TVector4): TVector4; overload; inline; class function Divide(const v: TVector2; const a: T): TVector2; overload; inline; class function Divide(const v: TVector3; const a: T): TVector3; overload; inline; class function Divide(const v: TVector4; const a: T): TVector4; overload; inline; class function Dot(const v1: TVector2; const v2: TVector2): T; overload; inline; class function Dot(const v1: TVector3; const v2: TVector3): T; overload; inline; class function Dot(const v1: TVector4; const v2: TVector4): T; overload; inline; class function Cross(const v1: TVector3; const v2: TVector3): TVector3; overload; inline; class function Angle(const v1: TVector2; const v2: TVector2): Double; overload; inline; class function Angle(const v1: TVector3; const v2: TVector3): Double; overload; inline; class function Angle2(const v1: TVector2; const v2: TVector2): Double; overload; inline; end; TgluVectorP = specialize TgluVectorHelper; TgluVectorE = specialize TgluVectorHelper; TgluVectorI = specialize TgluVectorHelperI; TgluVectorUS = specialize TgluVectorHelperI; TgluVectorUB = specialize TgluVectorHelperI; TgluVectorF = specialize TgluVectorHelperF; TgluVectorD = specialize TgluVectorHelperF; TPointerTypeHelper = type helper for Pointer function ToString(const aRound: Integer = -3): String; class function TryFromString(s: String; out v: Pointer): Boolean; static; end; TCardinalTypeHelper = type helper for Cardinal function ToString(const aRound: Integer = -3): String; class function TryFromString(s: String; out v: Cardinal): Boolean; static; end; TIntegerTypeHelper = type helper for Integer function ToString(const aRound: Integer = -3): String; class function TryFromString(s: String; out v: Integer): Boolean; static; end; TWordTypeHelper = type helper for Word function ToString(const aRound: Integer = -3): String; class function TryFromString(s: String; out v: Word): Boolean; static; end; TByteTypeHelper = type helper for Byte function ToString(const aRound: Integer = -3): String; class function TryFromString(s: String; out v: Byte): Boolean; static; end; TSingleTypeHelper = type helper for Single function ToString(const aRound: Integer = -3): String; class function TryFromString(s: String; out v: Single): Boolean; static; end; TDoubleTypeHelper = type helper for Double function ToString(const aRound: Integer = -3): String; class function TryFromString(s: String; out v: Double): Boolean; static; end; implementation uses Math; function IntToStrRounded(i: Int64; const aRound: Integer): String; var p: Cardinal; begin if (aRound > 0) then begin p := Round(power(10, aRound)); i := i div p; i := i * p; end; result := IntToStr(i); end; function FloatToStrRounded(f: Extended; const aRound: Integer): String; var p: Cardinal; fmt: TFormatSettings; begin if (aRound > 0) then begin p := Round(power(10, aRound)); f := Round(f / p) * p; end; fmt.DecimalSeparator := '.'; result := Format('%.*f', [Max(0, -aRound), f], fmt); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TPointerTypeHelper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TPointerTypeHelper.ToString(const aRound: Integer): String; begin result := '0x' + IntToHex({%H-}PtrUInt(self), 2 * SizeOf(Pointer)); end; class function TPointerTypeHelper.TryFromString(s: String; out v: Pointer): Boolean; var i: Int64; begin s := StringReplace(s, '0x', '$', [rfReplaceAll, rfIgnoreCase]); result := TryStrToInt64(s, i); if result then v := {%H-}Pointer(PtrUInt(i)) else v := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TCardinalTypeHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TCardinalTypeHelper.ToString(const aRound: Integer): String; begin result := IntToStrRounded(self, aRound); end; class function TCardinalTypeHelper.TryFromString(s: String; out v: Cardinal): Boolean; var i: LongInt; begin result := TryStrToInt(s, i); if result then v := i else v := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TIntegerTypeHelper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TIntegerTypeHelper.ToString(const aRound: Integer): String; begin result := IntToStrRounded(self, aRound); end; class function TIntegerTypeHelper.TryFromString(s: String; out v: Integer): Boolean; begin result := TryStrToInt(s, v); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TWordTypeHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TWordTypeHelper.ToString(const aRound: Integer): String; begin result := IntToStrRounded(self, aRound); end; class function TWordTypeHelper.TryFromString(s: String; out v: Word): Boolean; var i: LongInt; begin result := TryStrToInt(s, i); if result then v := i else v := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TByteTypeHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TByteTypeHelper.ToString(const aRound: Integer): String; begin result := IntToStrRounded(self, aRound); end; class function TByteTypeHelper.TryFromString(s: String; out v: Byte): Boolean; var i: LongInt; begin result := TryStrToInt(s, i); if result then v := i else v := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TSingleTypeHelper///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TSingleTypeHelper.ToString(const aRound: Integer): String; begin result := FloatToStrRounded(self, aRound); end; class function TSingleTypeHelper.TryFromString(s: String; out v: Single): Boolean; var f: TFormatSettings; begin f.DecimalSeparator := '.'; result := TryStrToFloat(s, v, f); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TDoubleTypeHelper///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TDoubleTypeHelper.ToString(const aRound: Integer): String; begin result := FloatToStrRounded(self, aRound); end; class function TDoubleTypeHelper.TryFromString(s: String; out v: Double): Boolean; var f: TFormatSettings; begin f.DecimalSeparator := '.'; result := TryStrToFloat(s, v, f); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TgluVectorHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TgluVectorHelper.Vector2(const x, y: T): TVector2; begin result[0] := x; result[1] := y; end; class function TgluVectorHelper.Vector3(const x, y, z: T): TVector3; begin result[0] := x; result[1] := y; result[2] := z; end; class function TgluVectorHelper.Vector4(const x, y, z, w: T): TVector4; begin result[0] := x; result[1] := y; result[2] := z; result[3] := w; end; class function TgluVectorHelper.Equals(const v1: TVector2; const v2: TVector2): Boolean; begin result := (v1[0] = v2[0]) and (v1[1] = v2[1]); end; class function TgluVectorHelper.Equals(const v1: TVector3; const v2: TVector3): Boolean; begin result := Equals(PVector2(@v1[0])^, PVector2(@v2[0])^) and (v1[2] = v2[2]); end; class function TgluVectorHelper.Equals(const v1: TVector4; const v2: TVector4): Boolean; begin result := Equals(PVector3(@v1[0])^, PVector3(@v2[0])^) and (v1[3] = v2[3]); end; class function TgluVectorHelper.ToString(const v: TVector2; const aRound: Integer): String; begin result := v[0].ToString(aRound) + '; ' + v[1].ToString(aRound); end; class function TgluVectorHelper.ToString(const v: TVector3; const aRound: Integer): String; begin result := v[0].ToString(aRound) + '; ' + v[1].ToString(aRound) + '; ' + v[2].ToString(aRound); end; class function TgluVectorHelper.ToString(const v: TVector4; const aRound: Integer): String; begin result := v[0].ToString(aRound) + '; ' + v[1].ToString(aRound) + '; ' + v[2].ToString(aRound) + '; ' + v[3].ToString(aRound); end; class function TgluVectorHelper.TryFromString(const s: String; out v: TVector2): Boolean; begin result := TryFromString(s, @v[0], 2); end; class function TgluVectorHelper.TryFromString(const s: String; out v: TVector3): Boolean; begin result := TryFromString(s, @v[0], 3); end; class function TgluVectorHelper.TryFromString(const s: String; out v: TVector4): Boolean; begin result := TryFromString(s, @v[0], 4); end; class function TgluVectorHelper.TryFromString(const s: String; p: PBaseType; aCount: Integer): Boolean; var i, j, l: Integer; begin result := true; i := 1; j := 1; l := Length(s); while ({%H-}i <= {%H-}l) and (aCount > 0) and result {%H-}do begin if (s[i] = ';') or (i = l) then begin if (i = l) then inc(i); result := TBaseType.TryFromString(Trim(copy(s, j, i-{%H-}j)), p^); j := i+1; inc(p); dec(aCount); end; inc(i); end; result := (aCount = 0); while (aCount > 0) do begin p^ := TBaseType(0); inc(p); dec(aCount); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TgluVectorHelperI///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TgluVectorHelperI.Length(const v: TVector2): Double; begin result := SQRT(v[0]*v[0] + v[1]*v[1]); end; class function TgluVectorHelperI.Length(const v: TVector3): Double; begin result := SQRT(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); end; class function TgluVectorHelperI.Length(const v: TVector4): Double; begin result := SQRT(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) * v[3]; end; class function TgluVectorHelperI.SqrLength(const v: TVector2): Double; begin result := v[0]*v[0] + v[1]*v[1]; end; class function TgluVectorHelperI.SqrLength(const v: TVector3): Double; begin result := v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; end; class function TgluVectorHelperI.SqrLength(const v: TVector4): Double; begin result := (v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) * v[3]; end; class function TgluVectorHelperI.Multiply(const v: TVector2; const a: T): TVector2; begin result[0] := v[0] * a; result[1] := v[1] * a; end; class function TgluVectorHelperI.Multiply(const v: TVector3; const a: T): TVector3; begin result[0] := v[0] * a; result[1] := v[1] * a; result[2] := v[2] * a; end; class function TgluVectorHelperI.Multiply(const v: TVector4; const a: T): TVector4; begin result[0] := v[0] * a; result[1] := v[1] * a; result[2] := v[2] * a; result[3] := v[3] * a; end; class function TgluVectorHelperI.Multiply(const v1, v2: TVector2): TVector2; begin result[0] := v1[0] * v2[0]; result[1] := v1[1] * v2[1]; end; class function TgluVectorHelperI.Multiply(const v1, v2: TVector3): TVector3; begin result[0] := v1[0] * v2[0]; result[1] := v1[1] * v2[1]; result[2] := v1[2] * v2[2]; end; class function TgluVectorHelperI.Multiply(const v1, v2: TVector4): TVector4; begin result[0] := v1[0] * v2[0]; result[1] := v1[1] * v2[1]; result[2] := v1[2] * v2[2]; result[3] := v1[3] * v2[3]; end; class function TgluVectorHelperI.Add(const v1, v2: TVector2): TVector2; begin result[0] := v1[0] + v2[0]; result[1] := v1[1] + v2[1]; end; class function TgluVectorHelperI.Add(const v1, v2: TVector3): TVector3; begin result[0] := v1[0] + v2[0]; result[1] := v1[1] + v2[1]; result[2] := v1[2] + v2[2]; end; class function TgluVectorHelperI.Add(const v1, v2: TVector4): TVector4; begin result[0] := v1[0] + v2[0]; result[1] := v1[1] + v2[1]; result[2] := v1[2] + v2[2]; result[3] := v1[3] + v2[3]; end; class function TgluVectorHelperI.Sub(const v1, v2: TVector2): TVector2; begin result[0] := v1[0] - v2[0]; result[1] := v1[1] - v2[1]; end; class function TgluVectorHelperI.Sub(const v1, v2: TVector3): TVector3; begin result[0] := v1[0] - v2[0]; result[1] := v1[1] - v2[1]; result[2] := v1[2] - v2[2]; end; class function TgluVectorHelperI.Sub(const v1, v2: TVector4): TVector4; begin result[0] := v1[0] - v2[0]; result[1] := v1[1] - v2[1]; result[2] := v1[2] - v2[2]; result[3] := v1[3] - v2[3]; end; class function TgluVectorHelperI.ClampVal(const v, aMin, aMax: T): T; begin if (v < aMin) then result := aMin else if (v > aMax) then result := aMax else result := v; end; class function TgluVectorHelperI.Clamp(const v, aMin, aMax: TVector2): TVector2; begin result[0] := ClampVal(v[0], aMin[0], aMax[0]); result[1] := ClampVal(v[1], aMin[1], aMax[1]); end; class function TgluVectorHelperI.Clamp(const v, aMin, aMax: TVector3): TVector3; begin result[0] := ClampVal(v[0], aMin[0], aMax[0]); result[1] := ClampVal(v[1], aMin[1], aMax[1]); result[2] := ClampVal(v[2], aMin[2], aMax[2]); end; class function TgluVectorHelperI.Clamp(const v, aMin, aMax: TVector4): TVector4; begin result[0] := ClampVal(v[0], aMin[0], aMax[0]); result[1] := ClampVal(v[1], aMin[1], aMax[1]); result[2] := ClampVal(v[2], aMin[2], aMax[2]); result[3] := ClampVal(v[3], aMin[3], aMax[3]); end; class function TgluVectorHelperI.Clamp(const v: TVector2; const aMin, aMax: T): TVector2; begin result[0] := ClampVal(v[0], aMin, aMax); result[1] := ClampVal(v[1], aMin, aMax); end; class function TgluVectorHelperI.Clamp(const v: TVector3; const aMin, aMax: T): TVector3; begin result[0] := ClampVal(v[0], aMin, aMax); result[1] := ClampVal(v[1], aMin, aMax); result[2] := ClampVal(v[2], aMin, aMax); end; class function TgluVectorHelperI.Clamp(const v: TVector4; const aMin, aMax: T): TVector4; begin result[0] := ClampVal(v[0], aMin, aMax); result[1] := ClampVal(v[1], aMin, aMax); result[2] := ClampVal(v[2], aMin, aMax); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TgluVectorHelperF///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TgluVectorHelperF.Normalize(const v: TVector2): TVector2; var l: Double; begin l := Length(v); result[0] := v[0] / l; result[1] := v[1] / l; end; class function TgluVectorHelperF.Normalize(const v: TVector3): TVector3; var l: Double; begin l := Length(v); result[0] := v[0] / l; result[1] := v[1] / l; result[2] := v[2] / l; end; class function TgluVectorHelperF.Normalize(const v: TVector4): TVector4; begin result := v; if (result[3] <> 0) then result := Divide(v, v[3]); PVector3(@result[0])^ := Normalize(PVector3(@result[0])^); end; class function TgluVectorHelperF.Divide(const v: TVector2; const a: T): TVector2; begin result[0] := v[0] / a; result[1] := v[1] / a; end; class function TgluVectorHelperF.Divide(const v: TVector3; const a: T): TVector3; begin result[0] := v[0] / a; result[1] := v[1] / a; result[2] := v[2] / a; end; class function TgluVectorHelperF.Divide(const v: TVector4; const a: T): TVector4; begin result[0] := v[0] / a; result[1] := v[1] / a; result[2] := v[2] / a; result[3] := v[3] / a; end; class function TgluVectorHelperF.Dot(const v1: TVector2; const v2: TVector2): T; begin result := v1[0] * v2[0] + v1[1] * v2[1]; end; class function TgluVectorHelperF.Dot(const v1: TVector3; const v2: TVector3): T; begin result := v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; end; class function TgluVectorHelperF.Dot(const v1: TVector4; const v2: TVector4): T; begin result := v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3]; end; class function TgluVectorHelperF.Cross(const v1: TVector3; const v2: TVector3): TVector3; begin result[0] := v1[1] * v2[2] - v1[2] * v2[1]; result[1] := v1[2] * v2[0] - v1[0] * v2[2]; result[2] := v1[0] * v2[1] - v1[1] * v2[0]; end; class function TgluVectorHelperF.Angle(const v1: TVector2; const v2: TVector2): Double; begin result := ArcCos(Dot(v1, v2) / (Length(v1) * Length(v2))); end; class function TgluVectorHelperF.Angle(const v1: TVector3; const v2: TVector3): Double; begin result := ArcCos(Dot(v1, v2) / (Length(v1) * Length(v2))); end; class function TgluVectorHelperF.Angle2(const v1: TVector2; const v2: TVector2): Double; begin result := arctan2( v2[0] * v1[1] - v2[1] * v1[0], v2[0] * v1[0] + v2[1] * v1[1]); end; end.