Skip to content
Snippets Groups Projects
Commit d71d0eaf authored by Mat Ellis's avatar Mat Ellis Committed by Alex Reisner
Browse files

Add option "bearing". When set to :line or :spherical it returns the bearing...

Add option "bearing". When set to :line or :spherical it returns the bearing of the record from the search point, i.e. if the record is due north you'll see 0.0 returned. :line is a straight line, :spherical is the shortest path where the bearing between two points varies with distance to take into account curvature of the planet.
parent e64151ae
No related branches found
No related tags found
No related merge requests found
...@@ -59,6 +59,7 @@ module Geocoder::Orm ...@@ -59,6 +59,7 @@ module Geocoder::Orm
# +limit+ :: number of records to return (for LIMIT SQL clause) # +limit+ :: number of records to return (for LIMIT SQL clause)
# +offset+ :: number of records to skip (for OFFSET SQL clause) # +offset+ :: number of records to skip (for OFFSET SQL clause)
# +select+ :: string with the SELECT SQL fragment (e.g. “id, name”) # +select+ :: string with the SELECT SQL fragment (e.g. “id, name”)
# +bearing+ :: :line for straight line calcs, :sphere for spherical
# #
def near_scope_options(latitude, longitude, radius = 20, options = {}) def near_scope_options(latitude, longitude, radius = 20, options = {})
radius *= Geocoder::Calculations.km_in_mi if options[:units] == :km radius *= Geocoder::Calculations.km_in_mi if options[:units] == :km
...@@ -82,6 +83,15 @@ module Geocoder::Orm ...@@ -82,6 +83,15 @@ module Geocoder::Orm
def full_near_scope_options(latitude, longitude, radius, options) def full_near_scope_options(latitude, longitude, radius, options)
lat_attr = geocoder_options[:latitude] lat_attr = geocoder_options[:latitude]
lon_attr = geocoder_options[:longitude] lon_attr = geocoder_options[:longitude]
bearing = case options[:bearing]
# Credit for SQL query (adapted) http://www.beginningspatial.com/calculating_bearing_one_point_another
when :line
", (DEGREES(ATAN2(( longitude - #{longitude} ), ( latitude - #{latitude} )))+360) % 360 AS bearing"
when :spherical
", (DEGREES( ATAN2( SIN(RADIANS(longitude - #{longitude})) * COS(RADIANS(latitude)), ( COS(RADIANS(#{latitude})) * SIN(RADIANS(latitude)) ) - ( SIN(RADIANS(#{latitude})) * COS(RADIANS(latitude)) * COS(RADIANS(longitude - #{longitude})) ) )) + 360 ) % 360 AS bearing"
else
""
end
distance = "3956 * 2 * ASIN(SQRT(" + distance = "3956 * 2 * ASIN(SQRT(" +
"POWER(SIN((#{latitude} - #{lat_attr}) * " + "POWER(SIN((#{latitude} - #{lat_attr}) * " +
"PI() / 180 / 2), 2) + COS(#{latitude} * PI()/180) * " + "PI() / 180 / 2), 2) + COS(#{latitude} * PI()/180) * " +
...@@ -90,7 +100,7 @@ module Geocoder::Orm ...@@ -90,7 +100,7 @@ module Geocoder::Orm
"PI() / 180 / 2), 2) ))" "PI() / 180 / 2), 2) ))"
options[:order] ||= "#{distance} ASC" options[:order] ||= "#{distance} ASC"
default_near_scope_options(latitude, longitude, radius, options).merge( default_near_scope_options(latitude, longitude, radius, options).merge(
:select => "#{options[:select] || '*'}, #{distance} AS distance", :select => "#{options[:select] || '*'}, #{distance} AS distance#{bearing}",
:having => "#{distance} <= #{radius}" :having => "#{distance} <= #{radius}"
) )
end end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment