|
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 |