vincenty 1.0.6 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/History.txt +34 -0
- data/README.md +3 -3
- data/Rakefile +17 -10
- data/lib/angle.rb +178 -194
- data/lib/coordinate.rb +18 -19
- data/lib/core_extensions.rb +40 -59
- data/lib/latitude.rb +24 -26
- data/lib/longitude.rb +16 -20
- data/lib/track_and_distance.rb +36 -37
- data/lib/vincenty.rb +137 -128
- data/test/ts_all.rb +8 -9
- data/test/ts_angle.rb +49 -48
- data/test/ts_coordinate.rb +6 -5
- data/test/ts_latitude.rb +10 -7
- data/test/ts_longitude.rb +10 -7
- data/test/ts_track_and_distance.rb +12 -9
- data/test/ts_vincenty.rb +74 -65
- metadata +12 -14
- data/.gemtest +0 -0
data/lib/vincenty.rb
CHANGED
@@ -1,192 +1,201 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#Vincenty's algorithms for finding the bearing and distance between two coordinates and
|
9
|
-
#for finding the latitude and longitude, given a start coordinate, distance and bearing.
|
1
|
+
require_relative 'core_extensions.rb'
|
2
|
+
require_relative 'angle.rb'
|
3
|
+
require_relative 'latitude.rb'
|
4
|
+
require_relative 'longitude.rb'
|
5
|
+
require_relative 'track_and_distance.rb'
|
6
|
+
require_relative 'coordinate.rb'
|
7
|
+
|
8
|
+
# Vincenty's algorithms for finding the bearing and distance between two coordinates and
|
9
|
+
# for finding the latitude and longitude, given a start coordinate, distance and bearing.
|
10
10
|
#
|
11
11
|
# Coded from formulae from Wikipedia http://en.wikipedia.org/wiki/Vincenty%27s_formulae
|
12
12
|
# Modified to incorporate corrections to formulae as found in script on http://www.movable-type.co.uk/scripts/LatLongVincenty.html
|
13
13
|
# Added my Modification of the distanceAndAngle formulae to correct the compass bearing.
|
14
14
|
class Vincenty < Coordinate
|
15
|
-
VERSION = '1.0.
|
16
|
-
|
15
|
+
VERSION = '1.0.10'
|
16
|
+
|
17
17
|
# @return [String] constant VERSION
|
18
18
|
def version
|
19
19
|
VERSION
|
20
20
|
end
|
21
|
-
|
22
|
-
#
|
23
|
-
|
24
|
-
|
21
|
+
|
22
|
+
WGS84_ER = 6378137 # Equatorial Radius of earth
|
23
|
+
WGS84_IF = 298.257223563 # Inverse Flattening
|
24
|
+
GRS80_ER = 6378137 # Equatorial Radius of earth
|
25
|
+
GRS80_IF = 298.25722210882711 # Inverse Flattening
|
26
|
+
|
27
|
+
# Great Circle formulae http://en.wikipedia.org/wiki/Great-circle_distance
|
28
|
+
# Reference calculation for testing, assumes the earth is a sphere, which it isn't.
|
29
|
+
# This gives us an approximation to verify Vincenty algorithm.
|
25
30
|
# @param [Coordinate] p2 is target coordinate that we want the bearing to.
|
26
31
|
# @return [TrackAndDistance] with the compass bearing and distance in meters to P2
|
27
|
-
def sphericalDistanceAndAngle( p2 )
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
def sphericalDistanceAndAngle( p2, equatorial_radius = WGS84_ER, inverse_flattening = WGS84_IF )
|
33
|
+
if self.latitude == p2.latitude && self.longitude == p2.longitude
|
34
|
+
return TrackAndDistance.new(0, 0, true) # No calculations necessary
|
35
|
+
end
|
36
|
+
|
37
|
+
a = equatorial_radius # equatorial radius in meters (+/-2 m)
|
38
|
+
f = inverse_flattening
|
39
|
+
b = a - a / f # WGS84 = 6356752.314245179 polar radius in meters
|
40
|
+
r = (a + b) / 2 # average diametre as a rough estimate for our tests.
|
41
|
+
|
32
42
|
sin_lat1 = Math.sin(@latitude.to_rad)
|
33
43
|
sin_lat2 = Math.sin(p2.latitude.to_rad)
|
34
44
|
cos_lat1 = Math.cos(@latitude.to_rad)
|
35
45
|
atan1_2 = Math.atan(1) * 2
|
36
|
-
t1 = cos_lat1 * Math.cos(p2.latitude.to_rad) *
|
37
|
-
angular_distance = Math.atan(-t1/Math.sqrt(-t1 * t1 +1)) + atan1_2 #central angle in radians so we can calculate the arc length.
|
46
|
+
t1 = cos_lat1 * Math.cos(p2.latitude.to_rad) * Math.cos(@longitude.to_rad - p2.longitude.to_rad) + sin_lat1 * sin_lat2
|
47
|
+
angular_distance = Math.atan(-t1 / Math.sqrt(-t1 * t1 + 1)) + atan1_2 # central angle in radians so we can calculate the arc length.
|
38
48
|
|
39
49
|
t2 = (sin_lat2 - sin_lat1 * Math.cos(angular_distance)) / (cos_lat1 * Math.sin(angular_distance))
|
40
|
-
if
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
50
|
+
bearing = if Math.sin(p2.longitude.to_rad - @longitude.to_rad) < 0
|
51
|
+
2 * Math::PI - (Math.atan(-t2 / Math.sqrt(-t2 * t2 + 1)) + atan1_2) # Compass Bearing in radians (clockwise)
|
52
|
+
else
|
53
|
+
Math.atan(-t2 / Math.sqrt(-t2 * t2 + 1)) + atan1_2 # Compass Bearing in radians (clockwise)
|
54
|
+
end
|
45
55
|
|
46
|
-
#Note that the bearing is a compass angle. That is angles are positive clockwise.
|
56
|
+
# Note that the bearing is a compass angle. That is angles are positive clockwise.
|
47
57
|
return TrackAndDistance.new(bearing, angular_distance * r, true)
|
48
58
|
end
|
49
59
|
|
50
|
-
#Vincenty's algorithm for finding bearing and distance between to coordinates.
|
51
|
-
#Assumes earth is a WGS-84 Ellipsod.
|
60
|
+
# Vincenty's algorithm for finding bearing and distance between to coordinates.
|
61
|
+
# Assumes earth is a WGS-84 Ellipsod.
|
52
62
|
# @param [Coordinate] p2 is target coordinate that we want the bearing to.
|
53
63
|
# @return [TrackAndDistance] with the compass bearing and distance in meters to P2
|
54
64
|
def distanceAndAngle( p2 )
|
65
|
+
if self.latitude == p2.latitude && self.longitude == p2.longitude
|
66
|
+
return TrackAndDistance.new(0, 0, true) # No calculations necessary. Solv NAN issue
|
67
|
+
end
|
68
|
+
|
55
69
|
# a, b = major & minor semiaxes of the ellipsoid
|
56
|
-
a = 6378137 #equatorial radius in meters (+/-2 m)
|
57
|
-
b = 6356752.31424518 #polar radius in meters
|
58
|
-
f = (a-b)/a # flattening
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
70
|
+
a = 6378137 # equatorial radius in meters (+/-2 m)
|
71
|
+
b = 6356752.31424518 # polar radius in meters
|
72
|
+
f = (a - b) / a # flattening
|
73
|
+
|
74
|
+
lat1 = @latitude.to_rad
|
75
|
+
lon1 = @longitude.to_rad
|
76
|
+
lat2 = p2.latitude.to_rad
|
77
|
+
lon2 = p2.longitude.to_rad
|
78
|
+
lat1 = lat1.sign * (Math::PI / 2 - 1e-10) if (Math::PI / 2 - lat1.abs).abs < 1.0e-10
|
79
|
+
lat2 = lat2.sign * (Math::PI / 2 - 1e-10) if (Math::PI / 2 - lat2.abs).abs < 1.0e-10
|
66
80
|
|
67
81
|
# lat1, lat2 = geodetic latitude
|
68
|
-
|
69
|
-
l = (lon2 - lon1).abs #difference in longitude
|
70
|
-
l = 2*Math::PI - l if l > Math::PI
|
71
|
-
u1 = Math.atan( ( 1 - f) * Math.tan( lat1 ) ) #U is 'reduced latitude'
|
72
|
-
u2 = Math.atan( ( 1 - f) * Math.tan( lat2 ) )
|
73
|
-
sin_u1 = Math.sin(u1)
|
74
|
-
cos_u1 = Math.cos(u1)
|
75
|
-
sin_u2 = Math.sin(u2)
|
76
|
-
cos_u2 = Math.cos(u2)
|
77
|
-
|
78
|
-
lambda_v = l
|
79
|
-
lambda_dash = Math::PI * 2
|
80
|
-
while( (lambda_v - lambda_dash).abs > 1.0e-12 ) #i.e. 0.06 mm error
|
81
|
-
sin_lambda_v = Math.sin(lambda_v)
|
82
|
-
cos_lambda_v = Math.cos(lambda_v)
|
83
|
-
sin_sigma = Math.sqrt( ( cos_u2 * sin_lambda_v ) ** 2 + ( cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda_v ) ** 2 )
|
84
|
-
cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda_v
|
85
|
-
sigma = Math.atan2(sin_sigma, cos_sigma)
|
86
|
-
sin_alpha= cos_u1 * cos_u2 * sin_lambda_v / sin_sigma
|
87
|
-
cos_2_alpha = 1 - sin_alpha * sin_alpha #trig identity
|
88
|
-
cos_2_sigma_m = cos_sigma - 2 * sin_u1 * sin_u2/cos_2_alpha
|
89
|
-
c = f / 16 * cos_2_alpha * (4 + f*(4-3*cos_2_alpha))
|
90
|
-
lambda_dash = lambda_v
|
91
|
-
lambda_v = l + (1-c) * f * sin_alpha * (sigma + c * sin_sigma * (cos_2_sigma_m + c * cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m) ) ) # use cos_2_sigma_m=0 when over equatorial lines
|
92
|
-
if lambda_v > Math::PI
|
93
|
-
lambda_v = Math::PI
|
94
|
-
break
|
95
|
-
end
|
96
|
-
end
|
97
82
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
83
|
+
l = (lon2 - lon1).abs # difference in longitude
|
84
|
+
l = 2 * Math::PI - l if l > Math::PI
|
85
|
+
u1 = Math.atan( ( 1 - f) * Math.tan( lat1 ) ) # U is 'reduced latitude'
|
86
|
+
u2 = Math.atan( ( 1 - f) * Math.tan( lat2 ) )
|
87
|
+
sin_u1 = Math.sin(u1)
|
88
|
+
cos_u1 = Math.cos(u1)
|
89
|
+
sin_u2 = Math.sin(u2)
|
90
|
+
cos_u2 = Math.cos(u2)
|
91
|
+
|
92
|
+
lambda_v = l
|
93
|
+
lambda_dash = Math::PI * 2
|
94
|
+
while (lambda_v - lambda_dash).abs > 1.0e-12 # i.e. 0.06 mm error
|
103
95
|
sin_lambda_v = Math.sin(lambda_v)
|
104
96
|
cos_lambda_v = Math.cos(lambda_v)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
97
|
+
sin_sigma = Math.sqrt( ( cos_u2 * sin_lambda_v )**2 + ( cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda_v )**2 )
|
98
|
+
cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda_v
|
99
|
+
sigma = Math.atan2(sin_sigma, cos_sigma)
|
100
|
+
sin_alpha = cos_u1 * cos_u2 * sin_lambda_v / sin_sigma
|
101
|
+
cos_2_alpha = 1 - sin_alpha * sin_alpha # trig identity
|
102
|
+
cos_2_sigma_m = cos_sigma - 2 * sin_u1 * sin_u2 / cos_2_alpha
|
103
|
+
c = f / 16 * cos_2_alpha * (4 + f * (4 - 3 * cos_2_alpha))
|
104
|
+
lambda_dash = lambda_v
|
105
|
+
lambda_v = l + (1 - c) * f * sin_alpha * (sigma + c * sin_sigma * (cos_2_sigma_m + c * cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m) ) ) # use cos_2_sigma_m=0 when over equatorial lines
|
106
|
+
if lambda_v > Math::PI
|
107
|
+
lambda_v = Math::PI
|
108
|
+
break
|
114
109
|
end
|
115
|
-
|
116
|
-
|
117
|
-
|
110
|
+
end
|
111
|
+
|
112
|
+
u_2 = cos_2_alpha * (a * a - b * b) / (b * b)
|
113
|
+
a1 = 1 + u_2 / 16384 * (4096 + u_2 * (-768 + u_2 * (320 - 175 * u_2)))
|
114
|
+
b1 = u_2 / 1024 * (256 + u_2 * (-128 + u_2 * (74 - 47 * u_2)))
|
115
|
+
delta_sigma = b1 * sin_sigma * (cos_2_sigma_m + b1 / 4 * (cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m) - b1 / 6 * cos_2_sigma_m * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * cos_2_sigma_m * cos_2_sigma_m)))
|
116
|
+
s = b * a1 * (sigma - delta_sigma)
|
117
|
+
sin_lambda_v = Math.sin(lambda_v)
|
118
|
+
cos_lambda_v = Math.cos(lambda_v)
|
119
|
+
|
120
|
+
# This test isn't in original formulae, and fixes the problem of all angles returned being between 0 - PI (0-180)
|
121
|
+
# Also converts the result to compass bearing, rather than the mathmatical anticlockwise angles.
|
122
|
+
alpha_1 = if Math.sin(p2.longitude.to_rad - @longitude.to_rad) < 0
|
123
|
+
Math::PI * 2 - Math.atan2( cos_u2 * sin_lambda_v, cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda_v)
|
124
|
+
# alpha_2 = Math::PI*2-Math.atan2(cos_u1 * sin_lambda_v, -sin_u1 * cos_u2 + cos_u1 * sin_u2 * cos_lambda_v)
|
125
|
+
else
|
126
|
+
Math.atan2( cos_u2 * sin_lambda_v, cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda_v)
|
127
|
+
# alpha_2 = Math.atan2(cos_u1 * sin_lambda_v, -sin_u1 * cos_u2 + cos_u1 * sin_u2 * cos_lambda_v)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Note that the bearing is a compass (i.e. clockwise) angle.
|
131
|
+
return TrackAndDistance.new(alpha_1, s, true) # What to do with alpha_2?
|
118
132
|
end
|
119
133
|
|
120
|
-
#spherical earth estimate of calculation for finding target coordinate from start coordinate, bearing and distance
|
121
|
-
#Used to run checks on the Vincenty algorithm
|
134
|
+
# spherical earth estimate of calculation for finding target coordinate from start coordinate, bearing and distance
|
135
|
+
# Used to run checks on the Vincenty algorithm
|
122
136
|
# @param [TrackAndDistance] track_and_distance specifying bearing and distance.
|
123
137
|
# @return [Vincenty] with the destination coordinates.
|
124
138
|
def sphereDestination( track_and_distance )
|
125
|
-
a = 6378137 #equatorial radius in meters (+/-2 m)
|
126
|
-
b = 6356752.31424518 #polar radius in meters
|
127
|
-
r = (a+b)/2 #average diametre as a rough estimate for our tests.
|
128
|
-
|
139
|
+
a = 6378137 # equatorial radius in meters (+/-2 m)
|
140
|
+
b = 6356752.31424518 # polar radius in meters
|
141
|
+
r = (a + b) / 2 # average diametre as a rough estimate for our tests.
|
142
|
+
|
129
143
|
d = track_and_distance.distance.abs
|
130
|
-
sin_dor = Math.sin(d/r)
|
131
|
-
cos_dor = Math.cos(d/r)
|
144
|
+
sin_dor = Math.sin(d / r)
|
145
|
+
cos_dor = Math.cos(d / r)
|
132
146
|
sin_lat1 = Math.sin(@latitude.to_rad)
|
133
147
|
cos_lat1 = Math.cos(@latitude.to_rad)
|
134
148
|
lat2 = Math.asin( sin_lat1 * cos_dor + cos_lat1 * sin_dor * Math.cos(track_and_distance.bearing.to_rad) )
|
135
|
-
lon2 = @longitude.to_rad + Math.atan2(Math.sin(track_and_distance.bearing.to_rad) * sin_dor * cos_lat1, cos_dor-sin_lat1 * Math.sin(lat2))
|
136
|
-
|
137
|
-
Vincenty.new(lat2, lon2, 0, true)
|
149
|
+
lon2 = @longitude.to_rad + Math.atan2(Math.sin(track_and_distance.bearing.to_rad) * sin_dor * cos_lat1, cos_dor - sin_lat1 * Math.sin(lat2))
|
150
|
+
|
151
|
+
Vincenty.new(lat2, lon2, 0, true)
|
138
152
|
end
|
139
153
|
|
140
154
|
#
|
141
155
|
# Calculate destination point given start point lat/long, bearing and distance.
|
142
|
-
#Assumes earth is a WGS-84 Ellipsod.
|
156
|
+
# Assumes earth is a WGS-84 Ellipsod.
|
143
157
|
# @param [TrackAndDistance] specifying bearing and distance.
|
144
158
|
# @return [Vincenty] with the destination coordinates.
|
145
|
-
def destination( track_and_distance )
|
159
|
+
def destination( track_and_distance )
|
146
160
|
# a, b = major & minor semiaxes of the ellipsoid
|
147
|
-
a = 6378137 #equatorial radius in meters (+/-2 m)
|
148
|
-
b = 6356752.31424518 #polar radius in meters
|
149
|
-
f = (a-b)/a # flattening
|
150
|
-
|
151
|
-
s = track_and_distance.distance.abs
|
161
|
+
a = 6378137 # equatorial radius in meters (+/-2 m)
|
162
|
+
b = 6356752.31424518 # polar radius in meters
|
163
|
+
f = (a - b) / a # flattening
|
164
|
+
|
165
|
+
s = track_and_distance.distance.abs
|
152
166
|
alpha1 = track_and_distance.bearing.to_rad
|
153
167
|
sin_alpha1 = Math.sin(alpha1)
|
154
168
|
cos_alpha1 = Math.cos(alpha1)
|
155
|
-
|
156
|
-
tanU1 = (1-f)
|
157
|
-
cosU1 = 1 / Math.sqrt((1
|
169
|
+
|
170
|
+
tanU1 = (1 - f) * Math.tan(@latitude.to_rad)
|
171
|
+
cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1))
|
158
172
|
sinU1 = tanU1 * cosU1
|
159
173
|
sigma1 = Math.atan2(tanU1, cos_alpha1)
|
160
|
-
sin_alpha = cosU1
|
161
|
-
cos_2_alpha = 1 - sin_alpha * sin_alpha #Trig identity
|
162
|
-
u_2 = cos_2_alpha
|
163
|
-
a1 = 1
|
164
|
-
b1 = u_2/1024
|
165
|
-
|
174
|
+
sin_alpha = cosU1 * sin_alpha1
|
175
|
+
cos_2_alpha = 1 - sin_alpha * sin_alpha # Trig identity
|
176
|
+
u_2 = cos_2_alpha * (a * a - b * b) / (b * b)
|
177
|
+
a1 = 1 + u_2 / 16384 * (4096 + u_2 * (-768 + u_2 * (320 - 175 * u_2)))
|
178
|
+
b1 = u_2 / 1024 * (256 + u_2 * (-128 + u_2 * (74 - 47 * u_2)))
|
179
|
+
|
166
180
|
sigma = s / (b * a1)
|
167
181
|
sigma_dash = 2 * Math::PI
|
168
|
-
while (
|
169
|
-
cos_2_sigma_m = Math.cos(2 * sigma1
|
182
|
+
while (sigma - sigma_dash).abs > 1.0e-12 # i.e 0.06mm
|
183
|
+
cos_2_sigma_m = Math.cos(2 * sigma1 + sigma)
|
170
184
|
sin_sigma = Math.sin(sigma)
|
171
185
|
cos_sigma = Math.cos(sigma)
|
172
|
-
delta_sigma = b1 * sin_sigma * (cos_2_sigma_m + b1/4 * (cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m) - b1/6 * cos_2_sigma_m * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * cos_2_sigma_m * cos_2_sigma_m)))
|
186
|
+
delta_sigma = b1 * sin_sigma * (cos_2_sigma_m + b1 / 4 * (cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m) - b1 / 6 * cos_2_sigma_m * (-3 + 4 * sin_sigma * sin_sigma) * (-3 + 4 * cos_2_sigma_m * cos_2_sigma_m)))
|
173
187
|
sigma_dash = sigma
|
174
|
-
sigma = s / (b * a1)
|
188
|
+
sigma = s / (b * a1) + delta_sigma
|
175
189
|
end
|
176
190
|
|
177
191
|
tmp = sinU1 * sin_sigma - cosU1 * cos_sigma * cos_alpha1
|
178
|
-
lat2 = Math.atan2(sinU1 * cos_sigma
|
192
|
+
lat2 = Math.atan2(sinU1 * cos_sigma + cosU1 * sin_sigma * cos_alpha1, (1 - f) * Math.sqrt(sin_alpha * sin_alpha + tmp * tmp))
|
179
193
|
lambda_v = Math.atan2(sin_sigma * sin_alpha1, cosU1 * cos_sigma - sinU1 * sin_sigma * cos_alpha1)
|
180
|
-
c = f/16 * cos_2_alpha * (4 + f * (4-3 * cos_2_alpha))
|
181
|
-
l = lambda_v - (1-c)
|
182
|
-
|
183
|
-
#sigma2 = Math.atan2(sin_alpha, -tmp) # reverse azimuth
|
184
|
-
|
185
|
-
return Vincenty.new(lat2, @longitude + l, 0, true);
|
186
|
-
end
|
194
|
+
c = f / 16 * cos_2_alpha * (4 + f * (4 - 3 * cos_2_alpha))
|
195
|
+
l = lambda_v - (1 - c) * f * sin_alpha * (sigma + c * sin_sigma * (cos_2_sigma_m + c * cos_sigma * (-1 + 2 * cos_2_sigma_m * cos_2_sigma_m))) # difference in longitude
|
187
196
|
|
197
|
+
# sigma2 = Math.atan2(sin_alpha, -tmp) # reverse azimuth
|
188
198
|
|
199
|
+
return Vincenty.new(lat2, @longitude + l, 0, true)
|
200
|
+
end
|
189
201
|
end
|
190
|
-
|
191
|
-
|
192
|
-
|
data/test/ts_all.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative 'ts_angle.rb'
|
3
|
+
require_relative 'ts_vincenty.rb'
|
4
|
+
require_relative 'ts_latitude.rb'
|
5
|
+
require_relative 'ts_longitude.rb'
|
6
|
+
require_relative 'ts_coordinate.rb'
|
7
|
+
require_relative 'ts_track_and_distance.rb'
|
7
8
|
|
8
|
-
puts
|
9
|
+
puts 'Testing from source'
|
9
10
|
puts Vincenty.new.version
|
10
|
-
|
11
|
-
|
data/test/ts_angle.rb
CHANGED
@@ -1,19 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
1
2
|
require 'test/unit'
|
2
|
-
|
3
|
+
require_relative '../lib/vincenty.rb'
|
3
4
|
|
4
|
-
class TestAngle< Test::Unit::TestCase
|
5
|
-
#test Angle creation
|
5
|
+
class TestAngle < Test::Unit::TestCase
|
6
|
+
# test Angle creation
|
6
7
|
def test_angle
|
7
|
-
assert_equal(Angle.new
|
8
|
-
assert_equal(Angle.new("S37 01'7.5\"").to_deg,
|
9
|
-
assert_equal(Angle.new("37 01'7.5\"S").to_deg
|
10
|
-
assert_equal(Angle.new("-37 01'7.5\"").to_deg,
|
11
|
-
assert_equal(Angle.new("-37 1.125'").to_deg, -37.01875) #Decimal minutes, rather than minutes and seconds.
|
12
|
-
assert_equal(Angle.new("-37 01'.125").to_deg, -37.01875) #Nb. the minute marker ' between the minutes and fraction
|
13
|
-
assert_equal(Angle.new("S37 01'.125").to_deg, -37.01875) #Nb. the minute marker ' between the minutes and fraction
|
14
|
-
assert_equal(Angle.new("37 01'.125S").to_deg, -37.01875) #Nb. the minute marker ' between the minutes and fraction
|
15
|
-
assert_equal(Angle.new(
|
16
|
-
assert_equal(Angle.new([-37, 1, 7.5]).to_deg,
|
8
|
+
assert_equal(Angle.new, 0)
|
9
|
+
assert_equal(Angle.new("S37 01'7.5\"").to_deg, -37.01875) # Leading NSEW
|
10
|
+
assert_equal(Angle.new("37 01'7.5\"S").to_deg, -37.01875) # Trailing NSEW
|
11
|
+
assert_equal(Angle.new("-37 01'7.5\"").to_deg, -37.01875) # Use of - rather than S or W
|
12
|
+
assert_equal(Angle.new("-37 1.125'").to_deg, -37.01875) # Decimal minutes, rather than minutes and seconds.
|
13
|
+
assert_equal(Angle.new("-37 01'.125").to_deg, -37.01875) # Nb. the minute marker ' between the minutes and fraction
|
14
|
+
assert_equal(Angle.new("S37 01'.125").to_deg, -37.01875) # Nb. the minute marker ' between the minutes and fraction
|
15
|
+
assert_equal(Angle.new("37 01'.125S").to_deg, -37.01875) # Nb. the minute marker ' between the minutes and fraction
|
16
|
+
assert_equal(Angle.new('-37.01875 ').to_deg, -37.01875) # decimal degrees, rather than deg, min, sec.
|
17
|
+
assert_equal(Angle.new([ -37, 1, 7.5 ]).to_deg, -37.01875) # an array of deg,min,sec
|
17
18
|
assert_equal(Angle.new(-37.01875).to_deg, -37.01875)
|
18
19
|
assert_equal(Angle.degrees(-37.01875).to_deg, -37.01875)
|
19
20
|
assert_equal(Angle.degrees(-37.01875).to_rad.round(15), -0.646099072472651)
|
@@ -21,61 +22,61 @@ class TestAngle< Test::Unit::TestCase
|
|
21
22
|
assert_equal(Angle.new(-0.646099072472651, true).to_rad, -0.646099072472651)
|
22
23
|
assert_equal(Angle.radians(-0.646099072472651).to_deg.round(5), -37.01875)
|
23
24
|
assert_equal(Angle.radians(-0.646099072472651).value, Angle.radians(-0.646099072472651).angle)
|
24
|
-
assert_equal(Angle.decimal_deg(1,2,3,'S'), -(1.0 + 2/60.0 + 3/3600.0))
|
25
|
-
assert_equal(Angle.decimal_deg(1,2,3,'E'), (1.0 + 2/60.0 + 3/3600.0))
|
26
|
-
assert_equal(Angle.decimal_deg(1,2,4,'N'), (1.0 + 2/60.0 + 4/3600.0))
|
27
|
-
assert_equal(Angle.decimal_deg(1,5,4,'W'), -(1.0 + 5/60.0 + 4/3600.0))
|
28
|
-
assert_equal(Angle.decimal_deg_from_ary([1,5,4,'W']), -(1.0 + 5/60.0 + 4/3600.0))
|
29
|
-
assert_equal(Angle.decimal_deg_from_ary(Angle.dms( -(1.0 + 5/60.0 + 1.0/3600.0) ))
|
25
|
+
assert_equal(Angle.decimal_deg(1, 2, 3, 'S'), -(1.0 + 2 / 60.0 + 3 / 3600.0))
|
26
|
+
assert_equal(Angle.decimal_deg(1, 2, 3, 'E'), (1.0 + 2 / 60.0 + 3 / 3600.0))
|
27
|
+
assert_equal(Angle.decimal_deg(1, 2, 4, 'N'), (1.0 + 2 / 60.0 + 4 / 3600.0))
|
28
|
+
assert_equal(Angle.decimal_deg(1, 5, 4, 'W'), -(1.0 + 5 / 60.0 + 4 / 3600.0))
|
29
|
+
assert_equal(Angle.decimal_deg_from_ary([ 1, 5, 4, 'W' ]), -(1.0 + 5 / 60.0 + 4 / 3600.0))
|
30
|
+
assert_equal(Angle.decimal_deg_from_ary(Angle.dms( -(1.0 + 5 / 60.0 + 1.0 / 3600.0) )), -(1.0 + 5 / 60.0 + 1.0 / 3600.0)) # double call, rounding error always produced a failure.
|
30
31
|
end
|
31
|
-
|
32
|
+
|
32
33
|
def test_strf
|
33
34
|
a = Angle.new("S37 01'7.5\"")
|
34
|
-
assert_equal("-37 01'07.5000\"", a.strf) #default format of strf
|
35
|
+
assert_equal("-37 01'07.5000\"", a.strf) # default format of strf
|
35
36
|
assert_equal("37 01'07.50000\"S", a.strf( "%d %2m'%2.5s\"%N" ))
|
36
37
|
assert_equal("37 01'07.50000\"W", a.strf("%d %2m'%2.5s\"%E" ))
|
37
38
|
assert_equal("-37 01'07.5000\"", a.strf("%d %2m'%2.4s\"" ))
|
38
39
|
assert_equal("-37 01.1250'\n", a.strf("%d %2.4M'\n" ))
|
39
|
-
assert_equal("*** -37 01'.1250", a.strf( "*** %d %2m'%4W" )) #puting the minute ' before decimal point.
|
40
|
-
assert_equal(
|
40
|
+
assert_equal("*** -37 01'.1250", a.strf( "*** %d %2m'%4W" )) # puting the minute ' before decimal point.
|
41
|
+
assert_equal('-37.01875 ', a.strf('%0.5D ' ))
|
41
42
|
assert_equal("-0.64610 radians\n", a.strf("%0.5r radians\n" ))
|
42
43
|
|
43
|
-
assert_equal("-037 01'7.5000\"", Angle.new("-37 01'7.5\"").to_s('%3d %2m\'%1.4s"')) #testing leading 0 with -deg, no leading 0 %s
|
44
|
-
assert_equal("00 01'07.5000\"S", Angle.new("0 01'7.5\"S").to_s('%2d %2m\'%2.4s"%N')) #testing 0 degrees and leading 0 %s
|
45
|
-
assert_equal("00 -01'07.5000\"", Angle.new("0 01'7.5\"S").to_s('%2d %2m\'%2.4s"')) #testing 0 degrees and -min
|
46
|
-
assert_equal("00 -01'07.5000\"", Angle.new("0 01'7.5\"S").to_s('%2d %2m\'%2.4s"') ) #test of 0 degrees, -min, no NSEW
|
47
|
-
assert_equal("000 00'07.5000\"W", Angle.new("0 0'7.5\"W").to_s('%3d %2m\'%2.4s"%E') ) #testing E W 0 deg and 0 min and -sec
|
48
|
-
assert_equal("00 00'-07.5000\"", Angle.new("0 0'7.5\"S").to_s('%2d %2m\'%2.4s"') ) #testing 0 deg and 0 min and -sec no NSEW
|
44
|
+
assert_equal("-037 01'7.5000\"", Angle.new("-37 01'7.5\"").to_s('%3d %2m\'%1.4s"')) # testing leading 0 with -deg, no leading 0 %s
|
45
|
+
assert_equal("00 01'07.5000\"S", Angle.new("0 01'7.5\"S").to_s('%2d %2m\'%2.4s"%N')) # testing 0 degrees and leading 0 %s
|
46
|
+
assert_equal("00 -01'07.5000\"", Angle.new("0 01'7.5\"S").to_s('%2d %2m\'%2.4s"')) # testing 0 degrees and -min
|
47
|
+
assert_equal("00 -01'07.5000\"", Angle.new("0 01'7.5\"S").to_s('%2d %2m\'%2.4s"') ) # test of 0 degrees, -min, no NSEW
|
48
|
+
assert_equal("000 00'07.5000\"W", Angle.new("0 0'7.5\"W").to_s('%3d %2m\'%2.4s"%E') ) # testing E W 0 deg and 0 min and -sec
|
49
|
+
assert_equal("00 00'-07.5000\"", Angle.new("0 0'7.5\"S").to_s('%2d %2m\'%2.4s"') ) # testing 0 deg and 0 min and -sec no NSEW
|
49
50
|
end
|
50
51
|
|
51
52
|
def test_operators
|
52
|
-
#Comparable.
|
53
|
-
assert_equal(Angle.radians(-0.646099072472651), Angle.radians(-0.646099072472651))
|
54
|
-
#unary-op Angle
|
55
|
-
assert_equal(+Angle.radians(-0.646099072472651), Angle.radians(-0.646099072472651)) #unary +
|
56
|
-
assert_equal(-Angle.radians(-0.646099072472651), Angle.radians(0.646099072472651)) #unary -
|
57
|
-
#Angle op Numeric
|
58
|
-
assert_equal(5, Angle.radians(2) +
|
59
|
-
assert_equal(-1, Angle.radians(2) -
|
60
|
-
assert_equal(6, Angle.radians(2) *
|
61
|
-
assert_equal(2, Angle.radians(4) /2) # /
|
53
|
+
# Comparable.
|
54
|
+
assert_equal(Angle.radians(-0.646099072472651), Angle.radians(-0.646099072472651)) # <=>
|
55
|
+
# unary-op Angle
|
56
|
+
assert_equal(+Angle.radians(-0.646099072472651), Angle.radians(-0.646099072472651)) # unary +
|
57
|
+
assert_equal(-Angle.radians(-0.646099072472651), Angle.radians(0.646099072472651)) # unary -
|
58
|
+
# Angle op Numeric
|
59
|
+
assert_equal(5, Angle.radians(2) + 3) # +
|
60
|
+
assert_equal(-1, Angle.radians(2) - 3) # -
|
61
|
+
assert_equal(6, Angle.radians(2) * 3) # *
|
62
|
+
assert_equal(2, Angle.radians(4) / 2) # /
|
62
63
|
assert_equal(1, Angle.radians(4) % 3) # %
|
63
|
-
assert_equal(64, Angle.radians(4)
|
64
|
-
#Numeric op Angle
|
64
|
+
assert_equal(64, Angle.radians(4)**3) # **
|
65
|
+
# Numeric op Angle
|
65
66
|
assert_equal(5.1, 3.1 + Angle.radians(2) ) # +
|
66
67
|
assert_equal(2.646099072472651, 2 - Angle.radians(-0.646099072472651) ) # -
|
67
68
|
assert_equal(6, 3 * Angle.radians(2) ) # *
|
68
69
|
assert_equal(2, 4 / Angle.radians(2) ) # /
|
69
|
-
#Angle op Angle
|
70
|
-
assert_equal(Angle.radians(3.2+2.1), Angle.radians(3.2) + Angle.radians(2.1) ) # +
|
71
|
-
#Sign method.
|
70
|
+
# Angle op Angle
|
71
|
+
assert_equal(Angle.radians(3.2 + 2.1), Angle.radians(3.2) + Angle.radians(2.1) ) # +
|
72
|
+
# Sign method.
|
72
73
|
assert_equal(1, Angle.radians(3).sign)
|
73
74
|
assert_equal(-1, Angle.radians(-3).sign)
|
74
|
-
#abs
|
75
|
+
# abs
|
75
76
|
assert_equal(3, Angle.radians(-3).abs)
|
76
|
-
#reverse
|
77
|
+
# reverse
|
77
78
|
assert_equal(Angle.degrees(90), Angle.degrees(270).reverse)
|
78
|
-
#bearing
|
79
|
+
# bearing
|
79
80
|
assert_equal(Angle.degrees(340), Angle.degrees(20).to_bearing)
|
80
81
|
end
|
81
|
-
end
|
82
|
+
end
|
data/test/ts_coordinate.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
1
2
|
require 'test/unit'
|
2
|
-
|
3
|
+
require_relative '../lib/vincenty.rb'
|
3
4
|
|
4
|
-
class
|
5
|
-
#test Coordinate
|
5
|
+
class TestCoordinate < Test::Unit::TestCase
|
6
|
+
# test Coordinate
|
6
7
|
def test_coordinate
|
7
|
-
c = Coordinate.new(-36.9923293459124, 174.485341187381,13.5)
|
8
|
+
c = Coordinate.new(-36.9923293459124, 174.485341187381, 13.5)
|
8
9
|
ca = c.to_ary
|
9
10
|
assert_equal(-36.9923293459124, ca[0].to_deg)
|
10
11
|
assert_equal(174.485341187381, ca[1].to_deg)
|
@@ -15,4 +16,4 @@ class TestAngle< Test::Unit::TestCase
|
|
15
16
|
assert_equal(13.5, ch[:altitude])
|
16
17
|
assert_equal("36 59'32.3856\"S 174 29'07.2283\"E 13.5m", c.to_s)
|
17
18
|
end
|
18
|
-
end
|
19
|
+
end
|
data/test/ts_latitude.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
1
2
|
require 'test/unit'
|
2
|
-
|
3
|
+
require_relative '../lib/vincenty.rb'
|
3
4
|
|
4
|
-
class
|
5
|
+
class TestLatitude < Test::Unit::TestCase
|
5
6
|
def test_strf
|
6
7
|
assert_equal("37 01'07.5000\"S", Latitude.new("S37 01'7.5\"").to_s)
|
7
8
|
assert_equal("37 01'07.5000\"S", Latitude.new("-37 01'7.5\"").to_s)
|
@@ -10,12 +11,14 @@ class TestAngle< Test::Unit::TestCase
|
|
10
11
|
assert_equal("37 01'07.5000\"N", Latitude.new("37 01'7.5\"").to_s)
|
11
12
|
assert_equal("37 01'07.5000\"N", Latitude.new("37 01'7.5\"N").to_s)
|
12
13
|
end
|
14
|
+
|
13
15
|
def test_to_radians
|
14
|
-
assert_equal(Math::PI/4, Latitude.degrees(45).to_rad)
|
15
|
-
assert_equal(Math::PI/4, Latitude.degrees(135).to_rad)
|
16
|
-
assert_equal(-Math::PI/4, Latitude.degrees(225).to_rad)
|
17
|
-
assert_equal(-Math::PI/4, Latitude.degrees(315).to_rad)
|
16
|
+
assert_equal(Math::PI / 4, Latitude.degrees(45).to_rad)
|
17
|
+
assert_equal(Math::PI / 4, Latitude.degrees(135).to_rad)
|
18
|
+
assert_equal(-Math::PI / 4, Latitude.degrees(225).to_rad)
|
19
|
+
assert_equal(-Math::PI / 4, Latitude.degrees(315).to_rad)
|
18
20
|
end
|
21
|
+
|
19
22
|
def test_to_degrees
|
20
23
|
assert_equal(45, Latitude.degrees(45).to_deg)
|
21
24
|
assert_equal(45, Latitude.degrees(135).to_deg)
|
@@ -28,4 +31,4 @@ class TestAngle< Test::Unit::TestCase
|
|
28
31
|
assert_equal(89, Latitude.degrees(89).to_deg)
|
29
32
|
assert_equal(89, Latitude.degrees(91).to_deg)
|
30
33
|
end
|
31
|
-
end
|
34
|
+
end
|
data/test/ts_longitude.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
1
2
|
require 'test/unit'
|
2
|
-
|
3
|
+
require_relative '../lib/vincenty.rb'
|
3
4
|
|
4
|
-
class
|
5
|
+
class TestLongitude < Test::Unit::TestCase
|
5
6
|
def test_strf
|
6
7
|
assert_equal("037 01'07.5000\"W", Longitude.new("W37 01'7.5\"").to_s)
|
7
8
|
assert_equal("037 01'07.5000\"W", Longitude.new("-37 01'7.5\"").to_s)
|
@@ -10,16 +11,18 @@ class TestAngle< Test::Unit::TestCase
|
|
10
11
|
assert_equal("037 01'07.5000\"E", Longitude.new("37 01'7.5\"").to_s)
|
11
12
|
assert_equal("037 01'07.5000\"E", Longitude.new("37 01'7.5\"E").to_s)
|
12
13
|
end
|
14
|
+
|
13
15
|
def test_to_radians
|
14
|
-
assert_equal(Math::PI/4, Longitude.degrees(45).to_rad)
|
15
|
-
assert_equal(3*Math::PI/4, Longitude.degrees(135).to_rad)
|
16
|
-
assert_equal(-3*Math::PI/4, Longitude.degrees(225).to_rad)
|
17
|
-
assert_equal(-Math::PI/4, Longitude.degrees(315).to_rad)
|
16
|
+
assert_equal(Math::PI / 4, Longitude.degrees(45).to_rad)
|
17
|
+
assert_equal(3 * Math::PI / 4, Longitude.degrees(135).to_rad)
|
18
|
+
assert_equal(-3 * Math::PI / 4, Longitude.degrees(225).to_rad)
|
19
|
+
assert_equal(-Math::PI / 4, Longitude.degrees(315).to_rad)
|
18
20
|
end
|
21
|
+
|
19
22
|
def test_to_degrees
|
20
23
|
assert_equal(45, Longitude.degrees(45).to_deg)
|
21
24
|
assert_equal(135, Longitude.degrees(135).to_deg)
|
22
25
|
assert_equal(-135, Longitude.degrees(225).to_deg)
|
23
26
|
assert_equal(-45, Longitude.degrees(315).to_deg)
|
24
27
|
end
|
25
|
-
end
|
28
|
+
end
|
@@ -1,16 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
1
2
|
require 'test/unit'
|
2
|
-
|
3
|
+
require_relative '../lib/vincenty.rb'
|
3
4
|
|
4
|
-
class
|
5
|
-
#test TrackAndDistance
|
5
|
+
class TestTrackAndDistance < Test::Unit::TestCase
|
6
|
+
# test TrackAndDistance
|
6
7
|
def test_track_and_distance
|
7
|
-
assert_equal("140 14'10.0000\" 12.0m", TrackAndDistance.new(Angle.new(
|
8
|
-
assert_equal("215 03'00.0000\" 19.73m", TrackAndDistance.new(
|
9
|
-
|
8
|
+
assert_equal("140 14'10.0000\" 12.0m", TrackAndDistance.new(Angle.new('320,14,10').reverse, 12.0).to_s)
|
9
|
+
assert_equal("215 03'00.0000\" 19.73m", TrackAndDistance.new('215,3,0', 19.73 ).to_s)
|
10
|
+
|
11
|
+
a = TrackAndDistance.new('215,3,0', 19.73 ).to_ary
|
10
12
|
assert_equal("215 03'00.0000\"", a[0].strf)
|
11
|
-
assert_equal(
|
12
|
-
|
13
|
+
assert_equal('19.73', a[1].to_s)
|
14
|
+
|
15
|
+
a = TrackAndDistance.new('215,3,0', 19.73 ).to_hash
|
13
16
|
assert_equal("215 03'00.0000\"", a[:bearing].strf)
|
14
|
-
assert_equal(
|
17
|
+
assert_equal('19.73', a[:distance].to_s)
|
15
18
|
end
|
16
19
|
end
|