3
3
GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon
5
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
6
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
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
13
14
class GeometryCollection(GEOSGeometry):
14
_allowed = (Point, LineString, LinearRing, Polygon)
17
17
def __init__(self, *args, **kwargs):
34
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.')
35
# this is moved to list mixin super class
36
self._check_allowed(init_geoms)
38
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)
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)
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.')
57
geoms = get_pointer_arr(ngeoms)
58
for i in xrange(ngeoms):
60
geoms[i] = geom_clone(geom.ptr)
62
geoms[i] = geom_clone(get_geomn(self.ptr, i))
64
# Creating a new collection, and destroying the contents of the previous poiner.
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)
39
collection = self._create_collection(len(init_geoms), iter(init_geoms))
40
super(GeometryCollection, self).__init__(collection, **kwargs)
71
42
def __iter__(self):
72
43
"Iterates over each Geometry in the Collection."
73
44
for i in xrange(len(self)):
74
yield self.__getitem__(i)
77
48
"Returns the number of geometries in this Collection."
78
49
return self.num_geom
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))
51
### Methods for compatibility with ListMixin ###
52
def _create_collection(self, length, items):
53
# Creating the geometry pointer array.
54
geoms = get_pointer_arr(length)
55
for i, g in enumerate(items):
56
# this is a little sloppy, but makes life easier
57
# allow GEOSGeometry types (python wrappers) or pointer types
58
geoms[i] = capi.geom_clone(getattr(g, 'ptr', g))
60
return capi.create_collection(c_int(self._typeid), byref(geoms), c_uint(length))
62
def _get_single_internal(self, index):
63
return capi.get_geomn(self.ptr, index)
65
def _get_single_external(self, index):
66
"Returns the Geometry from this Collection at the given index (0-based)."
67
# Checking the index and returning the corresponding GEOS geometry.
68
return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
70
def _set_list(self, length, items):
71
"Create a new collection, and destroy the contents of the previous pointer."
74
self.ptr = self._create_collection(length, items)
75
if srid: self.srid = srid
76
capi.destroy_geom(prev_ptr)
78
_set_single = GEOSGeometry._set_single_rebuild
79
_assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
96
92
# MultiPoint, MultiLineString, and MultiPolygon class definitions.
97
class MultiPoint(GeometryCollection):
93
class MultiPoint(GeometryCollection):
100
class MultiLineString(GeometryCollection):
97
class MultiLineString(GeometryCollection):
101
98
_allowed = (LineString, LinearRing)
103
class MultiPolygon(GeometryCollection):
104
Returns a LineString representing the line merge of this
107
return self._topology(capi.geos_linemerge(self.ptr))
109
class MultiPolygon(GeometryCollection):
104
110
_allowed = Polygon
114
def cascaded_union(self):
115
"Returns a cascaded union of this MultiPolygon."
117
return GEOSGeometry(capi.geos_cascaded_union(self.ptr), self.srid)
119
raise GEOSException('The cascaded union operation requires GEOS 3.1+.')
121
# Setting the allowed types here since GeometryCollection is defined before
123
GeometryCollection._allowed = (Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon)