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.
@@ -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
@@ -1,43 +1,78 @@
1
1
  require 'sugar-high/numeric'
2
2
 
3
3
  module GeoUnitExt
4
- ::GeoUnits.units.each do |unit|
5
- class_eval %{
6
- def #{unit}_to unit
7
- unit = GeoUnits.key(unit)
8
- (self.to_f / GeoUnits.meters_map[:#{unit}]) * GeoUnits.meters_map[unit]
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 rpd
16
- self * GeoUnits.radians_per_degree
17
- end
18
- alias_method :to_radians, :rpd
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 Fixnum
21
+ class Numeric
22
22
  include GeoUnitExt
23
- include ::GeoUnits::NumericExt
23
+ include ::GeoUnits::Numeric
24
+ include ::GeoUnits::Numeric::Dms
25
+ include ::GeoUnits::Numeric::Normalizer
24
26
  end
25
27
 
26
- class Float
27
- include GeoUnitExt
28
- include ::GeoUnits::NumericExt
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
- class String
32
- def parse_dms
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 = self.respond_to?(:to_lat) ? self.to_lat : self[0]
40
- lng = self.respond_to?(:to_lng) ? self.to_lng : self[1]
41
- [lat.to_lat_dms, lng.to_lng_dms].join(', ')
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
@@ -1,61 +1,10 @@
1
1
  module GeoUnits
2
2
  module Maps
3
- def earth_radius_map
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 meters_map
52
- {
53
- :feet => 3.2808399,
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