app/django/contrib/gis/geos/coordseq.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     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 c_double, c_uint, byref
       
     7 from types import ListType, TupleType
       
     8 from django.contrib.gis.geos.error import GEOSException, GEOSIndexError
       
     9 from django.contrib.gis.geos.libgeos import CS_PTR, HAS_NUMPY
       
    10 from django.contrib.gis.geos.prototypes import cs_clone, cs_getdims, cs_getordinate, cs_getsize, cs_setordinate
       
    11 if HAS_NUMPY: from numpy import ndarray
       
    12 
       
    13 class GEOSCoordSeq(object):
       
    14     "The internal representation of a list of coordinates inside a Geometry."
       
    15 
       
    16     #### Python 'magic' routines ####
       
    17     def __init__(self, ptr, z=False):
       
    18         "Initializes from a GEOS pointer."
       
    19         if not isinstance(ptr, CS_PTR):
       
    20             raise TypeError('Coordinate sequence should initialize with a CS_PTR.')
       
    21         self._ptr = ptr
       
    22         self._z = z
       
    23 
       
    24     def __iter__(self):
       
    25         "Iterates over each point in the coordinate sequence."
       
    26         for i in xrange(self.size):
       
    27             yield self[i]
       
    28 
       
    29     def __len__(self):
       
    30         "Returns the number of points in the coordinate sequence."
       
    31         return int(self.size)
       
    32 
       
    33     def __str__(self):
       
    34         "Returns the string representation of the coordinate sequence."
       
    35         return str(self.tuple)
       
    36 
       
    37     def __getitem__(self, index):
       
    38         "Returns the coordinate sequence value at the given index."
       
    39         coords = [self.getX(index), self.getY(index)]
       
    40         if self.dims == 3 and self._z:
       
    41             coords.append(self.getZ(index))
       
    42         return tuple(coords)
       
    43 
       
    44     def __setitem__(self, index, value):
       
    45         "Sets the coordinate sequence value at the given index."
       
    46         # Checking the input value
       
    47         if isinstance(value, (ListType, TupleType)):
       
    48             pass
       
    49         elif HAS_NUMPY and isinstance(value, ndarray):
       
    50             pass
       
    51         else:
       
    52             raise TypeError('Must set coordinate with a sequence (list, tuple, or numpy array).')
       
    53         # Checking the dims of the input
       
    54         if self.dims == 3 and self._z:
       
    55             n_args = 3
       
    56             set_3d = True
       
    57         else:
       
    58             n_args = 2
       
    59             set_3d = False
       
    60         if len(value) != n_args:
       
    61             raise TypeError('Dimension of value does not match.')
       
    62         # Setting the X, Y, Z
       
    63         self.setX(index, value[0])
       
    64         self.setY(index, value[1])
       
    65         if set_3d: self.setZ(index, value[2])
       
    66 
       
    67     #### Internal Routines ####
       
    68     def _checkindex(self, index):
       
    69         "Checks the given index."
       
    70         sz = self.size
       
    71         if (sz < 1) or (index < 0) or (index >= sz):
       
    72             raise GEOSIndexError('invalid GEOS Geometry index: %s' % str(index))
       
    73 
       
    74     def _checkdim(self, dim):
       
    75         "Checks the given dimension."
       
    76         if dim < 0 or dim > 2:
       
    77             raise GEOSException('invalid ordinate dimension "%d"' % dim)
       
    78 
       
    79     @property
       
    80     def ptr(self):
       
    81         """
       
    82         Property for controlling access to coordinate sequence pointer,
       
    83         preventing attempted access to a NULL memory location.
       
    84         """
       
    85         if self._ptr: return self._ptr
       
    86         else: raise GEOSException('NULL coordinate sequence pointer encountered.')
       
    87 
       
    88     #### Ordinate getting and setting routines ####
       
    89     def getOrdinate(self, dimension, index):
       
    90         "Returns the value for the given dimension and index."
       
    91         self._checkindex(index)
       
    92         self._checkdim(dimension)
       
    93         return cs_getordinate(self.ptr, index, dimension, byref(c_double()))
       
    94 
       
    95     def setOrdinate(self, dimension, index, value):
       
    96         "Sets the value for the given dimension and index."
       
    97         self._checkindex(index)
       
    98         self._checkdim(dimension)
       
    99         cs_setordinate(self.ptr, index, dimension, value)
       
   100 
       
   101     def getX(self, index):
       
   102         "Get the X value at the index."
       
   103         return self.getOrdinate(0, index)
       
   104 
       
   105     def setX(self, index, value):
       
   106         "Set X with the value at the given index."
       
   107         self.setOrdinate(0, index, value)
       
   108 
       
   109     def getY(self, index):
       
   110         "Get the Y value at the given index."
       
   111         return self.getOrdinate(1, index)
       
   112 
       
   113     def setY(self, index, value):
       
   114         "Set Y with the value at the given index."
       
   115         self.setOrdinate(1, index, value)
       
   116 
       
   117     def getZ(self, index):
       
   118         "Get Z with the value at the given index."
       
   119         return self.getOrdinate(2, index)
       
   120 
       
   121     def setZ(self, index, value):
       
   122         "Set Z with the value at the given index."
       
   123         self.setOrdinate(2, index, value)
       
   124 
       
   125     ### Dimensions ###
       
   126     @property
       
   127     def size(self):
       
   128         "Returns the size of this coordinate sequence."
       
   129         return cs_getsize(self.ptr, byref(c_uint()))
       
   130 
       
   131     @property
       
   132     def dims(self):
       
   133         "Returns the dimensions of this coordinate sequence."
       
   134         return cs_getdims(self.ptr, byref(c_uint()))
       
   135 
       
   136     @property
       
   137     def hasz(self):
       
   138         """
       
   139         Returns whether this coordinate sequence is 3D.  This property value is
       
   140         inherited from the parent Geometry.
       
   141         """
       
   142         return self._z
       
   143 
       
   144     ### Other Methods ###
       
   145     def clone(self):
       
   146         "Clones this coordinate sequence."
       
   147         return GEOSCoordSeq(cs_clone(self.ptr), self.hasz)
       
   148 
       
   149     @property
       
   150     def kml(self):
       
   151         "Returns the KML representation for the coordinates."
       
   152         # Getting the substitution string depending on whether the coordinates have
       
   153         #  a Z dimension.
       
   154         if self.hasz: substr = '%s,%s,%s '
       
   155         else: substr = '%s,%s,0 '
       
   156         return '<coordinates>%s</coordinates>' % \
       
   157             ''.join([substr % self[i] for i in xrange(len(self))]).strip()
       
   158 
       
   159     @property
       
   160     def tuple(self):
       
   161         "Returns a tuple version of this coordinate sequence."
       
   162         n = self.size
       
   163         if n == 1: return self[0]
       
   164         else: return tuple([self[i] for i in xrange(n)])