4

I have a django based web app which stores locations.

I have an android mobile app which pulls the locations from the web app and saves locations to the web app. The locations returned back to me I load on a mapoverlay in my app.

I would like to send my current coordinates and return a list of locations which are within a certain range. For example I send my location and get back items within a radius of 2km. (Similar to how the Google Places API works, just searching my data).

It is probably best to send the location coordinates and do all this logic in my python django app, Then return a list of correct locations and just display the places on my map.

I don't know where to begin doing this. How can I filter out my stored locations within certain radius(km) based off a given set of coordinates?

darren
  • 18,845
  • 17
  • 60
  • 79
  • Post your model,need to understand how your table structure looks like. – Vivek S Jun 05 '12 at 10:08
  • 1
    1) select all the locations that are near your current location (say, within the same lat/long lines). 2) use the distance calculation for each of the selected coordinates and eliminate the ones that are > desired range (2km). In case you forgot distance is `sqrt(dx**2+dy**2)` – Joel Cornett Jun 05 '12 at 10:10

4 Answers4

13

Haversine Equation is the answer to your question. However it is slightly difficult to decrypt so here I provide you with a simple explanation:

To put it simply:

Here's the sample/example SQL statement that will find the closest 20 locations that are within a radius of 25 miles to the 37, -122 coordinate. It calculates the distance based on the latitude/longitude of that row and the target latitude/longitude (given by lat/lng in the equation below), and then asks for only rows where the distance value is less than 25, orders the whole query by distance, and limits it to 20 results. To search by kilometers instead of miles, replace 3959 with 6371.

SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;

You can convert the sql to anything you desire. I mean the principle remains the same.

Yavar
  • 11,883
  • 5
  • 32
  • 63
  • 1
    thanks. edited it slightly for postgresql `SELECT distance FROM (SELECT ( 6371 * acos( cos( radians(45) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(10) ) + sin( radians(45) ) * sin( radians( latitude ) ) ) ) AS distance FROM spots_spot ) sub GROUP BY sub.distance HAVING sub.distance < 2` and here is a python class [Haversine](http://www.platoscave.net/blog/2009/oct/5/calculate-distance-latitude-longitude-python/) – darren Jun 06 '12 at 09:00
1

Simplest approach is to calculate distance to the every location and pick points within certain distance. If you want to do search faster, you could organize your locations in more sophisticated data structure (for example kd-tree).

cval
  • 6,609
  • 2
  • 17
  • 14
1

GeoDjango integrates with the excellent PostGIS add on for Postgres which provides you all these distance lookups for free.

If you have LatLong stored within the model that is stored as a Postgres type, you can run a trivial ORM query to get all the locations within the certain distance to the current LatLong.

GeoDjango is very powerful and has a lot of options and if all you ever have to do is just find the locations from the list that are within a given distance, you might just use the simple math: distance = sqrt(dx^2 + dy^2)

lprsd
  • 84,407
  • 47
  • 135
  • 168
0

I am currently working on this feature on an android app, I came across this, hope this helps. I was at first going to filter out the JSON result from the server then I came to this and realized Mysql is far more sophisticated than I initially perceived it.

https://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL

The comment above wasn't working for me but they are on the money with going with Haversine Equation. Its far more efficient to do most of this on the server side so the phone doesn't get overwhelm with information that won't be used for anything. That's like baking a full blown 10inch cake only to slice an 8th of it and throw the rest away, why not just bake a tiny cake with a radius of 2inches? May not seem like it makes a big different but like any good program, only get what you need unless you need all of it.

to use a live working version run small test on your own code use this link below. http://sqlfiddle.com/#!2/abba1/2

Hope this post helps.