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.