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
|
||||
from ctypes import byref
|
||||
from ctypes import c_double, byref
|
||||
|
||||
# Other GDAL imports.
|
||||
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.feature import Feature
|
||||
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
|
||||
|
||||
# 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:
|
||||
# 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))
|
||||
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 ####
|
||||
def get_fields(self, field_name):
|
||||
"""
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
related data structures. OGR_Dr_*, OGR_DS_*, OGR_L_*, OGR_F_*,
|
||||
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.libgdal import lgdal
|
||||
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])
|
||||
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])
|
||||
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 ###
|
||||
get_fd_geom_type = int_output(lgdal.OGR_FD_GetGeomType, [c_void_p])
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
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 import gis
|
||||
|
||||
# Path for SHP files
|
||||
data_path = os.path.join(os.path.dirname(gis.__file__), 'tests' + os.sep + 'data')
|
||||
def get_ds_file(name, ext):
|
||||
|
||||
|
||||
return os.sep.join([data_path, name, name + '.%s' % ext])
|
||||
|
||||
# Test SHP data source object
|
||||
|
@ -191,7 +189,41 @@ class DataSourceTest(unittest.TestCase):
|
|||
if hasattr(source, '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():
|
||||
s = unittest.TestSuite()
|
||||
s.addTest(unittest.makeSuite(DataSourceTest))
|
||||
|
|
Loading…
Reference in New Issue