Browse Source

* Add some structured types methods

Michaël Van Canneyt 7 tháng trước cách đây
mục cha
commit
8a0ab88be4
2 tập tin đã thay đổi với 1536 bổ sung3 xóa
  1. 1 1
      packages/rtl/src/math.pas
  2. 1535 2
      packages/rtl/src/types.pas

+ 1 - 1
packages/rtl/src/math.pas

@@ -23,7 +23,7 @@ const
   MaxInteger = $fffffffffffff;
   MinDouble  =  5.0e-324;
   MaxDouble  =  1.7e+308;
-
+  Epsilon    = 1.1e-10;
 const
   NaN: Double; external name 'NaN';
   Infinity: Double; external name 'Infinity';

+ 1535 - 2
packages/rtl/src/types.pas

@@ -15,10 +15,17 @@ unit Types;
 {$ENDIF}
 
 {$mode objfpc}
+{$modeswitch advancedrecords}
 
 interface
 
+const
+  Epsilon: Single = 1E-40;
+  Epsilon2: Single = 1E-30;
+
 type
+  RTLString = string; // Compatibility with FPC
+
   THandle = NativeInt;
   TDirection = (FromBeginning, FromEnd);
 
@@ -28,10 +35,17 @@ type
   TNativeIntDynArray = array of NativeInt;
   TStringDynArray = array of String;
   TDoubleDynArray = array of Double;
+  TSingleDynArray = TDoubleDynArray; //Avoid warning
   TJSValueDynArray = array of JSValue;
   TObjectDynArray = array of TObject;
   TByteDynArray = array of Byte;
 
+  TSplitRectType = (
+    srLeft,
+    srRight,
+    srTop,
+    srBottom
+  );
   TDuplicates = (dupIgnore, dupAccept, dupError);
   TProc = Reference to Procedure;
   TProcString = Reference to Procedure(Const aString : String);
@@ -47,26 +61,322 @@ type
     x, y: integer;
   end;
 
-  TRect  = record
-    Left, Top, Right, Bottom: Integer;
+  { TRect }
+
+  TRect =
+{$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
+  packed
+{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
+  record
+  private
+    function GetBottomRight: TPoint;
+    function  getHeight: Longint; inline;
+    function  getLocation: TPoint;
+    function  getSize: TSize;
+    function GetTopLeft: TPoint;
+    function  getWidth : Longint; inline;
+    procedure SetBottomRight(const aValue: TPoint);
+    procedure setHeight(AValue: Longint);
+    procedure setSize(AValue: TSize);
+    procedure SetTopLeft(const aValue: TPoint);
+    procedure setWidth (AValue: Longint);
+  public
+    constructor Create(Origin: TPoint); // empty rect at given origin
+    constructor Create(Origin: TPoint; AWidth, AHeight: Longint);
+    constructor Create(ALeft, ATop, ARight, ABottom: Longint);
+    constructor Create(P1, P2: TPoint; Normalize: Boolean = False);
+    constructor Create(R: TRect; Normalize: Boolean = False);
+    (*
+    class operator = (L, R: TRect): Boolean; static;
+    class operator <> (L, R: TRect): Boolean; static;
+    class operator + (L, R: TRect): TRect; static; // union
+    class operator * (L, R: TRect): TRect; static; // intersection
+    *)
+    class function Empty: TRect; static;
+    procedure NormalizeRect;
+    function IsEmpty: Boolean;
+    function Contains(Pt: TPoint): Boolean;
+    function Contains(R: TRect): Boolean;
+    function IntersectsWith(R: TRect): Boolean;
+    class function Intersect(R1: TRect; R2: TRect): TRect; static;
+    procedure Intersect(R: TRect);
+    class function Union(R1, R2: TRect): TRect; static;
+    procedure Union(R: TRect);
+    class function Union(const Points: array of TPoint): TRect; static;
+    procedure Offset(DX, DY: Longint);
+    procedure Offset(DP: TPoint);
+    procedure SetLocation(X, Y: Longint);
+    procedure SetLocation(P: TPoint);
+    procedure Inflate(DX, DY: Longint);
+    procedure Inflate(DL, DT, DR, DB: Longint);
+    function CenterPoint: TPoint;
+    function SplitRect(SplitType: TSplitRectType; ASize: Longint): TRect;
+    function SplitRect(SplitType: TSplitRectType; Percent: Double): TRect;
+  public
+    Left,Top,Right,Bottom : Longint;
+    property Height: Longint read getHeight write setHeight;
+    property Width : Longint read getWidth  write setWidth;
+    property Size  : TSize   read getSize   write setSize;
+    property Location  : TPoint read getLocation write setLocation;
+    property TopLeft : TPoint read GetTopLeft Write SetTopLeft;
+    property BottomRight : TPoint Read GetBottomRight Write SetBottomRight;
+    // 2: (Vector:TArray4IntegerType);
+  end;
+  PRect = ^TRect;
+
+  { TPointF }
+  PPointF = ^TPointF;
+  TPointF =
+{$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
+  packed
+{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
+  record
+       x,y : Single;
+       public
+          function Add(const apt: TPoint): TPointF;
+          function Add(const apt: TPointF): TPointF;
+          function Distance(const apt : TPointF) : Single;
+          function DotProduct(const apt : TPointF) : Single;
+          function IsZero : Boolean;
+          function Subtract(const apt : TPointF): TPointF;
+          function Subtract(const apt : TPoint): TPointF;
+          procedure SetLocation(const apt :TPointF);
+          procedure SetLocation(const apt :TPoint);
+          procedure SetLocation(ax,ay : Single);
+          procedure Offset(const apt :TPointF);
+          procedure Offset(const apt :TPoint);
+          procedure Offset(dx,dy : Single);
+          function EqualsTo(const apt: TPointF; const aEpsilon : Single): Boolean; overload;
+          function EqualsTo(const apt: TPointF): Boolean; overload;
+
+          function  Scale (afactor:Single)  : TPointF;
+          function  Ceiling : TPoint;
+          function  Truncate: TPoint;
+          function  Floor   : TPoint;
+          function  Round   : TPoint;
+          function  Length  : Single;
+
+          function Rotate(angle: single): TPointF;
+          function Reflect(const normal: TPointF): TPointF;
+          function MidPoint(const b: TPointF): TPointF;
+          class function PointInCircle(const pt, center: TPointF; radius: single): Boolean; static;
+          class function PointInCircle(const pt, center: TPointF; radius: integer): Boolean; static;
+          class function Zero: TPointF; inline; static;
+          function Angle(const b: TPointF): Single;
+          function AngleCosine(const b: TPointF): single;
+          function CrossProduct(const apt: TPointF): Single;
+          function Normalize: TPointF;
+          function ToString(aSize,aDecimals : Byte) : RTLString; overload;
+          function ToString : RTLString; overload; inline;
+
+          class function Create(const ax, ay: Single): TPointF; overload; static; inline;
+          class function Create(const apt: TPoint): TPointF; overload; static; inline;
+(*
+          class operator equals(const apt1, apt2 : TPointF) : Boolean; static;
+          class operator <> (const apt1, apt2 : TPointF): Boolean; static;
+          class operator + (const apt1, apt2 : TPointF): TPointF;static;
+          class operator - (const apt1, apt2 : TPointF): TPointF;static;
+          class operator - (const apt1 : TPointF): TPointF;static;
+          class operator * (const apt1, apt2: TPointF): TPointF;static;
+          class operator * (const apt1: TPointF; afactor: single): TPointF;static;
+          class operator * (afactor: single; const apt1: TPointF): TPointF;static;
+          class operator / (const apt1: TPointF; afactor: single): TPointF;static;
+          class operator := (const apt: TPoint): TPointF;static;
+          class operator ** (const apt1, apt2: TPointF): Single;static; // scalar product
+*)
   end;
+
+  { TSizeF }
+  PSizeF = ^TSizeF;
+  TSizeF =
+{$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
+  packed
+{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
+  record
+       cx,cy : Single;
+       public
+          function Add(const asz: TSize): TSizeF;
+          function Add(const asz: TSizeF): TSizeF;
+          function Distance(const asz : TSizeF) : Single;
+          function IsZero : Boolean;
+          function Subtract(const asz : TSizeF): TSizeF;
+          function Subtract(const asz : TSize): TSizeF;
+          function SwapDimensions:TSizeF;
+
+          function  Scale (afactor:Single)  : TSizeF;
+          function  Ceiling : TSize;
+          function  Truncate: TSize;
+          function  Floor   : TSize;
+          function  Round   : TSize;
+          function  Length  : Single;
+          function ToString(aSize,aDecimals : Byte) : RTLString; overload;
+          function ToString : RTLString; overload; inline;
+
+          class function Create(const ax, ay: Single): TSizeF; overload; static; inline;
+          class function Create(const asz: TSize): TSizeF; overload; static; inline;
+(*
+          class operator = (const asz1, asz2 : TSizeF) : Boolean;static;
+          class operator <> (const asz1, asz2 : TSizeF): Boolean;static;
+          class operator + (const asz1, asz2 : TSizeF): TSizeF;static;
+          class operator - (const asz1, asz2 : TSizeF): TSizeF;static;
+          class operator - (const asz1 : TSizeF): TSizeF;static;
+          class operator * (const asz1: TSizeF; afactor: single): TSizeF;static;
+          class operator * (afactor: single; const asz1: TSizeF): TSizeF;static;
+          class operator := (const apt: TPointF): TSizeF;static;
+          class operator := (const asz: TSize): TSizeF;static;
+          class operator := (const asz: TSizeF): TPointF;static;
+*)
+          property Width: Single read cx write cx;
+          property Height: Single read cy write cy;
+       end;
+
+  {$SCOPEDENUMS ON}
+  TVertRectAlign = (Center, Top, Bottom);
+  THorzRectAlign = (Center, Left, Right);
+  {$SCOPEDENUMS OFF}
+
+  { TRectF }
+  PRectF = ^TRectF;
+  TRectF =
+{$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
+  packed
+{$endif FPC_REQUIRES_PROPER_ALIGNMENT}
+  record
+  private
+    function GetBottomRight: TPointF;
+    function  GetLocation: TPointF;
+    function  GetSize: TSizeF;
+    function GetTopLeft: TPointF;
+    procedure SetBottomRight(const aValue: TPointF);
+    procedure SetSize(AValue: TSizeF);
+    function GetHeight: Single; inline;
+    function GetWidth: Single;  inline;
+    procedure SetHeight(AValue: Single);
+    procedure SetTopLeft(const aValue: TPointF);
+    procedure SetWidth (AValue: Single);
+  public
+    Left, Top, Right, Bottom: Single;
+    constructor Create(Origin: TPointF); // empty rect at given origin
+    constructor Create(Origin: TPointF; AWidth, AHeight: Single);
+    constructor Create(ALeft, ATop, ARight, ABottom: Single);
+    constructor Create(P1, P2: TPointF; Normalize: Boolean = False);
+    constructor Create(R: TRectF; Normalize: Boolean = False);
+    constructor Create(R: TRect; Normalize: Boolean = False);
+
+(*
+    class operator = (L, R: TRectF): Boolean;static;
+    class operator <> (L, R: TRectF): Boolean;static;
+    class operator + (L, R: TRectF): TRectF; static;// union
+    class operator * (L, R: TRectF): TRectF; static;// intersection
+    class operator := (const arc: TRect): TRectF; static;
+*)
+    class function Empty: TRectF; static;
+
+    class function Intersect(R1: TRectF; R2: TRectF): TRectF; static;
+    class function Union(const Points: array of TPointF): TRectF; static;
+    class function Union(R1, R2: TRectF): TRectF; static;
+    Function Ceiling : TRectF;
+    function CenterAt(const Dest: TRectF): TRectF;
+    function CenterPoint: TPointF;
+    function Contains(Pt: TPointF): Boolean;
+    function Contains(R: TRectF): Boolean;
+    function EqualsTo(const R: TRectF; const Epsilon: Single = 0): Boolean;
+    function Fit(const Dest: TRectF): Single; deprecated 'Use FitInto';
+    function FitInto(const Dest: TRectF): TRectF; overload;
+    function FitInto(const Dest: TRectF; out Ratio: Single): TRectF; overload;
+    function IntersectsWith(R: TRectF): Boolean;
+    function IsEmpty: Boolean;
+    function PlaceInto(const Dest: TRectF; const AHorzAlign: THorzRectAlign = THorzRectAlign.Center;  const AVertAlign: TVertRectAlign = TVertRectAlign.Center): TRectF;
+    function Round: TRect;
+    function SnapToPixel(AScale: Single; APlaceBetweenPixels: Boolean = True): TRectF;
+    function Truncate: TRect;
+    procedure Inflate(DL, DT, DR, DB: Single);
+    procedure Inflate(DX, DY: Single);
+    procedure Intersect(R: TRectF);
+    procedure NormalizeRect;
+    procedure Offset (const dx,dy : Single); inline;
+    procedure Offset (DP: TPointF); inline;
+    procedure SetLocation(P: TPointF);
+//    procedure SetLocation(X, Y: Single);
+    function ToString(aSize,aDecimals : Byte; aUseSize : Boolean = False) : RTLString; overload;
+    function ToString(aUseSize : Boolean = False) : RTLString; overload; inline;
+    procedure Union  (const r: TRectF); inline;
+    property  Width  : Single read GetWidth write SetWidth;
+    property  Height : Single read GetHeight write SetHeight;
+    property  Size   : TSizeF read getSize   write SetSize;
+    property  Location: TPointF read getLocation write setLocation;
+    property TopLeft : TPointF Read GetTopLeft Write SetTopLeft;
+    property BottomRight : TPointF Read GetBottomRight Write SetBottomRight;
+    end;
+
+  { TPoint3D }
+
+  TPoint3D = record
+  Public
+    Type TSingle3Array = array[0..2] of single;
+
+    private
+      function GetSingle3Array: TSingle3Array;
+      procedure SetSingle3Array(const aValue: TSingle3Array);
+    public
+     constructor Create(const ax,ay,az:single);
+     procedure   Offset(const adeltax,adeltay,adeltaz:single); inline;
+     procedure   Offset(const adelta:TPoint3D); inline;
+     function ToString(aSize,aDecimals : Byte) : RTLString; overload;
+     function ToString : RTLString; overload; inline;
+   public
+     Property Data : TSingle3Array Read GetSingle3Array Write SetSingle3Array;
+     x,y,z : single;
+    end;
+
   
 function EqualRect(const r1,r2 : TRect) : Boolean;
 function Rect(Left, Top, Right, Bottom : Integer) : TRect;
 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 UnionRect(out aRect: TRect; const R1,R2: TRect) : Boolean;
 function IsRectEmpty(const aRect: TRect) : Boolean;
 function OffsetRect(var aRect: TRect; DX, DY: Integer) : Boolean;
+function OffsetRect(var aRect: TRectF; DX, DY: single) : Boolean;
 function CenterPoint(const aRect: TRect): TPoint;
 function InflateRect(var aRect: TRect; dx, dy: Integer): Boolean;
 function Size(AWidth, AHeight: Integer): TSize;
 function Size(const aRect: TRect): TSize;
+function RectCenter(var R: TRect; const Bounds: TRect): TRect;
+function RectCenter(var R: TRectF; const Bounds: TRectF): TRectF;
 
 implementation
 
+uses math;
+
+function RectCenter(var R: TRect; const Bounds: TRect): TRect;
+
+var
+  C : TPoint;
+  CS : TPoint;
+
+begin
+  C:=Bounds.CenterPoint;
+  CS:=R.CenterPoint;
+  OffsetRect(R,C.X-CS.X,C.Y-CS.Y);
+  Result:=R;
+end;
+
+function RectCenter(var R: TRectF; const Bounds: TRectF): TRectF;
+
+Var
+  C,CS : TPointF;
+
+begin
+  C:=Bounds.CenterPoint;
+  CS:=R.CenterPoint;
+  OffsetRect(R,C.X-CS.X,C.Y-CS.Y);
+  Result:=R;
+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);
@@ -94,6 +404,12 @@ begin
   Result.y:=y;
 end;
 
+function PointF(x, y: single): TPointF;
+begin
+  Result.X:=X;
+  Result.Y:=Y;
+end;
+
 function PtInRect(const aRect: TRect; const p: TPoint): Boolean;
 begin
   Result:=(p.y>=aRect.Top) and
@@ -161,6 +477,19 @@ begin
   Result:=(aRect.Right<=aRect.Left) or (aRect.Bottom<=aRect.Top);
 end;
 
+function OffsetRect(var aRect: TRectF; DX, DY: single) : Boolean;
+
+begin
+  with aRect do
+    begin
+    Left:=Left+dx;
+    Top:=Top+dy;
+    Right:=Right+dx;
+    Bottom:=Bottom+dy;
+    end;
+  Result:=true;
+end;
+
 function OffsetRect(var aRect: TRect; DX, DY: Integer): Boolean;
 begin
   with aRect do
@@ -215,5 +544,1209 @@ begin
   Result.cy := aRect.Bottom - aRect.Top;
 end;
 
+{ TPointF}
+
+Function SingleToStr(aValue : Single; aSize,aDecimals : Byte) : String; inline;
+
+var
+  S : String;
+  Len,P : Byte;
+
+begin
+  Str(aValue:aSize:aDecimals,S);
+  Len:=Length(S);
+  P:=1;
+  While (P<=Len) and (S[P]=' ') do
+    Inc(P);
+  if P>1 then
+    Delete(S,1,P-1);
+  Result:=S;
+end;
+
+{ TRect }
+
+{ TRect }
+
+(*
+class operator TRect. * (L, R: TRect): TRect;
+begin
+  Result := TRect.Intersect(L, R);
+end;
+
+class operator TRect. + (L, R: TRect): TRect;
+begin
+  Result := TRect.Union(L, R);
+end;
+
+class operator TRect. <> (L, R: TRect): Boolean;
+begin
+  Result := not(L=R);
+end;
+
+class operator TRect. = (L, R: TRect): Boolean;
+begin
+  Result :=
+    (L.Left = R.Left) and (L.Right = R.Right) and
+    (L.Top = R.Top) and (L.Bottom = R.Bottom);
+end;
+*)
+constructor TRect.Create(ALeft, ATop, ARight, ABottom: Longint);
+begin
+  Left := ALeft;
+  Top := ATop;
+  Right := ARight;
+  Bottom := ABottom;
+end;
+
+constructor TRect.Create(P1, P2: TPoint; Normalize: Boolean);
+begin
+  TopLeft := P1;
+  BottomRight := P2;
+  if Normalize then
+    NormalizeRect;
+end;
+
+constructor TRect.Create(Origin: TPoint);
+begin
+  TopLeft := Origin;
+  BottomRight := Origin;
+end;
+
+constructor TRect.Create(Origin: TPoint; AWidth, AHeight: Longint);
+begin
+  TopLeft := Origin;
+  Width := AWidth;
+  Height := AHeight;
+end;
+
+constructor TRect.Create(R: TRect; Normalize: Boolean);
+begin
+  Self := R;
+  if Normalize then
+    NormalizeRect;
+end;
+
+function TRect.CenterPoint: TPoint;
+begin
+  Result.X := (Right-Left) div 2 + Left;
+  Result.Y := (Bottom-Top) div 2 + Top;
+end;
+
+function TRect.Contains(Pt: TPoint): Boolean;
+begin
+  Result := (Left <= Pt.X) and (Pt.X < Right) and (Top <= Pt.Y) and (Pt.Y < Bottom);
+end;
+
+function TRect.Contains(R: TRect): Boolean;
+begin
+  Result := (Left <= R.Left) and (R.Right <= Right) and (Top <= R.Top) and (R.Bottom <= Bottom);
+end;
+
+class function TRect.Empty: TRect;
+begin
+  Result := TRect.Create(0,0,0,0);
+end;
+
+function TRect.GetBottomRight: TPoint;
+begin
+  Result:=Point(Right,Bottom);
+end;
+
+function TRect.getHeight: Longint;
+begin
+  result:=bottom-top;
+end;
+
+function TRect.getLocation: TPoint;
+begin
+  result.x:=Left; result.y:=top;
+end;
+
+function TRect.getSize: TSize;
+begin
+  result.cx:=width; result.cy:=height;
+end;
+
+function TRect.GetTopLeft: TPoint;
+begin
+  Result:=Point(Left,Top);
+end;
+
+function TRect.getWidth: Longint;
+begin
+  result:=right-left;
+end;
+
+procedure TRect.SetBottomRight(const aValue: TPoint);
+begin
+  Bottom:=aValue.Y;
+  Right:=aValue.X;
+end;
+
+procedure TRect.Inflate(DX, DY: Longint);
+begin
+  InflateRect(Self, DX, DY);
+end;
+
+procedure TRect.Intersect(R: TRect);
+begin
+  Self := Intersect(Self, R);
+end;
+
+class function TRect.Intersect(R1: TRect; R2: TRect): TRect;
+begin
+  IntersectRect(Result, R1, R2);
+end;
+
+function TRect.IntersectsWith(R: TRect): Boolean;
+begin
+  Result := (Left < R.Right) and (R.Left < Right) and (Top < R.Bottom) and (R.Top < Bottom);
+end;
+
+function TRect.IsEmpty: Boolean;
+begin
+  Result := (Right <= Left) or (Bottom <= Top);
+end;
+
+procedure TRect.NormalizeRect;
+var
+  x: LongInt;
+begin
+  if Top>Bottom then
+  begin
+    x := Top;
+    Top := Bottom;
+    Bottom := x;
+  end;
+  if Left>Right then
+  begin
+    x := Left;
+    Left := Right;
+    Right := x;
+  end
+end;
+
+procedure TRect.Inflate(DL, DT, DR, DB: Longint);
+begin
+  Dec(Left, DL);
+  Dec(Top, DT);
+  Inc(Right, DR);
+  Inc(Bottom, DB);
+end;
+
+procedure TRect.Offset(DX, DY: Longint);
+begin
+  OffsetRect(Self, DX, DY);
+end;
+
+procedure TRect.Offset(DP: TPoint);
+begin
+  OffsetRect(Self, DP.X, DP.Y);
+end;
+
+procedure TRect.setHeight(AValue: Longint);
+begin
+  bottom:=top+avalue;
+end;
+
+procedure TRect.SetLocation(X, Y: Longint);
+begin
+  Offset(X-Left, Y-Top);
+end;
+
+procedure TRect.SetLocation(P: TPoint);
+begin
+  SetLocation(P.X, P.Y);
+end;
+
+procedure TRect.setSize(AValue: TSize);
+begin
+  bottom:=top+avalue.cy;
+  right:=left+avalue.cx;
+end;
+
+procedure TRect.SetTopLeft(const aValue: TPoint);
+begin
+  Top:=aValue.y;
+  Left:=aValue.x;
+end;
+
+procedure TRect.setWidth(AValue: Longint);
+begin
+  right:=left+avalue;
+end;
+
+function TRect.SplitRect(SplitType: TSplitRectType; Percent: Double): TRect;
+begin
+  Result := Self;
+  case SplitType of
+    srLeft: Result.Right := Left + Trunc(Percent*Width);
+    srRight: Result.Left := Right - Trunc(Percent*Width);
+    srTop: Result.Bottom := Top + Trunc(Percent*Height);
+    srBottom: Result.Top := Bottom - Trunc(Percent*Height);
+  end;
+end;
+
+function TRect.SplitRect(SplitType: TSplitRectType; ASize: Longint): TRect;
+begin
+  Result := Self;
+  case SplitType of
+    srLeft: Result.Right := Left + ASize;
+    srRight: Result.Left := Right - ASize;
+    srTop: Result.Bottom := Top + ASize;
+    srBottom: Result.Top := Bottom - ASize;
+  end;
+end;
+
+class function TRect.Union(const Points: array of TPoint): TRect;
+var
+  i: Integer;
+begin
+  if Length(Points) > 0 then
+  begin
+    Result.TopLeft := Points[Low(Points)];
+    Result.BottomRight := Points[Low(Points)];
+
+    for i := Low(Points)+1 to High(Points) do
+    begin
+      if Points[i].X < Result.Left then Result.Left := Points[i].X;
+      if Points[i].X > Result.Right then Result.Right := Points[i].X;
+      if Points[i].Y < Result.Top then Result.Top := Points[i].Y;
+      if Points[i].Y > Result.Bottom then Result.Bottom := Points[i].Y;
+    end;
+  end else
+    Result := Empty;
+end;
+
+procedure TRect.Union(R: TRect);
+begin
+  Self := Union(Self, R);
+end;
+
+class function TRect.Union(R1, R2: TRect): TRect;
+begin
+  UnionRect(Result, R1, R2);
+end;
+
+{ TPointF}
+
+function TPointF.ToString : RTLString;
+
+begin
+  Result:=ToString(8,2);
+end;
+
+function TPointF.ToString(aSize,aDecimals : Byte) : RTLString;
+
+var
+  Sx,Sy : string;
+
+begin
+  Sx:=SingleToStr(X,aSize,aDecimals);
+  Sy:=SingleToStr(Y,aSize,aDecimals);
+  Result:='('+Sx+','+Sy+')';
+end;
+
+function TPointF.Add(const apt: TPoint): TPointF;
+begin
+  result.x:=x+apt.x;
+  result.y:=y+apt.y;
+end;
+
+function TPointF.Add(const apt: TPointF): TPointF;
+begin
+  result.x:=x+apt.x;
+  result.y:=y+apt.y;
+end;
+
+function TPointF.Subtract(const apt : TPointF): TPointF;
+begin
+  result.x:=x-apt.x;
+  result.y:=y-apt.y;
+end;
+
+function TPointF.Subtract(const apt: TPoint): TPointF;
+begin
+  result.x:=x-apt.x;
+  result.y:=y-apt.y;
+end;
+
+function TPointF.Distance(const apt : TPointF) : Single;
+begin
+  result:=sqrt(sqr(apt.x-x)+sqr(apt.y-y));
+end;
+
+function TPointF.DotProduct(const apt: TPointF): Single;
+begin
+  result:=x*apt.x+y*apt.y;
+end;
+
+function TPointF.IsZero : Boolean;
+begin
+  result:=SameValue(x,0.0) and SameValue(y,0.0);
+end;
+
+procedure TPointF.Offset(const apt :TPointF);
+begin
+  x:=x+apt.x;
+  y:=y+apt.y;
+end;
+
+procedure TPointF.Offset(const apt: TPoint);
+begin
+  x:=x+apt.x;
+  y:=y+apt.y;
+end;
+
+procedure TPointF.Offset(dx,dy : Single);
+begin
+  x:=x+dx;
+  y:=y+dy;
+end;
+
+function TPointF.EqualsTo(const apt: TPointF): Boolean;
+
+begin
+  Result:=EqualsTo(apt,0);
+end;
+
+function TPointF.EqualsTo(const apt: TPointF; const aEpsilon: Single): Boolean;
+
+  function Eq(a,b : single) : boolean; inline;
+
+  begin
+    result:=abs(a-b)<=aEpsilon;
+  end;
+
+begin
+  Result:=Eq(X,apt.X) and Eq(Y,apt.Y);
+end;
+
+function TPointF.Scale(afactor: Single): TPointF;
+begin
+  result.x:=afactor*x;
+  result.y:=afactor*y;
+end;
+
+function TPointF.Ceiling: TPoint;
+begin
+  result.x:=ceil(x);
+  result.y:=ceil(y);
+end;
+
+function TPointF.Truncate: TPoint;
+begin
+  result.x:=trunc(x);
+  result.y:=trunc(y);
+end;
+
+function TPointF.Floor: TPoint;
+begin
+  result.x:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Math.floor(x);
+  result.y:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Math.floor(y);
+end;
+
+function TPointF.Round: TPoint;
+begin
+  result.x:=System.round(x);
+  result.y:=System.round(y);
+end;
+
+function TPointF.Length: Single;
+begin
+  result:=sqrt(sqr(x)+sqr(y));
+end;
+
+function TPointF.Rotate(angle: single): TPointF;
+var
+  sina, cosa: single;
+begin
+  sincos(angle, sina, cosa);
+  result.x := x * cosa - y * sina;
+  result.y := x * sina + y * cosa;
+end;
+
+function TPointF.Reflect(const normal: TPointF): TPointF;
+begin
+  //result := self + (-2 * normal ** self) * normal;
+end;
+
+function TPointF.MidPoint(const b: TPointF): TPointF;
+begin
+  result.x := 0.5 * (x + b.x);
+  result.y := 0.5 * (y + b.y);
+end;
+
+class function TPointF.Zero: TPointF;
+
+begin
+  Result.X:=0;
+  Result.Y:=0;
+end;
+
+class function TPointF.PointInCircle(const pt, center: TPointF; radius: single): Boolean;
+begin
+  result := sqr(center.x - pt.x) + sqr(center.y - pt.y) < sqr(radius);
+end;
+
+class function TPointF.PointInCircle(const pt, center: TPointF; radius: integer): Boolean;
+begin
+  result := sqr(center.x - pt.x) + sqr(center.y - pt.y) < sqr(single(radius));
+end;
+
+function TPointF.Angle(const b: TPointF): Single;
+begin
+  result := ArcTan2(y - b.y, x - b.x);
+end;
+
+function TPointF.AngleCosine(const b: TPointF): single;
+begin
+//  result := EnsureRange((self ** b) / sqrt((sqr(x) + sqr(y)) * (sqr(b.x) + sqr(b.y))), -1, 1);
+end;
+
+(*
+class operator TPointF.= (const apt1, apt2 : TPointF) : Boolean; static;
+begin
+  result:=SameValue(apt1.x,apt2.x) and SameValue(apt1.y,apt2.y);
+end;
+
+class operator TPointF.<> (const apt1, apt2 : TPointF): Boolean;
+begin
+  result:=NOT (SameValue(apt1.x,apt2.x) and Samevalue(apt1.y,apt2.y));
+end;
+
+class operator TPointF. * (const apt1, apt2: TPointF): TPointF;
+begin
+  result.x:=apt1.x*apt2.x;
+  result.y:=apt1.y*apt2.y;
+end;
+
+class operator TPointF. * (afactor: single; const apt1: TPointF): TPointF;
+begin
+  result:=apt1.Scale(afactor);
+end;
+
+class operator TPointF. * (const apt1: TPointF; afactor: single): TPointF;
+begin
+  result:=apt1.Scale(afactor);
+end;
+
+class operator TPointF. ** (const apt1, apt2: TPointF): Single;
+begin
+  result:=apt1.x*apt2.x + apt1.y*apt2.y;
+end;
+
+class operator TPointF.+ (const apt1, apt2 : TPointF): TPointF;
+begin
+  result.x:=apt1.x+apt2.x;
+  result.y:=apt1.y+apt2.y;
+end;
+
+class operator TPointF.- (const apt1, apt2 : TPointF): TPointF;
+begin
+  result.x:=apt1.x-apt2.x;
+  result.y:=apt1.y-apt2.y;
+end;
+
+class operator TPointF. - (const apt1: TPointF): TPointF;
+begin
+  Result.x:=-apt1.x;
+  Result.y:=-apt1.y;
+end;
+
+class operator TPointF. / (const apt1: TPointF; afactor: single): TPointF;
+begin
+  result:=apt1.Scale(1/afactor);
+end;
+
+class operator TPointF. := (const apt: TPoint): TPointF;
+begin
+  Result.x:=apt.x;
+  Result.y:=apt.y;
+end;
+*)
+procedure TPointF.SetLocation(const apt :TPointF);
+begin
+ x:=apt.x; y:=apt.y;
+end;
+
+procedure TPointF.SetLocation(const apt: TPoint);
+begin
+  x:=apt.x; y:=apt.y;
+end;
+
+procedure TPointF.SetLocation(ax,ay : Single);
+begin
+  x:=ax; y:=ay;
+end;
+
+class function TPointF.Create(const ax, ay: Single): TPointF;
+begin
+  Result.x := ax;
+  Result.y := ay;
+end;
+
+class function TPointF.Create(const apt: TPoint): TPointF;
+begin
+  Result.x := apt.X;
+  Result.y := apt.Y;
+end;
+
+
+function TPointF.CrossProduct(const apt: TPointF): Single;
+begin
+  Result:=X*apt.Y-Y*apt.X;
+end;
+
+function TPointF.Normalize: TPointF;
+
+var
+  L: Single;
+
+begin
+  L:=Sqrt(Sqr(X)+Sqr(Y));
+  if SameValue(L,0,Epsilon) then
+    Result:=Self
+  else
+    begin
+    Result.X:=X/L;
+    Result.Y:=Y/L;
+    end;
+end;
+
+
+{ TSizeF }
+
+function TSizeF.ToString(aSize,aDecimals : Byte) : RTLString;
+
+var
+  Sx,Sy : string;
+
+begin
+  Sx:=SingleToStr(cx,aSize,aDecimals);
+  Sy:=SingleToStr(cy,aSize,aDecimals);
+  Result:='('+Sx+'x'+Sy+')';
+end;
+
+function TSizeF.ToString : RTLString;
+
+begin
+  Result:=ToString(8,2);
+end;
+
+
+
+function TSizeF.Add(const asz: TSize): TSizeF;
+begin
+  result.cx:=cx+asz.cx;
+  result.cy:=cy+asz.cy;
+end;
+
+function TSizeF.Add(const asz: TSizeF): TSizeF;
+begin
+  result.cx:=cx+asz.cx;
+  result.cy:=cy+asz.cy;
+end;
+
+function TSizeF.Subtract(const asz : TSizeF): TSizeF;
+begin
+  result.cx:=cx-asz.cx;
+  result.cy:=cy-asz.cy;
+end;
+
+function TSizeF.SwapDimensions:TSizeF;
+begin
+  result.cx:=cy;
+  result.cy:=cx;
+end;
+
+function TSizeF.Subtract(const asz: TSize): TSizeF;
+begin
+  result.cx:=cx-asz.cx;
+  result.cy:=cy-asz.cy;
+end;
+
+function TSizeF.Distance(const asz : TSizeF) : Single;
+begin
+  result:=sqrt(sqr(asz.cx-cx)+sqr(asz.cy-cy));
+end;
+
+function TSizeF.IsZero : Boolean;
+begin
+  result:=SameValue(cx,0.0) and SameValue(cy,0.0);
+end;
+
+function TSizeF.Scale(afactor: Single): TSizeF;
+begin
+  result.cx:=afactor*cx;
+  result.cy:=afactor*cy;
+end;
+
+function TSizeF.Ceiling: TSize;
+begin
+  result.cx:=ceil(cx);
+  result.cy:=ceil(cy);
+end;
+
+function TSizeF.Truncate: TSize;
+begin
+  result.cx:=trunc(cx);
+  result.cy:=trunc(cy);
+end;
+
+function TSizeF.Floor: TSize;
+begin
+  result.cx:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Math.floor(cx);
+  result.cy:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Math.floor(cy);
+end;
+
+function TSizeF.Round: TSize;
+begin
+  result.cx:=System.round(cx);
+  result.cy:=System.round(cy);
+end;
+
+function TSizeF.Length: Single;
+begin     //distance(self) ?
+  result:=sqrt(sqr(cx)+sqr(cy));
+end;
+
+(*
+class operator TSizeF.= (const asz1, asz2 : TSizeF) : Boolean;
+begin
+  result:=SameValue(asz1.cx,asz2.cx) and SameValue(asz1.cy,asz2.cy);
+end;
+
+class operator TSizeF.<> (const asz1, asz2 : TSizeF): Boolean;
+begin
+  result:=NOT (SameValue(asz1.cx,asz2.cx) and Samevalue(asz1.cy,asz2.cy));
+end;
+
+class operator TSizeF. * (afactor: single; const asz1: TSizeF): TSizeF;
+begin
+  result:=asz1.Scale(afactor);
+end;
+
+class operator TSizeF. * (const asz1: TSizeF; afactor: single): TSizeF;
+begin
+  result:=asz1.Scale(afactor);
+end;
+
+class operator TSizeF.+ (const asz1, asz2 : TSizeF): TSizeF;
+begin
+  result.cx:=asz1.cx+asz2.cx;
+  result.cy:=asz1.cy+asz2.cy;
+end;
+
+class operator TSizeF.- (const asz1, asz2 : TSizeF): TSizeF;
+begin
+  result.cx:=asz1.cx-asz2.cx;
+  result.cy:=asz1.cy-asz2.cy;
+end;
+
+class operator TSizeF. - (const asz1: TSizeF): TSizeF;
+begin
+  Result.cx:=-asz1.cx;
+  Result.cy:=-asz1.cy;
+end;
+
+class operator TSizeF. := (const apt: TPointF): TSizeF;
+begin
+  Result.cx:=apt.x;
+  Result.cy:=apt.y;
+end;
+
+class operator TSizeF. := (const asz: TSize): TSizeF;
+begin
+  Result.cx := asz.cx;
+  Result.cy := asz.cy;
+end;
+
+class operator TSizeF. := (const asz: TSizeF): TPointF;
+begin
+  Result.x := asz.cx;
+  Result.y := asz.cy;
+end;
+*)
+class function TSizeF.Create(const ax, ay: Single): TSizeF;
+begin
+  Result.cx := ax;
+  Result.cy := ay;
+end;
+
+class function TSizeF.Create(const asz: TSize): TSizeF;
+begin
+  Result.cx := asz.cX;
+  Result.cy := asz.cY;
+end;
+
+{ TRectF }
+
+function TRectF.ToString(aSize,aDecimals : Byte; aUseSize : Boolean = False) : RTLString;
+
+var
+  S : RTLString;
+
+begin
+  if aUseSize then
+    S:=Size.ToString(aSize,aDecimals)
+  else
+    S:=BottomRight.ToString(aSize,aDecimals);
+  Result:='['+TopLeft.ToString(aSize,aDecimals)+' - '+S+']';
+end;
+
+function TRectF.ToString(aUseSize: Boolean = False) : RTLString;
+
+begin
+  Result:=ToString(8,2,aUseSize);
+end;
+
+(*
+class operator TRectF. * (L, R: TRectF): TRectF;
+begin
+  Result := TRectF.Intersect(L, R);
+end;
+
+class operator TRectF. + (L, R: TRectF): TRectF;
+begin
+  Result := TRectF.Union(L, R);
+end;
+
+class operator TRectF. := (const arc: TRect): TRectF;
+begin
+  Result.Left:=arc.Left;
+  Result.Top:=arc.Top;
+  Result.Right:=arc.Right;
+  Result.Bottom:=arc.Bottom;
+end;
+
+class operator TRectF. <> (L, R: TRectF): Boolean;
+begin
+  Result := not(L=R);
+end;
+
+class operator TRectF. = (L, R: TRectF): Boolean;
+begin
+  Result :=
+    SameValue(L.Left,R.Left) and SameValue(L.Right,R.Right) and
+    SameValue(L.Top,R.Top) and SameValue(L.Bottom,R.Bottom);
+end;
+*)
+constructor TRectF.Create(ALeft, ATop, ARight, ABottom: Single);
+begin
+  Left := ALeft;
+  Top := ATop;
+  Right := ARight;
+  Bottom := ABottom;
+end;
+
+constructor TRectF.Create(P1, P2: TPointF; Normalize: Boolean);
+begin
+  TopLeft := P1;
+  BottomRight := P2;
+  if Normalize then
+    NormalizeRect;
+end;
+
+constructor TRectF.Create(Origin: TPointF);
+begin
+  TopLeft := Origin;
+  BottomRight := Origin;
+end;
+
+constructor TRectF.Create(Origin: TPointF; AWidth, AHeight: Single);
+begin
+  TopLeft := Origin;
+  Width := AWidth;
+  Height := AHeight;
+end;
+
+constructor TRectF.Create(R: TRectF; Normalize: Boolean);
+begin
+  Self := R;
+  if Normalize then
+    NormalizeRect;
+end;
+
+constructor TRectF.Create(R: TRect; Normalize: Boolean);
+begin
+  Self.Left := R.Left;
+  Self.Top := R.Top;
+  Self.Right := R.Right;
+  Self.Bottom := R.Bottom;
+  if Normalize then
+    NormalizeRect;
+end;
+
+function TRectF.CenterPoint: TPointF;
+begin
+  Result.X := (Right-Left) / 2 + Left;
+  Result.Y := (Bottom-Top) / 2 + Top;
+end;
+
+function TRectF.Ceiling: TRectF;
+begin
+  Result.BottomRight:=TPointF.Create(BottomRight.Ceiling.X,BottomRight.Ceiling.Y);
+  Result.TopLeft:=TPointF.Create(TopLeft.Ceiling.X,TopLeft.Ceiling.Y);
+end;
+
+function TRectF.CenterAt(const Dest: TRectF): TRectF;
+begin
+  Result:=Self;
+  RectCenter(Result,Dest);
+end;
+
+function TRectF.Fit(const Dest: TRectF): Single;
+
+var
+  R : TRectF;
+
+begin
+  R:=FitInto(Dest,Result);
+  Self:=R;
+end;
+
+function TRectF.FitInto(const Dest: TRectF; out Ratio: Single): TRectF;
+begin
+  if (Dest.Width<=0) or (Dest.Height<=0) then
+  begin
+    Ratio:=1.0;
+    exit(Self);
+  end;
+  Ratio:=Max(Self.Width / Dest.Width, Self.Height / Dest.Height);
+  if Ratio=0 then
+    exit(Self);
+  Result.Width:=Self.Width / Ratio;
+  Result.Height:=Self.Height / Ratio;
+  Result.Left:=Self.Left + (Self.Width - Result.Width) / 2;
+  Result.Top:=Self.Top + (Self.Height - Result.Height) / 2;
+end;
+
+function TRectF.FitInto(const Dest: TRectF): TRectF;
+var
+  Ratio: Single;
+begin
+  Result:=FitInto(Dest,Ratio);
+end;
+
+function TRectF.PlaceInto(const Dest: TRectF; const AHorzAlign: THorzRectAlign = THorzRectAlign.Center;  const AVertAlign: TVertRectAlign = TVertRectAlign.Center): TRectF;
+
+var
+  R : TRectF;
+  X,Y : Single;
+  D : TRectF absolute dest;
+
+begin
+  if (Height>Dest.Height) or (Width>Dest.Width) then
+    R:=FitInto(Dest)
+  else
+    R:=Self;
+  case AHorzAlign of
+     THorzRectAlign.Left:
+       X:=D.Left;
+     THorzRectAlign.Center:
+       X:=(D.Left+D.Right-R.Width)/2;
+     THorzRectAlign.Right:
+       X:=D.Right-R.Width;
+  end;
+  case AVertAlign of
+    TVertRectAlign.Top:
+      Y:=D.Top;
+    TVertRectAlign.Center:
+      Y:=(D.Top+D.Bottom-R.Height)/2;
+    TVertRectAlign.Bottom:
+      Y:=D.Bottom-R.Height;
+  end;
+  R.SetLocation(PointF(X,Y));
+  Result:=R;
+end;
+
+function TRectF.SnapToPixel(AScale: Single; APlaceBetweenPixels: Boolean): TRectF;
+
+  function sc (S : single) : single; inline;
+
+  begin
+    Result:=System.Trunc(S*AScale)/AScale;
+  end;
+
+var
+  R : TRectF;
+  Off: Single;
+
+begin
+  if AScale<=0 then
+    AScale := 1;
+  R.Top:=Sc(Top);
+  R.Left:=Sc(Left);
+  R.Width:=Sc(Width);
+  R.Height:=Sc(Height);
+  if APlaceBetweenPixels then
+    begin
+    Off:=1/(2*aScale);
+    R.Offset(Off,Off);
+    end;
+  Result:=R;
+end;
+
+
+function TRectF.Contains(Pt: TPointF): Boolean;
+begin
+  Result := (Left <= Pt.X) and (Pt.X < Right) and (Top <= Pt.Y) and (Pt.Y < Bottom);
+end;
+
+function TRectF.Contains(R: TRectF): Boolean;
+begin
+  Result := (Left <= R.Left) and (R.Right <= Right) and (Top <= R.Top) and (R.Bottom <= Bottom);
+end;
+
+class function TRectF.Empty: TRectF;
+begin
+  Result := TRectF.Create(0,0,0,0);
+end;
+
+function TRectF.EqualsTo(const R: TRectF; const Epsilon: Single): Boolean;
+begin
+  Result:=TopLeft.EqualsTo(R.TopLeft,Epsilon);
+  Result:=Result and BottomRight.EqualsTo(R.BottomRight,Epsilon);
+end;
+
+function TRectF.GetHeight: Single;
+begin
+  result:=bottom-top;
+end;
+
+function TRectF.GetBottomRight: TPointF;
+begin
+  Result:=TPointF.Create(Right,Bottom);
+end;
+
+function TRectF.GetLocation: TPointF;
+begin
+  result.x:=Left; result.y:=top;
+end;
+
+function TRectF.GetSize: TSizeF;
+begin
+  result.cx:=width; result.cy:=height;
+end;
+
+function TRectF.GetTopLeft: TPointF;
+begin
+  Result:=TPointF.Create(Left,Top);
+end;
+
+procedure TRectF.SetBottomRight(const aValue: TPointF);
+begin
+  Right:=aValue.X;
+  Bottom:=aValue.y;
+end;
+
+function TRectF.GetWidth: Single;
+begin
+  result:=right-left;
+end;
+
+procedure TRectF.Inflate(DX, DY: Single);
+begin
+  Left:=Left-dx;
+  Top:=Top-dy;
+  Right:=Right+dx;
+  Bottom:=Bottom+dy;
+end;
+
+procedure TRectF.Intersect(R: TRectF);
+begin
+  Self := Intersect(Self, R);
+end;
+
+class function TRectF.Intersect(R1: TRectF; R2: TRectF): TRectF;
+begin
+  Result := R1;
+  if R2.Left > R1.Left then
+    Result.Left := R2.Left;
+  if R2.Top > R1.Top then
+    Result.Top := R2.Top;
+  if R2.Right < R1.Right then
+    Result.Right := R2.Right;
+  if R2.Bottom < R1.Bottom then
+    Result.Bottom := R2.Bottom;
+end;
+
+function TRectF.IntersectsWith(R: TRectF): Boolean;
+begin
+  Result := (Left < R.Right) and (R.Left < Right) and (Top < R.Bottom) and (R.Top < Bottom);
+end;
+
+function TRectF.IsEmpty: Boolean;
+begin
+  Result := (CompareValue(Right,Left)<=0) or (CompareValue(Bottom,Top)<=0);
+end;
+
+procedure TRectF.NormalizeRect;
+var
+  x: Single;
+begin
+  if Top>Bottom then
+  begin
+    x := Top;
+    Top := Bottom;
+    Bottom := x;
+  end;
+  if Left>Right then
+  begin
+    x := Left;
+    Left := Right;
+    Right := x;
+  end
+end;
+
+procedure TRectF.Inflate(DL, DT, DR, DB: Single);
+begin
+  Left:=Left-dl;
+  Top:=Top-dt;
+  Right:=Right+dr;
+  Bottom:=Bottom+db;
+end;
+
+procedure TRectF.Offset(const dx, dy: Single);
+begin
+  left:=left+dx; right:=right+dx;
+  bottom:=bottom+dy; top:=top+dy;
+end;
+
+procedure TRectF.Offset(DP: TPointF);
+begin
+  left:=left+DP.x; right:=right+DP.x;
+  bottom:=bottom+DP.y; top:=top+DP.y;
+end;
+
+function TRectF.Truncate: TRect;
+begin
+  Result.BottomRight:=BottomRight.Truncate;
+  Result.TopLeft:=TopLeft.Truncate;
+end;
+
+function TRectF.Round: TRect;
+begin
+  Result.BottomRight:=BottomRight.Round;
+  Result.TopLeft:=TopLeft.Round;
+end;
+
+procedure TRectF.SetHeight(AValue: Single);
+begin
+  bottom:=top+avalue;
+end;
+
+procedure TRectF.SetTopLeft(const aValue: TPointF);
+begin
+  Left:=aValue.X;
+  Top:=aValue.Y;
+end;
+
+(*
+procedure TRectF.SetLocation(const X, Y: Single);
+begin
+  Offset(X-Left, Y-Top);
+end;
+*)
+
+procedure TRectF.SetLocation(P: TPointF);
+begin
+  Offset(P.X-Left,P.Y-Top);
+end;
+
+procedure TRectF.SetSize(AValue: TSizeF);
+begin
+  bottom:=top+avalue.cy;
+  right:=left+avalue.cx;
+end;
+
+procedure TRectF.SetWidth(AValue: Single);
+begin
+  right:=left+avalue;
+end;
+
+class function TRectF.Union(const Points: array of TPointF): TRectF;
+var
+  i: Integer;
+begin
+  if Length(Points) > 0 then
+  begin
+    Result.TopLeft := Points[Low(Points)];
+    Result.BottomRight := Points[Low(Points)];
+
+    for i := Low(Points)+1 to High(Points) do
+    begin
+      if Points[i].X < Result.Left then Result.Left := Points[i].X;
+      if Points[i].X > Result.Right then Result.Right := Points[i].X;
+      if Points[i].Y < Result.Top then Result.Top := Points[i].Y;
+      if Points[i].Y > Result.Bottom then Result.Bottom := Points[i].Y;
+    end;
+  end else
+    Result := Empty;
+end;
+
+procedure TRectF.Union(const r: TRectF);
+begin
+  left:=min(r.left,left);
+  top:=min(r.top,top);
+  right:=max(r.right,right);
+  bottom:=max(r.bottom,bottom);
+end;
+
+class function TRectF.Union(R1, R2: TRectF): TRectF;
+begin
+  Result:=R1;
+  Result.Union(R2);
+end;
+
+{ TPoint3D }
+
+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);
+  Sz:=SingleToStr(Z,aSize,aDecimals);
+  Result:='('+Sx+','+Sy+','+Sz+')';
+end;
+
+function TPoint3D.ToString : RTLString;
+
+begin
+  Result:=ToString(8,2);
+end;
+
+function TPoint3D.GetSingle3Array: TSingle3Array;
+begin
+  Result:=[x,y,z]
+end;
+
+procedure TPoint3D.SetSingle3Array(const aValue: TSingle3Array);
+begin
+  x:=aValue[0];
+  y:=aValue[1];
+  z:=aValue[2];
+end;
+
+constructor TPoint3D.Create(const ax,ay,az:single);
+begin
+  x:=ax; y:=ay; z:=az;
+end;
+
+procedure   TPoint3D.Offset(const adeltax,adeltay,adeltaz:single);
+begin
+  x:=x+adeltax; y:=y+adeltay; z:=z+adeltaz;
+end;
+
+procedure   TPoint3D.Offset(const adelta:TPoint3D);
+begin
+  x:=x+adelta.x; y:=y+adelta.y; z:=z+adelta.z;
+end;
+
 end.