summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Fedoseev <fedoseev.sergey@gmail.com>2017-04-02 00:02:09 +0500
committerTim Graham <timograham@gmail.com>2017-04-01 15:02:09 -0400
commitede4f6d48c1fe060c239b2477c00df6bbfd4fd7c (patch)
tree953aa4ddd3692a0bf5141bfeb7cb4b1a4fb454ce
parent7b53041420009ad430035116c25f36804e714cd5 (diff)
Fixed #12410 -- Added LineLocatePoint GIS function.
-rw-r--r--django/contrib/gis/db/backends/base/operations.py8
-rw-r--r--django/contrib/gis/db/backends/mysql/operations.py5
-rw-r--r--django/contrib/gis/db/backends/oracle/operations.py3
-rw-r--r--django/contrib/gis/db/backends/spatialite/operations.py1
-rw-r--r--django/contrib/gis/db/models/functions.py6
-rw-r--r--docs/ref/contrib/gis/db-api.txt1
-rw-r--r--docs/ref/contrib/gis/functions.txt13
-rw-r--r--docs/releases/2.0.txt3
-rw-r--r--tests/gis_tests/geoapp/test_functions.py5
9 files changed, 38 insertions, 7 deletions
diff --git a/django/contrib/gis/db/backends/base/operations.py b/django/contrib/gis/db/backends/base/operations.py
index 8fa1c2cd44..ba3d3bdf67 100644
--- a/django/contrib/gis/db/backends/base/operations.py
+++ b/django/contrib/gis/db/backends/base/operations.py
@@ -27,10 +27,10 @@ class BaseSpatialOperations:
unsupported_functions = {
'Area', 'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG',
'BoundingCircle', 'Centroid', 'Difference', 'Distance', 'Envelope',
- 'ForceRHR', 'GeoHash', 'Intersection', 'IsValid', 'Length', 'MakeValid',
- 'MemSize', 'NumGeometries', 'NumPoints', 'Perimeter', 'PointOnSurface',
- 'Reverse', 'Scale', 'SnapToGrid', 'SymDifference', 'Transform',
- 'Translate', 'Union',
+ 'ForceRHR', 'GeoHash', 'Intersection', 'IsValid', 'Length',
+ 'LineLocatePoint', 'MakeValid', 'MemSize', 'NumGeometries',
+ 'NumPoints', 'Perimeter', 'PointOnSurface', 'Reverse', 'Scale',
+ 'SnapToGrid', 'SymDifference', 'Transform', 'Translate', 'Union',
}
# Constructors
diff --git a/django/contrib/gis/db/backends/mysql/operations.py b/django/contrib/gis/db/backends/mysql/operations.py
index 58aeda4deb..33f148f5f6 100644
--- a/django/contrib/gis/db/backends/mysql/operations.py
+++ b/django/contrib/gis/db/backends/mysql/operations.py
@@ -73,8 +73,9 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
def unsupported_functions(self):
unsupported = {
'AsGML', 'AsKML', 'AsSVG', 'BoundingCircle', 'ForceRHR',
- 'MakeValid', 'MemSize', 'Perimeter', 'PointOnSurface', 'Reverse',
- 'Scale', 'SnapToGrid', 'Transform', 'Translate',
+ 'LineLocatePoint', 'MakeValid', 'MemSize', 'Perimeter',
+ 'PointOnSurface', 'Reverse', 'Scale', 'SnapToGrid', 'Transform',
+ 'Translate',
}
if self.connection.mysql_version < (5, 7, 5):
unsupported.update({'AsGeoJSON', 'GeoHash', 'IsValid'})
diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py
index 62506e4227..649449b160 100644
--- a/django/contrib/gis/db/backends/oracle/operations.py
+++ b/django/contrib/gis/db/backends/oracle/operations.py
@@ -112,7 +112,8 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
unsupported_functions = {
'AsGeoJSON', 'AsKML', 'AsSVG', 'Envelope', 'ForceRHR', 'GeoHash',
- 'MakeValid', 'MemSize', 'Scale', 'SnapToGrid', 'Translate',
+ 'LineLocatePoint', 'MakeValid', 'MemSize', 'Scale', 'SnapToGrid',
+ 'Translate',
}
def geo_quote_name(self, name):
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
index 46cac8c0b3..23b38694f8 100644
--- a/django/contrib/gis/db/backends/spatialite/operations.py
+++ b/django/contrib/gis/db/backends/spatialite/operations.py
@@ -81,6 +81,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
def function_names(self):
return {
'Length': 'ST_Length',
+ 'LineLocatePoint': 'ST_Line_Locate_Point',
'NumPoints': 'ST_NPoints',
'Reverse': 'ST_Reverse',
'Scale': 'ScaleCoords',
diff --git a/django/contrib/gis/db/models/functions.py b/django/contrib/gis/db/models/functions.py
index c595a143d0..ee2df7cfb4 100644
--- a/django/contrib/gis/db/models/functions.py
+++ b/django/contrib/gis/db/models/functions.py
@@ -389,6 +389,12 @@ class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
return super().as_sql(compiler, connection, function=function)
+class LineLocatePoint(GeoFunc):
+ output_field_class = FloatField
+ arity = 2
+ geom_param_pos = (0, 1)
+
+
class MakeValid(GeoFunc):
pass
diff --git a/docs/ref/contrib/gis/db-api.txt b/docs/ref/contrib/gis/db-api.txt
index d0555ec145..c3d7003636 100644
--- a/docs/ref/contrib/gis/db-api.txt
+++ b/docs/ref/contrib/gis/db-api.txt
@@ -386,6 +386,7 @@ Function PostGIS Oracle MySQL Spat
:class:`Intersection` X X X (≥ 5.6.1) X
:class:`IsValid` X X X (≥ 5.7.5) X (LWGEOM)
:class:`Length` X X X X
+:class:`LineLocatePoint` X X
:class:`MakeValid` X X (LWGEOM)
:class:`MemSize` X
:class:`NumGeometries` X X X X
diff --git a/docs/ref/contrib/gis/functions.txt b/docs/ref/contrib/gis/functions.txt
index b54feb03a1..4bf1994ea6 100644
--- a/docs/ref/contrib/gis/functions.txt
+++ b/docs/ref/contrib/gis/functions.txt
@@ -358,6 +358,19 @@ resource-intensive) with the ``spheroid`` keyword argument.
In older versions, a raw value was returned on MySQL when used on
projected SRS.
+``LineLocatePoint``
+===================
+
+.. class:: LineLocatePoint(linestring, point, **extra)
+
+.. versionadded:: 2.0
+
+*Availability*: `PostGIS <https://postgis.net/docs/ST_LineLocatePoint.html>`__,
+SpatiaLite
+
+Returns a float between 0 and 1 representing the location of the closest point on
+``linestring`` to the given ``point``, as a fraction of the 2D line length.
+
``MakeValid``
=============
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index 0006ef4c45..33f969d443 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -68,6 +68,9 @@ Minor features
:class:`~django.contrib.gis.db.models.functions.IsValid` function, and
:lookup:`isvalid` lookup.
+* Added the :class:`~django.contrib.gis.db.models.functions.LineLocatePoint`
+ function, supported on PostGIS and SpatiaLite.
+
:mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py
index 818ec56e93..ff6d1db9a8 100644
--- a/tests/gis_tests/geoapp/test_functions.py
+++ b/tests/gis_tests/geoapp/test_functions.py
@@ -286,6 +286,11 @@ class GISFunctionsTests(TestCase):
with self.assertRaisesMessage(ValueError, 'AreaField only accepts Area measurement objects.'):
qs.get(area__lt=500000)
+ @skipUnlessDBFeature("has_LineLocatePoint_function")
+ def test_line_locate_point(self):
+ pos_expr = functions.LineLocatePoint(LineString((0, 0), (0, 3), srid=4326), Point(0, 1, srid=4326))
+ self.assertAlmostEqual(State.objects.annotate(pos=pos_expr).first().pos, 0.3333333)
+
@skipUnlessDBFeature("has_MakeValid_function")
def test_make_valid(self):
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')