app/django/contrib/gis/gdal/field.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     1 from ctypes import byref, c_int
       
     2 from datetime import date, datetime, time
       
     3 from django.contrib.gis.gdal.error import OGRException
       
     4 from 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
       
     8 
       
     9 # For more information, see the OGR C API source code:
       
    10 #  http://www.gdal.org/ogr/ogr__api_8h.html
       
    11 #
       
    12 # The OGR_Fld_* routines are relevant here.
       
    13 class Field(object):
       
    14     "A class that wraps an OGR Field, needs to be instantiated from a Feature object."
       
    15 
       
    16     #### Python 'magic' routines ####
       
    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)
       
    28         if not fld:
       
    29             raise OGRException('Cannot create OGR Field, invalid pointer given.')
       
    30         self._ptr = fld
       
    31 
       
    32         # Setting the class depending upon the OGR Field Type (OFT)
       
    33         self.__class__ = FIELD_CLASSES[self.type]
       
    34 
       
    35         # OFTReal with no precision should be an OFTInteger.
       
    36         if isinstance(self, OFTReal) and self.precision == 0:
       
    37             self.__class__ = OFTInteger
       
    38 
       
    39     def __str__(self):
       
    40         "Returns the string representation of the Field."
       
    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.')
       
    65 
       
    66     #### Field Properties ####
       
    67     @property
       
    68     def name(self):
       
    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)
       
    76 
       
    77     @property
       
    78     def type(self):
       
    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)
       
    86 
       
    87     @property
       
    88     def value(self):
       
    89         "Returns the value of this Field."
       
    90         # Default is to get the field as a string.
       
    91         return self.as_string()
       
    92 
       
    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. ###
       
    99 class OFTInteger(Field):
       
   100     @property
       
   101     def value(self):
       
   102         "Returns an integer contained in this field."
       
   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
       
   113 
       
   114 class OFTReal(Field):
       
   115     @property
       
   116     def value(self):
       
   117         "Returns a float contained in this field."
       
   118         return self.as_double()
       
   119 
       
   120 # String & Binary fields, just subclasses
       
   121 class OFTString(Field): pass
       
   122 class OFTWideString(Field): pass
       
   123 class OFTBinary(Field): pass
       
   124 
       
   125 # OFTDate, OFTTime, OFTDateTime fields.
       
   126 class 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         try:
       
   132             return date(yy.value, mm.value, dd.value)
       
   133         except ValueError:
       
   134             return None
       
   135 
       
   136 class OFTDateTime(Field):
       
   137     @property
       
   138     def value(self):
       
   139         "Returns a Python `datetime` object for this OFTDateTime field."
       
   140         yy, mm, dd, hh, mn, ss, tz = self.as_datetime()
       
   141         # TODO: Adapt timezone information.
       
   142         #  See http://lists.maptools.org/pipermail/gdal-dev/2006-February/007990.html
       
   143         #  The `tz` variable has values of: 0=unknown, 1=localtime (ambiguous), 
       
   144         #  100=GMT, 104=GMT+1, 80=GMT-5, etc.
       
   145         try:
       
   146             return datetime(yy.value, mm.value, dd.value, hh.value, mn.value, ss.value)
       
   147         except ValueError:
       
   148             return None
       
   149 
       
   150 class OFTTime(Field):
       
   151     @property
       
   152     def value(self):
       
   153         "Returns a Python `time` object for this OFTTime field."
       
   154         yy, mm, dd, hh, mn, ss, tz = self.as_datetime()
       
   155         try:
       
   156             return time(hh.value, mn.value, ss.value)
       
   157         except ValueError:
       
   158             return None
       
   159 
       
   160 # List fields are also just subclasses
       
   161 class OFTIntegerList(Field): pass
       
   162 class OFTRealList(Field): pass
       
   163 class OFTStringList(Field): pass
       
   164 class OFTWideStringList(Field): pass
       
   165 
       
   166 # Class mapping dictionary for OFT Types
       
   167 FIELD_CLASSES = { 0 : OFTInteger,
       
   168                   1 : OFTIntegerList,
       
   169                   2 : OFTReal,
       
   170                   3 : OFTRealList,
       
   171                   4 : OFTString,
       
   172                   5 : OFTStringList,
       
   173                   6 : OFTWideString,
       
   174                   7 : OFTWideStringList,
       
   175                   8 : OFTBinary,
       
   176                   9 : OFTDate,
       
   177                  10 : OFTTime,
       
   178                  11 : OFTDateTime,
       
   179                   }