Skip to content
Browse files

Models chenged to use the configurations for units and method. Some t…

…ests included.
  • Loading branch information...
1 parent 32ddeff commit 5c2cf499c8888fab40befc2ac875b5b1eb15ba40 Anderson Bravalheri committed Jul 21, 2011
View
38 lib/geocoder/calculations.rb
@@ -24,15 +24,17 @@ module Calculations
##
# Distance spanned by one degree of latitude in the given units.
#
- def latitude_degree_distance(units = :mi)
+ def latitude_degree_distance(units = nil)
+ units ||= Geocoder::Configuration.units
2 * Math::PI * earth_radius(units) / 360
end
##
# Distance spanned by one degree of longitude at the given latitude.
# This ranges from around 69 miles at the equator to zero at the poles.
#
- def longitude_degree_distance(latitude, units = :mi)
+ def longitude_degree_distance(latitude, units = nil)
+ units ||= Geocoder::Configuration.units
latitude_degree_distance(units) * Math.cos(to_radians(latitude))
end
@@ -49,12 +51,13 @@ def longitude_degree_distance(latitude, units = :mi)
#
# The options hash supports:
#
- # * <tt>:units</tt> - <tt>:mi</tt> (default) or <tt>:km</tt>
+ # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>
+ # See Geocoder::Configuration to know how configure default units.
#
def distance_between(point1, point2, options = {})
# set default options
- options[:units] ||= :mi
+ options[:units] ||= Geocoder::Configuration.units
# convert to coordinate arrays
point1 = extract_coordinates(point1)
@@ -81,17 +84,18 @@ def distance_between(point1, point2, options = {})
# See Geocoder::Calculations.distance_between for
# ways of specifying the points. Also accepts an options hash:
#
- # * <tt>:method</tt> - <tt>:linear</tt> (default) or <tt>:spherical</tt>;
+ # * <tt>:method</tt> - <tt>:linear</tt> or <tt>:spherical</tt>;
# the spherical method is "correct" in that it returns the shortest path
- # (one along a great circle) but the linear method is the default as it
- # is less confusing (returns due east or west when given two points with
- # the same latitude)
+ # (one along a great circle) but the linear method is less confusing
+ # (returns due east or west when given two points with the same latitude).
+ # See Geocoder::Configuration to know how configure default method.
#
# Based on: http://www.movable-type.co.uk/scripts/latlong.html
#
def bearing_between(point1, point2, options = {})
# set default options
+ options[:method] ||= Geocoder::Configuration.method
options[:method] = :linear unless options[:method] == :spherical
# convert to coordinate arrays
@@ -177,12 +181,13 @@ def geographic_center(points)
# See Geocoder::Calculations.distance_between for
# ways of specifying the point. Also accepts an options hash:
#
- # * <tt>:units</tt> - <tt>:mi</tt> (default) or <tt>:km</tt>
+ # * <tt>:units</tt> - <tt>:mi</tt> or <tt>:km</tt>.
+ # See Geocoder::Configuration to know how configure default units.
#
def bounding_box(point, radius, options = {})
lat,lon = extract_coordinates(point)
radius = radius.to_f
- units = options[:units] || :mi
+ units = options[:units] || Geocoder::Configuration.units
[
lat - (radius / latitude_degree_distance(units)),
lon - (radius / longitude_degree_distance(lat, units)),
@@ -219,11 +224,13 @@ def to_degrees(*args)
end
end
- def distance_to_radians(distance, units = :mi)
+ def distance_to_radians(distance, units = nil)
+ units ||= Geocoder::Configuration.units
distance.to_f / earth_radius(units)
end
- def radians_to_distance(radians, units = :mi)
+ def radians_to_distance(radians, units = nil)
+ units ||= Geocoder::Configuration.units
radians * earth_radius(units)
end
@@ -242,9 +249,11 @@ def to_miles(km)
end
##
- # Radius of the Earth in the given units (:mi or :km). Default is :mi.
+ # Radius of the Earth in the given units (:mi or :km).
+ # See Geocoder::Configuration to know how configure default units.
#
- def earth_radius(units = :mi)
+ def earth_radius(units = nil)
+ units ||= Geocoder::Configuration.units
units == :km ? EARTH_RADIUS : to_miles(EARTH_RADIUS)
end
@@ -277,3 +286,4 @@ def extract_coordinates(point)
end
end
end
+
View
10 lib/geocoder/configuration.rb
@@ -28,8 +28,8 @@ module Geocoder
# config.always_raise = []
#
# # Calculation options
- # @units = :km # :km for kilometers or :mi for miles
- # @method = :spherical # :spherical or :linear
+ # @units = :mi # :km for kilometers or :mi for miles
+ # @method = :linear # :spherical or :linear
# end
#
# @example Using +Geocoder::Configuration+ class directly, like in:
@@ -73,8 +73,10 @@ def set_defaults
@always_raise = []
# Calculation options
- @units = :km # Internationl System standard unit for distance
- @method = :spherical # More precise
+ @units = :mi # :mi or :km - Wouldn't it be better to better change this
+ # definitions to use the International Units System
+ # (:km by default)?
+ @method = :linear # :linear or spherical
end
# Delegates getters and setters for all configuration settings,
View
9 lib/geocoder/models/active_record.rb
@@ -14,7 +14,9 @@ def geocoded_by(address_attr, options = {}, &block)
:user_address => address_attr,
:latitude => options[:latitude] || :latitude,
:longitude => options[:longitude] || :longitude,
- :geocode_block => block
+ :geocode_block => block,
+ :units => options[:units],
+ :method => options[:method]
)
end
@@ -27,7 +29,9 @@ def reverse_geocoded_by(latitude_attr, longitude_attr, options = {}, &block)
:fetched_address => options[:address] || :address,
:latitude => latitude_attr,
:longitude => longitude_attr,
- :reverse_block => block
+ :reverse_block => block,
+ :units => options[:units],
+ :method => options[:method]
)
end
@@ -39,3 +43,4 @@ def geocoder_module_name; "ActiveRecord"; end
end
end
end
+
View
6 lib/geocoder/models/base.rb
@@ -12,7 +12,9 @@ def geocoder_options
if defined?(@geocoder_options)
@geocoder_options
elsif superclass.respond_to?(:geocoder_options)
- superclass.geocoder_options
+ superclass.geocoder_options || { }
+ else
+ { }
end
end
@@ -24,7 +26,6 @@ def reverse_geocoded_by
fail
end
-
private # ----------------------------------------------------------------
def geocoder_init(options)
@@ -38,3 +39,4 @@ def geocoder_init(options)
end
end
end
+
View
11 lib/geocoder/models/mongo_base.rb
@@ -16,7 +16,9 @@ def geocoded_by(address_attr, options = {}, &block)
:geocode => true,
:user_address => address_attr,
:coordinates => options[:coordinates] || :coordinates,
- :geocode_block => block
+ :geocode_block => block,
+ :units => options[:units],
+ :method => options[:method]
)
end
@@ -28,15 +30,17 @@ def reverse_geocoded_by(coordinates_attr, options = {}, &block)
:reverse_geocode => true,
:fetched_address => options[:address] || :address,
:coordinates => coordinates_attr,
- :reverse_block => block
+ :reverse_block => block,
+ :units => options[:units],
+ :method => options[:method]
)
end
private # ----------------------------------------------------------------
def geocoder_init(options)
unless geocoder_initialized?
- @geocoder_options = {}
+ @geocoder_options = { }
require "geocoder/stores/#{geocoder_file_name}"
include eval("Geocoder::Store::" + geocoder_module_name)
end
@@ -53,3 +57,4 @@ def geocoder_initialized?
end
end
end
+
View
32 lib/geocoder/stores/active_record.rb
@@ -51,22 +51,23 @@ module ClassMethods
##
# Get options hash suitable for passing to ActiveRecord.find to get
- # records within a radius (in miles) of the given point.
+ # records within a radius (in kilometers) of the given point.
# Options hash may include:
#
- # * +:units+ - <tt>:mi</tt> (default) or <tt>:km</tt>; to be used
+ # * +:units+ - <tt>:mi</tt> or <tt>:km</tt>; to be used.
# for interpreting radius as well as the +distance+ attribute which
- # is added to each found nearby object
- # * +:bearing+ - <tt>:linear</tt> (default) or <tt>:spherical</tt>;
+ # is added to each found nearby object.
+ # See Geocoder::Configuration to know how configure default units.
+ # * +:bearing+ - <tt>:linear</tt> or <tt>:spherical</tt>.
# the method to be used for calculating the bearing (direction)
# between the given point and each found nearby point;
- # set to false for no bearing calculation
+ # set to false for no bearing calculation.
+ # See Geocoder::Configuration to know how configure default method.
# * +:select+ - string with the SELECT SQL fragment (e.g. “id, name”)
# * +:order+ - column(s) for ORDER BY SQL clause; default is distance
# * +:exclude+ - an object to exclude (used by the +nearbys+ method)
#
def near_scope_options(latitude, longitude, radius = 20, options = {})
- radius *= Geocoder::Calculations.km_in_mi if options[:units] == :km
if connection.adapter_name.match /sqlite/i
approx_near_scope_options(latitude, longitude, radius, options)
else
@@ -88,7 +89,9 @@ def near_scope_options(latitude, longitude, radius = 20, options = {})
def full_near_scope_options(latitude, longitude, radius, options)
lat_attr = geocoder_options[:latitude]
lon_attr = geocoder_options[:longitude]
- options[:bearing] = :linear unless options.include?(:bearing)
+ options[:bearing] ||= (options[:method] ||
+ geocoder_options[:method] ||
+ Geocoder::Configuration.method)
bearing = case options[:bearing]
when :linear
"CAST(" +
@@ -110,7 +113,8 @@ def full_near_scope_options(latitude, longitude, radius, options)
")) + 360 " +
"AS decimal) % 360"
end
- earth = Geocoder::Calculations.earth_radius(options[:units] || :mi)
+ options[:units] ||= (geocoder_options[:units] || Geocoder::Configuration.units)
+ earth = Geocoder::Calculations.earth_radius(options[:units])
distance = "#{earth} * 2 * ASIN(SQRT(" +
"POWER(SIN((#{latitude} - #{lat_attr}) * PI() / 180 / 2), 2) + " +
"COS(#{latitude} * PI() / 180) * COS(#{lat_attr} * PI() / 180) * " +
@@ -136,7 +140,11 @@ def full_near_scope_options(latitude, longitude, radius, options)
def approx_near_scope_options(latitude, longitude, radius, options)
lat_attr = geocoder_options[:latitude]
lon_attr = geocoder_options[:longitude]
- options[:bearing] = :linear unless options.include?(:bearing)
+ unless options.include?(:bearing)
+ options[:bearing] = (options[:method] || \
+ geocoder_options[:method] || \
+ Geocoder::Configuration.method)
+ end
if options[:bearing]
bearing = "CASE " +
"WHEN (#{lat_attr} >= #{latitude} AND #{lon_attr} >= #{longitude}) THEN 45.0 " +
@@ -148,8 +156,9 @@ def approx_near_scope_options(latitude, longitude, radius, options)
bearing = false
end
- dx = Geocoder::Calculations.longitude_degree_distance(30, options[:units] || :mi)
- dy = Geocoder::Calculations.latitude_degree_distance(options[:units] || :mi)
+ options[:units] ||= (geocoder_options[:units] || Geocoder::Configuration.units)
+ dx = Geocoder::Calculations.longitude_degree_distance(30, options[:units])
+ dy = Geocoder::Calculations.latitude_degree_distance(options[:units])
# sin of 45 degrees = average x or y component of vector
factor = Math.sin(Math::PI / 4)
@@ -222,3 +231,4 @@ def reverse_geocode
alias_method :fetch_address, :reverse_geocode
end
end
+
View
9 lib/geocoder/stores/base.rb
@@ -20,9 +20,10 @@ def to_coordinates
# Calculate the distance from the object to an arbitrary point.
# See Geocoder::Calculations.distance_between for ways of specifying
# the point. Also takes a symbol specifying the units
- # (:mi or :km; default is :mi).
+ # (:mi or :km; can be specified in Geocoder configuration).
#
- def distance_to(point, units = :mi)
+ def distance_to(point, units = nil)
+ units ||= self.class.geocoder_options[:units]
return nil unless geocoded?
Geocoder::Calculations.distance_between(
to_coordinates, point, :units => units)
@@ -36,6 +37,7 @@ def distance_to(point, units = :mi)
# ways of specifying the point.
#
def bearing_to(point, options = {})
+ options[:method] ||= self.class.geocoder_options[:method]
return nil unless geocoded?
Geocoder::Calculations.bearing_between(
to_coordinates, point, options)
@@ -47,6 +49,7 @@ def bearing_to(point, options = {})
# ways of specifying the point.
#
def bearing_from(point, options = {})
+ options[:method] ||= self.class.geocoder_options[:method]
return nil unless geocoded?
Geocoder::Calculations.bearing_between(
point, to_coordinates, options)
@@ -78,7 +81,6 @@ def reverse_geocode
fail
end
-
private # --------------------------------------------------------------
##
@@ -115,3 +117,4 @@ def do_lookup(reverse = false)
end
end
end
+
View
4 lib/geocoder/stores/mongo_base.rb
@@ -20,6 +20,7 @@ def self.included_by_model(base)
radius = args.size > 0 ? args.shift : 20
options = args.size > 0 ? args.shift : {}
+ options[:units] ||= geocoder_options[:units]
# Use BSON::OrderedHash if Ruby's hashes are unordered.
# Conditions must be in order required by indexes (see mongo gem).
@@ -30,7 +31,7 @@ def self.included_by_model(base)
conds[field] = empty.clone
conds[field]["$nearSphere"] = coords.reverse
conds[field]["$maxDistance"] = \
- Geocoder::Calculations.distance_to_radians(radius, options[:units] || :mi)
+ Geocoder::Calculations.distance_to_radians(radius, options[:units])
if obj = options[:exclude]
conds[:_id.ne] = obj.id
@@ -79,3 +80,4 @@ def reverse_geocode
end
end
end
+
View
8 test/calculations_test.rb
@@ -2,7 +2,12 @@
require 'test_helper'
class CalculationsTest < Test::Unit::TestCase
-
+ def setup
+ Geocoder.configure do
+ config.units = :mi
+ config.method = :linear
+ end
+ end
# --- degree distance ---
@@ -145,3 +150,4 @@ def test_linear_bearing_from_and_to_are_exactly_opposite
assert_equal l.bearing_from([50,-86.1]), l.bearing_to([50,-86.1]) - 180
end
end
+
View
58 test/configuration_test.rb
@@ -13,39 +13,75 @@ def test_exception_raised_on_bad_lookup_config
end
end
- # --- default configuration ---
- def test_default_units_in_kilometers
- assert_equal 111, Geocoder::Calculations.distance_between([0,0], [0,1]).round
- end
-
# --- class method configuration ---
def test_configurated_by_class_method
Geocoder::Configuration.units = :mi
distance = Geocoder::Calculations.distance_between([0,0], [0,1]).round
assert_not_equal 111, distance
- assert_equal 69, distance
+ assert_equal 69, distance
Geocoder::Configuration.units = :km
distance = Geocoder::Calculations.distance_between([0,0], [0,1]).round
- assert_equal 111, distance
+ assert_equal 111, distance
assert_not_equal 69, distance
+
+ Geocoder::Configuration.method = :spherical
+ angle = Geocoder::Calculations.bearing_between([50,-85], [40.750354, -73.993371]).round
+ assert_equal 136, angle
+ assert_not_equal 130, angle
+
+ Geocoder::Configuration.method = :linear
+ angle = Geocoder::Calculations.bearing_between([50,-85], [40.750354, -73.993371]).round
+ assert_not_equal 136, angle
+ assert_equal 130, angle
end
# --- Geocoder#configure method configuration ---
def test_geocoder_configuration
- Geocoder.configure { config.units = :mi }
+ # DSL
+ Geocoder.configure do
+ config.units = :mi
+ config.method = :linear
+ end
assert_equal Geocoder::Configuration.units, :mi
distance = Geocoder::Calculations.distance_between([0,0], [0,1]).round
assert_not_equal 111, distance
- assert_equal 69, distance
+ assert_equal 69, distance
- Geocoder.configure.units = :km
+ assert_equal Geocoder::Configuration.method, :linear
+ angle = Geocoder::Calculations.bearing_between([50,-85], [40.750354, -73.993371]).round
+ assert_not_equal 136, angle
+ assert_equal 130, angle
+
+ # Direct
+ Geocoder.configure.units = :km
+ Geocoder.configure.method = :spherical
assert_equal Geocoder::Configuration.units, :km
distance = Geocoder::Calculations.distance_between([0,0], [0,1]).round
- assert_equal 111, distance
+ assert_equal 111, distance
assert_not_equal 69, distance
+
+ assert_equal Geocoder::Configuration.method, :spherical
+ angle = Geocoder::Calculations.bearing_between([50,-85], [40.750354, -73.993371]).round
+ assert_equal 136, angle
+ assert_not_equal 130, angle
+ end
+
+ # Geocoder per-model configuration
+ def test_model_configuration
+ Landmark.reverse_geocoded_by :latitude, :longitude, :method => :spherical, :units => :km
+ assert_equal Landmark.geocoder_options[:units], :km
+ assert_equal :spherical, Landmark.geocoder_options[:method]
+
+ venue = Landmark.new(*landmark_params(:msg))
+ venue.latitude = 0
+ venue.longitude = 0
+ assert_equal 111, venue.distance_to([0,1]).round
+ venue.latitude = 40.750354
+ venue.longitude = -73.993371
+ assert_equal 136, venue.bearing_from([50,-85]).round
end
end
View
2 test/test_helper.rb
@@ -29,6 +29,7 @@ def update_attribute(attr_name, value)
def self.scope(*args); end
def method_missing(name, *args, &block)
+ puts "Nao incluiu direito no active record..." if name == "geocoder_options"
if name.to_s[-1..-1] == "="
write_attribute name.to_s[0...-1], *args
else
@@ -244,3 +245,4 @@ def street_lookups
all_lookups - [:freegeoip]
end
end
+

0 comments on commit 5c2cf49

Please sign in to comment.
Something went wrong with that request. Please try again.