geo_calc 0.6.1 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|