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