from django.contrib.gis.gdal.base import GDALBase from django.contrib.gis.gdal.error import GDALException from django.contrib.gis.gdal.field import Field from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType from django.contrib.gis.gdal.prototypes import ds as capi from django.contrib.gis.gdal.prototypes import geom as geom_api from django.utils.encoding import force_bytes, force_str # For more information, see the OGR C API source code: # https://gdal.org/api/vector_c_api.html # # The OGR_F_* routines are relevant here. class Feature(GDALBase): """ This class that wraps an OGR Feature, needs to be instantiated from a Layer object. """ destructor = capi.destroy_feature def __init__(self, feat, layer): """ Initialize Feature from a pointer and its Layer object. """ if not feat: raise GDALException("Cannot create OGR Feature, invalid pointer given.") self.ptr = feat self._layer = layer def __getitem__(self, index): """ Get the Field object at the specified index, which may be either an integer or the Field's string label. Note that the Field object is not the field's _value_ -- use the `get` method instead to retrieve the value (e.g. an integer) instead of a Field instance. """ if isinstance(index, str): i = self.index(index) elif 0 <= index < self.num_fields: i = index else: raise IndexError( "Index out of range when accessing field in a feature: %s." % index ) return Field(self, i) def __len__(self): "Return the count of fields in this feature." return self.num_fields def __str__(self): "The string name of the feature." return "Feature FID %d in Layer<%s>" % (self.fid, self.layer_name) def __eq__(self, other): "Do equivalence testing on the features." return bool(capi.feature_equal(self.ptr, other._ptr)) # #### Feature Properties #### @property def encoding(self): return self._layer._ds.encoding @property def fid(self): "Return the feature identifier." return capi.get_fid(self.ptr) @property def layer_name(self): "Return the name of the layer for the feature." name = capi.get_feat_name(self._layer._ldefn) return force_str(name, self.encoding, strings_only=True) @property def num_fields(self): "Return the number of fields in the Feature." return capi.get_feat_field_count(self.ptr) @property def fields(self): "Return a list of fields in the Feature." return [ force_str( capi.get_field_name(capi.get_field_defn(self._layer._ldefn, i)), self.encoding, strings_only=True, ) for i in range(self.num_fields) ] @property def geom(self): "Return the OGR Geometry for this Feature." # Retrieving the geometry pointer for the feature. geom_ptr = capi.get_feat_geom_ref(self.ptr) return OGRGeometry(geom_api.clone_geom(geom_ptr)) @property def geom_type(self): "Return the OGR Geometry Type for this Feature." return OGRGeomType(capi.get_fd_geom_type(self._layer._ldefn)) # #### Feature Methods #### def get(self, field): """ Return the value of the field, instead of an instance of the Field object. May take a string of the field name or a Field object as parameters. """ field_name = getattr(field, "name", field) return self[field_name].value def index(self, field_name): "Return the index of the given field name." i = capi.get_field_index(self.ptr, force_bytes(field_name)) if i < 0: raise IndexError("Invalid OFT field name given: %s." % field_name) return i