web/lib/django/contrib/gis/geos/collections.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     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 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
       
    13 
       
    14 class GeometryCollection(GEOSGeometry):
       
    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], (tuple, list)):
       
    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         # this is moved to list mixin super class
       
    36         self._check_allowed(init_geoms)
       
    37 
       
    38         # Creating the geometry pointer array.
       
    39         collection = self._create_collection(len(init_geoms), iter(init_geoms))
       
    40         super(GeometryCollection, self).__init__(collection, **kwargs)
       
    41 
       
    42     def __iter__(self):
       
    43         "Iterates over each Geometry in the Collection."
       
    44         for i in xrange(len(self)):
       
    45             yield self[i]
       
    46 
       
    47     def __len__(self):
       
    48         "Returns the number of geometries in this Collection."
       
    49         return self.num_geom
       
    50 
       
    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
       
    80 
       
    81     @property
       
    82     def kml(self):
       
    83         "Returns the KML for this Geometry Collection."
       
    84         return '<MultiGeometry>%s</MultiGeometry>' % ''.join([g.kml for g in self])
       
    85 
       
    86     @property
       
    87     def tuple(self):
       
    88         "Returns a tuple of all the coordinates in this Geometry Collection"
       
    89         return tuple([g.tuple for g in self])
       
    90     coords = tuple
       
    91 
       
    92 # MultiPoint, MultiLineString, and MultiPolygon class definitions.
       
    93 class MultiPoint(GeometryCollection):
       
    94     _allowed = Point
       
    95     _typeid = 4
       
    96 
       
    97 class MultiLineString(GeometryCollection):
       
    98     _allowed = (LineString, LinearRing)
       
    99     _typeid = 5
       
   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):
       
   110     _allowed = Polygon
       
   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)