diff options
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.py | 726 |
1 files changed, 0 insertions, 726 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 deleted file mode 100644 index 0d75620..0000000 --- a/lib/python2.7/site-packages/django/contrib/gis/gdal/geometries.py +++ /dev/null @@ -1,726 +0,0 @@ -""" - 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, - } |