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.
- checksums.yaml +7 -0
- data/History.txt +62 -52
- data/README.md +3 -3
- data/Rakefile +17 -10
- data/lib/angle.rb +215 -203
- data/lib/coordinate.rb +24 -23
- data/lib/core_extensions.rb +67 -59
- data/lib/latitude.rb +30 -29
- data/lib/longitude.rb +22 -23
- data/lib/track_and_distance.rb +36 -32
- data/lib/vincenty.rb +153 -143
- data/test/ts_all.rb +8 -8
- data/test/ts_angle.rb +55 -54
- data/test/ts_coordinate.rb +10 -9
- data/test/ts_latitude.rb +20 -17
- data/test/ts_longitude.rb +14 -11
- data/test/ts_track_and_distance.rb +12 -9
- data/test/ts_vincenty.rb +80 -71
- metadata +33 -39
- data/.gemtest +0 -0
data/lib/core_extensions.rb
CHANGED
@@ -1,90 +1,98 @@
|
|
1
1
|
require 'scanf'
|
2
2
|
|
3
|
-
#Extends Numeric, hence Fixed & Float to_r & to_d
|
4
|
-
#Also adds in sign.
|
3
|
+
# Extends Numeric, hence Fixed & Float to_r & to_d
|
4
|
+
# Also adds in sign.
|
5
5
|
class Numeric
|
6
|
-
#Convert Radians to Degrees
|
7
|
-
#
|
8
|
-
#
|
9
|
-
def to_degrees(mod=false)
|
10
|
-
if mod
|
11
|
-
(self * 180
|
12
|
-
else
|
13
|
-
self * 180
|
6
|
+
# Convert Radians to Degrees
|
7
|
+
# @return [Numeric] degrees
|
8
|
+
# @param [true,false] mod Optional argument mod == true, then applies % 360
|
9
|
+
def to_degrees(mod = false)
|
10
|
+
if mod
|
11
|
+
(self * 180 / Math::PI) % 360
|
12
|
+
else
|
13
|
+
self * 180 / Math::PI
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
17
|
-
#Converts degrees to Radians
|
18
|
-
#
|
19
|
-
#
|
20
|
-
def to_radians(mod=false)
|
21
|
-
if mod
|
16
|
+
|
17
|
+
# Converts degrees to Radians
|
18
|
+
# @return [Numeric] radians
|
19
|
+
# @param [true,false] mod Optional argument mod == true, then applies % Math::PI
|
20
|
+
def to_radians(mod = false)
|
21
|
+
if mod
|
22
22
|
(self * Math::PI / 180) % Math::PI
|
23
|
-
else
|
23
|
+
else
|
24
24
|
self * Math::PI / 180
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
alias to_r to_radians
|
29
|
-
alias
|
30
|
-
|
31
|
-
|
29
|
+
alias to_rad to_radians
|
30
|
+
alias to_deg to_degrees
|
31
|
+
|
32
|
+
# @return [Fixnum] 1 if number is positive, -1 if negative.
|
32
33
|
def sign
|
33
34
|
self < 0 ? -1 : 1
|
34
35
|
end
|
35
|
-
|
36
36
|
end
|
37
37
|
|
38
|
-
#Alters round method to have an optional number of decimal places.
|
38
|
+
# Alters round method to have an optional number of decimal places.
|
39
39
|
class Float
|
40
|
+
# Replace default round, so we can reference it later.
|
41
|
+
# @return [Float]
|
40
42
|
alias round0 round
|
41
|
-
|
42
|
-
#
|
43
|
-
#
|
43
|
+
|
44
|
+
# Compatible Replacement for Float.round
|
45
|
+
# @return [Float] float rounded to n decimal places.
|
46
|
+
# @param [Numeric] n Optional argument n is the number of decimal places to round to.
|
44
47
|
def round(n = 0)
|
45
|
-
|
46
|
-
|
48
|
+
if n == 0
|
49
|
+
self.round0 # This is to preserve the default behaviour, which is to return a Fixnum, not a float.
|
50
|
+
else
|
51
|
+
m = 10.0**n
|
52
|
+
(self * m).round0 / m
|
53
|
+
end
|
47
54
|
end
|
48
55
|
end
|
49
56
|
|
50
|
-
#Extends String to to_dec_degrees, add to_r and to_d
|
57
|
+
# Extends String to to_dec_degrees, add to_r and to_d
|
51
58
|
class String
|
52
|
-
#string expected to be degrees, returns decimal degrees.
|
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, ...
|
54
|
-
#
|
55
|
-
def to_dec_degrees
|
56
|
-
#reorder 37 001'.512S, S37 001'.512 into 37 001.512'S, S37 001.512' respectively
|
57
|
-
s = self.gsub(/([0-9])(
|
58
|
-
#add in minutes and seconds to get 3 values 'deg 0 0'from S37 0, 37 0S
|
59
|
-
s.gsub!(/^([^0-9
|
60
|
-
#add in seconds get 3 values 'deg min 0' from S37 01.512', 37 01.512'S
|
61
|
-
s.gsub!(/^([^0-9
|
62
|
-
|
63
|
-
#look for anything of the form S37 001'7.5'', S37 01.512', S37.01875 0, ...
|
64
|
-
s.scanf(
|
59
|
+
# string expected to be degrees, returns decimal degrees.
|
60
|
+
# 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, ...
|
61
|
+
# @return [Float] angle in decimal degrees
|
62
|
+
def to_dec_degrees
|
63
|
+
# reorder 37 001'.512S, S37 001'.512 into 37 001.512'S, S37 001.512' respectively
|
64
|
+
s = self.gsub(/([0-9])(')\.([0-9]+)/, '\1.\3\2')
|
65
|
+
# add in minutes and seconds to get 3 values 'deg 0 0'from S37 0, 37 0S
|
66
|
+
s.gsub!(/^([^0-9.\-]*)([0-9\-.]+)([^0-9\-.]*)$/, '\1\2\3 0 0\5')
|
67
|
+
# add in seconds get 3 values 'deg min 0' from S37 01.512', 37 01.512'S
|
68
|
+
s.gsub!(/^([^0-9.\-]*)([0-9\-.]+)([^0-9\-.]+)([0-9\-.]+)([^0-9\-.]*)$/, '\1\2\3\4 0\5')
|
69
|
+
|
70
|
+
# look for anything of the form S37 001'7.5'', S37 01.512', S37.01875 0, ...
|
71
|
+
s.scanf('%[NSEW]%f%[^0-9-]%f%[^0-9-]%f') do |direction, deg, _sep1, min, _sep2, sec|
|
65
72
|
return Angle.decimal_deg( deg, min, sec, direction)
|
66
73
|
end
|
67
|
-
|
68
|
-
#look for anything of the form 37 001'7.5''S , -37 001'7.5'', -37 0 1.512'. -37.01875 0, ...
|
69
|
-
s.scanf(
|
74
|
+
|
75
|
+
# look for anything of the form 37 001'7.5''S , -37 001'7.5'', -37 0 1.512'. -37.01875 0, ...
|
76
|
+
s.scanf('%f%[^0-9-]%f%[^0-9-]%f%[^NSEW]%[NSEW]') do |deg, _sep1, min, _sep2, sec, _sep3, direction|
|
70
77
|
return Angle.decimal_deg( deg, min, sec, direction)
|
71
78
|
end
|
72
79
|
end
|
73
|
-
|
74
|
-
#Convert Radians to Degrees
|
75
|
-
#
|
76
|
-
#
|
77
|
-
def to_degrees(mod=false)
|
78
|
-
self.to_f.to_degrees(mod)
|
80
|
+
|
81
|
+
# Convert String number in Radians to Degrees
|
82
|
+
# @return [Float] degrees
|
83
|
+
# @param [true,false] mod Optional argument mod == true, then applies % 360
|
84
|
+
def to_degrees(mod = false)
|
85
|
+
return self.to_f.to_degrees(mod)
|
79
86
|
end
|
80
|
-
|
81
|
-
#Converts string degrees to to_decimal_degrees, then to Radians
|
82
|
-
#
|
83
|
-
#
|
84
|
-
def to_radians(mod=false)
|
85
|
-
self.to_dec_degrees.to_radians(mod)
|
87
|
+
|
88
|
+
# Converts string degrees to to_decimal_degrees, then to Radians
|
89
|
+
# @return [Float] radians
|
90
|
+
# @param [true,false] mod Optional argument mod == true, then applies % Math::PI
|
91
|
+
def to_radians(mod = false)
|
92
|
+
return self.to_dec_degrees.to_radians(mod)
|
86
93
|
end
|
87
|
-
|
94
|
+
|
95
|
+
alias to_rad to_radians
|
88
96
|
alias to_r to_radians
|
89
|
-
alias
|
97
|
+
alias to_deg to_degrees
|
90
98
|
end
|
data/lib/latitude.rb
CHANGED
@@ -1,41 +1,42 @@
|
|
1
|
+
require_relative 'angle.rb'
|
1
2
|
|
2
|
-
|
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
|
-
|
3
|
+
# Subclass of Angle to add in special treatment of to_d, to_r , to_s
|
4
|
+
# Latitude degrees are between -PI and PI, South to North (+/- 90 degrees)
|
7
5
|
class Latitude < Angle
|
8
|
-
|
9
|
-
#Returns angle as degrees in range -90 and 90
|
6
|
+
# @return [Float] angle as degrees in range -90 and 90
|
10
7
|
def to_degrees
|
11
8
|
degrees = super
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
if degrees > 270
|
10
|
+
-(360 - degrees)
|
11
|
+
elsif degrees > 180 || degrees > 90 || degrees < -90
|
12
|
+
180 - degrees
|
13
|
+
else
|
14
|
+
degrees
|
18
15
|
end
|
19
16
|
end
|
20
|
-
|
21
|
-
#
|
17
|
+
|
18
|
+
# @return [Float] angle as degrees in range -PI and PI
|
22
19
|
def to_radians
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
if @angle > 3 * Math::PI / 2
|
21
|
+
@angle - Math::PI * 2
|
22
|
+
elsif @angle > Math::PI || @angle > Math::PI / 2
|
23
|
+
Math::PI - @angle
|
24
|
+
elsif @angle < -Math::PI / 2
|
25
|
+
-Math::PI - @angle
|
26
|
+
else
|
27
|
+
@angle
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
|
-
#
|
33
|
-
#A South angle is negative, North is Positive.
|
34
|
-
|
35
|
-
|
31
|
+
# @return [String] angle as string in degrees minutes seconds direction.
|
32
|
+
# A South angle is negative, North is Positive.
|
33
|
+
# @param [String] fmt Optional format string passed to Angle#to_s
|
34
|
+
def to_s(fmt = "%2d %2m'%2.4s\"%N")
|
35
|
+
super(fmt)
|
36
36
|
end
|
37
|
-
|
38
|
-
alias to_r to_radians
|
39
|
-
alias to_d to_degrees
|
40
37
|
|
41
|
-
|
38
|
+
alias to_r to_radians
|
39
|
+
alias to_rad to_radians
|
40
|
+
# alias to_d to_degrees
|
41
|
+
alias to_deg to_degrees
|
42
|
+
end
|
data/lib/longitude.rb
CHANGED
@@ -1,35 +1,34 @@
|
|
1
|
+
require_relative 'angle.rb'
|
1
2
|
|
2
|
-
|
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
|
-
|
3
|
+
# Subclass of Angle to add in special treatment of to_d, to_r and to_s
|
4
|
+
# Longitude degrees are between -2PI and 2PI, West to East (+/- 180 degrees)
|
7
5
|
class Longitude < Angle
|
8
|
-
|
9
|
-
#Returns angle as degrees in range -180 and 180
|
6
|
+
# @return [Float] angle as degrees in range -180 and 180
|
10
7
|
def to_degrees
|
11
8
|
degrees = super
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
if degrees > 180 then degrees - 360
|
10
|
+
else
|
11
|
+
degrees
|
15
12
|
end
|
16
13
|
end
|
17
|
-
|
18
|
-
#
|
14
|
+
|
15
|
+
# @return [Float] angle as degrees in range -2PI and 2PI
|
19
16
|
def to_radians
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
if @angle > Math::PI then @angle - 2 * Math::PI
|
18
|
+
else
|
19
|
+
@angle
|
23
20
|
end
|
24
21
|
end
|
25
|
-
|
26
|
-
#
|
27
|
-
#A West angle is negative, East is Positive.
|
28
|
-
|
22
|
+
|
23
|
+
# @return [String] angle as string in degrees minutes seconds direction.
|
24
|
+
# A West angle is negative, East is Positive.
|
25
|
+
# @param [String] fmt Optional format string passed to Angle#to_s
|
26
|
+
def to_s(fmt = "%3d %2m'%2.4s\"%E")
|
29
27
|
super(fmt)
|
30
28
|
end
|
31
|
-
|
29
|
+
|
32
30
|
alias to_r to_radians
|
33
|
-
alias
|
34
|
-
|
35
|
-
|
31
|
+
alias to_rad to_radians
|
32
|
+
# alias to_d to_degrees
|
33
|
+
alias to_deg to_degrees
|
34
|
+
end
|
data/lib/track_and_distance.rb
CHANGED
@@ -1,36 +1,40 @@
|
|
1
|
+
require_relative 'angle.rb'
|
1
2
|
|
2
|
-
|
3
|
-
|
4
|
-
#Holds a bearing and distance
|
3
|
+
# Holds a bearing and distance
|
5
4
|
class TrackAndDistance
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(bearing, distance, radians=false)
|
11
|
-
@bearing = Angle.new(bearing, radians)
|
12
|
-
@distance = distance
|
13
|
-
end
|
14
|
-
|
15
|
-
#format string fmt is currently just for the bearing angle.
|
16
|
-
#Need to change this to include the distance is single format string.
|
17
|
-
#Returns: Bearing angle and distance in a string.
|
18
|
-
def to_s(fmt = nil)
|
19
|
-
if(fmt)
|
20
|
-
#needs work to include distance as well as angle fmt.
|
21
|
-
"#{@bearing.strf(fmt)} #{distance.round(4)}m"
|
22
|
-
else
|
23
|
-
"#{@bearing.strf} #{distance.round(4)}m"
|
24
|
-
end
|
25
|
-
end
|
5
|
+
# @return [Angle]
|
6
|
+
attr_accessor :bearing
|
7
|
+
# @return [Float]
|
8
|
+
attr_accessor :distance
|
26
9
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
10
|
+
# @param [String, Numeric, #to_radian, #to_f] Bearing can be a String or Numeric or any object with to_radians and to_f
|
11
|
+
# @param [Numeric] distance
|
12
|
+
# @param [true,false, :radians] radians Bearing is in degrees unless radians == true (or set to :radians).
|
13
|
+
def initialize(bearing, distance, radians = false)
|
14
|
+
@bearing = Angle.new(bearing, radians)
|
15
|
+
@distance = distance
|
16
|
+
end
|
17
|
+
|
18
|
+
# format string fmt is currently just for the bearing angle.
|
19
|
+
# Need to change this to include the distance is single format string.
|
20
|
+
# @return [String] Bearing angle and distance in meters.
|
21
|
+
# @param [String] fmt Optional format string passed to Coordinate#strf
|
22
|
+
def to_s(fmt = nil)
|
23
|
+
if fmt
|
24
|
+
# needs work to include distance as well as angle fmt.
|
25
|
+
return "#{@bearing.strf(fmt)} #{distance.round(4)}m"
|
26
|
+
else
|
27
|
+
return "#{@bearing.strf} #{distance.round(4)}m"
|
35
28
|
end
|
36
|
-
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Array] with members bearing and distance.
|
32
|
+
def to_ary
|
33
|
+
return [ @bearing, @distance ]
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Hash] with keys :bearing and :distance
|
37
|
+
def to_hash
|
38
|
+
return { bearing: @bearing, distance: @distance }
|
39
|
+
end
|
40
|
+
end
|