Geocoder
Google geocoder implementation. Requires the Geokit::Geocoders::GOOGLE variable to contain a Google API key. Conforms to the interface set by the Geocoder class.
(Not documented)
# File /Users/andre/projects/rails/geokit/lib/geokit/geocoders.rb, line 442
442: def self.construct_bias_string_from_options(bias)
443: if bias.is_a?(String) or bias.is_a?(Symbol)
444: # country code biasing
445: "&gl=#{bias.to_s.downcase}"
446: elsif bias.is_a?(Bounds)
447: # viewport biasing
448: "&ll=#{bias.center.ll}&spn=#{bias.to_span.ll}"
449: end
450: end
Template method which does the geocode lookup.
Supports viewport/country code biasing
country or viewport. Country code biasing is achieved by passing the ccTLD
('uk' for .co.uk, for example) as a :bias value. For a list of ccTLD's,
look here: http://en.wikipedia.org/wiki/CcTLD. By default, the geocoder
will be biased to results within the US (ccTLD .com).
If you'd like the Google Geocoder to prefer results within a given viewport,
you can pass a Geokit::Bounds object as the :bias value.
# By default, the geocoder will return Syracuse, NY Geokit::Geocoders::GoogleGeocoder.geocode(‘Syracuse’).country_code # => ‘US’ # With country code biasing, it returns Syracuse in Sicily, Italy Geokit::Geocoders::GoogleGeocoder.geocode(‘Syracuse’, :bias => :it).country_code # => ‘IT’
# By default, the geocoder will return Winnetka, IL Geokit::Geocoders::GoogleGeocoder.geocode(‘Winnetka’).state # => ‘IL’ # When biased to an bounding box around California, it will now return the Winnetka neighbourhood, CA bounds = Geokit::Bounds.normalize([34.074081, -118.694401], [34.321129, -118.399487]) Geokit::Geocoders::GoogleGeocoder.geocode(‘Winnetka’, :bias => bounds).state # => ‘CA’
# File /Users/andre/projects/rails/geokit/lib/geokit/geocoders.rb, line 432
432: def self.do_geocode(address, options = {})
433: bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
434: address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
435: res = self.call_geocoder_service("http://maps.google.com/maps/geo?q=#{Geokit::Inflector::url_escape(address_str)}&output=xml#{bias_str}&key=#{Geokit::Geocoders::google}&oe=utf-8")
436: return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
437: xml = res.body
438: logger.debug "Google geocoding. Address: #{address}. Result: #{xml}"
439: return self.xml2GeoLoc(xml, address)
440: end
Template method which does the reverse-geocode lookup.
# File /Users/andre/projects/rails/geokit/lib/geokit/geocoders.rb, line 397
397: def self.do_reverse_geocode(latlng)
398: latlng=LatLng.normalize(latlng)
399: res = self.call_geocoder_service("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(latlng.ll)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8")
400: # 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"))
401: return GeoLoc.new unless (res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPOK))
402: xml = res.body
403: logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{xml}"
404: return self.xml2GeoLoc(xml)
405: end
extracts a single geoloc from a //placemark element in the google results xml
# File /Users/andre/projects/rails/geokit/lib/geokit/geocoders.rb, line 487
487: def self.extract_placemark(doc)
488: res = GeoLoc.new
489: coordinates=doc.elements['.//coordinates'].text.to_s.split(',')
490:
491: #basics
492: res.lat=coordinates[1]
493: res.lng=coordinates[0]
494: res.country_code=doc.elements['.//CountryNameCode'].text if doc.elements['.//CountryNameCode']
495: res.provider='google'
496:
497: #extended -- false if not not available
498: res.city = doc.elements['.//LocalityName'].text if doc.elements['.//LocalityName']
499: res.state = doc.elements['.//AdministrativeAreaName'].text if doc.elements['.//AdministrativeAreaName']
500: res.province = doc.elements['.//SubAdministrativeAreaName'].text if doc.elements['.//SubAdministrativeAreaName']
501: res.full_address = doc.elements['.//address'].text if doc.elements['.//address'] # google provides it
502: res.zip = doc.elements['.//PostalCodeNumber'].text if doc.elements['.//PostalCodeNumber']
503: res.street_address = doc.elements['.//ThoroughfareName'].text if doc.elements['.//ThoroughfareName']
504: res.country = doc.elements['.//CountryName'].text if doc.elements['.//CountryName']
505: res.district = doc.elements['.//DependentLocalityName'].text if doc.elements['.//DependentLocalityName']
506: # Translate accuracy into Yahoo-style token address, street, zip, zip+4, city, state, country
507: # For Google, 1=low accuracy, 8=high accuracy
508: address_details=doc.elements['.//*[local-name() = "AddressDetails"]']
509: res.accuracy = address_details ? address_details.attributes['Accuracy'].to_i : 0
510: res.precision=%w{unknown country state state city zip zip+4 street address building}[res.accuracy]
511:
512: # google returns a set of suggested boundaries for the geocoded result
513: if suggested_bounds = doc.elements['//LatLonBox']
514: res.suggested_bounds = Bounds.normalize(
515: [suggested_bounds.attributes['south'], suggested_bounds.attributes['west']],
516: [suggested_bounds.attributes['north'], suggested_bounds.attributes['east']])
517: end
518:
519: res.success=true
520:
521: return res
522: end
(Not documented)
# File /Users/andre/projects/rails/geokit/lib/geokit/geocoders.rb, line 452
452: def self.xml2GeoLoc(xml, address="")
453: doc=REXML::Document.new(xml)
454:
455: if doc.elements['//kml/Response/Status/code'].text == '200'
456: geoloc = nil
457: # Google can return multiple results as //Placemark elements.
458: # iterate through each and extract each placemark as a geoloc
459: doc.each_element('//Placemark') do |e|
460: extracted_geoloc = extract_placemark(e) # g is now an instance of GeoLoc
461: if geoloc.nil?
462: # first time through, geoloc is still nil, so we make it the geoloc we just extracted
463: geoloc = extracted_geoloc
464: else
465: # second (and subsequent) iterations, we push additional
466: # geolocs onto "geoloc.all"
467: geoloc.all.push(extracted_geoloc)
468: end
469: end
470: return geoloc
471: elsif doc.elements['//kml/Response/Status/code'].text == '620'
472: raise Geokit::TooManyQueriesError
473: else
474: logger.info "Google was unable to geocode address: "+address
475: return GeoLoc.new
476: end
477:
478: rescue Geokit::TooManyQueriesError
479: # re-raise because of other rescue
480: raise Geokit::TooManyQueriesError, "Google returned a 620 status, too many queries. The given key has gone over the requests limit in the 24 hour period or has submitted too many requests in too short a period of time. If you're sending multiple requests in parallel or in a tight loop, use a timer or pause in your code to make sure you don't send the requests too quickly."
481: rescue
482: logger.error "Caught an error during Google geocoding call: "+$!
483: return GeoLoc.new
484: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.