You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

coordseq.py 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. """
  2. This module houses the GEOSCoordSeq object, which is used internally
  3. by GEOSGeometry to house the actual coordinates of the Point,
  4. LineString, and LinearRing geometries.
  5. """
  6. from ctypes import byref, c_double, c_uint
  7. from django.contrib.gis.geos import prototypes as capi
  8. from django.contrib.gis.geos.base import GEOSBase
  9. from django.contrib.gis.geos.error import GEOSException
  10. from django.contrib.gis.geos.libgeos import CS_PTR
  11. from django.contrib.gis.shortcuts import numpy
  12. class GEOSCoordSeq(GEOSBase):
  13. "The internal representation of a list of coordinates inside a Geometry."
  14. ptr_type = CS_PTR
  15. def __init__(self, ptr, z=False):
  16. "Initialize from a GEOS pointer."
  17. if not isinstance(ptr, CS_PTR):
  18. raise TypeError('Coordinate sequence should initialize with a CS_PTR.')
  19. self._ptr = ptr
  20. self._z = z
  21. def __iter__(self):
  22. "Iterate over each point in the coordinate sequence."
  23. for i in range(self.size):
  24. yield self[i]
  25. def __len__(self):
  26. "Return the number of points in the coordinate sequence."
  27. return int(self.size)
  28. def __str__(self):
  29. "Return the string representation of the coordinate sequence."
  30. return str(self.tuple)
  31. def __getitem__(self, index):
  32. "Return the coordinate sequence value at the given index."
  33. self._checkindex(index)
  34. return self._point_getter(index)
  35. def __setitem__(self, index, value):
  36. "Set the coordinate sequence value at the given index."
  37. # Checking the input value
  38. if isinstance(value, (list, tuple)):
  39. pass
  40. elif numpy and isinstance(value, numpy.ndarray):
  41. pass
  42. else:
  43. raise TypeError('Must set coordinate with a sequence (list, tuple, or numpy array).')
  44. # Checking the dims of the input
  45. if self.dims == 3 and self._z:
  46. n_args = 3
  47. point_setter = self._set_point_3d
  48. else:
  49. n_args = 2
  50. point_setter = self._set_point_2d
  51. if len(value) != n_args:
  52. raise TypeError('Dimension of value does not match.')
  53. self._checkindex(index)
  54. point_setter(index, value)
  55. # #### Internal Routines ####
  56. def _checkindex(self, index):
  57. "Check the given index."
  58. if not (0 <= index < self.size):
  59. raise IndexError('invalid GEOS Geometry index: %s' % index)
  60. def _checkdim(self, dim):
  61. "Check the given dimension."
  62. if dim < 0 or dim > 2:
  63. raise GEOSException('invalid ordinate dimension "%d"' % dim)
  64. def _get_x(self, index):
  65. return capi.cs_getx(self.ptr, index, byref(c_double()))
  66. def _get_y(self, index):
  67. return capi.cs_gety(self.ptr, index, byref(c_double()))
  68. def _get_z(self, index):
  69. return capi.cs_getz(self.ptr, index, byref(c_double()))
  70. def _set_x(self, index, value):
  71. capi.cs_setx(self.ptr, index, value)
  72. def _set_y(self, index, value):
  73. capi.cs_sety(self.ptr, index, value)
  74. def _set_z(self, index, value):
  75. capi.cs_setz(self.ptr, index, value)
  76. @property
  77. def _point_getter(self):
  78. return self._get_point_3d if self.dims == 3 and self._z else self._get_point_2d
  79. def _get_point_2d(self, index):
  80. return (self._get_x(index), self._get_y(index))
  81. def _get_point_3d(self, index):
  82. return (self._get_x(index), self._get_y(index), self._get_z(index))
  83. def _set_point_2d(self, index, value):
  84. x, y = value
  85. self._set_x(index, x)
  86. self._set_y(index, y)
  87. def _set_point_3d(self, index, value):
  88. x, y, z = value
  89. self._set_x(index, x)
  90. self._set_y(index, y)
  91. self._set_z(index, z)
  92. # #### Ordinate getting and setting routines ####
  93. def getOrdinate(self, dimension, index):
  94. "Return the value for the given dimension and index."
  95. self._checkindex(index)
  96. self._checkdim(dimension)
  97. return capi.cs_getordinate(self.ptr, index, dimension, byref(c_double()))
  98. def setOrdinate(self, dimension, index, value):
  99. "Set the value for the given dimension and index."
  100. self._checkindex(index)
  101. self._checkdim(dimension)
  102. capi.cs_setordinate(self.ptr, index, dimension, value)
  103. def getX(self, index):
  104. "Get the X value at the index."
  105. return self.getOrdinate(0, index)
  106. def setX(self, index, value):
  107. "Set X with the value at the given index."
  108. self.setOrdinate(0, index, value)
  109. def getY(self, index):
  110. "Get the Y value at the given index."
  111. return self.getOrdinate(1, index)
  112. def setY(self, index, value):
  113. "Set Y with the value at the given index."
  114. self.setOrdinate(1, index, value)
  115. def getZ(self, index):
  116. "Get Z with the value at the given index."
  117. return self.getOrdinate(2, index)
  118. def setZ(self, index, value):
  119. "Set Z with the value at the given index."
  120. self.setOrdinate(2, index, value)
  121. # ### Dimensions ###
  122. @property
  123. def size(self):
  124. "Return the size of this coordinate sequence."
  125. return capi.cs_getsize(self.ptr, byref(c_uint()))
  126. @property
  127. def dims(self):
  128. "Return the dimensions of this coordinate sequence."
  129. return capi.cs_getdims(self.ptr, byref(c_uint()))
  130. @property
  131. def hasz(self):
  132. """
  133. Return whether this coordinate sequence is 3D. This property value is
  134. inherited from the parent Geometry.
  135. """
  136. return self._z
  137. # ### Other Methods ###
  138. def clone(self):
  139. "Clone this coordinate sequence."
  140. return GEOSCoordSeq(capi.cs_clone(self.ptr), self.hasz)
  141. @property
  142. def kml(self):
  143. "Return the KML representation for the coordinates."
  144. # Getting the substitution string depending on whether the coordinates have
  145. # a Z dimension.
  146. if self.hasz:
  147. substr = '%s,%s,%s '
  148. else:
  149. substr = '%s,%s,0 '
  150. return '<coordinates>%s</coordinates>' % \
  151. ''.join(substr % self[i] for i in range(len(self))).strip()
  152. @property
  153. def tuple(self):
  154. "Return a tuple version of this coordinate sequence."
  155. n = self.size
  156. get_point = self._point_getter
  157. if n == 1:
  158. return get_point(0)
  159. return tuple(get_point(i) for i in range(n))