### Navigation

- index
- modules
- Home »
- Contents »
- Module code »

# Source code for safe.storage.projection

    """**Class projection**
    """

    from osgeo import osr

    # The projection string depends on the gdal version
    DEFAULT_PROJECTION = '+proj=longlat +datum=WGS84 +no_defs'

    def proj4_to_dict(P):
        """Helper to turn a proj4 string into a dictionary for ease of comparison
        See issue #304

        Args:
            P: proj4 string, such as +proj=longlat +ellps=WGS84 +no_defs

        Returns
            dictionary of individual elements, e.g. {'+proj': 'longlat',
                                                     '+ellps': 'WGS84',
                                                     '+no_defs': ''}
        """

        D = {}
        for e in P.split():
            fields = e.strip().split('=')
            if len(fields) > 1:
                val = fields[1]
            else:
                val = ''
            D[fields[0]] = val
        return D

    class Projection:
        """Represents projections associated with layers
        """

        def __init__(self, p):
            """Constructor for Projection.

            Args:
                * p: Projection information.
                     Any of the GDAL formats are OK including WKT, proj4, ESRI, XML
                     It can also be an instance of Projection.
            """

            if p is None:
                #msg = 'Requested projection is None'
                #raise TypeError(msg)
                p = DEFAULT_PROJECTION

            # Clean input string. This will also work when p is of class
            # Projection by virtue of its __repr__()
            p = str(p).strip()

            # Create OSR spatial reference object
            srs = self.spatial_reference = osr.SpatialReference()

            # Try importing
            input_OK = False
            for import_func in [srs.ImportFromProj4,
                                srs.ImportFromWkt,
                                srs.ImportFromEPSG,
                                srs.ImportFromESRI,
                                # FIXME (Ole): This one emits the warning:
                                # Warning 5: Failed parsing CoordSys:
                                # 'Indonesia TM-3 zone 48.2'
                                #srs.ImportFromMICoordSys,
                                srs.ImportFromPCI,
                                srs.ImportFromXML,
                                srs.ImportFromUSGS,
                                srs.ImportFromUrl]:

                try:
                    res = import_func(p)
                except TypeError:
                    # FIXME: NetCDF raster layer gives SRS error
                    # Occasionally we get things like
                    #   File "/usr/lib/python2.7/dist-packages/osgeo/osr.py",
                    #   line 639, in ImportFromEPSG
                    #   return _osr.SpatialReference_ImportFromEPSG(self, *args)
                    #   TypeError: in method 'SpatialReference_ImportFromEPSG',
                    #   argument 2 of type 'int'
                    # e.g. when using NetCDF multiband data. Why?
                    pass

                if res == 0:
                    input_OK = True
                    break

            if not input_OK:
                msg = 'Spatial reference %s was not recognised' % p
                raise TypeError(msg)

            # Store some - FIXME this is only for backwards compat, remove.
            self.wkt = self.get_projection(proj4=False)
            self.proj4 = self.get_projection(proj4=True)

        def __repr__(self):
            return self.wkt

        def get_projection(self, proj4=False):
            """Return projection

            Args:
                * proj4: If True, projection will be returned in proj4 format.
                         If False (default) projection will be returned in WKT
                         format

            Note:
                To compare projections, use the __eq__ method directly on the
                projection objects: E.g.
                self.projection == other.projection
            """

            if proj4:
                p = self.spatial_reference.ExportToProj4()
            else:
                p = self.spatial_reference.ExportToWkt()

            return p.strip()

        def __eq__(self, other):
            """Override '==' to allow comparison with other projection objecs
            """

            try:
                other = Projection(other)
            except Exception, e:
                msg = ('Argument to == must be a spatial reference or object'
                       ' of class Projection. I got %s with error '
                       'message: %s' % (str(other), e))
                raise TypeError(msg)

            if self.spatial_reference.IsSame(other.spatial_reference):
                # OSR comparison checks out
                return True
            else:
                # We have seen cases where the native comparison didn't work
                # for projections that should be identical. See e.g.
                # https://github.com/AIFDR/inasafe/issues/304

                # FIXME (Ole): Someone, please find out how to robustly compare
                #              projections

                # For now we do a secondary check using the proj4 string:
                # Pull +proj and +ellips fields and compare

                # Attempt to compare strings like this. This is non trivial
                # as the proj4 format does not always have the same parameters
                # conf e.g. +towgs84 or +ellps vs +datum (tsk tsk):
                # +proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs
                # +proj=longlat +ellps=WGS84 +no_defs
                #
                # And even worse:
                # +proj=longlat +datum=WGS84 +no_defs
                # +proj=longlat +ellps=WGS84 +no_defs

                # Get proj4 representations
                P1 = self.get_projection(proj4=True)
                P2 = other.get_projection(proj4=True)
                if P1 == P2:
                    # Direct comparison of proj4 strings match
                    return True
                else:
                    # Check key elements
                    D1 = proj4_to_dict(P1)
                    D2 = proj4_to_dict(P2)

                    result = True
                    for key in D1:
                        # Only compare keys that appear in both (see above)
                        if key in D2:
                            if D1[key] != D2[key]:
                                result = False
                                break
                    return result

        def __ne__(self, other):
            """Override '!=' to allow comparison with other projection objecs
            """

            return not self == other

### Navigation

- index
- modules
- Home »
- Contents »
- Module code »