| 1 |
""" |
|---|
| 2 |
The GDAL/OGR library uses an Envelope structure to hold the bounding |
|---|
| 3 |
box information for a geometry. The envelope (bounding box) contains |
|---|
| 4 |
two pairs of coordinates, one for the lower left coordinate and one |
|---|
| 5 |
for the upper right coordinate: |
|---|
| 6 |
|
|---|
| 7 |
+----------o Upper right; (max_x, max_y) |
|---|
| 8 |
| | |
|---|
| 9 |
| | |
|---|
| 10 |
| | |
|---|
| 11 |
Lower left (min_x, min_y) o----------+ |
|---|
| 12 |
""" |
|---|
| 13 |
from ctypes import Structure, c_double |
|---|
| 14 |
from types import TupleType, ListType |
|---|
| 15 |
from django.contrib.gis.gdal.error import OGRException |
|---|
| 16 |
|
|---|
| 17 |
# The OGR definition of an Envelope is a C structure containing four doubles. |
|---|
| 18 |
# See the 'ogr_core.h' source file for more information: |
|---|
| 19 |
# http://www.gdal.org/ogr/ogr__core_8h-source.html |
|---|
| 20 |
class OGREnvelope(Structure): |
|---|
| 21 |
"Represents the OGREnvelope C Structure." |
|---|
| 22 |
_fields_ = [("MinX", c_double), |
|---|
| 23 |
("MaxX", c_double), |
|---|
| 24 |
("MinY", c_double), |
|---|
| 25 |
("MaxY", c_double), |
|---|
| 26 |
] |
|---|
| 27 |
|
|---|
| 28 |
class Envelope(object): |
|---|
| 29 |
""" |
|---|
| 30 |
The Envelope object is a C structure that contains the minimum and |
|---|
| 31 |
maximum X, Y coordinates for a rectangle bounding box. The naming |
|---|
| 32 |
of the variables is compatible with the OGR Envelope structure. |
|---|
| 33 |
""" |
|---|
| 34 |
|
|---|
| 35 |
def __init__(self, *args): |
|---|
| 36 |
""" |
|---|
| 37 |
The initialization function may take an OGREnvelope structure, 4-element |
|---|
| 38 |
tuple or list, or 4 individual arguments. |
|---|
| 39 |
""" |
|---|
| 40 |
|
|---|
| 41 |
if len(args) == 1: |
|---|
| 42 |
if isinstance(args[0], OGREnvelope): |
|---|
| 43 |
# OGREnvelope (a ctypes Structure) was passed in. |
|---|
| 44 |
self._envelope = args[0] |
|---|
| 45 |
elif isinstance(args[0], (TupleType, ListType)): |
|---|
| 46 |
# A tuple was passed in. |
|---|
| 47 |
if len(args[0]) != 4: |
|---|
| 48 |
raise OGRException('Incorrect number of tuple elements (%d).' % len(args[0])) |
|---|
| 49 |
else: |
|---|
| 50 |
self._from_sequence(args[0]) |
|---|
| 51 |
else: |
|---|
| 52 |
raise TypeError('Incorrect type of argument: %s' % str(type(args[0]))) |
|---|
| 53 |
elif len(args) == 4: |
|---|
| 54 |
# Individiual parameters passed in. |
|---|
| 55 |
# Thanks to ww for the help |
|---|
| 56 |
self._from_sequence(map(float, args)) |
|---|
| 57 |
else: |
|---|
| 58 |
raise OGRException('Incorrect number (%d) of arguments.' % len(args)) |
|---|
| 59 |
|
|---|
| 60 |
# Checking the x,y coordinates |
|---|
| 61 |
if self.min_x >= self.max_x: |
|---|
| 62 |
raise OGRException('Envelope minimum X >= maximum X.') |
|---|
| 63 |
if self.min_y >= self.max_y: |
|---|
| 64 |
raise OGRException('Envelope minimum Y >= maximum Y.') |
|---|
| 65 |
|
|---|
| 66 |
def __eq__(self, other): |
|---|
| 67 |
""" |
|---|
| 68 |
Returns True if the envelopes are equivalent; can compare against |
|---|
| 69 |
other Envelopes and 4-tuples. |
|---|
| 70 |
""" |
|---|
| 71 |
if isinstance(other, Envelope): |
|---|
| 72 |
return (self.min_x == other.min_x) and (self.min_y == other.min_y) and \ |
|---|
| 73 |
(self.max_x == other.max_x) and (self.max_y == other.max_y) |
|---|
| 74 |
elif isinstance(other, TupleType) and len(other) == 4: |
|---|
| 75 |
return (self.min_x == other[0]) and (self.min_y == other[1]) and \ |
|---|
| 76 |
(self.max_x == other[2]) and (self.max_y == other[3]) |
|---|
| 77 |
else: |
|---|
| 78 |
raise OGRException('Equivalence testing only works with other Envelopes.') |
|---|
| 79 |
|
|---|
| 80 |
def __str__(self): |
|---|
| 81 |
"Returns a string representation of the tuple." |
|---|
| 82 |
return str(self.tuple) |
|---|
| 83 |
|
|---|
| 84 |
def _from_sequence(self, seq): |
|---|
| 85 |
"Initializes the C OGR Envelope structure from the given sequence." |
|---|
| 86 |
self._envelope = OGREnvelope() |
|---|
| 87 |
self._envelope.MinX = seq[0] |
|---|
| 88 |
self._envelope.MinY = seq[1] |
|---|
| 89 |
self._envelope.MaxX = seq[2] |
|---|
| 90 |
self._envelope.MaxY = seq[3] |
|---|
| 91 |
|
|---|
| 92 |
@property |
|---|
| 93 |
def min_x(self): |
|---|
| 94 |
"Returns the value of the minimum X coordinate." |
|---|
| 95 |
return self._envelope.MinX |
|---|
| 96 |
|
|---|
| 97 |
@property |
|---|
| 98 |
def min_y(self): |
|---|
| 99 |
"Returns the value of the minimum Y coordinate." |
|---|
| 100 |
return self._envelope.MinY |
|---|
| 101 |
|
|---|
| 102 |
@property |
|---|
| 103 |
def max_x(self): |
|---|
| 104 |
"Returns the value of the maximum X coordinate." |
|---|
| 105 |
return self._envelope.MaxX |
|---|
| 106 |
|
|---|
| 107 |
@property |
|---|
| 108 |
def max_y(self): |
|---|
| 109 |
"Returns the value of the maximum Y coordinate." |
|---|
| 110 |
return self._envelope.MaxY |
|---|
| 111 |
|
|---|
| 112 |
@property |
|---|
| 113 |
def ur(self): |
|---|
| 114 |
"Returns the upper-right coordinate." |
|---|
| 115 |
return (self.max_x, self.max_y) |
|---|
| 116 |
|
|---|
| 117 |
@property |
|---|
| 118 |
def ll(self): |
|---|
| 119 |
"Returns the lower-left coordinate." |
|---|
| 120 |
return (self.min_x, self.min_y) |
|---|
| 121 |
|
|---|
| 122 |
@property |
|---|
| 123 |
def tuple(self): |
|---|
| 124 |
"Returns a tuple representing the envelope." |
|---|
| 125 |
return (self.min_x, self.min_y, self.max_x, self.max_y) |
|---|
| 126 |
|
|---|
| 127 |
@property |
|---|
| 128 |
def wkt(self): |
|---|
| 129 |
"Returns WKT representing a Polygon for this envelope." |
|---|
| 130 |
# TODO: Fix significant figures. |
|---|
| 131 |
return 'POLYGON((%s %s,%s %s,%s %s,%s %s,%s %s))' % \ |
|---|
| 132 |
(self.min_x, self.min_y, self.min_x, self.max_y, |
|---|
| 133 |
self.max_x, self.max_y, self.max_x, self.min_y, |
|---|
| 134 |
self.min_x, self.min_y) |
|---|