/django/contrib/gis/gdal/field.py
Python | 186 lines | 128 code | 26 blank | 32 comment | 10 complexity | 1c97e6b9e0cd031036ba9cf75e5e4eea MD5 | raw file
Possible License(s): BSD-3-Clause
1from ctypes import byref, c_int 2from datetime import date, datetime, time 3from django.contrib.gis.gdal.base import GDALBase 4from django.contrib.gis.gdal.error import OGRException 5from django.contrib.gis.gdal.prototypes import ds as capi 6 7# For more information, see the OGR C API source code: 8# http://www.gdal.org/ogr/ogr__api_8h.html 9# 10# The OGR_Fld_* routines are relevant here. 11class Field(GDALBase): 12 "A class that wraps an OGR Field, needs to be instantiated from a Feature object." 13 14 #### Python 'magic' routines #### 15 def __init__(self, feat, index): 16 """ 17 Initializes on the feature pointer and the integer index of 18 the field within the feature. 19 """ 20 # Setting the feature pointer and index. 21 self._feat = feat 22 self._index = index 23 24 # Getting the pointer for this field. 25 fld_ptr = capi.get_feat_field_defn(feat, index) 26 if not fld_ptr: 27 raise OGRException('Cannot create OGR Field, invalid pointer given.') 28 self.ptr = fld_ptr 29 30 # Setting the class depending upon the OGR Field Type (OFT) 31 self.__class__ = OGRFieldTypes[self.type] 32 33 # OFTReal with no precision should be an OFTInteger. 34 if isinstance(self, OFTReal) and self.precision == 0: 35 self.__class__ = OFTInteger 36 self._double = True 37 38 def __str__(self): 39 "Returns the string representation of the Field." 40 return str(self.value).strip() 41 42 #### Field Methods #### 43 def as_double(self): 44 "Retrieves the Field's value as a double (float)." 45 return capi.get_field_as_double(self._feat, self._index) 46 47 def as_int(self): 48 "Retrieves the Field's value as an integer." 49 return capi.get_field_as_integer(self._feat, self._index) 50 51 def as_string(self): 52 "Retrieves the Field's value as a string." 53 return capi.get_field_as_string(self._feat, self._index) 54 55 def as_datetime(self): 56 "Retrieves the Field's value as a tuple of date & time components." 57 yy, mm, dd, hh, mn, ss, tz = [c_int() for i in range(7)] 58 status = capi.get_field_as_datetime(self._feat, self._index, byref(yy), byref(mm), byref(dd), 59 byref(hh), byref(mn), byref(ss), byref(tz)) 60 if status: 61 return (yy, mm, dd, hh, mn, ss, tz) 62 else: 63 raise OGRException('Unable to retrieve date & time information from the field.') 64 65 #### Field Properties #### 66 @property 67 def name(self): 68 "Returns the name of this Field." 69 return capi.get_field_name(self.ptr) 70 71 @property 72 def precision(self): 73 "Returns the precision of this Field." 74 return capi.get_field_precision(self.ptr) 75 76 @property 77 def type(self): 78 "Returns the OGR type of this Field." 79 return capi.get_field_type(self.ptr) 80 81 @property 82 def type_name(self): 83 "Return the OGR field type name for this Field." 84 return capi.get_field_type_name(self.type) 85 86 @property 87 def value(self): 88 "Returns the value of this Field." 89 # Default is to get the field as a string. 90 return self.as_string() 91 92 @property 93 def width(self): 94 "Returns the width of this Field." 95 return capi.get_field_width(self.ptr) 96 97### The Field sub-classes for each OGR Field type. ### 98class OFTInteger(Field): 99 _double = False 100 101 @property 102 def value(self): 103 "Returns an integer contained in this field." 104 if self._double: 105 # If this is really from an OFTReal field with no precision, 106 # read as a double and cast as Python int (to prevent overflow). 107 return int(self.as_double()) 108 else: 109 return self.as_int() 110 111 @property 112 def type(self): 113 """ 114 GDAL uses OFTReals to represent OFTIntegers in created 115 shapefiles -- forcing the type here since the underlying field 116 type may actually be OFTReal. 117 """ 118 return 0 119 120class OFTReal(Field): 121 @property 122 def value(self): 123 "Returns a float contained in this field." 124 return self.as_double() 125 126# String & Binary fields, just subclasses 127class OFTString(Field): pass 128class OFTWideString(Field): pass 129class OFTBinary(Field): pass 130 131# OFTDate, OFTTime, OFTDateTime fields. 132class OFTDate(Field): 133 @property 134 def value(self): 135 "Returns a Python `date` object for the OFTDate field." 136 try: 137 yy, mm, dd, hh, mn, ss, tz = self.as_datetime() 138 return date(yy.value, mm.value, dd.value) 139 except (ValueError, OGRException): 140 return None 141 142class OFTDateTime(Field): 143 @property 144 def value(self): 145 "Returns a Python `datetime` object for this OFTDateTime field." 146 # TODO: Adapt timezone information. 147 # See http://lists.maptools.org/pipermail/gdal-dev/2006-February/007990.html 148 # The `tz` variable has values of: 0=unknown, 1=localtime (ambiguous), 149 # 100=GMT, 104=GMT+1, 80=GMT-5, etc. 150 try: 151 yy, mm, dd, hh, mn, ss, tz = self.as_datetime() 152 return datetime(yy.value, mm.value, dd.value, hh.value, mn.value, ss.value) 153 except (ValueError, OGRException): 154 return None 155 156class OFTTime(Field): 157 @property 158 def value(self): 159 "Returns a Python `time` object for this OFTTime field." 160 try: 161 yy, mm, dd, hh, mn, ss, tz = self.as_datetime() 162 return time(hh.value, mn.value, ss.value) 163 except (ValueError, OGRException): 164 return None 165 166# List fields are also just subclasses 167class OFTIntegerList(Field): pass 168class OFTRealList(Field): pass 169class OFTStringList(Field): pass 170class OFTWideStringList(Field): pass 171 172# Class mapping dictionary for OFT Types and reverse mapping. 173OGRFieldTypes = { 0 : OFTInteger, 174 1 : OFTIntegerList, 175 2 : OFTReal, 176 3 : OFTRealList, 177 4 : OFTString, 178 5 : OFTStringList, 179 6 : OFTWideString, 180 7 : OFTWideStringList, 181 8 : OFTBinary, 182 9 : OFTDate, 183 10 : OFTTime, 184 11 : OFTDateTime, 185 } 186ROGRFieldTypes = dict([(cls, num) for num, cls in OGRFieldTypes.items()])