Fixed #11854 -- Added Azimuth GIS function. (#8286)

This commit is contained in:
Sergey Fedoseev 2017-04-02 23:24:06 +05:00 committed by Tim Graham
parent 4f99ba84b3
commit 5e710cf4a5
9 changed files with 46 additions and 13 deletions

View File

@ -25,7 +25,7 @@ class BaseSpatialOperations:
# Blacklist/set of known unsupported functions of the backend # Blacklist/set of known unsupported functions of the backend
unsupported_functions = { unsupported_functions = {
'Area', 'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG', 'Area', 'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG', 'Azimuth',
'BoundingCircle', 'Centroid', 'Difference', 'Distance', 'Envelope', 'BoundingCircle', 'Centroid', 'Difference', 'Distance', 'Envelope',
'ForceRHR', 'GeoHash', 'Intersection', 'IsValid', 'Length', 'ForceRHR', 'GeoHash', 'Intersection', 'IsValid', 'Length',
'LineLocatePoint', 'MakeValid', 'MemSize', 'NumGeometries', 'LineLocatePoint', 'MakeValid', 'MemSize', 'NumGeometries',

View File

@ -72,7 +72,7 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
@cached_property @cached_property
def unsupported_functions(self): def unsupported_functions(self):
unsupported = { unsupported = {
'AsGML', 'AsKML', 'AsSVG', 'BoundingCircle', 'ForceRHR', 'AsGML', 'AsKML', 'AsSVG', 'Azimuth', 'BoundingCircle', 'ForceRHR',
'LineLocatePoint', 'MakeValid', 'MemSize', 'Perimeter', 'LineLocatePoint', 'MakeValid', 'MemSize', 'Perimeter',
'PointOnSurface', 'Reverse', 'Scale', 'SnapToGrid', 'Transform', 'PointOnSurface', 'Reverse', 'Scale', 'SnapToGrid', 'Transform',
'Translate', 'Translate',

View File

@ -111,9 +111,9 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
} }
unsupported_functions = { unsupported_functions = {
'AsGeoJSON', 'AsKML', 'AsSVG', 'Envelope', 'ForceRHR', 'GeoHash', 'AsGeoJSON', 'AsKML', 'AsSVG', 'Azimuth', 'Envelope', 'ForceRHR',
'LineLocatePoint', 'MakeValid', 'MemSize', 'Scale', 'SnapToGrid', 'GeoHash', 'LineLocatePoint', 'MakeValid', 'MemSize', 'Scale',
'Translate', 'SnapToGrid', 'Translate',
} }
def geo_quote_name(self, name): def geo_quote_name(self, name):

View File

@ -93,7 +93,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
def unsupported_functions(self): def unsupported_functions(self):
unsupported = {'BoundingCircle', 'ForceRHR', 'MemSize'} unsupported = {'BoundingCircle', 'ForceRHR', 'MemSize'}
if not self.lwgeom_version(): if not self.lwgeom_version():
unsupported |= {'GeoHash', 'IsValid', 'MakeValid'} unsupported |= {'Azimuth', 'GeoHash', 'IsValid', 'MakeValid'}
return unsupported return unsupported
@cached_property @cached_property

View File

@ -162,6 +162,12 @@ class Area(OracleToleranceMixin, GeoFunc):
return self.as_sql(compiler, connection, **extra_context) return self.as_sql(compiler, connection, **extra_context)
class Azimuth(GeoFunc):
output_field_class = FloatField
arity = 2
geom_param_pos = (0, 1)
class AsGeoJSON(GeoFunc): class AsGeoJSON(GeoFunc):
output_field_class = TextField output_field_class = TextField

View File

@ -376,6 +376,7 @@ Function PostGIS Oracle MySQL Spat
:class:`AsGML` X X X :class:`AsGML` X X X
:class:`AsKML` X X :class:`AsKML` X X
:class:`AsSVG` X X :class:`AsSVG` X X
:class:`Azimuth` X X (LWGEOM)
:class:`BoundingCircle` X X :class:`BoundingCircle` X X
:class:`Centroid` X X X X :class:`Centroid` X X X X
:class:`Difference` X X X (≥ 5.6.1) X :class:`Difference` X X X (≥ 5.6.1) X

View File

@ -23,11 +23,11 @@ Function's summary:
================== ======================= ====================== =================== ================== ===================== ================== ======================= ====================== =================== ================== =====================
Measurement Relationships Operations Editors Output format Miscellaneous Measurement Relationships Operations Editors Output format Miscellaneous
================== ======================= ====================== =================== ================== ===================== ================== ======================= ====================== =================== ================== =====================
:class:`Area` :class:`BoundingCircle` :class:`Difference` :class:`ForceRHR` :class:`AsGeoJSON` :class:`IsValid` :class:`Area` :class:`Azimuth` :class:`Difference` :class:`ForceRHR` :class:`AsGeoJSON` :class:`IsValid`
:class:`Distance` :class:`Centroid` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`MemSize` :class:`Distance` :class:`BoundingCircle` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`MemSize`
:class:`Length` :class:`Envelope` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`NumGeometries` :class:`Length` :class:`Centroid` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`NumGeometries`
:class:`Perimeter` :class:`PointOnSurface` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumPoints` :class:`Perimeter` :class:`Envelope` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumPoints`
.. :class:`SnapToGrid` :class:`GeoHash` .. :class:`PointOnSurface` :class:`SnapToGrid` :class:`GeoHash`
.. :class:`Transform` .. :class:`Transform`
.. :class:`Translate` .. :class:`Translate`
================== ======================= ====================== =================== ================== ===================== ================== ======================= ====================== =================== ================== =====================
@ -173,6 +173,21 @@ Keyword Argument Description
__ http://www.w3.org/Graphics/SVG/ __ http://www.w3.org/Graphics/SVG/
``Azimuth``
===========
.. class:: Azimuth(point_a, point_b, **extra)
.. versionadded:: 2.0
*Availability*: `PostGIS <https://postgis.net/docs/ST_Azimuth.html>`__,
SpatiaLite (LWGEOM)
Returns the azimuth in radians of the segment defined by the given point
geometries, or ``None`` if the two points are coincident. The azimuth is angle
referenced from north and is positive clockwise: north = ``0``; east = ``π/2``;
south = ``π``; west = ``3π/2``.
``BoundingCircle`` ``BoundingCircle``
================== ==================

View File

@ -68,8 +68,9 @@ Minor features
:class:`~django.contrib.gis.db.models.functions.IsValid` function, and :class:`~django.contrib.gis.db.models.functions.IsValid` function, and
:lookup:`isvalid` lookup. :lookup:`isvalid` lookup.
* Added the :class:`~django.contrib.gis.db.models.functions.LineLocatePoint` * Added the :class:`~django.contrib.gis.db.models.functions.Azimuth` and
function, supported on PostGIS and SpatiaLite. :class:`~django.contrib.gis.db.models.functions.LineLocatePoint` functions,
supported on PostGIS and SpatiaLite.
* Any :class:`~django.contrib.gis.geos.GEOSGeometry` imported from GeoJSON now * Any :class:`~django.contrib.gis.geos.GEOSGeometry` imported from GeoJSON now
has its SRID set. has its SRID set.

View File

@ -1,4 +1,5 @@
import json import json
import math
import re import re
from decimal import Decimal from decimal import Decimal
@ -145,6 +146,15 @@ class GISFunctionsTests(TestCase):
self.assertEqual(svg1, City.objects.annotate(svg=functions.AsSVG('point')).get(name='Pueblo').svg) self.assertEqual(svg1, City.objects.annotate(svg=functions.AsSVG('point')).get(name='Pueblo').svg)
self.assertEqual(svg2, City.objects.annotate(svg=functions.AsSVG('point', relative=5)).get(name='Pueblo').svg) self.assertEqual(svg2, City.objects.annotate(svg=functions.AsSVG('point', relative=5)).get(name='Pueblo').svg)
@skipUnlessDBFeature("has_Azimuth_function")
def test_azimuth(self):
# Returns the azimuth in radians.
azimuth_expr = functions.Azimuth(Point(0, 0, srid=4326), Point(1, 1, srid=4326))
self.assertAlmostEqual(City.objects.annotate(azimuth=azimuth_expr).first().azimuth, math.pi / 4)
# Returns None if the two points are coincident.
azimuth_expr = functions.Azimuth(Point(0, 0, srid=4326), Point(0, 0, srid=4326))
self.assertIsNone(City.objects.annotate(azimuth=azimuth_expr).first().azimuth)
@skipUnlessDBFeature("has_BoundingCircle_function") @skipUnlessDBFeature("has_BoundingCircle_function")
def test_bounding_circle(self): def test_bounding_circle(self):
def circle_num_points(num_seg): def circle_num_points(num_seg):