Ignore:
Timestamp:
Apr 17, 2019, 10:42:18 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Updated Graphics32 library.
Location:
GraphicTest/Packages/Graphics32
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/Graphics32

    • Property svn:ignore set to
      lib
  • GraphicTest/Packages/Graphics32/GR32_Geometry.pas

    r450 r522  
    2727 * Michael Hansen <dyster_tid@hotmail.com>
    2828 *
    29  * Portions created by the Initial Developers are Copyright (C) 2005-2009
     29 * Portions created by the Initial Developers are Copyright (C) 2005-2012
    3030 * the Initial Developers. All Rights Reserved.
    3131 *
     
    3838
    3939uses
    40   Math, GR32, GR32_Math;
     40  Math, Types, GR32;
    4141
    4242type
    43   PFixedVector = ^TFixedVector;
    44   TFixedVector = TFixedPoint;
    45 
    46   PFloatVector = ^TFloatVector;
    47   TFloatVector = TFloatPoint;
    48 
    49 function Add(const V1, V2: TFloatVector): TFloatVector;  overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    50 function Add(const V: TFloatVector; Value: TFloat): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    51 function Sub(const V1, V2: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    52 function Sub(const V: TFloatVector; Value: TFloat): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    53 function Mul(const V1, V2: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    54 function Mul(const V: TFloatVector; Multiplier: TFloat): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    55 function Divide(const V: TFloatVector; Divisor: TFloat): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    56 function Divide(const V1, V2: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    57 
    58 function Combine(const V1, V2: TFloatVector; W: TFloat): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    59 function AbsV(const V: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    60 function Neg(const V: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    61 function Average(const V1, V2: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    62 function Max(const V1, V2: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    63 function Min(const V1, V2: TFloatVector): TFloatVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    64 
    65 function Dot(const V1, V2: TFloatVector): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    66 function Distance(const V1, V2: TFloatVector): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    67 function SqrDistance(const V1, V2: TFloatVector): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    68 
    69 // Fixed Overloads
    70 function Add(const V1, V2: TFixedVector): TFixedVector;  overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    71 function Add(const V: TFixedVector; Value: TFixed): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    72 function Sub(const V1, V2: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    73 function Sub(const V: TFixedVector; Value: TFixed): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    74 function Mul(const V1, V2: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    75 function Mul(const V: TFixedVector; Multiplier: TFixed): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    76 function Divide(const V: TFixedVector; Divisor: TFixed): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    77 function Divide(const V1, V2: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    78 
    79 function Combine(const V1, V2: TFixedVector; W: TFixed): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    80 function AbsV(const V: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    81 function Neg(const V: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    82 function Average(const V1, V2: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    83 function Max(const V1, V2: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    84 function Min(const V1, V2: TFixedVector): TFixedVector; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    85 
    86 function Dot(const V1, V2: TFixedVector): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    87 function Distance(const V1, V2: TFixedVector): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
    88 function SqrDistance(const V1, V2: TFixedVector): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     43  TLinePos = (lpStart, lpEnd, lpBoth, lpNeither);
     44
     45// TFloat Overloads
     46function Average(const V1, V2: TFloatPoint): TFloatPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     47function CrossProduct(V1, V2: TFloatPoint): TFloat; overload; {$IFDEF USEINLINING} inline; {$ENDIF}
     48function Dot(const V1, V2: TFloatPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     49function Distance(const V1, V2: TFloatPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     50function SqrDistance(const V1, V2: TFloatPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     51function GetPointAtAngleFromPoint(const Pt: TFloatPoint; const Dist, Radians: Single): TFloatPoint; overload;
     52function GetAngleOfPt2FromPt1(const Pt1, Pt2: TFloatPoint): Single; overload;
     53function GetUnitNormal(const Pt1, Pt2: TFloatPoint): TFloatPoint; overload;
     54function GetUnitVector(const Pt1, Pt2: TFloatPoint): TFloatPoint; overload;
     55function OffsetPoint(const Pt: TFloatPoint; DeltaX, DeltaY: TFloat): TFloatPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     56function OffsetPoint(const Pt, Delta: TFloatPoint): TFloatPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     57function OffsetRect(const Rct: TFloatRect; const DeltaX, DeltaY: TFloat): TFloatRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     58function OffsetRect(const Rct: TFloatRect; const Delta: TFloatPoint): TFloatRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     59function Shorten(const Pts: TArrayOfFloatPoint;
     60  Delta: TFloat; LinePos: TLinePos): TArrayOfFloatPoint; overload;
     61function PointInPolygon(const Pt: TFloatPoint; const Pts: TArrayOfFloatPoint): Boolean; overload;
     62function SegmentIntersect(const P1, P2, P3, P4: TFloatPoint;
     63  out IntersectPoint: TFloatPoint): Boolean; overload;
     64function PerpendicularDistance(const P, P1, P2: TFloatPoint): TFloat; overload;
     65
     66
     67// TFixed Overloads
     68function Average(const V1, V2: TFixedPoint): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     69function CrossProduct(V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     70function Dot(const V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     71function Distance(const V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     72function SqrDistance(const V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     73function GetPointAtAngleFromPoint(const Pt: TFixedPoint; const Dist, Radians: Single): TFixedPoint; overload;
     74function GetAngleOfPt2FromPt1(Pt1, Pt2: TFixedPoint): Single; overload;
     75function GetUnitVector(const Pt1, Pt2: TFixedPoint): TFloatPoint; overload;
     76function GetUnitNormal(const Pt1, Pt2: TFixedPoint): TFloatPoint; overload;
     77function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFixed): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     78function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFloat): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     79function OffsetPoint(const Pt: TFixedPoint; const Delta: TFixedPoint): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     80function OffsetPoint(const Pt: TFixedPoint; const Delta: TFloatPoint): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     81function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFixed): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     82function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFloat): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     83function OffsetRect(const Rct: TFixedRect; const Delta: TFixedPoint): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     84function OffsetRect(const Rct: TFixedRect; const Delta: TFloatPoint): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     85function Shorten(const Pts: TArrayOfFixedPoint;
     86  Delta: TFloat; LinePos: TLinePos): TArrayOfFixedPoint; overload;
     87function PointInPolygon(const Pt: TFixedPoint; const Pts: array of TFixedPoint): Boolean; overload;
     88function SegmentIntersect(const P1, P2, P3, P4: TFixedPoint;
     89  out IntersectPoint: TFixedPoint): Boolean; overload;
     90function PerpendicularDistance(const P, P1, P2: TFixedPoint): TFixed; overload;
     91
     92// Integer Overloads
     93function Average(const V1, V2: TPoint): TPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     94function CrossProduct(V1, V2: TPoint): Integer; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     95function Dot(const V1, V2: TPoint): Integer; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     96function Distance(const V1, V2: TPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     97function SqrDistance(const V1, V2: TPoint): Integer; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     98function OffsetPoint(const Pt: TPoint; DeltaX, DeltaY: Integer): TPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     99function OffsetPoint(const Pt, Delta: TPoint): TPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF}
     100function PerpendicularDistance(const P, P1, P2: TPoint): TFloat; overload;
     101
     102const
     103  CRad01 = Pi / 180;
     104  CRad30 = Pi / 6;
     105  CRad45 = Pi / 4;
     106  CRad60 = Pi / 3;
     107  CRad90 = Pi / 2;
     108  CRad180 = Pi;
     109  CRad270 = CRad90 * 3;
     110  CRad360 = CRad180 * 2;
     111  CDegToRad = Pi / 180;
     112  CRadToDeg = 180 / Pi;
    89113
    90114implementation
    91115
    92 function Add(const V1, V2: TFloatVector): TFloatVector;
    93 begin
    94   Result.X := V1.X + V2.X;
    95   Result.Y := V1.Y + V2.Y;
    96 end;
    97 
    98 function Add(const V: TFloatVector; Value: TFloat): TFloatVector;
    99 begin
    100   Result.X := V.X + Value;
    101   Result.Y := V.Y + Value;
    102 end;
    103 
    104 function Sub(const V1, V2: TFloatVector): TFloatVector;
    105 begin
    106   Result.X := V1.X - V2.X;
    107   Result.Y := V1.Y - V2.Y;
    108 end;
    109 
    110 function Sub(const V: TFloatVector; Value: TFloat): TFloatVector;
    111 begin
    112   Result.X := V.X - Value;
    113   Result.Y := V.Y - Value;
    114 end;
    115 
    116 function Mul(const V1, V2: TFloatVector): TFloatVector;
    117 begin
    118   Result.X := V1.X * V2.X;
    119   Result.Y := V1.Y * V2.Y;
    120 end;
    121 
    122 function Mul(const V: TFloatVector; Multiplier: TFloat): TFloatVector;
    123 begin
    124   Result.X := V.X * Multiplier;
    125   Result.Y := V.Y * Multiplier;
    126 end;
    127 
    128 function Divide(const V: TFloatVector; Divisor: TFloat): TFloatVector;
    129 begin
    130   Divisor := 1 / Divisor;
    131   Result.X := V.X * Divisor;
    132   Result.Y := V.Y * Divisor;
    133 end;
    134 
    135 function Divide(const V1, V2: TFloatVector): TFloatVector;
    136 begin
    137   Result.X := V1.X / V2.X;
    138   Result.Y := V1.Y / V2.Y;
    139 end;
    140 
    141 function Combine(const V1, V2: TFloatVector; W: TFloat): TFloatVector;
    142 begin
    143   Result.X := V2.X + (V1.X - V2.X) * W;
    144   Result.Y := V2.Y + (V1.Y - V2.Y) * W;
    145 end;
    146 
    147 function AbsV(const V: TFloatVector): TFloatVector;
    148 begin
    149   Result.X := System.Abs(V.X);
    150   Result.Y := System.Abs(V.Y);
    151 end;
    152 
    153 function Neg(const V: TFloatVector): TFloatVector;
    154 begin
    155   Result.X := - V.X;
    156   Result.Y := - V.Y;
    157 end;
    158 
    159 function Average(const V1, V2: TFloatVector): TFloatVector;
     116uses
     117  GR32_Math;
     118
     119function Average(const V1, V2: TFloatPoint): TFloatPoint;
    160120begin
    161121  Result.X := (V1.X + V2.X) * 0.5;
     
    163123end;
    164124
    165 function Max(const V1, V2: TFloatVector): TFloatVector;
    166 begin
    167   Result := V1;
    168   if V2.X > V1.X then Result.X := V2.X;
    169   if V2.Y > V1.Y then Result.Y := V2.Y;
    170 end;
    171 
    172 function Min(const V1, V2: TFloatVector): TFloatVector;
    173 begin
    174   Result := V1;
    175   if V2.X < V1.X then Result.X := V2.X;
    176   if V2.Y < V1.Y then Result.Y := V2.Y;
    177 end;
    178 
    179 function Dot(const V1, V2: TFloatVector): TFloat;
     125function CrossProduct(V1, V2: TFloatPoint): TFloat;
     126begin
     127  Result := V1.X * V2.Y - V1.Y * V2.X;
     128end;
     129
     130function Dot(const V1, V2: TFloatPoint): TFloat;
    180131begin
    181132  Result := V1.X * V2.X + V1.Y * V2.Y;
    182133end;
    183134
    184 function Distance(const V1, V2: TFloatVector): TFloat;
    185 begin
    186   Result := Hypot(V2.X - V1.X, V2.Y - V1.Y);
    187 end;
    188 
    189 function SqrDistance(const V1, V2: TFloatVector): TFloat;
     135function Distance(const V1, V2: TFloatPoint): TFloat;
     136begin
     137  Result := GR32_Math.Hypot(V2.X - V1.X, V2.Y - V1.Y);
     138end;
     139
     140function SqrDistance(const V1, V2: TFloatPoint): TFloat;
    190141begin
    191142  Result := Sqr(V2.X - V1.X) + Sqr(V2.Y - V1.Y);
    192143end;
    193144
     145function GetPointAtAngleFromPoint(const Pt: TFloatPoint;
     146  const Dist, Radians: TFloat): TFloatPoint; overload;
     147var
     148  SinAng, CosAng: TFloat;
     149begin
     150  GR32_Math.SinCos(Radians, SinAng, CosAng);
     151  Result.X :=  Dist * CosAng + Pt.X;
     152  Result.Y := -Dist * SinAng + Pt.Y; // Y axis is positive down
     153end;
     154
     155function GetAngleOfPt2FromPt1(const Pt1, Pt2: TFloatPoint): Single;
     156var
     157  X, Y: TFloat;
     158begin
     159  X := Pt2.X - Pt1.X;
     160  Y := Pt2.Y - Pt1.Y;
     161  if X = 0 then
     162  begin
     163    if Y > 0 then Result := CRad270 else Result := CRad90;
     164  end else
     165  begin
     166    Result := ArcTan2(-Y, X);
     167    if Result < 0 then Result := Result + CRad360;
     168  end;
     169end;
     170
     171function GetUnitVector(const Pt1, Pt2: TFloatPoint): TFloatPoint;
     172var
     173  Delta: TFloatPoint;
     174  Temp: TFloat;
     175begin
     176  Delta.X := (Pt2.X - Pt1.X);
     177  Delta.Y := (Pt2.Y - Pt1.Y);
     178  if (Delta.X = 0) and (Delta.Y = 0) then
     179    Result := FloatPoint(0, 0)
     180  else
     181  begin
     182    Temp := 1 / GR32_Math.Hypot(Delta.X, Delta.Y);
     183    Result.X := Delta.X * Temp;
     184    Result.Y := Delta.Y * Temp;
     185  end;
     186end;
     187
     188function GetUnitNormal(const Pt1, Pt2: TFloatPoint): TFloatPoint;
     189var
     190  Delta: TFloatPoint;
     191  Temp: TFloat;
     192begin
     193  Delta.X := (Pt2.X - Pt1.X);
     194  Delta.Y := (Pt2.Y - Pt1.Y);
     195
     196  if (Delta.X = 0) and (Delta.Y = 0) then
     197    Result := FloatPoint(0, 0)
     198  else
     199  begin
     200    Temp := 1 / GR32_Math.Hypot(Delta.X, Delta.Y);
     201    Delta.X := Delta.X * Temp;
     202    Delta.Y := Delta.Y * Temp;
     203  end;
     204  Result.X :=  Delta.Y; // ie perpendicular to
     205  Result.Y := -Delta.X; // the unit vector
     206end;
     207
     208function OffsetPoint(const Pt: TFloatPoint; DeltaX, DeltaY: TFloat): TFloatPoint;
     209begin
     210  Result.X := Pt.X + DeltaX;
     211  Result.Y := Pt.Y + DeltaY;
     212end;
     213
     214function OffsetPoint(const Pt, Delta: TFloatPoint): TFloatPoint;
     215begin
     216  Result.X := Pt.X + Delta.X;
     217  Result.Y := Pt.Y + Delta.Y;
     218end;
     219
     220function OffsetRect(const Rct: TFloatRect; const DeltaX, DeltaY: TFloat): TFloatRect;
     221begin
     222  Result.TopLeft := OffsetPoint(Rct.TopLeft, DeltaX, DeltaY);
     223  Result.BottomRight := OffsetPoint(Rct.BottomRight, DeltaX, DeltaY);
     224end;
     225
     226function OffsetRect(const Rct: TFloatRect; const Delta: TFloatPoint): TFloatRect;
     227begin
     228  Result.TopLeft := OffsetPoint(Rct.TopLeft, Delta);
     229  Result.BottomRight := OffsetPoint(Rct.BottomRight, Delta);
     230end;
     231
     232
     233function Shorten(const Pts: TArrayOfFloatPoint;
     234  Delta: TFloat; LinePos: TLinePos): TArrayOfFloatPoint;
     235var
     236  Index, HighI: integer;
     237  Dist, DeltaSqr: TFloat;
     238  UnitVec: TFloatPoint;
     239
     240  procedure FixStart;
     241  begin
     242    Index := 1;
     243    while (Index < HighI) and (SqrDistance(Pts[Index], Pts[0]) < DeltaSqr) do
     244      Inc(Index);
     245    UnitVec := GetUnitVector(Pts[Index], Pts[0]);
     246    Dist := Distance(Pts[Index], Pts[0]) - Delta;
     247    if Index > 1 then
     248    begin
     249      HighI := HighI - Index + 1;
     250      Move(Result[Index], Result[1], SizeOf(TFloatPoint) * HighI);
     251      SetLength(Result, HighI + 1);
     252    end;
     253    Result[0] := OffsetPoint(Result[1], UnitVec.X * Dist, UnitVec.Y * Dist);
     254  end;
     255
     256  procedure FixEnd;
     257  begin
     258    Index := HighI - 1;
     259    while (Index > 0) and (SqrDistance(Pts[Index],Pts[HighI]) < DeltaSqr) do
     260      Dec(Index);
     261    UnitVec := GetUnitVector(Pts[Index],Pts[HighI]);
     262    Dist := Distance(Pts[Index], Pts[HighI]) - Delta;
     263    if Index + 1 < HighI then SetLength(Result, Index + 2);
     264    Result[Index + 1] := OffsetPoint(Result[Index], UnitVec.X * Dist, UnitVec.Y * Dist);
     265  end;
     266
     267begin
     268  Result := Pts;
     269  HighI := High(Pts);
     270  DeltaSqr := Delta * Delta;
     271  if HighI < 1 then Exit;
     272
     273  case LinePos of
     274    lpStart: FixStart;
     275    lpEnd  : FixEnd;
     276    lpBoth : begin FixStart; FixEnd; end;
     277  end;
     278end;
     279
     280function PointInPolygon(const Pt: TFloatPoint; const Pts: TArrayOfFloatPoint): Boolean;
     281var
     282  Index: Integer;
     283  iPt, jPt: PFloatPoint;
     284begin
     285  Result := False;
     286  iPt := @Pts[0];
     287  jPt := @Pts[High(Pts)];
     288  for Index := 0 to High(Pts) do
     289  begin
     290    Result := Result xor (((Pt.Y >= iPt.Y) xor (Pt.Y >= jPt.Y)) and
     291      ((Pt.X - iPt.X) < ((jPt.X - iPt.X) * (Pt.Y -iPt.Y) / (jPt.Y - iPt.Y))));
     292    jPt := iPt;
     293    Inc(iPt);
     294  end;
     295end;
     296
     297function SegmentIntersect(const P1, P2, P3, P4: TFloatPoint;
     298  out IntersectPoint: TFloatPoint): Boolean;
     299var
     300  m1, b1, m2, b2: TFloat;
     301begin
     302  // see http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
     303  Result := False;
     304  if (P2.X = P1.X) then
     305  begin
     306    if (P4.X = P3.X) then Exit; // parallel lines
     307    m2 := (P4.Y - P3.Y) / (P4.X - P3.X);
     308    b2 := P3.Y - m2 * P3.X;
     309    IntersectPoint.X := P1.X;
     310    IntersectPoint.Y := m2 * P1.X + b2;
     311    Result := (((IntersectPoint.Y < P2.Y) = (IntersectPoint.Y > P1.Y)) or
     312      (IntersectPoint.Y = P2.Y) or (IntersectPoint.Y = P1.Y)) and
     313      (((IntersectPoint.Y < P3.Y) = (IntersectPoint.Y > P4.Y)) or
     314      (IntersectPoint.Y = P3.Y) or (IntersectPoint.Y = P4.Y));
     315  end
     316  else if (P4.X = P3.X) then
     317  begin
     318    m1 := (P2.Y - P1.Y) / (P2.X - P1.X);
     319    b1 := P1.Y - m1 * P1.X;
     320    IntersectPoint.X := P3.X;
     321    IntersectPoint.Y := m1 * P3.X + b1;
     322    Result := (((IntersectPoint.Y < P2.Y) = (IntersectPoint.Y > P1.Y)) or
     323      (IntersectPoint.Y = P2.Y) or (IntersectPoint.Y = P1.Y)) and
     324      (((IntersectPoint.Y < P3.Y) = (IntersectPoint.Y > P4.Y)) or
     325      (IntersectPoint.Y = P3.Y) or (IntersectPoint.Y = P4.Y));
     326  end else
     327  begin
     328    m1 := (P2.Y - P1.Y) / (P2.X - P1.X);
     329    b1 := P1.Y - m1 * P1.X;
     330    m2 := (P4.Y - P3.Y) / (P4.X - P3.X);
     331    b2 := P3.Y - m2 * P3.X;
     332    if m1 = m2 then Exit; // parallel lines
     333    IntersectPoint.X := (b2 - b1) / (m1 - m2);
     334    IntersectPoint.Y := m1 * IntersectPoint.X + b1;
     335    Result := (((IntersectPoint.X < P2.X) = (IntersectPoint.X > P1.X)) or
     336      (IntersectPoint.X = P2.X) or (IntersectPoint.X = P1.X)) and
     337      (((IntersectPoint.X < P3.X) = (IntersectPoint.X > P4.X)) or
     338      (IntersectPoint.X = P3.X) or (IntersectPoint.X = P4.X));
     339  end;
     340end;
     341
     342function PerpendicularDistance(const P, P1, P2: TFloatPoint): TFloat;
     343begin
     344  Result := Abs((P.x - P2.x) * (P1.y - P2.y) - (P.y - P2.y) * (P1.x - P2.x)) /
     345    GR32_Math.Hypot(P1.x - P2.x, P1.y - P2.y);
     346end;
     347
     348
    194349// Fixed overloads
    195350
    196 function Add(const V1, V2: TFixedVector): TFixedVector;
    197 begin
    198   Result.X := V1.X + V2.X;
    199   Result.Y := V1.Y + V2.Y;
    200 end;
    201 
    202 function Add(const V: TFixedVector; Value: TFixed): TFixedVector;
    203 begin
    204   Result.X := V.X + Value;
    205   Result.Y := V.Y + Value;
    206 end;
    207 
    208 function Sub(const V1, V2: TFixedVector): TFixedVector;
    209 begin
    210   Result.X := V1.X - V2.X;
    211   Result.Y := V1.Y - V2.Y;
    212 end;
    213 
    214 function Sub(const V: TFixedVector; Value: TFixed): TFixedVector;
    215 begin
    216   Result.X := V.X - Value;
    217   Result.Y := V.Y - Value;
    218 end;
    219 
    220 function Mul(const V1, V2: TFixedVector): TFixedVector;
    221 begin
    222   Result.X := FixedMul(V1.X, V2.X);
    223   Result.Y := FixedMul(V1.Y, V2.Y);
    224 end;
    225 
    226 function Mul(const V: TFixedVector; Multiplier: TFixed): TFixedVector;
    227 begin
    228   Result.X := FixedMul(V.X, Multiplier);
    229   Result.Y := FixedMul(V.Y, Multiplier);
    230 end;
    231 
    232 function Divide(const V: TFixedVector; Divisor: TFixed): TFixedVector;
    233 var
    234   D: TFloat;
    235 begin
    236   D := FIXEDONE / Divisor;
    237   Result.X := Round(V.X * D);
    238   Result.Y := Round(V.Y * D);
    239 end;
    240 
    241 function Divide(const V1, V2: TFixedVector): TFixedVector;
    242 begin
    243   Result.X := FixedDiv(V1.X, V2.X);
    244   Result.Y := FixedDiv(V1.Y, V2.Y);
    245 end;
    246 
    247 function Combine(const V1, V2: TFixedVector; W: TFixed): TFixedVector;
    248 begin
    249   Result.X := V2.X + FixedMul(V1.X - V2.X, W);
    250   Result.Y := V2.Y + FixedMul(V1.Y - V2.Y, W);
    251 end;
    252 
    253 function AbsV(const V: TFixedVector): TFixedVector;
    254 begin
    255   Result.X := System.Abs(V.X);
    256   Result.Y := System.Abs(V.Y);
    257 end;
    258 
    259 function Neg(const V: TFixedVector): TFixedVector;
    260 begin
    261   Result.X := - V.X;
    262   Result.Y := - V.Y;
    263 end;
    264 
    265 function Average(const V1, V2: TFixedVector): TFixedVector;
     351function Average(const V1, V2: TFixedPoint): TFixedPoint;
    266352begin
    267353  Result.X := (V1.X + V2.X) div 2;
     
    269355end;
    270356
    271 function Max(const V1, V2: TFixedVector): TFixedVector;
    272 begin
    273   Result := V1;
    274   if V2.X > V1.X then Result.X := V2.X;
    275   if V2.Y > V1.Y then Result.Y := V2.Y;
    276 end;
    277 
    278 function Min(const V1, V2: TFixedVector): TFixedVector;
    279 begin
    280   Result := V1;
    281   if V2.X < V1.X then Result.X := V2.X;
    282   if V2.Y < V1.Y then Result.Y := V2.Y;
    283 end;
    284 
    285 function Dot(const V1, V2: TFixedVector): TFixed;
     357function CrossProduct(V1, V2: TFixedPoint): TFixed;
     358begin
     359  Result := FixedMul(V1.X, V2.Y) - FixedMul(V1.Y, V2.X);
     360end;
     361
     362function Dot(const V1, V2: TFixedPoint): TFixed;
    286363begin
    287364  Result := FixedMul(V1.X, V2.X) + FixedMul(V1.Y, V2.Y);
    288365end;
    289366
    290 function Distance(const V1, V2: TFixedVector): TFixed;
    291 begin
    292   Result := Fixed(Hypot((V2.X - V1.X) * FixedToFloat, (V2.Y - V1.Y) * FixedToFloat));
    293 end;
    294 
    295 function SqrDistance(const V1, V2: TFixedVector): TFixed;
     367function Distance(const V1, V2: TFixedPoint): TFixed;
     368begin
     369  Result :=
     370    Fixed(Hypot((V2.X - V1.X) * FixedToFloat, (V2.Y - V1.Y) * FixedToFloat));
     371end;
     372
     373function SqrDistance(const V1, V2: TFixedPoint): TFixed;
    296374begin
    297375  Result := FixedSqr(V2.X - V1.X) + FixedSqr(V2.Y - V1.Y);
    298376end;
    299377
     378function GetPointAtAngleFromPoint(const Pt: TFixedPoint;
     379  const Dist, Radians: TFloat): TFixedPoint;
     380var
     381  SinAng, CosAng: TFloat;
     382begin
     383  GR32_Math.SinCos(Radians, SinAng, CosAng);
     384  Result.X := Round(Dist * CosAng * FixedOne) + Pt.X;
     385  Result.Y := -Round(Dist * SinAng * FixedOne) + Pt.Y; // Y axis is positive down
     386end;
     387
     388function GetAngleOfPt2FromPt1(Pt1, Pt2: TFixedPoint): Single;
     389begin
     390  with Pt2 do
     391  begin
     392    X := X - Pt1.X;
     393    Y := Y - Pt1.Y;
     394    if X = 0 then
     395    begin
     396     if Y > 0 then Result := CRad270 else Result := CRad90;
     397    end else
     398    begin
     399      Result := ArcTan2(-Y,X);
     400      if Result < 0 then Result := Result + CRad360;
     401    end;
     402  end;
     403end;
     404
     405function GetUnitVector(const Pt1, Pt2: TFixedPoint): TFloatPoint;
     406var
     407  Delta: TFloatPoint;
     408  Temp: Single;
     409begin
     410  Delta.X := (Pt2.X - Pt1.X) * FixedToFloat;
     411  Delta.Y := (Pt2.Y - Pt1.Y) * FixedToFloat;
     412  if (Delta.X = 0) and (Delta.Y = 0) then
     413  begin
     414    Result := FloatPoint(0,0);
     415  end else
     416  begin
     417    Temp := 1 / GR32_Math.Hypot(Delta.X, Delta.Y);
     418    Result.X := Delta.X * Temp;
     419    Result.Y := Delta.Y * Temp;
     420  end;
     421end;
     422
     423function GetUnitNormal(const Pt1, Pt2: TFixedPoint): TFloatPoint;
     424var
     425  Delta: TFloatPoint;
     426  Temp: Single;
     427begin
     428  Delta.X := (Pt2.X - Pt1.X) * FixedToFloat;
     429  Delta.Y := (Pt2.Y - Pt1.Y) * FixedToFloat;
     430
     431  if (Delta.X = 0) and (Delta.Y = 0) then
     432  begin
     433    Result := FloatPoint(0,0);
     434  end else
     435  begin
     436    Temp := 1 / GR32_Math.Hypot(Delta.X, Delta.Y);
     437    Delta.X := Delta.X * Temp;
     438    Delta.Y := Delta.Y * Temp;
     439  end;
     440  Result.X :=  Delta.Y; // ie perpendicular to
     441  Result.Y := -Delta.X; // the unit vector
     442end;
     443
     444function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFixed): TFixedPoint;
     445begin
     446  Result.X := Pt.X + DeltaX;
     447  Result.Y := Pt.Y + DeltaY;
     448end;
     449
     450function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFloat): TFixedPoint;
     451begin
     452  Result.X := Pt.X + Fixed(DeltaX);
     453  Result.Y := Pt.Y + Fixed(DeltaY);
     454end;
     455
     456function OffsetPoint(const Pt: TFixedPoint; const Delta: TFixedPoint): TFixedPoint;
     457begin
     458  Result.X := Pt.X + Delta.X;
     459  Result.Y := Pt.Y + Delta.Y;
     460end;
     461
     462function OffsetPoint(const Pt: TFixedPoint; const Delta: TFloatPoint): TFixedPoint;
     463begin
     464  Result.X := Pt.X + Fixed(Delta.X);
     465  Result.Y := Pt.Y + Fixed(Delta.Y);
     466end;
     467
     468function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFixed): TFixedRect;
     469begin
     470  Result.TopLeft := OffsetPoint(Rct.TopLeft, DeltaX, DeltaY);
     471  Result.BottomRight := OffsetPoint(Rct.BottomRight, DeltaX, DeltaY);
     472end;
     473
     474function OffsetRect(const Rct: TFixedRect; const Delta: TFixedPoint): TFixedRect;
     475begin
     476  Result.TopLeft := OffsetPoint(Rct.TopLeft, Delta);
     477  Result.BottomRight := OffsetPoint(Rct.BottomRight, Delta);
     478end;
     479
     480function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFloat): TFixedRect;
     481var
     482  DX, DY: TFixed;
     483begin
     484  DX := Fixed(DeltaX);
     485  DY := Fixed(DeltaY);
     486  Result.TopLeft := OffsetPoint(Rct.TopLeft, DX, DY);
     487  Result.BottomRight := OffsetPoint(Rct.BottomRight, DX, DY);
     488end;
     489
     490function OffsetRect(const Rct: TFixedRect; const Delta: TFloatPoint): TFixedRect;
     491var
     492  DX, DY: TFixed;
     493begin
     494  DX := Fixed(Delta.X);
     495  DY := Fixed(Delta.Y);
     496  Result.TopLeft := OffsetPoint(Rct.TopLeft, DX, DY);
     497  Result.BottomRight := OffsetPoint(Rct.BottomRight, DX, DY);
     498end;
     499
     500function Shorten(const Pts: TArrayOfFixedPoint;
     501  Delta: TFloat; LinePos: TLinePos): TArrayOfFixedPoint;
     502var
     503  Index, HighI: integer;
     504  Dist, DeltaSqr: TFloat;
     505  UnitVec: TFloatPoint;
     506
     507  procedure FixStart;
     508  begin
     509    Index := 1;
     510    while (Index < HighI) and (SqrDistance(Pts[Index],Pts[0]) < DeltaSqr) do Inc(Index);
     511    UnitVec := GetUnitVector(Pts[Index], Pts[0]);
     512    Dist := Distance(Pts[Index],Pts[0]) - Delta;
     513    if Index > 1 then
     514    begin
     515      Move(Result[Index], Result[1], SizeOf(TFloatPoint) * (HighI - Index + 1));
     516      SetLength(Result, HighI - Index + 2);
     517      HighI := HighI - Index + 1;
     518    end;
     519    Result[0] := OffsetPoint(Result[1], UnitVec.X * Dist, UnitVec.Y * Dist);
     520  end;
     521
     522  procedure FixEnd;
     523  begin
     524    Index := HighI -1;
     525    while (Index > 0) and (SqrDistance(Pts[Index],Pts[HighI]) < DeltaSqr) do Dec(Index);
     526    UnitVec := GetUnitVector(Pts[Index],Pts[HighI]);
     527    Dist := Distance(Pts[Index],Pts[HighI]) - Delta;
     528    if Index + 1 < HighI then SetLength(Result, Index + 2);
     529    Result[Index + 1] := OffsetPoint(Result[Index], UnitVec.X * Dist, UnitVec.Y * Dist);
     530  end;
     531
     532begin
     533  Result := Pts;
     534  HighI := High(Pts);
     535  DeltaSqr := Delta * Delta;
     536  if HighI < 1 then Exit;
     537
     538  case LinePos of
     539    lpStart: FixStart;
     540    lpEnd  : FixEnd;
     541    lpBoth : begin FixStart; FixEnd; end;
     542  end;
     543end;
     544
     545function PointInPolygon(const Pt: TFixedPoint; const Pts: array of TFixedPoint): Boolean;
     546var
     547  I: Integer;
     548  iPt, jPt: PFixedPoint;
     549begin
     550  Result := False;
     551  iPt := @Pts[0];
     552  jPt := @Pts[High(Pts)];
     553  for I := 0 to High(Pts) do
     554  begin
     555    Result := Result xor (((Pt.Y >= iPt.Y) xor (Pt.Y >= jPt.Y)) and
     556      (Pt.X - iPt.X < MulDiv(jPt.X - iPt.X, Pt.Y - iPt.Y, jPt.Y - iPt.Y)));
     557    jPt := iPt;
     558    Inc(iPt);
     559  end;
     560end;
     561
     562function SegmentIntersect(const P1, P2, P3, P4: TFixedPoint;
     563  out IntersectPoint: TFixedPoint): Boolean;
     564var
     565  m1,b1,m2,b2: TFloat;
     566begin
     567  Result := False;
     568  if (P2.X = P1.X) then
     569  begin
     570    if (P4.X = P3.X) then Exit; // parallel lines
     571    m2 := (P4.Y - P3.Y) / (P4.X - P3.X);
     572    b2 := P3.Y - m2 * P3.X;
     573    IntersectPoint.X := P1.X;
     574    IntersectPoint.Y := Round(m2 * P1.X + b2);
     575    Result := (IntersectPoint.Y < P2.Y) = (IntersectPoint.Y > P1.Y);
     576  end
     577  else if (P4.X = P3.X) then
     578  begin
     579    m1 := (P2.Y - P1.Y) / (P2.X - P1.X);
     580    b1 := P1.Y - m1 * P1.X;
     581    IntersectPoint.X := P3.X;
     582    IntersectPoint.Y := Round(m1 * P3.X + b1);
     583    Result := (IntersectPoint.Y < P3.Y) = (IntersectPoint.Y > P4.Y);
     584  end else
     585  begin
     586    m1 := (P2.Y - P1.Y) / (P2.X - P1.X);
     587    b1 := P1.Y - m1 * P1.X;
     588    m2 := (P4.Y - P3.Y) / (P4.X - P3.X);
     589    b2 := P3.Y - m2 * P3.X;
     590    if m1 = m2 then Exit; // parallel lines
     591    IntersectPoint.X := Round((b2 - b1) / (m1 - m2));
     592    IntersectPoint.Y := Round(m1 * IntersectPoint.X + b1);
     593    Result := ((IntersectPoint.X < P2.X) = (IntersectPoint.X > P1.X));
     594  end;
     595end;
     596
     597function PerpendicularDistance(const P, P1, P2: TFixedPoint): TFixed;
     598begin
     599  Result := Fixed(Abs((P.x - P2.x) * (P1.y - P2.y) - (P.y - P2.y) *
     600    (P1.x - P2.x)) * FixedToFloat / Hypot((P1.x - P2.x) * FixedToFloat,
     601    (P1.y - P2.y) * FixedToFloat));
     602end;
     603
     604
     605// Integer overloads
     606
     607function Average(const V1, V2: TPoint): TPoint;
     608begin
     609  Result.X := (V1.X + V2.X) div 2;
     610  Result.Y := (V1.Y + V2.Y) div 2;
     611end;
     612
     613function CrossProduct(V1, V2: TPoint): Integer;
     614begin
     615  Result := V1.X * V2.Y - V1.Y * V2.X;
     616end;
     617
     618function Dot(const V1, V2: TPoint): Integer;
     619begin
     620  Result := V1.X * V2.X + V1.Y * V2.Y;
     621end;
     622
     623function Distance(const V1, V2: TPoint): TFloat;
     624begin
     625  Result := Hypot(Integer(V2.X - V1.X), Integer(V2.Y - V1.Y));
     626end;
     627
     628function SqrDistance(const V1, V2: TPoint): Integer;
     629begin
     630  Result := Sqr(V2.X - V1.X) + Sqr(V2.Y - V1.Y);
     631end;
     632
     633function OffsetPoint(const Pt: TPoint; DeltaX, DeltaY: Integer): TPoint;
     634begin
     635  Result.X := Pt.X + DeltaX;
     636  Result.Y := Pt.Y + DeltaY;
     637end;
     638
     639function OffsetPoint(const Pt, Delta: TPoint): TPoint;
     640begin
     641  Result.X := Pt.X + Delta.X;
     642  Result.Y := Pt.Y + Delta.Y;
     643end;
     644
     645function PerpendicularDistance(const P, P1, P2: TPoint): TFloat;
     646begin
     647  Result := Abs((P.x - P2.x) * (P1.y - P2.y) - (P.y - P2.y) * (P1.x - P2.x)) /
     648    Math.Hypot(P1.x - P2.x, P1.y - P2.y);
     649end;
     650
    300651end.
Note: See TracChangeset for help on using the changeset viewer.