|
1 """ |
|
2 The Spatial Reference class, represensents OGR Spatial Reference objects. |
|
3 |
|
4 Example: |
|
5 >>> from django.contrib.gis.gdal import SpatialReference |
|
6 >>> srs = SpatialReference('WGS84') |
|
7 >>> print srs |
|
8 GEOGCS["WGS 84", |
|
9 DATUM["WGS_1984", |
|
10 SPHEROID["WGS 84",6378137,298.257223563, |
|
11 AUTHORITY["EPSG","7030"]], |
|
12 TOWGS84[0,0,0,0,0,0,0], |
|
13 AUTHORITY["EPSG","6326"]], |
|
14 PRIMEM["Greenwich",0, |
|
15 AUTHORITY["EPSG","8901"]], |
|
16 UNIT["degree",0.01745329251994328, |
|
17 AUTHORITY["EPSG","9122"]], |
|
18 AUTHORITY["EPSG","4326"]] |
|
19 >>> print srs.proj |
|
20 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs |
|
21 >>> print srs.ellipsoid |
|
22 (6378137.0, 6356752.3142451793, 298.25722356300003) |
|
23 >>> print srs.projected, srs.geographic |
|
24 False True |
|
25 >>> srs.import_epsg(32140) |
|
26 >>> print srs.name |
|
27 NAD83 / Texas South Central |
|
28 """ |
|
29 import re |
|
30 from ctypes import byref, c_char_p, c_int, c_void_p |
|
31 |
|
32 # Getting the error checking routine and exceptions |
|
33 from django.contrib.gis.gdal.base import GDALBase |
|
34 from django.contrib.gis.gdal.error import OGRException, SRSException |
|
35 from django.contrib.gis.gdal.prototypes import srs as capi |
|
36 |
|
37 #### Spatial Reference class. #### |
|
38 class SpatialReference(GDALBase): |
|
39 """ |
|
40 A wrapper for the OGRSpatialReference object. According to the GDAL website, |
|
41 the SpatialReference object "provide[s] services to represent coordinate |
|
42 systems (projections and datums) and to transform between them." |
|
43 """ |
|
44 |
|
45 #### Python 'magic' routines #### |
|
46 def __init__(self, srs_input=''): |
|
47 """ |
|
48 Creates a GDAL OSR Spatial Reference object from the given input. |
|
49 The input may be string of OGC Well Known Text (WKT), an integer |
|
50 EPSG code, a PROJ.4 string, and/or a projection "well known" shorthand |
|
51 string (one of 'WGS84', 'WGS72', 'NAD27', 'NAD83'). |
|
52 """ |
|
53 buf = c_char_p('') |
|
54 srs_type = 'user' |
|
55 |
|
56 if isinstance(srs_input, basestring): |
|
57 # Encoding to ASCII if unicode passed in. |
|
58 if isinstance(srs_input, unicode): |
|
59 srs_input = srs_input.encode('ascii') |
|
60 try: |
|
61 # If SRID is a string, e.g., '4326', then make acceptable |
|
62 # as user input. |
|
63 srid = int(srs_input) |
|
64 srs_input = 'EPSG:%d' % srid |
|
65 except ValueError: |
|
66 pass |
|
67 elif isinstance(srs_input, (int, long)): |
|
68 # EPSG integer code was input. |
|
69 srs_type = 'epsg' |
|
70 elif isinstance(srs_input, self.ptr_type): |
|
71 srs = srs_input |
|
72 srs_type = 'ogr' |
|
73 else: |
|
74 raise TypeError('Invalid SRS type "%s"' % srs_type) |
|
75 |
|
76 if srs_type == 'ogr': |
|
77 # Input is already an SRS pointer. |
|
78 srs = srs_input |
|
79 else: |
|
80 # Creating a new SRS pointer, using the string buffer. |
|
81 srs = capi.new_srs(buf) |
|
82 |
|
83 # If the pointer is NULL, throw an exception. |
|
84 if not srs: |
|
85 raise SRSException('Could not create spatial reference from: %s' % srs_input) |
|
86 else: |
|
87 self.ptr = srs |
|
88 |
|
89 # Importing from either the user input string or an integer SRID. |
|
90 if srs_type == 'user': |
|
91 self.import_user_input(srs_input) |
|
92 elif srs_type == 'epsg': |
|
93 self.import_epsg(srs_input) |
|
94 |
|
95 def __del__(self): |
|
96 "Destroys this spatial reference." |
|
97 if self._ptr: capi.release_srs(self._ptr) |
|
98 |
|
99 def __getitem__(self, target): |
|
100 """ |
|
101 Returns the value of the given string attribute node, None if the node |
|
102 doesn't exist. Can also take a tuple as a parameter, (target, child), |
|
103 where child is the index of the attribute in the WKT. For example: |
|
104 |
|
105 >>> wkt = 'GEOGCS["WGS 84", DATUM["WGS_1984, ... AUTHORITY["EPSG","4326"]]') |
|
106 >>> srs = SpatialReference(wkt) # could also use 'WGS84', or 4326 |
|
107 >>> print srs['GEOGCS'] |
|
108 WGS 84 |
|
109 >>> print srs['DATUM'] |
|
110 WGS_1984 |
|
111 >>> print srs['AUTHORITY'] |
|
112 EPSG |
|
113 >>> print srs['AUTHORITY', 1] # The authority value |
|
114 4326 |
|
115 >>> print srs['TOWGS84', 4] # the fourth value in this wkt |
|
116 0 |
|
117 >>> print srs['UNIT|AUTHORITY'] # For the units authority, have to use the pipe symbole. |
|
118 EPSG |
|
119 >>> print srs['UNIT|AUTHORITY', 1] # The authority value for the untis |
|
120 9122 |
|
121 """ |
|
122 if isinstance(target, tuple): |
|
123 return self.attr_value(*target) |
|
124 else: |
|
125 return self.attr_value(target) |
|
126 |
|
127 def __str__(self): |
|
128 "The string representation uses 'pretty' WKT." |
|
129 return self.pretty_wkt |
|
130 |
|
131 #### SpatialReference Methods #### |
|
132 def attr_value(self, target, index=0): |
|
133 """ |
|
134 The attribute value for the given target node (e.g. 'PROJCS'). The index |
|
135 keyword specifies an index of the child node to return. |
|
136 """ |
|
137 if not isinstance(target, basestring) or not isinstance(index, int): |
|
138 raise TypeError |
|
139 return capi.get_attr_value(self.ptr, target, index) |
|
140 |
|
141 def auth_name(self, target): |
|
142 "Returns the authority name for the given string target node." |
|
143 return capi.get_auth_name(self.ptr, target) |
|
144 |
|
145 def auth_code(self, target): |
|
146 "Returns the authority code for the given string target node." |
|
147 return capi.get_auth_code(self.ptr, target) |
|
148 |
|
149 def clone(self): |
|
150 "Returns a clone of this SpatialReference object." |
|
151 return SpatialReference(capi.clone_srs(self.ptr)) |
|
152 |
|
153 def from_esri(self): |
|
154 "Morphs this SpatialReference from ESRI's format to EPSG." |
|
155 capi.morph_from_esri(self.ptr) |
|
156 |
|
157 def identify_epsg(self): |
|
158 """ |
|
159 This method inspects the WKT of this SpatialReference, and will |
|
160 add EPSG authority nodes where an EPSG identifier is applicable. |
|
161 """ |
|
162 capi.identify_epsg(self.ptr) |
|
163 |
|
164 def to_esri(self): |
|
165 "Morphs this SpatialReference to ESRI's format." |
|
166 capi.morph_to_esri(self.ptr) |
|
167 |
|
168 def validate(self): |
|
169 "Checks to see if the given spatial reference is valid." |
|
170 capi.srs_validate(self.ptr) |
|
171 |
|
172 #### Name & SRID properties #### |
|
173 @property |
|
174 def name(self): |
|
175 "Returns the name of this Spatial Reference." |
|
176 if self.projected: return self.attr_value('PROJCS') |
|
177 elif self.geographic: return self.attr_value('GEOGCS') |
|
178 elif self.local: return self.attr_value('LOCAL_CS') |
|
179 else: return None |
|
180 |
|
181 @property |
|
182 def srid(self): |
|
183 "Returns the SRID of top-level authority, or None if undefined." |
|
184 try: |
|
185 return int(self.attr_value('AUTHORITY', 1)) |
|
186 except (TypeError, ValueError): |
|
187 return None |
|
188 |
|
189 #### Unit Properties #### |
|
190 @property |
|
191 def linear_name(self): |
|
192 "Returns the name of the linear units." |
|
193 units, name = capi.linear_units(self.ptr, byref(c_char_p())) |
|
194 return name |
|
195 |
|
196 @property |
|
197 def linear_units(self): |
|
198 "Returns the value of the linear units." |
|
199 units, name = capi.linear_units(self.ptr, byref(c_char_p())) |
|
200 return units |
|
201 |
|
202 @property |
|
203 def angular_name(self): |
|
204 "Returns the name of the angular units." |
|
205 units, name = capi.angular_units(self.ptr, byref(c_char_p())) |
|
206 return name |
|
207 |
|
208 @property |
|
209 def angular_units(self): |
|
210 "Returns the value of the angular units." |
|
211 units, name = capi.angular_units(self.ptr, byref(c_char_p())) |
|
212 return units |
|
213 |
|
214 @property |
|
215 def units(self): |
|
216 """ |
|
217 Returns a 2-tuple of the units value and the units name, |
|
218 and will automatically determines whether to return the linear |
|
219 or angular units. |
|
220 """ |
|
221 if self.projected or self.local: |
|
222 return capi.linear_units(self.ptr, byref(c_char_p())) |
|
223 elif self.geographic: |
|
224 return capi.angular_units(self.ptr, byref(c_char_p())) |
|
225 else: |
|
226 return (None, None) |
|
227 |
|
228 #### Spheroid/Ellipsoid Properties #### |
|
229 @property |
|
230 def ellipsoid(self): |
|
231 """ |
|
232 Returns a tuple of the ellipsoid parameters: |
|
233 (semimajor axis, semiminor axis, and inverse flattening) |
|
234 """ |
|
235 return (self.semi_major, self.semi_minor, self.inverse_flattening) |
|
236 |
|
237 @property |
|
238 def semi_major(self): |
|
239 "Returns the Semi Major Axis for this Spatial Reference." |
|
240 return capi.semi_major(self.ptr, byref(c_int())) |
|
241 |
|
242 @property |
|
243 def semi_minor(self): |
|
244 "Returns the Semi Minor Axis for this Spatial Reference." |
|
245 return capi.semi_minor(self.ptr, byref(c_int())) |
|
246 |
|
247 @property |
|
248 def inverse_flattening(self): |
|
249 "Returns the Inverse Flattening for this Spatial Reference." |
|
250 return capi.invflattening(self.ptr, byref(c_int())) |
|
251 |
|
252 #### Boolean Properties #### |
|
253 @property |
|
254 def geographic(self): |
|
255 """ |
|
256 Returns True if this SpatialReference is geographic |
|
257 (root node is GEOGCS). |
|
258 """ |
|
259 return bool(capi.isgeographic(self.ptr)) |
|
260 |
|
261 @property |
|
262 def local(self): |
|
263 "Returns True if this SpatialReference is local (root node is LOCAL_CS)." |
|
264 return bool(capi.islocal(self.ptr)) |
|
265 |
|
266 @property |
|
267 def projected(self): |
|
268 """ |
|
269 Returns True if this SpatialReference is a projected coordinate system |
|
270 (root node is PROJCS). |
|
271 """ |
|
272 return bool(capi.isprojected(self.ptr)) |
|
273 |
|
274 #### Import Routines ##### |
|
275 def import_epsg(self, epsg): |
|
276 "Imports the Spatial Reference from the EPSG code (an integer)." |
|
277 capi.from_epsg(self.ptr, epsg) |
|
278 |
|
279 def import_proj(self, proj): |
|
280 "Imports the Spatial Reference from a PROJ.4 string." |
|
281 capi.from_proj(self.ptr, proj) |
|
282 |
|
283 def import_user_input(self, user_input): |
|
284 "Imports the Spatial Reference from the given user input string." |
|
285 capi.from_user_input(self.ptr, user_input) |
|
286 |
|
287 def import_wkt(self, wkt): |
|
288 "Imports the Spatial Reference from OGC WKT (string)" |
|
289 capi.from_wkt(self.ptr, byref(c_char_p(wkt))) |
|
290 |
|
291 def import_xml(self, xml): |
|
292 "Imports the Spatial Reference from an XML string." |
|
293 capi.from_xml(self.ptr, xml) |
|
294 |
|
295 #### Export Properties #### |
|
296 @property |
|
297 def wkt(self): |
|
298 "Returns the WKT representation of this Spatial Reference." |
|
299 return capi.to_wkt(self.ptr, byref(c_char_p())) |
|
300 |
|
301 @property |
|
302 def pretty_wkt(self, simplify=0): |
|
303 "Returns the 'pretty' representation of the WKT." |
|
304 return capi.to_pretty_wkt(self.ptr, byref(c_char_p()), simplify) |
|
305 |
|
306 @property |
|
307 def proj(self): |
|
308 "Returns the PROJ.4 representation for this Spatial Reference." |
|
309 return capi.to_proj(self.ptr, byref(c_char_p())) |
|
310 |
|
311 @property |
|
312 def proj4(self): |
|
313 "Alias for proj()." |
|
314 return self.proj |
|
315 |
|
316 @property |
|
317 def xml(self, dialect=''): |
|
318 "Returns the XML representation of this Spatial Reference." |
|
319 return capi.to_xml(self.ptr, byref(c_char_p()), dialect) |
|
320 |
|
321 class CoordTransform(GDALBase): |
|
322 "The coordinate system transformation object." |
|
323 |
|
324 def __init__(self, source, target): |
|
325 "Initializes on a source and target SpatialReference objects." |
|
326 if not isinstance(source, SpatialReference) or not isinstance(target, SpatialReference): |
|
327 raise TypeError('source and target must be of type SpatialReference') |
|
328 self.ptr = capi.new_ct(source._ptr, target._ptr) |
|
329 self._srs1_name = source.name |
|
330 self._srs2_name = target.name |
|
331 |
|
332 def __del__(self): |
|
333 "Deletes this Coordinate Transformation object." |
|
334 if self._ptr: capi.destroy_ct(self._ptr) |
|
335 |
|
336 def __str__(self): |
|
337 return 'Transform from "%s" to "%s"' % (self._srs1_name, self._srs2_name) |