vincenty 1.0.6 → 1.0.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|