geo_units 0.2.6 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -1
- data/Gemfile +1 -0
- data/README.textile +15 -0
- data/VERSION +1 -1
- data/geo_units.gemspec +21 -5
- data/lib/geo_units.rb +48 -19
- data/lib/geo_units/constants.rb +5 -17
- data/lib/geo_units/converter.rb +11 -55
- data/lib/geo_units/converter/dms.rb +112 -0
- data/lib/geo_units/converter/normalizer.rb +52 -0
- data/lib/geo_units/converter/units.rb +41 -0
- data/lib/geo_units/core_ext.rb +60 -25
- data/lib/geo_units/maps.rb +6 -58
- data/lib/geo_units/maps/earth.rb +49 -0
- data/lib/geo_units/maps/meters.rb +25 -0
- data/lib/geo_units/numeric.rb +50 -0
- data/lib/geo_units/numeric/dms.rb +18 -0
- data/lib/geo_units/numeric/normalizer.rb +62 -0
- data/spec/geo_units/{dms_converter_spec.rb → converter/dms_spec.rb} +5 -5
- data/spec/geo_units/converter/normalizer_spec.rb +0 -0
- data/spec/geo_units/converter/units_spec.rb +0 -0
- data/spec/geo_units/converter_spec.rb +7 -7
- data/spec/geo_units/core_ext_spec.rb +62 -7
- data/spec/geo_units/maps/earth_spec.rb +25 -0
- data/spec/geo_units/maps/meters_spec.rb +24 -0
- data/spec/geo_units/maps_spec.rb +25 -0
- data/spec/geo_units/numeric/dms_spec.rb +0 -0
- data/spec/geo_units/numeric/normalizer_spec.rb +0 -0
- data/spec/geo_units/numeric_spec.rb +21 -0
- data/spec/geo_units_spec.rb +7 -1
- metadata +35 -6
- data/lib/geo_units/dms_converter.rb +0 -107
- data/lib/geo_units/numeric_ext.rb +0 -117
- data/spec/geo_units/numeric_ext_spec.rb +0 -12
@@ -0,0 +1,52 @@
|
|
1
|
+
module GeoUnits
|
2
|
+
module Converter
|
3
|
+
module Normalizer
|
4
|
+
# all degrees between -180 and 180
|
5
|
+
def normalize_lng deg
|
6
|
+
case deg
|
7
|
+
when -360..-180
|
8
|
+
deg % 180
|
9
|
+
when -180..0
|
10
|
+
-180 + (deg % 180)
|
11
|
+
when 0..180
|
12
|
+
deg
|
13
|
+
when 180..360
|
14
|
+
deg % 180
|
15
|
+
else
|
16
|
+
raise ArgumentError, "Degrees #{deg} out of range, must be between -360 to 360"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# all degrees between -90 and 90
|
21
|
+
def normalize_lat deg
|
22
|
+
case deg
|
23
|
+
when -360..-270
|
24
|
+
deg % 90
|
25
|
+
when -270..-180
|
26
|
+
90 - (deg % 90)
|
27
|
+
when -180..-90
|
28
|
+
- (deg % 90)
|
29
|
+
when -90..0
|
30
|
+
-90 + (deg % 90)
|
31
|
+
when 0..90
|
32
|
+
deg
|
33
|
+
when 90..180
|
34
|
+
deg % 90
|
35
|
+
when 180..270
|
36
|
+
- (deg % 90)
|
37
|
+
when 270..360
|
38
|
+
- 90 + (deg % 90)
|
39
|
+
else
|
40
|
+
raise ArgumentError, "Degrees #{deg} out of range, must be between -360 to 360"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def normalize_deg degrees, shift = 0
|
45
|
+
(degrees + shift) % 360
|
46
|
+
end
|
47
|
+
alias_method :normalize_degrees, :normalize_deg
|
48
|
+
|
49
|
+
extend self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module GeoUnits
|
2
|
+
module Converter
|
3
|
+
module Units
|
4
|
+
def degrees_to_radians(degrees)
|
5
|
+
degrees.to_f * GeoUnits::Constants.radians_per_degree
|
6
|
+
end
|
7
|
+
|
8
|
+
def units_sphere_multiplier(units)
|
9
|
+
units = GeoUnits.key units
|
10
|
+
GeoUnits::Mapsearth_radius_map[units]
|
11
|
+
end
|
12
|
+
|
13
|
+
def units_per_latitude_degree(units)
|
14
|
+
units = GeoUnits.key units
|
15
|
+
GeoUnits::Maps.radian_multiplier[units]
|
16
|
+
end
|
17
|
+
|
18
|
+
def pi_div_rad
|
19
|
+
GeoUnits::Constants.pi_div_rad
|
20
|
+
end
|
21
|
+
|
22
|
+
def units_per_longitude_degree(lat, units)
|
23
|
+
miles_per_longitude_degree = (lat * Math.cos(lat * pi_div_rad)).abs
|
24
|
+
units = GeoUnits.key units
|
25
|
+
miles_per_longitude_degree.miles_to(units)
|
26
|
+
end
|
27
|
+
|
28
|
+
def earth_radius units
|
29
|
+
units = GeoUnits.key units
|
30
|
+
GeoUnits::Maps.earth_radius_map[units]
|
31
|
+
end
|
32
|
+
|
33
|
+
def radians_ratio units
|
34
|
+
units = GeoUnits.key units
|
35
|
+
radians_per_degree * earth_radius(units)
|
36
|
+
end
|
37
|
+
|
38
|
+
extend self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/geo_units/core_ext.rb
CHANGED
@@ -1,43 +1,78 @@
|
|
1
1
|
require 'sugar-high/numeric'
|
2
2
|
|
3
3
|
module GeoUnitExt
|
4
|
-
::GeoUnits.units.each do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
}
|
4
|
+
::GeoUnits.units.each do |unit_type|
|
5
|
+
define_method "#{unit_type}_to" do |unit|
|
6
|
+
unit = GeoUnits.normalized(unit)
|
7
|
+
self.to_f * GeoUnits::Maps::Meters.from_unit[unit_type] * GeoUnits::Maps::Meters.to_unit[unit]
|
8
|
+
end
|
11
9
|
end
|
12
10
|
|
13
11
|
include NumberDslExt # from sugar-high
|
14
12
|
|
15
|
-
def
|
16
|
-
|
17
|
-
end
|
18
|
-
alias_method :to_radians, :
|
13
|
+
def to_rad
|
14
|
+
GeoUnits::Converter.to_rad self
|
15
|
+
end
|
16
|
+
alias_method :to_radians, :to_rad
|
17
|
+
alias_method :degrees_to_rad, :to_radians
|
18
|
+
alias_method :deg_to_rad, :to_radians
|
19
19
|
end
|
20
20
|
|
21
|
-
class
|
21
|
+
class Numeric
|
22
22
|
include GeoUnitExt
|
23
|
-
include ::GeoUnits::
|
23
|
+
include ::GeoUnits::Numeric
|
24
|
+
include ::GeoUnits::Numeric::Dms
|
25
|
+
include ::GeoUnits::Numeric::Normalizer
|
24
26
|
end
|
25
27
|
|
26
|
-
class
|
27
|
-
|
28
|
-
|
29
|
-
end
|
28
|
+
class String
|
29
|
+
def parse_dms options = {}
|
30
|
+
GeoUnits::Converter::Dms.parse_dms self, options
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_lng
|
34
|
+
self.match(/[E|W]/) ? self.to_i : nil
|
35
|
+
end
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
GeoUnits::DmsConverter.parse_dms self
|
37
|
+
def to_lat
|
38
|
+
self.match(/[N|S]/) ? self.to_i : nil
|
34
39
|
end
|
35
40
|
end
|
36
41
|
|
37
42
|
class Array
|
38
|
-
def to_dms
|
39
|
-
lat =
|
40
|
-
|
41
|
-
|
43
|
+
def to_dms direction = nil
|
44
|
+
lng, lat = extract_coords(direction)
|
45
|
+
res = direction == :lat_lng ? [lat.to_lat_dms, lng.to_lng_dms] : [lng.to_lng_dms, lat.to_lat_dms]
|
46
|
+
res.join(', ')
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_dms direction = nil
|
50
|
+
lng, lat = extract_coords(direction)
|
51
|
+
direction == :lat_lng ? [lat.parse_dms, lng.parse_dms] : [lng.parse_dms, lat.parse_dms]
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def extract_coords direction = nil
|
57
|
+
direction ||= GeoUnits.default_coords_order
|
58
|
+
|
59
|
+
unless [:lng_lat, :lat_lng].include? direction
|
60
|
+
raise ArgumentError, "Direction must be either :lng_lat or :lat_lng, was: #{direction}. You can also set the default direction via GeoUnits#default_direction="
|
61
|
+
end
|
62
|
+
|
63
|
+
lat_index = direction == :reverse ? 0 : 1
|
64
|
+
lng_index = direction == :reverse ? 1 : 0
|
65
|
+
|
66
|
+
lat = self.to_lat if self.respond_to?(:to_lat)
|
67
|
+
lat ||= self[lat_index] if self[lat_index].respond_to?(:to_lat) && self[lat_index].to_lat
|
68
|
+
lat ||= self[lng_index] if self[lng_index].respond_to?(:to_lat) && self[lng_index].to_lat
|
69
|
+
lat ||= self[lat_index]
|
70
|
+
|
71
|
+
lng = self.to_lng if self.respond_to?(:to_lng)
|
72
|
+
lng ||= self[lng_index] if self[lng_index].respond_to?(:to_lng) && self[lng_index].to_lng
|
73
|
+
lng ||= self[lat_index] if self[lat_index].respond_to?(:to_lng) && self[lat_index].to_lng
|
74
|
+
lng ||= self[lng_index]
|
75
|
+
|
76
|
+
[lng, lat]
|
42
77
|
end
|
43
|
-
end
|
78
|
+
end
|
data/lib/geo_units/maps.rb
CHANGED
@@ -1,61 +1,10 @@
|
|
1
1
|
module GeoUnits
|
2
2
|
module Maps
|
3
|
-
|
4
|
-
{
|
5
|
-
:miles => 3963.1676,
|
6
|
-
:kilometers => 6378.135,
|
7
|
-
:meters => 6378135,
|
8
|
-
:feet => 20925639.8
|
9
|
-
}
|
10
|
-
end
|
11
|
-
|
12
|
-
def earth_major_axis_radius_map
|
13
|
-
{
|
14
|
-
:miles => 3963.19059,
|
15
|
-
:kilometers => 6378.137,
|
16
|
-
:meters => 6378137,
|
17
|
-
:feet => 20925646.36
|
18
|
-
}
|
19
|
-
end
|
20
|
-
|
21
|
-
def earth_minor_axis_radius_map
|
22
|
-
{
|
23
|
-
:kilometers => 6356.7523142,
|
24
|
-
:miles => 3949.90276,
|
25
|
-
:meters => 6356752.3142,
|
26
|
-
:feet => 20855486.627
|
27
|
-
}
|
28
|
-
end
|
29
|
-
|
30
|
-
# from mongoid-geo, as suggested by niedhui :)
|
31
|
-
def radian_multiplier
|
32
|
-
{
|
33
|
-
:feet => 364491.8,
|
34
|
-
:meters => 111170,
|
35
|
-
:kms => 111.17,
|
36
|
-
:miles => 69.407,
|
37
|
-
:radians => 1
|
38
|
-
}
|
39
|
-
end
|
40
|
-
|
41
|
-
def meters_multiplier
|
42
|
-
{
|
43
|
-
:feet => 0.305,
|
44
|
-
:meters => 1,
|
45
|
-
:kms => 6371,
|
46
|
-
:miles => 3959,
|
47
|
-
:radians => 111170
|
48
|
-
}
|
49
|
-
end
|
3
|
+
autoload_modules :Earth, :Meters
|
50
4
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
:meters => 1,
|
55
|
-
:kms => 0.001,
|
56
|
-
:miles => 0.00062137,
|
57
|
-
:radians => 0.00000899
|
58
|
-
}
|
5
|
+
def self.included(base)
|
6
|
+
base.send :include, Earth
|
7
|
+
base.send :include, Meters
|
59
8
|
end
|
60
9
|
|
61
10
|
def precision
|
@@ -66,8 +15,7 @@ module GeoUnits
|
|
66
15
|
:miles => 4,
|
67
16
|
:radians => 4
|
68
17
|
}
|
69
|
-
end
|
70
|
-
|
18
|
+
end
|
71
19
|
extend self
|
72
20
|
end
|
73
|
-
end
|
21
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module GeoUnits
|
2
|
+
module Maps
|
3
|
+
module Earth
|
4
|
+
# from mongoid-geo, as suggested by niedhui :)
|
5
|
+
def distance_per_latitude_degree
|
6
|
+
{
|
7
|
+
:feet => 364491.8,
|
8
|
+
:meters => 111170,
|
9
|
+
:kilometers => 111.17,
|
10
|
+
:miles => 69.407,
|
11
|
+
:degrees => 1
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def radius
|
16
|
+
{
|
17
|
+
:miles => 3963.1676,
|
18
|
+
:kilometers => 6378.135,
|
19
|
+
:meters => 6378135,
|
20
|
+
:feet => 20925639.8
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def major_axis_radius
|
25
|
+
{
|
26
|
+
:miles => 3963.19059,
|
27
|
+
:kilometers => 6378.137,
|
28
|
+
:meters => 6378137,
|
29
|
+
:feet => 20925646.36
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def minor_axis_radius
|
34
|
+
{
|
35
|
+
:kilometers => 6356.7523142,
|
36
|
+
:miles => 3949.90276,
|
37
|
+
:meters => 6356752.3142,
|
38
|
+
:feet => 20855486.627
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def latitude_degrees unit = :miles
|
43
|
+
radius[unit] / distance_per_latitude_degree[unit]
|
44
|
+
end
|
45
|
+
|
46
|
+
extend self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GeoUnits
|
2
|
+
module Maps
|
3
|
+
module Meters
|
4
|
+
def from_unit
|
5
|
+
{
|
6
|
+
:feet => 0.3048,
|
7
|
+
:meters => 1,
|
8
|
+
:kilometers => 1000,
|
9
|
+
:miles => 1609.344
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_unit
|
14
|
+
{
|
15
|
+
:feet => 3.2808399,
|
16
|
+
:meters => 1,
|
17
|
+
:kilometers => 0.001,
|
18
|
+
:miles => 0.00062137
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
extend self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module GeoUnits
|
2
|
+
module Numeric
|
3
|
+
autoload_modules :Normalizer, :Dms
|
4
|
+
|
5
|
+
def to_lat
|
6
|
+
normalize_lat
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_lng
|
10
|
+
normalize_lng
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_between? lower, upper
|
14
|
+
(lower..upper).cover? self
|
15
|
+
end
|
16
|
+
|
17
|
+
# Converts numeric degrees to radians
|
18
|
+
def to_rad
|
19
|
+
self * Math::PI / 180
|
20
|
+
end
|
21
|
+
alias_method :to_radians, :to_rad
|
22
|
+
alias_method :as_rad, :to_rad
|
23
|
+
alias_method :as_radians, :to_rad
|
24
|
+
alias_method :in_rad, :to_rad
|
25
|
+
alias_method :in_radians, :to_rad
|
26
|
+
|
27
|
+
|
28
|
+
# Converts radians to numeric (signed) degrees
|
29
|
+
# latitude (north to south) from equator +90 up then -90 down (equator again) = 180 then 180 for south = 360 total
|
30
|
+
# longitude (west to east) east +180, west -180 = 360 total
|
31
|
+
def to_deg
|
32
|
+
self * 180 / Math::PI
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :to_degrees, :to_deg
|
36
|
+
alias_method :as_deg, :to_deg
|
37
|
+
alias_method :as_degrees, :to_deg
|
38
|
+
alias_method :in_deg, :to_deg
|
39
|
+
alias_method :in_degrees, :to_deg
|
40
|
+
|
41
|
+
# Formats the significant digits of a number, using only fixed-point notation (no exponential)
|
42
|
+
#
|
43
|
+
# @param {Number} precision: Number of significant digits to appear in the returned string
|
44
|
+
# @returns {String} A string representation of number which contains precision significant digits
|
45
|
+
def to_precision precision
|
46
|
+
self.round(precision).to_s
|
47
|
+
end
|
48
|
+
alias_method :to_fixed, :to_precision
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module GeoUnits
|
2
|
+
module Numeric
|
3
|
+
module Dms
|
4
|
+
def to_dms format = :dms, dp = nil
|
5
|
+
GeoUnits::DmsConverter.to_dms self, format, dp
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_lat_dms format = :dms, dp = nil
|
9
|
+
GeoUnits::Converter.to_lat self, format, dp
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_lon_dms format = :dms, dp = nil
|
13
|
+
GeoUnits::Converter.to_lon self, format, dp
|
14
|
+
end
|
15
|
+
alias_method :to_lng_dms, :to_lon_dms
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module GeoUnits
|
2
|
+
module Numeric
|
3
|
+
module Normalizer
|
4
|
+
# all degrees between -180 and 180
|
5
|
+
def normalize_lng
|
6
|
+
case self
|
7
|
+
when -360, 0, 360
|
8
|
+
0
|
9
|
+
when -360..-180
|
10
|
+
self % 180
|
11
|
+
when -180..0
|
12
|
+
-180 + (self % 180)
|
13
|
+
when 0..180
|
14
|
+
self
|
15
|
+
when 180..360
|
16
|
+
self % 180
|
17
|
+
else
|
18
|
+
return (self % 360).normalize_lng if self > 360
|
19
|
+
return (360 - (self % 360)).normalize_lng if self < -360
|
20
|
+
raise ArgumentError, "Degrees #{self} out of range"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# all degrees between -90 and 90
|
25
|
+
def normalize_lat
|
26
|
+
case self
|
27
|
+
when -360, 0, 360
|
28
|
+
0
|
29
|
+
when -180, 180
|
30
|
+
0
|
31
|
+
when -360..-270
|
32
|
+
self % 90
|
33
|
+
when -270..-180
|
34
|
+
90 - (self % 90)
|
35
|
+
when -180..-90
|
36
|
+
- (self % 90)
|
37
|
+
when -90..0
|
38
|
+
-90 + (self % 90)
|
39
|
+
when 0..90
|
40
|
+
self
|
41
|
+
when 90..180
|
42
|
+
self % 90
|
43
|
+
when 180..270
|
44
|
+
- (self % 90)
|
45
|
+
when 270..360
|
46
|
+
- 90 + (self % 90)
|
47
|
+
else
|
48
|
+
return (self % 360).normalize_lat if self > 360
|
49
|
+
return (360 - (self % 360)).normalize_lat if self < -360
|
50
|
+
raise ArgumentError, "Degrees #{self} out of range"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def normalize_deg shift = 0
|
55
|
+
(self + shift) % 360
|
56
|
+
end
|
57
|
+
alias_method :normalize_degrees, :normalize_deg
|
58
|
+
|
59
|
+
extend self
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|