/django/contrib/gis/gdal/srs.py
Python | 337 lines | 324 code | 1 blank | 12 comment | 14 complexity | 2d225133c23fdd5793fe0a0542fa5839 MD5 | raw file
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""" 29import re 30from ctypes import byref, c_char_p, c_int, c_void_p 31 32# Getting the error checking routine and exceptions 33from django.contrib.gis.gdal.base import GDALBase 34from django.contrib.gis.gdal.error import OGRException, SRSException 35from django.contrib.gis.gdal.prototypes import srs as capi 36 37#### Spatial Reference class. #### 38class SpatialReference(GDALBase): 39 """ 40 A wrapper for the OGRSpatialReference object. According to the GDAL Web site, 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 321class 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)