vincenty 1.0.4 → 1.0.9

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.
data/lib/vincenty.rb CHANGED
@@ -1,191 +1,201 @@
1
- require 'core_extensions.rb'
2
- require 'angle.rb'
3
- require 'latitude.rb'
4
- require 'longitude.rb'
5
- require 'track_and_distance.rb'
6
- require '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.
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.4'
16
-
15
+ VERSION = '1.0.9'
16
+
17
+ # @return [String] constant VERSION
17
18
  def version
18
19
  VERSION
19
20
  end
20
-
21
- #Great Circle formulae http://en.wikipedia.org/wiki/Great-circle_distance
22
- #Reference calculation for testing, assumes the earth is a sphere, which it isn't.
23
- #This gives us an approximation to verify Vincenty algorithm.
24
- #Takes: argument p2 is target coordinate that we want the bearing to.
25
- #Returns: TrackAndDistance object with the compass bearing and distance in meters to P2
26
- def sphericalDistanceAndAngle( p2 )
27
- a = 6378137 #equatorial radius in meters (+/-2 m)
28
- b = 6356752.31424518 #polar radius in meters
29
- r = (a+b)/2 #average diametre as a rough estimate for our tests.
30
-
31
- sin_lat1 = Math.sin(@latitude.to_r)
32
- sin_lat2 = Math.sin(p2.latitude.to_r)
33
- cos_lat1 = Math.cos(@latitude.to_r)
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.
30
+ # @param [Coordinate] p2 is target coordinate that we want the bearing to.
31
+ # @return [TrackAndDistance] with the compass bearing and distance in meters to P2
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
+
42
+ sin_lat1 = Math.sin(@latitude.to_rad)
43
+ sin_lat2 = Math.sin(p2.latitude.to_rad)
44
+ cos_lat1 = Math.cos(@latitude.to_rad)
34
45
  atan1_2 = Math.atan(1) * 2
35
- t1 = cos_lat1 * Math.cos(p2.latitude.to_r) * ( Math.cos(@longitude.to_r - p2.longitude.to_r) ) + sin_lat1 * sin_lat2
36
- 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.
37
48
 
38
49
  t2 = (sin_lat2 - sin_lat1 * Math.cos(angular_distance)) / (cos_lat1 * Math.sin(angular_distance))
39
- if(Math.sin(p2.longitude.to_r - @longitude.to_r) < 0)
40
- bearing = 2 * Math::PI - (Math.atan(-t2 / Math.sqrt(-t2 * t2 + 1)) + atan1_2) #Compass Bearing in radians (clockwise)
41
- else
42
- bearing = Math.atan(-t2 / Math.sqrt(-t2 * t2 + 1)) + atan1_2 #Compass Bearing in radians (clockwise)
43
- end
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
44
55
 
45
- #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.
46
57
  return TrackAndDistance.new(bearing, angular_distance * r, true)
47
58
  end
48
59
 
49
- #Vincenty's algorithm for finding bearing and distance between to coordinates.
50
- #Assumes earth is a WGS-84 Ellipsod.
51
- #Takes: argument p2 is target coordinate that we want the bearing to.
52
- #Returns: TrackAndDistance object with the compass bearing and distance in meters to P2
60
+ # Vincenty's algorithm for finding bearing and distance between to coordinates.
61
+ # Assumes earth is a WGS-84 Ellipsod.
62
+ # @param [Coordinate] p2 is target coordinate that we want the bearing to.
63
+ # @return [TrackAndDistance] with the compass bearing and distance in meters to P2
53
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
+
54
69
  # a, b = major & minor semiaxes of the ellipsoid
55
- a = 6378137 #equatorial radius in meters (+/-2 m)
56
- b = 6356752.31424518 #polar radius in meters
57
- f = (a-b)/a # flattening
58
-
59
- lat1 = @latitude.to_r
60
- lon1 = @longitude.to_r
61
- lat2 = p2.latitude.to_r
62
- lon2 = p2.longitude.to_r
63
- lat1 = lat1.sign * (Math::PI/2-(1e-10)) if (Math::PI/2-lat1.abs).abs < 1.0e-10
64
- lat2 = lat2.sign * (Math::PI/2-(1e-10)) if (Math::PI/2-lat2.abs).abs < 1.0e-10
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
65
80
 
66
81
  # lat1, lat2 = geodetic latitude
67
-
68
- l = (lon2 - lon1).abs #difference in longitude
69
- l = 2*Math::PI - l if l > Math::PI
70
- u1 = Math.atan( ( 1 - f) * Math.tan( lat1 ) ) #U is 'reduced latitude'
71
- u2 = Math.atan( ( 1 - f) * Math.tan( lat2 ) )
72
- sin_u1 = Math.sin(u1)
73
- cos_u1 = Math.cos(u1)
74
- sin_u2 = Math.sin(u2)
75
- cos_u2 = Math.cos(u2)
76
-
77
- lambda_v = l
78
- lambda_dash = Math::PI * 2
79
- while( (lambda_v - lambda_dash).abs > 1.0e-12 ) #i.e. 0.06 mm error
80
- sin_lambda_v = Math.sin(lambda_v)
81
- cos_lambda_v = Math.cos(lambda_v)
82
- sin_sigma = Math.sqrt( ( cos_u2 * sin_lambda_v ) ** 2 + ( cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda_v ) ** 2 )
83
- cos_sigma = sin_u1 * sin_u2 + cos_u1 * cos_u2 * cos_lambda_v
84
- sigma = Math.atan2(sin_sigma, cos_sigma)
85
- sin_alpha= cos_u1 * cos_u2 * sin_lambda_v / sin_sigma
86
- cos_2_alpha = 1 - sin_alpha * sin_alpha #trig identity
87
- cos_2_sigma_m = cos_sigma - 2 * sin_u1 * sin_u2/cos_2_alpha
88
- c = f / 16 * cos_2_alpha * (4 + f*(4-3*cos_2_alpha))
89
- lambda_dash = lambda_v
90
- 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
91
- if lambda_v > Math::PI
92
- lambda_v = Math::PI
93
- break
94
- end
95
- end
96
82
 
97
- u_2 = cos_2_alpha * (a * a - b * b) / (b * b)
98
- a1 = 1 + u_2 / 16384 * (4096 + u_2 * (-768 + u_2 * (320 - 175 * u_2)))
99
- b1 = u_2 / 1024 * (256 + u_2 * (-128 + u_2 * (74 - 47 * u_2)))
100
- 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)))
101
- s = b * a1 * (sigma - delta_sigma)
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
102
95
  sin_lambda_v = Math.sin(lambda_v)
103
96
  cos_lambda_v = Math.cos(lambda_v)
104
-
105
- #This test isn't in original formulae, and fixes the problem of all angles returned being between 0 - PI (0-180)
106
- #Also converts the result to compass bearing, rather than the mathmatical anticlockwise angles.
107
- if(Math.sin(p2.longitude.to_r - @longitude.to_r) < 0)
108
- alpha_1 = Math::PI*2-Math.atan2( cos_u2 * sin_lambda_v, cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda_v)
109
- #alpha_2 = Math::PI*2-Math.atan2(cos_u1 * sin_lambda_v, -sin_u1 * cos_u2 + cos_u1 * sin_u2 * cos_lambda_v)
110
- else
111
- alpha_1 = Math.atan2( cos_u2 * sin_lambda_v, cos_u1 * sin_u2 - sin_u1 * cos_u2 * cos_lambda_v)
112
- #alpha_2 = Math.atan2(cos_u1 * sin_lambda_v, -sin_u1 * cos_u2 + cos_u1 * sin_u2 * cos_lambda_v)
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
113
109
  end
114
-
115
- #Note that the bearing is a compass (i.e. clockwise) angle.
116
- return TrackAndDistance.new(alpha_1, s, true) #What to do with alpha_2?
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?
117
132
  end
118
133
 
119
- #spherical earth estimate of calculation for finding target coordinate from start coordinate, bearing and distance
120
- #Used to run checks on the Vincenty algorithm
121
- #Takes: TrackAndDistance object with bearing and distance.
122
- #Returns new Vincenty object with the destination coordinates.
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
136
+ # @param [TrackAndDistance] track_and_distance specifying bearing and distance.
137
+ # @return [Vincenty] with the destination coordinates.
123
138
  def sphereDestination( track_and_distance )
124
- a = 6378137 #equatorial radius in meters (+/-2 m)
125
- b = 6356752.31424518 #polar radius in meters
126
- r = (a+b)/2 #average diametre as a rough estimate for our tests.
127
-
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
+
128
143
  d = track_and_distance.distance.abs
129
- sin_dor = Math.sin(d/r)
130
- cos_dor = Math.cos(d/r)
131
- sin_lat1 = Math.sin(@latitude.to_r)
132
- cos_lat1 = Math.cos(@latitude.to_r)
133
- lat2 = Math.asin( sin_lat1 * cos_dor + cos_lat1 * sin_dor * Math.cos(track_and_distance.bearing.to_r) )
134
- lon2 = @longitude.to_r + Math.atan2(Math.sin(track_and_distance.bearing.to_r) * sin_dor * cos_lat1, cos_dor-sin_lat1 * Math.sin(lat2))
135
-
136
- Vincenty.new(lat2, lon2, 0, true);
144
+ sin_dor = Math.sin(d / r)
145
+ cos_dor = Math.cos(d / r)
146
+ sin_lat1 = Math.sin(@latitude.to_rad)
147
+ cos_lat1 = Math.cos(@latitude.to_rad)
148
+ lat2 = Math.asin( sin_lat1 * cos_dor + cos_lat1 * sin_dor * Math.cos(track_and_distance.bearing.to_rad) )
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)
137
152
  end
138
153
 
139
154
  #
140
155
  # Calculate destination point given start point lat/long, bearing and distance.
141
- #Assumes earth is a WGS-84 Ellipsod.
142
- #Takes: TrackAndDistance object with bearing and distance.
143
- #Returns: new Vincenty object with the destination coordinates.
144
- def destination( track_and_distance )
156
+ # Assumes earth is a WGS-84 Ellipsod.
157
+ # @param [TrackAndDistance] specifying bearing and distance.
158
+ # @return [Vincenty] with the destination coordinates.
159
+ def destination( track_and_distance )
145
160
  # a, b = major & minor semiaxes of the ellipsoid
146
- a = 6378137 #equatorial radius in meters (+/-2 m)
147
- b = 6356752.31424518 #polar radius in meters
148
- f = (a-b)/a # flattening
149
-
150
- s = track_and_distance.distance.abs;
151
- alpha1 = track_and_distance.bearing.to_r
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
166
+ alpha1 = track_and_distance.bearing.to_rad
152
167
  sin_alpha1 = Math.sin(alpha1)
153
168
  cos_alpha1 = Math.cos(alpha1)
154
-
155
- tanU1 = (1-f) * Math.tan(@latitude.to_r);
156
- cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1))
169
+
170
+ tanU1 = (1 - f) * Math.tan(@latitude.to_rad)
171
+ cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1))
157
172
  sinU1 = tanU1 * cosU1
158
173
  sigma1 = Math.atan2(tanU1, cos_alpha1)
159
- sin_alpha = cosU1 * sin_alpha1
160
- cos_2_alpha = 1 - sin_alpha * sin_alpha #Trig identity
161
- u_2 = cos_2_alpha * (a * a - b * b) / (b * b)
162
- a1 = 1 + u_2/16384 * (4096 + u_2 * (-768 + u_2 * (320-175 * u_2)))
163
- b1 = u_2/1024 * (256 + u_2 * (-128 + u_2 * (74-47 * u_2)))
164
-
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
+
165
180
  sigma = s / (b * a1)
166
181
  sigma_dash = 2 * Math::PI
167
- while ((sigma-sigma_dash).abs > 1.0e-12) #i.e 0.06mm
168
- cos_2_sigma_m = Math.cos(2 * sigma1 + sigma)
182
+ while (sigma - sigma_dash).abs > 1.0e-12 # i.e 0.06mm
183
+ cos_2_sigma_m = Math.cos(2 * sigma1 + sigma)
169
184
  sin_sigma = Math.sin(sigma)
170
185
  cos_sigma = Math.cos(sigma)
171
- 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)))
172
187
  sigma_dash = sigma
173
- sigma = s / (b * a1) + delta_sigma
188
+ sigma = s / (b * a1) + delta_sigma
174
189
  end
175
190
 
176
191
  tmp = sinU1 * sin_sigma - cosU1 * cos_sigma * cos_alpha1
177
- lat2 = Math.atan2(sinU1 * cos_sigma + cosU1 * sin_sigma * cos_alpha1, (1-f) * Math.sqrt(sin_alpha * sin_alpha + tmp * tmp))
192
+ lat2 = Math.atan2(sinU1 * cos_sigma + cosU1 * sin_sigma * cos_alpha1, (1 - f) * Math.sqrt(sin_alpha * sin_alpha + tmp * tmp))
178
193
  lambda_v = Math.atan2(sin_sigma * sin_alpha1, cosU1 * cos_sigma - sinU1 * sin_sigma * cos_alpha1)
179
- c = f/16 * cos_2_alpha * (4 + f * (4-3 * cos_2_alpha))
180
- 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
181
-
182
- #sigma2 = Math.atan2(sin_alpha, -tmp) # reverse azimuth
183
-
184
- return Vincenty.new(lat2, @longitude + l, 0, true);
185
- 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
186
196
 
197
+ # sigma2 = Math.atan2(sin_alpha, -tmp) # reverse azimuth
187
198
 
199
+ return Vincenty.new(lat2, @longitude + l, 0, true)
200
+ end
188
201
  end
189
-
190
-
191
-
data/test/ts_all.rb CHANGED
@@ -1,10 +1,10 @@
1
- require 'ts_angle.rb'
2
- require 'ts_vincenty.rb'
3
- require 'ts_latitude.rb'
4
- require 'ts_longitude.rb'
5
- require 'ts_coordinate.rb'
6
- require 'ts_track_and_distance.rb'
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
 
9
+ puts 'Testing from source'
8
10
  puts Vincenty.new.version
9
-
10
-
data/test/ts_angle.rb CHANGED
@@ -1,81 +1,82 @@
1
+ #!/usr/bin/env ruby
1
2
  require 'test/unit'
2
- require 'vincenty.rb'
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(), 0)
8
- assert_equal(Angle.new("S37 01'7.5\"").to_d, -37.01875) #Leading NSEW
9
- assert_equal(Angle.new("37 01'7.5\"S").to_d , -37.01875) #Trailing NSEW
10
- assert_equal(Angle.new("-37 01'7.5\"").to_d, -37.01875) #Use of - rather than S or W
11
- assert_equal(Angle.new("-37 1.125'").to_d, -37.01875) #Decimal minutes, rather than minutes and seconds.
12
- assert_equal(Angle.new("-37 01'.125").to_d, -37.01875) #Nb. the minute marker ' between the minutes and fraction
13
- assert_equal(Angle.new("S37 01'.125").to_d, -37.01875) #Nb. the minute marker ' between the minutes and fraction
14
- assert_equal(Angle.new("37 01'.125S").to_d, -37.01875) #Nb. the minute marker ' between the minutes and fraction
15
- assert_equal(Angle.new("-37.01875 ").to_d, -37.01875) #decimal degrees, rather than deg, min, sec.
16
- assert_equal(Angle.new([-37, 1, 7.5]).to_d, -37.01875) #an array of deg,min,sec
17
- assert_equal(Angle.new(-37.01875).to_d, -37.01875)
18
- assert_equal(Angle.degrees(-37.01875).to_d, -37.01875)
19
- assert_equal(Angle.degrees(-37.01875).to_r.round(15), -0.646099072472651)
20
- assert_equal(Angle.new(-0.646099072472651, true).to_d.round(5), -37.01875)
21
- assert_equal(Angle.new(-0.646099072472651, true).to_r, -0.646099072472651)
22
- assert_equal(Angle.radians(-0.646099072472651).to_d.round(5), -37.01875)
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
18
+ assert_equal(Angle.new(-37.01875).to_deg, -37.01875)
19
+ assert_equal(Angle.degrees(-37.01875).to_deg, -37.01875)
20
+ assert_equal(Angle.degrees(-37.01875).to_rad.round(15), -0.646099072472651)
21
+ assert_equal(Angle.new(-0.646099072472651, true).to_deg.round(5), -37.01875)
22
+ assert_equal(Angle.new(-0.646099072472651, true).to_rad, -0.646099072472651)
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) )),-(1.0 + 5/60.0 + 1.0/3600.0)) #double call, rounding error always produced a failure.
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("-37.01875 ", a.strf("%0.5D " ))
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) + 3) # +
59
- assert_equal(-1, Angle.radians(2) - 3) # -
60
- assert_equal(6, Angle.radians(2) * 3) # *
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) ** 3) # **
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
@@ -1,18 +1,19 @@
1
+ #!/usr/bin/env ruby
1
2
  require 'test/unit'
2
- require 'vincenty.rb'
3
+ require_relative '../lib/vincenty.rb'
3
4
 
4
- class TestAngle< Test::Unit::TestCase
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
- assert_equal(-36.9923293459124, ca[0].to_d)
10
- assert_equal(174.485341187381, ca[1].to_d)
10
+ assert_equal(-36.9923293459124, ca[0].to_deg)
11
+ assert_equal(174.485341187381, ca[1].to_deg)
11
12
  assert_equal(13.5, ca[2])
12
13
  ch = c.to_hash
13
- assert_equal(-36.9923293459124, ch[:latitude].to_d)
14
- assert_equal(174.485341187381, ch[:longitude].to_d)
14
+ assert_equal(-36.9923293459124, ch[:latitude].to_deg)
15
+ assert_equal(174.485341187381, ch[:longitude].to_deg)
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
- require 'vincenty.rb'
3
+ require_relative '../lib/vincenty.rb'
3
4
 
4
- class TestAngle< Test::Unit::TestCase
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,22 +11,24 @@ 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_r)
15
- assert_equal(Math::PI/4, Latitude.degrees(135).to_r)
16
- assert_equal(-Math::PI/4, Latitude.degrees(225).to_r)
17
- assert_equal(-Math::PI/4, Latitude.degrees(315).to_r)
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
- assert_equal(45, Latitude.degrees(45).to_d)
21
- assert_equal(45, Latitude.degrees(135).to_d)
22
- assert_equal(-45, Latitude.degrees(225).to_d)
23
- assert_equal(-45, Latitude.degrees(315).to_d)
24
- assert_equal(1, Latitude.degrees(179).to_d)
25
- assert_equal(-1, Latitude.degrees(181).to_d)
26
- assert_equal(-89, Latitude.degrees(269).to_d)
27
- assert_equal(-89, Latitude.degrees(271).to_d)
28
- assert_equal(89, Latitude.degrees(89).to_d)
29
- assert_equal(89, Latitude.degrees(91).to_d)
23
+ assert_equal(45, Latitude.degrees(45).to_deg)
24
+ assert_equal(45, Latitude.degrees(135).to_deg)
25
+ assert_equal(-45, Latitude.degrees(225).to_deg)
26
+ assert_equal(-45, Latitude.degrees(315).to_deg)
27
+ assert_equal(1, Latitude.degrees(179).to_deg)
28
+ assert_equal(-1, Latitude.degrees(181).to_deg)
29
+ assert_equal(-89, Latitude.degrees(269).to_deg)
30
+ assert_equal(-89, Latitude.degrees(271).to_deg)
31
+ assert_equal(89, Latitude.degrees(89).to_deg)
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
- require 'vincenty.rb'
3
+ require_relative '../lib/vincenty.rb'
3
4
 
4
- class TestAngle< Test::Unit::TestCase
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_r)
15
- assert_equal(3*Math::PI/4, Longitude.degrees(135).to_r)
16
- assert_equal(-3*Math::PI/4, Longitude.degrees(225).to_r)
17
- assert_equal(-Math::PI/4, Longitude.degrees(315).to_r)
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
- assert_equal(45, Longitude.degrees(45).to_d)
21
- assert_equal(135, Longitude.degrees(135).to_d)
22
- assert_equal(-135, Longitude.degrees(225).to_d)
23
- assert_equal(-45, Longitude.degrees(315).to_d)
23
+ assert_equal(45, Longitude.degrees(45).to_deg)
24
+ assert_equal(135, Longitude.degrees(135).to_deg)
25
+ assert_equal(-135, Longitude.degrees(225).to_deg)
26
+ assert_equal(-45, Longitude.degrees(315).to_deg)
24
27
  end
25
- end
28
+ end