Skip to content

Commit 19d2dc1

Browse files
committed
Support multiple distance algorithms
1 parent 86ac787 commit 19d2dc1

File tree

7 files changed

+139
-51
lines changed

7 files changed

+139
-51
lines changed

Source/script/imports/simba.import_math.pas

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,38 @@ implementation
2626
Distance
2727
--------
2828
```
29-
function Distance(const X1, Y1, X2, Y2: Double): Double;
30-
```
29+
function Distance(X1, Y1, X2, Y2: Double; Algo: EDistanceAlgo = EDistanceAlgo.Euclidean): Double;
30+
```
31+
Calculates the distance between X1,Y1 and X2,Y2.
32+
If not provided the `Algo` parameter defaults to Euclidean.
33+
But can be any of these:
34+
- `EDistanceAlgo.Euclidean`
35+
- `EDistanceAlgo.EuclideanSq`
36+
- `EDistanceAlgo.Manhattan`
37+
- `EDistanceAlgo.Chebyshev`
3138
*)
32-
procedure _LapeDistance(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
39+
procedure _LapeDistance1(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
3340
begin
34-
PDouble(Result)^ := Distance(PDouble(Params^[0])^, PDouble(Params^[1])^, PDouble(Params^[2])^, PDouble(Params^[3])^);
41+
PDouble(Result)^ := Distance(PDouble(Params^[0])^, PDouble(Params^[1])^, PDouble(Params^[2])^, PDouble(Params^[3])^, EDistanceAlgo(Params^[4]^));
3542
end;
3643

3744
(*
3845
Distance
3946
--------
4047
```
41-
function Distance(const P1, P2: TPoint): Double;
48+
function Distance(P1, P2: TPoint; Algo: EDistanceAlgo = EDistanceAlgo.Euclidean): Double;
4249
```
50+
Calculates the distance between two points.
51+
If not provided the `Algo` parameter defaults to Euclidean.
52+
But can be any of these:
53+
- `EDistanceAlgo.Euclidean`
54+
- `EDistanceAlgo.EuclideanSq`
55+
- `EDistanceAlgo.Manhattan`
56+
- `EDistanceAlgo.Chebyshev`
4357
*)
44-
procedure _LapeDistanceEx(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
58+
procedure _LapeDistance2(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
4559
begin
46-
PDouble(Result)^ := Distance(PPoint(Params^[0])^, PPoint(Params^[1])^);
60+
PDouble(Result)^ := Distance(PPoint(Params^[0])^, PPoint(Params^[1])^, EDistanceAlgo(Params^[2]^));
4761
end;
4862

4963
(*
@@ -170,7 +184,7 @@ procedure _LapeLog10(const Params: PParamArray; const Result: Pointer); LAPE_WRA
170184
NextPower2
171185
----------
172186
```
173-
function NextPower2(const n: Integer): Integer;
187+
function NextPower2(n: Integer): Integer;
174188
```
175189
*)
176190
procedure _LapeNextPower2(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -182,7 +196,7 @@ procedure _LapeNextPower2(const Params: PParamArray; const Result: Pointer); LAP
182196
Modulo
183197
------
184198
```
185-
function Modulo(const X, Y: Integer): Integer;
199+
function Modulo(X, Y: Integer): Integer;
186200
```
187201
*)
188202
procedure _LapeModulo(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -194,7 +208,7 @@ procedure _LapeModulo(const Params: PParamArray; const Result: Pointer); LAPE_WR
194208
Modulo
195209
------
196210
```
197-
function Modulo(const X, Y: Double): Double;
211+
function Modulo(X, Y: Double): Double;
198212
```
199213
*)
200214
procedure _LapeModuloF(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -206,7 +220,7 @@ procedure _LapeModuloF(const Params: PParamArray; const Result: Pointer); LAPE_W
206220
DeltaAngle
207221
----------
208222
```
209-
function DeltaAngle(const DegreesA, DegreesB: Double; R: Double = 360): Double;
223+
function DeltaAngle(DegreesA, DegreesB: Double; R: Double = 360): Double;
210224
```
211225
*)
212226
procedure _LapeDeltaAngle(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -219,7 +233,7 @@ procedure _LapeDeltaAngle(const Params: PParamArray; const Result: Pointer); LAP
219233
CrossProduct
220234
------------
221235
```
222-
function CrossProduct(const r, p, q: TPoint): Int64;
236+
function CrossProduct(r, p, q: TPoint): Int64;
223237
```
224238
*)
225239
procedure _LapeCrossProduct1(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -231,7 +245,7 @@ procedure _LapeCrossProduct1(const Params: PParamArray; const Result: Pointer);
231245
CrossProduct
232246
------------
233247
```
234-
function CrossProduct(const rx,ry, px,py, qx,qy: Double): Double;
248+
function CrossProduct(rx,ry, px,py, qx,qy: Double): Double;
235249
```
236250
*)
237251
procedure _LapeCrossProduct2(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -243,7 +257,7 @@ procedure _LapeCrossProduct2(const Params: PParamArray; const Result: Pointer);
243257
LinesIntersect
244258
--------------
245259
```
246-
function LinesIntersect(const P1, P2, Q1, Q2: TPoint): Boolean;
260+
function LinesIntersect(P1, P2, Q1, Q2: TPoint): Boolean;
247261
```
248262
*)
249263
procedure _LapeLinesIntersect1(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -255,7 +269,7 @@ procedure _LapeLinesIntersect1(const Params: PParamArray; const Result: Pointer)
255269
LinesIntersect
256270
--------------
257271
```
258-
function LinesIntersect(const P1, P2, Q1, Q2: TPoint; out Where: TPoint): Boolean;
272+
function LinesIntersect(P1, P2, Q1, Q2: TPoint; out Where: TPoint): Boolean;
259273
```
260274
*)
261275
procedure _LapeLinesIntersect2(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -267,7 +281,7 @@ procedure _LapeLinesIntersect2(const Params: PParamArray; const Result: Pointer)
267281
DistToLine
268282
----------
269283
```
270-
function DistToLine(const P, P1, P2: TPoint; out Nearest: TPoint): Double;
284+
function DistToLine(P, P1, P2: TPoint; out Nearest: TPoint): Double;
271285
```
272286
*)
273287
procedure _LapeDistToLine1(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -279,7 +293,7 @@ procedure _LapeDistToLine1(const Params: PParamArray; const Result: Pointer); LA
279293
DistToLine
280294
----------
281295
```
282-
function DistToLine(const P, P1, P2: TPoint): Double;
296+
function DistToLine(P, P1, P2: TPoint): Double;
283297
```
284298
*)
285299
procedure _LapeDistToLine2(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -291,7 +305,7 @@ procedure _LapeDistToLine2(const Params: PParamArray; const Result: Pointer); LA
291305
IsNumber
292306
--------
293307
```
294-
function IsNumber(const Value: Single): Boolean;
308+
function IsNumber(Value: Single): Boolean;
295309
```
296310
*)
297311
procedure _LapeIsNumberS(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV
@@ -322,11 +336,13 @@ procedure ImportMath(Script: TSimbaScript);
322336
addGlobalVar(SQRT_3, 'SQRT_3').isConstant := True;
323337
addGlobalVar(SQRT_5, 'SQRT_5').isConstant := True;
324338

325-
addGlobalFunc('function IsNumber(const Value: Single): Boolean; overload', @_LapeIsNumberS);
326-
addGlobalFunc('function IsNumber(const Value: Double): Boolean; overload', @_LapeIsNumberD);
339+
addGlobalType('enum(Euclidean, EuclideanSq, Manhattan, Chebyshev)', 'EDistanceAlgo');
340+
341+
addGlobalFunc('function IsNumber(Value: Single): Boolean; overload', @_LapeIsNumberS);
342+
addGlobalFunc('function IsNumber(Value: Double): Boolean; overload', @_LapeIsNumberD);
327343

328-
addGlobalFunc('function Distance(const X1, Y1, X2, Y2: Double): Double; overload', @_LapeDistance);
329-
addGlobalFunc('function Distance(const P1, P2: TPoint): Double; overload', @_LapeDistanceEx);
344+
addGlobalFunc('function Distance(X1, Y1, X2, Y2: Double; Algo: EDistanceAlgo = EDistanceAlgo.Euclidean): Double; overload', @_LapeDistance1);
345+
addGlobalFunc('function Distance(P1, P2: TPoint; Algo: EDistanceAlgo = EDistanceAlgo.Euclidean): Double; overload', @_LapeDistance2);
330346

331347
addGlobalFunc('function Sar(x: Integer; Shift: Byte): Integer', @_LapeSar);
332348
addGlobalFunc('function Ror(x: UInt32; Shift: Byte): UInt32', @_LapeRor);
@@ -346,15 +362,15 @@ procedure ImportMath(Script: TSimbaScript);
346362
addGlobalFunc('function Modulo(const X, Y: Integer): Integer; overload', @_LapeModulo);
347363
addGlobalFunc('function Modulo(const X, Y: Double): Double; overload', @_LapeModuloF);
348364

349-
addGlobalFunc('function DeltaAngle(const DegreesA, DegreesB: Double; R: Double = 360): Double', @_LapeDeltaAngle);
365+
addGlobalFunc('function DeltaAngle(DegreesA, DegreesB: Double; R: Double = 360): Double', @_LapeDeltaAngle);
350366

351-
addGlobalFunc('function CrossProduct(const r, p, q: TPoint): Int64; overload', @_LapeCrossProduct1);
352-
addGlobalFunc('function CrossProduct(const rx,ry, px,py, qx,qy: Double): Double; overload', @_LapeCrossProduct2);
353-
addGlobalFunc('function LinesIntersect(const P1, P2, Q1, Q2: TPoint): Boolean; overload', @_LapeLinesIntersect1);
354-
addGlobalFunc('function LinesIntersect(const P1, P2, Q1, Q2: TPoint; out Where: TPoint): Boolean; overload', @_LapeLinesIntersect2);
367+
addGlobalFunc('function CrossProduct(r, p, q: TPoint): Int64; overload', @_LapeCrossProduct1);
368+
addGlobalFunc('function CrossProduct(rx,ry, px,py, qx,qy: Double): Double; overload', @_LapeCrossProduct2);
369+
addGlobalFunc('function LinesIntersect(P1, P2, Q1, Q2: TPoint): Boolean; overload', @_LapeLinesIntersect1);
370+
addGlobalFunc('function LinesIntersect(P1, P2, Q1, Q2: TPoint; out Where: TPoint): Boolean; overload', @_LapeLinesIntersect2);
355371

356-
addGlobalFunc('function DistToLine(const P, P1, P2: TPoint; out Nearest: TPoint): Double; overload', @_LapeDistToLine1);
357-
addGlobalFunc('function DistToLine(const P, P1, P2: TPoint): Double; overload', @_LapeDistToLine2);
372+
addGlobalFunc('function DistToLine(P, P1, P2: TPoint; out Nearest: TPoint): Double; overload', @_LapeDistToLine1);
373+
addGlobalFunc('function DistToLine(P, P1, P2: TPoint): Double; overload', @_LapeDistToLine2);
358374

359375
DumpSection := '';
360376
end;

Source/simba.math.pas

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,30 @@ interface
1919
SQRT_3 = Double(1.73205080756888);
2020
SQRT_5 = Double(2.23606797749979);
2121

22-
function Distance(const P1,P2: TPoint): Double; overload; inline;
23-
function Distance(const X1,Y1,X2,Y2: Double): Double; overload; inline;
22+
{$scopedenums on}
23+
type
24+
EDistanceAlgo = (
25+
Euclidean,
26+
EuclideanSq,
27+
Manhattan,
28+
Chebyshev
29+
);
30+
{$scopedenums off}
31+
32+
function Distance(const P1,P2: TPoint; Algo: EDistanceAlgo): Single; overload;
33+
function Distance(const X1,Y1,X2,Y2: Double; Algo: EDistanceAlgo): Single; overload;
34+
35+
function DistEuclidean(const P1,P2: TPoint): Single; inline; overload;
36+
function DistEuclidean(const X1,Y1,X2,Y2: Double): Single; inline; overload;
37+
38+
function DistEuclideanSq(const P1,P2: TPoint): Single; inline; overload;
39+
function DistEuclideanSq(const X1,Y1,X2,Y2: Double): Single; inline; overload;
40+
41+
function DistManhattan(const P1,P2: TPoint): Single; inline; overload;
42+
function DistManhattan(const X1,Y1,X2,Y2: Double): Single; inline; overload;
43+
44+
function DistChebyshev(const P1,P2: TPoint): Single; inline; overload;
45+
function DistChebyshev(const X1,Y1,X2,Y2: Double): Single; inline; overload;
2446

2547
function NextPower2(const n: Integer): Integer;
2648

@@ -38,14 +60,75 @@ implementation
3860
uses
3961
Math;
4062

63+
function Distance(const P1, P2: TPoint; Algo: EDistanceAlgo): Single;
64+
begin
65+
case Algo of
66+
EDistanceAlgo.Euclidean: Result := DistEuclidean(P1, P2);
67+
EDistanceAlgo.EuclideanSq: Result := DistEuclideanSq(P1, P2);
68+
EDistanceAlgo.Chebyshev: Result := DistChebyshev(P1, P2);
69+
EDistanceAlgo.Manhattan: Result := DistManhattan(P1, P2);
70+
end;
71+
end;
72+
73+
function Distance(const X1, Y1, X2, Y2: Double; Algo: EDistanceAlgo): Single;
74+
begin
75+
case Algo of
76+
EDistanceAlgo.Euclidean: Result := DistEuclidean(X1, Y1, X2, Y2);
77+
EDistanceAlgo.EuclideanSq: Result := DistEuclideanSq(X1, Y1, X2, Y2);
78+
EDistanceAlgo.Chebyshev: Result := DistChebyshev(X1, Y1, X2, Y2);
79+
EDistanceAlgo.Manhattan: Result := DistManhattan(X1, Y1, X2, Y2);
80+
end;
81+
end;
82+
83+
function DistEuclidean(const P1,P2: TPoint): Single;
84+
begin
85+
// use Double to prevent integer overflows
86+
Result := Sqrt(Sqr(Double(P1.X) - Double(P2.X)) + Sqr(Double(P1.Y) - Double(P2.Y)));
87+
end;
88+
89+
function DistEuclidean(const X1,Y1,X2,Y2: Double): Single;
90+
begin
91+
Result := Sqrt(Sqr(X2 - X1) + Sqr(Y2 - Y1));
92+
end;
93+
94+
function DistEuclideanSq(const P1,P2: TPoint): Single;
95+
begin
96+
Result := Sqr(Double(P1.X) - Double(P2.X)) + Sqr(Double(P1.Y) - Double(P2.Y));
97+
end;
98+
99+
function DistEuclideanSq(const X1,Y1,X2,Y2: Double): Single;
100+
begin
101+
Result := Sqr(X1-X2) + Sqr(Y1-Y2);
102+
end;
103+
104+
function DistManhattan(const P1,P2: TPoint): Single;
105+
begin
106+
Result := Abs(Double(P1.X) - Double(P2.X)) + Abs(Double(P1.Y) - Double(P2.Y));
107+
end;
108+
109+
function DistManhattan(const X1,Y1,X2,Y2: Double): Single;
110+
begin
111+
Result := Abs(X1-X2) + Abs(Y1-Y2);
112+
end;
113+
114+
function DistChebyshev(const P1,P2: TPoint): Single;
115+
begin
116+
Result := Max(Abs(Double(P1.X) - Double(P2.X)), Abs(Double(P1.Y) - Double(P2.Y)));
117+
end;
118+
119+
function DistChebyshev(const X1,Y1,X2,Y2: Double): Single;
120+
begin
121+
Result := Max(Abs(X1 - X2), Abs(Y1 - Y2));
122+
end;
123+
41124
function IsNumber(const n: Double): Boolean;
42125
begin
43126
Result := (not IsNan(n)) and (not IsInfinite(n));
44127
end;
45128

46129
function IsNumber(const n: Single): Boolean;
47130
begin
48-
Result := (LongWord(n) and $7fffffff) < $7f800000; // Result := (not IsNan(n)) and (not IsInfinite(n));
131+
Result := (LongWord(n) and $7FFFFFFF) < $7F800000; // Result := (not IsNan(n)) and (not IsInfinite(n));
49132
end;
50133

51134
function Modulo(const X, Y: Double): Double;
@@ -75,16 +158,6 @@ function NextPower2(const n: Integer): Integer;
75158
Result := Result + 1;
76159
end;
77160

78-
function Distance(const P1, P2: TPoint): Double;
79-
begin
80-
Result := Sqrt(Sqr(Double(P2.X) - Double(P1.X)) + Sqr(Double(P2.Y) - Double(P1.Y))); // convert to Double to prevent integer overflows
81-
end;
82-
83-
function Distance(const X1, Y1, X2, Y2: Double): Double;
84-
begin
85-
Result := Sqrt(Sqr(X2 - X1) + Sqr(Y2 - Y1));
86-
end;
87-
88161
function CeilTo(const n: Double; const Precision: Int8 = 0): Double;
89162
begin
90163
if (Precision = 0) then
@@ -94,4 +167,3 @@ function CeilTo(const n: Double; const Precision: Int8 = 0): Double;
94167
end;
95168

96169
end.
97-

Source/simba.vartype_box.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ function TBoxArrayHelper.SortFrom(From: TPoint): TBoxArray;
395395
begin
396396
SetLength(Weights, Length(Self));
397397
for I := 0 to High(Weights) do
398-
Weights[I] := Distance(From, Self[I].Center);
398+
Weights[I] := DistEuclidean(From, Self[I].Center);
399399

400400
Result := Self.Sort(Weights);
401401
end;

Source/simba.vartype_circle.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class function TCircleHelper.CreateFromPoints(Points: TPointArray): TCircle;
108108

109109
function TCircleHelper.Contains(const P: TPoint): Boolean;
110110
begin
111-
Result := Distance(X, Y, P.X, P.Y) <= Radius;
111+
Result := DistEuclidean(X, Y, P.X, P.Y) <= Radius;
112112
end;
113113

114114
function TCircleHelper.PointAtDegrees(Degrees: Double): TPoint;

Source/simba.vartype_pointarray.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1663,7 +1663,7 @@ function TPointArrayHelper.IsPointNearby(Other: TPoint; MinDist, MaxDist: Double
16631663
I: Integer;
16641664
begin
16651665
for I := 0 to High(Self) do
1666-
if InRange(Distance(Self[I], Other), MinDist, MaxDist) then
1666+
if InRange(DistEuclidean(Self[I], Other), MinDist, MaxDist) then
16671667
Exit(True);
16681668

16691669
Result := False;

Source/simba.vartype_quad.pas

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ function TQuadHelper.GetMean: TPoint;
173173

174174
function TQuadHelper.GetArea: Integer;
175175
begin
176-
Result := Round(Distance(Self.Bottom, Self.Right)) * Round(Distance(Self.Bottom, Self.Left));
176+
Result := Round(DistEuclidean(Self.Bottom, Self.Right)) * Round(DistEuclidean(Self.Bottom, Self.Left));
177177
end;
178178

179179
function TQuadHelper.Rotate(Radians: Double): TQuad;
@@ -333,7 +333,7 @@ function TQuadArrayHelper.SortFrom(From: TPoint): TQuadArray;
333333
begin
334334
SetLength(Weights, Length(Self));
335335
for I := 0 to High(Weights) do
336-
Weights[I] := Distance(From, Self[I].Mean);
336+
Weights[I] := DistEuclidean(From, Self[I].Mean);
337337

338338
Result := Self.Sort(Weights);
339339
end;

Source/simba.vartype_triangle.pas

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ function TTriangleHelper.Incenter(): TPoint;
145145
var
146146
ar, br, cr: Single;
147147
begin
148-
ar := Distance(B, C);
149-
br := Distance(A, C);
150-
cr := Distance(A, B);
148+
ar := DistEuclidean(B, C);
149+
br := DistEuclidean(A, C);
150+
cr := DistEuclidean(A, B);
151151

152152
Result.x := Round((ar * A.x + br * B.x + cr * C.x) / (ar + br + cr));
153153
Result.y := Round((ar * A.y + br * B.y + cr * C.y) / (ar + br + cr));

0 commit comments

Comments
 (0)