Changeset 522 for GraphicTest/Packages/Graphics32/GR32_Geometry.pas
- Timestamp:
- Apr 17, 2019, 10:42:18 AM (5 years ago)
- Location:
- GraphicTest/Packages/Graphics32
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/Packages/Graphics32
-
Property svn:ignore
set to
lib
-
Property svn:ignore
set to
-
GraphicTest/Packages/Graphics32/GR32_Geometry.pas
r450 r522 27 27 * Michael Hansen <dyster_tid@hotmail.com> 28 28 * 29 * Portions created by the Initial Developers are Copyright (C) 2005-20 0929 * Portions created by the Initial Developers are Copyright (C) 2005-2012 30 30 * the Initial Developers. All Rights Reserved. 31 31 * … … 38 38 39 39 uses 40 Math, GR32, GR32_Math;40 Math, Types, GR32; 41 41 42 42 type 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 46 function Average(const V1, V2: TFloatPoint): TFloatPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 47 function CrossProduct(V1, V2: TFloatPoint): TFloat; overload; {$IFDEF USEINLINING} inline; {$ENDIF} 48 function Dot(const V1, V2: TFloatPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 49 function Distance(const V1, V2: TFloatPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 50 function SqrDistance(const V1, V2: TFloatPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 51 function GetPointAtAngleFromPoint(const Pt: TFloatPoint; const Dist, Radians: Single): TFloatPoint; overload; 52 function GetAngleOfPt2FromPt1(const Pt1, Pt2: TFloatPoint): Single; overload; 53 function GetUnitNormal(const Pt1, Pt2: TFloatPoint): TFloatPoint; overload; 54 function GetUnitVector(const Pt1, Pt2: TFloatPoint): TFloatPoint; overload; 55 function OffsetPoint(const Pt: TFloatPoint; DeltaX, DeltaY: TFloat): TFloatPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 56 function OffsetPoint(const Pt, Delta: TFloatPoint): TFloatPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 57 function OffsetRect(const Rct: TFloatRect; const DeltaX, DeltaY: TFloat): TFloatRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 58 function OffsetRect(const Rct: TFloatRect; const Delta: TFloatPoint): TFloatRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 59 function Shorten(const Pts: TArrayOfFloatPoint; 60 Delta: TFloat; LinePos: TLinePos): TArrayOfFloatPoint; overload; 61 function PointInPolygon(const Pt: TFloatPoint; const Pts: TArrayOfFloatPoint): Boolean; overload; 62 function SegmentIntersect(const P1, P2, P3, P4: TFloatPoint; 63 out IntersectPoint: TFloatPoint): Boolean; overload; 64 function PerpendicularDistance(const P, P1, P2: TFloatPoint): TFloat; overload; 65 66 67 // TFixed Overloads 68 function Average(const V1, V2: TFixedPoint): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 69 function CrossProduct(V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 70 function Dot(const V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 71 function Distance(const V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 72 function SqrDistance(const V1, V2: TFixedPoint): TFixed; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 73 function GetPointAtAngleFromPoint(const Pt: TFixedPoint; const Dist, Radians: Single): TFixedPoint; overload; 74 function GetAngleOfPt2FromPt1(Pt1, Pt2: TFixedPoint): Single; overload; 75 function GetUnitVector(const Pt1, Pt2: TFixedPoint): TFloatPoint; overload; 76 function GetUnitNormal(const Pt1, Pt2: TFixedPoint): TFloatPoint; overload; 77 function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFixed): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 78 function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFloat): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 79 function OffsetPoint(const Pt: TFixedPoint; const Delta: TFixedPoint): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 80 function OffsetPoint(const Pt: TFixedPoint; const Delta: TFloatPoint): TFixedPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 81 function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFixed): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 82 function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFloat): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 83 function OffsetRect(const Rct: TFixedRect; const Delta: TFixedPoint): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 84 function OffsetRect(const Rct: TFixedRect; const Delta: TFloatPoint): TFixedRect; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 85 function Shorten(const Pts: TArrayOfFixedPoint; 86 Delta: TFloat; LinePos: TLinePos): TArrayOfFixedPoint; overload; 87 function PointInPolygon(const Pt: TFixedPoint; const Pts: array of TFixedPoint): Boolean; overload; 88 function SegmentIntersect(const P1, P2, P3, P4: TFixedPoint; 89 out IntersectPoint: TFixedPoint): Boolean; overload; 90 function PerpendicularDistance(const P, P1, P2: TFixedPoint): TFixed; overload; 91 92 // Integer Overloads 93 function Average(const V1, V2: TPoint): TPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 94 function CrossProduct(V1, V2: TPoint): Integer; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 95 function Dot(const V1, V2: TPoint): Integer; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 96 function Distance(const V1, V2: TPoint): TFloat; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 97 function SqrDistance(const V1, V2: TPoint): Integer; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 98 function OffsetPoint(const Pt: TPoint; DeltaX, DeltaY: Integer): TPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 99 function OffsetPoint(const Pt, Delta: TPoint): TPoint; overload;{$IFDEF USEINLINING} inline; {$ENDIF} 100 function PerpendicularDistance(const P, P1, P2: TPoint): TFloat; overload; 101 102 const 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; 89 113 90 114 implementation 91 115 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; 116 uses 117 GR32_Math; 118 119 function Average(const V1, V2: TFloatPoint): TFloatPoint; 160 120 begin 161 121 Result.X := (V1.X + V2.X) * 0.5; … … 163 123 end; 164 124 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; 125 function CrossProduct(V1, V2: TFloatPoint): TFloat; 126 begin 127 Result := V1.X * V2.Y - V1.Y * V2.X; 128 end; 129 130 function Dot(const V1, V2: TFloatPoint): TFloat; 180 131 begin 181 132 Result := V1.X * V2.X + V1.Y * V2.Y; 182 133 end; 183 134 184 function Distance(const V1, V2: TFloat Vector): TFloat;185 begin 186 Result := Hypot(V2.X - V1.X, V2.Y - V1.Y);187 end; 188 189 function SqrDistance(const V1, V2: TFloat Vector): TFloat;135 function Distance(const V1, V2: TFloatPoint): TFloat; 136 begin 137 Result := GR32_Math.Hypot(V2.X - V1.X, V2.Y - V1.Y); 138 end; 139 140 function SqrDistance(const V1, V2: TFloatPoint): TFloat; 190 141 begin 191 142 Result := Sqr(V2.X - V1.X) + Sqr(V2.Y - V1.Y); 192 143 end; 193 144 145 function GetPointAtAngleFromPoint(const Pt: TFloatPoint; 146 const Dist, Radians: TFloat): TFloatPoint; overload; 147 var 148 SinAng, CosAng: TFloat; 149 begin 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 153 end; 154 155 function GetAngleOfPt2FromPt1(const Pt1, Pt2: TFloatPoint): Single; 156 var 157 X, Y: TFloat; 158 begin 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; 169 end; 170 171 function GetUnitVector(const Pt1, Pt2: TFloatPoint): TFloatPoint; 172 var 173 Delta: TFloatPoint; 174 Temp: TFloat; 175 begin 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; 186 end; 187 188 function GetUnitNormal(const Pt1, Pt2: TFloatPoint): TFloatPoint; 189 var 190 Delta: TFloatPoint; 191 Temp: TFloat; 192 begin 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 206 end; 207 208 function OffsetPoint(const Pt: TFloatPoint; DeltaX, DeltaY: TFloat): TFloatPoint; 209 begin 210 Result.X := Pt.X + DeltaX; 211 Result.Y := Pt.Y + DeltaY; 212 end; 213 214 function OffsetPoint(const Pt, Delta: TFloatPoint): TFloatPoint; 215 begin 216 Result.X := Pt.X + Delta.X; 217 Result.Y := Pt.Y + Delta.Y; 218 end; 219 220 function OffsetRect(const Rct: TFloatRect; const DeltaX, DeltaY: TFloat): TFloatRect; 221 begin 222 Result.TopLeft := OffsetPoint(Rct.TopLeft, DeltaX, DeltaY); 223 Result.BottomRight := OffsetPoint(Rct.BottomRight, DeltaX, DeltaY); 224 end; 225 226 function OffsetRect(const Rct: TFloatRect; const Delta: TFloatPoint): TFloatRect; 227 begin 228 Result.TopLeft := OffsetPoint(Rct.TopLeft, Delta); 229 Result.BottomRight := OffsetPoint(Rct.BottomRight, Delta); 230 end; 231 232 233 function Shorten(const Pts: TArrayOfFloatPoint; 234 Delta: TFloat; LinePos: TLinePos): TArrayOfFloatPoint; 235 var 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 267 begin 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; 278 end; 279 280 function PointInPolygon(const Pt: TFloatPoint; const Pts: TArrayOfFloatPoint): Boolean; 281 var 282 Index: Integer; 283 iPt, jPt: PFloatPoint; 284 begin 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; 295 end; 296 297 function SegmentIntersect(const P1, P2, P3, P4: TFloatPoint; 298 out IntersectPoint: TFloatPoint): Boolean; 299 var 300 m1, b1, m2, b2: TFloat; 301 begin 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; 340 end; 341 342 function PerpendicularDistance(const P, P1, P2: TFloatPoint): TFloat; 343 begin 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); 346 end; 347 348 194 349 // Fixed overloads 195 350 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; 351 function Average(const V1, V2: TFixedPoint): TFixedPoint; 266 352 begin 267 353 Result.X := (V1.X + V2.X) div 2; … … 269 355 end; 270 356 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; 357 function CrossProduct(V1, V2: TFixedPoint): TFixed; 358 begin 359 Result := FixedMul(V1.X, V2.Y) - FixedMul(V1.Y, V2.X); 360 end; 361 362 function Dot(const V1, V2: TFixedPoint): TFixed; 286 363 begin 287 364 Result := FixedMul(V1.X, V2.X) + FixedMul(V1.Y, V2.Y); 288 365 end; 289 366 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; 367 function Distance(const V1, V2: TFixedPoint): TFixed; 368 begin 369 Result := 370 Fixed(Hypot((V2.X - V1.X) * FixedToFloat, (V2.Y - V1.Y) * FixedToFloat)); 371 end; 372 373 function SqrDistance(const V1, V2: TFixedPoint): TFixed; 296 374 begin 297 375 Result := FixedSqr(V2.X - V1.X) + FixedSqr(V2.Y - V1.Y); 298 376 end; 299 377 378 function GetPointAtAngleFromPoint(const Pt: TFixedPoint; 379 const Dist, Radians: TFloat): TFixedPoint; 380 var 381 SinAng, CosAng: TFloat; 382 begin 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 386 end; 387 388 function GetAngleOfPt2FromPt1(Pt1, Pt2: TFixedPoint): Single; 389 begin 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; 403 end; 404 405 function GetUnitVector(const Pt1, Pt2: TFixedPoint): TFloatPoint; 406 var 407 Delta: TFloatPoint; 408 Temp: Single; 409 begin 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; 421 end; 422 423 function GetUnitNormal(const Pt1, Pt2: TFixedPoint): TFloatPoint; 424 var 425 Delta: TFloatPoint; 426 Temp: Single; 427 begin 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 442 end; 443 444 function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFixed): TFixedPoint; 445 begin 446 Result.X := Pt.X + DeltaX; 447 Result.Y := Pt.Y + DeltaY; 448 end; 449 450 function OffsetPoint(const Pt: TFixedPoint; DeltaX, DeltaY: TFloat): TFixedPoint; 451 begin 452 Result.X := Pt.X + Fixed(DeltaX); 453 Result.Y := Pt.Y + Fixed(DeltaY); 454 end; 455 456 function OffsetPoint(const Pt: TFixedPoint; const Delta: TFixedPoint): TFixedPoint; 457 begin 458 Result.X := Pt.X + Delta.X; 459 Result.Y := Pt.Y + Delta.Y; 460 end; 461 462 function OffsetPoint(const Pt: TFixedPoint; const Delta: TFloatPoint): TFixedPoint; 463 begin 464 Result.X := Pt.X + Fixed(Delta.X); 465 Result.Y := Pt.Y + Fixed(Delta.Y); 466 end; 467 468 function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFixed): TFixedRect; 469 begin 470 Result.TopLeft := OffsetPoint(Rct.TopLeft, DeltaX, DeltaY); 471 Result.BottomRight := OffsetPoint(Rct.BottomRight, DeltaX, DeltaY); 472 end; 473 474 function OffsetRect(const Rct: TFixedRect; const Delta: TFixedPoint): TFixedRect; 475 begin 476 Result.TopLeft := OffsetPoint(Rct.TopLeft, Delta); 477 Result.BottomRight := OffsetPoint(Rct.BottomRight, Delta); 478 end; 479 480 function OffsetRect(const Rct: TFixedRect; const DeltaX, DeltaY: TFloat): TFixedRect; 481 var 482 DX, DY: TFixed; 483 begin 484 DX := Fixed(DeltaX); 485 DY := Fixed(DeltaY); 486 Result.TopLeft := OffsetPoint(Rct.TopLeft, DX, DY); 487 Result.BottomRight := OffsetPoint(Rct.BottomRight, DX, DY); 488 end; 489 490 function OffsetRect(const Rct: TFixedRect; const Delta: TFloatPoint): TFixedRect; 491 var 492 DX, DY: TFixed; 493 begin 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); 498 end; 499 500 function Shorten(const Pts: TArrayOfFixedPoint; 501 Delta: TFloat; LinePos: TLinePos): TArrayOfFixedPoint; 502 var 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 532 begin 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; 543 end; 544 545 function PointInPolygon(const Pt: TFixedPoint; const Pts: array of TFixedPoint): Boolean; 546 var 547 I: Integer; 548 iPt, jPt: PFixedPoint; 549 begin 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; 560 end; 561 562 function SegmentIntersect(const P1, P2, P3, P4: TFixedPoint; 563 out IntersectPoint: TFixedPoint): Boolean; 564 var 565 m1,b1,m2,b2: TFloat; 566 begin 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; 595 end; 596 597 function PerpendicularDistance(const P, P1, P2: TFixedPoint): TFixed; 598 begin 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)); 602 end; 603 604 605 // Integer overloads 606 607 function Average(const V1, V2: TPoint): TPoint; 608 begin 609 Result.X := (V1.X + V2.X) div 2; 610 Result.Y := (V1.Y + V2.Y) div 2; 611 end; 612 613 function CrossProduct(V1, V2: TPoint): Integer; 614 begin 615 Result := V1.X * V2.Y - V1.Y * V2.X; 616 end; 617 618 function Dot(const V1, V2: TPoint): Integer; 619 begin 620 Result := V1.X * V2.X + V1.Y * V2.Y; 621 end; 622 623 function Distance(const V1, V2: TPoint): TFloat; 624 begin 625 Result := Hypot(Integer(V2.X - V1.X), Integer(V2.Y - V1.Y)); 626 end; 627 628 function SqrDistance(const V1, V2: TPoint): Integer; 629 begin 630 Result := Sqr(V2.X - V1.X) + Sqr(V2.Y - V1.Y); 631 end; 632 633 function OffsetPoint(const Pt: TPoint; DeltaX, DeltaY: Integer): TPoint; 634 begin 635 Result.X := Pt.X + DeltaX; 636 Result.Y := Pt.Y + DeltaY; 637 end; 638 639 function OffsetPoint(const Pt, Delta: TPoint): TPoint; 640 begin 641 Result.X := Pt.X + Delta.X; 642 Result.Y := Pt.Y + Delta.Y; 643 end; 644 645 function PerpendicularDistance(const P, P1, P2: TPoint): TFloat; 646 begin 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); 649 end; 650 300 651 end.
Note:
See TracChangeset
for help on using the changeset viewer.