Why do the Centroid function and centroid method return (slightly) different results
I have a GeoDjango (v5.2) model ("Location") with a MultiPolygonField ("coordinates") and use PostGIS (v17-3.5) as database backend. When I annotate a queryset with the multi-polygon's centroid, I get slightly different results compared to the centroid method of a single instance. They only seem to be rounding errors, but given the names of function and method, I was expecting the same results.
from django.contrib.gis.db import models
from django.contrib.gis.db.models.functions import Centroid
class Location(models.Model):
coordinates = models.MultiPolygonField(
unique=True,
srid=DATABASE_SRID,
dim=2,
geography=True,
)
...
# Get an arbitrary location that is centered at (20°N, 20°E).
foo = Location.objects.get(pk=1)
bar = Location.objects.filter(pk=1).annotate(center=Centroid("coordinates"))
print(foo.coordinates.centroid.coords)
# > (21.99999999999877, 22.0000000000065)
print(bar.first().center.centroid.coords)
# > (22.000000000008804, 21.999999999992266)
My understanding is that when you annotate a queryset, Django uses functions provided by your database - https://docs.djangoproject.com/en/5.2/ref/contrib/gis/functions/
However, if you interact with a spatial Model attribute, the processing is handled by GEOS - https://docs.djangoproject.com/en/5.2/ref/contrib/gis/geos/
That means your "foo" example is using GEOS.
Your "bar" example is using the database (the annotation) to create a centroid named "center", but you are then using GEOS to request the centroid property of that in the print statement. Not sure if this duplication would be having any effect.
bar = Location.objects.filter(pk=1).annotate(center=Centroid("coordinates"))
print(bar.first().center.centroid.coords)