summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/django/contrib/gis/gdal/geometries.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/django/contrib/gis/gdal/geometries.py')
-rw-r--r--lib/python2.7/site-packages/django/contrib/gis/gdal/geometries.py726
1 files changed, 726 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/contrib/gis/gdal/geometries.py b/lib/python2.7/site-packages/django/contrib/gis/gdal/geometries.py
new file mode 100644
index 0000000..0d75620
--- /dev/null
+++ b/lib/python2.7/site-packages/django/contrib/gis/gdal/geometries.py
@@ -0,0 +1,726 @@
+"""
+ The OGRGeometry is a wrapper for using the OGR Geometry class
+ (see http://www.gdal.org/ogr/classOGRGeometry.html). OGRGeometry
+ may be instantiated when reading geometries from OGR Data Sources
+ (e.g. SHP files), or when given OGC WKT (a string).
+
+ While the 'full' API is not present yet, the API is "pythonic" unlike
+ the traditional and "next-generation" OGR Python bindings. One major
+ advantage OGR Geometries have over their GEOS counterparts is support
+ for spatial reference systems and their transformation.
+
+ Example:
+ >>> from django.contrib.gis.gdal import OGRGeometry, OGRGeomType, SpatialReference
+ >>> wkt1, wkt2 = 'POINT(-90 30)', 'POLYGON((0 0, 5 0, 5 5, 0 5)'
+ >>> pnt = OGRGeometry(wkt1)
+ >>> print(pnt)
+ POINT (-90 30)
+ >>> mpnt = OGRGeometry(OGRGeomType('MultiPoint'), SpatialReference('WGS84'))
+ >>> mpnt.add(wkt1)
+ >>> mpnt.add(wkt1)
+ >>> print(mpnt)
+ MULTIPOINT (-90 30,-90 30)
+ >>> print(mpnt.srs.name)
+ WGS 84
+ >>> print(mpnt.srs.proj)
+ +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs
+ >>> mpnt.transform_to(SpatialReference('NAD27'))
+ >>> print(mpnt.proj)
+ +proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
+ >>> print(mpnt)
+ MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641)
+
+ The OGRGeomType class is to make it easy to specify an OGR geometry type:
+ >>> from django.contrib.gis.gdal import OGRGeomType
+ >>> gt1 = OGRGeomType(3) # Using an integer for the type
+ >>> gt2 = OGRGeomType('Polygon') # Using a string
+ >>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive
+ >>> print(gt1 == 3, gt1 == 'Polygon') # Equivalence works w/non-OGRGeomType objects
+ True True
+"""
+# Python library requisites.
+import sys
+from binascii import a2b_hex, b2a_hex
+from ctypes import byref, string_at, c_char_p, c_double, c_ubyte, c_void_p
+
+from django.contrib.gis import memoryview
+
+# Getting GDAL prerequisites
+from django.contrib.gis.gdal.base import GDALBase
+from django.contrib.gis.gdal.envelope import Envelope, OGREnvelope
+from django.contrib.gis.gdal.error import OGRException, OGRIndexError, SRSException
+from django.contrib.gis.gdal.geomtype import OGRGeomType
+from django.contrib.gis.gdal.libgdal import GDAL_VERSION
+from django.contrib.gis.gdal.srs import SpatialReference, CoordTransform
+
+# Getting the ctypes prototype functions that interface w/the GDAL C library.
+from django.contrib.gis.gdal.prototypes import geom as capi, srs as srs_api
+
+# For recognizing geometry input.
+from django.contrib.gis.geometry.regex import hex_regex, wkt_regex, json_regex
+
+from django.utils import six
+from django.utils.six.moves import xrange
+
+# For more information, see the OGR C API source code:
+# http://www.gdal.org/ogr/ogr__api_8h.html
+#
+# The OGR_G_* routines are relevant here.
+
+#### OGRGeometry Class ####
+class OGRGeometry(GDALBase):
+ "Generally encapsulates an OGR geometry."
+
+ def __init__(self, geom_input, srs=None):
+ "Initializes Geometry on either WKT or an OGR pointer as input."
+
+ str_instance = isinstance(geom_input, six.string_types)
+
+ # If HEX, unpack input to a binary buffer.
+ if str_instance and hex_regex.match(geom_input):
+ geom_input = memoryview(a2b_hex(geom_input.upper().encode()))
+ str_instance = False
+
+ # Constructing the geometry,
+ if str_instance:
+ wkt_m = wkt_regex.match(geom_input)
+ json_m = json_regex.match(geom_input)
+ if wkt_m:
+ if wkt_m.group('srid'):
+ # If there's EWKT, set the SRS w/value of the SRID.
+ srs = int(wkt_m.group('srid'))
+ if wkt_m.group('type').upper() == 'LINEARRING':
+ # OGR_G_CreateFromWkt doesn't work with LINEARRING WKT.
+ # See http://trac.osgeo.org/gdal/ticket/1992.
+ g = capi.create_geom(OGRGeomType(wkt_m.group('type')).num)
+ capi.import_wkt(g, byref(c_char_p(wkt_m.group('wkt').encode())))
+ else:
+ g = capi.from_wkt(byref(c_char_p(wkt_m.group('wkt').encode())), None, byref(c_void_p()))
+ elif json_m:
+ g = capi.from_json(geom_input.encode())
+ else:
+ # Seeing if the input is a valid short-hand string
+ # (e.g., 'Point', 'POLYGON').
+ ogr_t = OGRGeomType(geom_input)
+ g = capi.create_geom(OGRGeomType(geom_input).num)
+ elif isinstance(geom_input, memoryview):
+ # WKB was passed in
+ g = capi.from_wkb(bytes(geom_input), None, byref(c_void_p()), len(geom_input))
+ elif isinstance(geom_input, OGRGeomType):
+ # OGRGeomType was passed in, an empty geometry will be created.
+ g = capi.create_geom(geom_input.num)
+ elif isinstance(geom_input, self.ptr_type):
+ # OGR pointer (c_void_p) was the input.
+ g = geom_input
+ else:
+ raise OGRException('Invalid input type for OGR Geometry construction: %s' % type(geom_input))
+
+ # Now checking the Geometry pointer before finishing initialization
+ # by setting the pointer for the object.
+ if not g:
+ raise OGRException('Cannot create OGR Geometry from input: %s' % str(geom_input))
+ self.ptr = g
+
+ # Assigning the SpatialReference object to the geometry, if valid.
+ if bool(srs): self.srs = srs
+
+ # Setting the class depending upon the OGR Geometry Type
+ self.__class__ = GEO_CLASSES[self.geom_type.num]
+
+ def __del__(self):
+ "Deletes this Geometry."
+ if self._ptr: capi.destroy_geom(self._ptr)
+
+ # Pickle routines
+ def __getstate__(self):
+ srs = self.srs
+ if srs:
+ srs = srs.wkt
+ else:
+ srs = None
+ return bytes(self.wkb), srs
+
+ def __setstate__(self, state):
+ wkb, srs = state
+ ptr = capi.from_wkb(wkb, None, byref(c_void_p()), len(wkb))
+ if not ptr: raise OGRException('Invalid OGRGeometry loaded from pickled state.')
+ self.ptr = ptr
+ self.srs = srs
+
+ @classmethod
+ def from_bbox(cls, bbox):
+ "Constructs a Polygon from a bounding box (4-tuple)."
+ x0, y0, x1, y1 = bbox
+ return OGRGeometry( 'POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))' % (
+ x0, y0, x0, y1, x1, y1, x1, y0, x0, y0) )
+
+ ### Geometry set-like operations ###
+ # g = g1 | g2
+ def __or__(self, other):
+ "Returns the union of the two geometries."
+ return self.union(other)
+
+ # g = g1 & g2
+ def __and__(self, other):
+ "Returns the intersection of this Geometry and the other."
+ return self.intersection(other)
+
+ # g = g1 - g2
+ def __sub__(self, other):
+ "Return the difference this Geometry and the other."
+ return self.difference(other)
+
+ # g = g1 ^ g2
+ def __xor__(self, other):
+ "Return the symmetric difference of this Geometry and the other."
+ return self.sym_difference(other)
+
+ def __eq__(self, other):
+ "Is this Geometry equal to the other?"
+ if isinstance(other, OGRGeometry):
+ return self.equals(other)
+ else:
+ return False
+
+ def __ne__(self, other):
+ "Tests for inequality."
+ return not (self == other)
+
+ def __str__(self):
+ "WKT is used for the string representation."
+ return self.wkt
+
+ #### Geometry Properties ####
+ @property
+ def dimension(self):
+ "Returns 0 for points, 1 for lines, and 2 for surfaces."
+ return capi.get_dims(self.ptr)
+
+ def _get_coord_dim(self):
+ "Returns the coordinate dimension of the Geometry."
+ if isinstance(self, GeometryCollection) and GDAL_VERSION < (1, 5, 2):
+ # On GDAL versions prior to 1.5.2, there exists a bug in which
+ # the coordinate dimension of geometry collections is always 2:
+ # http://trac.osgeo.org/gdal/ticket/2334
+ # Here we workaround by returning the coordinate dimension of the
+ # first geometry in the collection instead.
+ if len(self):
+ return capi.get_coord_dim(capi.get_geom_ref(self.ptr, 0))
+ return capi.get_coord_dim(self.ptr)
+
+ def _set_coord_dim(self, dim):
+ "Sets the coordinate dimension of this Geometry."
+ if not dim in (2, 3):
+ raise ValueError('Geometry dimension must be either 2 or 3')
+ capi.set_coord_dim(self.ptr, dim)
+
+ coord_dim = property(_get_coord_dim, _set_coord_dim)
+
+ @property
+ def geom_count(self):
+ "The number of elements in this Geometry."
+ return capi.get_geom_count(self.ptr)
+
+ @property
+ def point_count(self):
+ "Returns the number of Points in this Geometry."
+ return capi.get_point_count(self.ptr)
+
+ @property
+ def num_points(self):
+ "Alias for `point_count` (same name method in GEOS API.)"
+ return self.point_count
+
+ @property
+ def num_coords(self):
+ "Alais for `point_count`."
+ return self.point_count
+
+ @property
+ def geom_type(self):
+ "Returns the Type for this Geometry."
+ return OGRGeomType(capi.get_geom_type(self.ptr))
+
+ @property
+ def geom_name(self):
+ "Returns the Name of this Geometry."
+ return capi.get_geom_name(self.ptr)
+
+ @property
+ def area(self):
+ "Returns the area for a LinearRing, Polygon, or MultiPolygon; 0 otherwise."
+ return capi.get_area(self.ptr)
+
+ @property
+ def envelope(self):
+ "Returns the envelope for this Geometry."
+ # TODO: Fix Envelope() for Point geometries.
+ return Envelope(capi.get_envelope(self.ptr, byref(OGREnvelope())))
+
+ @property
+ def extent(self):
+ "Returns the envelope as a 4-tuple, instead of as an Envelope object."
+ return self.envelope.tuple
+
+ #### SpatialReference-related Properties ####
+
+ # The SRS property
+ def _get_srs(self):
+ "Returns the Spatial Reference for this Geometry."
+ try:
+ srs_ptr = capi.get_geom_srs(self.ptr)
+ return SpatialReference(srs_api.clone_srs(srs_ptr))
+ except SRSException:
+ return None
+
+ def _set_srs(self, srs):
+ "Sets the SpatialReference for this geometry."
+ # Do not have to clone the `SpatialReference` object pointer because
+ # when it is assigned to this `OGRGeometry` it's internal OGR
+ # reference count is incremented, and will likewise be released
+ # (decremented) when this geometry's destructor is called.
+ if isinstance(srs, SpatialReference):
+ srs_ptr = srs.ptr
+ elif isinstance(srs, six.integer_types + six.string_types):
+ sr = SpatialReference(srs)
+ srs_ptr = sr.ptr
+ else:
+ raise TypeError('Cannot assign spatial reference with object of type: %s' % type(srs))
+ capi.assign_srs(self.ptr, srs_ptr)
+
+ srs = property(_get_srs, _set_srs)
+
+ # The SRID property
+ def _get_srid(self):
+ srs = self.srs
+ if srs: return srs.srid
+ return None
+
+ def _set_srid(self, srid):
+ if isinstance(srid, six.integer_types):
+ self.srs = srid
+ else:
+ raise TypeError('SRID must be set with an integer.')
+
+ srid = property(_get_srid, _set_srid)
+
+ #### Output Methods ####
+ @property
+ def geos(self):
+ "Returns a GEOSGeometry object from this OGRGeometry."
+ from django.contrib.gis.geos import GEOSGeometry
+ return GEOSGeometry(self.wkb, self.srid)
+
+ @property
+ def gml(self):
+ "Returns the GML representation of the Geometry."
+ return capi.to_gml(self.ptr)
+
+ @property
+ def hex(self):
+ "Returns the hexadecimal representation of the WKB (a string)."
+ return b2a_hex(self.wkb).upper()
+
+ @property
+ def json(self):
+ """
+ Returns the GeoJSON representation of this Geometry.
+ """
+ return capi.to_json(self.ptr)
+ geojson = json
+
+ @property
+ def kml(self):
+ "Returns the KML representation of the Geometry."
+ return capi.to_kml(self.ptr, None)
+
+ @property
+ def wkb_size(self):
+ "Returns the size of the WKB buffer."
+ return capi.get_wkbsize(self.ptr)
+
+ @property
+ def wkb(self):
+ "Returns the WKB representation of the Geometry."
+ if sys.byteorder == 'little':
+ byteorder = 1 # wkbNDR (from ogr_core.h)
+ else:
+ byteorder = 0 # wkbXDR
+ sz = self.wkb_size
+ # Creating the unsigned character buffer, and passing it in by reference.
+ buf = (c_ubyte * sz)()
+ wkb = capi.to_wkb(self.ptr, byteorder, byref(buf))
+ # Returning a buffer of the string at the pointer.
+ return memoryview(string_at(buf, sz))
+
+ @property
+ def wkt(self):
+ "Returns the WKT representation of the Geometry."
+ return capi.to_wkt(self.ptr, byref(c_char_p()))
+
+ @property
+ def ewkt(self):
+ "Returns the EWKT representation of the Geometry."
+ srs = self.srs
+ if srs and srs.srid:
+ return 'SRID=%s;%s' % (srs.srid, self.wkt)
+ else:
+ return self.wkt
+
+ #### Geometry Methods ####
+ def clone(self):
+ "Clones this OGR Geometry."
+ return OGRGeometry(capi.clone_geom(self.ptr), self.srs)
+
+ def close_rings(self):
+ """
+ If there are any rings within this geometry that have not been
+ closed, this routine will do so by adding the starting point at the
+ end.
+ """
+ # Closing the open rings.
+ capi.geom_close_rings(self.ptr)
+
+ def transform(self, coord_trans, clone=False):
+ """
+ Transforms this geometry to a different spatial reference system.
+ May take a CoordTransform object, a SpatialReference object, string
+ WKT or PROJ.4, and/or an integer SRID. By default nothing is returned
+ and the geometry is transformed in-place. However, if the `clone`
+ keyword is set, then a transformed clone of this geometry will be
+ returned.
+ """
+ if clone:
+ klone = self.clone()
+ klone.transform(coord_trans)
+ return klone
+
+ # Have to get the coordinate dimension of the original geometry
+ # so it can be used to reset the transformed geometry's dimension
+ # afterwards. This is done because of GDAL bug (in versions prior
+ # to 1.7) that turns geometries 3D after transformation, see:
+ # http://trac.osgeo.org/gdal/changeset/17792
+ if GDAL_VERSION < (1, 7):
+ orig_dim = self.coord_dim
+
+ # Depending on the input type, use the appropriate OGR routine
+ # to perform the transformation.
+ if isinstance(coord_trans, CoordTransform):
+ capi.geom_transform(self.ptr, coord_trans.ptr)
+ elif isinstance(coord_trans, SpatialReference):
+ capi.geom_transform_to(self.ptr, coord_trans.ptr)
+ elif isinstance(coord_trans, six.integer_types + six.string_types):
+ sr = SpatialReference(coord_trans)
+ capi.geom_transform_to(self.ptr, sr.ptr)
+ else:
+ raise TypeError('Transform only accepts CoordTransform, '
+ 'SpatialReference, string, and integer objects.')
+
+ # Setting with original dimension, see comment above.
+ if GDAL_VERSION < (1, 7):
+ if isinstance(self, GeometryCollection):
+ # With geometry collections have to set dimension on
+ # each internal geometry reference, as the collection
+ # dimension isn't affected.
+ for i in xrange(len(self)):
+ internal_ptr = capi.get_geom_ref(self.ptr, i)
+ if orig_dim != capi.get_coord_dim(internal_ptr):
+ capi.set_coord_dim(internal_ptr, orig_dim)
+ else:
+ if self.coord_dim != orig_dim:
+ self.coord_dim = orig_dim
+
+ def transform_to(self, srs):
+ "For backwards-compatibility."
+ self.transform(srs)
+
+ #### Topology Methods ####
+ def _topology(self, func, other):
+ """A generalized function for topology operations, takes a GDAL function and
+ the other geometry to perform the operation on."""
+ if not isinstance(other, OGRGeometry):
+ raise TypeError('Must use another OGRGeometry object for topology operations!')
+
+ # Returning the output of the given function with the other geometry's
+ # pointer.
+ return func(self.ptr, other.ptr)
+
+ def intersects(self, other):
+ "Returns True if this geometry intersects with the other."
+ return self._topology(capi.ogr_intersects, other)
+
+ def equals(self, other):
+ "Returns True if this geometry is equivalent to the other."
+ return self._topology(capi.ogr_equals, other)
+
+ def disjoint(self, other):
+ "Returns True if this geometry and the other are spatially disjoint."
+ return self._topology(capi.ogr_disjoint, other)
+
+ def touches(self, other):
+ "Returns True if this geometry touches the other."
+ return self._topology(capi.ogr_touches, other)
+
+ def crosses(self, other):
+ "Returns True if this geometry crosses the other."
+ return self._topology(capi.ogr_crosses, other)
+
+ def within(self, other):
+ "Returns True if this geometry is within the other."
+ return self._topology(capi.ogr_within, other)
+
+ def contains(self, other):
+ "Returns True if this geometry contains the other."
+ return self._topology(capi.ogr_contains, other)
+
+ def overlaps(self, other):
+ "Returns True if this geometry overlaps the other."
+ return self._topology(capi.ogr_overlaps, other)
+
+ #### Geometry-generation Methods ####
+ def _geomgen(self, gen_func, other=None):
+ "A helper routine for the OGR routines that generate geometries."
+ if isinstance(other, OGRGeometry):
+ return OGRGeometry(gen_func(self.ptr, other.ptr), self.srs)
+ else:
+ return OGRGeometry(gen_func(self.ptr), self.srs)
+
+ @property
+ def boundary(self):
+ "Returns the boundary of this geometry."
+ return self._geomgen(capi.get_boundary)
+
+ @property
+ def convex_hull(self):
+ """
+ Returns the smallest convex Polygon that contains all the points in
+ this Geometry.
+ """
+ return self._geomgen(capi.geom_convex_hull)
+
+ def difference(self, other):
+ """
+ Returns a new geometry consisting of the region which is the difference
+ of this geometry and the other.
+ """
+ return self._geomgen(capi.geom_diff, other)
+
+ def intersection(self, other):
+ """
+ Returns a new geometry consisting of the region of intersection of this
+ geometry and the other.
+ """
+ return self._geomgen(capi.geom_intersection, other)
+
+ def sym_difference(self, other):
+ """
+ Returns a new geometry which is the symmetric difference of this
+ geometry and the other.
+ """
+ return self._geomgen(capi.geom_sym_diff, other)
+
+ def union(self, other):
+ """
+ Returns a new geometry consisting of the region which is the union of
+ this geometry and the other.
+ """
+ return self._geomgen(capi.geom_union, other)
+
+# The subclasses for OGR Geometry.
+class Point(OGRGeometry):
+
+ @property
+ def x(self):
+ "Returns the X coordinate for this Point."
+ return capi.getx(self.ptr, 0)
+
+ @property
+ def y(self):
+ "Returns the Y coordinate for this Point."
+ return capi.gety(self.ptr, 0)
+
+ @property
+ def z(self):
+ "Returns the Z coordinate for this Point."
+ if self.coord_dim == 3:
+ return capi.getz(self.ptr, 0)
+
+ @property
+ def tuple(self):
+ "Returns the tuple of this point."
+ if self.coord_dim == 2:
+ return (self.x, self.y)
+ elif self.coord_dim == 3:
+ return (self.x, self.y, self.z)
+ coords = tuple
+
+class LineString(OGRGeometry):
+
+ def __getitem__(self, index):
+ "Returns the Point at the given index."
+ if index >= 0 and index < self.point_count:
+ x, y, z = c_double(), c_double(), c_double()
+ capi.get_point(self.ptr, index, byref(x), byref(y), byref(z))
+ dim = self.coord_dim
+ if dim == 1:
+ return (x.value,)
+ elif dim == 2:
+ return (x.value, y.value)
+ elif dim == 3:
+ return (x.value, y.value, z.value)
+ else:
+ raise OGRIndexError('index out of range: %s' % str(index))
+
+ def __iter__(self):
+ "Iterates over each point in the LineString."
+ for i in xrange(self.point_count):
+ yield self[i]
+
+ def __len__(self):
+ "The length returns the number of points in the LineString."
+ return self.point_count
+
+ @property
+ def tuple(self):
+ "Returns the tuple representation of this LineString."
+ return tuple([self[i] for i in xrange(len(self))])
+ coords = tuple
+
+ def _listarr(self, func):
+ """
+ Internal routine that returns a sequence (list) corresponding with
+ the given function.
+ """
+ return [func(self.ptr, i) for i in xrange(len(self))]
+
+ @property
+ def x(self):
+ "Returns the X coordinates in a list."
+ return self._listarr(capi.getx)
+
+ @property
+ def y(self):
+ "Returns the Y coordinates in a list."
+ return self._listarr(capi.gety)
+
+ @property
+ def z(self):
+ "Returns the Z coordinates in a list."
+ if self.coord_dim == 3:
+ return self._listarr(capi.getz)
+
+# LinearRings are used in Polygons.
+class LinearRing(LineString): pass
+
+class Polygon(OGRGeometry):
+
+ def __len__(self):
+ "The number of interior rings in this Polygon."
+ return self.geom_count
+
+ def __iter__(self):
+ "Iterates through each ring in the Polygon."
+ for i in xrange(self.geom_count):
+ yield self[i]
+
+ def __getitem__(self, index):
+ "Gets the ring at the specified index."
+ if index < 0 or index >= self.geom_count:
+ raise OGRIndexError('index out of range: %s' % index)
+ else:
+ return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
+
+ # Polygon Properties
+ @property
+ def shell(self):
+ "Returns the shell of this Polygon."
+ return self[0] # First ring is the shell
+ exterior_ring = shell
+
+ @property
+ def tuple(self):
+ "Returns a tuple of LinearRing coordinate tuples."
+ return tuple([self[i].tuple for i in xrange(self.geom_count)])
+ coords = tuple
+
+ @property
+ def point_count(self):
+ "The number of Points in this Polygon."
+ # Summing up the number of points in each ring of the Polygon.
+ return sum([self[i].point_count for i in xrange(self.geom_count)])
+
+ @property
+ def centroid(self):
+ "Returns the centroid (a Point) of this Polygon."
+ # The centroid is a Point, create a geometry for this.
+ p = OGRGeometry(OGRGeomType('Point'))
+ capi.get_centroid(self.ptr, p.ptr)
+ return p
+
+# Geometry Collection base class.
+class GeometryCollection(OGRGeometry):
+ "The Geometry Collection class."
+
+ def __getitem__(self, index):
+ "Gets the Geometry at the specified index."
+ if index < 0 or index >= self.geom_count:
+ raise OGRIndexError('index out of range: %s' % index)
+ else:
+ return OGRGeometry(capi.clone_geom(capi.get_geom_ref(self.ptr, index)), self.srs)
+
+ def __iter__(self):
+ "Iterates over each Geometry."
+ for i in xrange(self.geom_count):
+ yield self[i]
+
+ def __len__(self):
+ "The number of geometries in this Geometry Collection."
+ return self.geom_count
+
+ def add(self, geom):
+ "Add the geometry to this Geometry Collection."
+ if isinstance(geom, OGRGeometry):
+ if isinstance(geom, self.__class__):
+ for g in geom: capi.add_geom(self.ptr, g.ptr)
+ else:
+ capi.add_geom(self.ptr, geom.ptr)
+ elif isinstance(geom, six.string_types):
+ tmp = OGRGeometry(geom)
+ capi.add_geom(self.ptr, tmp.ptr)
+ else:
+ raise OGRException('Must add an OGRGeometry.')
+
+ @property
+ def point_count(self):
+ "The number of Points in this Geometry Collection."
+ # Summing up the number of points in each geometry in this collection
+ return sum([self[i].point_count for i in xrange(self.geom_count)])
+
+ @property
+ def tuple(self):
+ "Returns a tuple representation of this Geometry Collection."
+ return tuple([self[i].tuple for i in xrange(self.geom_count)])
+ coords = tuple
+
+# Multiple Geometry types.
+class MultiPoint(GeometryCollection): pass
+class MultiLineString(GeometryCollection): pass
+class MultiPolygon(GeometryCollection): pass
+
+# Class mapping dictionary (using the OGRwkbGeometryType as the key)
+GEO_CLASSES = {1 : Point,
+ 2 : LineString,
+ 3 : Polygon,
+ 4 : MultiPoint,
+ 5 : MultiLineString,
+ 6 : MultiPolygon,
+ 7 : GeometryCollection,
+ 101: LinearRing,
+ 1 + OGRGeomType.wkb25bit : Point,
+ 2 + OGRGeomType.wkb25bit : LineString,
+ 3 + OGRGeomType.wkb25bit : Polygon,
+ 4 + OGRGeomType.wkb25bit : MultiPoint,
+ 5 + OGRGeomType.wkb25bit : MultiLineString,
+ 6 + OGRGeomType.wkb25bit : MultiPolygon,
+ 7 + OGRGeomType.wkb25bit : GeometryCollection,
+ }