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

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

üst 4f99ba84
...@@ -25,7 +25,7 @@ class BaseSpatialOperations: ...@@ -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',
......
...@@ -72,7 +72,7 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): ...@@ -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',
......
...@@ -111,9 +111,9 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations): ...@@ -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):
......
...@@ -93,7 +93,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations): ...@@ -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
......
...@@ -162,6 +162,12 @@ class Area(OracleToleranceMixin, GeoFunc): ...@@ -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
......
...@@ -376,6 +376,7 @@ Function PostGIS Oracle MySQL Spat ...@@ -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
......
...@@ -23,11 +23,11 @@ Function's summary: ...@@ -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 ...@@ -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``
================== ==================
......
...@@ -68,8 +68,9 @@ Minor features ...@@ -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.
......
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): ...@@ -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):
......
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