Ignore:
Timestamp:
Nov 23, 2017, 5:02:49 PM (7 years ago)
Author:
chronos
Message:
  • Modified: UGeometry unit rewritten to use generics and define own TPoint and TRect types.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Packages/Common/UGeometry.pas

    r169 r170  
    99
    1010type
    11   TPointArray = array of TPoint;
    12 
    13   { TLine }
    14 
    15   TLine = record
     11  { TGPoint }
     12
     13  TGPoint<T> = record
     14  public
     15    X: T;
     16    Y: T;
     17    constructor Create(const X, Y: T);
     18    procedure Rotate(Base: TGPoint<T>; Angle: Double);
     19    class operator Add(const A, B: TGPoint<T>): TGPoint<T>;
     20    class operator Subtract(const A, B: TGPoint<T>): TGPoint<T>;
     21    class operator GreaterThan(const A, B: TGPoint<T>): Boolean;
     22    class operator LessThan(const A, B: TGPoint<T>): Boolean;
     23    class operator Equal(const A, B: TGPoint<T>): Boolean;
     24    function Min(const A, B: TGPoint<T>): TGPoint<T>;
     25    function Max(const A, B: TGPoint<T>): TGPoint<T>;
     26  end;
     27
     28  { TGPoint3D }
     29
     30  TGPoint3D<T> = record
     31  public
     32    X: T;
     33    Y: T;
     34    Z: T;
     35    constructor Create(const X, Y, Z: T);
     36  end;
     37
     38  { TGRect }
     39
     40  TGRect<T> = record
     41  private
     42    function GetEmpty: Boolean;
     43    function GetSize: T;
     44    procedure SetSize(AValue: T);
     45  public
     46    P1: T;
     47    P2: T;
     48    function IsPointInside(const P: T): Boolean;
     49    function Center: T;
     50    procedure SetEmpty;
     51    class operator Equal(const A, B: TGRect<T>): Boolean;
     52    constructor Create(const P1, P2: T);
     53    constructor CreateBounds(const Origin, Size: T);
     54    property Size: T read GetSize write SetSize;
     55    property Empty: Boolean read GetEmpty;
     56  end;
     57
     58  { TGLine }
     59
     60  TGLine<T> = record
    1661  private
    1762    function GetDistance: Double;
    1863    procedure SetDistance(AValue: Double);
    1964  public
    20     P1: TPoint;
    21     P2: TPoint;
    22     function Create(const P1, P2: TPoint): TLine;
    23     function GetMiddle: TPoint;
     65    P1: T;
     66    P2: T;
     67    constructor Create(const P1, P2: T);
     68    function GetMiddle: T;
    2469    function GetAngle: Double;
    25     function GetSize: TPoint;
    26     function ToRect: TRect;
     70    function GetSize: T;
     71    function ToRect: TGRect<T>;
    2772    function DotProduct: Double;
     73    class function LineIntersect(const LineA, LineB: TGLine<T>; out Intersection: T): Boolean; static;
    2874    procedure Rotate(const Angle: Double);
    29     class operator Equal(const A, B: TLine): Boolean;
     75    class operator Equal(const A, B: TGLine<T>): Boolean;
    3076    property Distance: Double read GetDistance write SetDistance;
    3177  end;
    3278
    33   { TPolygon }
    34 
    35   TPolygon = record
     79  { TGPolygon }
     80
     81  TGPolygon<T> = record
    3682  private
    37     function GetPoint(const Index: Integer): TPoint; inline;
    38     procedure SetPoint(const Index: Integer; const AValue: TPoint); inline;
     83    function GetPoint(const Index: Integer): T; inline;
     84    procedure SetPoint(const Index: Integer; const AValue: T); inline;
    3985  public
     86    type
     87      TPointArray = array of T;
     88    var
    4089    Points: TPointArray;
    41     function IsPointInside(const P: TPoint): Boolean;
    42     function Create(const Points: TPointArray): TPolygon; overload;
    43     function Create(const Rect: TRect): TPolygon; overload;
    44     function GetRect: TRect;
    45     procedure AddPoint(const P: TPoint);
     90    function IsPointInside(const P: T): Boolean;
     91    constructor Create(const Points: TPointArray); overload;
     92    constructor Create(const Rect: TGRect<T>); overload;
     93    function GetRect: TGRect<T>;
     94    procedure AddPoint(const P: T);
    4695    procedure Clear;
    47     procedure CutLine(const Vector: TLine; const PointInside: TPoint);
    48     property Items[Index: Integer]: TPoint read GetPoint write SetPoint; default;
    49   end;
    50 
    51 function Distance(const P1, P2: TPoint): Integer;
    52 function Dot(const P1, P2: TPoint): Double;
    53 function AddPoint(const P1, P2: TPoint): TPoint;
    54 function SubPoint(const P1, P2: TPoint): TPoint;
    55 function PointToLineDistance(const P, V, W: TPoint): Integer;
    56 function ComparePoint(const P1, P2: TPoint): Boolean;
    57 function RotatePoint(const Center, P: TPoint; Angle: Double): TPoint;
    58 function RotatePoints(const Center: TPoint; P: TPointArray; Angle: Double): TPointArray;
    59 function LineIntersect(const LineA, LineB: TLine; out Intersection: TPoint): Boolean;
    60 function ArcTan2Point(const Point: TPoint): Float;
    61 function ArcTanPoint(const Point: TPoint): Float;
    62 function RectEquals(const A, B: TRect): Boolean;
    63 function RectEnlarge(const Rect: TRect; Value: Integer): TRect;
    64 function ShiftRect(const ARect: TRect; Delta: TPoint): TRect;
    65 function PointsToRect(const P1, P2: TPoint): TRect;
    66 function PointInRect(const P: TPoint; aRect: TRect): Boolean;
    67 function HalfDistancePoint(const P1, P2: TPoint): TPoint;
    68 function NormalizeAngle(const Angle: Double): Double;
    69 function SubAngle(A1, A2: Double): Double;
     96    procedure CutLine(const Vector: TGLine<T>; const PointInside: T);
     97    property Items[Index: Integer]: T read GetPoint write SetPoint; default;
     98  end;
     99
     100  // Integer
     101  TPoint = TGPoint<Integer>;
     102  TPoint3D = TGPoint3D<Integer>;
     103  TLine = TGLine<TPoint>;
     104  TRect = TGRect<TPoint>;
     105  TPolygon = TGPolygon<TPoint>;
     106
     107  // FLoating
     108  TPointF = TGPoint<Single>;
     109  TPoint3DF = TGPoint3D<Single>;
     110  TRectF = TGRect<TPointF>;
     111  TLineF = TGLine<TPointF>;
     112  TPolygonF = TGPolygon<TPointF>;
     113
     114function Divide(Divident, Divisor: Integer): Integer; overload;
     115function Divide(Divident, Divisor: Double): Double; overload;
     116function TypedRound(Value: Double): Integer; overload;
     117function TypedRound(Value: Double): Double; overload;
     118function StdPointToPoint(Value: Classes.TPoint): TPoint;
     119function PointToStdPoint(Value: TPoint): Classes.TPoint;
    70120
    71121
    72122implementation
    73123
    74 function Distance(const P1, P2: TPoint): Integer;
    75 begin
    76   Result := Trunc(Sqrt(Sqr(P2.X - P1.X) + Sqr(P2.Y - P1.Y)));
    77 end;
    78 
    79 function Dot(const P1, P2: TPoint): Double;
    80 begin
    81   Result := P1.X * P2.X + P1.Y * P2.Y;
    82 end;
    83 
    84 function AddPoint(const P1, P2: TPoint): TPoint;
    85 begin
    86   Result.X := P1.X + P2.X;
    87   Result.Y := P1.Y + P2.Y;
    88 end;
    89 
    90 function SubPoint(const P1, P2: TPoint): TPoint;
    91 begin
    92   Result.X := P1.X - P2.X;
    93   Result.Y := P1.Y - P2.Y;
    94 end;
    95 
    96 function PointToLineDistance(const P, V, W: TPoint): Integer;
    97 var
    98   l2, t: Double;
    99   tt: TPoint;
    100 begin
    101   // Return minimum distance between line segment vw and point p
    102   L2 := Distance(V, W); // i.e. |w-v|^2 -  avoid a sqrt
    103   L2 := Power(l2, 2);
    104   if L2 = 0 then begin
    105     Result := Distance(P, V);   // v == w case
    106     Exit;
    107   end;
    108   // Consider the line extending the segment, parameterized as v + t (w - v).
    109   // We find projection of point p onto the line.
    110   // It falls where t = [(p-v) . (w-v)] / |w-v|^2
    111   T := Dot(SubPoint(P, V), SubPoint(W, V)) / L2;
    112   if T < 0 then begin
    113     Result := Distance(P, V);       // Beyond the 'v' end of the segment
    114     exit;
    115   end
    116   else if T > 1 then begin
    117     Result := Distance(P, W);  // Beyond the 'w' end of the segment
    118     Exit;
    119   end;
    120   TT.X := Trunc(V.X + T * (W.X - V.X));
    121   TT.Y := Trunc(V.Y + T * (W.Y - V.Y));
    122   Result := Distance(P, TT);
    123 end;
    124 
    125 function ComparePoint(const P1, P2: TPoint): Boolean;
    126 begin
    127   Result := (P1.X = P2.X) and (P1.Y = P2.Y);
    128 end;
    129 
    130 function RotatePoint(const Center, P: TPoint; Angle: Double): TPoint;
    131 var
    132   D: TPoint;
    133 begin
    134   D := Point(P.X - Center.X, P.Y - Center.Y);
    135   Result := Point(Center.X + Round(D.X * Cos(Angle) - D.Y * Sin(Angle)),
    136     Center.Y + Round(D.X * Sin(Angle) + D.Y * Cos(Angle)));
    137 end;
    138 
    139 function RotatePoints(const Center: TPoint; P: TPointArray; Angle: Double): TPointArray;
    140 var
    141   I: Integer;
    142 begin
    143   SetLength(Result, Length(P));
    144   for I := 0 to High(P) do
    145     Result[I] := RotatePoint(Center, P[I], Angle);
    146 end;
    147 
    148 function LineIntersect(const LineA, LineB: TLine; out Intersection: TPoint): Boolean;
    149 Var
    150   LDetLineA, LDetLineB, LDetDivInv: Double;
    151   LDiffLA, LDiffLB: TPoint;
    152   D: Integer;
    153 begin
    154   if ComparePoint(LineA.P1, LineA.P2) or ComparePoint(LineB.P1, LineB.P2) then begin
    155     Result := False;
    156     Exit;
    157   end;
    158   LDetLineA := LineA.P1.X * LineA.P2.Y - LineA.P1.Y * LineA.P2.X;
    159   LDetLineB := LineB.P1.X * LineB.P2.Y - LineB.P1.Y * LineB.P2.X;
    160 
    161   LDiffLA := SubPoint(LineA.P1, LineA.P2);
    162   LDiffLB := SubPoint(LineB.P1, LineB.P2);
    163 
    164   D := (LDiffLA.X * LDiffLB.Y) - (LDiffLA.Y * LDiffLB.X);
    165   if D = 0 then begin
    166     // Parallel lines without intersection
    167     Result := False;
    168     Exit;
    169   end;
    170   LDetDivInv := 1 / D;
    171 
    172   Intersection.X := Round(((LDetLineA * LDiffLB.X) - (LDiffLA.X * LDetLineB)) * LDetDivInv);
    173   Intersection.Y := Round(((LDetLineA * LDiffLB.Y) - (LDiffLA.Y * LDetLineB)) * LDetDivInv);
    174   Result := True;
    175 end;
    176 
    177 function ArcTan2Point(const Point: TPoint): Float;
    178 begin
    179   Result := ArcTan2(Point.Y, Point.X);
    180 end;
    181 
    182 function ArcTanPoint(const Point: TPoint): Float;
    183 begin
    184   if Point.Y = 0 then Result := Infinity
    185     else Result := ArcTan(Point.X / Point.Y);
    186 end;
    187 
    188 function RectEquals(const A, B: TRect): Boolean;
    189 begin
    190   Result := (A.Left = B.Left) and (A.Top = B.Top) and
    191     (A.Right = B.Right) and (A.Bottom = B.Bottom);
    192 end;
    193 
    194 function RectEnlarge(const Rect: TRect; Value: Integer): TRect;
    195 begin
    196   Result.Left := Rect.Left - Value;
    197   Result.Right := Rect.Right + Value;
    198   Result.Top := Rect.Top - Value;
    199   Result.Bottom := Rect.Bottom + Value;
    200 end;
    201 
    202 function ShiftRect(const ARect: TRect; Delta: TPoint): TRect;
    203 begin
    204   Result := Rect(ARect.Left + Delta.X, ARect.Top + Delta.Y,
    205     ARect.Right + Delta.X, ARect.Bottom + Delta.Y);
    206 end;
    207 
    208 function PointsToRect(const P1, P2: TPoint): TRect;
    209 begin
    210   if P1.X < P2.X then Result.Left := P1.X else Result.Left := P2.X;
    211   if P1.Y < P2.Y then Result.Top := P1.Y else Result.Top := P2.Y;
    212   if P1.X > P2.X then Result.Right := P1.X else Result.Right := P2.X;
    213   if P1.Y > P2.Y then Result.Bottom := P1.Y else Result.Bottom := P2.Y;
    214 end;
    215 
    216 function PointInRect(const P: TPoint; aRect: TRect): Boolean;
    217 begin
    218   Result := (P.X >= aRect.Left) and (P.X <= aRect.Right) and
    219     (P.Y >= aRect.Top) and (P.Y <= aRect.Bottom);
    220 end;
    221 
    222 function HalfDistancePoint(const P1, P2: TPoint): TPoint;
    223 begin
    224   Result := Point(P1.X + (P2.X - P1.X) div 2, P1.Y + (P2.Y - P1.Y) div 2)
    225 end;
    226 
    227 function NormalizeAngle(const Angle: Double): Double;
    228 begin
    229   if Angle < 0 then Result := Angle + (Trunc(Angle / (2 * Pi)) + 1) * (2 * Pi)
    230   else if Angle > 2 * Pi then Result := Angle - Trunc(Angle / (2 * Pi)) * (2 * Pi)
    231   else Result := Angle;
    232 end;
    233 
    234 function SubAngle(A1, A2: Double): Double;
    235 begin
    236   A1 := NormalizeAngle(A1);
    237   A2 := NormalizeAngle(A2);
    238   if A1 < A2 then Result := A1 + 2 * Pi - A2
    239     else Result := A1 - A2;
     124function Divide(Divident, Divisor: Integer): Integer;
     125begin
     126  Result := Divident div Divisor;
     127end;
     128
     129function Divide(Divident, Divisor: Double): Double;
     130begin
     131  Result := Divident / Divisor;
     132end;
     133
     134function TypedRound(Value: Double): Integer;
     135begin
     136  Result := Round(Value);
     137end;
     138
     139function TypedRound(Value: Double): Double;
     140begin
     141  Result := Value;
     142end;
     143
     144function StdPointToPoint(Value: Classes.TPoint): TPoint;
     145begin
     146  Result.X := Value.X;
     147  Result.Y := Value.Y;
     148end;
     149
     150function PointToStdPoint(Value: TPoint): Classes.TPoint;
     151begin
     152  Result.X := Value.X;
     153  Result.Y := Value.Y;
    240154end;
    241155
    242156{ TPolygon }
    243157
    244 function TPolygon.GetPoint(const Index: Integer): TPoint;
     158function TGPolygon<T>.GetPoint(const Index: Integer): T;
    245159begin
    246160  Result := Points[Index];
    247161end;
    248162
    249 procedure TPolygon.SetPoint(const Index: Integer; const AValue: TPoint);
     163procedure TGPolygon<T>.SetPoint(const Index: Integer; const AValue: T);
    250164begin
    251165  Points[Index] := AValue;
    252166end;
    253167
    254 function TPolygon.IsPointInside(const P: TPoint): Boolean;
     168function TGPolygon<T>.IsPointInside(const P: T): Boolean;
    255169var
    256170  I, J: Integer;
     
    292206
    293207
    294 function TPolygon.Create(const Points: TPointArray): TPolygon;
     208constructor TGPolygon<T>.Create(const Points: TPointArray);
    295209var
    296210  I: Integer;
    297211begin
    298   SetLength(Result.Points, Length(Points));
     212  SetLength(Self.Points, Length(Points));
    299213  for I := 0 to Length(Points) - 1 do
    300     Result.Points[I] := Points[I];
    301 end;
    302 
    303 function TPolygon.Create(const Rect: TRect): TPolygon;
    304 begin
    305   SetLength(Result.Points, 4);
    306   Result.Points[0] := Point(Rect.Left, Rect.Top);
    307   Result.Points[1] := Point(Rect.Right, Rect.Top);
    308   Result.Points[2] := Point(Rect.Right, Rect.Bottom);
    309   Result.Points[3] := Point(Rect.Left, Rect.Bottom);
    310 end;
    311 
    312 function TPolygon.GetRect: TRect;
     214    Self.Points[I] := Points[I];
     215end;
     216
     217constructor TGPolygon<T>.Create(const Rect: TGRect<T>);
     218begin
     219  SetLength(Self.Points, 4);
     220  Self.Points[0] := Rect.P1;
     221  Self.Points[1] := T.Create(Rect.P2.X, Rect.P1.Y);
     222  Self.Points[2] := Rect.P1;
     223  Self.Points[3] := T.Create(Rect.P1.X, Rect.P2.Y);
     224end;
     225
     226function TGPolygon<T>.GetRect: TGRect<T>;
    313227var
    314228  I: Integer;
    315 begin
    316   Result := Rect(High(Integer), High(Integer),
    317     Low(Integer), Low(Integer));
    318   for I := 0 to Length(Points) - 1 do
    319   with Points[I] do begin
    320     if X > Result.Right then
    321       Result.Right := X;
    322     if X < Result.Left then
    323       Result.Left := X;
    324     if Y > Result.Bottom then
    325       Result.Bottom := Y;
    326     if Y < Result.Top then
    327       Result.Top := Y;
    328   end;
    329 end;
    330 
    331 procedure TPolygon.AddPoint(const P: TPoint);
     229  P1: TGPoint<T>;
     230begin
     231  if Length(Points) = 0 then
     232    Result.Empty
     233  else begin
     234    Result := TGRect<T>.Create(Points[0], Points[0]);
     235    for I := 1 to Length(Points) - 1 do
     236    with Points[I] do begin
     237      Result.P1 := Points[I].Min(Result.P1, Points[I]);
     238      Result.P2 := Points[I].Max(Result.P2, Points[I]);
     239    end;
     240  end;
     241end;
     242
     243procedure TGPolygon<T>.AddPoint(const P: T);
    332244begin
    333245  SetLength(Points, Length(Points) + 1);
     
    335247end;
    336248
    337 procedure TPolygon.Clear;
     249procedure TGPolygon<T>.Clear;
    338250begin
    339251  SetLength(Points, 0);
    340252end;
    341253
    342 procedure TPolygon.CutLine(const Vector: TLine; const PointInside: TPoint);
     254procedure TGPolygon<T>.CutLine(const Vector: TGLine<T>; const PointInside: T);
    343255var
    344256  I: Integer;
    345257  PointsChecked: Integer;
    346   L1, L2: TLine;
    347   Intersection: TPoint;
    348   NewPoly: TPolygon;
     258  L1, L2: TGLine<T>;
     259  Intersection: T;
     260  NewPoly: TGPolygon<T>;
    349261  NewPolygonStarted: Boolean;
    350262  Success: Boolean;
     
    359271  if Length(Points) > 0 then
    360272  while True do begin
    361     L2 := TLine.Create(Points[I], Points[(I + 1) mod Length(Points)]);
    362     if LineIntersect(L1, L2, Intersection) then
    363     if PointInRect(Intersection, L2.ToRect) then begin
     273    L2 := TGLine<T>.Create(Points[I], Points[(I + 1) mod Length(Points)]);
     274    if TGLine<T>.LineIntersect(L1, L2, Intersection) then
     275    if L2.ToRect.IsPointInside(Intersection) then begin
    364276      if not NewPolygonStarted then begin
    365277        // Crossing line, start new polygon
     
    391303{ TLine }
    392304
    393 function TLine.GetDistance: Double;
     305function TGLine<T>.GetDistance: Double;
    394306begin
    395307  Result := Sqrt(Sqr(P2.X - P1.X) + Sqr(P2.Y - P1.Y));
    396308end;
    397309
    398 procedure TLine.SetDistance(AValue: Double);
     310procedure TGLine<T>.SetDistance(AValue: Double);
    399311var
    400312  Angle: Double;
    401313begin
    402314  Angle := GetAngle;
    403   P2 := Point(Round(P1.X + Cos(Angle) * AValue),
     315  P2 := T.Create(Round(P1.X + Cos(Angle) * AValue),
    404316    Round(P1.Y + Sin(Angle) * AValue));
    405317end;
    406318
    407 function TLine.Create(const P1, P2: TPoint): TLine;
     319constructor TGLine<T>.Create(const P1, P2: T);
     320begin
     321  Self.P1 := P1;
     322  Self.P2 := P2;
     323end;
     324
     325function TGLine<T>.GetMiddle: T;
     326begin
     327  Result := T.Create(P1.X + Divide((P2.X - P1.X), 2), P1.Y + Divide((P2.Y - P1.Y), 2));
     328end;
     329
     330function TGLine<T>.GetAngle: Double;
     331begin
     332  Result := ArcTan2(P2.Y - P1.Y, P2.X - P1.X);
     333end;
     334
     335function TGLine<T>.GetSize: T;
     336begin
     337  Result := P2 - P1;
     338end;
     339
     340function TGLine<T>.ToRect: TGRect<T>;
    408341begin
    409342  Result.P1 := P1;
     
    411344end;
    412345
    413 function TLine.GetMiddle: TPoint;
    414 begin
    415   Result := Point(P1.X + (P2.X - P1.X) div 2, P1.Y + (P2.Y - P1.Y) div 2);
    416 end;
    417 
    418 function TLine.GetAngle: Double;
    419 begin
    420   Result := ArcTan2(P2.Y - P1.Y, P2.X - P1.X);
    421 end;
    422 
    423 function TLine.GetSize: TPoint;
    424 begin
    425   Result := Point(P2.X - P1.X, P2.Y - P1.Y);
    426 end;
    427 
    428 function TLine.ToRect: TRect;
    429 begin
    430   if P1.X < P2.X then Result.Left := P1.X else Result.Left := P2.X;
    431   if P1.Y < P2.Y then Result.Top := P1.Y else Result.Top := P2.Y;
    432   if P1.X > P2.X then Result.Right := P1.X else Result.Right := P2.X;
    433   if P1.Y > P2.Y then Result.Bottom := P1.Y else Result.Bottom := P2.Y;
    434 end;
    435 
    436 function TLine.DotProduct: Double;
     346function TGLine<T>.DotProduct: Double;
    437347begin
    438348  Result := P1.X * P2.X + P1.Y * P2.Y;
    439349end;
    440350
    441 procedure TLine.Rotate(const Angle: Double);
    442 begin
    443   P2 := RotatePoint(P1, P2, Angle);
    444 end;
    445 
    446 class operator TLine.Equal(const A, B: TLine): Boolean;
    447 begin
    448   Result := ComparePoint(A.P1, B.P1) and ComparePoint(A.P2, B.P2);
     351procedure TGLine<T>.Rotate(const Angle: Double);
     352begin
     353  P2.Rotate(P1, Angle);
     354end;
     355
     356class operator TGLine<T>.Equal(const A, B: TGLine<T>): Boolean;
     357begin
     358  Result := (A.P1 = B.P1) and (A.P2 = B.P2);
     359end;
     360
     361{ TGPoint3D }
     362
     363constructor TGPoint3D<T>.Create(const X, Y, Z: T);
     364begin
     365  Self.X := X;
     366  Self.Y := Y;
     367  Self.Z := Z;
     368end;
     369
     370{ TGPoint }
     371
     372constructor TGPoint<T>.Create(const X, Y: T);
     373begin
     374  Self.X := X;
     375  Self.Y := Y;
     376end;
     377
     378class operator TGPoint<T>.Equal(const A, B: TGPoint<T>): Boolean;
     379begin
     380  Result := (A.X = B.X) and (A.Y = B.Y);
     381end;
     382
     383class operator TGPoint<T>.Add(const A, B: TGPoint<T>): TGPoint<T>;
     384begin
     385  Result.X := A.X + B.X;
     386  Result.Y := A.Y + B.Y;
     387end;
     388
     389class operator TGPoint<T>.Subtract(const A, B: TGPoint<T>): TGPoint<T>;
     390begin
     391  Result.X := A.X - B.X;
     392  Result.Y := A.Y - B.Y;
     393end;
     394
     395class operator TGPoint<T>.GreaterThan(const A, B: TGPoint<T>): Boolean;
     396begin
     397  Result := (B.X > A.X) and (B.Y > A.Y);
     398end;
     399
     400class operator TGPoint<T>.LessThan(const A, B: TGPoint<T>): Boolean;
     401begin
     402  Result := (B.X < A.X) and (B.Y < A.Y);
     403end;
     404
     405{ TGLine }
     406
     407class function TGLine<T>.LineIntersect(const LineA, LineB: TGLine<T>; out
     408  Intersection: T): Boolean;
     409Var
     410  LDetLineA, LDetLineB, LDetDivInv: Double;
     411  LDiffLA, LDiffLB: T;
     412  D: Double;
     413begin
     414  if (LineA.P1 = LineA.P2) or (LineB.P1 = LineB.P2) then begin
     415    Result := False;
     416    Exit;
     417  end;
     418  LDetLineA := LineA.P1.X * LineA.P2.Y - LineA.P1.Y * LineA.P2.X;
     419  LDetLineB := LineB.P1.X * LineB.P2.Y - LineB.P1.Y * LineB.P2.X;
     420
     421  LDiffLA := LineA.P1 - LineA.P2;
     422  LDiffLB := LineB.P1 - LineB.P2;
     423
     424  D := (LDiffLA.X * LDiffLB.Y) - (LDiffLA.Y * LDiffLB.X);
     425  if D = 0 then begin
     426    // Parallel lines without intersection
     427    Result := False;
     428    Exit;
     429  end;
     430  LDetDivInv := 1 / D;
     431
     432  Intersection.X := TypedRound(((LDetLineA * LDiffLB.X) - (LDiffLA.X * LDetLineB)) * LDetDivInv);
     433  Intersection.Y := TypedRound(((LDetLineA * LDiffLB.Y) - (LDiffLA.Y * LDetLineB)) * LDetDivInv);
     434  Result := True;
     435end;
     436
     437procedure TGPoint<T>.Rotate(Base: TGPoint<T>; Angle: Double);
     438var
     439  D: TGPoint<T>;
     440begin
     441  D := TGPoint<T>.Create(X - Base.X, Y - Base.Y);
     442  //X := Base.X + TypedRound(D.X * Cos(Angle) - D.Y * Sin(Angle));
     443  //Y := Base.Y + TypedRound(D.X * Sin(Angle) + D.Y * Cos(Angle));
     444end;
     445
     446function TGPoint<T>.Min(const A, B: TGPoint<T>): TGPoint<T>;
     447begin
     448  if A.X < B.X then Result.X := A.X else Result.X := B.X;
     449  if A.Y < B.Y then Result.Y := A.Y else Result.Y := B.Y;
     450end;
     451
     452function TGPoint<T>.Max(const A, B: TGPoint<T>): TGPoint<T>;
     453begin
     454  if A.X > B.X then Result.X := A.X else Result.X := B.X;
     455  if A.Y > B.Y then Result.Y := A.Y else Result.Y := B.Y;
     456end;
     457
     458{ TGRect }
     459
     460function TGRect<T>.IsPointInside(const P: T): Boolean;
     461begin
     462  Result := (P > P1) and (P < P2);
     463end;
     464
     465function TGRect<T>.GetEmpty: Boolean;
     466begin
     467  Result := P1 = P2;
     468end;
     469
     470procedure TGRect<T>.SetEmpty;
     471begin
     472  P2 := P1;
     473end;
     474
     475function TGRect<T>.Center: T;
     476begin
     477  Result.X := Divide(P2.X - P1.X, 2);
     478  Result.Y := Divide(P2.Y - P1.Y, 2);
     479end;
     480
     481function TGRect<T>.GetSize: T;
     482begin
     483  Result := P2 - P1;
     484end;
     485
     486procedure TGRect<T>.SetSize(AValue: T);
     487begin
     488  P2 := P1 + AValue;
     489end;
     490
     491constructor TGRect<T>.Create(const P1, P2: T);
     492begin
     493  Self.P1 := P1;
     494  Self.P2 := P2;
     495end;
     496
     497constructor TGRect<T>.CreateBounds(const Origin, Size: T);
     498begin
     499  Self.P1 := Origin;
     500  Self.P2 := Origin + Size;
     501end;
     502
     503class operator TGRect<T>.Equal(const A, B: TGRect<T>): Boolean;
     504begin
     505  Result := (A.P1 = B.P1) and (A.P2 = B.P2);
    449506end;
    450507
Note: See TracChangeset for help on using the changeset viewer.