Skip to content

Instantly share code, notes, and snippets.

@kany
Last active September 26, 2016 16:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kany/e3d0f3c137747a7dfb42f8c17c783ddf to your computer and use it in GitHub Desktop.
Save kany/e3d0f3c137747a7dfb42f8c17c783ddf to your computer and use it in GitHub Desktop.
Use raw sql to calculate distance between latitude/longitude coordinates
# Use raw sql to calculate distance between latitude/longitude coordinates
# From the web
# - http://gis.stackexchange.com/questions/31628/find-points-within-a-distance-using-mysql
"SELECT
id, (
3959 * acos (
cos ( radians(78.3232) )
* cos( radians( lat ) )
* cos( radians( lng ) - radians(65.3234) )
+ sin ( radians(78.3232) )
* sin( radians( lat ) )
)
) AS distance
FROM markers
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 20;"
# Example usage in ActiveRecord Model
# ActiveRecord::Base.connection.quote to prevent SQL injections
class Market < ActiveRecord::Base
scope :nearest_to, lambda { |latitude, longitude|
select("markets.*,
(3963.19 * acos (
cos ( radians( #{ActiveRecord::Base.connection.quote(latitude)} ) )
* cos( radians( lat ) )
* cos( radians( lng ) - radians( #{ActiveRecord::Base.connection.quote(longitude)} ) )
+ sin ( radians( #{ActiveRecord::Base.connection.quote(latitude)} ) )
* sin( radians( lat ) )
)) AS distance").
order(:distance).having("distance < range_in_miles") }
def find_market
Market.nearest_to(latitude, longitude).first
end
end
# Comparison of Raw SQL vs Geokit
# Raw SQL
[1] pry(#<Property>)> Market.with_distance(latitude, longitude).collect(&:distance).sort
=> [0.0,
184.9088153239107,
945.0517878990462,
1099.1091011031144,
1099.1091011031144,
2231.5771018419705,
2552.9080305439775,
2569.7314203097667,
8885.790207134487]
# GeoKit
[3] pry(#<Property>)> Market.by_distance(:origin => [latitude, longitude]).collect { |m| m.distance_to(self) }
=> [0.0,
184.9088153239107,
945.0517878990462,
1099.1091011031126,
1099.1091011031126,
2231.5771018419714,
2552.9080305439775,
2569.7314203097667,
8885.790207134487]
# Benchmarks
[2] pry(#<Property>)> Benchmark.measure{ Market.with_distance(latitude, longitude).collect(&:distance).sort }
=> 0.000000 0.000000 0.000000 ( 0.001536)
[3] pry(#<Property>)> Benchmark.measure{ Market.by_distance(:origin => [latitude, longitude]).collect { |m| m.distance_to(self) } }
=> 0.000000 0.000000 0.000000 ( 0.002511)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment