web/lib/django/contrib/gis/gdal/srs.py
changeset 0 0d40e90630ef
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     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)