geo_calc 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -0
- data/README.textile +12 -0
- data/VERSION +1 -1
- data/geo_calc.gemspec +29 -6
- data/lib/geo_calc/calc/destination.rb +1 -1
- data/lib/geo_calc/calc/distance.rb +1 -1
- data/lib/geo_calc/calc/rhumb.rb +2 -2
- data/lib/geo_calc/calc.rb +20 -21
- data/lib/geo_calc/dms/converter.rb +106 -0
- data/lib/geo_calc/dms.rb +5 -0
- data/lib/geo_calc/extensions/array.rb +26 -0
- data/lib/geo_calc/extensions/hash.rb +23 -0
- data/lib/geo_calc/extensions/math.rb +6 -0
- data/lib/geo_calc/extensions/numeric.rb +24 -0
- data/lib/geo_calc/extensions/string.rb +44 -0
- data/lib/geo_calc/extensions/symbol.rb +9 -0
- data/lib/geo_calc/extensions.rb +4 -0
- data/lib/geo_calc/geo_point/class_methods.rb +15 -0
- data/lib/geo_calc/geo_point/core_extension.rb +11 -0
- data/lib/geo_calc/geo_point/shared.rb +29 -0
- data/lib/geo_calc/geo_point.rb +42 -40
- data/lib/geo_calc/pretty_print.rb +2 -2
- data/lib/geo_calc.rb +5 -0
- data/lib/geo_units/converter.rb +123 -0
- data/lib/geo_units/numeric_ext.rb +117 -0
- data/lib/geo_units.rb +21 -0
- data/spec/geo_calc/core_ext/numeric_geo_ext_spec.rb +48 -50
- data/spec/geo_calc/core_ext_spec.rb +49 -51
- data/spec/geo_calc/dms/converter_spec.rb +60 -0
- data/spec/geo_calc/geo_point/class_methods_spec.rb +31 -0
- data/spec/geo_calc/geo_point/initializer_spec.rb +148 -0
- data/spec/geo_calc/geo_point/lat_lon.rb +115 -0
- data/spec/geo_calc/geo_point_spec.rb +4 -274
- data/spec/geo_units/converter_spec.rb +57 -0
- metadata +56 -17
- data/lib/geo_calc/core_ext.rb +0 -318
- data/lib/geo_calc/geo.rb +0 -171
- data/spec/geo_calc/geo_spec.rb +0 -99
data/Gemfile
CHANGED
data/README.textile
CHANGED
@@ -2,6 +2,18 @@ h1. Geo calculations
|
|
2
2
|
|
3
3
|
Geo Calculation library. Useful functions to add to your geo arsenal, fx when designing your own Geo library.
|
4
4
|
|
5
|
+
h2. Status update (June 10, 2011)
|
6
|
+
|
7
|
+
- Major refactoring splitting into more logical file/modular structure
|
8
|
+
- Use autoload
|
9
|
+
- Extract GeoUnits
|
10
|
+
- Extract Dms with converter
|
11
|
+
- GeoPoint can now have set :coords_mode which affects how Ruby Core objects such as String and Array are parsed into :lng and :lat.
|
12
|
+
|
13
|
+
TODO:
|
14
|
+
- The GeoPoint class should be extracted into separate gem, then this geo_calc gem should only have the more generic geo functionality as modules to be included
|
15
|
+
where needed in other gems!
|
16
|
+
|
5
17
|
h2. Install
|
6
18
|
|
7
19
|
@require 'geo_calc'@
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.1
|
data/geo_calc.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{geo_calc}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.7.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = [%q{Kristian Mandrup}]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-06-11}
|
13
13
|
s.description = %q{Geo calculations in ruby and javascript}
|
14
14
|
s.email = %q{kmandrup@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -34,37 +34,58 @@ Gem::Specification.new do |s|
|
|
34
34
|
"lib/geo_calc/calc/intersection.rb",
|
35
35
|
"lib/geo_calc/calc/midpoint.rb",
|
36
36
|
"lib/geo_calc/calc/rhumb.rb",
|
37
|
-
"lib/geo_calc/
|
38
|
-
"lib/geo_calc/
|
37
|
+
"lib/geo_calc/dms.rb",
|
38
|
+
"lib/geo_calc/dms/converter.rb",
|
39
|
+
"lib/geo_calc/extensions.rb",
|
40
|
+
"lib/geo_calc/extensions/array.rb",
|
41
|
+
"lib/geo_calc/extensions/hash.rb",
|
42
|
+
"lib/geo_calc/extensions/math.rb",
|
43
|
+
"lib/geo_calc/extensions/numeric.rb",
|
44
|
+
"lib/geo_calc/extensions/string.rb",
|
45
|
+
"lib/geo_calc/extensions/symbol.rb",
|
39
46
|
"lib/geo_calc/geo_point.rb",
|
47
|
+
"lib/geo_calc/geo_point/class_methods.rb",
|
48
|
+
"lib/geo_calc/geo_point/core_extension.rb",
|
49
|
+
"lib/geo_calc/geo_point/shared.rb",
|
40
50
|
"lib/geo_calc/pretty_print.rb",
|
51
|
+
"lib/geo_units.rb",
|
52
|
+
"lib/geo_units/converter.rb",
|
53
|
+
"lib/geo_units/numeric_ext.rb",
|
41
54
|
"spec/geo_calc/calculations_spec.rb",
|
42
55
|
"spec/geo_calc/core_ext/array_ext_spec.rb",
|
43
56
|
"spec/geo_calc/core_ext/hash_ext_spec.rb",
|
44
57
|
"spec/geo_calc/core_ext/numeric_geo_ext_spec.rb",
|
45
58
|
"spec/geo_calc/core_ext/string_ext_spec.rb",
|
46
59
|
"spec/geo_calc/core_ext_spec.rb",
|
60
|
+
"spec/geo_calc/dms/converter_spec.rb",
|
61
|
+
"spec/geo_calc/geo_point/class_methods_spec.rb",
|
62
|
+
"spec/geo_calc/geo_point/initializer_spec.rb",
|
63
|
+
"spec/geo_calc/geo_point/lat_lon.rb",
|
47
64
|
"spec/geo_calc/geo_point_spec.rb",
|
48
|
-
"spec/
|
65
|
+
"spec/geo_units/converter_spec.rb",
|
49
66
|
"spec/spec_helper.rb",
|
50
67
|
"vendor/assets/javascript/geo_calc.js"
|
51
68
|
]
|
52
69
|
s.homepage = %q{http://github.com/kristianmandrup/geo_calc}
|
53
70
|
s.licenses = [%q{MIT}]
|
54
71
|
s.require_paths = [%q{lib}]
|
55
|
-
s.rubygems_version = %q{1.8.
|
72
|
+
s.rubygems_version = %q{1.8.5}
|
56
73
|
s.summary = %q{Geo calculation library}
|
57
74
|
|
58
75
|
if s.respond_to? :specification_version then
|
59
76
|
s.specification_version = 3
|
60
77
|
|
61
78
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
79
|
+
s.add_runtime_dependency(%q<require_all>, ["~> 1.2.0"])
|
80
|
+
s.add_runtime_dependency(%q<sugar-high>, ["~> 0.4.5.2"])
|
62
81
|
s.add_development_dependency(%q<rspec>, [">= 2.5.0"])
|
63
82
|
s.add_development_dependency(%q<bundler>, [">= 1"])
|
64
83
|
s.add_development_dependency(%q<jeweler>, [">= 1.5.2"])
|
65
84
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
66
85
|
s.add_development_dependency(%q<rake>, [">= 0.9"])
|
67
86
|
else
|
87
|
+
s.add_dependency(%q<require_all>, ["~> 1.2.0"])
|
88
|
+
s.add_dependency(%q<sugar-high>, ["~> 0.4.5.2"])
|
68
89
|
s.add_dependency(%q<rspec>, [">= 2.5.0"])
|
69
90
|
s.add_dependency(%q<bundler>, [">= 1"])
|
70
91
|
s.add_dependency(%q<jeweler>, [">= 1.5.2"])
|
@@ -72,6 +93,8 @@ Gem::Specification.new do |s|
|
|
72
93
|
s.add_dependency(%q<rake>, [">= 0.9"])
|
73
94
|
end
|
74
95
|
else
|
96
|
+
s.add_dependency(%q<require_all>, ["~> 1.2.0"])
|
97
|
+
s.add_dependency(%q<sugar-high>, ["~> 0.4.5.2"])
|
75
98
|
s.add_dependency(%q<rspec>, [">= 2.5.0"])
|
76
99
|
s.add_dependency(%q<bundler>, [">= 1"])
|
77
100
|
s.add_dependency(%q<jeweler>, [">= 1.5.2"])
|
@@ -14,7 +14,7 @@ module GeoCalc::Calc
|
|
14
14
|
# Returns GeoPoint: Destination point
|
15
15
|
|
16
16
|
def self.destination_point base_point, brng, dist
|
17
|
-
dist = dist / base_point.
|
17
|
+
dist = dist / base_point.earth_radius_km # convert dist to angular distance in radians
|
18
18
|
brng = brng.to_rad
|
19
19
|
lat1 = base_point.lat.to_rad
|
20
20
|
lon1 = base_point.lon.to_rad
|
@@ -35,7 +35,7 @@ module GeoCalc::Calc
|
|
35
35
|
|
36
36
|
a = Math.sin(dlat/2) * Math.sin(dlat/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlon/2) * Math.sin(dlon/2)
|
37
37
|
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
|
38
|
-
d = base_point.
|
38
|
+
d = base_point.earth_radius_km * c
|
39
39
|
d.round(precision)
|
40
40
|
end
|
41
41
|
end
|
data/lib/geo_calc/calc/rhumb.rb
CHANGED
@@ -29,7 +29,7 @@ module GeoCalc::Calc
|
|
29
29
|
# if dlon over 180° take shorter rhumb across 180° meridian:
|
30
30
|
dlon = 2*Math::PI - dlon if (dlon > Math::PI)
|
31
31
|
|
32
|
-
dist = Math.sqrt(dlat*dlat + q*q*dlon*dlon) * base_point.
|
32
|
+
dist = Math.sqrt(dlat*dlat + q*q*dlon*dlon) * base_point.earth_radius_km;
|
33
33
|
|
34
34
|
dist.round(4) # 4 sig figures reflects typical 0.3% accuracy of spherical model
|
35
35
|
end
|
@@ -69,7 +69,7 @@ module GeoCalc::Calc
|
|
69
69
|
# @returns {LatLon} Destination point
|
70
70
|
|
71
71
|
def self.rhumb_destination_point base_point, brng, dist
|
72
|
-
d = dist / base_point.
|
72
|
+
d = dist / base_point.earth_radius_km # d = angular distance covered on earth's surface
|
73
73
|
lat1 = base_point.lat.to_rad
|
74
74
|
lon1 = base_point.lon.to_rad
|
75
75
|
brng = brng.to_rad
|
data/lib/geo_calc/calc.rb
CHANGED
@@ -1,27 +1,26 @@
|
|
1
1
|
module GeoCalc
|
2
2
|
autoload :PrettyPrint, 'geo_calc/pretty_print'
|
3
|
-
|
4
|
-
module Calc
|
5
|
-
end
|
6
3
|
end
|
7
4
|
|
8
|
-
module GeoCalc
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
module GeoCalc
|
6
|
+
module Calc
|
7
|
+
autoload :Bearing, 'geo_calc/calc/bearing'
|
8
|
+
autoload :Destination, 'geo_calc/calc/destination'
|
9
|
+
autoload :Distance, 'geo_calc/calc/distance'
|
10
|
+
autoload :Intersection, 'geo_calc/calc/intersection'
|
11
|
+
autoload :Midpoint, 'geo_calc/calc/midpoint'
|
12
|
+
autoload :Rhumb, 'geo_calc/calc/rhumb'
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
14
|
+
module All
|
15
|
+
def self.included base
|
16
|
+
base.send :include, GeoCalc::Calc::Bearing
|
17
|
+
base.send :include, GeoCalc::Calc::Destination
|
18
|
+
base.send :include, GeoCalc::Calc::Distance
|
19
|
+
base.send :include, GeoCalc::Calc::Intersection
|
20
|
+
base.send :include, GeoCalc::Calc::Midpoint
|
21
|
+
base.send :include, GeoCalc::Calc::Rhumb
|
22
|
+
base.send :include, GeoCalc::PrettyPrint
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
27
26
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module GeoCalc
|
2
|
+
module Dms
|
3
|
+
module Converter
|
4
|
+
include GeoCalc::NumericCheckExt
|
5
|
+
|
6
|
+
def parse_dms dms_str
|
7
|
+
# check for signed decimal degrees without NSEW, if so return it directly
|
8
|
+
return dms_str if is_numeric?(dms_str)
|
9
|
+
|
10
|
+
# strip off any sign or compass dir'n & split out separate d/m/s
|
11
|
+
dms = dms_str.trim.gsub(/^-/,'').gsub(/[NSEW]$/i,'').split(/[^0-9.,]+/).map(&:trim).map(&:to_f)
|
12
|
+
return nil if dms.empty?
|
13
|
+
|
14
|
+
# and convert to decimal degrees...
|
15
|
+
deg = case dms.length
|
16
|
+
when 3 # interpret 3-part result as d/m/s
|
17
|
+
dms[0]/1 + dms[1]/60 + dms[2]/3600
|
18
|
+
when 2 # interpret 2-part result as d/m
|
19
|
+
dms[0]/1 + dms[1]/60
|
20
|
+
when 1 # just d (possibly decimal) or non-separated dddmmss
|
21
|
+
d = dms[0];
|
22
|
+
# check for fixed-width unseparated format eg 0033709W
|
23
|
+
d = "0#{d}" if (/[NS]/i.match(dms_str)) # - normalise N/S to 3-digit degrees
|
24
|
+
d = "#{d.slice(0,3)/1}#{deg.slice(3,5)/60}#{deg.slice(5)/3600}" if (/[0-9]{7}/.match(deg))
|
25
|
+
d
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
return nil if !deg
|
30
|
+
deg = (deg * -1) if (/^-|[WS]$/i.match(dms_str.trim)) # take '-', west and south as -ve
|
31
|
+
deg.to_f
|
32
|
+
end
|
33
|
+
|
34
|
+
# Convert decimal degrees to deg/min/sec format
|
35
|
+
# - degree, prime, double-prime symbols are added, but sign is discarded, though no compass
|
36
|
+
# direction is added
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# @param {Number} deg: Degrees
|
40
|
+
# @param {String} [format=dms]: Return value as 'd', 'dm', 'dms'
|
41
|
+
# @param {Number} [dp=0|2|4]: No of decimal places to use - default 0 for dms, 2 for dm, 4 for d
|
42
|
+
# @returns {String} deg formatted as deg/min/secs according to specified format
|
43
|
+
# @throws {TypeError} deg is an object, perhaps DOM object without .value?
|
44
|
+
|
45
|
+
def to_dms deg, format = :dms, dp = nil
|
46
|
+
deg = begin
|
47
|
+
deg.to_f
|
48
|
+
rescue
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
return nil if !deg # give up here if we can't make a number from deg
|
52
|
+
|
53
|
+
# default values
|
54
|
+
format ||= :dms
|
55
|
+
dp = if dp.nil?
|
56
|
+
case format.to_sym
|
57
|
+
when :d
|
58
|
+
4
|
59
|
+
when :dm
|
60
|
+
2
|
61
|
+
else
|
62
|
+
0 # default
|
63
|
+
end
|
64
|
+
end
|
65
|
+
dp ||= 0
|
66
|
+
|
67
|
+
deg = deg.abs # (unsigned result ready for appending compass dir'n)
|
68
|
+
|
69
|
+
case format
|
70
|
+
when :d
|
71
|
+
d = deg.round(dp) # round degrees
|
72
|
+
ds = "0#{d}" if (d <100) # pad with leading zeros
|
73
|
+
ds = "0#{ds}" if (d <10)
|
74
|
+
dms = ds.to_s.concat("\u00B0") # add º symbol
|
75
|
+
when :dm
|
76
|
+
min = (deg*60).round(dp) # convert degrees to minutes & round
|
77
|
+
d = d.to_i
|
78
|
+
d = (min / 60).floor # get component deg/min
|
79
|
+
m = (min % 60).round(dp) # pad with trailing zeros
|
80
|
+
ds = d
|
81
|
+
ms = m
|
82
|
+
ds = "0#{d}" if (d<100) # pad with leading zeros
|
83
|
+
ds = "0#{d}" if (d<10)
|
84
|
+
ms = "0#{m}" if (m<10)
|
85
|
+
dms = ds.to_s.concat("\u00B0", ms, "\u2032") # add º, ' symbols
|
86
|
+
when :dms
|
87
|
+
sec = (deg * 3600).round # convert degrees to seconds & round
|
88
|
+
d = (sec / 3600).floor # get component deg/min/sec
|
89
|
+
m = ((sec / 60) % 60).floor
|
90
|
+
s = (sec % 60).round(dp) # pad with trailing zeros
|
91
|
+
ds = d
|
92
|
+
ms = m
|
93
|
+
ss = s
|
94
|
+
ds = "0#{d}" if (d < 100) # pad with leading zeros
|
95
|
+
ds = "0#{ds}" if (d < 10)
|
96
|
+
ms = "0#{m}" if (m < 10)
|
97
|
+
ss = "0#{s}" if (s < 10)
|
98
|
+
dms = ds.to_s.concat("\u00B0", ms, "\u2032", ss, "\u2033") # add º, ', " symbols
|
99
|
+
end
|
100
|
+
return dms
|
101
|
+
end
|
102
|
+
|
103
|
+
extend self
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/geo_calc/dms.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Array
|
2
|
+
include ::GeoPoint::CoreExtension
|
3
|
+
|
4
|
+
def to_lat_lng
|
5
|
+
raise "Array must contain at least two elements to be converted to latitude and longitude" if !(size >= 2)
|
6
|
+
[to_lat, to_lng]
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_lng_lat
|
10
|
+
to_lat_lng.reverse
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_lat
|
14
|
+
raise "Array must contain at least one element to return the latitude" if empty?
|
15
|
+
first.to_lat
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_lng
|
19
|
+
raise "Array must contain at least two elements to return the longitude" if !self[1]
|
20
|
+
self[1].to_lng
|
21
|
+
end
|
22
|
+
|
23
|
+
def trim
|
24
|
+
join.trim
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Hash
|
2
|
+
include GeoPoint::CoreExtension
|
3
|
+
|
4
|
+
def to_lat_lng
|
5
|
+
[to_lat, to_lng]
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_lng_lat
|
9
|
+
to_lat_lng.reverse
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_lat
|
13
|
+
v = Symbol.lat_symbols.select {|key| self[key] }
|
14
|
+
return self[v.first].to_lat if !v.empty?
|
15
|
+
raise "Hash must contain either of the keys: [:lat, :latitude] to be converted to a latitude"
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_lng
|
19
|
+
v = Symbol.lng_symbols.select {|key| self[key] }
|
20
|
+
return self[v.first].to_lng if !v.empty?
|
21
|
+
raise "Hash must contain either of the keys: [:lon, :long, :lng, :longitude] to be converted to a longitude"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'geo_units'
|
2
|
+
|
3
|
+
module GeoCalc
|
4
|
+
module NumericCheckExt
|
5
|
+
def is_numeric? arg
|
6
|
+
arg.is_a? Numeric
|
7
|
+
end
|
8
|
+
|
9
|
+
alias_method :is_num?, :is_numeric?
|
10
|
+
|
11
|
+
def check_numeric! arg
|
12
|
+
raise ArgumentError, "Argument must be Numeric" if !is_numeric? arg
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Fixnum
|
18
|
+
include ::GeoUnits::NumericExt
|
19
|
+
end
|
20
|
+
|
21
|
+
class Float
|
22
|
+
include ::GeoUnits::NumericExt
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class String
|
2
|
+
include ::GeoPoint::CoreExtension
|
3
|
+
|
4
|
+
def concat *args
|
5
|
+
args.inject(self) do |res, arg|
|
6
|
+
res << arg.to_s
|
7
|
+
res
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_dms
|
12
|
+
GeoCalc::Dms::Converter.parse_dms self
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_rad
|
16
|
+
parse_dms.to_rad
|
17
|
+
end
|
18
|
+
|
19
|
+
def trim
|
20
|
+
strip
|
21
|
+
end
|
22
|
+
|
23
|
+
def geo_clean
|
24
|
+
self.gsub(/^\(/, '').gsub(/\)$/, '').trim
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_lat_lng
|
28
|
+
geo_clean.split(',').to_lat_lng
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_lng_lat
|
32
|
+
geo_clean.split(',').to_lng_lat
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_lat
|
36
|
+
raise "An empty String has no latitude" if empty?
|
37
|
+
geo_clean.parse_dms.to_f.to_lat
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_lng
|
41
|
+
raise "An empty String has no latitude" if empty?
|
42
|
+
geo_clean.parse_dms.to_f.to_lng
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class GeoPoint
|
2
|
+
module Shared
|
3
|
+
def unit
|
4
|
+
:degrees
|
5
|
+
end
|
6
|
+
|
7
|
+
def earth_radius_km= radius_km
|
8
|
+
raise ArgumentException, "Not a valid earth km radius: #{radius_km}" unless valid_earth_radius? radius_km
|
9
|
+
@earth_radius_km = radius_km
|
10
|
+
end
|
11
|
+
|
12
|
+
def coord_mode= mode
|
13
|
+
raise ArgumentException, "Not a valid coordinates mode: #{mode}" unless valid_mode? mode
|
14
|
+
@coord_mode = mode
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
include GeoCalc::NumericCheckExt
|
20
|
+
|
21
|
+
def valid_earth_radius? radius_km
|
22
|
+
is_numeric?(radius_km) && radius_km.is_between?(6350, 6380)
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid_mode? mode
|
26
|
+
[:lng_lat, :lat_lng].include? mode
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/geo_calc/geo_point.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
require '
|
1
|
+
require 'sugar-high/arguments'
|
2
2
|
require 'geo_calc/calc'
|
3
|
+
require 'geo_calc/extensions'
|
4
|
+
require 'geo_calc/geo_point/shared'
|
3
5
|
|
4
6
|
# Sample usage:
|
5
7
|
# p1 = GeoPoint.new(51.5136, -0.0983)
|
@@ -8,38 +10,48 @@ require 'geo_calc/calc'
|
|
8
10
|
# brng = p1.bearing_to(p2) # in degrees clockwise from north
|
9
11
|
# ... etc
|
10
12
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
11
|
-
#
|
12
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
13
|
-
# Note that minimal error checking is performed in this example code!
|
14
|
-
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
15
13
|
|
16
14
|
class GeoPoint
|
17
15
|
include GeoCalc::Calc::All
|
16
|
+
|
17
|
+
autoload :Shared, 'geo_calc/geo_point/shared'
|
18
|
+
autoload :ClassMethods, 'geo_calc/geo_point/class_methods'
|
19
|
+
autoload :CoreExtension, 'geo_calc/geo_point/core_extension'
|
20
|
+
|
21
|
+
attr_reader :lat, :lon
|
22
|
+
|
18
23
|
# Creates a point on the earth's surface at the supplied latitude / longitude
|
19
24
|
#
|
20
|
-
#
|
21
|
-
# - Numeric
|
22
|
-
# - Numeric lon: longitude in numeric degrees
|
23
|
-
# - Numeric [rad=6371]: radius of earth if different value is required from standard 6,371km
|
25
|
+
# - Numeric latitude in numeric degrees
|
26
|
+
# - Numeric longitude in numeric degrees
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
# Optional options
|
29
|
+
# - :radius - earth radius in km
|
30
|
+
# - :mode - coordinates mode, either :lng_lat or :lat_lng, otherwise uses global setting as per GeoPoint.coord_mode
|
28
31
|
def initialize *args
|
29
|
-
|
30
|
-
|
32
|
+
options = args.is_a?(GeoPoint) ? {} : args.last_option
|
33
|
+
earth_radius_km = options[:radius]
|
34
|
+
coord_mode = options[:mode]
|
35
|
+
|
31
36
|
case args.size
|
32
37
|
when 1
|
33
|
-
create_from_one
|
38
|
+
create_from_one args
|
34
39
|
when 2
|
35
|
-
create_from_two *args
|
40
|
+
create_from_two *args
|
36
41
|
else
|
37
42
|
raise "GeoPoint must be initialized with either one or to arguments defining the (latitude, longitude) coordinate on the map"
|
38
43
|
end
|
39
44
|
end
|
40
45
|
|
41
|
-
|
42
|
-
|
46
|
+
extend ClassMethods
|
47
|
+
include Shared
|
48
|
+
|
49
|
+
def coord_mode
|
50
|
+
@coord_mode ||= GeoPoint.coord_mode
|
51
|
+
end
|
52
|
+
|
53
|
+
def earth_radius_km
|
54
|
+
@earth_radius_km ||= GeoPoint.earth_radius_km # default
|
43
55
|
end
|
44
56
|
|
45
57
|
def lat= value
|
@@ -70,7 +82,7 @@ class GeoPoint
|
|
70
82
|
case key
|
71
83
|
when Fixnum
|
72
84
|
raise ArgumentError, "Index must be 0 or 1" if !(0..1).cover?(key)
|
73
|
-
|
85
|
+
to_a[key]
|
74
86
|
when String, Symbol
|
75
87
|
send(key) if respond_to? key
|
76
88
|
else
|
@@ -98,36 +110,26 @@ class GeoPoint
|
|
98
110
|
[lng, lat]
|
99
111
|
end
|
100
112
|
|
101
|
-
def
|
102
|
-
|
103
|
-
reverse_arr? ? a.reverse : a
|
104
|
-
end
|
105
|
-
|
106
|
-
def reverse_arr?
|
107
|
-
@reverse_arr
|
108
|
-
end
|
109
|
-
|
110
|
-
def reverse_arr!
|
111
|
-
@reverse_arr = true
|
112
|
-
end
|
113
|
-
|
114
|
-
def normal_arr!
|
115
|
-
@reverse_arr = false
|
113
|
+
def to_a
|
114
|
+
send(:"to_#{coord_mode}")
|
116
115
|
end
|
117
116
|
|
118
117
|
protected
|
119
118
|
|
120
|
-
include NumericCheckExt
|
119
|
+
include ::GeoCalc::NumericCheckExt
|
120
|
+
|
121
|
+
def to_coords points
|
122
|
+
points.send(:"to_#{coord_mode}")
|
123
|
+
end
|
121
124
|
|
122
|
-
def create_from_one
|
123
|
-
|
125
|
+
def create_from_one args
|
126
|
+
args = args.first
|
127
|
+
create_from_two *to_coords(args)
|
124
128
|
end
|
125
129
|
|
126
|
-
def create_from_two lat, lon
|
127
|
-
rad ||= 6371 # earth's mean radius in km
|
130
|
+
def create_from_two lat, lon
|
128
131
|
@lat = lat.to_lat
|
129
132
|
@lon = lon.to_lng
|
130
|
-
@radius = rad
|
131
133
|
end
|
132
134
|
end
|
133
135
|
|
@@ -43,8 +43,8 @@ module GeoCalc
|
|
43
43
|
|
44
44
|
return '-,-' if !lat || !lon
|
45
45
|
|
46
|
-
_lat =
|
47
|
-
_lon =
|
46
|
+
_lat = GeoUnits::Converter.to_lat lat, format, dp
|
47
|
+
_lon = GeoUnits::Converter.to_lon lon, format, dp
|
48
48
|
|
49
49
|
"#{_lat}, #{_lon}"
|
50
50
|
end
|