| 1 |
""" |
|---|
| 2 |
This module houses the Geometry Collection objects: |
|---|
| 3 |
GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon |
|---|
| 4 |
""" |
|---|
| 5 |
from ctypes import c_int, c_uint, byref |
|---|
| 6 |
from types import TupleType, ListType |
|---|
| 7 |
from django.contrib.gis.geos.base import GEOSGeometry |
|---|
| 8 |
from django.contrib.gis.geos.error import GEOSException, GEOSIndexError |
|---|
| 9 |
from django.contrib.gis.geos.geometries import Point, LineString, LinearRing, Polygon |
|---|
| 10 |
from django.contrib.gis.geos.libgeos import get_pointer_arr, GEOM_PTR |
|---|
| 11 |
from django.contrib.gis.geos.prototypes import create_collection, destroy_geom, geom_clone, geos_typeid, get_cs, get_geomn |
|---|
| 12 |
|
|---|
| 13 |
class GeometryCollection(GEOSGeometry): |
|---|
| 14 |
_allowed = (Point, LineString, LinearRing, Polygon) |
|---|
| 15 |
_typeid = 7 |
|---|
| 16 |
|
|---|
| 17 |
def __init__(self, *args, **kwargs): |
|---|
| 18 |
"Initializes a Geometry Collection from a sequence of Geometry objects." |
|---|
| 19 |
|
|---|
| 20 |
# Checking the arguments |
|---|
| 21 |
if not args: |
|---|
| 22 |
raise TypeError, 'Must provide at least one Geometry to initialize %s.' % self.__class__.__name__ |
|---|
| 23 |
|
|---|
| 24 |
if len(args) == 1: |
|---|
| 25 |
# If only one geometry provided or a list of geometries is provided |
|---|
| 26 |
# in the first argument. |
|---|
| 27 |
if isinstance(args[0], (TupleType, ListType)): |
|---|
| 28 |
init_geoms = args[0] |
|---|
| 29 |
else: |
|---|
| 30 |
init_geoms = args |
|---|
| 31 |
else: |
|---|
| 32 |
init_geoms = args |
|---|
| 33 |
|
|---|
| 34 |
# Ensuring that only the permitted geometries are allowed in this collection |
|---|
| 35 |
if False in [isinstance(geom, self._allowed) for geom in init_geoms]: |
|---|
| 36 |
raise TypeError('Invalid Geometry type encountered in the arguments.') |
|---|
| 37 |
|
|---|
| 38 |
# Creating the geometry pointer array. |
|---|
| 39 |
ngeoms = len(init_geoms) |
|---|
| 40 |
geoms = get_pointer_arr(ngeoms) |
|---|
| 41 |
for i in xrange(ngeoms): geoms[i] = geom_clone(init_geoms[i].ptr) |
|---|
| 42 |
super(GeometryCollection, self).__init__(create_collection(c_int(self._typeid), byref(geoms), c_uint(ngeoms)), **kwargs) |
|---|
| 43 |
|
|---|
| 44 |
def __getitem__(self, index): |
|---|
| 45 |
"Returns the Geometry from this Collection at the given index (0-based)." |
|---|
| 46 |
# Checking the index and returning the corresponding GEOS geometry. |
|---|
| 47 |
self._checkindex(index) |
|---|
| 48 |
return GEOSGeometry(geom_clone(get_geomn(self.ptr, index)), srid=self.srid) |
|---|
| 49 |
|
|---|
| 50 |
def __setitem__(self, index, geom): |
|---|
| 51 |
"Sets the Geometry at the specified index." |
|---|
| 52 |
self._checkindex(index) |
|---|
| 53 |
if not isinstance(geom, self._allowed): |
|---|
| 54 |
raise TypeError('Incompatible Geometry for collection.') |
|---|
| 55 |
|
|---|
| 56 |
ngeoms = len(self) |
|---|
| 57 |
geoms = get_pointer_arr(ngeoms) |
|---|
| 58 |
for i in xrange(ngeoms): |
|---|
| 59 |
if i == index: |
|---|
| 60 |
geoms[i] = geom_clone(geom.ptr) |
|---|
| 61 |
else: |
|---|
| 62 |
geoms[i] = geom_clone(get_geomn(self.ptr, i)) |
|---|
| 63 |
|
|---|
| 64 |
# Creating a new collection, and destroying the contents of the previous poiner. |
|---|
| 65 |
prev_ptr = self.ptr |
|---|
| 66 |
srid = self.srid |
|---|
| 67 |
self._ptr = create_collection(c_int(self._typeid), byref(geoms), c_uint(ngeoms)) |
|---|
| 68 |
if srid: self.srid = srid |
|---|
| 69 |
destroy_geom(prev_ptr) |
|---|
| 70 |
|
|---|
| 71 |
def __iter__(self): |
|---|
| 72 |
"Iterates over each Geometry in the Collection." |
|---|
| 73 |
for i in xrange(len(self)): |
|---|
| 74 |
yield self.__getitem__(i) |
|---|
| 75 |
|
|---|
| 76 |
def __len__(self): |
|---|
| 77 |
"Returns the number of geometries in this Collection." |
|---|
| 78 |
return self.num_geom |
|---|
| 79 |
|
|---|
| 80 |
def _checkindex(self, index): |
|---|
| 81 |
"Checks the given geometry index." |
|---|
| 82 |
if index < 0 or index >= self.num_geom: |
|---|
| 83 |
raise GEOSIndexError('invalid GEOS Geometry index: %s' % str(index)) |
|---|
| 84 |
|
|---|
| 85 |
@property |
|---|
| 86 |
def kml(self): |
|---|
| 87 |
"Returns the KML for this Geometry Collection." |
|---|
| 88 |
return '<MultiGeometry>%s</MultiGeometry>' % ''.join([g.kml for g in self]) |
|---|
| 89 |
|
|---|
| 90 |
@property |
|---|
| 91 |
def tuple(self): |
|---|
| 92 |
"Returns a tuple of all the coordinates in this Geometry Collection" |
|---|
| 93 |
return tuple([g.tuple for g in self]) |
|---|
| 94 |
coords = tuple |
|---|
| 95 |
|
|---|
| 96 |
# MultiPoint, MultiLineString, and MultiPolygon class definitions. |
|---|
| 97 |
class MultiPoint(GeometryCollection): |
|---|
| 98 |
_allowed = Point |
|---|
| 99 |
_typeid = 4 |
|---|
| 100 |
class MultiLineString(GeometryCollection): |
|---|
| 101 |
_allowed = (LineString, LinearRing) |
|---|
| 102 |
_typeid = 5 |
|---|
| 103 |
class MultiPolygon(GeometryCollection): |
|---|
| 104 |
_allowed = Polygon |
|---|
| 105 |
_typeid = 6 |
|---|