diff --git a/django/contrib/gis/geos/prepared.py b/django/contrib/gis/geos/prepared.py index d5b531bb430..90a3f4df214 100644 --- a/django/contrib/gis/geos/prepared.py +++ b/django/contrib/gis/geos/prepared.py @@ -1,6 +1,7 @@ -from django.contrib.gis.geos.base import GEOSBase -from django.contrib.gis.geos.geometry import GEOSGeometry -from django.contrib.gis.geos.prototypes import prepared as capi +from .base import GEOSBase +from .geometry import GEOSGeometry +from .libgeos import geos_version_info +from .prototypes import prepared as capi class PreparedGeometry(GEOSBase): @@ -35,3 +36,30 @@ class PreparedGeometry(GEOSBase): def intersects(self, other): return capi.prepared_intersects(self.ptr, other.ptr) + + # Added in GEOS 3.3: + + def crosses(self, other): + if geos_version_info()['version'] < '3.3.0': + raise GEOSException("crosses on prepared geometries requires GEOS >= 3.3.0") + return capi.prepared_crosses(self.ptr, other.ptr) + + def disjoint(self, other): + if geos_version_info()['version'] < '3.3.0': + raise GEOSException("disjoint on prepared geometries requires GEOS >= 3.3.0") + return capi.prepared_disjoint(self.ptr, other.ptr) + + def overlaps(self, other): + if geos_version_info()['version'] < '3.3.0': + raise GEOSException("overlaps on prepared geometries requires GEOS >= 3.3.0") + return capi.prepared_overlaps(self.ptr, other.ptr) + + def touches(self, other): + if geos_version_info()['version'] < '3.3.0': + raise GEOSException("touches on prepared geometries requires GEOS >= 3.3.0") + return capi.prepared_touches(self.ptr, other.ptr) + + def within(self, other): + if geos_version_info()['version'] < '3.3.0': + raise GEOSException("within on prepared geometries requires GEOS >= 3.3.0") + return capi.prepared_within(self.ptr, other.ptr) diff --git a/django/contrib/gis/geos/prototypes/prepared.py b/django/contrib/gis/geos/prototypes/prepared.py index eef141a2f7a..ced56395b0c 100644 --- a/django/contrib/gis/geos/prototypes/prepared.py +++ b/django/contrib/gis/geos/prototypes/prepared.py @@ -1,5 +1,5 @@ from ctypes import c_char -from django.contrib.gis.geos.libgeos import GEOM_PTR, PREPGEOM_PTR +from django.contrib.gis.geos.libgeos import GEOM_PTR, PREPGEOM_PTR, geos_version_info from django.contrib.gis.geos.prototypes.errcheck import check_predicate from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc @@ -24,3 +24,10 @@ prepared_contains = prepared_predicate(GEOSFunc('GEOSPreparedContains')) prepared_contains_properly = prepared_predicate(GEOSFunc('GEOSPreparedContainsProperly')) prepared_covers = prepared_predicate(GEOSFunc('GEOSPreparedCovers')) prepared_intersects = prepared_predicate(GEOSFunc('GEOSPreparedIntersects')) + +if geos_version_info()['version'] > '3.3.0': + prepared_crosses = prepared_predicate(GEOSFunc('GEOSPreparedCrosses')) + prepared_disjoint = prepared_predicate(GEOSFunc('GEOSPreparedDisjoint')) + prepared_overlaps = prepared_predicate(GEOSFunc('GEOSPreparedOverlaps')) + prepared_touches = prepared_predicate(GEOSFunc('GEOSPreparedTouches')) + prepared_within = prepared_predicate(GEOSFunc('GEOSPreparedWithin')) diff --git a/django/contrib/gis/geos/tests/test_geos.py b/django/contrib/gis/geos/tests/test_geos.py index 8356343839c..4c38c9bfcbe 100644 --- a/django/contrib/gis/geos/tests/test_geos.py +++ b/django/contrib/gis/geos/tests/test_geos.py @@ -1032,6 +1032,16 @@ class GEOSTest(unittest.TestCase, TestDataMixin): self.assertEqual(mpoly.intersects(pnt), prep.intersects(pnt)) self.assertEqual(c, prep.covers(pnt)) + if geos_version_info()['version'] > '3.3.0': + self.assertTrue(prep.crosses(fromstr('LINESTRING(1 1, 15 15)'))) + self.assertTrue(prep.disjoint(Point(-5, -5))) + poly = Polygon(((-1, -1), (1, 1), (1, 0), (-1, -1))) + self.assertTrue(prep.overlaps(poly)) + poly = Polygon(((-5, 0), (-5, 5), (0, 5), (-5, 0))) + self.assertTrue(prep.touches(poly)) + poly = Polygon(((-1, -1), (-1, 11), (11, 11), (11, -1), (-1, -1))) + self.assertTrue(prep.within(poly)) + # Original geometry deletion should not crash the prepared one (#21662) del mpoly self.assertTrue(prep.covers(Point(5, 5))) diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt index a1f92b31c7f..769c2cdd32a 100644 --- a/docs/ref/contrib/gis/geos.txt +++ b/docs/ref/contrib/gis/geos.txt @@ -527,8 +527,8 @@ a :class:`Polygon`). Returns a GEOS ``PreparedGeometry`` for the contents of this geometry. ``PreparedGeometry`` objects are optimized for the contains, intersects, -and covers operations. Refer to the :ref:`prepared-geometries` documentation -for more information. +covers, crosses, disjoint, overlaps, touches and within operations. Refer to +the :ref:`prepared-geometries` documentation for more information. .. attribute:: GEOSGeometry.srs @@ -746,8 +746,48 @@ For example:: .. method:: covers(other) + .. method:: crosses(other) + + .. versionadded:: 1.7 + + .. note:: + + GEOS 3.3 is *required* to use this predicate. + + .. method:: disjoint(other) + + .. versionadded:: 1.7 + + .. note:: + + GEOS 3.3 is *required* to use this predicate. + .. method:: intersects(other) + .. method:: overlaps(other) + + .. versionadded:: 1.7 + + .. note:: + + GEOS 3.3 is *required* to use this predicate. + + .. method:: touches(other) + + .. versionadded:: 1.7 + + .. note:: + + GEOS 3.3 is *required* to use this predicate. + + .. method:: within(other) + + .. versionadded:: 1.7 + + .. note:: + + GEOS 3.3 is *required* to use this predicate. + Geometry Factories ================== diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index 21449b4e7c8..106de20ec15 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -211,6 +211,10 @@ Minor features * The default OpenLayers library version included in widgets has been updated from 2.11 to 2.13. +* Prepared geometries now also support the ``crosses``, ``disjoint``, + ``overlaps``, ``touches`` and ``within`` predicates, if GEOS 3.3 or later is + installed. + :mod:`django.contrib.messages` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^