summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Fedoseev <fedoseev.sergey@gmail.com>2016-12-14 15:44:23 +0500
committerTim Graham <timograham@gmail.com>2016-12-15 14:16:09 -0500
commit38a6df555f285cc4f1732467c4cf0617a2050124 (patch)
treeac8351bf7c2a57d51688140fea5e14cc3ba596a2
parent5a23cc00f535a045db6d9c04c3c14594ee23fbec (diff)
Fixed #27602 -- Added Oracle support for BoundingCircle GIS function.
-rw-r--r--django/contrib/gis/db/backends/oracle/operations.py16
-rw-r--r--django/contrib/gis/db/models/functions.py7
-rw-r--r--docs/ref/contrib/gis/db-api.txt60
-rw-r--r--docs/ref/contrib/gis/functions.txt9
-rw-r--r--docs/releases/1.11.txt1
-rw-r--r--tests/gis_tests/geoapp/test_functions.py30
6 files changed, 73 insertions, 50 deletions
diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py
index 0680a8d0af..013ffa74f6 100644
--- a/django/contrib/gis/db/backends/oracle/operations.py
+++ b/django/contrib/gis/db/backends/oracle/operations.py
@@ -18,6 +18,7 @@ from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Distance
from django.db.backends.oracle.operations import DatabaseOperations
from django.utils import six
+from django.utils.functional import cached_property
DEFAULT_TOLERANCE = '0.05'
@@ -85,6 +86,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
function_names = {
'Area': 'SDO_GEOM.SDO_AREA',
+ 'BoundingCircle': 'SDO_GEOM.SDO_MBC',
'Centroid': 'SDO_GEOM.SDO_CENTROID',
'Difference': 'SDO_GEOM.SDO_DIFFERENCE',
'Distance': 'SDO_GEOM.SDO_DISTANCE',
@@ -131,11 +133,15 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
truncate_params = {'relate': None}
- unsupported_functions = {
- 'AsGeoJSON', 'AsKML', 'AsSVG', 'BoundingCircle', 'Envelope',
- 'ForceRHR', 'GeoHash', 'MakeValid', 'MemSize', 'Scale',
- 'SnapToGrid', 'Translate',
- }
+ @cached_property
+ def unsupported_functions(self):
+ unsupported = {
+ 'AsGeoJSON', 'AsKML', 'AsSVG', 'Envelope', 'ForceRHR', 'GeoHash',
+ 'MakeValid', 'MemSize', 'Scale', 'SnapToGrid', 'Translate',
+ }
+ if self.connection.oracle_full_version < '12.1.0.2':
+ unsupported.add('BoundingCircle')
+ return unsupported
def geo_quote_name(self, name):
return super(OracleOperations, self).geo_quote_name(name).upper()
diff --git a/django/contrib/gis/db/models/functions.py b/django/contrib/gis/db/models/functions.py
index b404397f95..dea042493a 100644
--- a/django/contrib/gis/db/models/functions.py
+++ b/django/contrib/gis/db/models/functions.py
@@ -201,10 +201,15 @@ class AsSVG(GeoFunc):
super(AsSVG, self).__init__(*expressions, **extra)
-class BoundingCircle(GeoFunc):
+class BoundingCircle(OracleToleranceMixin, GeoFunc):
def __init__(self, expression, num_seg=48, **extra):
super(BoundingCircle, self).__init__(*[expression, num_seg], **extra)
+ def as_oracle(self, compiler, connection):
+ clone = self.copy()
+ clone.set_source_expressions([self.get_source_expressions()[0]])
+ return super(BoundingCircle, clone).as_oracle(compiler, connection)
+
class Centroid(OracleToleranceMixin, GeoFunc):
arity = 1
diff --git a/docs/ref/contrib/gis/db-api.txt b/docs/ref/contrib/gis/db-api.txt
index 670b23cd78..2ed758db28 100644
--- a/docs/ref/contrib/gis/db-api.txt
+++ b/docs/ref/contrib/gis/db-api.txt
@@ -374,38 +374,38 @@ Database functions
The following table provides a summary of what geography-specific database
functions are available on each spatial backend.
-==================================== ======= ====== =========== ==========
-Function PostGIS Oracle MySQL SpatiaLite
-==================================== ======= ====== =========== ==========
-:class:`Area` X X X X
-:class:`AsGeoJSON` X X
-:class:`AsGML` X X X
-:class:`AsKML` X X
-:class:`AsSVG` X X
-:class:`BoundingCircle` X
-:class:`Centroid` X X X X
-:class:`Difference` X X X (≥ 5.6.1) X
-:class:`Distance` X X X (≥ 5.6.1) X
-:class:`Envelope` X X X
+==================================== ======= ============== =========== ==========
+Function PostGIS Oracle MySQL SpatiaLite
+==================================== ======= ============== =========== ==========
+:class:`Area` X X X X
+:class:`AsGeoJSON` X X
+:class:`AsGML` X X X
+:class:`AsKML` X X
+:class:`AsSVG` X X
+:class:`BoundingCircle` X X (≥ 12.1.0.2)
+:class:`Centroid` X X X X
+:class:`Difference` X X X (≥ 5.6.1) X
+:class:`Distance` X X X (≥ 5.6.1) X
+:class:`Envelope` X X X
:class:`ForceRHR` X
-:class:`GeoHash` X X (LWGEOM)
-:class:`Intersection` X X X (≥ 5.6.1) X
-:class:`IsValid` X X X (LWGEOM)
-:class:`Length` X X X X
-:class:`MakeValid` X X (LWGEOM)
+:class:`GeoHash` X X (LWGEOM)
+:class:`Intersection` X X X (≥ 5.6.1) X
+:class:`IsValid` X X X (LWGEOM)
+:class:`Length` X X X X
+:class:`MakeValid` X X (LWGEOM)
:class:`MemSize` X
-:class:`NumGeometries` X X X X
-:class:`NumPoints` X X X X
-:class:`Perimeter` X X X
-:class:`PointOnSurface` X X X
-:class:`Reverse` X X X
-:class:`Scale` X X
-:class:`SnapToGrid` X X
-:class:`SymDifference` X X X (≥ 5.6.1) X
-:class:`Transform` X X X
-:class:`Translate` X X
-:class:`Union` X X X (≥ 5.6.1) X
-==================================== ======= ====== =========== ==========
+:class:`NumGeometries` X X X X
+:class:`NumPoints` X X X X
+:class:`Perimeter` X X X
+:class:`PointOnSurface` X X X
+:class:`Reverse` X X X
+:class:`Scale` X X
+:class:`SnapToGrid` X X
+:class:`SymDifference` X X X (≥ 5.6.1) X
+:class:`Transform` X X X
+:class:`Translate` X X
+:class:`Union` X X X (≥ 5.6.1) X
+==================================== ======= ============== =========== ==========
Aggregate Functions
-------------------
diff --git a/docs/ref/contrib/gis/functions.txt b/docs/ref/contrib/gis/functions.txt
index 3a731c96f9..2917a658af 100644
--- a/docs/ref/contrib/gis/functions.txt
+++ b/docs/ref/contrib/gis/functions.txt
@@ -165,11 +165,18 @@ __ http://www.w3.org/Graphics/SVG/
.. class:: BoundingCircle(expression, num_seg=48, **extra)
-*Availability*: `PostGIS <http://postgis.net/docs/ST_MinimumBoundingCircle.html>`__
+*Availability*: `PostGIS <http://postgis.net/docs/ST_MinimumBoundingCircle.html>`__,
+`Oracle (≥ 12.1.0.2) <https://docs.oracle.com/database/121/SPATL/GUID-82A61626-BB64-4793-B53D-A0DBEC91831A.htm#SPATL1554>`_
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:: 1.11
+
+ Oracle support was added.
+
``Centroid``
============
diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt
index 40467eca88..4eea7f0df8 100644
--- a/docs/releases/1.11.txt
+++ b/docs/releases/1.11.txt
@@ -165,6 +165,7 @@ Minor features
* Added Oracle support for the
:class:`~django.contrib.gis.db.models.functions.AsGML` function,
+ :class:`~django.contrib.gis.db.models.functions.BoundingCircle` function,
:class:`~django.contrib.gis.db.models.functions.IsValid` function, and
:lookup:`isvalid` lookup.
diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py
index 7b6281a4b9..023a6a087f 100644
--- a/tests/gis_tests/geoapp/test_functions.py
+++ b/tests/gis_tests/geoapp/test_functions.py
@@ -11,7 +11,7 @@ from django.db.models import Sum
from django.test import TestCase, skipUnlessDBFeature
from django.utils import six
-from ..utils import mysql, oracle, spatialite
+from ..utils import mysql, oracle, postgis, spatialite
from .models import City, Country, CountryWebMercator, State, Track
@@ -148,21 +148,25 @@ class GISFunctionsTests(TestCase):
# num_seg is the number of segments per quarter circle.
return (4 * num_seg) + 1
- # The weak precision in the assertions is because the BoundingCircle
- # calculation changed on PostGIS 2.3.
+ expected_areas = (169, 136) if postgis else (171, 126)
qs = Country.objects.annotate(circle=functions.BoundingCircle('mpoly')).order_by('name')
- self.assertAlmostEqual(qs[0].circle.area, 169, 0)
- self.assertAlmostEqual(qs[1].circle.area, 136, 0)
- # By default num_seg=48.
- self.assertEqual(qs[0].circle.num_points, circle_num_points(48))
- self.assertEqual(qs[1].circle.num_points, circle_num_points(48))
+ self.assertAlmostEqual(qs[0].circle.area, expected_areas[0], 0)
+ self.assertAlmostEqual(qs[1].circle.area, expected_areas[1], 0)
+ if postgis:
+ # By default num_seg=48.
+ self.assertEqual(qs[0].circle.num_points, circle_num_points(48))
+ self.assertEqual(qs[1].circle.num_points, circle_num_points(48))
qs = Country.objects.annotate(circle=functions.BoundingCircle('mpoly', num_seg=12)).order_by('name')
- self.assertGreater(qs[0].circle.area, 168.4, 0)
- self.assertLess(qs[0].circle.area, 169.5, 0)
- self.assertAlmostEqual(qs[1].circle.area, 136, 0)
- self.assertEqual(qs[0].circle.num_points, circle_num_points(12))
- self.assertEqual(qs[1].circle.num_points, circle_num_points(12))
+ if postgis:
+ self.assertGreater(qs[0].circle.area, 168.4, 0)
+ self.assertLess(qs[0].circle.area, 169.5, 0)
+ self.assertAlmostEqual(qs[1].circle.area, 136, 0)
+ self.assertEqual(qs[0].circle.num_points, circle_num_points(12))
+ self.assertEqual(qs[1].circle.num_points, circle_num_points(12))
+ else:
+ self.assertAlmostEqual(qs[0].circle.area, expected_areas[0], 0)
+ self.assertAlmostEqual(qs[1].circle.area, expected_areas[1], 0)
@skipUnlessDBFeature("has_Centroid_function")
def test_centroid(self):