~ubuntu-branches/ubuntu/quantal/python-django/quantal-security

« back to all changes in this revision

Viewing changes to django/contrib/gis/geos/collections.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2009-07-29 11:26:28 UTC
  • mfrom: (1.2.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: james.westby@ubuntu.com-20090729112628-9qrzwnl9x32jxhbg
Tags: upstream-1.1
ImportĀ upstreamĀ versionĀ 1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon
4
4
"""
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
12
13
 
13
14
class GeometryCollection(GEOSGeometry):
14
 
    _allowed = (Point, LineString, LinearRing, Polygon)
15
15
    _typeid = 7
16
16
 
17
17
    def __init__(self, *args, **kwargs):
21
21
        if not args:
22
22
            raise TypeError, 'Must provide at least one Geometry to initialize %s.' % self.__class__.__name__
23
23
 
24
 
        if len(args) == 1: 
 
24
        if len(args) == 1:
25
25
            # If only one geometry provided or a list of geometries is provided
26
26
            #  in the first argument.
27
 
            if isinstance(args[0], (TupleType, ListType)):
 
27
            if isinstance(args[0], (tuple, list)):
28
28
                init_geoms = args[0]
29
29
            else:
30
30
                init_geoms = args
32
32
            init_geoms = args
33
33
 
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)
37
37
 
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)
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)
 
39
        collection = self._create_collection(len(init_geoms), iter(init_geoms))
 
40
        super(GeometryCollection, self).__init__(collection, **kwargs)
70
41
 
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)
 
45
            yield self[i]
75
46
 
76
47
    def __len__(self):
77
48
        "Returns the number of geometries in this Collection."
78
49
        return self.num_geom
79
50
 
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))
 
59
 
 
60
        return capi.create_collection(c_int(self._typeid), byref(geoms), c_uint(length))
 
61
 
 
62
    def _get_single_internal(self, index):
 
63
        return capi.get_geomn(self.ptr, index)
 
64
 
 
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)
 
69
 
 
70
    def _set_list(self, length, items):
 
71
        "Create a new collection, and destroy the contents of the previous pointer."
 
72
        prev_ptr = self.ptr
 
73
        srid = self.srid
 
74
        self.ptr = self._create_collection(length, items)
 
75
        if srid: self.srid = srid
 
76
        capi.destroy_geom(prev_ptr)
 
77
 
 
78
    _set_single = GEOSGeometry._set_single_rebuild
 
79
    _assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
84
80
 
85
81
    @property
86
82
    def kml(self):
94
90
    coords = tuple
95
91
 
96
92
# MultiPoint, MultiLineString, and MultiPolygon class definitions.
97
 
class MultiPoint(GeometryCollection): 
 
93
class MultiPoint(GeometryCollection):
98
94
    _allowed = Point
99
95
    _typeid = 4
100
 
class MultiLineString(GeometryCollection): 
 
96
 
 
97
class MultiLineString(GeometryCollection):
101
98
    _allowed = (LineString, LinearRing)
102
99
    _typeid = 5
103
 
class MultiPolygon(GeometryCollection): 
 
100
 
 
101
    @property
 
102
    def merged(self):
 
103
        """ 
 
104
        Returns a LineString representing the line merge of this 
 
105
        MultiLineString.
 
106
        """ 
 
107
        return self._topology(capi.geos_linemerge(self.ptr))         
 
108
 
 
109
class MultiPolygon(GeometryCollection):
104
110
    _allowed = Polygon
105
111
    _typeid = 6
 
112
 
 
113
    @property
 
114
    def cascaded_union(self):
 
115
        "Returns a cascaded union of this MultiPolygon."
 
116
        if GEOS_PREPARE:
 
117
            return GEOSGeometry(capi.geos_cascaded_union(self.ptr), self.srid)
 
118
        else:
 
119
            raise GEOSException('The cascaded union operation requires GEOS 3.1+.')
 
120
 
 
121
# Setting the allowed types here since GeometryCollection is defined before
 
122
# its subclasses.
 
123
GeometryCollection._allowed = (Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon)