web/lib/django/contrib/gis/models.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
     1 """
     1 from django.db import connection
     2  Imports the SpatialRefSys and GeometryColumns models dependent on the
       
     3  spatial database backend.
       
     4 """
       
     5 import re
       
     6 from django.conf import settings
       
     7 
     2 
     8 # Checking for the presence of GDAL (needed for the SpatialReference object)
     3 if (hasattr(connection.ops, 'spatial_version') and
     9 from django.contrib.gis.gdal import HAS_GDAL, PYTHON23
     4     not connection.ops.mysql):
    10 if HAS_GDAL:
     5     # Getting the `SpatialRefSys` and `GeometryColumns`
    11     from django.contrib.gis.gdal import SpatialReference
     6     # models for the default spatial backend.  These
    12 
     7     # aliases are provided for backwards-compatibility.
    13 class SpatialRefSysMixin(object):
     8     SpatialRefSys = connection.ops.spatial_ref_sys()
    14     """
     9     GeometryColumns = connection.ops.geometry_columns()
    15     The SpatialRefSysMixin is a class used by the database-dependent
       
    16     SpatialRefSys objects to reduce redundnant code.
       
    17     """
       
    18     # For pulling out the spheroid from the spatial reference string. This
       
    19     # regular expression is used only if the user does not have GDAL installed.
       
    20     # TODO: Flattening not used in all ellipsoids, could also be a minor axis,
       
    21     # or 'b' parameter.
       
    22     spheroid_regex = re.compile(r'.+SPHEROID\[\"(?P<name>.+)\",(?P<major>\d+(\.\d+)?),(?P<flattening>\d{3}\.\d+),')
       
    23 
       
    24     # For pulling out the units on platforms w/o GDAL installed.
       
    25     # TODO: Figure out how to pull out angular units of projected coordinate system and
       
    26     # fix for LOCAL_CS types.  GDAL should be highly recommended for performing
       
    27     # distance queries.
       
    28     units_regex = re.compile(r'.+UNIT ?\["(?P<unit_name>[\w \'\(\)]+)", ?(?P<unit>[\d\.]+)(,AUTHORITY\["(?P<unit_auth_name>[\w \'\(\)]+)","(?P<unit_auth_val>\d+)"\])?\]([\w ]+)?(,AUTHORITY\["(?P<auth_name>[\w \'\(\)]+)","(?P<auth_val>\d+)"\])?\]$')
       
    29 
       
    30     def srs(self):
       
    31         """
       
    32         Returns a GDAL SpatialReference object, if GDAL is installed.
       
    33         """
       
    34         if HAS_GDAL:
       
    35             # TODO: Is caching really necessary here?  Is complexity worth it?
       
    36             if hasattr(self, '_srs'):
       
    37                 # Returning a clone of the cached SpatialReference object.
       
    38                 return self._srs.clone()
       
    39             else:
       
    40                 # Attempting to cache a SpatialReference object.
       
    41 
       
    42                 # Trying to get from WKT first.
       
    43                 try:
       
    44                     self._srs = SpatialReference(self.wkt)
       
    45                     return self.srs
       
    46                 except Exception, msg:
       
    47                     pass
       
    48 
       
    49                 try:
       
    50                     self._srs = SpatialReference(self.proj4text)
       
    51                     return self.srs
       
    52                 except Exception, msg:
       
    53                     pass
       
    54 
       
    55                 raise Exception('Could not get OSR SpatialReference from WKT: %s\nError:\n%s' % (self.wkt, msg))
       
    56         else:
       
    57             raise Exception('GDAL is not installed.')
       
    58     srs = property(srs)
       
    59 
       
    60     def ellipsoid(self):
       
    61         """
       
    62         Returns a tuple of the ellipsoid parameters:
       
    63         (semimajor axis, semiminor axis, and inverse flattening).
       
    64         """
       
    65         if HAS_GDAL:
       
    66             return self.srs.ellipsoid
       
    67         else:
       
    68             m = self.spheroid_regex.match(self.wkt)
       
    69             if m: return (float(m.group('major')), float(m.group('flattening')))
       
    70             else: return None
       
    71     ellipsoid = property(ellipsoid)
       
    72 
       
    73     def name(self):
       
    74         "Returns the projection name."
       
    75         return self.srs.name
       
    76     name = property(name)
       
    77 
       
    78     def spheroid(self):
       
    79         "Returns the spheroid name for this spatial reference."
       
    80         return self.srs['spheroid']
       
    81     spheroid = property(spheroid)
       
    82 
       
    83     def datum(self):
       
    84         "Returns the datum for this spatial reference."
       
    85         return self.srs['datum']
       
    86     datum = property(datum)
       
    87 
       
    88     def projected(self):
       
    89         "Is this Spatial Reference projected?"
       
    90         if HAS_GDAL:
       
    91             return self.srs.projected
       
    92         else:
       
    93             return self.wkt.startswith('PROJCS')
       
    94     projected = property(projected)
       
    95 
       
    96     def local(self):
       
    97         "Is this Spatial Reference local?"
       
    98         if HAS_GDAL:
       
    99             return self.srs.local
       
   100         else:
       
   101             return self.wkt.startswith('LOCAL_CS')
       
   102     local = property(local)
       
   103 
       
   104     def geographic(self):
       
   105         "Is this Spatial Reference geographic?"
       
   106         if HAS_GDAL:
       
   107             return self.srs.geographic
       
   108         else:
       
   109             return self.wkt.startswith('GEOGCS')
       
   110     geographic = property(geographic)
       
   111 
       
   112     def linear_name(self):
       
   113         "Returns the linear units name."
       
   114         if HAS_GDAL:
       
   115             return self.srs.linear_name
       
   116         elif self.geographic:
       
   117             return None
       
   118         else:
       
   119             m = self.units_regex.match(self.wkt)
       
   120             return m.group('unit_name')
       
   121     linear_name = property(linear_name)
       
   122 
       
   123     def linear_units(self):
       
   124         "Returns the linear units."
       
   125         if HAS_GDAL:
       
   126             return self.srs.linear_units
       
   127         elif self.geographic:
       
   128             return None
       
   129         else:
       
   130             m = self.units_regex.match(self.wkt)
       
   131             return m.group('unit')
       
   132     linear_units = property(linear_units)
       
   133 
       
   134     def angular_name(self):
       
   135         "Returns the name of the angular units."
       
   136         if HAS_GDAL:
       
   137             return self.srs.angular_name
       
   138         elif self.projected:
       
   139             return None
       
   140         else:
       
   141             m = self.units_regex.match(self.wkt)
       
   142             return m.group('unit_name')
       
   143     angular_name = property(angular_name)
       
   144 
       
   145     def angular_units(self):
       
   146         "Returns the angular units."
       
   147         if HAS_GDAL:
       
   148             return self.srs.angular_units
       
   149         elif self.projected:
       
   150             return None
       
   151         else:
       
   152             m = self.units_regex.match(self.wkt)
       
   153             return m.group('unit')
       
   154     angular_units = property(angular_units)
       
   155 
       
   156     def units(self):
       
   157         "Returns a tuple of the units and the name."
       
   158         if self.projected or self.local:
       
   159             return (self.linear_units, self.linear_name)
       
   160         elif self.geographic:
       
   161             return (self.angular_units, self.angular_name)
       
   162         else:
       
   163             return (None, None)
       
   164     units = property(units)
       
   165 
       
   166     def get_units(cls, wkt):
       
   167         """
       
   168         Class method used by GeometryField on initialization to
       
   169         retrive the units on the given WKT, without having to use
       
   170         any of the database fields.
       
   171         """
       
   172         if HAS_GDAL:
       
   173             return SpatialReference(wkt).units
       
   174         else:
       
   175             m = cls.units_regex.match(wkt)
       
   176             return m.group('unit'), m.group('unit_name')
       
   177     get_units = classmethod(get_units)
       
   178 
       
   179     def get_spheroid(cls, wkt, string=True):
       
   180         """
       
   181         Class method used by GeometryField on initialization to
       
   182         retrieve the `SPHEROID[..]` parameters from the given WKT.
       
   183         """
       
   184         if HAS_GDAL:
       
   185             srs = SpatialReference(wkt)
       
   186             sphere_params = srs.ellipsoid
       
   187             sphere_name = srs['spheroid']
       
   188         else:
       
   189             m = cls.spheroid_regex.match(wkt)
       
   190             if m:
       
   191                 sphere_params = (float(m.group('major')), float(m.group('flattening')))
       
   192                 sphere_name = m.group('name')
       
   193             else:
       
   194                 return None
       
   195 
       
   196         if not string:
       
   197             return sphere_name, sphere_params
       
   198         else:
       
   199             # `string` parameter used to place in format acceptable by PostGIS
       
   200             if len(sphere_params) == 3:
       
   201                 radius, flattening = sphere_params[0], sphere_params[2]
       
   202             else:
       
   203                 radius, flattening = sphere_params
       
   204             return 'SPHEROID["%s",%s,%s]' % (sphere_name, radius, flattening)
       
   205     get_spheroid = classmethod(get_spheroid)
       
   206 
       
   207     def __unicode__(self):
       
   208         """
       
   209         Returns the string representation.  If GDAL is installed,
       
   210         it will be 'pretty' OGC WKT.
       
   211         """
       
   212         try:
       
   213             return unicode(self.srs)
       
   214         except:
       
   215             return unicode(self.wkt)
       
   216 
       
   217 # Django test suite on 2.3 platforms will choke on code inside this
       
   218 # conditional.
       
   219 if not PYTHON23:
       
   220     try:
       
   221         # try/except'ing the importation of SpatialBackend.  Have to fail
       
   222         # silently because this module may be inadvertently invoked by
       
   223         # non-GeoDjango users (e.g., when the Django test suite executes
       
   224         # the models.py of all contrib apps).
       
   225         from django.contrib.gis.db.backend import SpatialBackend
       
   226         if SpatialBackend.mysql: raise Exception
       
   227 
       
   228         # Exposing the SpatialRefSys and GeometryColumns models.
       
   229         class SpatialRefSys(SpatialBackend.SpatialRefSys, SpatialRefSysMixin):
       
   230             pass
       
   231         GeometryColumns = SpatialBackend.GeometryColumns
       
   232     except:
       
   233         pass