field.py 6.3 KB

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