You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

collections.py 4.1KB

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