Last active
September 26, 2016 16:10
-
-
Save kany/e3d0f3c137747a7dfb42f8c17c783ddf to your computer and use it in GitHub Desktop.
Use raw sql to calculate distance between latitude/longitude coordinates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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