|
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) |