Fixed #33136 -- Added GEOSGeometry.make_valid() method.
This commit is contained in:
parent
fb05ca420d
commit
4ffada3609
|
@ -11,7 +11,7 @@ from django.contrib.gis.geos import prototypes as capi
|
||||||
from django.contrib.gis.geos.base import GEOSBase
|
from django.contrib.gis.geos.base import GEOSBase
|
||||||
from django.contrib.gis.geos.coordseq import GEOSCoordSeq
|
from django.contrib.gis.geos.coordseq import GEOSCoordSeq
|
||||||
from django.contrib.gis.geos.error import GEOSException
|
from django.contrib.gis.geos.error import GEOSException
|
||||||
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
from django.contrib.gis.geos.libgeos import GEOM_PTR, geos_version_tuple
|
||||||
from django.contrib.gis.geos.mutable_list import ListMixin
|
from django.contrib.gis.geos.mutable_list import ListMixin
|
||||||
from django.contrib.gis.geos.prepared import PreparedGeometry
|
from django.contrib.gis.geos.prepared import PreparedGeometry
|
||||||
from django.contrib.gis.geos.prototypes.io import (
|
from django.contrib.gis.geos.prototypes.io import (
|
||||||
|
@ -219,6 +219,15 @@ class GEOSGeometryBase(GEOSBase):
|
||||||
"Convert this Geometry to normal form (or canonical form)."
|
"Convert this Geometry to normal form (or canonical form)."
|
||||||
capi.geos_normalize(self.ptr)
|
capi.geos_normalize(self.ptr)
|
||||||
|
|
||||||
|
def make_valid(self):
|
||||||
|
"""
|
||||||
|
Attempt to create a valid representation of a given invalid geometry
|
||||||
|
without losing any of the input vertices.
|
||||||
|
"""
|
||||||
|
if geos_version_tuple() < (3, 8):
|
||||||
|
raise GEOSException('GEOSGeometry.make_valid() requires GEOS >= 3.8.0.')
|
||||||
|
return GEOSGeometry(capi.geos_makevalid(self.ptr), srid=self.srid)
|
||||||
|
|
||||||
# #### Unary predicates ####
|
# #### Unary predicates ####
|
||||||
@property
|
@property
|
||||||
def empty(self):
|
def empty(self):
|
||||||
|
|
|
@ -12,9 +12,9 @@ from django.contrib.gis.geos.prototypes.coordseq import ( # NOQA
|
||||||
from django.contrib.gis.geos.prototypes.geom import ( # NOQA
|
from django.contrib.gis.geos.prototypes.geom import ( # NOQA
|
||||||
create_collection, create_empty_polygon, create_linearring,
|
create_collection, create_empty_polygon, create_linearring,
|
||||||
create_linestring, create_point, create_polygon, destroy_geom, geom_clone,
|
create_linestring, create_point, create_polygon, destroy_geom, geom_clone,
|
||||||
geos_get_srid, geos_normalize, geos_set_srid, geos_type, geos_typeid,
|
geos_get_srid, geos_makevalid, geos_normalize, geos_set_srid, geos_type,
|
||||||
get_dims, get_extring, get_geomn, get_intring, get_nrings, get_num_coords,
|
geos_typeid, get_dims, get_extring, get_geomn, get_intring, get_nrings,
|
||||||
get_num_geoms,
|
get_num_coords, get_num_geoms,
|
||||||
)
|
)
|
||||||
from django.contrib.gis.geos.prototypes.misc import * # NOQA
|
from django.contrib.gis.geos.prototypes.misc import * # NOQA
|
||||||
from django.contrib.gis.geos.prototypes.predicates import ( # NOQA
|
from django.contrib.gis.geos.prototypes.predicates import ( # NOQA
|
||||||
|
|
|
@ -44,6 +44,7 @@ class StringFromGeom(GEOSFuncFactory):
|
||||||
# ### ctypes prototypes ###
|
# ### ctypes prototypes ###
|
||||||
|
|
||||||
# The GEOS geometry type, typeid, num_coordinates and number of geometries
|
# The GEOS geometry type, typeid, num_coordinates and number of geometries
|
||||||
|
geos_makevalid = GeomOutput('GEOSMakeValid', argtypes=[GEOM_PTR])
|
||||||
geos_normalize = IntFromGeom('GEOSNormalize')
|
geos_normalize = IntFromGeom('GEOSNormalize')
|
||||||
geos_type = StringFromGeom('GEOSGeomType')
|
geos_type = StringFromGeom('GEOSGeomType')
|
||||||
geos_typeid = IntFromGeom('GEOSGeomTypeId')
|
geos_typeid = IntFromGeom('GEOSGeomTypeId')
|
||||||
|
|
|
@ -655,6 +655,16 @@ Other Properties & Methods
|
||||||
doesn't impose any constraints on the geometry's SRID if called with a
|
doesn't impose any constraints on the geometry's SRID if called with a
|
||||||
:class:`~django.contrib.gis.gdal.CoordTransform` object.
|
:class:`~django.contrib.gis.gdal.CoordTransform` object.
|
||||||
|
|
||||||
|
.. method:: GEOSGeometry.make_valid()
|
||||||
|
|
||||||
|
.. versionadded:: 4.1
|
||||||
|
|
||||||
|
Returns a valid :class:`GEOSGeometry` equivalent, trying not to lose any of
|
||||||
|
the input vertices. If the geometry is already valid, it is returned
|
||||||
|
untouched. This is similar to the
|
||||||
|
:class:`~django.contrib.gis.db.models.functions.MakeValid` database
|
||||||
|
function. Requires GEOS 3.8.
|
||||||
|
|
||||||
.. method:: GEOSGeometry.normalize()
|
.. method:: GEOSGeometry.normalize()
|
||||||
|
|
||||||
Converts this geometry to canonical form::
|
Converts this geometry to canonical form::
|
||||||
|
|
|
@ -53,7 +53,8 @@ Minor features
|
||||||
:mod:`django.contrib.gis`
|
:mod:`django.contrib.gis`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* The new :meth:`.GEOSGeometry.make_valid()` method allows converting invalid
|
||||||
|
geometries to valid ones.
|
||||||
|
|
||||||
:mod:`django.contrib.messages`
|
:mod:`django.contrib.messages`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -1429,6 +1429,25 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
||||||
self.assertIsNone(g.normalize())
|
self.assertIsNone(g.normalize())
|
||||||
self.assertTrue(g.equals_exact(MultiPoint(Point(2, 2), Point(1, 1), Point(0, 0))))
|
self.assertTrue(g.equals_exact(MultiPoint(Point(2, 2), Point(1, 1), Point(0, 0))))
|
||||||
|
|
||||||
|
@skipIf(geos_version_tuple() < (3, 8), 'GEOS >= 3.8.0 is required')
|
||||||
|
def test_make_valid(self):
|
||||||
|
poly = GEOSGeometry('POLYGON((0 0, 0 23, 23 0, 23 23, 0 0))')
|
||||||
|
self.assertIs(poly.valid, False)
|
||||||
|
valid_poly = poly.make_valid()
|
||||||
|
self.assertIs(valid_poly.valid, True)
|
||||||
|
self.assertNotEqual(valid_poly, poly)
|
||||||
|
|
||||||
|
valid_poly2 = valid_poly.make_valid()
|
||||||
|
self.assertIs(valid_poly2.valid, True)
|
||||||
|
self.assertEqual(valid_poly, valid_poly2)
|
||||||
|
|
||||||
|
@mock.patch('django.contrib.gis.geos.libgeos.geos_version', lambda: b'3.7.3')
|
||||||
|
def test_make_valid_geos_version(self):
|
||||||
|
msg = 'GEOSGeometry.make_valid() requires GEOS >= 3.8.0.'
|
||||||
|
poly = GEOSGeometry('POLYGON((0 0, 0 23, 23 0, 23 23, 0 0))')
|
||||||
|
with self.assertRaisesMessage(GEOSException, msg):
|
||||||
|
poly.make_valid()
|
||||||
|
|
||||||
def test_empty_point(self):
|
def test_empty_point(self):
|
||||||
p = Point(srid=4326)
|
p = Point(srid=4326)
|
||||||
self.assertEqual(p.ogr.ewkt, p.ewkt)
|
self.assertEqual(p.ogr.ewkt, p.ewkt)
|
||||||
|
|
Loading…
Reference in New Issue