From 45f59d0eab56629f88826117e911af05bd55d2c3 Mon Sep 17 00:00:00 2001 From: David Smith <39445562+smithdc1@users.noreply.github.com> Date: Thu, 4 Jan 2024 20:50:14 +0000 Subject: [PATCH] Fixed #35086 -- Added support for BoundedCircle on Spatialite 5.1+. Spatialite 5.1 added support for BoundingCircle (GEOSMinimumBoundingCircle). GEOS 3.7 is required which is lower than Django's currently supported minmum of 3.8. https://groups.google.com/g/spatialite-users/c/hAJ2SgitN4M https://www.gaia-gis.it/gaia-sins/spatialite-sql-5.1.0.html --- django/contrib/gis/db/backends/spatialite/operations.py | 5 ++++- django/contrib/gis/db/models/functions.py | 7 +++++++ docs/ref/contrib/gis/db-api.txt | 2 +- docs/ref/contrib/gis/functions.txt | 7 ++++++- docs/releases/5.1.txt | 3 ++- tests/gis_tests/geoapp/test_functions.py | 7 ++++++- 6 files changed, 26 insertions(+), 5 deletions(-) diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py index 0b8b26ab6f8b..8a3d84b5de62 100644 --- a/django/contrib/gis/db/backends/spatialite/operations.py +++ b/django/contrib/gis/db/backends/spatialite/operations.py @@ -66,6 +66,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations): function_names = { "AsWKB": "St_AsBinary", + "BoundingCircle": "GEOSMinimumBoundingCircle", "ForcePolygonCW": "ST_ForceLHR", "FromWKB": "ST_GeomFromWKB", "FromWKT": "ST_GeomFromText", @@ -80,9 +81,11 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations): @cached_property def unsupported_functions(self): - unsupported = {"BoundingCircle", "GeometryDistance", "IsEmpty", "MemSize"} + unsupported = {"GeometryDistance", "IsEmpty", "MemSize"} if not self.geom_lib_version(): unsupported |= {"Azimuth", "GeoHash", "MakeValid"} + if self.spatial_version < (5, 1): + unsupported |= {"BoundingCircle"} return unsupported @cached_property diff --git a/django/contrib/gis/db/models/functions.py b/django/contrib/gis/db/models/functions.py index bd02e3717d85..419b64c5e8e6 100644 --- a/django/contrib/gis/db/models/functions.py +++ b/django/contrib/gis/db/models/functions.py @@ -274,6 +274,13 @@ def as_oracle(self, compiler, connection, **extra_context): compiler, connection, **extra_context ) + def as_sqlite(self, compiler, connection, **extra_context): + clone = self.copy() + clone.set_source_expressions([self.get_source_expressions()[0]]) + return super(BoundingCircle, clone).as_sqlite( + compiler, connection, **extra_context + ) + class Centroid(OracleToleranceMixin, GeomOutputGeoFunc): arity = 1 diff --git a/docs/ref/contrib/gis/db-api.txt b/docs/ref/contrib/gis/db-api.txt index df1d3847e60c..f2dd1c7bf433 100644 --- a/docs/ref/contrib/gis/db-api.txt +++ b/docs/ref/contrib/gis/db-api.txt @@ -397,7 +397,7 @@ Function PostGIS Oracle MariaDB MySQL :class:`AsWKB` X X X X X :class:`AsWKT` X X X X X :class:`Azimuth` X X (LWGEOM/RTTOPO) -:class:`BoundingCircle` X X +:class:`BoundingCircle` X X X (≥ 5.1) :class:`Centroid` X X X X X :class:`ClosestPoint` X X :class:`Difference` X X X X X diff --git a/docs/ref/contrib/gis/functions.txt b/docs/ref/contrib/gis/functions.txt index 36ef651cfe72..f55d314b3f85 100644 --- a/docs/ref/contrib/gis/functions.txt +++ b/docs/ref/contrib/gis/functions.txt @@ -230,13 +230,18 @@ south = ``π``; west = ``3π/2``. *Availability*: `PostGIS `__, `Oracle `_ +SDO_GEOM-reference.html#GUID-82A61626-BB64-4793-B53D-A0DBEC91831A>`_, +SpatiaLite 5.1+ Accepts a single geographic field or expression and returns the smallest circle polygon that can fully contain the geometry. The ``num_seg`` parameter is used only on PostGIS. +.. versionchanged:: 5.1 + + SpatiaLite 5.1+ support was added. + ``Centroid`` ============ diff --git a/docs/releases/5.1.txt b/docs/releases/5.1.txt index 544b1f5d0855..03ca07f298d2 100644 --- a/docs/releases/5.1.txt +++ b/docs/releases/5.1.txt @@ -53,7 +53,8 @@ Minor features :mod:`django.contrib.gis` ~~~~~~~~~~~~~~~~~~~~~~~~~ -* ... +* :class:`~django.contrib.gis.db.models.functions.BoundingCircle` is now + supported on SpatiaLite 5.1+. :mod:`django.contrib.messages` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py index 047c7f903602..9edadc48c21e 100644 --- a/tests/gis_tests/geoapp/test_functions.py +++ b/tests/gis_tests/geoapp/test_functions.py @@ -258,7 +258,12 @@ def circle_num_points(num_seg): # num_seg is the number of segments per quarter circle. return (4 * num_seg) + 1 - expected_areas = (169, 136) if connection.ops.postgis else (171, 126) + if connection.ops.postgis: + expected_areas = (169, 136) + elif connection.ops.spatialite: + expected_areas = (168, 135) + else: # Oracle. + expected_areas = (171, 126) qs = Country.objects.annotate( circle=functions.BoundingCircle("mpoly") ).order_by("name")