source: trunk/Packages/Common/UGeometric.pas

Last change on this file was 10, checked in by chronos, 2 years ago
  • Modified: General UTest unit moved into Common package.
File size: 4.5 KB
Line 
1unit UGeometric;
2
3interface
4
5uses
6 Classes, SysUtils, Math;
7
8type
9 TPointArray = array of TPoint;
10
11function Distance(P1, P2: TPoint): Integer;
12function Dot(const P1, P2: TPoint): Double;
13function AddPoint(const P1, P2: TPoint): TPoint;
14function SubPoint(const P1, P2: TPoint): TPoint;
15function PointToLineDistance(const P, V, W: TPoint): Integer;
16function ComparePoint(P1, P2: TPoint): Boolean;
17function RotatePoint(Center, P: TPoint; Angle: Double): TPoint;
18function RotatePoints(Center: TPoint; P: TPointArray; Angle: Double): TPointArray;
19function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint;
20 out Intersection: TPoint): Boolean;
21function ArcTan2Point(Point: TPoint): Float;
22function ArcTanPoint(Point: TPoint): Float;
23function RectEquals(A, B: TRect): Boolean;
24function RectEnlarge(Rect: TRect; Value: Integer): TRect;
25function ShiftRect(ARect: TRect; Delta: TPoint): TRect;
26
27
28implementation
29
30function Distance(P1, P2: TPoint): Integer;
31begin
32 Result := Trunc(Sqrt(Sqr(P2.X - P1.X) + Sqr(P2.Y - P1.Y)));
33end;
34
35function Dot(const P1, P2: TPoint): Double;
36begin
37 Result := P1.X * P2.X + P1.Y * P2.Y;
38end;
39
40function AddPoint(const P1, P2: TPoint): TPoint;
41begin
42 Result.X := P1.X + P2.X;
43 Result.Y := P1.Y + P2.Y;
44end;
45
46function SubPoint(const P1, P2: TPoint): TPoint;
47begin
48 Result.X := P1.X - P2.X;
49 Result.Y := P1.Y - P2.Y;
50end;
51
52function PointToLineDistance(const P, V, W: TPoint): Integer;
53var
54 l2, t: Double;
55 tt: TPoint;
56begin
57 // Return minimum distance between line segment vw and point p
58 L2 := Distance(V, W); // i.e. |w-v|^2 - avoid a sqrt
59 L2 := Power(l2, 2);
60 if L2 = 0 then begin
61 Result := Distance(P, V); // v == w case
62 Exit;
63 end;
64 // Consider the line extending the segment, parameterized as v + t (w - v).
65 // We find projection of point p onto the line.
66 // It falls where t = [(p-v) . (w-v)] / |w-v|^2
67 T := Dot(SubPoint(P, V), SubPoint(W, V)) / L2;
68 if T < 0 then begin
69 Result := Distance(P, V); // Beyond the 'v' end of the segment
70 exit;
71 end
72 else if T > 1 then begin
73 Result := Distance(P, W); // Beyond the 'w' end of the segment
74 Exit;
75 end;
76 TT.X := Trunc(V.X + T * (W.X - V.X));
77 TT.Y := Trunc(V.Y + T * (W.Y - V.Y));
78 Result := Distance(P, TT);
79end;
80
81function ComparePoint(P1, P2: TPoint): Boolean;
82begin
83 Result := (P1.X = P2.X) and (P1.Y = P2.Y);
84end;
85
86function RotatePoint(Center, P: TPoint; Angle: Double): TPoint;
87begin
88 P := Point(P.X - Center.X, P.Y - Center.Y);
89 Result := Point(Center.X + Round(P.X * Cos(Angle) - P.Y * Sin(Angle)),
90 Center.Y + Round(P.X * Sin(Angle) + P.Y * Cos(Angle)));
91end;
92
93function RotatePoints(Center: TPoint; P: TPointArray; Angle: Double): TPointArray;
94var
95 I: Integer;
96begin
97 Result := Default(TPointArray);
98 SetLength(Result, Length(P));
99 for I := 0 to High(P) do
100 Result[I] := RotatePoint(Center, P[I], Angle);
101end;
102
103function LineIntersect(LineAP1, LineAP2, LineBP1, LineBP2: TPoint;
104 out Intersection: TPoint): Boolean;
105Var
106 LDetLineA, LDetLineB, LDetDivInv: Double;
107 LDiffLA, LDiffLB: TPoint;
108 D: Double;
109begin
110 if (LineAP1 = LineAP2) or (LineBP1 = LineBP2) then begin
111 Result := False;
112 Exit;
113 end;
114 LDetLineA := LineAP1.X * LineAP2.Y - LineAP1.Y * LineAP2.X;
115 LDetLineB := LineBP1.X * LineBP2.Y - LineBP1.Y * LineBP2.X;
116
117 LDiffLA := SubPoint(LineAP1, LineAP2);
118 LDiffLB := SubPoint(LineBP1, LineBP2);
119
120 D := ((LDiffLA.X * LDiffLB.Y) - (LDiffLA.Y * LDiffLB.X));
121 if D = 0 then begin
122 // Parallel lines without intersection
123 Result := False;
124 Exit;
125 end;
126 LDetDivInv := 1 / D;
127
128 Intersection.X := Trunc(((LDetLineA * LDiffLB.X) - (LDiffLA.X * LDetLineB)) * LDetDivInv);
129 Intersection.Y := Trunc(((LDetLineA * LDiffLB.Y) - (LDiffLA.Y * LDetLineB)) * LDetDivInv);
130 Result := True;
131end;
132
133function ArcTan2Point(Point: TPoint): Float;
134begin
135 Result := ArcTan2(Point.Y, Point.X);
136end;
137
138function ArcTanPoint(Point: TPoint): Float;
139begin
140 if Point.Y = 0 then Result := Infinity
141 else Result := ArcTan(Point.X / Point.Y);
142end;
143
144function RectEquals(A, B: TRect): Boolean;
145begin
146 Result := (A.Left = B.Left) and (A.Top = B.Top) and
147 (A.Right = B.Right) and (A.Bottom = B.Bottom);
148end;
149
150function RectEnlarge(Rect: TRect; Value: Integer): TRect;
151begin
152 Result.Left := Rect.Left - Value;
153 Result.Right := Rect.Right + Value;
154 Result.Top := Rect.Top - Value;
155 Result.Bottom := Rect.Bottom + Value;
156end;
157
158function ShiftRect(ARect: TRect; Delta: TPoint): TRect;
159begin
160 Result := Rect(ARect.Left + Delta.X, ARect.Top + Delta.Y,
161 ARect.Right + Delta.X, ARect.Bottom + Delta.Y);
162end;
163
164
165end.
166
Note: See TracBrowser for help on using the repository browser.