collections.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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.geometry import GEOSGeometry
  7. from django.contrib.gis.geos.libgeos import get_pointer_arr
  8. from django.contrib.gis.geos.linestring import LineString, LinearRing
  9. from django.contrib.gis.geos.point import Point
  10. from django.contrib.gis.geos.polygon import Polygon
  11. from django.contrib.gis.geos import prototypes as capi
  12. from django.utils.six.moves import xrange
  13. class GeometryCollection(GEOSGeometry):
  14. _typeid = 7
  15. def __init__(self, *args, **kwargs):
  16. "Initializes a Geometry Collection from a sequence of Geometry objects."
  17. # Checking the arguments
  18. if not args:
  19. raise TypeError('Must provide at least one Geometry to initialize %s.' % self.__class__.__name__)
  20. if len(args) == 1:
  21. # If only one geometry provided or a list of geometries is provided
  22. # in the first argument.
  23. if isinstance(args[0], (tuple, list)):
  24. init_geoms = args[0]
  25. else:
  26. init_geoms = args
  27. else:
  28. init_geoms = args
  29. # Ensuring that only the permitted geometries are allowed in this collection
  30. # this is moved to list mixin super class
  31. self._check_allowed(init_geoms)
  32. # Creating the geometry pointer array.
  33. collection = self._create_collection(len(init_geoms), iter(init_geoms))
  34. super(GeometryCollection, self).__init__(collection, **kwargs)
  35. def __iter__(self):
  36. "Iterates over each Geometry in the Collection."
  37. for i in xrange(len(self)):
  38. yield self[i]
  39. def __len__(self):
  40. "Returns the number of geometries in this Collection."
  41. return self.num_geom
  42. ### Methods for compatibility with ListMixin ###
  43. def _create_collection(self, length, items):
  44. # Creating the geometry pointer array.
  45. geoms = get_pointer_arr(length)
  46. for i, g in enumerate(items):
  47. # this is a little sloppy, but makes life easier
  48. # allow GEOSGeometry types (python wrappers) or pointer types
  49. geoms[i] = capi.geom_clone(getattr(g, 'ptr', g))
  50. return capi.create_collection(c_int(self._typeid), byref(geoms), c_uint(length))
  51. def _get_single_internal(self, index):
  52. return capi.get_geomn(self.ptr, index)
  53. def _get_single_external(self, index):
  54. "Returns the Geometry from this Collection at the given index (0-based)."
  55. # Checking the index and returning the corresponding GEOS geometry.
  56. return GEOSGeometry(capi.geom_clone(self._get_single_internal(index)), srid=self.srid)
  57. def _set_list(self, length, items):
  58. "Create a new collection, and destroy the contents of the previous pointer."
  59. prev_ptr = self.ptr
  60. srid = self.srid
  61. self.ptr = self._create_collection(length, items)
  62. if srid:
  63. self.srid = srid
  64. capi.destroy_geom(prev_ptr)
  65. _set_single = GEOSGeometry._set_single_rebuild
  66. _assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild
  67. @property
  68. def kml(self):
  69. "Returns the KML for this Geometry Collection."
  70. return '<MultiGeometry>%s</MultiGeometry>' % ''.join(g.kml for g in self)
  71. @property
  72. def tuple(self):
  73. "Returns a tuple of all the coordinates in this Geometry Collection"
  74. return tuple(g.tuple for g in self)
  75. coords = tuple
  76. # MultiPoint, MultiLineString, and MultiPolygon class definitions.
  77. class MultiPoint(GeometryCollection):
  78. _allowed = Point
  79. _typeid = 4
  80. class MultiLineString(GeometryCollection):
  81. _allowed = (LineString, LinearRing)
  82. _typeid = 5
  83. @property
  84. def merged(self):
  85. """
  86. Returns a LineString representing the line merge of this
  87. MultiLineString.
  88. """
  89. return self._topology(capi.geos_linemerge(self.ptr))
  90. class MultiPolygon(GeometryCollection):
  91. _allowed = Polygon
  92. _typeid = 6
  93. @property
  94. def cascaded_union(self):
  95. "Returns a cascaded union of this MultiPolygon."
  96. return GEOSGeometry(capi.geos_cascaded_union(self.ptr), self.srid)
  97. # Setting the allowed types here since GeometryCollection is defined before
  98. # its subclasses.
  99. GeometryCollection._allowed = (Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon)