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 len0 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 lenNUM_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)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)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=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.