Fixed #27602 -- Added Oracle support for BoundingCircle GIS function.
This commit is contained in:
parent
5a23cc00f5
commit
38a6df555f
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
-------------------
|
||||
|
|
|
@ -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``
|
||||
============
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue