Fixed #14318 -- Added `GEOSGeometry.valid_reason` property. Thanks, Rob Coup.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14447 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
877033b479
commit
cabc21ca60
|
@ -275,6 +275,15 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
"This property tests the validity of this Geometry."
|
"This property tests the validity of this Geometry."
|
||||||
return capi.geos_isvalid(self.ptr)
|
return capi.geos_isvalid(self.ptr)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def valid_reason(self):
|
||||||
|
"""
|
||||||
|
Returns a string containing the reason for any invalidity.
|
||||||
|
"""
|
||||||
|
if not GEOS_PREPARE:
|
||||||
|
raise GEOSException('Upgrade GEOS to 3.1 to get validity reason.')
|
||||||
|
return capi.geos_isvalidreason(self.ptr)
|
||||||
|
|
||||||
#### Binary predicates. ####
|
#### Binary predicates. ####
|
||||||
def contains(self, other):
|
def contains(self, other):
|
||||||
"Returns true if other.within(this) returns true."
|
"Returns true if other.within(this) returns true."
|
||||||
|
@ -376,7 +385,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
"""
|
"""
|
||||||
Returns the WKB of this Geometry in hexadecimal form. Please note
|
Returns the WKB of this Geometry in hexadecimal form. Please note
|
||||||
that the SRID and Z values are not included in this representation
|
that the SRID and Z values are not included in this representation
|
||||||
because it is not a part of the OGC specification (use the `hexewkb`
|
because it is not a part of the OGC specification (use the `hexewkb`
|
||||||
property instead).
|
property instead).
|
||||||
"""
|
"""
|
||||||
# A possible faster, all-python, implementation:
|
# A possible faster, all-python, implementation:
|
||||||
|
@ -386,14 +395,14 @@ class GEOSGeometry(GEOSBase, ListMixin):
|
||||||
@property
|
@property
|
||||||
def hexewkb(self):
|
def hexewkb(self):
|
||||||
"""
|
"""
|
||||||
Returns the EWKB of this Geometry in hexadecimal form. This is an
|
Returns the EWKB of this Geometry in hexadecimal form. This is an
|
||||||
extension of the WKB specification that includes SRID and Z values
|
extension of the WKB specification that includes SRID and Z values
|
||||||
that are a part of this geometry.
|
that are a part of this geometry.
|
||||||
"""
|
"""
|
||||||
if self.hasz:
|
if self.hasz:
|
||||||
if not GEOS_PREPARE:
|
if not GEOS_PREPARE:
|
||||||
# See: http://trac.osgeo.org/geos/ticket/216
|
# See: http://trac.osgeo.org/geos/ticket/216
|
||||||
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
|
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
|
||||||
return ewkb_w3d().write_hex(self)
|
return ewkb_w3d().write_hex(self)
|
||||||
else:
|
else:
|
||||||
return ewkb_w().write_hex(self)
|
return ewkb_w().write_hex(self)
|
||||||
|
|
|
@ -18,7 +18,7 @@ from django.contrib.gis.geos.prototypes.geom import from_hex, from_wkb, from_wkt
|
||||||
to_hex, to_wkb, to_wkt
|
to_hex, to_wkb, to_wkt
|
||||||
|
|
||||||
# Miscellaneous routines.
|
# Miscellaneous routines.
|
||||||
from django.contrib.gis.geos.prototypes.misc import geos_area, geos_distance, geos_length
|
from django.contrib.gis.geos.prototypes.misc import *
|
||||||
|
|
||||||
# Predicates
|
# Predicates
|
||||||
from django.contrib.gis.geos.prototypes.predicates import geos_hasz, geos_isempty, \
|
from django.contrib.gis.geos.prototypes.predicates import geos_hasz, geos_isempty, \
|
||||||
|
|
|
@ -3,10 +3,13 @@
|
||||||
ones that return the area, distance, and length.
|
ones that return the area, distance, and length.
|
||||||
"""
|
"""
|
||||||
from ctypes import c_int, c_double, POINTER
|
from ctypes import c_int, c_double, POINTER
|
||||||
from django.contrib.gis.geos.libgeos import GEOM_PTR
|
from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOS_PREPARE
|
||||||
from django.contrib.gis.geos.prototypes.errcheck import check_dbl
|
from django.contrib.gis.geos.prototypes.errcheck import check_dbl, check_string
|
||||||
|
from django.contrib.gis.geos.prototypes.geom import geos_char_p
|
||||||
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
|
||||||
|
|
||||||
|
__all__ = ['geos_area', 'geos_distance', 'geos_length']
|
||||||
|
|
||||||
### ctypes generator function ###
|
### ctypes generator function ###
|
||||||
def dbl_from_geom(func, num_geom=1):
|
def dbl_from_geom(func, num_geom=1):
|
||||||
"""
|
"""
|
||||||
|
@ -26,3 +29,11 @@ def dbl_from_geom(func, num_geom=1):
|
||||||
geos_area = dbl_from_geom(GEOSFunc('GEOSArea'))
|
geos_area = dbl_from_geom(GEOSFunc('GEOSArea'))
|
||||||
geos_distance = dbl_from_geom(GEOSFunc('GEOSDistance'), num_geom=2)
|
geos_distance = dbl_from_geom(GEOSFunc('GEOSDistance'), num_geom=2)
|
||||||
geos_length = dbl_from_geom(GEOSFunc('GEOSLength'))
|
geos_length = dbl_from_geom(GEOSFunc('GEOSLength'))
|
||||||
|
|
||||||
|
# Validity reason; only in GEOS 3.1+
|
||||||
|
if GEOS_PREPARE:
|
||||||
|
geos_isvalidreason = GEOSFunc('GEOSisValidReason')
|
||||||
|
geos_isvalidreason.argtypes = [GEOM_PTR]
|
||||||
|
geos_isvalidreason.restype = geos_char_p
|
||||||
|
geos_isvalidreason.errcheck = check_string
|
||||||
|
__all__.append('geos_isvalidreason')
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import ctypes, random, unittest, sys
|
import ctypes, random, unittest, sys
|
||||||
from django.contrib.gis.geos import *
|
from django.contrib.gis.geos import *
|
||||||
from django.contrib.gis.geos.base import gdal, numpy, GEOSBase
|
from django.contrib.gis.geos.base import gdal, numpy, GEOSBase
|
||||||
|
from django.contrib.gis.geos.libgeos import GEOS_PREPARE
|
||||||
from django.contrib.gis.geometry.test_data import TestDataMixin
|
from django.contrib.gis.geometry.test_data import TestDataMixin
|
||||||
|
|
||||||
class GEOSTest(unittest.TestCase, TestDataMixin):
|
class GEOSTest(unittest.TestCase, TestDataMixin):
|
||||||
|
@ -917,6 +918,26 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
|
||||||
for geom, merged in zip(ref_geoms, ref_merged):
|
for geom, merged in zip(ref_geoms, ref_merged):
|
||||||
self.assertEqual(merged, geom.merged)
|
self.assertEqual(merged, geom.merged)
|
||||||
|
|
||||||
|
def test27_valid_reason(self):
|
||||||
|
"Testing IsValidReason support"
|
||||||
|
# Skipping tests if GEOS < v3.1.
|
||||||
|
if not GEOS_PREPARE: return
|
||||||
|
|
||||||
|
g = GEOSGeometry("POINT(0 0)")
|
||||||
|
self.assert_(g.valid)
|
||||||
|
self.assert_(isinstance(g.valid_reason, basestring))
|
||||||
|
self.assertEqual(g.valid_reason, "Valid Geometry")
|
||||||
|
|
||||||
|
print "\nBEGIN - expecting GEOS_NOTICE; safe to ignore.\n"
|
||||||
|
|
||||||
|
g = GEOSGeometry("LINESTRING(0 0, 0 0)")
|
||||||
|
|
||||||
|
self.assert_(not g.valid)
|
||||||
|
self.assert_(isinstance(g.valid_reason, basestring))
|
||||||
|
self.assertEqual(g.valid_reason, "Too few points in geometry component[0 0]")
|
||||||
|
|
||||||
|
print "\nEND - expecting GEOS_NOTICE; safe to ignore.\n"
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
s = unittest.TestSuite()
|
s = unittest.TestSuite()
|
||||||
s.addTest(unittest.makeSuite(GEOSTest))
|
s.addTest(unittest.makeSuite(GEOSTest))
|
||||||
|
|
|
@ -219,6 +219,12 @@ definition.
|
||||||
|
|
||||||
Returns a boolean indicating whether the geometry is valid.
|
Returns a boolean indicating whether the geometry is valid.
|
||||||
|
|
||||||
|
.. attribute:: GEOSGeometry.valid_reason
|
||||||
|
|
||||||
|
.. versionadded:: 1.3
|
||||||
|
|
||||||
|
Returns a string describing the reason why a geometry is invalid.
|
||||||
|
|
||||||
.. attribute:: GEOSGeometry.srid
|
.. attribute:: GEOSGeometry.srid
|
||||||
|
|
||||||
Property that may be used to retrieve or set the SRID associated with the
|
Property that may be used to retrieve or set the SRID associated with the
|
||||||
|
|
Loading…
Reference in New Issue