Fixed #12410 -- Added LineLocatePoint GIS function.

This commit is contained in:
Sergey Fedoseev 2017-04-02 00:02:09 +05:00 committed by Tim Graham
parent 7b53041420
commit ede4f6d48c
9 changed files with 38 additions and 7 deletions

View File

@ -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

View File

@ -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'})

View File

@ -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):

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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``
=============

View File

@ -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`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -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))')