|
@@ -19,10 +19,18 @@ unit Types;
|
|
|
|
|
|
interface
|
|
|
|
|
|
+Type
|
|
|
+ Single = Double; // Avoid warning.
|
|
|
+
|
|
|
const
|
|
|
Epsilon: Single = 1E-40;
|
|
|
Epsilon2: Single = 1E-30;
|
|
|
|
|
|
+ cPI: Single = 3.141592654;
|
|
|
+ cPIdiv180: Single = 0.017453292;
|
|
|
+ cPIdiv2: Single = 1.570796326;
|
|
|
+ cPIdiv4: Single = 0.785398163;
|
|
|
+
|
|
|
type
|
|
|
RTLString = string; // Compatibility with FPC
|
|
|
|
|
@@ -379,13 +387,24 @@ type
|
|
|
|
|
|
|
|
|
function EqualRect(const r1,r2 : TRect) : Boolean;
|
|
|
+function EqualRect(const r1,r2 : TRectF) : Boolean;
|
|
|
function Rect(Left, Top, Right, Bottom : Integer) : TRect;
|
|
|
+function RectF(Left,Top,Right,Bottom : Single) : TRectF; inline;
|
|
|
function Bounds(ALeft, ATop, AWidth, AHeight : Integer) : TRect;
|
|
|
function Point(x,y : Integer): TPoint; {$IFDEF Has_Inline}inline;{$ENDIF}
|
|
|
function PointF(x,y : single) : TPointF; {$IFDEF Has_Inline}inline;{$ENDIF}
|
|
|
function PtInRect(const aRect: TRect; const p: TPoint) : Boolean;
|
|
|
function IntersectRect(out aRect: TRect; const R1,R2: TRect) : Boolean;
|
|
|
+function IntersectRect(const Rect1, Rect2: TRect): Boolean;
|
|
|
+function IntersectRect(const Rect1, Rect2: TRectF): Boolean;
|
|
|
+//function IntersectRect(var Rect : TRect; const R1,R2 : TRect) : Boolean;
|
|
|
+function IntersectRect(var aRect : TRectF; const R1,R2 : TRectF) : Boolean;
|
|
|
+
|
|
|
function UnionRect(out aRect: TRect; const R1,R2: TRect) : Boolean;
|
|
|
+function UnionRect(out aRectF: TRectF; const R1,R2: TRectF) : Boolean;
|
|
|
+function UnionRect(const R1,R2 : TRect) : TRect;
|
|
|
+function UnionRect(const R1,R2 : TRectF) : TRectF;
|
|
|
+
|
|
|
function IsRectEmpty(const aRect: TRect) : Boolean;
|
|
|
function OffsetRect(var aRect: TRect; DX, DY: Integer) : Boolean;
|
|
|
function OffsetRect(var aRect: TRectF; DX, DY: single) : Boolean;
|
|
@@ -396,6 +415,30 @@ function Size(const aRect: TRect): TSize;
|
|
|
function RectCenter(var R: TRect; const Bounds: TRect): TRect;
|
|
|
function RectCenter(var R: TRectF; const Bounds: TRectF): TRectF;
|
|
|
|
|
|
+function NormalizeRectF(const Pts: array of TPointF): TRectF; overload;
|
|
|
+function NormalizeRect(const ARect: TRectF): TRectF; overload;
|
|
|
+
|
|
|
+function PtInRect(const Rect : TRectF; const p : TPointF) : Boolean;
|
|
|
+
|
|
|
+function RectHeight(const Rect: TRect): Integer; inline;
|
|
|
+function RectHeight(const Rect: TRectF): Single; inline;
|
|
|
+function RectWidth(const Rect: TRect): Integer; inline;
|
|
|
+function RectWidth(const Rect: TRectF): Single; inline;
|
|
|
+function IsRectEmpty(const Rect : TRectF) : Boolean;
|
|
|
+procedure MultiplyRect(var R: TRectF; const DX, DY: Single);
|
|
|
+function InflateRect(var Rect: TRectF; dx: single; dy: Single): Boolean;
|
|
|
+function Size(const ARect: TRectF): TSizeF; inline;
|
|
|
+function ScalePoint(const P: TPointF; dX, dY: Single): TPointF; overload;
|
|
|
+function ScalePoint(const P: TPoint; dX, dY: Single): TPoint; overload;
|
|
|
+function MinPoint(const P1, P2: TPointF): TPointF; overload;
|
|
|
+function MinPoint(const P1, P2: TPoint): TPoint; overload;
|
|
|
+function SplitRect(const Rect: TRect; SplitType: TSplitRectType; Size: Integer): TRect; overload;
|
|
|
+function SplitRect(const Rect: TRect; SplitType: TSplitRectType; Percent: Double): TRect; overload;
|
|
|
+function CenteredRect(const SourceRect: TRect; const aCenteredRect: TRect): TRect;
|
|
|
+function IntersectRectF(out Rect: TRectF; const R1, R2: TRectF): Boolean;
|
|
|
+function UnionRectF(out Rect: TRectF; const R1, R2: TRectF): Boolean;
|
|
|
+
|
|
|
+
|
|
|
implementation
|
|
|
|
|
|
uses math;
|
|
@@ -425,11 +468,165 @@ begin
|
|
|
Result:=R;
|
|
|
end;
|
|
|
|
|
|
+function NormalizeRectF(const Pts: array of TPointF): TRectF;
|
|
|
+var
|
|
|
+ Pt: TPointF;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result.Left:=$FFFF;
|
|
|
+ Result.Top:=$FFFF;
|
|
|
+ Result.Right:=-$FFFF;
|
|
|
+ Result.Bottom:=-$FFFF;
|
|
|
+ for Pt in Pts do
|
|
|
+ begin
|
|
|
+ Result.Left:=Min(Pt.X,Result.left);
|
|
|
+ Result.Top:=Min(Pt.Y,Result.Top);
|
|
|
+ Result.Right:=Max(Pt.X,Result.Right);
|
|
|
+ Result.Bottom:=Max(Pt.Y,Result.Bottom);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+function NormalizeRect(const ARect: TRectF): TRectF;
|
|
|
+
|
|
|
+begin
|
|
|
+ With aRect do
|
|
|
+ Result:=NormalizeRectF([PointF(Left,Top),
|
|
|
+ PointF(Right,Top),
|
|
|
+ PointF(Right,Bottom),
|
|
|
+ PointF(Left,Bottom)]);
|
|
|
+end;
|
|
|
+
|
|
|
+function PtInRect(const Rect: TRectF; const p: TPointF): Boolean;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=(p.y>=Rect.Top) and
|
|
|
+ (p.y<Rect.Bottom) and
|
|
|
+ (p.x>=Rect.Left) and
|
|
|
+ (p.x<Rect.Right);
|
|
|
+end;
|
|
|
+
|
|
|
+function RectHeight(const Rect: TRect): Integer;
|
|
|
+begin
|
|
|
+ Result:=Rect.Height;
|
|
|
+end;
|
|
|
+
|
|
|
+function RectHeight(const Rect: TRectF): Single;
|
|
|
+begin
|
|
|
+ Result:=Rect.Height;
|
|
|
+end;
|
|
|
+
|
|
|
+function RectWidth(const Rect: TRect): Integer;
|
|
|
+begin
|
|
|
+ Result:=Rect.Width;
|
|
|
+
|
|
|
+end;
|
|
|
+
|
|
|
+function RectWidth(const Rect: TRectF): Single;
|
|
|
+begin
|
|
|
+ Result:=Rect.Width;
|
|
|
+end;
|
|
|
+
|
|
|
+function IsRectEmpty(const Rect: TRectF): Boolean;
|
|
|
+begin
|
|
|
+ Result:=Rect.IsEmpty;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure MultiplyRect(var R: TRectF; const DX, DY: Single);
|
|
|
+begin
|
|
|
+ R.Left:=DX*R.Left;
|
|
|
+ R.Right:=DX*R.Right;
|
|
|
+ R.Top:=DY*R.Top;
|
|
|
+ R.Bottom:=DY*R.Bottom;
|
|
|
+end;
|
|
|
+
|
|
|
+function InflateRect(var Rect: TRectF; dx: single; dy: Single): Boolean;
|
|
|
+begin
|
|
|
+ Result:=True;
|
|
|
+ with Rect do
|
|
|
+ begin
|
|
|
+ Left:=Left-dx;
|
|
|
+ Top:=Top-dy;
|
|
|
+ Right:=Right+dx;
|
|
|
+ Bottom:=Bottom+dy;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+function Size(const ARect: TRectF): TSizeF;
|
|
|
+begin
|
|
|
+ Result.cx := ARect.Right - ARect.Left;
|
|
|
+ Result.cy := ARect.Bottom - ARect.Top;
|
|
|
+end;
|
|
|
+
|
|
|
+function ScalePoint(const P: TPointF; dX, dY: Single): TPointF;
|
|
|
+begin
|
|
|
+ Result.X:=P.X*dX;
|
|
|
+ Result.Y:=P.Y*dY;
|
|
|
+end;
|
|
|
+
|
|
|
+function ScalePoint(const P: TPoint; dX, dY: Single): TPoint;
|
|
|
+begin
|
|
|
+ Result.X:=Round(P.X*dX);
|
|
|
+ Result.Y:=Round(P.Y*dY);
|
|
|
+end;
|
|
|
+
|
|
|
+function MinPoint(const P1, P2: TPointF): TPointF;
|
|
|
+begin
|
|
|
+ Result:=P1;
|
|
|
+ if (P2.Y<P1.Y)
|
|
|
+ or ((P2.Y=P1.Y) and (P2.X<P1.X)) then
|
|
|
+ Result:=P2;
|
|
|
+end;
|
|
|
+
|
|
|
+function MinPoint(const P1, P2: TPoint): TPoint;
|
|
|
+begin
|
|
|
+ Result:=P1;
|
|
|
+ if (P2.Y<P1.Y)
|
|
|
+ or ((P2.Y=P1.Y) and (P2.X<P1.X)) then
|
|
|
+ Result:=P2;
|
|
|
+end;
|
|
|
+
|
|
|
+function SplitRect(const Rect: TRect; SplitType: TSplitRectType; Size: Integer): TRect;
|
|
|
+begin
|
|
|
+ Result:=Rect.SplitRect(SplitType,Size);
|
|
|
+end;
|
|
|
+
|
|
|
+function SplitRect(const Rect: TRect; SplitType: TSplitRectType; Percent: Double): TRect;
|
|
|
+begin
|
|
|
+ Result:=Rect.SplitRect(SplitType,Percent);
|
|
|
+end;
|
|
|
+
|
|
|
+function CenteredRect(const SourceRect: TRect; const aCenteredRect: TRect): TRect;
|
|
|
+var
|
|
|
+ W,H: Integer;
|
|
|
+ Center : TPoint;
|
|
|
+begin
|
|
|
+ W:=aCenteredRect.Width;
|
|
|
+ H:=aCenteredRect.Height;
|
|
|
+ Center:=SourceRect.CenterPoint;
|
|
|
+ With Center do
|
|
|
+ Result:= Rect(X-(W div 2),Y-(H div 2),X+((W+1) div 2),Y+((H+1) div 2));
|
|
|
+end;
|
|
|
+
|
|
|
+function IntersectRectF(out Rect: TRectF; const R1, R2: TRectF): Boolean;
|
|
|
+begin
|
|
|
+ Result:=IntersectRect(Rect,R1,R2);
|
|
|
+end;
|
|
|
+
|
|
|
+function UnionRectF(out Rect: TRectF; const R1, R2: TRectF): Boolean;
|
|
|
+begin
|
|
|
+ Result:=UnionRect(Rect,R1,R2);
|
|
|
+end;
|
|
|
+
|
|
|
function EqualRect(const r1, r2: TRect): Boolean;
|
|
|
begin
|
|
|
Result:=(r1.left=r2.left) and (r1.right=r2.right) and (r1.top=r2.top) and (r1.bottom=r2.bottom);
|
|
|
end;
|
|
|
|
|
|
+function EqualRect(const r1, r2: TRectF): Boolean;
|
|
|
+begin
|
|
|
+ EqualRect:=r1.EqualsTo(r2);
|
|
|
+end;
|
|
|
+
|
|
|
function Rect(Left, Top, Right, Bottom: Integer): TRect;
|
|
|
begin
|
|
|
Result.Left:=Left;
|
|
@@ -438,6 +635,16 @@ begin
|
|
|
Result.Bottom:=Bottom;
|
|
|
end;
|
|
|
|
|
|
+function RectF(Left,Top,Right,Bottom : Single) : TRectF; inline;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result.Left:=Left;
|
|
|
+ Result.Top:=Top;
|
|
|
+ Result.Right:=Right;
|
|
|
+ Result.Bottom:=Bottom;
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
|
|
|
begin
|
|
|
Result.Left:=ALeft;
|
|
@@ -494,6 +701,51 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
+function IntersectRect(const Rect1, Rect2: TRect): Boolean;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=(Rect1.Left<Rect2.Right)
|
|
|
+ and (Rect1.Right>Rect2.Left)
|
|
|
+ and (Rect1.Top<Rect2.Bottom)
|
|
|
+ and (Rect1.Bottom>Rect2.Top);
|
|
|
+end;
|
|
|
+
|
|
|
+function IntersectRect(const Rect1, Rect2: TRectF): Boolean;
|
|
|
+begin
|
|
|
+ Result:=(Rect1.Left<Rect2.Right)
|
|
|
+ and (Rect1.Right>Rect2.Left)
|
|
|
+ and (Rect1.Top<Rect2.Bottom)
|
|
|
+ and (Rect1.Bottom>Rect2.Top);
|
|
|
+end;
|
|
|
+
|
|
|
+function IntersectRect(var aRect: TRectF; const R1, R2: TRectF): Boolean;
|
|
|
+var
|
|
|
+ lRect: TRectF;
|
|
|
+begin
|
|
|
+ lRect := R1;
|
|
|
+ if R2.Left > R1.Left then
|
|
|
+ lRect.Left := R2.Left;
|
|
|
+ if R2.Top > R1.Top then
|
|
|
+ lRect.Top := R2.Top;
|
|
|
+ if R2.Right < R1.Right then
|
|
|
+ lRect.Right := R2.Right;
|
|
|
+ if R2.Bottom < R1.Bottom then
|
|
|
+ lRect.Bottom := R2.Bottom;
|
|
|
+
|
|
|
+ // The var parameter is only assigned in the end to avoid problems
|
|
|
+ // when passing the same rectangle in the var and const parameters.
|
|
|
+ if IsRectEmpty(lRect) then
|
|
|
+ begin
|
|
|
+ aRect:=RectF(0.0,0.0,0.0,0.0);
|
|
|
+ Result:=false;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ Result:=true;
|
|
|
+ aRect := lRect;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
function UnionRect(out aRect: TRect; const R1, R2: TRect): Boolean;
|
|
|
var
|
|
|
lRect: TRect;
|
|
@@ -520,6 +772,44 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
+function UnionRect(out aRectF: TRectF; const R1, R2: TRectF): Boolean;
|
|
|
+var
|
|
|
+ lRect: TRectF;
|
|
|
+begin
|
|
|
+ lRect:=R1;
|
|
|
+ if R2.Left<R1.Left then
|
|
|
+ lRect.Left:=R2.Left;
|
|
|
+ if R2.Top<R1.Top then
|
|
|
+ lRect.Top:=R2.Top;
|
|
|
+ if R2.Right>R1.Right then
|
|
|
+ lRect.Right:=R2.Right;
|
|
|
+ if R2.Bottom>R1.Bottom then
|
|
|
+ lRect.Bottom:=R2.Bottom;
|
|
|
+
|
|
|
+ if IsRectEmpty(lRect) then
|
|
|
+ begin
|
|
|
+ aRectF:=RectF(0.0,0.0,0.0,0.0);
|
|
|
+ Result:=false;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ aRectF:=lRect;
|
|
|
+ Result:=true;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+function UnionRect(const R1, R2: TRect): TRect;
|
|
|
+begin
|
|
|
+ Result:=Default(TRect);
|
|
|
+ UnionRect(Result,R1,R2);
|
|
|
+end;
|
|
|
+
|
|
|
+function UnionRect(const R1, R2: TRectF): TRectF;
|
|
|
+begin
|
|
|
+ Result:=Default(TRectF);
|
|
|
+ UnionRect(Result,R1,R2);
|
|
|
+end;
|
|
|
+
|
|
|
function IsRectEmpty(const aRect: TRect): Boolean;
|
|
|
begin
|
|
|
Result:=(aRect.Right<=aRect.Left) or (aRect.Bottom<=aRect.Top);
|
|
@@ -1015,8 +1305,18 @@ begin
|
|
|
end;
|
|
|
|
|
|
function TPointF.Reflect(const normal: TPointF): TPointF;
|
|
|
+var
|
|
|
+ lCross : single;
|
|
|
+ lTmp : TPointF;
|
|
|
+
|
|
|
begin
|
|
|
//result := self + (-2 * normal ** self) * normal;
|
|
|
+ lCross:=x*normal.x + y*normal.y;
|
|
|
+ lCross:=lCross * (-2);
|
|
|
+ lTmp.x:=normal.x*lCross;
|
|
|
+ lTmp.y:=normal.y*lCross;
|
|
|
+ Result.X:=X+lTmp.x;
|
|
|
+ Result.Y:=Y+lTmp.Y;
|
|
|
end;
|
|
|
|
|
|
function TPointF.MidPoint(const b: TPointF): TPointF;
|
|
@@ -1048,8 +1348,11 @@ begin
|
|
|
end;
|
|
|
|
|
|
function TPointF.AngleCosine(const b: TPointF): single;
|
|
|
+var
|
|
|
+ lCross : single;
|
|
|
begin
|
|
|
-// result := EnsureRange((self ** b) / sqrt((sqr(x) + sqr(y)) * (sqr(b.x) + sqr(b.y))), -1, 1);
|
|
|
+ lCross:=x*b.x + y*b.y;
|
|
|
+ result := EnsureRange(lCross / sqrt((sqr(x) + sqr(y)) * (sqr(b.x) + sqr(b.y))), -1, 1);
|
|
|
end;
|
|
|
|
|
|
(*
|
|
@@ -1754,8 +2057,6 @@ function TPoint3D.ToString(aSize,aDecimals : Byte) : RTLString;
|
|
|
|
|
|
var
|
|
|
Sx,Sy,Sz : string;
|
|
|
- P : integer;
|
|
|
-
|
|
|
begin
|
|
|
Sx:=SingleToStr(X,aSize,aDecimals);
|
|
|
Sy:=SingleToStr(Y,aSize,aDecimals);
|