vincenty_distance 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/vincenty.rb +106 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ee895e61add3011146f78ddedcba155e59d63acd
|
4
|
+
data.tar.gz: 306e3f4f06f5080c094ce5287a9afb2285f2e447
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a39fe6439a86f5c6c2481d075746702ef3f5305d3f4365da695a643436899b03a03affd6c12ebf52a7b97af49627561ebe63dfc48823a065229953cbab3ed637
|
7
|
+
data.tar.gz: 218cb0ded3da4216f231a26c576a609d35a6e75c1ddbc4e2d6e7897cc34903096ed81ebf473f11d040af6db30888bcc18f5a9bda821ef62a37d6dc22048d6c96
|
data/lib/vincenty.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
module Vincenty
|
2
|
+
class FailToConverge < StandardError; end
|
3
|
+
|
4
|
+
module Trigonometry
|
5
|
+
def deg_to_rad(angle_in_degrees)
|
6
|
+
angle_in_degrees * Math::PI / 180
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
extend Trigonometry
|
11
|
+
|
12
|
+
EQUATORIAL_RADIUS = 6_378_137.0
|
13
|
+
POLAR_RADIUS = 6_356_752.31424518
|
14
|
+
FLATTENING = (EQUATORIAL_RADIUS - POLAR_RADIUS) / EQUATORIAL_RADIUS
|
15
|
+
|
16
|
+
CONVERGENCE_THRESHOLD = 1e-12 # i.e. 0.06 mm error
|
17
|
+
MAX_ITERATIONS = 200
|
18
|
+
|
19
|
+
def distance_between_points(first, second)
|
20
|
+
lat1 = deg_to_rad(first[:latitude])
|
21
|
+
lon1 = deg_to_rad(first[:longitude])
|
22
|
+
lat2 = deg_to_rad(second[:latitude])
|
23
|
+
lon2 = deg_to_rad(second[:longitude])
|
24
|
+
|
25
|
+
return 0 if lat1 == lat2 && lon1 == lon2
|
26
|
+
|
27
|
+
lat1_sign = lat1.negative? ? -1 : 1
|
28
|
+
geodetic_lat1 = if (Math::PI / 2 - lat1.abs).abs < 1.0e-10
|
29
|
+
lat1_sign * (Math::PI / 2 - 1e-10)
|
30
|
+
else
|
31
|
+
lat1
|
32
|
+
end
|
33
|
+
|
34
|
+
lat2_sign = lat2.negative? ? -1 : 1
|
35
|
+
geodetic_lat2 = if (Math::PI / 2 - lat2.abs).abs < 1.0e-10
|
36
|
+
lat2_sign * (Math::PI / 2 - 1e-10)
|
37
|
+
else
|
38
|
+
lat2
|
39
|
+
end
|
40
|
+
|
41
|
+
difference_in_longitude = (lon2 - lon1).abs
|
42
|
+
if difference_in_longitude > Math::PI
|
43
|
+
difference_in_longitude = 2 * Math::PI - difference_in_longitude
|
44
|
+
end
|
45
|
+
|
46
|
+
# latitude on the auxiliary sphere
|
47
|
+
reduced_latitude1 = Math.atan((1 - FLATTENING) * Math.tan(geodetic_lat1))
|
48
|
+
reduced_latitude2 = Math.atan((1 - FLATTENING) * Math.tan(geodetic_lat2))
|
49
|
+
|
50
|
+
sin_reduced_latitude1 = Math.sin(reduced_latitude1)
|
51
|
+
cos_reduced_latitude1 = Math.cos(reduced_latitude1)
|
52
|
+
sin_reduced_latitude2 = Math.sin(reduced_latitude2)
|
53
|
+
cos_reduced_latitude2 = Math.cos(reduced_latitude2)
|
54
|
+
|
55
|
+
lambda_v = difference_in_longitude
|
56
|
+
iteration_index = 0
|
57
|
+
|
58
|
+
while iteration_index < MAX_ITERATIONS
|
59
|
+
sin_lambda_v = Math.sin(lambda_v)
|
60
|
+
cos_lambda_v = Math.cos(lambda_v)
|
61
|
+
|
62
|
+
sin_sigma = Math.sqrt(
|
63
|
+
(cos_reduced_latitude2 * sin_lambda_v)**2 +
|
64
|
+
(cos_reduced_latitude1 * sin_reduced_latitude2 -
|
65
|
+
sin_reduced_latitude1 * cos_reduced_latitude2 * cos_lambda_v)**2
|
66
|
+
)
|
67
|
+
|
68
|
+
cos_sigma =
|
69
|
+
sin_reduced_latitude1 * sin_reduced_latitude2 +
|
70
|
+
cos_reduced_latitude1 * cos_reduced_latitude2 * cos_lambda_v
|
71
|
+
|
72
|
+
sigma = Math.atan2(sin_sigma, cos_sigma)
|
73
|
+
sin_alpha = cos_reduced_latitude1 * cos_reduced_latitude2 * sin_lambda_v / sin_sigma
|
74
|
+
cos_sq_alpha = 1 - sin_alpha * sin_alpha
|
75
|
+
cos_2_sigma_m = cos_sigma - 2 * sin_reduced_latitude1 * sin_reduced_latitude2 / cos_sq_alpha
|
76
|
+
cos_2_sigma_m = 0 if cos_2_sigma_m.nan?
|
77
|
+
c = FLATTENING / 16 * cos_sq_alpha * (4 + FLATTENING * (4 - 3 * cos_sq_alpha))
|
78
|
+
|
79
|
+
lambda_prev = lambda_v
|
80
|
+
# use cos_2_sigma_m=0 when over equatorial lines
|
81
|
+
lambda_v =
|
82
|
+
difference_in_longitude +
|
83
|
+
(1 - c) * FLATTENING * sin_alpha * (sigma + c * sin_sigma *
|
84
|
+
(cos_2_sigma_m + c * cos_sigma *
|
85
|
+
(-1 + 2 * cos_2_sigma_m * cos_2_sigma_m)))
|
86
|
+
|
87
|
+
break if (lambda_v - lambda_prev).abs < CONVERGENCE_THRESHOLD
|
88
|
+
|
89
|
+
iteration_index += 1
|
90
|
+
end
|
91
|
+
|
92
|
+
raise FailToConverge if (lambda_v - lambda_prev).abs > CONVERGENCE_THRESHOLD
|
93
|
+
|
94
|
+
u_sq = cos_sq_alpha * (EQUATORIAL_RADIUS**2 - POLAR_RADIUS**2) / POLAR_RADIUS**2
|
95
|
+
a1 = 1 + u_sq / 16_384 * (4096 + u_sq * (-768 + u_sq * (320 - 175 * u_sq)))
|
96
|
+
b1 = u_sq / 1024 * (256 + u_sq * (-128 + u_sq * (74 - 47 * u_sq)))
|
97
|
+
delta_sigma = b1 * sin_sigma * (cos_2_sigma_m + b1 / 4 * (cos_sigma *
|
98
|
+
(-1 + 2 * cos_2_sigma_m * cos_2_sigma_m) - b1 / 6 * cos_2_sigma_m *
|
99
|
+
(-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * cos_2_sigma_m * cos_2_sigma_m)))
|
100
|
+
|
101
|
+
distance = POLAR_RADIUS * a1 * (sigma - delta_sigma)
|
102
|
+
|
103
|
+
return distance
|
104
|
+
end
|
105
|
+
module_function :distance_between_points
|
106
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vincenty_distance
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aleksandr Kunin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-28 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Calculate the geographical distance between 2 points with extreme accuracy.
|
14
|
+
email: skyksandr@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/vincenty.rb
|
20
|
+
homepage: https://github.com/skyderby/vincenty_distance
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.6.8
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Vincenty distance
|
44
|
+
test_files: []
|