andre-geokit 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +2 -3
- data/README.markdown +90 -11
- data/lib/geokit.rb +3 -3
- data/lib/{geocoders.rb → geokit/geocoders.rb} +79 -9
- data/lib/{mappable.rb → geokit/mappable.rb} +2 -2
- metadata +3 -5
- data/History.txt +0 -5
data/Manifest.txt
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
.loadpath
|
2
2
|
.project
|
3
|
-
History.txt
|
4
3
|
Manifest.txt
|
5
4
|
README.markdown
|
6
5
|
Rakefile
|
7
6
|
geokit.gemspec
|
8
|
-
lib/geocoders.rb
|
7
|
+
lib/geokit/geocoders.rb
|
9
8
|
lib/geokit.rb
|
10
|
-
lib/mappable.rb
|
9
|
+
lib/geokit/mappable.rb
|
11
10
|
test/test_base_geocoder.rb
|
12
11
|
test/test_bounds.rb
|
13
12
|
test/test_ca_geocoder.rb
|
data/README.markdown
CHANGED
@@ -8,13 +8,10 @@ The Geokit gem provides the following:
|
|
8
8
|
|
9
9
|
* Distance calculations between two points on the earth. Calculate the distance in miles or KM, with all the trigonometry abstracted away by GeoKit.
|
10
10
|
* 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
|
+
* Rectangular bounds calculations: is a point within a given rectangular bounds?
|
12
|
+
* Heading and midpoint calculations
|
11
13
|
|
12
|
-
Combine this with gem with the geokit-rails plugin to get location-based finders for your Rails app. Plugins for other web frameworks and ORMs will provide similar functionality.
|
13
|
-
|
14
|
-
|
15
|
-
## FEATURES/PROBLEMS:
|
16
|
-
|
17
|
-
* none currently
|
14
|
+
Combine this with gem with the [geokit-rails plugin](http://github.com/andre/geokit-rails/tree/master) to get location-based finders for your Rails app. Plugins for other web frameworks and ORMs will provide similar functionality.
|
18
15
|
|
19
16
|
## SYNOPSIS:
|
20
17
|
|
@@ -30,21 +27,103 @@ Combine this with gem with the geokit-rails plugin to get location-based finders
|
|
30
27
|
=> 1.21120007413626
|
31
28
|
irb> a.heading_to(b)
|
32
29
|
=> 244.959832435678
|
30
|
+
irb(main):006:0> c=a.midpoint_to(b) # what's halfway from a to b?
|
31
|
+
irb> c.ll
|
32
|
+
=> "37.7899239257175,-122.406153503469"
|
33
|
+
irb(main):008:0> d=c.endpoint(90,10) # what's 10 miles to the east of c?
|
34
|
+
irb> d.ll
|
35
|
+
=> "37.7897825005142,-122.223214776155"
|
33
36
|
|
34
|
-
|
35
|
-
## REQUIREMENTS:
|
36
|
-
|
37
|
+
FYI, that `.ll` method means "latitude longitude".
|
37
38
|
|
38
39
|
## INSTALL:
|
39
40
|
|
40
41
|
* gem sources -a http://gems.github.com
|
41
|
-
* sudo gem install
|
42
|
+
* sudo gem install andre-geokit-gem
|
43
|
+
|
44
|
+
## Configuration
|
45
|
+
|
46
|
+
If you're using this gem by itself, here's how to set configurations:
|
47
|
+
|
48
|
+
# These defaults are used in Geokit::Mappable.distance_to and in acts_as_mappable
|
49
|
+
Geokit::default_units = :miles
|
50
|
+
Geokit::default_formula = :sphere
|
51
|
+
|
52
|
+
# This is the timeout value in seconds to be used for calls to the geocoder web
|
53
|
+
# services. For no timeout at all, comment out the setting. The timeout unit
|
54
|
+
# is in seconds.
|
55
|
+
Geokit::Geocoders::timeout = 3
|
56
|
+
|
57
|
+
# These settings are used if web service calls must be routed through a proxy.
|
58
|
+
# These setting can be nil if not needed, otherwise, addr and port must be
|
59
|
+
# filled in at a minimum. If the proxy requires authentication, the username
|
60
|
+
# and password can be provided as well.
|
61
|
+
Geokit::Geocoders::proxy_addr = nil
|
62
|
+
Geokit::Geocoders::proxy_port = nil
|
63
|
+
Geokit::Geocoders::proxy_user = nil
|
64
|
+
Geokit::Geocoders::proxy_pass = nil
|
65
|
+
|
66
|
+
# This is your yahoo application key for the Yahoo Geocoder.
|
67
|
+
# See http://developer.yahoo.com/faq/index.html#appid
|
68
|
+
# and http://developer.yahoo.com/maps/rest/V1/geocode.html
|
69
|
+
Geokit::Geocoders::yahoo = 'REPLACE_WITH_YOUR_YAHOO_KEY'
|
70
|
+
|
71
|
+
# This is your Google Maps geocoder key.
|
72
|
+
# See http://www.google.com/apis/maps/signup.html
|
73
|
+
# and http://www.google.com/apis/maps/documentation/#Geocoding_Examples
|
74
|
+
Geokit::Geocoders::google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
|
75
|
+
|
76
|
+
# This is your username and password for geocoder.us.
|
77
|
+
# To use the free service, the value can be set to nil or false. For
|
78
|
+
# usage tied to an account, the value should be set to username:password.
|
79
|
+
# See http://geocoder.us
|
80
|
+
# and http://geocoder.us/user/signup
|
81
|
+
Geokit::Geocoders::geocoder_us = false
|
82
|
+
|
83
|
+
# This is your authorization key for geocoder.ca.
|
84
|
+
# To use the free service, the value can be set to nil or false. For
|
85
|
+
# usage tied to an account, set the value to the key obtained from
|
86
|
+
# Geocoder.ca.
|
87
|
+
# See http://geocoder.ca
|
88
|
+
# and http://geocoder.ca/?register=1
|
89
|
+
Geokit::Geocoders::geocoder_ca = false
|
90
|
+
|
91
|
+
# This is the order in which the geocoders are called in a failover scenario
|
92
|
+
# If you only want to use a single geocoder, put a single symbol in the array.
|
93
|
+
# Valid symbols are :google, :yahoo, :us, and :ca.
|
94
|
+
# Be aware that there are Terms of Use restrictions on how you can use the
|
95
|
+
# various geocoders. Make sure you read up on relevant Terms of Use for each
|
96
|
+
# geocoder you are going to use.
|
97
|
+
Geokit::Geocoders::provider_order = [:google,:us]
|
98
|
+
|
99
|
+
If you're using this gem with the [geokit-rails plugin](http://github.com/andre/geokit-rails/tree/master), a template with these settings gets placed in your app's config/initializers directory.
|
100
|
+
|
101
|
+
## NOTES ON WHAT'S WHERE
|
102
|
+
|
103
|
+
mappable.rb contains the Mappable module, which provides basic
|
104
|
+
distance calculation methods, i.e., calculating the distance
|
105
|
+
between two points.
|
106
|
+
|
107
|
+
mappable.rb also contains LatLng, GeoLoc, and Bounds.
|
108
|
+
LatLng is a simple container for latitude and longitude, but
|
109
|
+
it's made more powerful by mixing in the above-mentioned Mappable
|
110
|
+
module -- therefore, you can calculate easily the distance between two
|
111
|
+
LatLng ojbects with `distance = first.distance_to(other)`
|
112
|
+
|
113
|
+
GeoLoc (also in mappable.rb) represents an address or location which
|
114
|
+
has been geocoded. You can get the city, zipcode, street address, etc.
|
115
|
+
from a GeoLoc object. GeoLoc extends LatLng, so you also get lat/lng
|
116
|
+
AND the Mappable modeule goodness for free.
|
117
|
+
|
118
|
+
geocoders.rb contains all the geocoder implemenations. All the gercoders
|
119
|
+
inherit from a common base (class Geocoder) and implement the private method
|
120
|
+
do_geocode.
|
42
121
|
|
43
122
|
## LICENSE:
|
44
123
|
|
45
124
|
(The MIT License)
|
46
125
|
|
47
|
-
Copyright (c) 2007-
|
126
|
+
Copyright (c) 2007-2009 Andre Lewis and Bill Eisenhauer
|
48
127
|
|
49
128
|
Permission is hereby granted, free of charge, to any person obtaining
|
50
129
|
a copy of this software and associated documentation files (the
|
data/lib/geokit.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Geokit
|
2
|
-
VERSION = '1.
|
2
|
+
VERSION = '1.2.0'
|
3
3
|
# These defaults are used in Geokit::Mappable.distance_to and in acts_as_mappable
|
4
4
|
@@default_units = :miles
|
5
5
|
@@default_formula = :sphere
|
@@ -21,8 +21,8 @@ module Geokit
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
require 'geocoders'
|
25
|
-
require 'mappable'
|
24
|
+
require 'geokit/geocoders'
|
25
|
+
require 'geokit/mappable'
|
26
26
|
|
27
27
|
# make old-style module name "GeoKit" equivilent to new-style "Geokit"
|
28
28
|
module GeoKit
|
@@ -59,11 +59,12 @@ module Geokit
|
|
59
59
|
@@google = 'REPLACE_WITH_YOUR_GOOGLE_KEY'
|
60
60
|
@@geocoder_us = false
|
61
61
|
@@geocoder_ca = false
|
62
|
+
@@geonames = false
|
62
63
|
@@provider_order = [:google,:us]
|
63
64
|
@@logger=Logger.new(STDOUT)
|
64
65
|
@@logger.level=Logger::INFO
|
65
66
|
|
66
|
-
[:yahoo, :google, :geocoder_us, :geocoder_ca, :provider_order, :timeout,
|
67
|
+
[:yahoo, :google, :geocoder_us, :geocoder_ca, :geonames, :provider_order, :timeout,
|
67
68
|
:proxy_addr, :proxy_port, :proxy_user, :proxy_pass,:logger].each do |sym|
|
68
69
|
class_eval <<-EOS, __FILE__, __LINE__
|
69
70
|
def self.#{sym}
|
@@ -111,9 +112,16 @@ module Geokit
|
|
111
112
|
private
|
112
113
|
|
113
114
|
# Wraps the geocoder call around a proxy if necessary.
|
114
|
-
def self.do_get(url)
|
115
|
-
|
116
|
-
|
115
|
+
def self.do_get(url)
|
116
|
+
uri = URI.parse(url)
|
117
|
+
req = Net::HTTP::Get.new(url)
|
118
|
+
req.basic_auth(uri.user, uri.password) if uri.userinfo
|
119
|
+
res = Net::HTTP::Proxy(GeoKit::Geocoders::proxy_addr,
|
120
|
+
GeoKit::Geocoders::proxy_port,
|
121
|
+
GeoKit::Geocoders::proxy_user,
|
122
|
+
GeoKit::Geocoders::proxy_pass).start(uri.host, uri.port) { |http| http.request(req) }
|
123
|
+
|
124
|
+
return res
|
117
125
|
end
|
118
126
|
|
119
127
|
# Adds subclass' geocode method making it conveniently available through
|
@@ -280,19 +288,32 @@ module Geokit
|
|
280
288
|
class UsGeocoder < Geocoder
|
281
289
|
|
282
290
|
private
|
283
|
-
|
284
|
-
# For now, the geocoder_method will only geocode full addresses -- not zips or cities in isolation
|
285
291
|
def self.do_geocode(address)
|
286
292
|
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
287
|
-
|
293
|
+
|
294
|
+
query = (address_str =~ /^\d{5}(?:-\d{4})?$/ ? "zip" : "address") + "=#{Geokit::Inflector::url_escape(address_str)}"
|
295
|
+
url = if GeoKit::Geocoders::geocoder_us
|
296
|
+
"http://#{GeoKit::Geocoders::geocoder_us}@geocoder.us/member/service/csv/geocode"
|
297
|
+
else
|
298
|
+
"http://geocoder.us/service/csv/geocode"
|
299
|
+
end
|
300
|
+
|
301
|
+
url = "#{url}?#{query}"
|
288
302
|
res = self.call_geocoder_service(url)
|
303
|
+
|
289
304
|
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
290
305
|
data = res.body
|
291
306
|
logger.debug "Geocoder.us geocoding. Address: #{address}. Result: #{data}"
|
292
307
|
array = data.chomp.split(',')
|
293
|
-
|
294
|
-
if array.length ==
|
308
|
+
|
309
|
+
if array.length == 5
|
295
310
|
res=GeoLoc.new
|
311
|
+
res.lat,res.lng,res.city,res.state,res.zip=array
|
312
|
+
res.country_code='US'
|
313
|
+
res.success=true
|
314
|
+
return res
|
315
|
+
elsif array.length == 6
|
316
|
+
res=GeoLoc.new
|
296
317
|
res.lat,res.lng,res.street_address,res.city,res.state,res.zip=array
|
297
318
|
res.country_code='US'
|
298
319
|
res.success=true
|
@@ -304,6 +325,7 @@ module Geokit
|
|
304
325
|
rescue
|
305
326
|
logger.error "Caught an error during geocoder.us geocoding call: "+$!
|
306
327
|
return GeoLoc.new
|
328
|
+
|
307
329
|
end
|
308
330
|
end
|
309
331
|
|
@@ -350,6 +372,54 @@ module Geokit
|
|
350
372
|
return GeoLoc.new
|
351
373
|
end
|
352
374
|
end
|
375
|
+
|
376
|
+
class GeonamesGeocoder < Geocoder
|
377
|
+
|
378
|
+
private
|
379
|
+
|
380
|
+
# Template method which does the geocode lookup.
|
381
|
+
def self.do_geocode(address)
|
382
|
+
address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
|
383
|
+
# geonames need a space seperated search string
|
384
|
+
address_str.gsub!(/,/, " ")
|
385
|
+
params = "/postalCodeSearch?placename=#{Geokit::Inflector::url_escape(address_str)}&maxRows=10"
|
386
|
+
|
387
|
+
if(GeoKit::Geocoders::geonames)
|
388
|
+
url = "http://ws.geonames.net#{params}&username=#{GeoKit::Geocoders::geonames}"
|
389
|
+
else
|
390
|
+
url = "http://ws.geonames.org#{params}"
|
391
|
+
end
|
392
|
+
|
393
|
+
res = self.call_geocoder_service(url)
|
394
|
+
|
395
|
+
return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
|
396
|
+
|
397
|
+
xml=res.body
|
398
|
+
logger.debug "Geonames geocoding. Address: #{address}. Result: #{xml}"
|
399
|
+
doc=REXML::Document.new(xml)
|
400
|
+
|
401
|
+
if(doc.elements['//geonames/totalResultsCount'].text.to_i > 0)
|
402
|
+
res=GeoLoc.new
|
403
|
+
|
404
|
+
# only take the first result
|
405
|
+
res.lat=doc.elements['//code/lat'].text if doc.elements['//code/lat']
|
406
|
+
res.lng=doc.elements['//code/lng'].text if doc.elements['//code/lng']
|
407
|
+
res.country_code=doc.elements['//code/countryCode'].text if doc.elements['//code/countryCode']
|
408
|
+
res.provider='genomes'
|
409
|
+
res.city=doc.elements['//code/name'].text if doc.elements['//code/name']
|
410
|
+
res.state=doc.elements['//code/adminName1'].text if doc.elements['//code/adminName1']
|
411
|
+
res.zip=doc.elements['//code/postalcode'].text if doc.elements['//code/postalcode']
|
412
|
+
res.success=true
|
413
|
+
return res
|
414
|
+
else
|
415
|
+
logger.info "Geonames was unable to geocode address: "+address
|
416
|
+
return GeoLoc.new
|
417
|
+
end
|
418
|
+
|
419
|
+
rescue
|
420
|
+
logger.error "Caught an error during Geonames geocoding call: "+$!
|
421
|
+
end
|
422
|
+
end
|
353
423
|
|
354
424
|
# Provides methods to geocode with a variety of geocoding service providers, plus failover
|
355
425
|
# among providers in the order you configure.
|
@@ -353,7 +353,7 @@ module Geokit
|
|
353
353
|
|
354
354
|
# provide sw and ne to instantiate a new Bounds instance
|
355
355
|
def initialize(sw,ne)
|
356
|
-
raise
|
356
|
+
raise ArgumentError if !(sw.is_a?(Geokit::LatLng) && ne.is_a?(Geokit::LatLng))
|
357
357
|
@sw,@ne=sw,ne
|
358
358
|
end
|
359
359
|
|
@@ -410,7 +410,7 @@ module Geokit
|
|
410
410
|
Geokit::Bounds.new(sw,ne)
|
411
411
|
end
|
412
412
|
|
413
|
-
# Takes two main combinations of
|
413
|
+
# Takes two main combinations of arguments to create a bounds:
|
414
414
|
# point,point (this is the only one which takes two arguments
|
415
415
|
# [point,point]
|
416
416
|
# . . . where a point is anything LatLng#normalize can handle (which is quite a lot)
|
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.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andre Lewis and Bill Eisenhauer
|
@@ -29,17 +29,15 @@ executables: []
|
|
29
29
|
extensions: []
|
30
30
|
|
31
31
|
extra_rdoc_files:
|
32
|
-
- History.txt
|
33
32
|
- Manifest.txt
|
34
33
|
- README.markdown
|
35
34
|
files:
|
36
|
-
- History.txt
|
37
35
|
- Manifest.txt
|
38
36
|
- README.markdown
|
39
37
|
- Rakefile
|
40
|
-
- lib/geocoders.rb
|
38
|
+
- lib/geokit/geocoders.rb
|
41
39
|
- lib/geokit.rb
|
42
|
-
- lib/mappable.rb
|
40
|
+
- lib/geokit/mappable.rb
|
43
41
|
- test/test_base_geocoder.rb
|
44
42
|
- test/test_bounds.rb
|
45
43
|
- test/test_ca_geocoder.rb
|