andre-geokit 1.2.0 → 1.2.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/Manifest.txt +2 -2
- data/README.markdown +6 -3
- data/Rakefile +1 -1
- data/lib/geokit.rb +1 -3
- data/lib/geokit/geocoders.rb +31 -2
- data/lib/geokit/mappable.rb +39 -16
- data/test/test_bounds.rb +1 -1
- data/test/test_latlng.rb +21 -0
- metadata +3 -3
data/Manifest.txt
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
.loadpath
|
2
1
|
.project
|
3
2
|
Manifest.txt
|
4
3
|
README.markdown
|
5
4
|
Rakefile
|
6
5
|
geokit.gemspec
|
7
|
-
lib/geokit/geocoders.rb
|
8
6
|
lib/geokit.rb
|
7
|
+
lib/geokit/geocoders.rb
|
9
8
|
lib/geokit/mappable.rb
|
10
9
|
test/test_base_geocoder.rb
|
11
10
|
test/test_bounds.rb
|
12
11
|
test/test_ca_geocoder.rb
|
13
12
|
test/test_geoloc.rb
|
14
13
|
test/test_google_geocoder.rb
|
14
|
+
test/test_google_reverse_geocoder.rb
|
15
15
|
test/test_ipgeocoder.rb
|
16
16
|
test/test_latlng.rb
|
17
17
|
test/test_multi_geocoder.rb
|
data/README.markdown
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# Geokit gem
|
2
2
|
|
3
|
-
[http://geokit.rubyforge.org](http://geokit.rubyforge.org)
|
3
|
+
* Geokit Documentation at Rubyforge [http://geokit.rubyforge.org](http://geokit.rubyforge.org).
|
4
|
+
* Repository at Github: [http://github.com/andre/geokit-gem/tree/master](http://github.com/andre/geokit-gem/tree/master).
|
4
5
|
|
5
6
|
## DESCRIPTION:
|
6
7
|
|
7
8
|
The Geokit gem provides the following:
|
8
9
|
|
9
|
-
* Distance calculations between two points on the earth. Calculate the distance in miles or
|
10
|
+
* Distance calculations between two points on the earth. Calculate the distance in miles, kilometers, or nautical miles, with all the trigonometry abstracted away by GeoKit.
|
10
11
|
* Geocoding from multiple providers. It currently supports Google, Yahoo, Geocoder.us, and Geocoder.ca geocoders, and it provides a uniform response structure from all of them. It also provides a fail-over mechanism, in case your input fails to geocode in one service.
|
11
12
|
* Rectangular bounds calculations: is a point within a given rectangular bounds?
|
12
13
|
* Heading and midpoint calculations
|
@@ -36,10 +37,12 @@ Combine this with gem with the [geokit-rails plugin](http://github.com/andre/geo
|
|
36
37
|
|
37
38
|
FYI, that `.ll` method means "latitude longitude".
|
38
39
|
|
40
|
+
See the RDOC more more ... there is also operations on rectangular bounds (e.g., determining if a point is within bounds, find the center, etc).
|
41
|
+
|
39
42
|
## INSTALL:
|
40
43
|
|
41
44
|
* gem sources -a http://gems.github.com
|
42
|
-
* sudo gem install andre-geokit
|
45
|
+
* sudo gem install andre-geokit
|
43
46
|
|
44
47
|
## Configuration
|
45
48
|
|
data/Rakefile
CHANGED
data/lib/geokit.rb
CHANGED
data/lib/geokit/geocoders.rb
CHANGED
@@ -95,6 +95,14 @@ module Geokit
|
|
95
95
|
return res.success ? res : GeoLoc.new
|
96
96
|
end
|
97
97
|
|
98
|
+
# Main method which calls the do_reverse_geocode template method which subclasses
|
99
|
+
# are responsible for implementing. Returns a populated GeoLoc or an
|
100
|
+
# empty one with a failed success code.
|
101
|
+
def self.reverse_geocode(latlng)
|
102
|
+
res = do_reverse_geocode(latlng)
|
103
|
+
return res.success ? res : GeoLoc.new
|
104
|
+
end
|
105
|
+
|
98
106
|
# Call the geocoder service using the timeout if configured.
|
99
107
|
def self.call_geocoder_service(url)
|
100
108
|
timeout(Geokit::Geocoders::timeout) { return self.do_get(url) } if Geokit::Geocoders::timeout
|
@@ -103,6 +111,13 @@ module Geokit
|
|
103
111
|
return nil
|
104
112
|
end
|
105
113
|
|
114
|
+
# Not all geocoders can do reverse geocoding. So, unless the subclass explicitly overrides this method,
|
115
|
+
# a call to reverse_geocode will return an empty GeoLoc. If you happen to be using MultiGeocoder,
|
116
|
+
# this will cause it to failover to the next geocoder, which will hopefully be one which supports reverse geocoding.
|
117
|
+
def self.do_reverse_geocode(latlng)
|
118
|
+
return GeoLoc.new
|
119
|
+
end
|
120
|
+
|
106
121
|
protected
|
107
122
|
|
108
123
|
def self.logger()
|
@@ -193,6 +208,16 @@ module Geokit
|
|
193
208
|
class GoogleGeocoder < Geocoder
|
194
209
|
|
195
210
|
private
|
211
|
+
|
212
|
+
# Template method which does the reverse-geocode lookup.
|
213
|
+
def self.do_reverse_geocode(latlng)
|
214
|
+
res = self.call_geocoder_service("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(latlng)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8")
|
215
|
+
# res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8"))
|
216
|
+
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
217
|
+
xml = res.body
|
218
|
+
logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{xml}"
|
219
|
+
return self.xml2GeoLoc(xml)
|
220
|
+
end
|
196
221
|
|
197
222
|
# Template method which does the geocode lookup.
|
198
223
|
def self.do_geocode(address)
|
@@ -200,8 +225,12 @@ module Geokit
|
|
200
225
|
res = self.call_geocoder_service("http://maps.google.com/maps/geo?q=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8")
|
201
226
|
# res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?q=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8"))
|
202
227
|
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
203
|
-
xml=res.body
|
228
|
+
xml = res.body
|
204
229
|
logger.debug "Google geocoding. Address: #{address}. Result: #{xml}"
|
230
|
+
return self.xml2GeoLoc(xml)
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.xml2GeoLoc(xml)
|
205
234
|
doc=REXML::Document.new(xml)
|
206
235
|
|
207
236
|
if doc.elements['//kml/Response/Status/code'].text == '200'
|
@@ -211,7 +240,7 @@ module Geokit
|
|
211
240
|
#basics
|
212
241
|
res.lat=coordinates[1]
|
213
242
|
res.lng=coordinates[0]
|
214
|
-
res.country_code=doc.elements['//CountryNameCode'].text
|
243
|
+
res.country_code=doc.elements['//CountryNameCode'].text if doc.elements['//CountryNameCode']
|
215
244
|
res.provider='google'
|
216
245
|
|
217
246
|
#extended -- false if not not available
|
data/lib/geokit/mappable.rb
CHANGED
@@ -9,14 +9,17 @@ module Geokit
|
|
9
9
|
# * Pythagorean Theory (flat Earth) - which assumes the world is flat and loses accuracy over long distances.
|
10
10
|
# * Haversine (sphere) - which is fairly accurate, but at a performance cost.
|
11
11
|
#
|
12
|
-
# Distance units supported are :miles and :
|
12
|
+
# Distance units supported are :miles, :kms, and :nms.
|
13
13
|
module Mappable
|
14
14
|
PI_DIV_RAD = 0.0174
|
15
15
|
KMS_PER_MILE = 1.609
|
16
|
+
NMS_PER_MILE = 0.868976242
|
16
17
|
EARTH_RADIUS_IN_MILES = 3963.19
|
17
18
|
EARTH_RADIUS_IN_KMS = EARTH_RADIUS_IN_MILES * KMS_PER_MILE
|
19
|
+
EARTH_RADIUS_IN_NMS = EARTH_RADIUS_IN_MILES * NMS_PER_MILE
|
18
20
|
MILES_PER_LATITUDE_DEGREE = 69.1
|
19
21
|
KMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * KMS_PER_MILE
|
22
|
+
NMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * NMS_PER_MILE
|
20
23
|
LATITUDE_DEGREES = EARTH_RADIUS_IN_MILES / MILES_PER_LATITUDE_DEGREE
|
21
24
|
|
22
25
|
# Mix below class methods into the includer.
|
@@ -27,7 +30,7 @@ module Geokit
|
|
27
30
|
module ClassMethods #:nodoc:
|
28
31
|
# Returns the distance between two points. The from and to parameters are
|
29
32
|
# required to have lat and lng attributes. Valid options are:
|
30
|
-
# :units - valid values are :miles
|
33
|
+
# :units - valid values are :miles, :kms, :nms (Geokit::default_units is the default)
|
31
34
|
# :formula - valid values are :flat or :sphere (Geokit::default_formula is the default)
|
32
35
|
def distance_between(from, to, options={})
|
33
36
|
from=Geokit::LatLng.normalize(from)
|
@@ -36,11 +39,15 @@ module Geokit
|
|
36
39
|
units = options[:units] || Geokit::default_units
|
37
40
|
formula = options[:formula] || Geokit::default_formula
|
38
41
|
case formula
|
39
|
-
when :sphere
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
when :sphere
|
43
|
+
begin
|
44
|
+
units_sphere_multiplier(units) *
|
45
|
+
Math.acos( Math.sin(deg2rad(from.lat)) * Math.sin(deg2rad(to.lat)) +
|
46
|
+
Math.cos(deg2rad(from.lat)) * Math.cos(deg2rad(to.lat)) *
|
47
|
+
Math.cos(deg2rad(to.lng) - deg2rad(from.lng)))
|
48
|
+
rescue Errno::EDOM
|
49
|
+
0.0
|
50
|
+
end
|
44
51
|
when :flat
|
45
52
|
Math.sqrt((units_per_latitude_degree(units)*(from.lat-to.lat))**2 +
|
46
53
|
(units_per_longitude_degree(from.lat, units)*(from.lng-to.lng))**2)
|
@@ -67,7 +74,11 @@ module Geokit
|
|
67
74
|
# will be used instead of this method.
|
68
75
|
def endpoint(start,heading, distance, options={})
|
69
76
|
units = options[:units] || Geokit::default_units
|
70
|
-
radius = units
|
77
|
+
radius = case units
|
78
|
+
when :kms: EARTH_RADIUS_IN_KMS
|
79
|
+
when :nms: EARTH_RADIUS_IN_NMS
|
80
|
+
else EARTH_RADIUS_IN_MILES
|
81
|
+
end
|
71
82
|
start=Geokit::LatLng.normalize(start)
|
72
83
|
lat=deg2rad(start.lat)
|
73
84
|
lng=deg2rad(start.lng)
|
@@ -86,7 +97,7 @@ module Geokit
|
|
86
97
|
# Returns the midpoint, given two points. Returns a LatLng.
|
87
98
|
# Typically, the instance method will be used instead of this method.
|
88
99
|
# Valid option:
|
89
|
-
# :units - valid values are :miles or :
|
100
|
+
# :units - valid values are :miles, :kms, or :nms (:miles is the default)
|
90
101
|
def midpoint_between(from,to,options={})
|
91
102
|
from=Geokit::LatLng.normalize(from)
|
92
103
|
|
@@ -120,18 +131,30 @@ module Geokit
|
|
120
131
|
|
121
132
|
# Returns the multiplier used to obtain the correct distance units.
|
122
133
|
def units_sphere_multiplier(units)
|
123
|
-
units
|
134
|
+
case units
|
135
|
+
when :kms: EARTH_RADIUS_IN_KMS
|
136
|
+
when :nms: EARTH_RADIUS_IN_NMS
|
137
|
+
else EARTH_RADIUS_IN_MILES
|
138
|
+
end
|
124
139
|
end
|
125
140
|
|
126
141
|
# Returns the number of units per latitude degree.
|
127
142
|
def units_per_latitude_degree(units)
|
128
|
-
units
|
143
|
+
case units
|
144
|
+
when :kms: KMS_PER_LATITUDE_DEGREE
|
145
|
+
when :nms: NMS_PER_LATITUDE_DEGREE
|
146
|
+
else MILES_PER_LATITUDE_DEGREE
|
147
|
+
end
|
129
148
|
end
|
130
149
|
|
131
150
|
# Returns the number units per longitude degree.
|
132
151
|
def units_per_longitude_degree(lat, units)
|
133
152
|
miles_per_longitude_degree = (LATITUDE_DEGREES * Math.cos(lat * PI_DIV_RAD)).abs
|
134
|
-
units
|
153
|
+
case units
|
154
|
+
when :kms: miles_per_longitude_degree * KMS_PER_MILE
|
155
|
+
when :nms: miles_per_longitude_degree * NMS_PER_MILE
|
156
|
+
else miles_per_longitude_degree
|
157
|
+
end
|
135
158
|
end
|
136
159
|
end
|
137
160
|
|
@@ -143,12 +166,12 @@ module Geokit
|
|
143
166
|
def to_lat_lng
|
144
167
|
return self if instance_of?(Geokit::LatLng) || instance_of?(Geokit::GeoLoc)
|
145
168
|
return LatLng.new(send(self.class.lat_column_name),send(self.class.lng_column_name)) if self.class.respond_to?(:acts_as_mappable)
|
146
|
-
|
169
|
+
nil
|
147
170
|
end
|
148
171
|
|
149
172
|
# Returns the distance from another point. The other point parameter is
|
150
173
|
# required to have lat and lng attributes. Valid options are:
|
151
|
-
# :units - valid values are :miles or :
|
174
|
+
# :units - valid values are :miles, :kms, :or :nms (:miles is the default)
|
152
175
|
# :formula - valid values are :flat or :sphere (:sphere is the default)
|
153
176
|
def distance_to(other, options={})
|
154
177
|
self.class.distance_between(self, other, options)
|
@@ -169,14 +192,14 @@ module Geokit
|
|
169
192
|
|
170
193
|
# Returns the endpoint, given a heading (in degrees) and distance.
|
171
194
|
# Valid option:
|
172
|
-
# :units - valid values are :miles or :
|
195
|
+
# :units - valid values are :miles, :kms, or :nms (:miles is the default)
|
173
196
|
def endpoint(heading,distance,options={})
|
174
197
|
self.class.endpoint(self,heading,distance,options)
|
175
198
|
end
|
176
199
|
|
177
200
|
# Returns the midpoint, given another point on the map.
|
178
201
|
# Valid option:
|
179
|
-
# :units - valid values are :miles or :
|
202
|
+
# :units - valid values are :miles, :kms, or :nms (:miles is the default)
|
180
203
|
def midpoint_to(other, options={})
|
181
204
|
self.class.midpoint_between(self,other,options)
|
182
205
|
end
|
data/test/test_bounds.rb
CHANGED
@@ -55,7 +55,7 @@ class BoundsTest < Test::Unit::TestCase #:nodoc: all
|
|
55
55
|
|
56
56
|
def test_center
|
57
57
|
assert_in_delta 32.939828,@bounds.center.lat,0.00005
|
58
|
-
assert_in_delta
|
58
|
+
assert_in_delta(-96.9511763,@bounds.center.lng,0.00005)
|
59
59
|
end
|
60
60
|
|
61
61
|
def test_center_cross_meridian
|
data/test/test_latlng.rb
CHANGED
@@ -24,6 +24,11 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
|
|
24
24
|
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :kms, :formula => :flat)
|
25
25
|
end
|
26
26
|
|
27
|
+
def test_distance_between_same_with_nms_and_flat
|
28
|
+
assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :nms, :formula => :flat)
|
29
|
+
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :nms, :formula => :flat)
|
30
|
+
end
|
31
|
+
|
27
32
|
def test_distance_between_same_with_miles_and_sphere
|
28
33
|
assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :miles, :formula => :sphere)
|
29
34
|
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :miles, :formula => :sphere)
|
@@ -34,6 +39,11 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
|
|
34
39
|
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :kms, :formula => :sphere)
|
35
40
|
end
|
36
41
|
|
42
|
+
def test_distance_between_same_with_nms_and_sphere
|
43
|
+
assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :nms, :formula => :sphere)
|
44
|
+
assert_equal 0, @loc_a.distance_to(@loc_a, :units => :nms, :formula => :sphere)
|
45
|
+
end
|
46
|
+
|
37
47
|
def test_distance_between_diff_using_defaults
|
38
48
|
assert_in_delta 3.97, Geokit::LatLng.distance_between(@loc_a, @loc_e), 0.01
|
39
49
|
assert_in_delta 3.97, @loc_a.distance_to(@loc_e), 0.01
|
@@ -49,6 +59,11 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
|
|
49
59
|
assert_in_delta 6.39, @loc_a.distance_to(@loc_e, :units => :kms, :formula => :flat), 0.4
|
50
60
|
end
|
51
61
|
|
62
|
+
def test_distance_between_diff_with_nms_and_flat
|
63
|
+
assert_in_delta 3.334, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :nms, :formula => :flat), 0.4
|
64
|
+
assert_in_delta 3.334, @loc_a.distance_to(@loc_e, :units => :nms, :formula => :flat), 0.4
|
65
|
+
end
|
66
|
+
|
52
67
|
def test_distance_between_diff_with_miles_and_sphere
|
53
68
|
assert_in_delta 3.97, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :miles, :formula => :sphere), 0.01
|
54
69
|
assert_in_delta 3.97, @loc_a.distance_to(@loc_e, :units => :miles, :formula => :sphere), 0.01
|
@@ -59,12 +74,18 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
|
|
59
74
|
assert_in_delta 6.39, @loc_a.distance_to(@loc_e, :units => :kms, :formula => :sphere), 0.01
|
60
75
|
end
|
61
76
|
|
77
|
+
def test_distance_between_diff_with_nms_and_sphere
|
78
|
+
assert_in_delta 3.454, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :nms, :formula => :sphere), 0.01
|
79
|
+
assert_in_delta 3.454, @loc_a.distance_to(@loc_e, :units => :nms, :formula => :sphere), 0.01
|
80
|
+
end
|
81
|
+
|
62
82
|
def test_manually_mixed_in
|
63
83
|
assert_equal 0, Geokit::LatLng.distance_between(@point, @point)
|
64
84
|
assert_equal 0, @point.distance_to(@point)
|
65
85
|
assert_equal 0, @point.distance_to(@loc_a)
|
66
86
|
assert_in_delta 3.97, @point.distance_to(@loc_e, :units => :miles, :formula => :flat), 0.2
|
67
87
|
assert_in_delta 6.39, @point.distance_to(@loc_e, :units => :kms, :formula => :flat), 0.4
|
88
|
+
assert_in_delta 3.334, @point.distance_to(@loc_e, :units => :nms, :formula => :flat), 0.4
|
68
89
|
end
|
69
90
|
|
70
91
|
def test_heading_between
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: andre-geokit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andre Lewis and Bill Eisenhauer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-02-01 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -52,7 +52,7 @@ homepage: http://geokit.rubyforge.org
|
|
52
52
|
post_install_message:
|
53
53
|
rdoc_options:
|
54
54
|
- --main
|
55
|
-
- README.
|
55
|
+
- README.markdown
|
56
56
|
require_paths:
|
57
57
|
- lib
|
58
58
|
required_ruby_version: !ruby/object:Gem::Requirement
|