Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can calculate the real distance between two points with GeoDjango?

from django.contrib.gis.geos import Point

p1 = Point(36.74851779201058, -6.429006806692149, srid=4326)
p2 = Point(37.03254161520977, -8.98366068931684, srid=4326)
p1.distance(p2)
Out: 2.5703941316759376

But what is the unit of this float number?

If you calculate this distance, this is 229.88 Km. You can get it too using geopy:

from geopy.distance import distance
distance(p1, p2)
Out: Distance(229.883275249)
distance(p1, p2).km
Out: 229.88327524944066

I have read that you can get (so so) this, if you divide the previous number for 111:

(2.5703941316759376 / 111) * 10000
Out: 231.5670388897241  # kilometers

Is there any way to get the real distance using only GeoDjango? Or should I use geopy?

like image 630
Goin Avatar asked Aug 29 '16 17:08

Goin


3 Answers

Usually, all spatial calculations yield results in the same coordinate system as the input was given. In your case you should seek a calculation using the SRID 4326 which is longitude/latitude polars in degrees from the prime meridian and equator.

Consequently, GeoDjango's distance calculation - if I get it correctly - is the Euclidean distance between the two pairs of coordinates. You are searching for the big circle distance (where your division by 111 is just a rough approximation that is only close to the actual big circle distance in certain ranges of latitude).

geopy should use the big circle distance for SRID 4326 implicitly, yielding the correct result.

You now have a few different options:

A: Implement big circle on your own

Google for haversine formula, you can punch in two pairs of lat/lon coordinates and you should get a good approximation of the actual big circle distance. However, this depends on the mercator approximation that is used -- remember that Earth is not a sphere. You may run into problems near the poles with this.

B: Transform to a metric (local) coordinate system

If you transform your two locations to another coordinate system that is measured in meters, calculating the Euclidean distance will yield the correct result. However, such coordinate systems (call them planar systems) are different for various regions on the globe. There are different projections for different countries, as the approximation of the Earth's irregularly curved surface as a plane is errorneous -- especially not uniquely errorneous for any location on its surface.

This is only applicable if all points among which you wish to calculate distances are in the same geographical region.

C: Use a library for this

Use geopy or shapely or any other qualified library that can calculate the actual big circle distance based on the SRID your points are given in. Remember that all coordinates are just approximations due to Earth's irregularity.

like image 114
jbndlr Avatar answered Nov 08 '22 20:11

jbndlr


As far as I know, GeoDjango doesn't support calculating the real distance. It just calculates the distance geometrically. Therefore, I think you should use geopy as I did in my project..

from geopy.distance import vincenty

distance = vincenty((lat1, lon1), (lat2, lon2)).kilometers

This will give the right distance as kilometers.

For further information, check the geopy documentation.

http://geopy.readthedocs.io/en/latest/

like image 41
Çağatay Barın Avatar answered Nov 08 '22 20:11

Çağatay Barın


There's a solution to this online, which explains both what GeoDjango is doing originally (a distance calculation that doesn't use any standard units, essentially), but also, how to get it into a form that returns the distance in more useful units -- the code is very similar to what you're already doing, except that it makes use of a transform on each point before retrieving the distance. The link is below, hopefully it's useful to you:

https://coderwall.com/p/k1gg1a/distance-calculation-in-geodjango

like image 1
Rob Wilkins Avatar answered Nov 08 '22 19:11

Rob Wilkins