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