GeoDjango: distance calculation

304 views
Skip to first unread message

kmishler

unread,
Jan 17, 2008, 2:18:41 PM1/17/08
to Django users
We are starting to use geodjango (revision 7003) and are having
problems using the api to calculate distance.

class Airport(models.Model):
icao = models.CharField('ICAO', max_length=4)
location = models.PointField()

The location field will eventually be populated using lat/longs from a
text file.

For now, I populated 3 records in the table:

Airport.objects.create(icao="KBWI",
location=fromstr('POINT(-76.668333333333337 39.175361111111108)',
srid=4326))
Airport.objects.create(icao="KDEN",
location=fromstr('POINT(-104.67317777777778 39.861655555555558)',
srid=4326))
Airport.objects.create(icao="EGLL",
location=fromstr('POINT(-0.4613888888888889 51.477499999999999)',
srid=4326))

When I try to use the api to get distance, I do not get the correct
results:

point = Airport.objects.get(icao="KBWI").location
for airport in Airport.objects.distance(point):
print airport.icao + ": " + str(airport.distance) + ", " +
str(Distance(degree=airport.distance).nm)

EGLL: 77.1935295397, 0.000727473678024
KBWI: 0.0, 0.0
KDEN: 28.0132524428, 0.000263997564426

select icao, ST_distance(ST_GeomFromText('POINT(-76.668333333333337
39.175361111111108)',4326), location) from common_airport;
icao | st_distance
------+------------------
KBWI | 0
KDEN | 28.0132524427637
EGLL | 77.1935295397234


select icao,
distance_sphere(ST_GeomFromText('POINT(-76.668333333333337
39.175361111111108)',4326), location) from common_airport;
icao | distance_sphere converting manually to nm
------+----------------------
KDEN | 2393555.0105449 1292.41631
KBWI | 2.81660258041303e-10 0
EGLL | 5833168.46744864 3149.65875


Using distance_sphere, I get the correct results. Is there any way to
use the django api to get distance_sphere?

I also tried using the SRID 32140:

class Airport(models.Model):
icao = models.CharField('ICAO', max_length=4)
location = models.PointField(32140)

I used the same code to populate the records - it's nice that
geodjango can do that.

When I try to use the api to get distance, I get closer results, but
they're still not correct:

point = Airport.objects.get(icao="KBWI").location
for airport in Airport.objects.distance(point):
print airport.icao + ": " + str(airport.distance) + ", " +
str(Distance(meter=airport.distance).nm)

EGLL: 6258767.81814, 3379.46426466
KBWI: 0.0, 0.0
KDEN: 2442966.58517, 1319.09642828

Is there any way to use the django api to get the distance?


Versions:
WhiteBox Enterprise Linux 3.0 (clone of Red Hat enterprise 3.0)
gcc 3.2.3 / glibc 3.2.3
Python 2.4.2
ctypes 1.0.2
PostgreSQL 8.2.4
postgis 1.3.2
geos 3.0.0
proj4 4.6.0
curl 7.17.1 (needed for gdal)
expat 2.0.1 (needed for gdal)
gdal 1.5.0

Justin Bronn

unread,
Jan 18, 2008, 1:01:22 PM1/18/08
to Django users
> We are starting to usegeodjango(revision 7003) and are having
> problems using the api to calculate distance.
>
> class Airport(models.Model):
> icao = models.CharField('ICAO', max_length=4)
> location = models.PointField()
>

First, a reminder to add the `objects.GeoManager()` to your models --
it appears that you just omitted it in this post (or else you would
have received errors).

> Using distance_sphere, I get the correct results. Is there any way to
> use the django api to get distance_sphere?

I just clarified this in the documentation - the current distance API
currently works only with projected coordinate systems. Geodetic
systems, such as WGS84 (the default), will just use the degree
conversion factor, thus producing inaccurate results. I know of
`distance_sphere`, however, it only supports calculation between
points in PostGIS. Thus, geodetic support was purposely delayed until
I could come up with a better solution.

> I also tried using the SRID 32140 ...
> When I try to use the api to get distance, I get closer results, but
> they're still not correct:

SRID 32140 is "NAD83 / Texas South Central", thus I would not be
surprised if you obtained invalid results when using it for geographic
data that is outside it's bounds (e.g., KDEN, or Denver International
Airport, is a long way from South Texas). See http://www.spatialreference.org/ref/epsg/32140/.

One option is to use custom SQL to perform the calculations using
`distance_sphere` -- a patch adding such support would be even better
(I created ticket #6414 for this purpose). An interim measure would
be to just support such calculations for PointFields, which would
requiring some hacking on the `PostGISDistance` SQL construction
object in django/contrib/gis/db/backends/postgis/query.py

Best Regards,
-Justin

kmishler

unread,
Feb 27, 2008, 5:32:47 PM2/27/08
to Django users
Justin: Thank you very much for fixing ticket #6414. We are starting
to use the API and it works.

Would it be possible to change the distance calculations to use
distance_sphere instead of distance_spheroid? Or have an option to be
able to use either one? For some of our calculations, it is much too
slow to use distance_spheroid - the slight loss in accuracy is worth
the enormous gain in speed.

Karen

Justin Bronn

unread,
Mar 4, 2008, 11:55:46 AM3/4/08
to Django users
> For some of our calculations, it is much too slow to use distance_spheroid -
> the slight loss in accuracy is worth the enormous gain in speed.

I did some performance tests and confirmed your findings. I've
created a ticket that includes a patch that changes the default
geodetic distance calculation to use `ST_distance_sphere` instead:

http://code.djangoproject.com/ticket/6715

My informal tests indicate that calculations are 30-40% faster, with a
maximum of 0.25% loss in accuracy. I haven't committed yet because I
wanted to solicit comments on the API that enables spheroid
calculations.

-Justin
Reply all
Reply to author
Forward
0 new messages