app/django/contrib/gis/gdal/datasource.py
author Sverre Rabbelier <srabbelier@gmail.com>
Fri, 23 Jan 2009 21:20:33 +0000
changeset 935 09f47e08f805
parent 323 ff1a9aa48cfd
permissions -rw-r--r--
Adust the as_table tag to render a pick link if appropriate The templates are adjusted to pass on a 'reference' value, which is the url_name of the view from which the entity should be picked. The as_table (and related) function(s) construct and then pass on this argument and enable takes_contex so that we have access to the context of the enclosing template. We only extract ReferenceProperties that end with '_link_id' since that is how all RP's are currently named. It is not possible to create a field with the same name as the RP, as GAE will try to interpret it's contents as the key of an entity before even calling any function we can override. Patch by: Sverre Rabbelier

"""
 DataSource is a wrapper for the OGR Data Source object, which provides
 an interface for reading vector geometry data from many different file
 formats (including ESRI shapefiles).

 When instantiating a DataSource object, use the filename of a
 GDAL-supported data source.  For example, a SHP file or a
 TIGER/Line file from the government.

 The ds_driver keyword is used internally when a ctypes pointer
 is passed in directly.

 Example:
  ds = DataSource('/home/foo/bar.shp')
  for layer in ds:
      for feature in layer:
          # Getting the geometry for the feature.
          g = feature.geom

          # Getting the 'description' field for the feature.
          desc = feature['description']

          # We can also increment through all of the fields
          #  attached to this feature.
          for field in feature:
              # Get the name of the field (e.g. 'description')
              nm = field.name

              # Get the type (integer) of the field, e.g. 0 => OFTInteger
              t = field.type

              # Returns the value the field; OFTIntegers return ints,
              #  OFTReal returns floats, all else returns string.
              val = field.value
"""
# ctypes prerequisites.
from ctypes import byref, c_void_p

# The GDAL C library, OGR exceptions, and the Layer object.
from django.contrib.gis.gdal.driver import Driver
from django.contrib.gis.gdal.error import OGRException, OGRIndexError
from django.contrib.gis.gdal.layer import Layer

# Getting the ctypes prototypes for the DataSource.
from django.contrib.gis.gdal.prototypes.ds import \
    destroy_ds, get_driver_count, register_all, open_ds, release_ds, \
    get_ds_name, get_layer, get_layer_count, get_layer_by_name

# For more information, see the OGR C API source code:
#  http://www.gdal.org/ogr/ogr__api_8h.html
#
# The OGR_DS_* routines are relevant here.
class DataSource(object):
    "Wraps an OGR Data Source object."

    #### Python 'magic' routines ####
    def __init__(self, ds_input, ds_driver=False, write=False):

        # DataSource pointer is initially NULL.
        self._ptr = None

        # The write flag.
        if write:
            self._write = 1
        else:
            self._write = 0

        # Registering all the drivers, this needs to be done
        #  _before_ we try to open up a data source.
        if not get_driver_count(): register_all()

        if isinstance(ds_input, basestring):
            # The data source driver is a void pointer.
            ds_driver = c_void_p()
            try:
                # OGROpen will auto-detect the data source type.
                ds = open_ds(ds_input, self._write, byref(ds_driver))
            except OGRException:
                # Making the error message more clear rather than something
                # like "Invalid pointer returned from OGROpen".
                raise OGRException('Could not open the datasource at "%s"' % ds_input)
        elif isinstance(ds_input, c_void_p) and isinstance(ds_driver, c_void_p):
            ds = ds_input
        else:
            raise OGRException('Invalid data source input type: %s' % type(ds_input))

        if bool(ds):
            self._ptr = ds
            self._driver = Driver(ds_driver)
        else:
            # Raise an exception if the returned pointer is NULL 
            raise OGRException('Invalid data source file "%s"' % ds_input)

    def __del__(self):
        "Destroys this DataStructure object."
        if self._ptr: destroy_ds(self._ptr)

    def __iter__(self):
        "Allows for iteration over the layers in a data source."
        for i in xrange(self.layer_count):
            yield self[i]

    def __getitem__(self, index):
        "Allows use of the index [] operator to get a layer at the index."
        if isinstance(index, basestring):
            l = get_layer_by_name(self._ptr, index)
            if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
        elif isinstance(index, int):
            if index < 0 or index >= self.layer_count:
                raise OGRIndexError('index out of range')
            l = get_layer(self._ptr, index)
        else:
            raise TypeError('Invalid index type: %s' % type(index))
        return Layer(l)
        
    def __len__(self):
        "Returns the number of layers within the data source."
        return self.layer_count

    def __str__(self):
        "Returns OGR GetName and Driver for the Data Source."
        return '%s (%s)' % (self.name, str(self.driver))

    #### DataSource Properties ####
    @property
    def driver(self):
        "Returns the Driver object for this Data Source."
        return self._driver
        
    @property
    def layer_count(self):
        "Returns the number of layers in the data source."
        return get_layer_count(self._ptr)

    @property
    def name(self):
        "Returns the name of the data source."
        return get_ds_name(self._ptr)