PageRenderTime 18917ms CodeModel.GetById 4ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 1ms

/django/contrib/gis/gdal/layer.py

https://code.google.com/p/mango-py/
Python | 212 lines | 132 code | 25 blank | 55 comment | 33 complexity | 9e612d749b966925f67e34f3253bc584 MD5 | raw file
  1# Needed ctypes routines
  2from ctypes import c_double, byref
  3
  4# Other GDAL imports.
  5from django.contrib.gis.gdal.base import GDALBase
  6from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
  7from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
  8from django.contrib.gis.gdal.feature import Feature
  9from django.contrib.gis.gdal.field import OGRFieldTypes
 10from django.contrib.gis.gdal.geomtype import OGRGeomType
 11from django.contrib.gis.gdal.geometries import OGRGeometry
 12from django.contrib.gis.gdal.srs import SpatialReference
 13
 14# GDAL ctypes function prototypes.
 15from django.contrib.gis.gdal.prototypes import ds as capi, geom as geom_api, srs as srs_api
 16
 17# For more information, see the OGR C API source code:
 18#  http://www.gdal.org/ogr/ogr__api_8h.html
 19#
 20# The OGR_L_* routines are relevant here.
 21class Layer(GDALBase):
 22    "A class that wraps an OGR Layer, needs to be instantiated from a DataSource object."
 23
 24    #### Python 'magic' routines ####
 25    def __init__(self, layer_ptr, ds):
 26        """
 27        Initializes on an OGR C pointer to the Layer and the `DataSource` object
 28        that owns this layer.  The `DataSource` object is required so that a 
 29        reference to it is kept with this Layer.  This prevents garbage 
 30        collection of the `DataSource` while this Layer is still active.
 31        """
 32        if not layer_ptr:
 33            raise OGRException('Cannot create Layer, invalid pointer given')
 34        self.ptr = layer_ptr
 35        self._ds = ds
 36        self._ldefn = capi.get_layer_defn(self._ptr)
 37        # Does the Layer support random reading?
 38        self._random_read = self.test_capability('RandomRead')
 39
 40    def __getitem__(self, index):
 41        "Gets the Feature at the specified index."
 42        if isinstance(index, (int, long)):
 43            # An integer index was given -- we cannot do a check based on the
 44            # number of features because the beginning and ending feature IDs
 45            # are not guaranteed to be 0 and len(layer)-1, respectively.
 46            if index < 0: raise OGRIndexError('Negative indices are not allowed on OGR Layers.')
 47            return self._make_feature(index)
 48        elif isinstance(index, slice):
 49            # A slice was given
 50            start, stop, stride = index.indices(self.num_feat)
 51            return [self._make_feature(fid) for fid in xrange(start, stop, stride)]
 52        else:
 53            raise TypeError('Integers and slices may only be used when indexing OGR Layers.')
 54
 55    def __iter__(self):
 56        "Iterates over each Feature in the Layer."
 57        # ResetReading() must be called before iteration is to begin.
 58        capi.reset_reading(self._ptr)
 59        for i in xrange(self.num_feat):
 60            yield Feature(capi.get_next_feature(self._ptr), self._ldefn)
 61
 62    def __len__(self):
 63        "The length is the number of features."
 64        return self.num_feat
 65
 66    def __str__(self):
 67        "The string name of the layer."
 68        return self.name
 69
 70    def _make_feature(self, feat_id):
 71        """
 72        Helper routine for __getitem__ that constructs a Feature from the given
 73        Feature ID.  If the OGR Layer does not support random-access reading,
 74        then each feature of the layer will be incremented through until the
 75        a Feature is found matching the given feature ID.
 76        """
 77        if self._random_read:
 78            # If the Layer supports random reading, return.
 79            try:
 80                return Feature(capi.get_feature(self.ptr, feat_id), self._ldefn)
 81            except OGRException:
 82                pass
 83        else:
 84            # Random access isn't supported, have to increment through
 85            # each feature until the given feature ID is encountered.
 86            for feat in self:
 87                if feat.fid == feat_id: return feat
 88        # Should have returned a Feature, raise an OGRIndexError.    
 89        raise OGRIndexError('Invalid feature id: %s.' % feat_id)
 90
 91    #### Layer properties ####
 92    @property
 93    def extent(self):
 94        "Returns the extent (an Envelope) of this layer."
 95        env = OGREnvelope()
 96        capi.get_extent(self.ptr, byref(env), 1)
 97        return Envelope(env)
 98
 99    @property
100    def name(self):
101        "Returns the name of this layer in the Data Source."
102        return capi.get_fd_name(self._ldefn)
103
104    @property
105    def num_feat(self, force=1):
106        "Returns the number of features in the Layer."
107        return capi.get_feature_count(self.ptr, force)
108
109    @property
110    def num_fields(self):
111        "Returns the number of fields in the Layer."
112        return capi.get_field_count(self._ldefn)
113
114    @property
115    def geom_type(self):
116        "Returns the geometry type (OGRGeomType) of the Layer."
117        return OGRGeomType(capi.get_fd_geom_type(self._ldefn))
118
119    @property
120    def srs(self):
121        "Returns the Spatial Reference used in this Layer."
122        try:
123            ptr = capi.get_layer_srs(self.ptr)
124            return SpatialReference(srs_api.clone_srs(ptr))
125        except SRSException:
126            return None
127
128    @property
129    def fields(self):
130        """
131        Returns a list of string names corresponding to each of the Fields
132        available in this Layer.
133        """
134        return [capi.get_field_name(capi.get_field_defn(self._ldefn, i)) 
135                for i in xrange(self.num_fields) ]
136    
137    @property
138    def field_types(self):
139        """
140        Returns a list of the types of fields in this Layer.  For example,
141        the list [OFTInteger, OFTReal, OFTString] would be returned for
142        an OGR layer that had an integer, a floating-point, and string
143        fields.
144        """
145        return [OGRFieldTypes[capi.get_field_type(capi.get_field_defn(self._ldefn, i))]
146                for i in xrange(self.num_fields)]
147
148    @property 
149    def field_widths(self):
150        "Returns a list of the maximum field widths for the features."
151        return [capi.get_field_width(capi.get_field_defn(self._ldefn, i))
152                for i in xrange(self.num_fields)]
153
154    @property 
155    def field_precisions(self):
156        "Returns the field precisions for the features."
157        return [capi.get_field_precision(capi.get_field_defn(self._ldefn, i))
158                for i in xrange(self.num_fields)]
159
160    def _get_spatial_filter(self):
161        try:
162            return OGRGeometry(geom_api.clone_geom(capi.get_spatial_filter(self.ptr)))
163        except OGRException:
164            return None
165
166    def _set_spatial_filter(self, filter):
167        if isinstance(filter, OGRGeometry):
168            capi.set_spatial_filter(self.ptr, filter.ptr)
169        elif isinstance(filter, (tuple, list)):
170            if not len(filter) == 4:
171                raise ValueError('Spatial filter list/tuple must have 4 elements.')
172            # Map c_double onto params -- if a bad type is passed in it
173            # will be caught here.
174            xmin, ymin, xmax, ymax = map(c_double, filter)
175            capi.set_spatial_filter_rect(self.ptr, xmin, ymin, xmax, ymax)
176        elif filter is None:
177            capi.set_spatial_filter(self.ptr, None)
178        else:
179            raise TypeError('Spatial filter must be either an OGRGeometry instance, a 4-tuple, or None.')
180
181    spatial_filter = property(_get_spatial_filter, _set_spatial_filter)
182
183    #### Layer Methods ####
184    def get_fields(self, field_name):
185        """
186        Returns a list containing the given field name for every Feature
187        in the Layer.
188        """
189        if not field_name in self.fields:
190            raise OGRException('invalid field name: %s' % field_name)
191        return [feat.get(field_name) for feat in self]
192
193    def get_geoms(self, geos=False):
194        """
195        Returns a list containing the OGRGeometry for every Feature in
196        the Layer.
197        """
198        if geos:
199            from django.contrib.gis.geos import GEOSGeometry
200            return [GEOSGeometry(feat.geom.wkb) for feat in self]
201        else:
202            return [feat.geom for feat in self]
203
204    def test_capability(self, capability):
205        """
206        Returns a bool indicating whether the this Layer supports the given
207        capability (a string).  Valid capability strings include:
208          'RandomRead', 'SequentialWrite', 'RandomWrite', 'FastSpatialFilter',
209          'FastFeatureCount', 'FastGetExtent', 'CreateField', 'Transactions',
210          'DeleteFeature', and 'FastSetNextByIndex'.
211        """
212        return bool(capi.test_capability(self.ptr, capability))