Merged in patch from Aryeh Leib Taurog for #9877, adapting as necessary.
2 This module houses the Geometry Collection objects:
3 GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon
5 from ctypes import c_int, c_uint, byref
6 from django.contrib.gis.geos.error import GEOSException, GEOSIndexError
7 from django.contrib.gis.geos.geometry import GEOSGeometry
8 from django.contrib.gis.geos.libgeos import get_pointer_arr, GEOM_PTR, GEOS_PREPARE
9 from django.contrib.gis.geos.linestring import LineString, LinearRing
10 from django.contrib.gis.geos.point import Point
11 from django.contrib.gis.geos.polygon import Polygon
12 from django.contrib.gis.geos import prototypes as capi
14 class GeometryCollection(GEOSGeometry):
17 def __init__(self, *args, **kwargs):
18 "Initializes a Geometry Collection from a sequence of Geometry objects."
20 # Checking the arguments
22 raise TypeError, 'Must provide at least one Geometry to initialize %s.' % self.__class__.__name__
25 # If only one geometry provided or a list of geometries is provided
26 # in the first argument.
27 if isinstance(args[0], (tuple, list)):
34 # Ensuring that only the permitted geometries are allowed in this collection
35 self._checkAllowedTypes(init_geoms)
37 # Creating the geometry pointer array.
38 collection = self._createCollection(len(init_geoms), iter(init_geoms))
39 super(GeometryCollection, self).__init__(collection, **kwargs)
42 def _createCollection(cls, length, items):
43 # Creating the geometry pointer array.
44 geoms = get_pointer_arr(length)
45 for i, g in enumerate(items):
46 # this is a little sloppy, but makes life easier
47 # allow GEOSGeometry types (python wrappers) or pointer types
49 geoms[i] = capi.geom_clone(g.ptr)
51 geoms[i] = capi.geom_clone(g)
53 return capi.create_collection(c_int(cls._typeid), byref(geoms), c_uint(length))
55 def _getItemInternal(self, index):
56 return capi.get_geomn(self.ptr, index)
58 def _getItemExternal(self, index):
59 "Returns the Geometry from this Collection at the given index (0-based)."
60 # Checking the index and returning the corresponding GEOS geometry.
61 self._checkindex(index)
62 return GEOSGeometry(capi.geom_clone(self._getItemInternal(index)), srid=self.srid)
64 def _setCollection(self, length, items):
65 "Create a new collection, and destroy the contents of the previous pointer."
68 self.ptr = self._createCollection(length, items)
69 if srid: self.srid = srid
70 capi.destroy_geom(prev_ptr)
73 "Iterates over each Geometry in the Collection."
74 for i in xrange(len(self)):
78 "Returns the number of geometries in this Collection."
83 "Returns the KML for this Geometry Collection."
84 return '<MultiGeometry>%s</MultiGeometry>' % ''.join([g.kml for g in self])
88 "Returns a tuple of all the coordinates in this Geometry Collection"
89 return tuple([g.tuple for g in self])
92 # MultiPoint, MultiLineString, and MultiPolygon class definitions.
93 class MultiPoint(GeometryCollection):
97 class MultiLineString(GeometryCollection):
98 _allowed = (LineString, LinearRing)
101 class MultiPolygon(GeometryCollection):
106 def cascaded_union(self):
107 "Returns a cascaded union of this MultiPolygon."
109 return GEOSGeometry(capi.geos_cascaded_union(self.ptr), self.srid)
111 raise GEOSException('The cascaded union operation requires GEOS 3.1+.')
113 # Setting the allowed types here since GeometryCollection is defined before
115 GeometryCollection._allowed = (Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon)