Added support for spatially filtering what OGR features are returned in iteration via the `Layer.spatial_filter` property.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11727 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
562d5d8a28
commit
f3bb5276e0
|
@ -1,5 +1,5 @@
|
||||||
# Needed ctypes routines
|
# Needed ctypes routines
|
||||||
from ctypes import byref
|
from ctypes import c_double, byref
|
||||||
|
|
||||||
# Other GDAL imports.
|
# Other GDAL imports.
|
||||||
from django.contrib.gis.gdal.base import GDALBase
|
from django.contrib.gis.gdal.base import GDALBase
|
||||||
|
@ -7,11 +7,12 @@ from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
|
||||||
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
|
from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
|
||||||
from django.contrib.gis.gdal.feature import Feature
|
from django.contrib.gis.gdal.feature import Feature
|
||||||
from django.contrib.gis.gdal.field import OGRFieldTypes
|
from django.contrib.gis.gdal.field import OGRFieldTypes
|
||||||
from django.contrib.gis.gdal.geometries import OGRGeomType
|
from django.contrib.gis.gdal.geomtype import OGRGeomType
|
||||||
|
from django.contrib.gis.gdal.geometries import OGRGeometry
|
||||||
from django.contrib.gis.gdal.srs import SpatialReference
|
from django.contrib.gis.gdal.srs import SpatialReference
|
||||||
|
|
||||||
# GDAL ctypes function prototypes.
|
# GDAL ctypes function prototypes.
|
||||||
from django.contrib.gis.gdal.prototypes import ds as capi, srs as srs_api
|
from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api, srs as srs_api
|
||||||
|
|
||||||
# For more information, see the OGR C API source code:
|
# For more information, see the OGR C API source code:
|
||||||
# http://www.gdal.org/ogr/ogr__api_8h.html
|
# http://www.gdal.org/ogr/ogr__api_8h.html
|
||||||
|
@ -156,6 +157,29 @@ class Layer(GDALBase):
|
||||||
return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
|
return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
|
||||||
for i in xrange(self.num_fields)]
|
for i in xrange(self.num_fields)]
|
||||||
|
|
||||||
|
def _get_spatial_filter(self):
|
||||||
|
try:
|
||||||
|
return OGRGeometry(geom_api.clone_geom(capi.get_spatial_filter(self.ptr)))
|
||||||
|
except OGRException:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _set_spatial_filter(self, filter):
|
||||||
|
if isinstance(filter, OGRGeometry):
|
||||||
|
capi.set_spatial_filter(self.ptr, filter.ptr)
|
||||||
|
elif isinstance(filter, (tuple, list)):
|
||||||
|
if not len(filter) == 4:
|
||||||
|
raise ValueError('Spatial filter list/tuple must have 4 elements.')
|
||||||
|
# Map c_double onto params -- if a bad type is passed in it
|
||||||
|
# will be caught here.
|
||||||
|
xmin, ymin, xmax, ymax = map(c_double, filter)
|
||||||
|
capi.set_spatial_filter_rect(self.ptr, xmin, ymin, xmax, ymax)
|
||||||
|
elif filter is None:
|
||||||
|
capi.set_spatial_filter(self.ptr, None)
|
||||||
|
else:
|
||||||
|
raise TypeError('Spatial filter must be either an OGRGeometry instance, a 4-tuple, or None.')
|
||||||
|
|
||||||
|
spatial_filter = property(_get_spatial_filter, _set_spatial_filter)
|
||||||
|
|
||||||
#### Layer Methods ####
|
#### Layer Methods ####
|
||||||
def get_fields(self, field_name):
|
def get_fields(self, field_name):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
related data structures. OGR_Dr_*, OGR_DS_*, OGR_L_*, OGR_F_*,
|
related data structures. OGR_Dr_*, OGR_DS_*, OGR_L_*, OGR_F_*,
|
||||||
OGR_Fld_* routines are relevant here.
|
OGR_Fld_* routines are relevant here.
|
||||||
"""
|
"""
|
||||||
from ctypes import c_char_p, c_int, c_long, c_void_p, POINTER
|
from ctypes import c_char_p, c_double, c_int, c_long, c_void_p, POINTER
|
||||||
from django.contrib.gis.gdal.envelope import OGREnvelope
|
from django.contrib.gis.gdal.envelope import OGREnvelope
|
||||||
from django.contrib.gis.gdal.libgdal import lgdal
|
from django.contrib.gis.gdal.libgdal import lgdal
|
||||||
from django.contrib.gis.gdal.prototypes.generation import \
|
from django.contrib.gis.gdal.prototypes.generation import \
|
||||||
|
@ -38,6 +38,9 @@ get_layer_srs = srs_output(lgdal.OGR_L_GetSpatialRef, [c_void_p])
|
||||||
get_next_feature = voidptr_output(lgdal.OGR_L_GetNextFeature, [c_void_p])
|
get_next_feature = voidptr_output(lgdal.OGR_L_GetNextFeature, [c_void_p])
|
||||||
reset_reading = void_output(lgdal.OGR_L_ResetReading, [c_void_p], errcheck=False)
|
reset_reading = void_output(lgdal.OGR_L_ResetReading, [c_void_p], errcheck=False)
|
||||||
test_capability = int_output(lgdal.OGR_L_TestCapability, [c_void_p, c_char_p])
|
test_capability = int_output(lgdal.OGR_L_TestCapability, [c_void_p, c_char_p])
|
||||||
|
get_spatial_filter = geom_output(lgdal.OGR_L_GetSpatialFilter, [c_void_p])
|
||||||
|
set_spatial_filter = void_output(lgdal.OGR_L_SetSpatialFilter, [c_void_p, c_void_p], errcheck=False)
|
||||||
|
set_spatial_filter_rect = void_output(lgdal.OGR_L_SetSpatialFilterRect, [c_void_p, c_double, c_double, c_double, c_double], errcheck=False)
|
||||||
|
|
||||||
### Feature Definition Routines ###
|
### Feature Definition Routines ###
|
||||||
get_fd_geom_type = int_output(lgdal.OGR_FD_GetGeomType, [c_void_p])
|
get_fd_geom_type = int_output(lgdal.OGR_FD_GetGeomType, [c_void_p])
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import os, os.path, unittest
|
import os, os.path, unittest
|
||||||
from django.contrib.gis.gdal import DataSource, Envelope, OGRException, OGRIndexError
|
from django.contrib.gis.gdal import DataSource, Envelope, OGRGeometry, OGRException, OGRIndexError
|
||||||
from django.contrib.gis.gdal.field import OFTReal, OFTInteger, OFTString
|
from django.contrib.gis.gdal.field import OFTReal, OFTInteger, OFTString
|
||||||
from django.contrib import gis
|
from django.contrib import gis
|
||||||
|
|
||||||
# Path for SHP files
|
# Path for SHP files
|
||||||
data_path = os.path.join(os.path.dirname(gis.__file__), 'tests' + os.sep + 'data')
|
data_path = os.path.join(os.path.dirname(gis.__file__), 'tests' + os.sep + 'data')
|
||||||
def get_ds_file(name, ext):
|
def get_ds_file(name, ext):
|
||||||
|
|
||||||
|
|
||||||
return os.sep.join([data_path, name, name + '.%s' % ext])
|
return os.sep.join([data_path, name, name + '.%s' % ext])
|
||||||
|
|
||||||
# Test SHP data source object
|
# Test SHP data source object
|
||||||
|
@ -191,6 +189,40 @@ class DataSourceTest(unittest.TestCase):
|
||||||
if hasattr(source, 'srs_wkt'):
|
if hasattr(source, 'srs_wkt'):
|
||||||
self.assertEqual(source.srs_wkt, g.srs.wkt)
|
self.assertEqual(source.srs_wkt, g.srs.wkt)
|
||||||
|
|
||||||
|
def test06_spatial_filter(self):
|
||||||
|
"Testing the Layer.spatial_filter property."
|
||||||
|
ds = DataSource(get_ds_file('cities', 'shp'))
|
||||||
|
lyr = ds[0]
|
||||||
|
|
||||||
|
# When not set, it should be None.
|
||||||
|
self.assertEqual(None, lyr.spatial_filter)
|
||||||
|
|
||||||
|
# Must be set a/an OGRGeometry or 4-tuple.
|
||||||
|
self.assertRaises(TypeError, lyr._set_spatial_filter, 'foo')
|
||||||
|
|
||||||
|
# Setting the spatial filter with a tuple/list with the extent of
|
||||||
|
# a buffer centering around Pueblo.
|
||||||
|
self.assertRaises(ValueError, lyr._set_spatial_filter, range(5))
|
||||||
|
filter_extent = (-105.609252, 37.255001, -103.609252, 39.255001)
|
||||||
|
lyr.spatial_filter = (-105.609252, 37.255001, -103.609252, 39.255001)
|
||||||
|
self.assertEqual(OGRGeometry.from_bbox(filter_extent), lyr.spatial_filter)
|
||||||
|
feats = [feat for feat in lyr]
|
||||||
|
self.assertEqual(1, len(feats))
|
||||||
|
self.assertEqual('Pueblo', feats[0].get('Name'))
|
||||||
|
|
||||||
|
# Setting the spatial filter with an OGRGeometry for buffer centering
|
||||||
|
# around Houston.
|
||||||
|
filter_geom = OGRGeometry('POLYGON((-96.363151 28.763374,-94.363151 28.763374,-94.363151 30.763374,-96.363151 30.763374,-96.363151 28.763374))')
|
||||||
|
lyr.spatial_filter = filter_geom
|
||||||
|
self.assertEqual(filter_geom, lyr.spatial_filter)
|
||||||
|
feats = [feat for feat in lyr]
|
||||||
|
self.assertEqual(1, len(feats))
|
||||||
|
self.assertEqual('Houston', feats[0].get('Name'))
|
||||||
|
|
||||||
|
# Clearing the spatial filter by setting it to None. Now
|
||||||
|
# should indicate that there are 3 features in the Layer.
|
||||||
|
lyr.spatial_filter = None
|
||||||
|
self.assertEqual(3, len(lyr))
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
s = unittest.TestSuite()
|
s = unittest.TestSuite()
|
||||||
|
|
Loading…
Reference in New Issue