Kaydet (Commit) 38a6df55 authored tarafından Sergey Fedoseev's avatar Sergey Fedoseev Kaydeden (comit) Tim Graham

Fixed #27602 -- Added Oracle support for BoundingCircle GIS function.

üst 5a23cc00
......@@ -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):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment