""" The GDAL/OGR library uses an Envelope structure to hold the bounding box information for a geometry. The envelope (bounding box) contains two pairs of coordinates, one for the lower left coordinate and one for the upper right coordinate: +----------o Upper right; (max_x, max_y) | | | | | | Lower left (min_x, min_y) o----------+ """ from ctypes import Structure, c_double from types import TupleType, ListType from django.contrib.gis.gdal.error import OGRException # The OGR definition of an Envelope is a C structure containing four doubles. # See the 'ogr_core.h' source file for more information: # http://www.gdal.org/ogr/ogr__core_8h-source.html class OGREnvelope(Structure): "Represents the OGREnvelope C Structure." _fields_ = [("MinX", c_double), ("MaxX", c_double), ("MinY", c_double), ("MaxY", c_double), ] class Envelope(object): """ The Envelope object is a C structure that contains the minimum and maximum X, Y coordinates for a rectangle bounding box. The naming of the variables is compatible with the OGR Envelope structure. """ def __init__(self, *args): """ The initialization function may take an OGREnvelope structure, 4-element tuple or list, or 4 individual arguments. """ if len(args) == 1: if isinstance(args[0], OGREnvelope): # OGREnvelope (a ctypes Structure) was passed in. self._envelope = args[0] elif isinstance(args[0], (TupleType, ListType)): # A tuple was passed in. if len(args[0]) != 4: raise OGRException('Incorrect number of tuple elements (%d).' % len(args[0])) else: self._from_sequence(args[0]) else: raise TypeError('Incorrect type of argument: %s' % str(type(args[0]))) elif len(args) == 4: # Individiual parameters passed in. # Thanks to ww for the help self._from_sequence(map(float, args)) else: raise OGRException('Incorrect number (%d) of arguments.' % len(args)) # Checking the x,y coordinates if self.min_x >= self.max_x: raise OGRException('Envelope minimum X >= maximum X.') if self.min_y >= self.max_y: raise OGRException('Envelope minimum Y >= maximum Y.') def __eq__(self, other): """ Returns True if the envelopes are equivalent; can compare against other Envelopes and 4-tuples. """ if isinstance(other, Envelope): return (self.min_x == other.min_x) and (self.min_y == other.min_y) and \ (self.max_x == other.max_x) and (self.max_y == other.max_y) elif isinstance(other, TupleType) and len(other) == 4: return (self.min_x == other[0]) and (self.min_y == other[1]) and \ (self.max_x == other[2]) and (self.max_y == other[3]) else: raise OGRException('Equivalence testing only works with other Envelopes.') def __str__(self): "Returns a string representation of the tuple." return str(self.tuple) def _from_sequence(self, seq): "Initializes the C OGR Envelope structure from the given sequence." self._envelope = OGREnvelope() self._envelope.MinX = seq[0] self._envelope.MinY = seq[1] self._envelope.MaxX = seq[2] self._envelope.MaxY = seq[3] @property def min_x(self): "Returns the value of the minimum X coordinate." return self._envelope.MinX @property def min_y(self): "Returns the value of the minimum Y coordinate." return self._envelope.MinY @property def max_x(self): "Returns the value of the maximum X coordinate." return self._envelope.MaxX @property def max_y(self): "Returns the value of the maximum Y coordinate." return self._envelope.MaxY @property def ur(self): "Returns the upper-right coordinate." return (self.max_x, self.max_y) @property def ll(self): "Returns the lower-left coordinate." return (self.min_x, self.min_y) @property def tuple(self): "Returns a tuple representing the envelope." return (self.min_x, self.min_y, self.max_x, self.max_y) @property def wkt(self): "Returns WKT representing a Polygon for this envelope." # TODO: Fix significant figures. return 'POLYGON((%s %s,%s %s,%s %s,%s %s,%s %s))' % \ (self.min_x, self.min_y, self.min_x, self.max_y, self.max_x, self.max_y, self.max_x, self.min_y, self.min_x, self.min_y)