Skip to content

Commit e3baee4

Browse files
vil02ZoomRmc
andauthored
feat: add haversineDistance (#80)
* feat: add `haversineDistance` * style: avoid `return` Co-authored-by: Zoom <ZoomRmc@users.noreply.github.com> * style: rename to `isClose` --------- Co-authored-by: Zoom <ZoomRmc@users.noreply.github.com>
1 parent 6356202 commit e3baee4

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

maths/haversine_distance.nim

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Haversine formula
2+
3+
import std/math
4+
5+
func haversineDistance(latitudeA, longitudeA, latitudeB,
6+
longitudeB: float): float =
7+
## returns the length of the shortest path connecting the input points on an unit sphere.
8+
## The input points are represented by their spherical/geographical coordinates.
9+
## The inputs are expected to be in radians.
10+
let
11+
dLatitude = latitudeB - latitudeA
12+
dLongitude = longitudeB - longitudeA
13+
a = sin(dLatitude / 2.0)^2 + cos(latitudeA) * cos(latitudeB) * sin(
14+
dLongitude / 2.0)^2
15+
2.0 * arcsin(sqrt(a))
16+
17+
when isMainModule:
18+
import std/[unittest, sequtils, strformat]
19+
suite "haversineDistance":
20+
const testCases = [
21+
(0.0, 0.0, 0.0, 0.0, 0.0),
22+
(0.0, 0.0, PI / 2.0, 0.0, PI / 2.0),
23+
(-PI / 2.0, 0.0, PI / 2.0, 0.0, PI),
24+
(0.0, 0.0, 0.0, PI / 2.0, PI / 2.0),
25+
(0.0, -PI / 2.0, 0.0, PI / 2.0, PI),
26+
(1.0, -PI / 2.0, -1.0, PI / 2.0, PI),
27+
(2.0, -PI / 2.0, -2.0, PI / 2.0, PI),
28+
(3.0, -PI / 2.0, -3.0, PI / 2.0, PI),
29+
(3.0, -PI / 2.0 + 0.5, -3.0, PI / 2.0 + 0.5, PI),
30+
(0.0, 0.0, 0.0, PI, PI),
31+
(PI / 2.0, 1.0, PI / 2.0, 2.0, 0.0),
32+
(-PI / 2.0, 1.0, -PI / 2.0, 2.0, 0.0),
33+
(0.0, 0.0, -PI / 4.0, 0.0, PI / 4.0),
34+
(0.0, 1.0, PI / 4.0, 1.0, PI / 4.0),
35+
(-PI / 2.0, 0.0, -PI / 4.0, 0.0, PI / 4.0),
36+
(-PI / 2.0, 0.0, -PI / 4.0, 0.6, PI / 4.0),
37+
(-PI / 2.0, 3.0, -PI / 4.0, 0.2, PI / 4.0),
38+
].mapIt:
39+
(id: fmt"posA=({it[0]}, {it[1]}), posB=({it[2]}, {it[3]})",
40+
latitudeA: it[0], longitudeA: it[1],
41+
latitudeB: it[2], longitudeB: it[3],
42+
expected: it[4])
43+
44+
func isClose(a, b: float): bool =
45+
return abs(a-b) < 0.0000001
46+
47+
for tc in testCases:
48+
test tc.id:
49+
checkpoint("returns expected result")
50+
check isClose(haversineDistance(tc.latitudeA, tc.longitudeA,
51+
tc.latitudeB, tc.longitudeB), tc.expected)
52+
check isClose(haversineDistance(tc.latitudeB, tc.longitudeB,
53+
tc.latitudeA, tc.longitudeA), tc.expected)

0 commit comments

Comments
 (0)