vincenty 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -1,3 +1,25 @@
1
+ === 1.0.1 / 2009-03-03
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
7
+ commit 1af085d57d8f5486b31fef3e018fa75a1e634028
8
+ Author: rbur004 <rob@burrowes.org>
9
+ Date: Fri Jan 1 11:10:33 2010 +1300
10
+
11
+ Found the error generating gems with gem 1.3.5 and Hoe. The url in README.txt should not have quotes around it.
12
+
13
+ Also the new way to specify the URL in the Rakefile is to use self.url. Kind of ugly really.
14
+
15
+ Also noted that Hoe is adding itself as a dependency in the gemspec, which it is not.
16
+
17
+ commit acc43b4a37c6cf878b9415524b8b720d46fec48b
18
+ Author: rbur004 <rob@burrowes.org>
19
+ Date: Thu Dec 31 23:39:08 2009 +1300
20
+
21
+ Commented out the require 'lib/vincenty.rb' as it is no longer required
22
+
1
23
  commit e8d8d9bce43f58b0bd487e48308f170ca48c380d
2
24
  Author: rbur004 <rob@burrowes.org>
3
25
  Date: Thu Dec 31 22:50:16 2009 +1300
@@ -1,6 +1,6 @@
1
1
  History.txt
2
2
  Manifest.txt
3
- README.txt
3
+ README.md
4
4
  Rakefile
5
5
  lib/angle.rb
6
6
  lib/coordinate.rb
@@ -1,8 +1,10 @@
1
- = Vincenty
1
+ # Vincenty
2
2
 
3
- * "http://rubyforge.org/projects/vincenty/"
3
+ * http://rbur004.github.com/vincenty/
4
+ * Source https://github.com/rbur004/vincenty
5
+ * Gem https://rubygems.org/gems/vincenty
4
6
 
5
- == DESCRIPTION:
7
+ ## DESCRIPTION:
6
8
 
7
9
  * Vincenty wrote an algorithm for calculating the bearing and distance between two coordinates on the earth
8
10
  and an algorithm for finding a second coordinate, given a starting coordinate, bearing and destination.
@@ -27,13 +29,13 @@
27
29
 
28
30
  ** T Vincenty, "Direct and Inverse Solutions of Geodesics on the Ellipsoid with application of nested equations", Survey Review, vol XXII no 176, 1975 http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
29
31
 
30
- == FEATURES/PROBLEMS:
32
+ ## FEATURES/PROBLEMS:
31
33
 
32
34
  * None that I yet know of :)
33
35
 
34
- == SYNOPSIS:
36
+ ## SYNOPSIS:
35
37
 
36
- flindersPeak = Vincenty.new("-37&deg;57&prime;3.72030", "144&deg;25&prime;29.52440" )
38
+ flindersPeak = Vincenty.new("-37&deg;57&prime;3.72030''", "144&deg;25&prime;29.52440''" )
37
39
  buninyong = Vincenty.new("-37&deg; 39' 10.15610''", "143&deg; 55' 35.38390''")
38
40
  track_and_bearing = flindersPeak.distanceAndAngle( buninyong )
39
41
  puts track_and_bearing
@@ -45,15 +47,15 @@
45
47
  #Angles is the parent class of Latitude and Longitude
46
48
  Angle.new("-37&deg;01&prime;.125").strf( "The angle is %d&deg;%2m&prime;%2.5s&Prime;%N" ) -> "The angle is 37&deg;01&prime;07.50000&Prime;S"
47
49
 
48
- == REQUIREMENTS:
50
+ ## REQUIREMENTS:
49
51
 
50
52
  * require 'rubygems'
51
53
 
52
- == INSTALL:
54
+ ## INSTALL:
53
55
 
54
56
  * sudo gem install vincenty
55
57
 
56
- == LICENSE:
58
+ ## LICENSE:
57
59
 
58
60
  Code unique to this implementation of Vincentys algrithm is distributed under the Ruby License.
59
61
 
@@ -65,42 +67,25 @@ Copyright (c) 2009
65
67
 
66
68
  2. You may modify your copy of the software in any way, provided that
67
69
  you do at least ONE of the following:
70
+ * place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software.
71
+ * use the modified software only within your corporation or organization.
72
+ * rename any non-standard executables so the names do not conflict with standard executables, which must also be provided.
73
+ * make other distribution arrangements with the author.
68
74
 
69
- a) place your modifications in the Public Domain or otherwise
70
- make them Freely Available, such as by posting said
71
- modifications to Usenet or an equivalent medium, or by allowing
72
- the author to include your modifications in the software.
73
-
74
- b) use the modified software only within your corporation or
75
- organization.
76
-
77
- c) rename any non-standard executables so the names do not conflict
78
- with standard executables, which must also be provided.
79
-
80
- d) make other distribution arrangements with the author.
81
-
82
- 3. You may distribute the software in object code or executable
83
- form, provided that you do at least ONE of the following:
84
-
85
- a) distribute the executables and library files of the software,
75
+ 3. You may distribute the software in object code or executable form, provided that you do at least ONE of the following:
76
+ * distribute the executables and library files of the software,
86
77
  together with instructions (in the manual page or equivalent)
87
78
  on where to get the original distribution.
88
-
89
- b) accompany the distribution with the machine-readable source of
79
+ * accompany the distribution with the machine-readable source of
90
80
  the software.
91
-
92
- c) give non-standard executables non-standard names, with
81
+ * give non-standard executables non-standard names, with
93
82
  instructions on where to get the original software distribution.
94
-
95
- d) make other distribution arrangements with the author.
83
+ * make other distribution arrangements with the author.
96
84
 
97
85
  4. You may modify and include the part of the software into any other
98
- software (possibly commercial). But some files in the distribution
99
- are not written by the author, so that they are not under this terms.
100
-
101
- They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
102
- files under the ./missing directory. See each file for the copying
103
- condition.
86
+ software (possibly commercial). But some files or libraries used by
87
+ code in this distribution may not written by the author, so that they
88
+ are not under these terms.
104
89
 
105
90
  5. The scripts and library files supplied as input to or produced as
106
91
  output from the software do not automatically fall under the
data/Rakefile CHANGED
@@ -1,17 +1,20 @@
1
1
  #!/usr/bin/ruby
2
2
  # -*- ruby -*-
3
3
 
4
- #require 'rubygems'
4
+ require 'rubygems'
5
5
  require 'hoe'
6
6
  #require 'lib/vincenty.rb'
7
-
7
+ Hoe.plugin :yard
8
8
 
9
9
  Hoe.spec 'vincenty' do
10
10
  self.rubyforge_name = "vincenty"
11
- developer( "Rob Burrowes","rob@burrowes.org")
12
- #s.url = "http://rubyforge.org/projects/vincenty/"
13
- #s.summary = "Vincenty Algorithm for Distance, Bearing between Map Coordinates."
14
- #s.description = s.paragraphs_of('README.txt', 1..4).join("\n\n")
15
- remote_rdoc_dir = '' # Release to root
11
+ self.developer( "Rob Burrowes","r.burrowes@auckland.ac.nz")
12
+
13
+ self.yard_title = 'Vincenty'
14
+ self.yard_options = ['--markup', 'markdown', '--protected']
15
+ #self.url = "http://www.wikarekare.org"
16
+ #self.summary = "Vincenty Algorithm for Distance, Bearing between Map Coordinates."
17
+ #self.description = s.paragraphs_of('README.txt', 1..4).join("\n\n")
18
+ #self.remote_rdoc_dir = '' # Release to root
16
19
  end
17
20
 
@@ -1,140 +1,171 @@
1
+ require 'core_extensions.rb'
2
+
1
3
  #Class Angle is a utility class that allows
2
- # * Angle arithmetic
3
- # * Angle comparison
4
+ # * Angle arithmetic ( +,-,*,/,**,% and unary +,-)
5
+ # * Angle comparison ( <=>, hence, <, >, >=, <=, == )
4
6
  # * Conversion to and from degrees and radians
5
7
  # * Conversion to string as radians or DMS format
6
8
 
7
- require 'core_extensions.rb'
8
-
9
9
  class Angle
10
10
  include Comparable
11
11
 
12
- #Provides test for Module Comparable
13
- def <=>(v)
14
- if v.class == Angle
15
- @value <=> v.value
16
- else
17
- @value <=> v
18
- end
19
- end
20
12
 
21
- attr_accessor :value #stored in radians
13
+ attr_accessor :angle #stored in radians
14
+ alias :value :angle #Older version of angle used volue rather than angle
15
+ alias :value= :angle= #Older version of angle used volue rather than angle
22
16
 
23
- #v may be anything that has a to_f and to_radians. The Default for v is degrees.
24
- #if radians == true then v is in radians, not degrees.
25
- def initialize(v=0, radians=false)
26
- #assumes that we are getting a value in degrees.
27
- if radians
28
- @value = v.to_f #works for String, Fixed, other Angles and for Float.
17
+ #angle may be anything that has a to_f and to_radians.
18
+ #The Default for angle is degrees, but internally @angle is stored in radians.
19
+ #if radians is passed true or :radians, then angle is in radians, not degrees.
20
+ def initialize(angle=0, radians=false)
21
+ #assumes that we are getting an angle in degrees.
22
+ if radians == true || radians == :radians
23
+ @angle = angle.to_f #works for String, Fixed, other Angles and for Float.
29
24
  else
30
- if v.class == Array
31
- @value = self.class.decimal_deg(*v).to_radians #Wild assumption that the array is deg,min,sec.
25
+ if angle.class == Array
26
+ @angle = self.class.decimal_deg(*angle).to_radians #Wild assumption that the array is deg,min,sec.
32
27
  else
33
- @value = v.to_radians #we have a String and Numeric class version of this. Another Angle will work too.
28
+ @angle = angle.to_radians #we have a String and Numeric class version of this. Another Angle will work too.
34
29
  end
35
30
  end
36
31
  end
37
32
 
38
- #Class level function that converts an array of up to 4 values into decimal degrees.
39
- #a[0..3] is degrees, minutes, seconds, direction. Dircection is one of 'N', 'S', 'E', 'W'.
40
- #nil values in the array are set to 0
41
- #if the a.length < 4,t then a is extended to be length 4 with 0
42
- #A 0 as the direction has no effect on the sign of the result
43
- #Returns: signed decimal degress.
44
- def self.decimal_deg(*a)
45
- (0..3).each { |x| a[x] = 0 if a[x] == nil } #convert nil arguments to 0 and ensure 4 values.
46
- s = { 'N'=>1, 'S'=>-1, 'E'=>1, 'W'=>-1, 0=>1 }
47
- a[0].sign * (a[0].abs + a[1]/60.0 + a[2]/3600.0) * s[a[3]]
33
+
34
+ #Class level function that converts 4 arguments into decimal degrees.
35
+ #Dircection is one of 'N', 'S', 'E', 'W'.
36
+ # direction is optional, as you might want to specify a negative value for degrees
37
+ # @return [Float] signed decimal degrees.
38
+ def self.decimal_deg(degrees=0, minutes=0, seconds=0, direction='N')
39
+ s = { 'N'=>1, 'S'=>-1, 'E'=>1, 'W'=>-1, 'n'=>1, 's'=>-1, 'e'=>1, 'w'=>-1 }
40
+ sign = s[direction]
41
+ sign = sign == nil ? 1 : sign #Assume 'N' or 'E' if the direction is not set.
42
+ #Shouldn't have a negative value for degrees if the direction is specified.
43
+ #I am defaulting to the degrees sign if it is set, otherwise the direction given
44
+ sign = degrees.sign == -1 || (degrees == 0 && (minutes < 0 || (minutes == 0 && seconds < 0))) ? -1 : sign
45
+ sign * (degrees.abs + minutes/60.0 + seconds/3600.0)
46
+ end
47
+
48
+ #Class level function that takes an array of [degress,minutes, seconds, direction]
49
+ # and returns decimal degrees
50
+ # @return [Float] signed decimal degrees.
51
+ def self.decimal_deg_from_ary(a)
52
+ self.decimal_deg(*a)
48
53
  end
49
54
 
50
- #Class level utility function to return the value as deg,min,sec
51
- #Assumes decimal degress unless radians == true
52
- #returns an array of signed deg, min, sec.
53
- def self.dms(v, radians = false)
54
- v = v.to_d if radians
55
+ #Class level utility function to return the angle as deg,min,sec
56
+ #Assumes decimal degress unless radians == true .
57
+ # @return [Array] of signed deg, min, sec.
58
+ #Nb. * That min will be negative if the angle is negative and deg == 0
59
+ # * That sec will be negative if the angle is negative and deg == 0 && min == 0
60
+ def self.dms(angle, radians = false)
61
+ angle = angle.to_d if radians == true || radians == :radians
62
+ v = angle.abs
55
63
  deg = v.floor
56
- min = ((v-@deg)*60).floor
57
- sec = ((v-@deg-min/60.0)*3600.0)
64
+ min = ((v-deg)*60.0).floor
65
+ sec = ((v-deg-min/60.0)*3600.0)
58
66
 
59
- if v < 0 && deg == 0
60
- if min == 0
61
- sec = -sec
67
+ if angle < 0
68
+ if deg == 0
69
+ if min == 0
70
+ sec = -sec
71
+ else
72
+ min = -min
73
+ end
62
74
  else
63
- min = -min
75
+ deg = -deg
64
76
  end
65
77
  end
78
+
66
79
  return deg,min,sec
67
80
  end
68
81
 
69
82
  #Class level function equivalent to Angle.new(r, true)
70
- #Returns: new Angle
83
+ # @return [Angle]
71
84
  def self.radians(r=0) #passed in radians.
72
85
  self.new(r.to_f, true) #Nb. self is Angle, be we don't Angle.new, as we want subclasses to return their class, not Angle.
73
86
  end
74
87
 
75
88
  #Class level function equivalent to Angle.new(d, false) or just Angle.new(d)
76
- #Returns: new Angle
89
+ # @return [Angle]
77
90
  def self.degrees(d=0) #passed in degrees.
78
91
  self.new(d.to_radians, true)
79
92
  end
80
93
 
94
+ #Provides test for Module Comparable, giving us <,>,<=,>=,== between angles
95
+ # @return [true,false]
96
+ def <=>(angle)
97
+ if angle.class == Angle
98
+ @angle <=> angle.angle
99
+ else
100
+ @angle <=> angle
101
+ end
102
+ end
103
+
81
104
  #unary +
82
- #Returns: new Angle
105
+ # @return [Angle] equivalent to @angle
83
106
  def +@
84
- self.class.radians(@value) #Nb. Not Angle.new, as we want subclasses to return their class, not Angle.
107
+ self.class.radians(@angle) #Nb. Not Angle.new, as we want subclasses to return their class, not Angle.
85
108
  end
86
109
 
87
110
  #Unary -
88
- #Returns: new Angle
111
+ # @return [Angle] -@angle
89
112
  def -@
90
- self.class.radians(-@value)
113
+ self.class.radians(-@angle)
91
114
  end
92
115
 
93
- #Returns :new Angle
94
- def +(v)
95
- self.class.radians(@value + v)
116
+ # Binary addition operator. Can add angles and numbers, or two angles.
117
+ # @return [Angle]
118
+ def +(angle)
119
+ self.class.radians(@angle + angle)
96
120
  end
97
121
 
98
- #Returns: new Angle
99
- def -(v)
100
- self.class.radians(@value - v)
122
+ # Binary subtraction operator. Can add angles and numbers, or two angles.
123
+ # @return [Angle]
124
+ def -(angle)
125
+ self.class.radians(@angle - angle)
101
126
  end
102
127
 
103
- #Returns :new Angle
104
- def *(v)
105
- self.class.radians(@value * v)
128
+ # Binary multiply operator. Can add angles and numbers, or two angles.
129
+ # @return [Angle]
130
+ def *(angle)
131
+ self.class.radians(@angle * angle)
106
132
  end
107
133
 
108
- #Returns: new Angle
109
- def **(v)
110
- self.class.radians(@value ** v)
134
+ # Binary power of operator. Can add angles and numbers, or two angles.
135
+ # @return [Angle]
136
+ def **(angle)
137
+ self.class.radians(@angle ** angle)
111
138
  end
112
139
 
113
- #Returns: new Angle
114
- def /(v)
115
- self.class.radians(@value / v)
140
+ # Binary division operator. Can add angles and numbers, or two angles.
141
+ # @return [Angle]
142
+ def /(angle)
143
+ self.class.radians(@angle / angle)
116
144
  end
117
145
 
118
- #Returns: new Angle
119
- def %(v)
120
- self.class.radians(@value % v)
146
+ # Binary mod operator. Can add angles and numbers, or two angles.
147
+ # @return [Angle]
148
+ def %(angle)
149
+ self.class.radians(@angle % angle)
121
150
  end
122
151
 
123
- #Returns: angle in degrees
152
+ # @return [Float] angle in degrees
124
153
  def to_degrees
125
- @value.to_degrees
154
+ @angle.to_degrees
126
155
  end
127
156
 
157
+ # @return [Float] angle in degrees
128
158
  alias to_d to_degrees
129
159
 
130
160
  #Returns: angle in radians
131
161
  def to_radians
132
- @value
162
+ @angle
133
163
  end
134
164
 
135
165
  alias to_r to_radians
136
166
 
137
- #Returns: [deg,min,sec]
167
+ # Returns @angle as decimal_degrees
168
+ # @return [Array] of signed Floats: degrees,minutes,seconds
138
169
  #Nb. * That min will be negative if the angle is negative and deg == 0
139
170
  # * That sec will be negative if the angle is negative and deg == 0 && min == 0
140
171
  def to_dms
@@ -143,7 +174,7 @@ class Angle
143
174
  min = ((d-deg)*60).floor
144
175
  sec = ((d-deg-min/60.0)*3600.0)
145
176
 
146
- if @value < 0
177
+ if @angle < 0
147
178
  if deg == 0
148
179
  if min == 0
149
180
  sec = -sec
@@ -158,76 +189,78 @@ class Angle
158
189
  return deg, min, sec
159
190
  end
160
191
 
161
- #Returns: the angle in radians as a float (equivalent to to_radians)
192
+ # @return [Float] the angle in radians as a float (equivalent to to_radians)
162
193
  alias to_f to_radians
163
194
 
164
- #Returns the angle truncated to an integer, in radians.
195
+ # @return [Fixnum] the angle truncated to an integer, in radians.
165
196
  def to_i
166
197
  to_radians.to_i
167
198
  end
168
199
 
200
+ # @return [Fixnum] the angle truncated to an integer, in radians.
169
201
  alias to_int to_i
170
202
 
171
- def coerce(v)
172
- [Float(v), @value]
203
+ # @return [Array] the angle parameter as a Float and the @angle parameter from this class.
204
+ def coerce(angle)
205
+ [Float(angle), @angle]
173
206
  end
174
207
 
175
- #Returns: the sign of the angle. 1 for positive, -1 for negative.
208
+ # @return [Fixnum] the sign of the angle. 1 for positive, -1 for negative.
176
209
  def sign
177
- @value.sign
210
+ @angle.sign
178
211
  end
179
212
 
180
- #Returns: the absolute value of the angle in radians
213
+ # @return [Float] the absolute angle of the angle in radians
181
214
  def abs
182
- @value.abs
215
+ @angle.abs
183
216
  end
184
217
 
185
- #Returns: angle as compass bearing in radians.
218
+ # @return [Float] angle as compass bearing in radians.
186
219
  #Compass bearings are clockwise, Math angles are counter clockwise.
187
220
  def to_bearing
188
- self.class.new(Math::PI * 2 - @value,true)
221
+ self.class.new(Math::PI * 2 - @angle,true)
189
222
  end
190
223
 
191
- #Returns: the reverse angle in radians. i.e. angle + PI (or angle + 180 degrees)
224
+ # @return [Float] the reverse angle in radians. i.e. angle + PI (or angle + 180 degrees)
192
225
  def reverse
193
- if (v = @value + Math::PI) > Math::PI * 2
194
- v -= Math::PI * 2
226
+ if (angle = @angle + Math::PI) > Math::PI * 2
227
+ angle -= Math::PI * 2
195
228
  end
196
- return self.class.new(v,true)
229
+ return self.class.new(angle,true)
197
230
  end
198
231
 
199
232
 
200
- #Returns: angle in radians as a string.
233
+ # @return [String] angle in radians as a string.
201
234
  def to_s(fmt = nil)
202
235
  return to_radians.to_s if(fmt == nil)
203
236
  return strf(fmt)
204
237
  end
205
238
 
206
239
  #formated output of the angle.
207
- #The default format is a signed deg°minutes′seconds with leading 0's in the minutes and seconds and 4 decimal places for seconds.
240
+ #The default format is a signed deg 0minutes'seconds" with leading 0's in the minutes and seconds and 4 decimal places for seconds.
208
241
  #formats are:
209
242
  # * %wd output the degrees as an integer.
210
243
  # ** where w is 0, 1, 2 or 3 and represents the field width.
211
244
  # *** 1 is the default, which indicates that at least 1 digit is displayed
212
- # *** 2 indicates that at least 2 digits are displayed. 1 to 9 will be displayed as 01° to 09°
213
- # *** 3 indicates that at least 4 digits are displayed. 10 to 99 will be displayed as 010° to 099°
245
+ # *** 2 indicates that at least 2 digits are displayed. 1 to 9 will be displayed as 01 0 to 09 0
246
+ # *** 3 indicates that at least 4 digits are displayed. 10 to 99 will be displayed as 010 0 to 099 0
214
247
  #
215
248
  # * %w.pD outputs degrees as a float.
216
- # ** p is the number of decimal places.
249
+ # * p is the number of decimal places.
217
250
  #
218
251
  # * %wm output minutes as an integer.
219
- # ** where the width w is 0, 1 , 2 with similar meaning to %d. p is again the number of decimal places.
252
+ # * where the width w is 0, 1 , 2 with similar meaning to %d. p is again the number of decimal places.
220
253
  #
221
- # * %w.pM outputs minutes as a float .e.g. 01.125′.
222
- # ** p is the number of decimal places.
254
+ # * %w.pM outputs minutes as a float .e.g. 01.125'.
255
+ # * p is the number of decimal places.
223
256
  #
224
257
  # * %wW outputs secs/60 as a float without the leading '0.'.
225
- # Used with %m like this %2m′%4W , to get minute marker before the decimal places.
226
- # e.g. -37°01′.1167 rather than -37°01.1167
227
- # ** p is the number of decimal places.
258
+ # Used with %m like this %2m'%4W , to get minute marker before the decimal places.
259
+ # e.g. -37 001'.1167 rather than -37 001.1167'
260
+ # * p is the number of decimal places.
228
261
  #
229
262
  # * %w.ps output seconds as a float.
230
- # ** where the width w is 1 , 2 with similar meaning to %d. p is again the number of decimal places.
263
+ # * where the width w is 1 , 2 with similar meaning to %d. p is again the number of decimal places.
231
264
  #
232
265
  # * %N outputs N if the angle is positive and S if the angle is negative.
233
266
  #
@@ -238,7 +271,8 @@ class Angle
238
271
  # * %% outputs %
239
272
  #
240
273
  # Other strings in the format are printed as is.
241
- def strf(fmt="%d°%2m′%2.4s″")
274
+ # @return [String]
275
+ def strf(fmt="%d %2m'%2.4s\"")
242
276
  tokens = fmt.scan(/%[0-9\.]*[%dmsDMNErW]|[^%]*/)
243
277
  have_dir = have_dms = false
244
278
  tokens.collect! do |t|
@@ -288,7 +322,7 @@ class Angle
288
322
  when 'd'
289
323
  s += s_int(deg, t[1], have_dir)
290
324
  when 'D'
291
- s += s_float(@value.to_d, t[1], t[2], have_dir)
325
+ s += s_float(@angle.to_d, t[1], t[2], have_dir)
292
326
  when 'm'
293
327
  s += s_int(min, t[1], have_dir)
294
328
  when 'M'
@@ -298,11 +332,11 @@ class Angle
298
332
  when 's'
299
333
  s += s_float(sec, t[1], t[2], have_dir)
300
334
  when 'r'
301
- s += s_float(@value, t[1], t[2], have_dir)
335
+ s += s_float(@angle, t[1], t[2], have_dir)
302
336
  when 'N'
303
- s += (@value < 0 ? 'S' : 'N')
337
+ s += (@angle < 0 ? 'S' : 'N')
304
338
  when 'E'
305
- s += (@value < 0 ? 'W' : 'E')
339
+ s += (@angle < 0 ? 'W' : 'E')
306
340
  end
307
341
  else
308
342
  s += t[1] #the fillers.
@@ -313,37 +347,50 @@ class Angle
313
347
  end
314
348
 
315
349
  private
316
- def s_places(v, places)
350
+ #Output angle_dec as a string to the number of decimal places specified by places.
351
+ #Assumes the angle is 0 <= angle_dec < 1
352
+ #No leading '0' is output. The string starts with a '.'
353
+ #If ploces is -1, then all decimal places are returned.
354
+ # @return [String]
355
+ def s_places(angle_dec, places)
317
356
  if places != -1
318
- dec_p = (v * 10 ** places).round
319
- f = ".%0#{places > 0 ? places : ''}d"
320
- f % dec_p
357
+ places > 0 ? ".%0#{places}d" % (angle_dec * 10 ** places).round : ''
321
358
  else
322
- '.' + v_dec.to_s[2..-1]
359
+ angle_dec.to_s[1..-1] #Output all decimal places stripping the leading 0
323
360
  end
324
361
  end
325
362
 
326
- def s_only_places(v, places)
327
- v_int, v_dec = v.abs.divmod(1)
328
- s_places(v_dec, places)
329
- end
330
-
331
- #Prints fixed width decimal portion with leading 0s to get at least the width specified
363
+ #return the angle as a string with fixed width decimal portion with leading 0s
364
+ #to get at least the width specified
332
365
  #Prints the number of places after the decimal point rounded to places places.
333
366
  #-1 width means no width format
334
367
  #-1 places means print all decimal places.
335
368
  #abs means print the absolute value.
336
- def s_float(v, width, places, abs)
337
- v_int, v_dec = v.abs.divmod(1)
369
+ # @return [String]
370
+ def s_float(angle, width, places, abs)
371
+ angle_int, angle_dec = angle.abs.divmod(1)
338
372
  f = "%0#{width > 0 ? width : ''}d"
339
- s = (abs == false && v.sign == -1) ? '-' : '' #catch the case of -0
340
- s += f % v.abs + s_places(v_dec, places)
373
+ s = (abs == false && angle.sign == -1) ? '-' : '' #catch the case of -0
374
+ s += f % angle.abs + s_places(angle_dec, places)
341
375
  end
342
376
 
343
- def s_int(v, width, abs)
377
+ #Return the integer part of angle as a string of fixed width
378
+ #If abs == true, then return the absolute value.
379
+ # @return [Fixnum]
380
+ def s_int(angle, width, abs)
344
381
  f = "%0#{width > 0 ? width : ''}d"
345
- s = (abs == false && v.sign == -1) ? '-' : '' #catch the case of -0
346
- s += f % v.abs
382
+ s = (abs == false && angle.sign == -1) ? '-' : '' #catch the case of -0
383
+ s += f % angle.abs
384
+ end
385
+
386
+ #Return the fractional part of angle as a string,
387
+ #to the number of decimal places specified by 'places'.
388
+ #No leading '0' is output. The string starts with a '.'
389
+ #If ploces is -1, then all decimal places are returned.
390
+ # @return [String]
391
+ def s_only_places(angle, places)
392
+ angle_int, angle_dec = angle.abs.divmod(1)
393
+ s_places(angle_dec, places)
347
394
  end
348
395
  end
349
396
 
@@ -1,29 +1,34 @@
1
- #Holds both latitude and longitude, and the altitude at that point
2
1
 
3
2
  require 'angle.rb'
4
3
 
4
+ #Holds the latitude, longitude, and the altitude for the coordinate
5
5
  class Coordinate
6
6
  attr_accessor :latitude, :longitude, :altitude
7
+
7
8
  #latitude and longitude can be Strings or Numeric, or anything else with to_radians and to_f
8
- #latitude and longitude are in degrees unless radians == true
9
+ #latitude and longitude are in degrees unless radians == true (or set to :radians)
9
10
  def initialize(latitude=0, longitude=0, altitude=0, radians = false)
10
11
  @latitude = Latitude.new(latitude,radians)
11
12
  @longitude = Longitude.new(longitude,radians)
12
13
  @altitude = altitude.to_f
13
14
  end
14
15
 
15
- #Should add a format string to this.
16
16
  #Returns: Latitude longitude and altitude as a single string.
17
+ #Should add an optional format string to this.
17
18
  def to_s
18
19
  "#{@latitude.to_s } #{@longitude.to_s} #{@altitude}m"
19
20
  end
20
21
 
22
+ #Return coordinate as a 3 member array, with
23
+ #members, latitude, longitude and altitude
21
24
  def to_ary
22
25
  [ @latitude, @longitude, @altitude ]
23
26
  end
24
27
 
25
28
  alias to_a to_ary
26
29
 
30
+ #return coordinate a 3 member hash with
31
+ #keys :latitude, :longitude, and :altitude
27
32
  def to_hash
28
33
  { :latitude => @latitude, :longitude => @longitude, :altitude => @altitude }
29
34
  end
@@ -13,6 +13,7 @@ class Numeric
13
13
  self * 180 / Math::PI
14
14
  end
15
15
  end
16
+
16
17
  #Converts degrees to Radians
17
18
  #if optional argument mod == true, then applies % Math::PI
18
19
  #Returns: radians
@@ -49,22 +50,22 @@ end
49
50
  #Extends String to to_dec_degrees, add to_r and to_d
50
51
  class String
51
52
  #string expected to be degrees, returns decimal degrees.
52
- #common forms are S37°01′7.5″, 37°01′7.5S , -37°01′7.5″, -37° 1.512′. -37.01875°, 37°01′.512S, S37°01′.512, ...
53
+ #common forms are S37 001'7.5'', 37 001'7.5''S , -37 001'7.5'', -37 0 1.512'. -37.01875 0, 37 001'.512S, S37 001'.512, ...
53
54
  #Returns: angle in decimal degrees
54
55
  def to_dec_degrees
55
- #reorder 37°01′.512S, S37°01′.512 into 37°01.512S, S37°01.512 respectively
56
- s = self.gsub(/([0-9])(['])\.([0-9]+)/, '\1.\3\2')
57
- #add in minutes and seconds to get 3 values 'deg 0 0'from S37°, 37°S
56
+ #reorder 37 001'.512S, S37 001'.512 into 37 001.512'S, S37 001.512' respectively
57
+ s = self.gsub(/([0-9])([''])\.([0-9]+)/, '\1.\3\2')
58
+ #add in minutes and seconds to get 3 values 'deg 0 0'from S37 0, 37 0S
58
59
  s.gsub!(/^([^0-9\.\-]*)([0-9\-\.]+)([^0-9\-\.]*)$/, '\1\2\3 0 0\5')
59
- #add in seconds get 3 values 'deg min 0' from S37°1.512′, 37°1.512S
60
+ #add in seconds get 3 values 'deg min 0' from S37 01.512', 37 01.512'S
60
61
  s.gsub!(/^([^0-9\.\-]*)([0-9\-\.]+)([^0-9\-\.]+)([0-9\-\.]+)([^0-9\-\.]*)$/, '\1\2\3\4 0\5')
61
62
 
62
- #look for anything of the form S37°01′7.5″, S37°1.512′, S37.01875°, ...
63
+ #look for anything of the form S37 001'7.5'', S37 01.512', S37.01875 0, ...
63
64
  s.scanf("%[NSEW]%f%[^0-9-]%f%[^0-9-]%f") do |direction, deg, sep1, min, sep2, sec|
64
65
  return Angle.decimal_deg( deg, min, sec, direction)
65
66
  end
66
67
 
67
- #look for anything of the form 37°01′7.5S , -37°01′7.5″, -37° 1.512′. -37.01875°, ...
68
+ #look for anything of the form 37 001'7.5''S , -37 001'7.5'', -37 0 1.512'. -37.01875 0, ...
68
69
  s.scanf("%f%[^0-9-]%f%[^0-9-]%f%[^NSEW]%[NSEW]") do |deg, sep1, min, sep2, sec, sep3, direction|
69
70
  return Angle.decimal_deg( deg, min, sec, direction)
70
71
  end
@@ -1,12 +1,13 @@
1
- #Subclass of Angle to add in special treatment of to_d, to_r , to_s
2
1
 
3
2
  require 'angle.rb'
4
3
 
4
+ #Subclass of Angle to add in special treatment of to_d, to_r , to_s
5
+ #Latitude degrees are between -PI and PI, South to North (+/- 90 degrees)
6
+
5
7
  class Latitude < Angle
6
- #Latitude degrees are between -90 and 90, South to North
8
+
7
9
  #Returns angle as degrees in range -90 and 90
8
10
  def to_degrees
9
- #longitude's are -180 to 180 for west to east
10
11
  degrees = super
11
12
  case
12
13
  when degrees > 270 ; -(360 - degrees)
@@ -17,22 +18,20 @@ class Latitude < Angle
17
18
  end
18
19
  end
19
20
 
20
- #Latitude degrees are between -PI and PI, South to North
21
21
  #Returns: angle as degrees in range -PI and PI
22
22
  def to_radians
23
- #longitude's are -180 to 180 for west to east
24
23
  case
25
- when @value > 3*Math::PI/2 ; @value - Math::PI * 2
26
- when @value > Math::PI ; Math::PI - @value
27
- when @value > Math::PI/2 ; Math::PI - @value
28
- when @value < -Math::PI/2 ; -Math::PI - @value
29
- else @value
24
+ when @angle > 3*Math::PI/2 ; @angle - Math::PI * 2
25
+ when @angle > Math::PI ; Math::PI - @angle
26
+ when @angle > Math::PI/2 ; Math::PI - @angle
27
+ when @angle < -Math::PI/2 ; -Math::PI - @angle
28
+ else @angle
30
29
  end
31
30
  end
32
31
 
33
32
  #Returns: angle as string in degrees minutes seconds direction.
34
33
  #A South angle is negative, North is Positive.
35
- def to_s(fmt='%2d°%2m′%2.4s″%N')
34
+ def to_s(fmt="%2d %2m'%2.4s\"%N")
36
35
  super(fmt)
37
36
  end
38
37
 
@@ -1,9 +1,11 @@
1
- #Subclass of Angle to add in special treatment of to_d, to_r and to_s
2
1
 
3
2
  require 'angle.rb'
4
3
 
4
+ #Subclass of Angle to add in special treatment of to_d, to_r and to_s
5
+ #Longitude degrees are between -2PI and 2PI, West to East (+/- 180 degrees)
6
+
5
7
  class Longitude < Angle
6
- #Longitude degrees are between -180 and 180 West to East
8
+
7
9
  #Returns angle as degrees in range -180 and 180
8
10
  def to_degrees
9
11
  degrees = super
@@ -13,18 +15,17 @@ class Longitude < Angle
13
15
  end
14
16
  end
15
17
 
16
- #Longitude degrees are between -2PI and 2PI, West to East
17
18
  #Returns: angle as degrees in range -2PI and 2PI
18
19
  def to_radians
19
20
  case
20
- when @value > Math::PI ; @value - 2 * Math::PI
21
- else @value
21
+ when @angle > Math::PI ; @angle - 2 * Math::PI
22
+ else @angle
22
23
  end
23
24
  end
24
25
 
25
26
  #Returns: angle as string in degrees minutes seconds direction.
26
27
  #A West angle is negative, East is Positive.
27
- def to_s(fmt='%3d°%2m′%2.4s″%E')
28
+ def to_s(fmt="%3d %2m'%2.4s\"%E")
28
29
  super(fmt)
29
30
  end
30
31
 
@@ -1,10 +1,11 @@
1
- #Holds a bearing and distance
2
1
 
3
2
  require 'angle.rb'
4
3
 
4
+ #Holds a bearing and distance
5
5
  class TrackAndDistance
6
6
  attr_accessor :bearing, :distance
7
- #Bearing is in degrees unless radians == true.
7
+
8
+ #Bearing is in degrees unless radians == true (or set to :radians).
8
9
  #Bearing can be a String or Numeric or any object with to_radians and to_f
9
10
  def initialize(bearing, distance, radians=false)
10
11
  @bearing = Angle.new(bearing, radians)
@@ -23,10 +24,12 @@ class TrackAndDistance
23
24
  end
24
25
  end
25
26
 
27
+ #Returns an array with members bearing and distance.
26
28
  def to_ary
27
29
  [ @bearing, @distance ]
28
30
  end
29
31
 
32
+ #Returns a hash with keys :bearing and :distance
30
33
  def to_hash
31
34
  { :bearing => @bearing, :distance => @distance }
32
35
  end
@@ -1,9 +1,3 @@
1
- #Vincenty's algorithms for finding the bearing and distance between two coordinates and
2
- #for finding the latitude and longitude, given a start coordinate, distance and bearing.
3
- #
4
- # Coded from formulae from Wikipedia http://en.wikipedia.org/wiki/Vincenty%27s_formulae
5
- # Modified to incorporate corrections to formulae as found in script on http://www.movable-type.co.uk/scripts/LatLongVincenty.html
6
- # Added my Modification of the distanceAndAngle formulae to correct the compass bearing.
7
1
  require 'core_extensions.rb'
8
2
  require 'angle.rb'
9
3
  require 'latitude.rb'
@@ -11,8 +5,14 @@ require 'longitude.rb'
11
5
  require 'track_and_distance.rb'
12
6
  require 'coordinate.rb'
13
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
+ #
11
+ # Coded from formulae from Wikipedia http://en.wikipedia.org/wiki/Vincenty%27s_formulae
12
+ # Modified to incorporate corrections to formulae as found in script on http://www.movable-type.co.uk/scripts/LatLongVincenty.html
13
+ # Added my Modification of the distanceAndAngle formulae to correct the compass bearing.
14
14
  class Vincenty < Coordinate
15
- VERSION = '1.0.3'
15
+ VERSION = '1.0.4'
16
16
 
17
17
  def version
18
18
  VERSION
@@ -24,7 +24,7 @@ class Vincenty < Coordinate
24
24
  #Takes: argument p2 is target coordinate that we want the bearing to.
25
25
  #Returns: TrackAndDistance object with the compass bearing and distance in meters to P2
26
26
  def sphericalDistanceAndAngle( p2 )
27
- a = 6378137 #equatorial radius in meters (±2 m)
27
+ a = 6378137 #equatorial radius in meters (+/-2 m)
28
28
  b = 6356752.31424518 #polar radius in meters
29
29
  r = (a+b)/2 #average diametre as a rough estimate for our tests.
30
30
 
@@ -52,7 +52,7 @@ class Vincenty < Coordinate
52
52
  #Returns: TrackAndDistance object with the compass bearing and distance in meters to P2
53
53
  def distanceAndAngle( p2 )
54
54
  # a, b = major & minor semiaxes of the ellipsoid
55
- a = 6378137 #equatorial radius in meters (±2 m)
55
+ a = 6378137 #equatorial radius in meters (+/-2 m)
56
56
  b = 6356752.31424518 #polar radius in meters
57
57
  f = (a-b)/a # flattening
58
58
 
@@ -67,7 +67,7 @@ class Vincenty < Coordinate
67
67
 
68
68
  l = (lon2 - lon1).abs #difference in longitude
69
69
  l = 2*Math::PI - l if l > Math::PI
70
- u1 = Math.atan( ( 1 - f) * Math.tan( lat1 ) ) #U is reduced latitude
70
+ u1 = Math.atan( ( 1 - f) * Math.tan( lat1 ) ) #U is 'reduced latitude'
71
71
  u2 = Math.atan( ( 1 - f) * Math.tan( lat2 ) )
72
72
  sin_u1 = Math.sin(u1)
73
73
  cos_u1 = Math.cos(u1)
@@ -121,7 +121,7 @@ class Vincenty < Coordinate
121
121
  #Takes: TrackAndDistance object with bearing and distance.
122
122
  #Returns new Vincenty object with the destination coordinates.
123
123
  def sphereDestination( track_and_distance )
124
- a = 6378137 #equatorial radius in meters (±2 m)
124
+ a = 6378137 #equatorial radius in meters (+/-2 m)
125
125
  b = 6356752.31424518 #polar radius in meters
126
126
  r = (a+b)/2 #average diametre as a rough estimate for our tests.
127
127
 
@@ -141,10 +141,9 @@ class Vincenty < Coordinate
141
141
  #Assumes earth is a WGS-84 Ellipsod.
142
142
  #Takes: TrackAndDistance object with bearing and distance.
143
143
  #Returns: new Vincenty object with the destination coordinates.
144
-
145
144
  def destination( track_and_distance )
146
145
  # a, b = major & minor semiaxes of the ellipsoid
147
- a = 6378137 #equatorial radius in meters (±2 m)
146
+ a = 6378137 #equatorial radius in meters (+/-2 m)
148
147
  b = 6356752.31424518 #polar radius in meters
149
148
  f = (a-b)/a # flattening
150
149
 
@@ -5,14 +5,14 @@ class TestAngle< Test::Unit::TestCase
5
5
  #test Angle creation
6
6
  def test_angle
7
7
  assert_equal(Angle.new(), 0)
8
- assert_equal(Angle.new("S37°017.5").to_d, -37.01875) #Leading NSEW
9
- assert_equal(Angle.new("37°017.5S").to_d , -37.01875) #Trailing NSEW
10
- assert_equal(Angle.new("-37°017.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.
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
16
  assert_equal(Angle.new([-37, 1, 7.5]).to_d, -37.01875) #an array of deg,min,sec
17
17
  assert_equal(Angle.new(-37.01875).to_d, -37.01875)
18
18
  assert_equal(Angle.degrees(-37.01875).to_d, -37.01875)
@@ -20,25 +20,32 @@ class TestAngle< Test::Unit::TestCase
20
20
  assert_equal(Angle.new(-0.646099072472651, true).to_d.round(5), -37.01875)
21
21
  assert_equal(Angle.new(-0.646099072472651, true).to_r, -0.646099072472651)
22
22
  assert_equal(Angle.radians(-0.646099072472651).to_d.round(5), -37.01875)
23
+ 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.
23
30
  end
24
31
 
25
32
  def test_strf
26
- a = Angle.new("S37°017.5")
27
- assert_equal("-37°0107.5000", a.strf) #default format of strf
28
- assert_equal("37°0107.50000S", a.strf( "%d°%2m′%2.5s″%N" ))
29
- assert_equal("37°0107.50000W", a.strf("%d°%2m′%2.5s″%E" ))
30
- assert_equal("-37°0107.5000", a.strf("%d°%2m′%2.4s" ))
31
- assert_equal("-37°01.1250′\n", a.strf("%d°%2.4M′\n" ))
32
- assert_equal("*** -37°01′.1250", a.strf( "*** %d°%2m′%4W" )) #puting the minute ' before decimal point.
33
- assert_equal("-37.01875°", a.strf("%0.5D°" ))
33
+ 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.50000\"S", a.strf( "%d %2m'%2.5s\"%N" ))
36
+ assert_equal("37 01'07.50000\"W", a.strf("%d %2m'%2.5s\"%E" ))
37
+ assert_equal("-37 01'07.5000\"", a.strf("%d %2m'%2.4s\"" ))
38
+ 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 " ))
34
41
  assert_equal("-0.64610 radians\n", a.strf("%0.5r radians\n" ))
35
42
 
36
- assert_equal("-037°017.5000", Angle.new("-37°017.5").to_s('%3d°%2m′%1.4s')) #testing leading 0 with -deg, no leading 0 %s
37
- assert_equal("00°0107.5000S", Angle.new("0°017.5S").to_s('%2d°%2m′%2.4s″%N')) #testing 0 degrees and leading 0 %s
38
- assert_equal("00°-0107.5000", Angle.new("0°017.5S").to_s('%2d°%2m′%2.4s')) #testing 0 degrees and -min
39
- assert_equal("00°-0107.5000", Angle.new("0°017.5S").to_s('%2d°%2m′%2.4s') ) #test of 0 degrees, -min, no NSEW
40
- assert_equal("000°0007.5000W", Angle.new("0°07.5W").to_s('%3d°%2m′%2.4s″%E') ) #testing E W 0 deg and 0 min and -sec
41
- assert_equal("00°00′-07.5000", Angle.new("0°07.5S").to_s('%2d°%2m′%2.4s') ) #testing 0 deg and 0 min and -sec no NSEW
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
42
49
  end
43
50
 
44
51
  def test_operators
@@ -13,6 +13,6 @@ class TestAngle< Test::Unit::TestCase
13
13
  assert_equal(-36.9923293459124, ch[:latitude].to_d)
14
14
  assert_equal(174.485341187381, ch[:longitude].to_d)
15
15
  assert_equal(13.5, ch[:altitude])
16
- assert_equal("36°5932.3856S 174°2907.2283E 13.5m", c.to_s)
16
+ assert_equal("36 59'32.3856\"S 174 29'07.2283\"E 13.5m", c.to_s)
17
17
  end
18
18
  end
@@ -3,12 +3,12 @@ require 'vincenty.rb'
3
3
 
4
4
  class TestAngle< Test::Unit::TestCase
5
5
  def test_strf
6
- assert_equal("37°0107.5000S", Latitude.new("S37°017.5").to_s)
7
- assert_equal("37°0107.5000S", Latitude.new("-37°017.5").to_s)
8
- assert_equal("37°0107.5000S", Latitude.new("37°017.5S").to_s)
9
- assert_equal("37°0107.5000N", Latitude.new("N37°017.5").to_s)
10
- assert_equal("37°0107.5000N", Latitude.new("37°017.5").to_s)
11
- assert_equal("37°0107.5000N", Latitude.new("37°017.5N").to_s)
6
+ assert_equal("37 01'07.5000\"S", Latitude.new("S37 01'7.5\"").to_s)
7
+ assert_equal("37 01'07.5000\"S", Latitude.new("-37 01'7.5\"").to_s)
8
+ assert_equal("37 01'07.5000\"S", Latitude.new("37 01'7.5\"S").to_s)
9
+ assert_equal("37 01'07.5000\"N", Latitude.new("N37 01'7.5\"").to_s)
10
+ assert_equal("37 01'07.5000\"N", Latitude.new("37 01'7.5\"").to_s)
11
+ assert_equal("37 01'07.5000\"N", Latitude.new("37 01'7.5\"N").to_s)
12
12
  end
13
13
  def test_to_radians
14
14
  assert_equal(Math::PI/4, Latitude.degrees(45).to_r)
@@ -3,12 +3,12 @@ require 'vincenty.rb'
3
3
 
4
4
  class TestAngle< Test::Unit::TestCase
5
5
  def test_strf
6
- assert_equal("037°0107.5000W", Longitude.new("W37°017.5").to_s)
7
- assert_equal("037°0107.5000W", Longitude.new("-37°017.5").to_s)
8
- assert_equal("037°0107.5000W", Longitude.new("37°017.5W").to_s)
9
- assert_equal("037°0107.5000E", Longitude.new("E37°017.5").to_s)
10
- assert_equal("037°0107.5000E", Longitude.new("37°017.5").to_s)
11
- assert_equal("037°0107.5000E", Longitude.new("37°017.5E").to_s)
6
+ assert_equal("037 01'07.5000\"W", Longitude.new("W37 01'7.5\"").to_s)
7
+ assert_equal("037 01'07.5000\"W", Longitude.new("-37 01'7.5\"").to_s)
8
+ assert_equal("037 01'07.5000\"W", Longitude.new("37 01'7.5\"W").to_s)
9
+ assert_equal("037 01'07.5000\"E", Longitude.new("E37 01'7.5\"").to_s)
10
+ assert_equal("037 01'07.5000\"E", Longitude.new("37 01'7.5\"").to_s)
11
+ assert_equal("037 01'07.5000\"E", Longitude.new("37 01'7.5\"E").to_s)
12
12
  end
13
13
  def test_to_radians
14
14
  assert_equal(Math::PI/4, Longitude.degrees(45).to_r)
@@ -4,13 +4,13 @@ require 'vincenty.rb'
4
4
  class TestAngle< Test::Unit::TestCase
5
5
  #test TrackAndDistance
6
6
  def test_track_and_distance
7
- assert_equal("140°1410.0000 12.0m", TrackAndDistance.new(Angle.new("320,14,10").reverse, 12.0).to_s)
8
- assert_equal("215°0300.0000 19.73m", TrackAndDistance.new("215,3,0", 19.73 ).to_s)
7
+ assert_equal("140 14'10.0000\" 12.0m", TrackAndDistance.new(Angle.new("320,14,10").reverse, 12.0).to_s)
8
+ assert_equal("215 03'00.0000\" 19.73m", TrackAndDistance.new("215,3,0", 19.73 ).to_s)
9
9
  a = TrackAndDistance.new("215,3,0", 19.73 ).to_ary
10
- assert_equal("215°0300.0000", a[0].strf)
10
+ assert_equal("215 03'00.0000\"", a[0].strf)
11
11
  assert_equal("19.73", a[1].to_s)
12
12
  a = TrackAndDistance.new("215,3,0", 19.73 ).to_hash
13
- assert_equal("215°0300.0000", a[:bearing].strf)
13
+ assert_equal("215 03'00.0000\"", a[:bearing].strf)
14
14
  assert_equal("19.73", a[:distance].to_s)
15
15
  end
16
16
  end
@@ -82,13 +82,13 @@ class TestVincenty< Test::Unit::TestCase
82
82
 
83
83
  #Run the Australian Geoscience site example.
84
84
  def test_geoscience_au
85
- flindersPeak = Vincenty.new("-37°57'3.72030″", "144°25'29.52440″" )
86
- buninyong = Vincenty.new("-37 ° 39 ' 10.15610 ''", "143 ° 55 ' 35.38390 ''") #Buninyong
85
+ flindersPeak = Vincenty.new("-37 57'3.72030″", "144 25'29.52440″" )
86
+ buninyong = Vincenty.new("-37 39 ' 10.15610 ''", "143 55 ' 35.38390 ''") #Buninyong
87
87
  track_and_bearing = flindersPeak.distanceAndAngle( buninyong )
88
- assert_equal(Angle.new("306 ° 52 ' 5.37 ''").to_d.round(4), track_and_bearing.bearing.to_d.round(4))
88
+ assert_equal(Angle.new("306 52 ' 5.37 ''").to_d.round(4), track_and_bearing.bearing.to_d.round(4))
89
89
  assert_equal(54972.271, track_and_bearing.distance.round(3))
90
90
 
91
- destination = flindersPeak.destination(TrackAndDistance.new("306 ° 52 ' 5.37 ''", 54972.271))
91
+ destination = flindersPeak.destination(TrackAndDistance.new("306 52 ' 5.37 ''", 54972.271))
92
92
  assert_equal(buninyong.latitude.to_d.round(4), destination.latitude.to_d.round(4))
93
93
  assert_equal(buninyong.longitude.to_d.round(4), destination.longitude.to_d.round(4))
94
94
  end
metadata CHANGED
@@ -1,32 +1,82 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: vincenty
3
- version: !ruby/object:Gem::Version
4
- version: 1.0.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ prerelease:
5
6
  platform: ruby
6
- authors:
7
+ authors:
7
8
  - Rob Burrowes
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
-
12
- date: 2009-12-31 00:00:00 +13:00
13
- default_executable:
14
- dependencies:
15
- description: "* Vincenty wrote an algorithm for calculating the bearing and distance between two coordinates on the earth and an algorithm for finding a second coordinate, given a starting coordinate, bearing and destination. The algorithms model the earth as an ellipsoid, using the WGS-84 model. This is the common GPS model for mapping to latitudes and longitudes. This is a Ruby implementation of Vincenty's algorithms, and the Vincenty class includes two methods for modeling the earth as a sphere. These were added as a reference for testing the Vincenty algorithm, but could be used on their own. The package also makes use of several other classes that may be useful in their own Right. These include class Angle, class Latitude (subclass of Angle), class Longitude (subclass of Angle), class TrackAndBearing and class coordinate (which class Vincenty is a subclass) Angle requires extensions to Numeric and String to provide to_radians (to_r) and to_degrees (to_d). String also includes a to_decimal_degrees(), which converts most string forms of Latitude and Longitude to decimal form. These extensions are included in the package in core_extensions.rb. Float has also been extended to change round to have an optional argument specifying the number of decimal places to round to. This is fully compatible with the Float.round, as the default is to round to 0 decimal places. * The Vincenty code is based on the wikipedia presentation of the Vincenty algorithm http://en.wikipedia.org/wiki/Vincenty%27s_formulae . * The algorithm was modified to include changes I found at http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html. * I also altered the formulae to correctly return the bearing for angles greater than 180. * Vincenty's original publication ** T Vincenty, \"Direct and Inverse Solutions of Geodesics on the Ellipsoid with application of nested equations\", Survey Review, vol XXII no 176, 1975 http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf"
16
- email:
17
- - rob@burrowes.org
12
+ date: 2013-01-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: hoe-yard
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.2
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: hoe
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.1'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.1'
46
+ description: ! "* Vincenty wrote an algorithm for calculating the bearing and distance
47
+ between two coordinates on the earth\n and an algorithm for finding a second coordinate,
48
+ given a starting coordinate, bearing and destination.\n The algorithms model the
49
+ earth as an ellipsoid, using the WGS-84 model. This is the common GPS model for\n
50
+ \ mapping to latitudes and longitudes.\n\n This is a Ruby implementation of Vincenty's
51
+ algorithms, and the Vincenty class includes two methods for \n modeling the earth
52
+ as a sphere. These were added as a reference for testing the Vincenty algorithm,
53
+ but\n could be used on their own. \n\n The package also makes use of several other
54
+ classes that may be useful in their own Right. These include\n class Angle, class
55
+ Latitude (subclass of Angle), class Longitude (subclass of Angle), \n class TrackAndBearing
56
+ and class coordinate (which class Vincenty is a subclass)\n\n Angle requires extensions
57
+ to Numeric and String to provide to_radians (to_r) and to_degrees (to_d). String
58
+ also includes a to_decimal_degrees(), which converts most string forms of Latitude
59
+ and Longitude to decimal form. These extensions are included in the package in core_extensions.rb.
60
+ Float has also been extended to change round to have an optional argument specifying
61
+ the number of decimal places to round to. This is fully compatible with the Float.round,
62
+ as the default is to round to 0 decimal places.\n\n* The Vincenty code is based
63
+ on the wikipedia presentation of the Vincenty algorithm http://en.wikipedia.org/wiki/Vincenty%27s_formulae
64
+ .\n* The algorithm was modified to include changes I found at http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html.\n*
65
+ \ I also altered the formulae to correctly return the bearing for angles greater
66
+ than 180. \n \n* Vincenty's original publication\n\n** T Vincenty, \"Direct and
67
+ Inverse Solutions of Geodesics on the Ellipsoid with application of nested equations\",
68
+ Survey Review, vol XXII no 176, 1975 http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf"
69
+ email:
70
+ - r.burrowes@auckland.ac.nz
18
71
  executables: []
19
-
20
72
  extensions: []
21
-
22
- extra_rdoc_files:
73
+ extra_rdoc_files:
23
74
  - History.txt
24
75
  - Manifest.txt
25
- - README.txt
26
- files:
76
+ files:
27
77
  - History.txt
28
78
  - Manifest.txt
29
- - README.txt
79
+ - README.md
30
80
  - Rakefile
31
81
  - lib/angle.rb
32
82
  - lib/coordinate.rb
@@ -42,34 +92,37 @@ files:
42
92
  - test/ts_vincenty.rb
43
93
  - test/ts_coordinate.rb
44
94
  - test/ts_track_and_distance.rb
45
- has_rdoc: true
46
- homepage: http://rubyforge.org/projects/vincenty/
95
+ - .gemtest
96
+ homepage: http://rbur004.github.com/vincenty/
47
97
  licenses: []
48
-
49
98
  post_install_message:
50
- rdoc_options:
51
- - --main
52
- - README.txt
53
- require_paths:
99
+ rdoc_options:
100
+ - --markup
101
+ - markdown
102
+ - --protected
103
+ - --title
104
+ - Vincenty
105
+ - --quiet
106
+ require_paths:
54
107
  - lib
55
- required_ruby_version: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - ">="
58
- - !ruby/object:Gem::Version
59
- version: "0"
60
- version:
61
- required_rubygems_version: !ruby/object:Gem::Requirement
62
- requirements:
63
- - - ">="
64
- - !ruby/object:Gem::Version
65
- version: "0"
66
- version:
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
67
120
  requirements: []
68
-
69
121
  rubyforge_project: vincenty
70
- rubygems_version: 1.3.5
122
+ rubygems_version: 1.8.24
71
123
  signing_key:
72
- specification_version: 2
73
- summary: "* Vincenty wrote an algorithm for calculating the bearing and distance between two coordinates on the earth and an algorithm for finding a second coordinate, given a starting coordinate, bearing and destination"
124
+ specification_version: 3
125
+ summary: ! '* Vincenty wrote an algorithm for calculating the bearing and distance
126
+ between two coordinates on the earth and an algorithm for finding a second coordinate,
127
+ given a starting coordinate, bearing and destination'
74
128
  test_files: []
75
-