"""Coordinate sequence utilities """ import sys from array import array from ctypes import byref, c_double, c_uint from shapely.geos import lgeos from shapely.topology import Validating if sys.version_info[0] < 3: range = xrange class CoordinateSequence(object): """ Iterative access to coordinate tuples from the parent geometry's coordinate sequence. Example: >>> from shapely.wkt import loads >>> g = loads('POINT (0.0 0.0)') >>> list(g.coords) [(0.0, 0.0)] """ # Attributes # ---------- # _cseq : c_void_p # Ctypes pointer to GEOS coordinate sequence # _ndim : int # Number of dimensions (2 or 3, generally) # __p__ : object # Parent (Shapely) geometry _cseq = None _ndim = None __p__ = None def __init__(self, parent): self.__p__ = parent def _update(self): self._ndim = self.__p__._ndim self._cseq = lgeos.GEOSGeom_getCoordSeq(self.__p__._geom) def __len__(self): self._update() cs_len = c_uint(0) lgeos.GEOSCoordSeq_getSize(self._cseq, byref(cs_len)) return cs_len.value def __iter__(self): self._update() dx = c_double() dy = c_double() dz = c_double() has_z = self._ndim == 3 for i in range(self.__len__()): lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(dx)) lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(dy)) if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(dz)) yield (dx.value, dy.value, dz.value) else: yield (dx.value, dy.value) def __getitem__(self, key): self._update() dx = c_double() dy = c_double() dz = c_double() m = self.__len__() has_z = self._ndim == 3 if isinstance(key, int): if key + m < 0 or key >= m: raise IndexError("index out of range") if key < 0: i = m + key else: i = key lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(dx)) lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(dy)) if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(dz)) return (dx.value, dy.value, dz.value) else: return (dx.value, dy.value) elif isinstance(key, slice): res = [] start, stop, stride = key.indices(m) for i in range(start, stop, stride): lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(dx)) lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(dy)) if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(dz)) res.append((dx.value, dy.value, dz.value)) else: res.append((dx.value, dy.value)) return res else: raise TypeError("key must be an index or slice") @property def ctypes(self): self._update() has_z = self._ndim == 3 n = self._ndim m = self.__len__() array_type = c_double * (m * n) data = array_type() temp = c_double() for i in range(m): lgeos.GEOSCoordSeq_getX(self._cseq, i, byref(temp)) data[n*i] = temp.value lgeos.GEOSCoordSeq_getY(self._cseq, i, byref(temp)) data[n*i+1] = temp.value if has_z: lgeos.GEOSCoordSeq_getZ(self._cseq, i, byref(temp)) data[n*i+2] = temp.value return data def array_interface(self): """Provide the Numpy array protocol.""" if sys.byteorder == 'little': typestr = ' maxx: maxx = x lgeos.GEOSCoordSeq_getY(cs, i, byref(temp)) y = temp.value if y < miny: miny = y if y > maxy: maxy = y return (minx, miny, maxx, maxy)