Reputation: 1834
Given the problem that you have 2000 lat / lngs that need to calculate their distance to another 2000 lat / lngs in pairs. i.e. 1 to 1. What would be the fastest way to get this done in ruby.
Could a C extension be quicker? or java. At the moment I am using the GeoKit gem and it is a little slow for so many points.
EDIT 1:
The time is over 30 seconds at the moment.
Upvotes: 1
Views: 128
Reputation: 864
If you're using PostgreSQL as your database you could have a look at http://postgis.refractions.net/
It would require reloading the Lat/Lng points back into a database table with PostGIS point datatypes, but as a bonus the database should now be able to handle shapefiles for things like borders and boundaries.
SQL Function to find distance between two geoms
http://postgis.refractions.net/documentation/manual-1.5/ST_Distance.html
Installation
http://postgis.refractions.net/documentation/manual-1.5/ch02.html
EDIT:
If these are only stored in memory I suppose you could use something like spawn (or roll your own version) https://github.com/tra/spawn, https://github.com/rfc2822/spawn to split the calculations up into groups. Since it sounds like the distance calculations are just between matched pairs it should be pretty straight-forward to merge the results back together at the end (as Karel suggests).
You could stream the results back to the client as they are finished (if they don't need to be ordered - although the final ordering could be done client side when the final results are recieved).
Upvotes: 0
Reputation: 31428
How do you use GeoKit? On my machine it takes 0.016s to calculate the distance between 2000 points.
require 'benchmark'
require 'geokit'
ll_arr = 2000.times.map {|i|
[Geokit::LatLng.new(rand(-180..180), rand(-180...180)),
Geokit::LatLng.new(rand(-180..180), rand(-180...180))]}
distances = []
Benchmark.bm do |x|
x.report do
ll_arr.each do |ll|
distances << ll[0].distance_from(ll[1], :units=>:kms)
end
end
end
10.times do |n|
m = n * 200
puts "ll #{m} from: #{ll_arr[m][0]} to: #{ll_arr[m][1]} distance: #{distances[m]}"
end
Outputs:
user system total real
0.016000 0.000000 0.016000 ( 0.015624)
And the results seems reasonable (in kilometers):
ll 0 from: -180,71 to: 111,164 distance: 10136.21791028502
ll 200 from: 40,-127 to: -62,-23 distance: 14567.00843599676
ll 400 from: 23,-178 to: -163,-140 distance: 16014.598170496456
ll 600 from: 85,155 to: 25,3 distance: 7727.840511097989
ll 800 from: -26,57 to: 145,-36 distance: 11384.743155770688
ll 1000 from: -111,-137 to: 5,-5 distance: 9007.969496928148
ll 1200 from: 118,-98 to: -153,179 distance: 12295.886774709148
ll 1400 from: 44,-139 to: -91,-134 distance: 15024.485920445308
ll 1600 from: 48,126 to: -37,-92 distance: 16724.015574628884
ll 1800 from: -174,-77 to: -69,75 distance: 7306.820947156828
Upvotes: 1