1713 lines
47 KiB
ObjectPascal
1713 lines
47 KiB
ObjectPascal
unit SpkMath;
|
|
|
|
{$mode ObjFpc}
|
|
{$H+}
|
|
{$DEFINE SPKMATH}
|
|
{.$Define EnhancedRecordSupport}
|
|
|
|
interface
|
|
|
|
{TODO: Consider if all implicit casts make sense }
|
|
|
|
uses
|
|
Types, Math, SysUtils;
|
|
|
|
const
|
|
NUM_ZERO = 1e-12;
|
|
|
|
type
|
|
TRectCorner = (rcLeftTop, rcRightTop, rcLeftBottom, rcRightBottom);
|
|
|
|
// Dwuwymiarowy wektor o ca³kowitych wspó³rzêdnych
|
|
// Two-dimensional vector routines
|
|
{$ifdef EnhancedRecordSupport}
|
|
T2DIntVector = record
|
|
x, y : integer;
|
|
public
|
|
constructor Create(Ax, Ay : integer);
|
|
class operator Implicit(i : integer) : T2DIntVector;
|
|
class operator Explicit(i : integer) : T2DIntVector;
|
|
class operator Implicit(vector : T2DIntVector) : string;
|
|
class operator Explicit(vector : T2DIntVector) : string;
|
|
class operator Implicit(point : TPoint) : T2DIntVector;
|
|
class operator Explicit(point : TPoint) : T2DIntVector;
|
|
class operator Implicit(vector : T2DIntVector) : TPoint;
|
|
class operator Explicit(vector : T2DIntVector) : TPoint;
|
|
class operator Positive(vector : T2DIntVector) : T2DIntVector;
|
|
class operator Negative(vector : T2DIntVector) : T2DIntVector;
|
|
class operator Add(left, right : T2DIntVector) : T2DIntVector;
|
|
class operator Subtract(left, right : T2DIntVector) : T2DIntVector;
|
|
class operator Multiply(left, right : T2DIntVector) : integer;
|
|
class operator Multiply(scalar : integer; right : T2DIntVector) : T2DIntVector;
|
|
class operator Multiply(left : T2DIntVector; scalar : integer) : T2DIntVector;
|
|
class operator Trunc(value : T2DIntVector) : T2DIntVector;
|
|
class operator Round(value : T2DIntVector) : T2DIntVector;
|
|
function DistanceTo(AVector : T2DIntVector) : double;
|
|
function Length : extended;
|
|
end;
|
|
{$else}
|
|
|
|
{ T2DIntVector }
|
|
|
|
T2DIntVector = object
|
|
x, y : integer;
|
|
public
|
|
constructor Create(Ax, Ay : Integer);
|
|
function DistanceTo(AVector : T2DIntVector) : double;
|
|
function DistanceTo(Ax, Ay : Integer) : double;
|
|
function Length : extended;
|
|
end;
|
|
{$endif}
|
|
|
|
// Punkt w przestrzeni dwuwymiarowej o ca³kowitych wspó³rzêdnych
|
|
// A point in two-dimensional space (integer numbers)
|
|
T2DIntPoint = T2DIntVector;
|
|
|
|
// Prostok¹t w przestrzeni dwuwymiarowej o ca³kowitych wspó³rzêdnych
|
|
// Rectangle in two-dimensional space (integer numbers)
|
|
{$ifdef EnhancedRecordSupport}
|
|
T2DIntRect = record
|
|
public
|
|
constructor Create(ALeft, ATop, ARight, ABottom : integer); overload;
|
|
constructor Create(ATopLeft : T2DIntVector; ABottomRight : T2DIntVector); overload;
|
|
class operator Implicit(ARect : T2DIntRect) : TRect;
|
|
class operator Explicit(ARect : T2DIntRect) : TRect;
|
|
class operator Implicit(ARect : TRect) : T2DIntRect;
|
|
class operator Explicit(ARect : TRect) : T2DIntRect;
|
|
class operator Implicit(ARect : T2DIntRect) : string;
|
|
class operator Explicit(ARect : T2DIntRect) : string;
|
|
class operator Add(ARect : T2DIntRect; AVector : T2DIntVector) : T2DIntRect;
|
|
class operator Add(AVector : T2DIntVector; ARect : T2DIntRect) : T2DIntRect;
|
|
class operator Subtract(ARect : T2DIntRect; AVector : T2DIntVector) : T2DIntRect;
|
|
class operator Subtract(AVector : T2DIntVector; ARect : T2DIntRect) : T2DIntRect;
|
|
function Contains(APoint : T2DIntPoint) : boolean;
|
|
function IntersectsWith(ARect : T2DIntRect) : boolean; overload;
|
|
function IntersectsWith(ARect : T2DIntRect; var Intersection : T2DIntRect) : boolean; overload;
|
|
procedure Move(dx, dy : integer); overload;
|
|
procedure Move(AVector : T2DIntVector); overload;
|
|
function Moved(dx, dy : integer) : T2DIntRect; overload;
|
|
function Moved(AVector : T2DIntVector) : T2DIntRect; overload;
|
|
function GetVertex(ACorner : TRectCorner) : T2DIntVector;
|
|
procedure Split(var LeftTop, RightTop, LeftBottom, RightBottom : T2DIntRect);
|
|
procedure ExpandBy(APoint : T2DIntPoint);
|
|
function Width : integer;
|
|
function Height : integer;
|
|
function ForWinAPI : TRect;
|
|
case integer of
|
|
0 : (Left, Top, Right, Bottom : integer);
|
|
1 : (TopLeft : T2DIntVector; BottomRight : T2DIntVector);
|
|
end;
|
|
{$else}
|
|
|
|
{ T2DIntRect }
|
|
|
|
T2DIntRect = object
|
|
Left, Top, Right, Bottom: integer;
|
|
//todo
|
|
//TopLeft : T2DIntVector;
|
|
//BottomRight : T2DIntVector;
|
|
public
|
|
constructor Create(ALeft, ATop, ARight, ABottom : integer); overload;
|
|
constructor Create(ATopLeft : T2DIntVector; ABottomRight : T2DIntVector); overload;
|
|
function Contains(APoint : T2DIntPoint) : boolean;
|
|
function Contains(Ax, Ay : Integer) : boolean;
|
|
function IntersectsWith(ARect : T2DIntRect) : boolean; overload;
|
|
function IntersectsWith(ARect : T2DIntRect; out Intersection : T2DIntRect) : boolean; overload;
|
|
procedure Move(dx, dy : integer); overload;
|
|
procedure Move(AVector : T2DIntVector); overload;
|
|
function Moved(dx, dy : integer) : T2DIntRect; overload;
|
|
function Moved(AVector : T2DIntVector) : T2DIntRect; overload;
|
|
function GetVertex(ACorner : TRectCorner) : T2DIntVector;
|
|
procedure Split(var LeftTop, RightTop, LeftBottom, RightBottom : T2DIntRect);
|
|
procedure ExpandBy(APoint : T2DIntPoint);
|
|
function Width : integer;
|
|
function Height : integer;
|
|
function ForWinAPI : TRect;
|
|
end;
|
|
{$endif}
|
|
|
|
// Wektor w przestrzeni dwuwymiarowej o rzeczywistych wspó³rzêdnych
|
|
// Vector in two-dimensional space (floating point numbers)
|
|
//todo change from extended to double
|
|
{$ifdef EnhancedRecordSupport}
|
|
T2DVector = record
|
|
x, y : extended;
|
|
public
|
|
constructor Create(Ax, Ay : extended);
|
|
class operator Implicit(i : integer) : T2DVector;
|
|
class operator Explicit(i : integer) : T2DVector;
|
|
class operator Implicit(e : extended) : T2DVector;
|
|
class operator Explicit(e : extended) : T2DVector;
|
|
class operator Implicit(vector : T2DVector) : string;
|
|
class operator Explicit(vector : T2DVector) : string;
|
|
class operator Implicit(vector : T2DIntVector) : T2DVector;
|
|
class operator Explicit(vector : T2DIntVector) : T2DVector;
|
|
class operator Implicit(vector : T2DVector) : T2DIntVector;
|
|
class operator Explicit(vector : T2DVector) : T2DIntVector;
|
|
class operator Positive(vector : T2DVector) : T2DVector;
|
|
class operator Negative(vector : T2DVector) : T2DVector;
|
|
class operator Add(left, right : T2DVector) : T2DVector;
|
|
class operator Subtract(left, right : T2DVector) : T2DVector;
|
|
class operator Multiply(left, right : T2DVector) : extended;
|
|
class operator Multiply(scalar : extended; right : T2DVector) : T2DVector;
|
|
class operator Multiply(left : T2DVector; scalar : extended) : T2DVector;
|
|
class operator Divide(left : T2DIntVector; scalar : extended) : T2DVector;
|
|
class operator Divide(left : T2DVector; scalar : extended) : T2DVector;
|
|
class operator Trunc(vector : T2DVector) : T2DIntVector;
|
|
class operator Round(vector : T2DVector) : T2DIntVector;
|
|
function Length : extended;
|
|
procedure Normalize;
|
|
function Normalized : T2DVector;
|
|
function UpNormal : T2DVector;
|
|
function DownNormal : T2DVector;
|
|
procedure ProjectTo(vector : T2DVector);
|
|
function ProjectedTo(vector : T2DVector) : T2DVector;
|
|
function Scale(dx, dy : extended) : T2DVector;
|
|
function LiesInsideCircle(APoint : T2DVector; radius : extended) : boolean;
|
|
function OrientationWith(AVector : T2DVector) : integer;
|
|
function CrossProductWith(AVector : T2DVector) : extended;
|
|
function DistanceFromAxis(APoint : T2DVector; AVector : T2DVector) : extended;
|
|
end;
|
|
{$else}
|
|
T2DVector = object
|
|
x, y : extended;
|
|
public
|
|
constructor Create(Ax, Ay : extended);
|
|
function Length : extended;
|
|
procedure Normalize;
|
|
function Normalized : T2DVector;
|
|
function UpNormal : T2DVector;
|
|
function DownNormal : T2DVector;
|
|
procedure ProjectTo(vector : T2DVector);
|
|
function ProjectedTo(vector : T2DVector) : T2DVector;
|
|
function Scale(dx, dy : extended) : T2DVector;
|
|
function LiesInsideCircle(APoint : T2DVector; radius : extended) : boolean;
|
|
function OrientationWith(AVector : T2DVector) : integer;
|
|
function CrossProductWith(AVector : T2DVector) : extended;
|
|
function DistanceFromAxis(APoint : T2DVector; AVector : T2DVector) : extended;
|
|
end;
|
|
{$endif}
|
|
|
|
// Punkt w przestrzeni dwuwymiarowej o rzeczywistych wspó³rzêdnych
|
|
// A point in two-dimensional space (floating point numbers)
|
|
T2DPoint = T2DVector;
|
|
|
|
// Prostok¹t w przestrzeni dwuwymiarowej o rzeczywistych wspó³rzêdnych
|
|
// Rectangle in two-dimensional space (floating point numbers)
|
|
{$ifdef EnhancedRecordSupport}
|
|
T2DRect = record
|
|
public
|
|
constructor Create(ALeft, ATop, ARight, ABottom : extended); overload;
|
|
constructor Create(ATopLeft : T2DVector; ABottomRight : T2DVector); overload;
|
|
class operator Implicit(ARect : T2DRect) : TRect;
|
|
class operator Explicit(ARect : T2DRect) : TRect;
|
|
class operator Implicit(ARect : TRect) : T2DRect;
|
|
class operator Explicit(ARect : TRect) : T2DRect;
|
|
class operator Implicit(ARect : T2DRect) : T2DIntRect;
|
|
class operator Explicit(ARect : T2DRect) : T2DIntRect;
|
|
class operator Implicit(ARect : T2DIntRect) : T2DRect;
|
|
class operator Explicit(ARect : T2DIntRect) : T2DRect;
|
|
class operator Implicit(ARect : T2DRect) : string;
|
|
class operator Explicit(ARect : T2DRect) : string;
|
|
function Contains(APoint : T2DPoint) : boolean;
|
|
function IntersectsWith(ARect : T2DRect) : boolean;
|
|
procedure Move(dx, dy : extended); overload;
|
|
procedure Move(Vector : T2DVector); overload;
|
|
function Moved(dx, dy : extended) : T2DRect; overload;
|
|
function Moved(Vector : T2DVector) : T2DRect; overload;
|
|
function GetVertex(ACorner : TRectCorner) : T2DVector;
|
|
procedure Split(var LeftTop, RightTop, LeftBottom, RightBottom : T2DRect);
|
|
procedure ExpandBy(APoint : T2DPoint);
|
|
function Width : extended;
|
|
function Height : extended;
|
|
procedure SetCenteredWidth(ANewWidth : extended);
|
|
procedure SetCenteredHeight(ANewHeight : extended);
|
|
case integer of
|
|
0 : (Left, Top, Right, Bottom : extended);
|
|
1 : (TopLeft : T2DVector; BottomRight : T2DVector);
|
|
end;
|
|
{$else}
|
|
T2DRect = object
|
|
Left, Top, Right, Bottom : extended;
|
|
//todo
|
|
//TopLeft : T2DVector; BottomRight : T2DVector;
|
|
public
|
|
constructor Create(ALeft, ATop, ARight, ABottom : extended); overload;
|
|
constructor Create(ATopLeft : T2DVector; ABottomRight : T2DVector); overload;
|
|
function Contains(APoint : T2DPoint) : boolean;
|
|
function IntersectsWith(ARect : T2DRect) : boolean;
|
|
procedure Move(dx, dy : extended); overload;
|
|
procedure Move(Vector : T2DVector); overload;
|
|
function Moved(dx, dy : extended) : T2DRect; overload;
|
|
function Moved(Vector : T2DVector) : T2DRect; overload;
|
|
function GetVertex(ACorner : TRectCorner) : T2DVector;
|
|
procedure Split(var LeftTop, RightTop, LeftBottom, RightBottom : T2DRect);
|
|
procedure ExpandBy(APoint : T2DPoint);
|
|
function Width : extended;
|
|
function Height : extended;
|
|
procedure SetCenteredWidth(ANewWidth : extended);
|
|
procedure SetCenteredHeight(ANewHeight : extended);
|
|
end;
|
|
{$endif}
|
|
|
|
// Wektor w przestrzeni trójwymiarowej o rzeczywistych wspó³rzêdnych
|
|
// Vector in three-dimensional space (floating point numbers)
|
|
{$ifdef EnhancedRecordSupport}
|
|
T3DVector = record
|
|
x, y, z : extended;
|
|
public
|
|
constructor create(Ax, Ay, Az : extended);
|
|
class operator Implicit(i : integer) : T3DVector;
|
|
class operator Explicit(i : integer) : T3DVector;
|
|
class operator Implicit(e : extended) : T3DVector;
|
|
class operator Explicit(e : extended) : T3DVector;
|
|
class operator Implicit(vector : T2DIntVector) : T3DVector;
|
|
class operator Explicit(vector : T2DIntVector) : T3DVector;
|
|
class operator Implicit(vector : T2DVector) : T3DVector;
|
|
class operator Explicit(vector : T2DVector) : T3DVector;
|
|
class operator Implicit(vector : T3DVector) : string;
|
|
class operator Explicit(vector : T3DVector) : string;
|
|
class operator Negative(vector : T3DVector) : T3DVector;
|
|
class operator Positive(vector : T3DVector) : T3DVector;
|
|
class operator Add(left, right : T3DVector) : T3DVector;
|
|
class operator Subtract(left, right : T3DVector) : T3DVector;
|
|
class operator Multiply(left, right : T3DVector) : extended;
|
|
class operator Multiply(scalar : extended; right : T3DVector) : T3DVector;
|
|
class operator Multiply(left : T3DVector; scalar : extended) : T3DVector;
|
|
class operator Divide(left : T3DVector; scalar : extended) : T3DVector;
|
|
function Length : extended;
|
|
procedure Normalize;
|
|
function Normalized : T3DVector;
|
|
function UpNormalTo(vector : T3DVector) : T3DVector;
|
|
function DownNormalTo(vector : T3DVector) : T3DVector;
|
|
procedure ProjectTo(vector : T3DVector);
|
|
function ProjectedTo(vector : T3DVector) : T3DVector;
|
|
function Scale(dx, dy, dz : extended) : T3DVector;
|
|
function LiesInsideSphere(APoint : T3DVector; radius : extended) : boolean;
|
|
function DistanceFromAxis(APoint : T3DVector; AVector : T3DVector) : extended;
|
|
end;
|
|
{$else}
|
|
T3DVector = object
|
|
x, y, z : extended;
|
|
public
|
|
constructor create(Ax, Ay, Az : extended);
|
|
function Length : extended;
|
|
procedure Normalize;
|
|
function Normalized : T3DVector;
|
|
function UpNormalTo(vector : T3DVector) : T3DVector;
|
|
function DownNormalTo(vector : T3DVector) : T3DVector;
|
|
procedure ProjectTo(vector : T3DVector);
|
|
function ProjectedTo(vector : T3DVector) : T3DVector;
|
|
function Scale(dx, dy, dz : extended) : T3DVector;
|
|
function LiesInsideSphere(APoint : T3DVector; radius : extended) : boolean;
|
|
function DistanceFromAxis(APoint : T3DVector; AVector : T3DVector) : extended;
|
|
end;
|
|
{$endif}
|
|
|
|
{$ifndef EnhancedRecordSupport}
|
|
|
|
function Create2DIntVector(Ax, Ay : Integer): T2DIntVector;
|
|
|
|
function Create2DIntPoint(Ax, Ay : Integer): T2DIntPoint;
|
|
|
|
function Create2DIntRect(ALeft, ATop, ARight, ABottom: Integer): T2DIntRect;
|
|
|
|
operator - (Left: T2DIntVector; Right: T2DIntVector): T2DIntVector;
|
|
|
|
operator := (APoint: T2DIntPoint): TPoint;
|
|
|
|
operator := (APoint: TPoint): T2DIntPoint;
|
|
|
|
operator - (Left: T2DIntRect; Right: T2DIntVector): T2DIntRect;
|
|
|
|
operator + (Left: T2DIntRect; Right: T2DIntVector): T2DIntRect;
|
|
|
|
operator := (ARect: TRect): T2DIntRect;
|
|
|
|
operator - (Left: T2DVector; Right: T2DVector): T2DVector;
|
|
|
|
operator - (Left: T3DVector; Right: T3DVector): T3DVector;
|
|
{$endif}
|
|
|
|
procedure EnsureOrder(var a, b: Integer);
|
|
|
|
implementation
|
|
|
|
{$ifndef EnhancedRecordSupport}
|
|
|
|
function Create2DIntVector(Ax, Ay: Integer): T2DIntVector;
|
|
begin
|
|
Result.Create(Ax, Ay);
|
|
end;
|
|
|
|
function Create2DIntPoint(Ax, Ay: Integer): T2DIntPoint;
|
|
begin
|
|
Result.Create(Ax, Ay);
|
|
end;
|
|
|
|
function Create2DIntRect(ALeft, ATop, ARight, ABottom: Integer): T2DIntRect;
|
|
begin
|
|
Result.Create(ALeft, ATop, ARight, ABottom);
|
|
end;
|
|
|
|
operator - (Left: T2DIntVector; Right: T2DIntVector): T2DIntVector;
|
|
begin
|
|
Result.x := Left.x - Right.x;
|
|
Result.y := Left.y - Right.y;
|
|
end;
|
|
|
|
operator := (APoint: T2DIntPoint): TPoint;
|
|
begin
|
|
Result.x := APoint.x;
|
|
Result.y := APoint.y;
|
|
end;
|
|
|
|
operator := (APoint: TPoint): T2DIntPoint;
|
|
begin
|
|
Result.x := APoint.x;
|
|
Result.y := APoint.y;
|
|
end;
|
|
|
|
operator - (Left: T2DIntRect; Right: T2DIntVector): T2DIntRect;
|
|
begin
|
|
Result.Create(Left.Left - Right.x, Left.Top - Right.y,
|
|
Left.Right - Right.x, Left.Bottom - Right.y);
|
|
end;
|
|
|
|
operator + (Left: T2DIntRect; Right: T2DIntVector): T2DIntRect;
|
|
begin
|
|
Result.Create(Left.left + Right.x, Left.top + Right.y,
|
|
Left.Right + Right.x, Left.bottom + Right.y);
|
|
end;
|
|
|
|
operator := (ARect: TRect): T2DIntRect;
|
|
begin
|
|
Result.Left := ARect.Left;
|
|
Result.Top := ARect.Top;
|
|
Result.Right := ARect.Right;
|
|
Result.Bottom := ARect.Bottom;
|
|
end;
|
|
|
|
operator - (Left: T2DVector; Right: T2DVector): T2DVector;
|
|
begin
|
|
Result.x := Left.x - Right.x;
|
|
Result.y := Left.y - Right.y;
|
|
end;
|
|
|
|
operator - (Left: T3DVector; Right: T3DVector): T3DVector;
|
|
begin
|
|
Result.x := Left.x - Right.x;
|
|
Result.y := Left.y - Right.y;
|
|
Result.z := Left.z - Right.z;
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
{ T2DIntVector }
|
|
|
|
constructor T2DIntVector.Create(Ax, Ay: integer);
|
|
begin
|
|
self.x:=Ax;
|
|
self.y:=Ay;
|
|
end;
|
|
|
|
function T2DIntVector.DistanceTo(AVector: T2DIntVector): double;
|
|
begin
|
|
result:=sqrt(sqr(self.x - AVector.x) + sqr(self.y - AVector.y));
|
|
end;
|
|
|
|
function T2DIntVector.DistanceTo(Ax, Ay: Integer): double;
|
|
begin
|
|
Result := sqrt(sqr(x - Ax) + sqr(y - Ay));
|
|
end;
|
|
|
|
function T2DIntVector.Length: extended;
|
|
begin
|
|
result:=sqrt(sqr(Self.x)+sqr(self.y));
|
|
end;
|
|
|
|
{$ifdef EnhancedRecordSupport}
|
|
|
|
class operator T2DIntVector.Add(left, right: T2DIntVector): T2DIntVector;
|
|
begin
|
|
result.x:=left.x+right.x;
|
|
result.y:=left.y+right.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Explicit(i: integer): T2DIntVector;
|
|
begin
|
|
result.x:=i;
|
|
result.y:=0;
|
|
end;
|
|
|
|
class operator T2DIntVector.Explicit(vector: T2DIntVector): string;
|
|
begin
|
|
result:='[x='+IntToStr(vector.x)+'; y='+IntToStr(vector.y)+']';
|
|
end;
|
|
|
|
class operator T2DIntVector.Implicit(vector: T2DIntVector): string;
|
|
begin
|
|
result:='[x='+IntToStr(vector.x)+'; y='+IntToStr(vector.y)+']';
|
|
end;
|
|
|
|
class operator T2DIntVector.Implicit(i: integer): T2DIntVector;
|
|
begin
|
|
result.x:=i;
|
|
result.y:=0;
|
|
end;
|
|
|
|
class operator T2DIntVector.Multiply(left: T2DIntVector;
|
|
scalar: integer): T2DIntVector;
|
|
begin
|
|
result.x:=left.x*scalar;
|
|
result.y:=left.y*scalar;
|
|
end;
|
|
|
|
class operator T2DIntVector.Multiply(left, right: T2DIntVector): integer;
|
|
begin
|
|
result:=left.x*right.x + left.y*right.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Multiply(scalar: integer;
|
|
right: T2DIntVector): T2DIntVector;
|
|
begin
|
|
result.x:=scalar*right.x;
|
|
result.y:=scalar*right.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Negative(vector: T2DIntVector): T2DIntVector;
|
|
begin
|
|
result.x:=-vector.x;
|
|
result.y:=-vector.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Positive(vector: T2DIntVector): T2DIntVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Round(value: T2DIntVector): T2DIntVector;
|
|
begin
|
|
result.x:=value.x;
|
|
result.y:=value.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Subtract(left, right: T2DIntVector): T2DIntVector;
|
|
begin
|
|
result.x:=left.x-right.x;
|
|
result.y:=left.y-right.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Trunc(value: T2DIntVector): T2DIntVector;
|
|
begin
|
|
result.x:=value.x;
|
|
result.y:=value.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Explicit(point: TPoint): T2DIntVector;
|
|
begin
|
|
result.x:=point.x;
|
|
result.y:=point.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Explicit(vector: T2DIntVector): TPoint;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Implicit(point: TPoint): T2DIntVector;
|
|
begin
|
|
result.x:=point.x;
|
|
result.y:=point.y;
|
|
end;
|
|
|
|
class operator T2DIntVector.Implicit(vector: T2DIntVector): TPoint;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
{ T2DVector }
|
|
|
|
constructor T2DVector.Create(Ax, Ay: extended);
|
|
begin
|
|
self.x:=Ax;
|
|
self.y:=Ay;
|
|
end;
|
|
|
|
function T2DVector.DistanceFromAxis(APoint, AVector: T2DVector): extended;
|
|
|
|
var temp, proj : T2DVector;
|
|
|
|
begin
|
|
temp:=self-APoint;
|
|
proj:=temp.ProjectedTo(AVector);
|
|
result:=(temp - proj).Length;
|
|
//todo: see if the below (without operator overloading) is faster
|
|
{
|
|
temp.x := x - APoint.x;
|
|
temp.y := y - APoint.y;
|
|
proj := temp.ProjectedTo(AVector);
|
|
temp.x := temp.x - proj.x;
|
|
temp.y := temp.y - proj.y;
|
|
Result := temp.Length;
|
|
}
|
|
end;
|
|
|
|
function T2DVector.DownNormal: T2DVector;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
len:=self.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T2DVector.DownNormal: Cannot normalize a vector of zero length!');
|
|
//raise exception.create('T2DVector.DownNormal: Nie mogê obliczyæ normalnej do wektora zerowego!');
|
|
|
|
if self.x>0 then
|
|
begin
|
|
result.x:=self.y/len;
|
|
result.y:=-self.x/len;
|
|
end
|
|
else
|
|
begin
|
|
result.x:=-self.y/len;
|
|
result.y:=self.x/len;
|
|
end;
|
|
end;
|
|
|
|
function T2DVector.Length: extended;
|
|
begin
|
|
result:=sqrt(sqr(self.x)+sqr(self.y));
|
|
end;
|
|
|
|
function T2DVector.LiesInsideCircle(APoint: T2DPoint;
|
|
radius: extended): boolean;
|
|
|
|
var Temp : T2DVector;
|
|
|
|
begin
|
|
Temp:=APoint - self;
|
|
result:=Temp.Length <= radius;
|
|
//todo: see if below is faster/better
|
|
{
|
|
Temp.x:=APoint.x - x;
|
|
Temp.y:=APoint.y - y;
|
|
result:=Temp.Length <= radius;
|
|
}
|
|
end;
|
|
|
|
procedure T2DVector.Normalize;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
len:=self.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T2DVector.Normalize: Cannot normalize a vector of zero length!');
|
|
//raise exception.create('T2DVector.Normalize: Nie mo¿na znormalizowaæ wektora zerowego!');
|
|
self.x:=self.x/len;
|
|
self.y:=self.y/len;
|
|
end;
|
|
|
|
function T2DVector.Normalized: T2DVector;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
len:=self.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T2DVector.Normalize: Cannot normalize a vector of zero length!');
|
|
//raise exception.create('T2DVector.Normalized: Nie mo¿na obliczyæ normy wektora zerowego!');
|
|
result.x:=self.x/len;
|
|
result.y:=self.y/len;
|
|
end;
|
|
|
|
function T2DVector.OrientationWith(AVector: T2DVector): integer;
|
|
|
|
var product : extended;
|
|
|
|
begin
|
|
product:=self.CrossProductWith(AVector);
|
|
if product<NUM_ZERO then result:=-1 else
|
|
if product>NUM_ZERO then result:=1 else
|
|
result:=0;
|
|
end;
|
|
|
|
function T2DVector.CrossProductWith(AVector: T2DVector): extended;
|
|
begin
|
|
result:=self.x * AVector.y - self.y * AVector.x;
|
|
end;
|
|
|
|
function T2DVector.ProjectedTo(vector: T2DVector): T2DVector;
|
|
|
|
var product : extended;
|
|
len : extended;
|
|
|
|
begin
|
|
len:=vector.Length;
|
|
if abs(len)<NUM_ZERO then
|
|
raise exception.create('T2DVector.ProjectedTo: Cannot project onto a vector of zero length!');
|
|
//raise exception.create('T2DVector.ProjectedTo: Nie mo¿na rzutowaæ na wektor zerowy!');
|
|
|
|
product:=self.x*vector.x + self.y*vector.y;
|
|
result.x:=(vector.x * product) / sqr(len);
|
|
result.y:=(vector.y * product) / sqr(len);
|
|
end;
|
|
|
|
procedure T2DVector.ProjectTo(vector: T2DVector);
|
|
|
|
var product : extended;
|
|
len : extended;
|
|
|
|
begin
|
|
len:=vector.Length;
|
|
if abs(len)<NUM_ZERO then
|
|
raise exception.create('T2DVector.ProjectTo: Cannot project onto a vector of zero length!');
|
|
// raise exception.create('T2DVector.ProjectTo: Nie mo¿na rzutowaæ na wektor zerowy!');
|
|
|
|
product:=self.x*vector.x + self.y*vector.y;
|
|
|
|
self.x:=(vector.x * product) / sqr(len);
|
|
self.y:=(vector.y * product) / sqr(len);
|
|
end;
|
|
|
|
function T2DVector.Scale(dx, dy: extended): T2DVector;
|
|
begin
|
|
result.x:=self.x * dx;
|
|
result.y:=self.y * dy;
|
|
end;
|
|
|
|
|
|
function T2DVector.UpNormal : T2DVector;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
len:=self.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T2DVector.UpNormal: Cannot normalize a vector of zero length!');
|
|
//raise exception.create('T2DVector.UpNormal: Nie mogê obliczyæ normalnej do wektora zerowego!');
|
|
|
|
if self.x>0 then
|
|
begin
|
|
result.x:=-self.y/len;
|
|
result.y:=self.x/len;
|
|
end
|
|
else
|
|
begin
|
|
result.x:=self.y/len;
|
|
result.y:=-self.x/len;
|
|
end;
|
|
end;
|
|
|
|
{$ifdef EnhancedRecordSupport}
|
|
|
|
class operator T2DVector.Add(left, right: T2DVector): T2DVector;
|
|
begin
|
|
result.x:=left.x+right.x;
|
|
result.y:=left.y+right.y;
|
|
end;
|
|
|
|
class operator T2DVector.Divide(left: T2DIntVector;
|
|
scalar: extended): T2DVector;
|
|
begin
|
|
if abs(scalar)<NUM_ZERO then
|
|
raise exception.create('T2DVector.Divide: Division by zero!');
|
|
//raise exception.create('T2DVector.Divide: Dzielenie przez zero!');
|
|
result.x:=left.x/scalar;
|
|
result.y:=left.y/scalar;
|
|
end;
|
|
|
|
class operator T2DVector.Divide(left: T2DVector; scalar: extended): T2DVector;
|
|
begin
|
|
if abs(scalar)<NUM_ZERO then
|
|
raise exception.create('T2DVector.Divide: Division by zero!');
|
|
//raise exception.create('T2DVector.Divide: Dzielenie przez zero!');
|
|
result.x:=left.x/scalar;
|
|
result.y:=left.y/scalar;
|
|
end;
|
|
|
|
class operator T2DVector.Explicit(vector: T2DVector): string;
|
|
begin
|
|
result:='[x='+FloatToStr(vector.x)+'; y='+FloatToStr(vector.y)+']';
|
|
end;
|
|
|
|
class operator T2DVector.Explicit(i: integer): T2DVector;
|
|
begin
|
|
result.x:=i;
|
|
result.y:=0;
|
|
end;
|
|
|
|
class operator T2DVector.Explicit(e: extended): T2DVector;
|
|
begin
|
|
result.x:=e;
|
|
result.y:=0;
|
|
end;
|
|
|
|
class operator T2DVector.Explicit(vector: T2DIntVector): T2DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
end;
|
|
|
|
class operator T2DVector.Explicit(vector: T2DVector): T2DIntVector;
|
|
begin
|
|
result.x:=round(vector.x);
|
|
result.y:=round(vector.y);
|
|
end;
|
|
|
|
class operator T2DVector.Implicit(vector: T2DVector): string;
|
|
begin
|
|
result:='[x='+FloatToStr(vector.x)+'; y='+FloatToStr(vector.y)+']';
|
|
end;
|
|
|
|
class operator T2DVector.Implicit(vector: T2DIntVector): T2DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
end;
|
|
|
|
class operator T2DVector.Implicit(i: integer): T2DVector;
|
|
begin
|
|
result.x:=i;
|
|
result.y:=0;
|
|
end;
|
|
|
|
class operator T2DVector.Implicit(e: extended): T2DVector;
|
|
begin
|
|
result.x:=e;
|
|
result.y:=0;
|
|
end;
|
|
|
|
class operator T2DVector.Implicit(vector: T2DVector): T2DIntVector;
|
|
begin
|
|
result.x:=round(vector.x);
|
|
result.y:=round(vector.y);
|
|
end;
|
|
|
|
class operator T2DVector.Multiply(left, right: T2DVector): extended;
|
|
begin
|
|
result:=left.x*right.x + left.y*right.y;
|
|
end;
|
|
|
|
class operator T2DVector.Multiply(left: T2DVector; scalar: extended): T2DVector;
|
|
begin
|
|
result.x:=left.x*scalar;
|
|
result.y:=left.y*scalar;
|
|
end;
|
|
|
|
class operator T2DVector.Multiply(scalar: extended;
|
|
right: T2DVector): T2DVector;
|
|
begin
|
|
result.x:=scalar*right.x;
|
|
result.y:=scalar*right.y;
|
|
end;
|
|
|
|
class operator T2DVector.Negative(vector: T2DVector): T2DVector;
|
|
begin
|
|
result.x:=-vector.x;
|
|
result.y:=-vector.y;
|
|
end;
|
|
|
|
class operator T2DVector.Positive(vector: T2DVector): T2DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
end;
|
|
|
|
class operator T2DVector.Round(vector: T2DVector): T2DIntVector;
|
|
begin
|
|
result.x:=round(vector.x);
|
|
result.y:=round(vector.y);
|
|
end;
|
|
|
|
class operator T2DVector.Subtract(left, right: T2DVector): T2DVector;
|
|
begin
|
|
result.x:=left.x-right.x;
|
|
result.y:=left.y-right.y;
|
|
end;
|
|
|
|
class operator T2DVector.Trunc(vector: T2DVector): T2DIntVector;
|
|
begin
|
|
result.x:=trunc(vector.x);
|
|
result.y:=trunc(vector.y);
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
{ T3DVector }
|
|
|
|
constructor T3DVector.create(Ax, Ay, Az: extended);
|
|
begin
|
|
self.x:=Ax;
|
|
self.y:=Ay;
|
|
self.z:=Az;
|
|
end;
|
|
|
|
function T3DVector.DistanceFromAxis(APoint, AVector: T3DVector): extended;
|
|
|
|
var temp, proj : T3DVector;
|
|
|
|
begin
|
|
temp:=self-APoint;
|
|
proj:=temp.ProjectedTo(AVector);
|
|
result:=(temp - proj).Length;
|
|
end;
|
|
|
|
function T3DVector.DownNormalTo(vector: T3DVector): T3DVector;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
result.x:=self.y * vector.z - self.z * vector.y;
|
|
result.y:=-(self.x * vector.z - self.z * vector.x);
|
|
result.z:=self.x * vector.y - self.y * vector.x;
|
|
len:=result.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T3DVector.DownNormalTo: Vector length is zero!');
|
|
//raise exception.create('T3DVector.DownNormalTo: Nie mogê obliczyæ normalnej: wektory le¿¹ na wspólnej prostej!');
|
|
result.x:=result.x/len;
|
|
result.y:=result.y/len;
|
|
result.z:=result.z/len;
|
|
|
|
if result.y>0 then
|
|
begin
|
|
result.x:=-result.x;
|
|
result.y:=-result.y;
|
|
result.z:=-result.z;
|
|
end;
|
|
end;
|
|
|
|
function T3DVector.Length: extended;
|
|
begin
|
|
result:=sqrt(sqr(self.x)+sqr(self.y)+sqr(self.z));
|
|
end;
|
|
|
|
function T3DVector.LiesInsideSphere(APoint: T3DVector;
|
|
radius: extended): boolean;
|
|
|
|
var Temp : T3DVector;
|
|
|
|
begin
|
|
Temp:=APoint - self;
|
|
result:=Temp.Length <= radius;
|
|
end;
|
|
|
|
|
|
procedure T3DVector.Normalize;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
len:=self.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T3DVector.Normalize: Vector length is zero!');
|
|
//raise exception.create('T3DVector.Normalize: Nie mo¿na znormalizowaæ wektora zerowego!');
|
|
self.x:=self.x/len;
|
|
self.y:=self.y/len;
|
|
self.z:=self.z/len;
|
|
end;
|
|
|
|
function T3DVector.Normalized: T3DVector;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
len:=self.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T3DVector.Normalized: Vector length is zero!');
|
|
//raise exception.create('T3DVector.Normalized: Nie mo¿na obliczyæ normy wektora zerowego!');
|
|
result.x:=self.x/len;
|
|
result.y:=self.y/len;
|
|
result.z:=self.z/len;
|
|
end;
|
|
|
|
|
|
function T3DVector.ProjectedTo(vector: T3DVector): T3DVector;
|
|
|
|
var product : extended;
|
|
len : extended;
|
|
|
|
begin
|
|
len:=vector.Length;
|
|
if abs(len)<NUM_ZERO then
|
|
raise exception.create('T3DVector.ProjectedTo: Vector length is zero!');
|
|
//raise exception.create('T3DVector.ProjectedTo: Nie mo¿na rzutowaæ na wektor zerowy!');
|
|
|
|
product:=self.x*vector.x + self.y*vector.y + self.z*vector.z;
|
|
result.x:=(vector.x * product) / sqr(len);
|
|
result.y:=(vector.y * product) / sqr(len);
|
|
result.z:=(vector.z * product) / sqr(len);
|
|
end;
|
|
|
|
procedure T3DVector.ProjectTo(vector: T3DVector);
|
|
|
|
var product : extended;
|
|
len : extended;
|
|
|
|
begin
|
|
len:=vector.Length;
|
|
if abs(len)<NUM_ZERO then
|
|
raise exception.create('T3DVector.ProjectTo: Vector length is zero!');
|
|
//raise exception.create('T3DVector.ProjectTo: Nie mo¿na rzutowaæ na wektor zerowy!');
|
|
|
|
product:=self.x*vector.x + self.y*vector.y + self.z*vector.z;
|
|
self.x:=(vector.x * product) / sqr(len);
|
|
self.y:=(vector.y * product) / sqr(len);
|
|
self.z:=(vector.z * product) / sqr(len);
|
|
end;
|
|
|
|
function T3DVector.Scale(dx, dy, dz: extended): T3DVector;
|
|
begin
|
|
result.x:=self.x * dx;
|
|
result.y:=self.y * dy;
|
|
result.z:=self.z * dz;
|
|
end;
|
|
|
|
function T3DVector.UpNormalTo(vector: T3DVector): T3DVector;
|
|
|
|
var len : extended;
|
|
|
|
begin
|
|
result.x:=self.y * vector.z - self.z * vector.y;
|
|
result.y:=-(self.x * vector.z - self.z * vector.x);
|
|
result.z:=self.x * vector.y - self.y * vector.x;
|
|
|
|
len:=result.Length;
|
|
if len<NUM_ZERO then
|
|
raise exception.create('T3DVector.UpNormalTo: Vector length is zero!');
|
|
//raise exception.create('T3DVector.UpNormalTo: Nie mogê obliczyæ normalnej: wektory le¿¹ na wspólnej prostej!');
|
|
result.x:=result.x/len;
|
|
result.y:=result.y/len;
|
|
result.z:=result.z/len;
|
|
|
|
if result.y<0 then
|
|
begin
|
|
result.x:=-result.x;
|
|
result.y:=-result.y;
|
|
result.z:=-result.z;
|
|
end;
|
|
end;
|
|
|
|
|
|
{$ifdef EnhancedRecordSupport}
|
|
|
|
class operator T3DVector.Add(left, right: T3DVector): T3DVector;
|
|
begin
|
|
result.x:=left.x+right.x;
|
|
result.y:=left.y+right.y;
|
|
result.z:=left.z+right.z;
|
|
end;
|
|
|
|
class operator T3DVector.Divide(left: T3DVector; scalar: extended): T3DVector;
|
|
begin
|
|
if abs(scalar)<NUM_ZERO then
|
|
raise exception.create('T3DVector.Divide: Division by zero!');
|
|
//raise exception.create('T3DVector.Divide: Dzielenie przez zero!');
|
|
result.x:=left.x/scalar;
|
|
result.y:=left.y/scalar;
|
|
result.z:=left.z/scalar;
|
|
end;
|
|
|
|
class operator T3DVector.Explicit(vector: T2DIntVector): T3DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Explicit(i: integer): T3DVector;
|
|
begin
|
|
result.x:=i;
|
|
result.y:=0;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Explicit(e: extended): T3DVector;
|
|
begin
|
|
result.x:=e;
|
|
result.y:=0;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Explicit(vector: T2DVector): T3DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Explicit(vector: T3DVector): string;
|
|
begin
|
|
result:='[x='+FloatToStr(vector.x)+'; y='+FloatToStr(vector.y)+'; z='+FloatToStr(vector.z)+']';
|
|
end;
|
|
|
|
class operator T3DVector.Implicit(vector: T2DIntVector): T3DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Implicit(vector: T2DVector): T3DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Implicit(i: integer): T3DVector;
|
|
begin
|
|
result.x:=i;
|
|
result.y:=0;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Implicit(e: extended): T3DVector;
|
|
begin
|
|
result.x:=e;
|
|
result.y:=0;
|
|
result.z:=0;
|
|
end;
|
|
|
|
class operator T3DVector.Implicit(vector: T3DVector): string;
|
|
begin
|
|
result:='[x='+FloatToStr(vector.x)+'; y='+FloatToStr(vector.y)+'; z='+FloatToStr(vector.z)+']';
|
|
end;
|
|
|
|
class operator T3DVector.Multiply(left: T3DVector; scalar: extended): T3DVector;
|
|
begin
|
|
result.x:=left.x*scalar;
|
|
result.y:=left.y*scalar;
|
|
result.z:=left.z*scalar;
|
|
end;
|
|
|
|
class operator T3DVector.Multiply(scalar: extended;
|
|
right: T3DVector): T3DVector;
|
|
begin
|
|
result.x:=scalar*right.x;
|
|
result.y:=scalar*right.y;
|
|
result.z:=scalar*right.z;
|
|
end;
|
|
|
|
class operator T3DVector.Multiply(left, right: T3DVector): extended;
|
|
begin
|
|
result:=left.x*right.x + left.y*right.y + left.z*right.z;
|
|
end;
|
|
|
|
class operator T3DVector.Negative(vector: T3DVector): T3DVector;
|
|
begin
|
|
result.x:=-vector.x;
|
|
result.y:=-vector.y;
|
|
result.z:=-vector.z;
|
|
end;
|
|
|
|
class operator T3DVector.Positive(vector: T3DVector): T3DVector;
|
|
begin
|
|
result.x:=vector.x;
|
|
result.y:=vector.y;
|
|
result.z:=vector.z;
|
|
end;
|
|
|
|
class operator T3DVector.Subtract(left, right: T3DVector): T3DVector;
|
|
begin
|
|
result.x:=left.x-right.x;
|
|
result.y:=left.y-right.y;
|
|
result.z:=left.z-right.z;
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
|
|
{ T2DIntRect }
|
|
|
|
constructor T2DIntRect.Create(ALeft, ATop, ARight, ABottom: integer);
|
|
begin
|
|
self.left:=ALeft;
|
|
self.top:=ATop;
|
|
self.right:=ARight;
|
|
self.bottom:=ABottom;
|
|
end;
|
|
|
|
constructor T2DIntRect.Create(ATopLeft, ABottomRight: T2DIntVector);
|
|
begin
|
|
{$ifdef EnhancedRecordSupport}
|
|
self.TopLeft:=ATopLeft;
|
|
self.BottomRight:=ABottomRight;
|
|
{$else}
|
|
Left := ATopLeft.x;
|
|
Top := ATopLeft.y;
|
|
Right := ABottomRight.x;
|
|
Bottom := ABottomRight.y;
|
|
{$endif}
|
|
end;
|
|
|
|
function T2DIntRect.Contains(APoint: T2DIntPoint): boolean;
|
|
begin
|
|
result:=(APoint.x>=self.Left) and (APoint.x<=self.Right) and
|
|
(APoint.y>=self.Top) and (APoint.y<=self.Bottom);
|
|
end;
|
|
|
|
function T2DIntRect.Contains(Ax, Ay: Integer): boolean;
|
|
begin
|
|
result:=(Ax>=Left) and (Ax<=Right) and
|
|
(Ay>=Top) and (Ay<=Bottom);
|
|
end;
|
|
|
|
procedure T2DIntRect.ExpandBy(APoint: T2DIntPoint);
|
|
begin
|
|
self.left:=min(self.left,APoint.x);
|
|
self.right:=max(self.right,APoint.x);
|
|
self.top:=min(self.top,APoint.y);
|
|
self.bottom:=max(self.bottom,APoint.y);
|
|
end;
|
|
|
|
function T2DIntRect.GetVertex(ACorner: TRectCorner): T2DIntVector;
|
|
begin
|
|
{$ifdef EnhancedRecordSupport}
|
|
case ACorner of
|
|
rcLeftTop : result:=T2DIntVector.create(self.left, self.top);
|
|
rcRightTop : result:=T2DIntVector.create(self.right, self.top);
|
|
rcLeftBottom : result:=T2DIntVector.create(self.left, self.bottom);
|
|
rcRightBottom : result:=T2DIntVector.create(self.right, self.bottom);
|
|
end;
|
|
{$else}
|
|
case ACorner of
|
|
rcLeftTop : result.create(self.left, self.top);
|
|
rcRightTop : result.create(self.right, self.top);
|
|
rcLeftBottom : result.create(self.left, self.bottom);
|
|
rcRightBottom : result.create(self.right, self.bottom);
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
function T2DIntRect.Height: integer;
|
|
begin
|
|
result:=self.bottom-self.top+1;
|
|
end;
|
|
|
|
function T2DIntRect.IntersectsWith(ARect : T2DIntRect;
|
|
out Intersection: T2DIntRect): boolean;
|
|
|
|
var XStart, XWidth, YStart, YWidth : integer;
|
|
|
|
begin
|
|
if self.left<=ARect.left then
|
|
begin
|
|
if ARect.left<=self.right then
|
|
begin
|
|
XStart:=ARect.Left;
|
|
XWidth:=min(ARect.right, self.Right) - ARect.left + 1;
|
|
end else
|
|
begin
|
|
XStart:=0;
|
|
XWidth:=0;
|
|
end;
|
|
end else
|
|
begin
|
|
if self.Left<=ARect.right then
|
|
begin
|
|
XStart:=self.left;
|
|
XWidth:=min(ARect.right, self.right) - self.left + 1;
|
|
end else
|
|
begin
|
|
XStart:=0;
|
|
XWidth:=0;
|
|
end;
|
|
end;
|
|
|
|
if self.top<=ARect.top then
|
|
begin
|
|
if ARect.top<=self.bottom then
|
|
begin
|
|
YStart:=ARect.Top;
|
|
YWidth:=min(ARect.bottom, self.bottom) - ARect.top + 1;
|
|
end else
|
|
begin
|
|
YStart:=0;
|
|
YWidth:=0;
|
|
end;
|
|
end else
|
|
begin
|
|
if self.Top<=ARect.bottom then
|
|
begin
|
|
YStart:=self.top;
|
|
YWidth:=min(ARect.bottom, self.bottom) - self.top + 1;
|
|
end else
|
|
begin
|
|
YStart:=0;
|
|
YWidth:=0;
|
|
end;
|
|
end;
|
|
|
|
{$ifdef EnhancedRecordSupport}
|
|
//todo: is it possible to call constructor directly like object?
|
|
Intersection:=T2DIntRect.create(XStart, YStart, XStart+XWidth-1, YStart+YWidth-1);
|
|
{$else}
|
|
Intersection.Create(XStart, YStart, XStart+XWidth-1, YStart+YWidth-1);
|
|
{$endif}
|
|
result:=(XWidth>0) and (YWidth>0);
|
|
end;
|
|
|
|
function T2DIntRect.IntersectsWith(ARect: T2DIntRect): boolean;
|
|
begin
|
|
result:=( max(ARect.left, self.left) <= min(ARect.right, self.right) )
|
|
and
|
|
( max(ARect.Top, self.top) <= min(ARect.bottom, self.bottom) );
|
|
end;
|
|
|
|
procedure T2DIntRect.Move(dx, dy: integer);
|
|
begin
|
|
inc(left, dx);
|
|
inc(right, dx);
|
|
inc(top, dy);
|
|
inc(bottom, dy);
|
|
end;
|
|
|
|
procedure T2DIntRect.Move(AVector: T2DIntVector);
|
|
begin
|
|
inc(self.left,AVector.x);
|
|
inc(self.right, AVector.x);
|
|
inc(self.top, AVector.y);
|
|
inc(self.Bottom, AVector.y);
|
|
end;
|
|
|
|
function T2DIntRect.Moved(AVector: T2DIntVector): T2DIntRect;
|
|
begin
|
|
result.left:=self.left+AVector.x;
|
|
result.Right:=self.right+AVector.x;
|
|
result.top:=self.top+AVector.y;
|
|
result.bottom:=self.bottom+AVector.y;
|
|
end;
|
|
|
|
procedure T2DIntRect.Split(var LeftTop, RightTop, LeftBottom,
|
|
RightBottom: T2DIntRect);
|
|
begin
|
|
if self.left = self.right then
|
|
begin
|
|
LeftTop.left:=self.left;
|
|
LeftTop.right:=self.right;
|
|
|
|
LeftBottom.left:=self.left;
|
|
LeftBottom.right:=self.right;
|
|
|
|
RightTop.left:=self.left;
|
|
RightTop.right:=self.right;
|
|
|
|
RightBottom.left:=self.left;
|
|
RightBottom.right:=self.right;
|
|
end else
|
|
begin
|
|
LeftTop.left:=self.left;
|
|
LeftTop.right:=self.left+(self.right-self.left) div 2;
|
|
|
|
LeftBottom.left:=self.left;
|
|
LeftBottom.right:=self.left+(self.right-self.left) div 2;
|
|
|
|
RightTop.left:=self.left+(self.right-self.left) div 2 + 1;
|
|
RightTop.right:=self.right;
|
|
|
|
RightBottom.left:=self.left+(self.right-self.left) div 2 + 1;
|
|
RightBottom.right:=self.right;
|
|
end;
|
|
|
|
if self.top = self.bottom then
|
|
begin
|
|
LeftTop.top:=self.top;
|
|
LeftTop.bottom:=self.bottom;
|
|
|
|
LeftBottom.top:=self.top;
|
|
LeftBottom.bottom:=self.bottom;
|
|
|
|
RightTop.top:=self.top;
|
|
RightTop.bottom:=self.bottom;
|
|
|
|
RightBottom.top:=self.top;
|
|
RightBottom.bottom:=self.bottom;
|
|
end else
|
|
begin
|
|
LeftTop.top:=self.top;
|
|
LeftTop.bottom:=self.top+(self.bottom-self.top) div 2;
|
|
|
|
LeftBottom.top:=self.top;
|
|
LeftBottom.bottom:=self.top+(self.bottom-self.top) div 2;
|
|
|
|
RightTop.top:=self.top+(self.bottom-self.top) div 2 + 1;
|
|
RightTop.bottom:=self.bottom;
|
|
|
|
RightBottom.top:=self.top+(self.bottom-self.top) div 2 + 1;
|
|
RightBottom.bottom:=self.bottom;
|
|
end;
|
|
end;
|
|
|
|
function T2DIntRect.Width: integer;
|
|
begin
|
|
result:=self.right-self.left+1;
|
|
end;
|
|
|
|
function T2DIntRect.Moved(dx, dy: integer): T2DIntRect;
|
|
begin
|
|
result.left:=self.left+dx;
|
|
result.Right:=self.right+dx;
|
|
result.top:=self.top+dy;
|
|
result.bottom:=self.bottom+dy;
|
|
end;
|
|
|
|
function T2DIntRect.ForWinAPI: TRect;
|
|
begin
|
|
result.left:=self.left;
|
|
result.top:=self.top;
|
|
result.right:=self.right+1;
|
|
result.bottom:=self.bottom+1;
|
|
end;
|
|
|
|
|
|
{$ifdef EnhancedRecordSupport}
|
|
|
|
class operator T2DIntRect.Add(AVector: T2DIntVector;
|
|
ARect: T2DIntRect): T2DIntRect;
|
|
begin
|
|
result:=T2DIntRect.Create(ARect.left + AVector.x,
|
|
ARect.top + AVector.y,
|
|
ARect.Right + AVector.x,
|
|
ARect.bottom + AVector.y);
|
|
end;
|
|
|
|
class operator T2DIntRect.Add(ARect: T2DIntRect;
|
|
AVector: T2DIntVector): T2DIntRect;
|
|
begin
|
|
result:=T2DIntRect.Create(ARect.left + AVector.x,
|
|
ARect.top + AVector.y,
|
|
ARect.Right + AVector.x,
|
|
ARect.bottom + AVector.y);
|
|
end;
|
|
|
|
class operator T2DIntRect.Explicit(ARect: T2DIntRect): TRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DIntRect.Explicit(ARect: TRect): T2DIntRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DIntRect.Implicit(ARect: T2DIntRect): TRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DIntRect.Implicit(ARect: TRect): T2DIntRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DIntRect.Implicit(ARect: T2DIntRect): string;
|
|
begin
|
|
result:='('+inttostr(ARect.left)+', '+inttostr(ARect.top)+', '+inttostr(ARect.right)+', '+inttostr(ARect.bottom)+')';
|
|
end;
|
|
|
|
|
|
|
|
class operator T2DIntRect.Subtract(AVector: T2DIntVector;
|
|
ARect: T2DIntRect): T2DIntRect;
|
|
begin
|
|
result:=T2DIntRect.Create(AVector.x - ARect.left,
|
|
AVector.y - ARect.top,
|
|
AVector.x - ARect.Right,
|
|
AVector.y - ARect.bottom);
|
|
end;
|
|
|
|
class operator T2DIntRect.Subtract(ARect: T2DIntRect;
|
|
AVector: T2DIntVector): T2DIntRect;
|
|
begin
|
|
result:=T2DIntRect.Create(ARect.left - AVector.x,
|
|
ARect.top - AVector.y,
|
|
ARect.Right - AVector.x,
|
|
ARect.bottom - AVector.y);
|
|
end;
|
|
|
|
|
|
class operator T2DIntRect.Explicit(ARect: T2DIntRect): string;
|
|
begin
|
|
result:='('+inttostr(ARect.left)+', '+inttostr(ARect.top)+', '+inttostr(ARect.right)+', '+inttostr(ARect.bottom)+')';
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
{ T2DRect }
|
|
|
|
constructor T2DRect.Create(ALeft, ATop, ARight, ABottom: extended);
|
|
begin
|
|
self.left:=ALeft;
|
|
self.top:=ATop;
|
|
self.right:=ARight;
|
|
self.bottom:=ABottom;
|
|
end;
|
|
|
|
constructor T2DRect.Create(ATopLeft, ABottomRight: T2DVector);
|
|
begin
|
|
{$ifdef EnhancedRecordSupport}
|
|
self.TopLeft:=ATopLeft;
|
|
self.BottomRight:=ABottomRight;
|
|
{$else}
|
|
Left := ATopLeft.x;
|
|
Top := ATopLeft.y;
|
|
Right := ABottomRight.x;
|
|
Bottom := ABottomRight.y;
|
|
{$endif}
|
|
end;
|
|
|
|
function T2DRect.Contains(APoint: T2DPoint): boolean;
|
|
begin
|
|
result:=(APoint.x>=self.Left) and (APoint.y<=self.Right) and
|
|
(APoint.y>=self.Top) and (APoint.y<=self.Bottom);
|
|
end;
|
|
|
|
procedure T2DRect.ExpandBy(APoint: T2DPoint);
|
|
begin
|
|
self.left:=min(self.left,APoint.x);
|
|
self.right:=max(self.right,APoint.x);
|
|
self.top:=min(self.top,APoint.y);
|
|
self.bottom:=max(self.bottom,APoint.y);
|
|
end;
|
|
|
|
function T2DRect.GetVertex(ACorner: TRectCorner): T2DVector;
|
|
begin
|
|
{$ifdef EnhancedRecordSupport}
|
|
case ACorner of
|
|
rcLeftTop : result:=T2DVector.Create(self.left, self.top);
|
|
rcRightTop : result:=T2DVector.Create(self.right, self.top);
|
|
rcLeftBottom : result:=T2DVector.Create(self.left, self.bottom);
|
|
rcRightBottom : result:=T2DVector.Create(self.right, self.bottom);
|
|
end;
|
|
{$else}
|
|
case ACorner of
|
|
rcLeftTop : result.Create(self.left, self.top);
|
|
rcRightTop : result.Create(self.right, self.top);
|
|
rcLeftBottom : result.Create(self.left, self.bottom);
|
|
rcRightBottom : result.Create(self.right, self.bottom);
|
|
end;
|
|
{$endif}
|
|
end;
|
|
|
|
function T2DRect.Height: extended;
|
|
begin
|
|
result:=self.bottom-self.top;
|
|
end;
|
|
|
|
function T2DRect.IntersectsWith(ARect: T2DRect): boolean;
|
|
begin
|
|
result:=( ( (ARect.left>=self.left) and (ARect.left<=self.left) ) or
|
|
( (ARect.right>=self.right) and (ARect.right<=self.right) ) or
|
|
( (self.left>=ARect.left) and (self.left<=ARect.right) ) or
|
|
( (self.right>=ARect.left) and (self.right<=ARect.right) ) )
|
|
and
|
|
( ( (ARect.top>=self.top) and (ARect.top<=self.top) ) or
|
|
( (ARect.bottom>=self.bottom) and (ARect.bottom<=self.bottom) ) or
|
|
( (self.top>=ARect.top) and (self.top<=ARect.bottom) ) or
|
|
( (self.bottom>=ARect.top) and (self.bottom<=ARect.bottom) ) );
|
|
end;
|
|
|
|
procedure T2DRect.Move(dx, dy: extended);
|
|
begin
|
|
self.left:=self.left+dx;
|
|
self.right:=self.right+dx;
|
|
self.top:=self.top+dy;
|
|
self.bottom:=self.bottom+dy;
|
|
end;
|
|
|
|
function T2DRect.Moved(dx, dy: extended): T2DRect;
|
|
begin
|
|
result.left:=self.left+dx;
|
|
result.right:=self.right+dx;
|
|
result.top:=self.top+dy;
|
|
result.bottom:=self.bottom+dy;
|
|
end;
|
|
|
|
procedure T2DRect.Move(Vector: T2DVector);
|
|
begin
|
|
self.left:=self.left+vector.x;
|
|
self.right:=self.right+vector.x;
|
|
self.top:=self.top+vector.y;
|
|
self.bottom:=self.bottom+vector.y;
|
|
end;
|
|
|
|
function T2DRect.Moved(Vector: T2DVector): T2DRect;
|
|
begin
|
|
result.left:=self.left+Vector.x;
|
|
result.right:=self.right+Vector.x;
|
|
result.top:=self.top+Vector.y;
|
|
result.bottom:=self.bottom+Vector.y;
|
|
end;
|
|
|
|
procedure T2DRect.SetCenteredHeight(ANewHeight: extended);
|
|
|
|
var center : extended;
|
|
|
|
begin
|
|
if (ANewHeight<0) then
|
|
raise exception.create('T2DRect.SetCenteredHeight: New height is less than zero!');
|
|
//raise exception.create('T2DRect.SetCenteredHeight: Nowa wysokoϾ mniejsza od zera!');
|
|
|
|
center:=self.top+(self.bottom-self.top)/2;
|
|
self.top:=center-(ANewHeight/2);
|
|
self.bottom:=center+(ANewHeight/2);
|
|
end;
|
|
|
|
procedure T2DRect.SetCenteredWidth(ANewWidth: extended);
|
|
|
|
var center : extended;
|
|
|
|
begin
|
|
if (ANewWidth<0) then
|
|
raise exception.create('T2DRect.SetCenteredWidth: New width is less than zero!');
|
|
//raise exception.create('T2DRect.SetCenteredWidth: Nowa szerokoϾ mniejsza od zera!');
|
|
|
|
center:=self.left+(self.right-self.left)/2;
|
|
self.left:=center-(ANewWidth/2);
|
|
self.right:=center+(ANewWidth/2);
|
|
end;
|
|
|
|
procedure T2DRect.Split(var LeftTop, RightTop, LeftBottom,
|
|
RightBottom: T2DRect);
|
|
begin
|
|
LeftTop.left:=self.left;
|
|
LeftTop.right:=self.left+(self.right-self.left)/2;
|
|
|
|
LeftBottom.left:=self.left;
|
|
LeftBottom.right:=self.left+(self.right-self.left)/2;
|
|
|
|
RightTop.left:=self.left+(self.Right-self.left)/2;
|
|
RightTop.Right:=self.right;
|
|
|
|
RightBottom.left:=self.left+(self.right-self.left)/2;
|
|
RightBottom.right:=self.right;
|
|
|
|
|
|
LeftTop.top:=self.top;
|
|
LeftTop.bottom:=self.top+(self.bottom-self.top)/2;
|
|
|
|
LeftBottom.top:=self.top;
|
|
LeftBottom.bottom:=self.top+(self.bottom-self.top)/2;
|
|
|
|
RightTop.top:=self.top+(self.bottom-self.top)/2;
|
|
RightTop.bottom:=self.bottom;
|
|
|
|
RightBottom.top:=self.top+(self.bottom-self.top)/2;
|
|
RightBottom.bottom:=self.bottom;
|
|
end;
|
|
|
|
function T2DRect.Width: extended;
|
|
begin
|
|
result:=self.right-self.left;
|
|
end;
|
|
|
|
{$ifdef EnhancedRecordSupport}
|
|
|
|
class operator T2DRect.Explicit(ARect: TRect): T2DRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DRect.Explicit(ARect: T2DRect): TRect;
|
|
begin
|
|
result.left:=round(ARect.left);
|
|
result.top:=round(ARect.top);
|
|
result.Right:=round(ARect.Right);
|
|
result.bottom:=round(ARect.bottom);
|
|
end;
|
|
|
|
class operator T2DRect.Explicit(ARect: T2DRect): T2DIntRect;
|
|
begin
|
|
result.left:=round(ARect.left);
|
|
result.top:=round(ARect.top);
|
|
result.Right:=round(ARect.Right);
|
|
result.bottom:=round(ARect.bottom);
|
|
end;
|
|
|
|
class operator T2DRect.Explicit(ARect: T2DIntRect): T2DRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DRect.Implicit(ARect: TRect): T2DRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DRect.Implicit(ARect: T2DRect): TRect;
|
|
begin
|
|
result.left:=round(ARect.left);
|
|
result.top:=round(ARect.top);
|
|
result.Right:=round(ARect.Right);
|
|
result.bottom:=round(ARect.bottom);
|
|
end;
|
|
|
|
class operator T2DRect.Implicit(ARect: T2DRect): T2DIntRect;
|
|
begin
|
|
result.left:=round(ARect.left);
|
|
result.top:=round(ARect.top);
|
|
result.Right:=round(ARect.Right);
|
|
result.bottom:=round(ARect.bottom);
|
|
end;
|
|
|
|
class operator T2DRect.Implicit(ARect: T2DIntRect): T2DRect;
|
|
begin
|
|
result.left:=ARect.left;
|
|
result.top:=ARect.top;
|
|
result.Right:=ARect.Right;
|
|
result.bottom:=ARect.bottom;
|
|
end;
|
|
|
|
class operator T2DRect.Explicit(ARect: T2DRect): string;
|
|
begin
|
|
result:='('+floattostr(ARect.left)+', '+floattostr(ARect.top)+', '+floattostr(ARect.right)+', '+floattostr(ARect.bottom)+')';
|
|
end;
|
|
|
|
class operator T2DRect.Implicit(ARect: T2DRect): string;
|
|
begin
|
|
result:='('+floattostr(ARect.left)+', '+floattostr(ARect.top)+', '+floattostr(ARect.right)+', '+floattostr(ARect.bottom)+')';
|
|
end;
|
|
|
|
{$endif}
|
|
|
|
procedure EnsureOrder(var a, b: Integer);
|
|
var
|
|
tmp: Integer;
|
|
begin
|
|
if a <= b then
|
|
exit;
|
|
tmp := a;
|
|
a := b;
|
|
b := tmp;
|
|
end;
|
|
|
|
end.
|