Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
  • Loading branch information...
commit f3bb5276e095ddaf6cfa5de37d8c3fa879903fdc 1 parent 562d5d8
@jbronn jbronn authored
View
30 django/contrib/gis/gdal/layer.py
@@ -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.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 @@ def field_precisions(self):
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):
"""
View
5 django/contrib/gis/gdal/prototypes/ds.py
@@ -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_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])
View
40 django/contrib/gis/gdal/tests/test_ds.py
@@ -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 @@ def test05_geometries(self):
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))
Please sign in to comment.
Something went wrong with that request. Please try again.