diff options
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/gis/geos/geometry.py | 32 | ||||
| -rw-r--r-- | django/contrib/gis/geos/prototypes/topology.py | 23 | ||||
| -rw-r--r-- | django/contrib/gis/geos/tests/test_geos.py | 21 |
3 files changed, 71 insertions, 5 deletions
diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py index 6dbb6b2cb3..079308bba8 100644 --- a/django/contrib/gis/geos/geometry.py +++ b/django/contrib/gis/geos/geometry.py @@ -581,6 +581,20 @@ class GEOSGeometry(GEOSBase, ListMixin): "Return the envelope for this geometry (a polygon)." return self._topology(capi.geos_envelope(self.ptr)) + def interpolate(self, distance): + if not isinstance(self, (LineString, MultiLineString)): + raise TypeError('interpolate only works on LineString and MultiLineString geometries') + if not hasattr(capi, 'geos_interpolate'): + raise NotImplementedError('interpolate requires GEOS 3.2+') + return self._topology(capi.geos_interpolate(self.ptr, distance)) + + def interpolate_normalized(self, distance): + if not isinstance(self, (LineString, MultiLineString)): + raise TypeError('interpolate only works on LineString and MultiLineString geometries') + if not hasattr(capi, 'geos_interpolate_normalized'): + raise NotImplementedError('interpolate_normalized requires GEOS 3.2+') + return self._topology(capi.geos_interpolate_normalized(self.ptr, distance)) + def intersection(self, other): "Returns a Geometry representing the points shared by this Geometry and other." return self._topology(capi.geos_intersection(self.ptr, other.ptr)) @@ -590,6 +604,24 @@ class GEOSGeometry(GEOSBase, ListMixin): "Computes an interior point of this Geometry." return self._topology(capi.geos_pointonsurface(self.ptr)) + def project(self, point): + if not isinstance(point, Point): + raise TypeError('locate_point argument must be a Point') + if not isinstance(self, (LineString, MultiLineString)): + raise TypeError('locate_point only works on LineString and MultiLineString geometries') + if not hasattr(capi, 'geos_project'): + raise NotImplementedError('geos_project requires GEOS 3.2+') + return capi.geos_project(self.ptr, point.ptr) + + def project_normalized(self, point): + if not isinstance(point, Point): + raise TypeError('locate_point argument must be a Point') + if not isinstance(self, (LineString, MultiLineString)): + raise TypeError('locate_point only works on LineString and MultiLineString geometries') + if not hasattr(capi, 'geos_project_normalized'): + raise NotImplementedError('project_normalized requires GEOS 3.2+') + return capi.geos_project_normalized(self.ptr, point.ptr) + def relate(self, other): "Returns the DE-9IM intersection matrix for this Geometry and the other." return capi.geos_relate(self.ptr, other.ptr).decode() diff --git a/django/contrib/gis/geos/prototypes/topology.py b/django/contrib/gis/geos/prototypes/topology.py index cc5734b5e4..dfea3e98b6 100644 --- a/django/contrib/gis/geos/prototypes/topology.py +++ b/django/contrib/gis/geos/prototypes/topology.py @@ -8,18 +8,18 @@ __all__ = ['geos_boundary', 'geos_buffer', 'geos_centroid', 'geos_convexhull', 'geos_simplify', 'geos_symdifference', 'geos_union', 'geos_relate'] from ctypes import c_double, c_int -from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOS_PREPARE -from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_string +from django.contrib.gis.geos.libgeos import geos_version_info, GEOM_PTR, GEOS_PREPARE +from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_minus_one, check_string from django.contrib.gis.geos.prototypes.geom import geos_char_p from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc -def topology(func, *args): +def topology(func, *args, **kwargs): "For GEOS unary topology functions." argtypes = [GEOM_PTR] if args: argtypes += args func.argtypes = argtypes - func.restype = GEOM_PTR - func.errcheck = check_geom + func.restype = kwargs.get('restype', GEOM_PTR) + func.errcheck = kwargs.get('errcheck', check_geom) return func ### Topology Routines ### @@ -49,3 +49,16 @@ if GEOS_PREPARE: geos_cascaded_union.argtypes = [GEOM_PTR] geos_cascaded_union.restype = GEOM_PTR __all__.append('geos_cascaded_union') + +# Linear referencing routines +info = geos_version_info() +if info['version'] >= '3.2.0': + geos_project = topology(GEOSFunc('GEOSProject'), GEOM_PTR, + restype=c_double, errcheck=check_minus_one) + geos_interpolate = topology(GEOSFunc('GEOSInterpolate'), c_double) + + geos_project_normalized = topology(GEOSFunc('GEOSProjectNormalized'), + GEOM_PTR, restype=c_double, errcheck=check_minus_one) + geos_interpolate_normalized = topology(GEOSFunc('GEOSInterpolateNormalized'), c_double) + __all__.extend(['geos_project', 'geos_interpolate', + 'geos_project_normalized', 'geos_interpolate_normalized']) diff --git a/django/contrib/gis/geos/tests/test_geos.py b/django/contrib/gis/geos/tests/test_geos.py index c8d3e43a0e..e10ac80982 100644 --- a/django/contrib/gis/geos/tests/test_geos.py +++ b/django/contrib/gis/geos/tests/test_geos.py @@ -1023,6 +1023,27 @@ class GEOSTest(unittest.TestCase, TestDataMixin): print("\nEND - expecting GEOS_NOTICE; safe to ignore.\n") + @unittest.skipUnless(geos_version_info()['version'] >= '3.2.0', "geos >= 3.2.0 is required") + def test_linearref(self): + "Testing linear referencing" + + ls = fromstr('LINESTRING(0 0, 0 10, 10 10, 10 0)') + mls = fromstr('MULTILINESTRING((0 0, 0 10), (10 0, 10 10))') + + self.assertEqual(ls.project(Point(0, 20)), 10.0) + self.assertEqual(ls.project(Point(7, 6)), 24) + self.assertEqual(ls.project_normalized(Point(0, 20)), 1.0/3) + + self.assertEqual(ls.interpolate(10), Point(0, 10)) + self.assertEqual(ls.interpolate(24), Point(10, 6)) + self.assertEqual(ls.interpolate_normalized(1.0/3), Point(0, 10)) + + self.assertEqual(mls.project(Point(0, 20)), 10) + self.assertEqual(mls.project(Point(7, 6)), 16) + + self.assertEqual(mls.interpolate(9), Point(0, 9)) + self.assertEqual(mls.interpolate(17), Point(10, 7)) + def test_geos_version(self): "Testing the GEOS version regular expression." from django.contrib.gis.geos.libgeos import version_regex |
