Django

Code

Changeset 6686

Show
Ignore:
Timestamp:
11/17/07 15:38:36 (8 months ago)
Author:
jbronn
Message:

gis: gdal: refactor of the GDAL ctypes interface

(1) All interactions with the GDAL library take place through predefined ctypes prototypes, abstracting away error-checking.
(2) Fixed memory leaks by properly freeing pointers allocated w/in GDAL.
(3) Improved OFTField support, and added support for the OGR date/time fields.
(4) Significantly improved the OGRGeometry tests.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/gis/django/contrib/gis/gdal/datasource.py

    r6639 r6686  
    1 # types and ctypes 
    2 from types import StringType 
    3 from ctypes import c_char_p, c_int, c_void_p, byref, string_at 
     1""" 
     2 DataSource is a wrapper for the OGR Data Source object, which provides 
     3 an interface for reading vector geometry data from many different file 
     4 formats (including ESRI shapefiles). 
     5 
     6 When instantiating a DataSource object, use the filename of a 
     7 GDAL-supported data source.  For example, a SHP file or a 
     8 TIGER/Line file from the government. 
     9 
     10 The ds_driver keyword is used internally when a ctypes pointer 
     11 is passed in directly. 
     12 
     13 Example: 
     14  ds = DataSource('/home/foo/bar.shp') 
     15  for layer in ds: 
     16      for feature in layer: 
     17          # Getting the geometry for the feature. 
     18          g = feature.geom 
     19 
     20          # Getting the 'description' field for the feature. 
     21          desc = feature['description'] 
     22 
     23          # We can also increment through all of the fields 
     24          #  attached to this feature. 
     25          for field in feature: 
     26              # Get the name of the field (e.g. 'description') 
     27              nm = field.name 
     28 
     29              # Get the type (integer) of the field, e.g. 0 => OFTInteger 
     30              t = field.type 
     31 
     32              # Returns the value the field; OFTIntegers return ints, 
     33              #  OFTReal returns floats, all else returns string. 
     34              val = field.value 
     35""" 
     36# ctypes prerequisites. 
     37from ctypes import byref, c_void_p 
    438 
    539# The GDAL C library, OGR exceptions, and the Layer object. 
    6 from django.contrib.gis.gdal.libgdal import lgdal 
    7 from django.contrib.gis.gdal.error import OGRException, OGRIndexError, check_err 
     40from django.contrib.gis.gdal.driver import Driver 
     41from django.contrib.gis.gdal.error import OGRException, OGRIndexError 
    842from django.contrib.gis.gdal.layer import Layer 
    9 from django.contrib.gis.gdal.driver import Driver 
    1043 
    11 """ 
    12   DataSource is a wrapper for the OGR Data Source object, which provides 
    13    an interface for reading vector geometry data from many different file 
    14    formats (including ESRI shapefiles). 
    15  
    16   When instantiating a DataSource object, use the filename of a 
    17    GDAL-supported data source.  For example, a SHP file or a 
    18    TIGER/Line file from the government. 
    19  
    20   The ds_driver keyword is used internally when a ctypes pointer 
    21     is passed in directly. 
    22  
    23   Example: 
    24     ds = DataSource('/home/foo/bar.shp') 
    25     for layer in ds: 
    26         for feature in layer: 
    27             # Getting the geometry for the feature. 
    28             g = feature.geom 
    29  
    30             # Getting the 'description' field for the feature. 
    31             desc = feature['description'] 
    32  
    33             # We can also increment through all of the fields 
    34             #  attached to this feature. 
    35             for field in feature: 
    36                 # Get the name of the field (e.g. 'description') 
    37                 nm = field.name 
    38  
    39                 # Get the type (integer) of the field, e.g. 0 => OFTInteger 
    40                 t = field.type 
    41  
    42                 # Returns the value the field; OFTIntegers return ints, 
    43                 #  OFTReal returns floats, all else returns string. 
    44                 val = field.value 
    45 """ 
     44# Getting the ctypes prototypes for the DataSource. 
     45from django.contrib.gis.gdal.prototypes.ds import \ 
     46    destroy_ds, get_driver_count, register_all, open_ds, release_ds, \ 
     47    get_ds_name, get_layer, get_layer_count, get_layer_by_name 
    4648 
    4749# For more information, see the OGR C API source code: 
     
    4951# 
    5052# The OGR_DS_* routines are relevant here. 
    51  
    5253class DataSource(object): 
    5354    "Wraps an OGR Data Source object." 
    5455 
    5556    #### Python 'magic' routines #### 
    56     def __init__(self, ds_input, ds_driver=False): 
     57    def __init__(self, ds_input, ds_driver=False, write=False): 
    5758 
    58         self._ds = None # Initially NULL 
     59        # DataSource pointer is initially NULL. 
     60        self._ptr = None 
     61 
     62        # The write flag. 
     63        if write: 
     64            self._write = 1 
     65        else: 
     66            self._write = 0 
    5967 
    6068        # Registering all the drivers, this needs to be done 
    6169        #  _before_ we try to open up a data source. 
    62         if not lgdal.OGRGetDriverCount() and not lgdal.OGRRegisterAll(): 
     70        if not get_driver_count() and not register_all(): 
    6371            raise OGRException('Could not register all the OGR data source drivers!') 
    6472 
    65         if isinstance(ds_input, StringType): 
    66  
     73        if isinstance(ds_input, basestring): 
    6774            # The data source driver is a void pointer. 
    6875            ds_driver = c_void_p() 
    6976 
    7077            # OGROpen will auto-detect the data source type. 
    71             ds = lgdal.OGROpen(c_char_p(ds_input), c_int(0), byref(ds_driver)) 
     78            ds = open_ds(ds_input, self._write, byref(ds_driver)) 
    7279        elif isinstance(ds_input, c_void_p) and isinstance(ds_driver, c_void_p): 
    7380            ds = ds_input 
    7481        else: 
    75             raise OGRException('Invalid data source input type: %s' % str(type(ds_input))) 
     82            raise OGRException('Invalid data source input type: %s' % type(ds_input)) 
    7683 
    77         # Raise an exception if the returned pointer is NULL 
    78         if not ds: 
    79             self._ds = False 
     84        if bool(ds): 
     85            self._ptr = ds 
     86            self._driver = Driver(ds_driver) 
     87        else: 
     88            # Raise an exception if the returned pointer is NULL  
    8089            raise OGRException('Invalid data source file "%s"' % ds_input) 
    81         else: 
    82             self._ds = ds 
    83             self._driver = Driver(ds_driver) 
    8490 
    8591    def __del__(self): 
    86         "This releases the reference to the data source (destroying it if it's the only one)." 
    87         if self._ds: lgdal.OGRReleaseDataSource(self._ds
     92        "Destroys this DataStructure object." 
     93        if self._ptr: destroy_ds(self._ptr
    8894 
    8995    def __iter__(self): 
    9096        "Allows for iteration over the layers in a data source." 
    9197        for i in xrange(self.layer_count): 
    92             yield self.__getitem__(i) 
     98            yield self[i] 
    9399 
    94100    def __getitem__(self, index): 
    95101        "Allows use of the index [] operator to get a layer at the index." 
    96         if isinstance(index, StringType): 
    97             l = lgdal.OGR_DS_GetLayerByName(self._ds, c_char_p(index)
     102        if isinstance(index, basestring): 
     103            l = get_layer_by_name(self._ptr, index
    98104            if not l: raise OGRIndexError('invalid OGR Layer name given: "%s"' % index) 
    99         else
     105        elif isinstance(index, int)
    100106            if index < 0 or index >= self.layer_count: 
    101107                raise OGRIndexError('index out of range') 
    102             l = lgdal.OGR_DS_GetLayer(self._ds, c_int(index)) 
     108            l = get_layer(self._ptr, index) 
     109        else: 
     110            raise TypeError('Invalid index type: %s' % type(index)) 
    103111        return Layer(l) 
    104112         
     
    120128    def layer_count(self): 
    121129        "Returns the number of layers in the data source." 
    122         return lgdal.OGR_DS_GetLayerCount(self._ds
     130        return get_layer_count(self._ptr
    123131 
    124132    @property 
    125133    def name(self): 
    126134        "Returns the name of the data source." 
    127         return string_at(lgdal.OGR_DS_GetName(self._ds)) 
    128  
     135        return get_ds_name(self._ptr) 
  • django/branches/gis/django/contrib/gis/gdal/driver.py

    r6639 r6686  
    1 # types and ctypes 
    2 from types import StringType 
    3 from ctypes import c_char_p, c_int, c_void_p, byref, string_at 
    4  
    5 # The GDAL C library, OGR exceptions, and the Layer object. 
    6 from django.contrib.gis.gdal.libgdal import lgdal 
     1# prerequisites imports  
     2from ctypes import c_void_p 
    73from django.contrib.gis.gdal.error import OGRException 
     4from django.contrib.gis.gdal.prototypes.ds import \ 
     5    get_driver, get_driver_by_name, get_driver_count, get_driver_name, register_all 
    86 
    97# For more information, see the OGR C API source code: 
     
    119# 
    1210# The OGR_Dr_* routines are relevant here. 
    13  
    1411class Driver(object): 
    1512    "Wraps an OGR Data Source Driver." 
     
    2320              } 
    2421                 
    25     def __init__(self, input, ptr=False): 
     22    def __init__(self, dr_input): 
    2623        "Initializes an OGR driver on either a string or integer input." 
    2724 
    28         if isinstance(input, StringType): 
     25        if isinstance(dr_input, basestring): 
    2926            # If a string name of the driver was passed in 
    30             self._dr = None # Initially NULL 
     27            self._ptr = None # Initially NULL 
    3128            self._register() 
    3229 
    3330            # Checking the alias dictionary (case-insensitive) to see if an alias 
    3431            #  exists for the given driver. 
    35             if input.lower() in self._alias: 
    36                 name = c_char_p(self._alias[input.lower()]) 
     32            if dr_input.lower() in self._alias: 
     33                name = self._alias[dr_input.lower()] 
    3734            else: 
    38                 name = c_char_p(input) 
     35                name = dr_input 
    3936 
    4037            # Attempting to get the OGR driver by the string name. 
    41             dr = lgdal.OGRGetDriverByName(name) 
    42         elif isinstance(input, int): 
     38            dr = get_driver_by_name(name) 
     39        elif isinstance(dr_input, int): 
    4340            self._register() 
    44             dr = lgdal.OGRGetDriver(c_int(input)
    45         elif isinstance(input, c_void_p): 
    46             dr = input 
     41            dr = get_driver(dr_input
     42        elif isinstance(dr_input, c_void_p): 
     43            dr = dr_input 
    4744        else: 
    48             raise OGRException('Unrecognized input type for OGR Driver: %s' % str(type(input))) 
     45            raise OGRException('Unrecognized input type for OGR Driver: %s' % str(type(dr_input))) 
    4946 
    5047        # Making sure we get a valid pointer to the OGR Driver 
    5148        if not dr: 
    52             raise OGRException('Could not initialize OGR Driver on input: %s' % str(input)) 
    53         self._dr = dr 
     49            raise OGRException('Could not initialize OGR Driver on input: %s' % str(dr_input)) 
     50        self._ptr = dr 
    5451 
    5552    def __str__(self): 
    5653        "Returns the string name of the OGR Driver." 
    57         return string_at(lgdal.OGR_Dr_GetName(self._dr)
     54        return get_driver_name(self._ptr
    5855 
    5956    def _register(self): 
     
    6158        # Only register all if the driver count is 0 (or else all drivers 
    6259        #  will be registered over and over again) 
    63         if not self.driver_count and not lgdal.OGRRegisterAll(): 
     60        if not self.driver_count and not register_all(): 
    6461            raise OGRException('Could not register all the OGR data source drivers!') 
    6562                     
     
    6865    def driver_count(self): 
    6966        "Returns the number of OGR data source drivers registered." 
    70         return lgdal.OGRGetDriverCount() 
    71      
    72     def create_ds(self, **kwargs): 
    73         "Creates a data source using the keyword args as name value options." 
    74         raise NotImplementedError 
    75         # Getting the options string 
    76         #options = '' 
    77         #n_opts = len(kwargs) 
    78         #for i in xrange(n_opts): 
    79         #    options += '%s=%s' % (str(k), str(v)) 
    80         #    if i < n_opts-1: options += ',' 
    81         #opts = c_char_p(options) 
    82          
    83          
    84          
    85      
     67        return get_driver_count() 
  • django/branches/gis/django/contrib/gis/gdal/envelope.py

    r6436 r6686  
    11""" 
    22 The GDAL/OGR library uses an Envelope structure to hold the bounding 
    3   box information for a geometry.  The envelope (bounding box) contains 
    4   two pairs of coordinates, one for the lower left coordinate and one 
    5   for the upper right coordinate: 
     3 box information for a geometry.  The envelope (bounding box) contains 
     4 two pairs of coordinates, one for the lower left coordinate and one 
     5 for the upper right coordinate: 
    66 
    7                             +----------o Upper right; (max_x, max_y) 
    8                             |          | 
    9                             |          | 
    10                             |          | 
    11   Lower left (min_x, min_y) o----------+ 
    12    
     7                           +----------o Upper right; (max_x, max_y) 
     8                           |          | 
     9                           |          | 
     10                           |          | 
     11 Lower left (min_x, min_y) o----------+ 
    1312""" 
    1413from ctypes import Structure, c_double 
     
    3029    """ 
    3130    The Envelope object is a C structure that contains the minimum and 
    32     maximum X, Y coordinates for a rectangle bounding box.  The naming 
    33     of the variables is compatible with the OGR Envelope structure. 
     31    maximum X, Y coordinates for a rectangle bounding box.  The naming 
     32    of the variables is compatible with the OGR Envelope structure. 
    3433    """ 
    3534 
     
    3736        """ 
    3837        The initialization function may take an OGREnvelope structure, 4-element 
    39         tuple or list, or 4 individual arguments. 
     38        tuple or list, or 4 individual arguments. 
    4039        """ 
    4140         
  • django/branches/gis/django/contrib/gis/gdal/error.py

    r6412 r6686  
    11""" 
    2   This module houses the OGR & SRS Exception objects, and the 
    3    check_err() routine which checks the status code returned by 
    4    OGR methods. 
     2 This module houses the OGR & SRS Exception objects, and the 
     3 check_err() routine which checks the status code returned by 
     4 OGR methods. 
    55""" 
    6  
    7 # OGR & SRS Exceptions 
     6#### OGR & SRS Exceptions #### 
    87class OGRException(Exception): pass 
    98class SRSException(Exception): pass 
     
    1615    """ 
    1716    silent_variable_failure = True 
     17 
     18#### OGR error checking codes and routine #### 
    1819 
    1920# OGR Error Codes 
     
    3738        raise e, msg 
    3839    else: 
    39         raise OGRException, 'Unknown error code: "%s"' % code 
     40        raise OGRException('Unknown error code: "%s"' % code) 
  • django/branches/gis/django/contrib/gis/gdal/feature.py

    r6639 r6686  
    1 # types and ctypes 
    2 from types import StringType 
    3 from ctypes import c_char_p, c_int, c_void_p, string_at 
    4  
    51# The GDAL C library, OGR exception, and the Field object 
    6 from django.contrib.gis.gdal.libgdal import lgdal 
    72from django.contrib.gis.gdal.error import OGRException, OGRIndexError 
    83from django.contrib.gis.gdal.field import Field 
    94from django.contrib.gis.gdal.geometries import OGRGeometry, OGRGeomType 
    105from django.contrib.gis.gdal.srs import SpatialReference 
     6 
     7# ctypes function prototypes 
     8from django.contrib.gis.gdal.prototypes.ds import \ 
     9    destroy_feature, feature_equal, get_fd_geom_type, get_feat_geom_ref, \ 
     10    get_feat_name, get_feat_field_count, get_fid, get_field_defn, \ 
     11    get_field_index 
     12from django.contrib.gis.gdal.prototypes.geom import clone_geom, get_geom_srs 
     13from django.contrib.gis.gdal.prototypes.srs import clone_srs 
    1114 
    1215# For more information, see the OGR C API source code: 
     
    1922    #### Python 'magic' routines #### 
    2023    def __init__(self, feat, fdefn): 
    21         "Needs a C pointer (Python integer in ctypes) in order to initialize." 
    22         self._feat = None # Initially NULL 
    23         self._fdefn = None  
     24        "Initializes on the pointers for the feature and the layer definition." 
     25        self._ptr = None # Initially NULL 
    2426        if not feat or not fdefn: 
    2527            raise OGRException('Cannot create OGR Feature, invalid pointer given.') 
    26         self._feat = feat 
     28        self._ptr = feat 
    2729        self._fdefn = fdefn 
    2830 
    2931    def __del__(self): 
    3032        "Releases a reference to this object." 
    31         if self._feat: lgdal.OGR_F_Destroy(self._feat
     33        if self._ptr: destroy_feature(self._ptr
    3234 
    3335    def __getitem__(self, index): 
    3436        "Gets the Field at the specified index." 
    35         if isinstance(index, StringType): 
     37        if isinstance(index, basestring): 
    3638            i = self.index(index) 
    3739        else: 
     
    3941                raise OGRIndexError('index out of range') 
    4042            i = index 
    41         return Field(lgdal.OGR_F_GetFieldDefnRef(self._feat, c_int(i)), 
    42                      string_at(lgdal.OGR_F_GetFieldAsString(self._feat, c_int(i)))) 
     43        return Field(self._ptr, i) 
    4344     
    4445    def __iter__(self): 
    4546        "Iterates over each field in the Feature." 
    4647        for i in xrange(self.num_fields): 
    47             yield self.__getitem__(i) 
     48            yield self[i] 
    4849 
    4950    def __len__(self): 
     
    5758    def __eq__(self, other): 
    5859        "Does equivalence testing on the features." 
    59         if lgdal.OGR_F_Equal(self._feat, other._feat): 
    60             return True 
    61         else: 
    62             return False 
     60        return bool(feature_equal(self._ptr, other._ptr)) 
    6361 
    6462    #### Feature Properties #### 
     
    6664    def fid(self): 
    6765        "Returns the feature identifier." 
    68         return lgdal.OGR_F_GetFID(self._feat
     66        return get_fid(self._ptr
    6967         
    7068    @property 
    7169    def layer_name(self): 
    7270        "Returns the name of the layer for the feature." 
    73         return string_at(lgdal.OGR_FD_GetName(self._fdefn)
     71        return get_feat_name(self._fdefn
    7472 
    7573    @property 
    7674    def num_fields(self): 
    7775        "Returns the number of fields in the Feature." 
    78         return lgdal.OGR_F_GetFieldCount(self._feat
     76        return get_feat_field_count(self._ptr
    7977 
    8078    @property 
    8179    def fields(self): 
    8280        "Returns a list of fields in the Feature." 
    83         return [ string_at(lgdal.OGR_Fld_GetNameRef(lgdal.OGR_FD_GetFieldDefn(self._fdefn, i))) 
    84                  for i in xrange(self.num_fields) ] 
     81        return [get_field_name(get_field_defn(self._fdefn, i))  
     82                for i in xrange(self.num_fields)] 
     83 
    8584    @property 
    8685    def geom(self): 
    8786        "Returns the OGR Geometry for this Feature." 
    8887        # Retrieving the geometry pointer for the feature. 
    89         geom_ptr = lgdal.OGR_F_GetGeometryRef(self._feat) 
    90         if not geom_ptr: 
    91             raise OGRException('Cannot retrieve Geometry from the feature.') 
     88        geom_ptr = get_feat_geom_ref(self._ptr) 
    9289 
    9390        # Attempting to retrieve the Spatial Reference for the geometry. 
    94         srs_ptr  = lgdal.OSRClone(lgdal.OGR_G_GetSpatialReference(geom_ptr)) 
    95         if srs_ptr: 
    96             srs = SpatialReference(srs_ptr, 'ogr') 
    97         else
     91        try: 
     92            srs_ptr = get_geom_srs(geom_ptr) 
     93            srs = SpatialReference(clone_srs(srs_ptr))  
     94        except OGRException
    9895            srs = None 
    99  
    100         # Geometry is cloned so the feature isn't invalidated. 
    101         return OGRGeometry(c_void_p(lgdal.OGR_G_Clone(geom_ptr)), srs) 
    102  
     96        # Geometry is cloned so the feature isn't invalidated.  
     97        return OGRGeometry(clone_geom(geom_ptr), srs) 
     98     
    10399    @property 
    104100    def geom_type(self): 
    105101        "Returns the OGR Geometry Type for this Feture." 
    106         return OGRGeomType(lgdal.OGR_FD_GetGeomType(self._fdefn)) 
     102        return OGRGeomType(get_fd_geom_type(self._fdefn)) 
    107103     
    108104    #### Feature Methods #### 
     
    114110        """ 
    115111        field_name = getattr(field, 'name', field) 
    116         return self.__getitem__(field_name).value 
     112        return self[field_name].value 
    117113 
    118114    def index(self, field_name): 
    119115        "Returns the index of the given field name." 
    120         i = lgdal.OGR_F_GetFieldIndex(self._feat, c_char_p(field_name)
     116        i = get_field_index(self._ptr, field_name
    121117        if i < 0: raise OGRIndexError('invalid OFT field name given: "%s"' % field_name) 
    122118        return i 
    123  
    124     def clone(self): 
    125         "Clones this Feature." 
    126         return Feature(lgdal.OGR_F_Clone(self._feat)) 
  • django/branches/gis/django/contrib/gis/gdal/field.py

    r6639 r6686  
    1 from ctypes import string_a
    2 from django.contrib.gis.gdal.libgdal import lgdal 
     1from ctypes import byref, c_in
     2from datetime import date, datetime, time 
    33from django.contrib.gis.gdal.error import OGRException 
     4from django.contrib.gis.gdal.prototypes.ds import \ 
     5    get_feat_field_defn, get_field_as_datetime, get_field_as_double, \ 
     6    get_field_as_integer, get_field_as_string, get_field_name, get_field_precision, \ 
     7    get_field_type, get_field_type_name, get_field_width 
    48 
    59# For more information, see the OGR C API source code: 
     
    1115 
    1216    #### Python 'magic' routines #### 
    13     def __init__(self, fld, val=''): 
    14         "Needs a C pointer (Python integer in ctypes) in order to initialize." 
    15         self._fld = None # Initially NULL 
    16  
     17    def __init__(self, feat, index): 
     18        """ 
     19        Initializes on the feature pointer and the integer index of 
     20        the field within the feature. 
     21        """ 
     22        # Setting the feature pointer and index. 
     23        self._feat = feat 
     24        self._index = index 
     25         
     26        # Getting the pointer for this field. 
     27        fld = get_feat_field_defn(feat, index) 
    1728        if not fld: 
    1829            raise OGRException('Cannot create OGR Field, invalid pointer given.') 
    19         self._fld = fld 
    20         self._val = val 
     30        self._ptr = fld 
    2131 
    2232        # Setting the class depending upon the OGR Field Type (OFT) 
    2333        self.__class__ = FIELD_CLASSES[self.type] 
    2434 
     35        # OFTReal with no precision should be an OFTInteger. 
     36        if isinstance(self, OFTReal) and self.precision == 0: 
     37            self.__class__ = OFTInteger 
     38 
    2539    def __str__(self): 
    2640        "Returns the string representation of the Field." 
    27         return '%s (%s)' % (self.name, self.value) 
     41        return str(self.value).strip() 
     42 
     43    #### Field Methods #### 
     44    def as_double(self): 
     45        "Retrieves the Field's value as a double (float)." 
     46        return get_field_as_double(self._feat, self._index) 
     47 
     48    def as_int(self): 
     49        "Retrieves the Field's value as an integer." 
     50        return get_field_as_integer(self._feat, self._index) 
     51 
     52    def as_string(self): 
     53        "Retrieves the Field's value as a string." 
     54        return get_field_as_string(self._feat, self._index) 
     55 
     56    def as_datetime(self): 
     57        "Retrieves the Field's value as a tuple of date & time components." 
     58        yy, mm, dd, hh, mn, ss, tz = [c_int() for i in range(7)] 
     59        status = get_field_as_datetime(self._feat, self._index, byref(yy), byref(mm), byref(dd), 
     60                                       byref(hh), byref(mn), byref(ss), byref(tz)) 
     61        if status: 
     62            return (yy, mm, dd, hh, mn, ss, tz) 
     63        else: 
     64            raise OGRException('Unable to retrieve date & time information from the field.') 
    2865 
    2966    #### Field Properties #### 
    3067    @property 
    3168    def name(self): 
    32         "Returns the name of the field." 
    33         return string_at(lgdal.OGR_Fld_GetNameRef(self._fld)) 
     69        "Returns the name of this Field." 
     70        return get_field_name(self._ptr) 
     71 
     72    @property 
     73    def precision(self): 
     74        "Returns the precision of this Field." 
     75        return get_field_precision(self._ptr) 
    3476 
    3577    @property 
    3678    def type(self): 
    37         "Returns the type of this field." 
    38         return lgdal.OGR_Fld_GetType(self._fld) 
     79        "Returns the OGR type of this Field." 
     80        return get_field_type(self._ptr) 
     81 
     82    @property 
     83    def type_name(self): 
     84        "Return the OGR field type name for this Field." 
     85        return get_field_type_name(self.type) 
    3986 
    4087    @property 
    4188    def value(self): 
    42         "Returns the value of this type of field." 
    43         return self._val 
     89        "Returns the value of this Field." 
     90        # Default is to get the field as a string. 
     91        return self.as_string() 
    4492 
    45 # The Field sub-classes for each OGR Field type. 
     93    @property 
     94    def width(self): 
     95        "Returns the width of this Field." 
     96        return get_field_width(self._ptr) 
     97 
     98### The Field sub-classes for each OGR Field type. ### 
    4699class OFTInteger(Field): 
    47100    @property 
    48101    def value(self): 
    49102        "Returns an integer contained in this field." 
    50         try: 
    51             return int(self._val) 
    52         except ValueError: 
    53             return None 
    54 class OFTIntegerList(Field): pass 
     103        return self.as_int() 
     104 
     105    @property 
     106    def type(self): 
     107        """ 
     108        GDAL uses OFTReals to represent OFTIntegers in created 
     109        shapefiles -- forcing the type here since the underlying field 
     110        type may actually be OFTReal. 
     111        """ 
     112        return 0 
    55113 
    56114class OFTReal(Field): 
     
    58116    def value(self): 
    59117        "Returns a float contained in this field." 
    60         try: 
    61             return float(self._val) 
    62         except ValueError: 
    63             return None 
     118        return self.as_double() 
     119 
     120# String & Binary fields, just subclasses 
     121class OFTString(Field): pass 
     122class OFTWideString(Field): pass 
     123class OFTBinary(Field): pass 
     124 
     125# OFTDate, OFTTime, OFTDateTime fields. 
     126class OFTDate(Field): 
     127    @property 
     128    def value(self): 
     129        "Returns a Python `date` object for the OFTDate field." 
     130        yy, mm, dd, hh, mn, ss, tz = self.as_datetime() 
     131        return date(yy.value, mm.value, dd.value) 
     132 
     133class OFTDateTime(Field): 
     134    @property 
     135    def value(self): 
     136        "Returns a Python `datetime` object for this OFTDateTime field." 
     137        yy, mm, dd, hh, mn, ss, tz = self.as_datetime() 
     138        # TODO: Adapt timezone information. 
     139        #  See http://lists.maptools.org/pipermail/gdal-dev/2006-February/007990.html 
     140        #  The `tz` variable has values of: 0=unknown, 1=localtime (ambiguous),  
     141        #  100=GMT, 104=GMT+1, 80=GMT-5, etc. 
     142        return datetime(yy.value, mm.value, dd.value, hh.value, mn.value, ss.value) 
     143 
     144class OFTTime(Field): 
     145    @property 
     146    def value(self): 
     147        "Returns a Python `time` object for this OFTTime field." 
     148        yy, mm, dd, hh, mn, ss, tz = self.as_datetime() 
     149        return time(hh.value, mn.value, ss.value) 
     150 
     151# List fields are also just subclasses 
     152class OFTIntegerList(Field): pass 
    64153class OFTRealList(Field): pass 
    65  
    66 class OFTString(Field): 
    67     def __str__(self): 
    68         return '%s ("%s")' % (self.name, self.value) 
    69      
    70154class OFTStringList(Field): pass 
    71 class OFTWideString(Field): pass 
    72155class OFTWideStringList(Field): pass 
    73 class OFTBinary(Field): pass 
    74 class OFTDate(Field): pass 
    75 class OFTTime(Field): pass 
    76 class OFTDateTime(Field): pass 
    77156 
    78157# Class mapping dictionary for OFT Types 
  • django/branches/gis/django/contrib/gis/gdal/geometries.py

    r6464 r6686  
    11""" 
    2   The OGRGeometry is a wrapper for using the OGR Geometry class 
    3    (see http://www.gdal.org/ogr/classOGRGeometry.html).  OGRGeometry 
    4    may be instantiated when reading geometries from OGR Data Sources 
    5    (e.g. SHP files), or when given OGC WKT (a string). 
    6  
    7   While the 'full' API is not present yet, the API is "pythonic" unlike 
    8    the traditional and "next-generation" OGR Python bindings.  One major 
    9    advantage OGR Geometries have over their GEOS counterparts is support 
    10    for spatial reference systems and their transformation. 
    11  
    12   Example: 
    13     >>> from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, SpatialReference 
    14     >>> wkt1, wkt2 = 'POINT(-90 30)', 'POLYGON((0 0, 5 0, 5 5, 0 5)' 
    15     >>> pnt = OGRGeometry(wkt1) 
    16     >>> print pnt 
    17     POINT (-90 30) 
    18     >>> mpnt = OGRGeometry(OGRGeomType('MultiPoint'), SpatialReference('WGS84')) 
    19     >>> mpnt.add(wkt1) 
    20     >>> mpnt.add(wkt1) 
    21     >>> print mpnt 
    22     MULTIPOINT (-90 30,-90 30) 
    23     >>> print mpnt.srs.name 
    24     WGS 84 
    25     >>> print mpnt.srs.proj 
    26     +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs 
    27     >>> mpnt.transform_to(SpatialReference('NAD27')) 
    28     >>> print mpnt.proj 
    29     +proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs 
    30     >>> print mpnt 
    31     MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641) 
    32      
     2 The OGRGeometry is a wrapper for using the OGR Geometry class 
     3 (see http://www.gdal.org/ogr/classOGRGeometry.html).  OGRGeometry 
     4 may be instantiated when reading geometries from OGR Data Sources 
     5 (e.g. SHP files), or when given OGC WKT (a string). 
     6 
     7 While the 'full' API is not present yet, the API is "pythonic" unlike 
     8 the traditional and "next-generation" OGR Python bindings.  One major 
     9 advantage OGR Geometries have over their GEOS counterparts is support 
     10 for spatial reference systems and their transformation. 
     11 
     12 Example: 
     13  >>> from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, SpatialReference 
     14  >>> wkt1, wkt2 = 'POINT(-90 30)', 'POLYGON((0 0, 5 0, 5 5, 0 5)' 
     15  >>> pnt = OGRGeometry(wkt1) 
     16  >>> print pnt 
     17  POINT (-90 30) 
     18  >>> mpnt = OGRGeometry(OGRGeomType('MultiPoint'), SpatialReference('WGS84')) 
     19  >>> mpnt.add(wkt1) 
     20  >>> mpnt.add(wkt1) 
     21  >>> print mpnt 
     22  MULTIPOINT (-90 30,-90 30) 
     23  >>> print mpnt.srs.name 
     24  WGS 84 
     25  >>> print mpnt.srs.proj 
     26  +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs 
     27  >>> mpnt.transform_to(SpatialReference('NAD27')) 
     28  >>> print mpnt.proj 
     29  +proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs 
     30  >>> print mpnt 
     31  MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641) 
     32   
    3333  The OGRGeomType class is to make it easy to specify an OGR geometry type: 
    34     >>> from django.contrib.gis.gdal import OGRGeomType 
    35     >>> gt1 = OGRGeomType(3) # Using an integer for the type 
    36     >>> gt2 = OGRGeomType('Polygon') # Using a string 
    37     >>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive 
    38     >>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects 
    39     True 
     34  >>> from django.contrib.gis.gdal import OGRGeomType 
     35  >>> gt1 = OGRGeomType(3) # Using an integer for the type 
     36  >>> gt2 = OGRGeomType('Polygon') # Using a string 
     37  >>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive 
     38  >>> print gt1 == 3, gt1 == 'Polygon' # Equivalence works w/non-OGRGeomType objects 
     39  True 
    4040""" 
    41 # Python library imports 
     41# Python library requisites. 
    4242import re, sys 
    43 from binascii import a2b_hex, b2a_hex 
    44 from ctypes import byref, create_string_buffer, string_at, c_char_p, c_double, c_int, c_void_p 
     43from binascii import a2b_hex 
     44from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p 
    4545from types import BufferType, IntType, StringType, UnicodeType 
    4646 
    4747# Getting GDAL prerequisites 
    48 from django.contrib.gis.gdal.libgdal import lgdal 
    4948from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope 
    50 from django.contrib.gis.gdal.error import check_err, OGRException, OGRIndexError 
     49from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException 
    5150from django.contrib.gis.gdal.geomtype import OGRGeomType 
    5251from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform 
     52 
     53# Getting the ctypes prototype functions that interface w/the GDAL C library. 
     54from django.contrib.gis.gdal.prototypes.geom import * 
     55from django.contrib.gis.gdal.prototypes.srs import clone_srs 
    5356 
    5457# For more information, see the OGR C API source code: 
     
    5760# The OGR_G_* routines are relevant here. 
    5861 
    59 #### ctypes prototypes for functions that return double values #### 
    60 def pnt_func(f): 
    61     "For accessing point information." 
    62     f.restype = c_double 
    63     f.argtypes = [c_void_p, c_int] 
    64     return f 
    65 # GetX, GetY, GetZ all return doubles. 
    66 getx = pnt_func(lgdal.OGR_G_GetX) 
    67 gety = pnt_func(lgdal.OGR_G_GetY) 
    68 getz = pnt_func(lgdal.OGR_G_GetZ) 
    69  
    70 # GetArea returns a double. 
    71 get_area = lgdal.OGR_G_GetArea 
    72 get_area.restype = c_double 
    73 get_area.argtypes = [c_void_p] 
    74  
    75 # Regular expression for determining whether the input is HEXEWKB. 
     62# Regular expressions for recognizing HEXEWKB and WKT. 
    7663hex_regex = re.compile(r'^[0-9A-F]+$', re.I) 
     64wkt_regex = re.compile(r'^(?P<type>POINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)[ACEGIMLONPSRUTY\d,\.\-\(\) ]+$', re.I) 
    7765 
    7866#### OGRGeometry Class #### 
     
    8371        "Initializes Geometry on either WKT or an OGR pointer as input." 
    8472 
    85         self._g = c_void_p(None) # Initially NULL 
     73        self._ptr = c_void_p(None) # Initially NULL 
    8674 
    8775        # Checking if unicode 
     
    9583 
    9684        if isinstance(geom_input, StringType): 
    97             # First, trying the input as WKT 
    98             buf = c_char_p(geom_input) 
    99             g = c_void_p() 
    100  
    101             try: 
    102                 check_err(lgdal.OGR_G_CreateFromWkt(byref(buf), c_void_p(), byref(g))) 
    103             except OGRException: 
    104                 try: 
    105                     # Seeing if the input is a valid short-hand string 
    106                     ogr_t = OGRGeomType(geom_input) 
    107                     g = lgdal.OGR_G_CreateGeometry(ogr_t.num) 
    108                 except: 
    109                     raise OGRException('Could not initialize OGR Geometry from: %s' % geom_input) 
     85            m = wkt_regex.match(geom_input) 
     86            if m: 
     87                if m.group('type').upper() == 'LINEARRING': 
     88                    # OGR_G_CreateFromWkt doesn't work with LINEARRING WKT. 
     89                    #  See http://trac.osgeo.org/gdal/ticket/1992. 
     90                    g = create_geom(OGRGeomType(m.group('type')).num) 
     91                    import_wkt(g, byref(c_char_p(geom_input))) 
     92                else: 
     93                    g = from_wkt(byref(c_char_p(geom_input)), None, byref(c_void_p())) 
     94            else: 
     95                # Seeing if the input is a valid short-hand string 
     96                # (e.g., 'Point', 'POLYGON'). 
     97                ogr_t = OGRGeomType(geom_input) 
     98                g = create_geom(OGRGeomType(geom_input).num) 
    11099        elif isinstance(geom_input, BufferType): 
    111100            # WKB was passed in 
    112             g = c_void_p() 
    113             check_err(lgdal.OGR_G_CreateFromWkb(c_char_p(str(geom_input)), c_void_p(), byref(g), len(geom_input))) 
     101            g = from_wkb(str(geom_input), None, byref(c_void_p()), len(geom_input)) 
    114102        elif isinstance(geom_input, OGRGeomType): 
    115103            # OGRGeomType was passed in, an empty geometry will be created. 
    116             g = lgdal.OGR_G_CreateGeometry(geom_input.num) 
     104            g = create_geom(geom_input.num) 
    117105        elif isinstance(geom_input, c_void_p): 
    118106            #