lib/geokit/mappable.rb in darrell-geokit-1.2.4.1 vs lib/geokit/mappable.rb in darrell-geokit-1.4.1.1
- old
+ new
@@ -108,13 +108,13 @@
distance=from.distance_to(to,options)
midpoint=from.endpoint(heading,distance/2,options)
end
# Geocodes a location using the multi geocoder.
- def geocode(location)
- res = Geocoders::MultiGeocoder.geocode(location)
- return res if res.success
+ def geocode(location, options = {})
+ res = Geocoders::MultiGeocoder.geocode(location, options)
+ return res if res.success?
raise Geokit::Geocoders::GeocodeError
end
protected
@@ -249,10 +249,18 @@
# is true if the lat and lng attributes are the same for both objects.
def ==(other)
other.is_a?(LatLng) ? self.lat == other.lat && self.lng == other.lng : false
end
+ def hash
+ lat.hash + lng.hash
+ end
+
+ def eql?(other)
+ self == other
+ end
+
# A *class* method to take anything which can be inferred as a point and generate
# a LatLng from it. You should use this anything you're not sure what the input is,
# and want to deal with it as a LatLng if at all possible. Can take:
# 1) two arguments (lat,lng)
# 2) a string in the format "37.1234,-129.1234" or "37.1234 -129.1234"
@@ -268,11 +276,11 @@
thing.strip!
if match=thing.match(/(\-?\d+\.?\d*)[, ] ?(\-?\d+\.?\d*)$/)
return Geokit::LatLng.new(match[1],match[2])
else
res = Geokit::Geocoders::MultiGeocoder.geocode(thing)
- return res if res.success
+ return res if res.success?
raise Geokit::Geocoders::GeocodeError
end
elsif thing.is_a?(Array) && thing.size==2
return Geokit::LatLng.new(thing[0],thing[1])
elsif thing.is_a?(LatLng) # will also be true for GeoLocs
@@ -282,10 +290,34 @@
end
raise ArgumentError.new("#{thing} (#{thing.class}) cannot be normalized to a LatLng. We tried interpreting it as an array, string, Mappable, etc., but no dice.")
end
+ # Reverse geocodes a LatLng object using the MultiGeocoder (default), or optionally
+ # using a geocoder of your choosing. Returns a new Geokit::GeoLoc object
+ #
+ # ==== Options
+ # * :using - Specifies the geocoder to use for reverse geocoding. Defaults to
+ # MultiGeocoder. Can be either the geocoder class (or any class that
+ # implements do_reverse_geocode for that matter), or the name of
+ # the class without the "Geocoder" part (e.g. :google)
+ #
+ # ==== Examples
+ # LatLng.new(51.4578329, 7.0166848).reverse_geocode # => #<Geokit::GeoLoc:0x12dac20 @state...>
+ # LatLng.new(51.4578329, 7.0166848).reverse_geocode(:using => :google) # => #<Geokit::GeoLoc:0x12dac20 @state...>
+ # LatLng.new(51.4578329, 7.0166848).reverse_geocode(:using => Geokit::Geocoders::GoogleGeocoder) # => #<Geokit::GeoLoc:0x12dac20 @state...>
+ def reverse_geocode(options = { :using => Geokit::Geocoders::MultiGeocoder })
+ if options[:using].is_a?(String) or options[:using].is_a?(Symbol)
+ provider = Geokit::Geocoders.const_get("#{Geokit::Inflector::camelize(options[:using].to_s)}Geocoder")
+ elsif options[:using].respond_to?(:do_reverse_geocode)
+ provider = options[:using]
+ else
+ raise ArgumentError.new("#{options[:using]} is not a valid geocoder.")
+ end
+
+ provider.send(:reverse_geocode, self)
+ end
end
# This class encapsulates the result of a geocoding call.
# It's primary purpose is to homogenize the results of multiple
# geocoding providers. It also provides some additional functionality, such as
@@ -312,13 +344,16 @@
# 100 Spear St, San Francisco, CA, 94101, US
attr_accessor :street_address, :city, :state, :zip, :country_code, :full_address, :all
# Attributes set upon return from geocoding. Success will be true for successful
# geocode lookups. The provider will be set to the name of the providing geocoder.
# Finally, precision is an indicator of the accuracy of the geocoding.
- attr_accessor :success, :provider, :precision
+ attr_accessor :success, :provider, :precision, :suggested_bounds
# Street number and street name are extracted from the street address attribute.
attr_reader :street_number, :street_name
+ # accuracy is set for Yahoo and Google geocoders, it is a numeric value of the
+ # precision. see http://code.google.com/apis/maps/documentation/geocoding/#GeocodingAccuracy
+ attr_accessor :accuracy
# Constructor expects a hash of symbols to correspond with attributes.
def initialize(h={})
@all = [self]
@@ -335,10 +370,14 @@
# Returns true if geocoded to the United States.
def is_us?
country_code == 'US'
end
+
+ def success?
+ success == true
+ end
# full_address is provided by google but not by yahoo. It is intended that the google
# geocoding method will provide the full address, whereas for yahoo it will be derived
# from the parts of the address we do have.
def full_address
@@ -372,26 +411,26 @@
# Sets the street address after capitalizing each word within the street address.
def street_address=(address)
#@street_address = Geokit::Inflector::titleize(address) if address
@street_address = address if address
end
-
+
# Returns a comma-delimited string consisting of the street address, city, state,
# zip, and country code. Only includes those attributes that are non-blank.
def to_geocodeable_s
a=[street_address, city, state, zip, country_code].compact
a.delete_if { |e| !e || e == '' }
a.join(', ')
end
def to_yaml_properties
- (instance_variables - ['@results']).sort
+ (instance_variables - ['@all']).sort
end
# Returns a string representation of the instance.
def to_s
- "Provider: #{provider}\n Street: #{street_address}\nCity: #{city}\nState: #{state}\nZip: #{zip}\nLatitude: #{lat}\nLongitude: #{lng}\nCountry: #{country_code}\nSuccess: #{success}"
+ "Provider: #{provider}\nStreet: #{street_address}\nCity: #{city}\nState: #{state}\nZip: #{zip}\nLatitude: #{lat}\nLongitude: #{lng}\nCountry: #{country_code}\nSuccess: #{success}"
end
end
# Bounds represents a rectangular bounds, defined by the SW and NE corners
class Bounds
@@ -439,9 +478,19 @@
# Returns true if the candidate object is logically equal. Logical equivalence
# is true if the lat and lng attributes are the same for both objects.
def ==(other)
other.is_a?(Bounds) ? self.sw == other.sw && self.ne == other.ne : false
+ end
+
+ # Equivalent to Google Maps API's .toSpan() method on GLatLng's.
+ #
+ # Returns a LatLng object, whose coordinates represent the size of a rectangle
+ # defined by these bounds.
+ def to_span
+ lat_span = (@ne.lat - @sw.lat).abs
+ lng_span = (crosses_meridian? ? 360 + @ne.lng - @sw.lng : @ne.lng - @sw.lng).abs
+ Geokit::LatLng.new(lat_span, lng_span)
end
class <<self
# returns an instance of bounds which completely encompases the given circle