Example #1
0
    def __init__(self, srs_code):
        """
        Create a new SRS with the given `srs_code` code.
        """
        self.srs_code = srs_code

        init = _SRS.proj_init.get(srs_code, None)
        if init is not None:
            self.proj = init()
        else:
            epsg_num = get_epsg_num(srs_code)
            self.proj = Proj(init='epsg:%d' % epsg_num)
Example #2
0
    def __init__(self, srs_code):
        """
        Create a new SRS with the given `srs_code` code.
        """
        self.srs_code = srs_code

        init = _SRS.proj_init.get(srs_code, None)
        if init is not None:
            self.proj = init()
        else:
            epsg_num = get_epsg_num(srs_code)
            self.proj = Proj(init='epsg:%d' % epsg_num)
Example #3
0
class _SRS(object):
    # http://trac.openlayers.org/wiki/SphericalMercator
    proj_init = {
        'EPSG:4326':
        lambda: Proj('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +over'),
        'CRS:84':
        lambda: Proj('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +over'),
    }
    for _epsg in WEBMERCATOR_EPSG:
        proj_init[_epsg] = lambda: Proj(
            '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 '
            '+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m '
            '+nadgrids=@null +no_defs +over')
    """
    This class represents a Spatial Reference System.
    """
    def __init__(self, srs_code):
        """
        Create a new SRS with the given `srs_code` code.
        """
        self.srs_code = srs_code

        init = _SRS.proj_init.get(srs_code, None)
        if init is not None:
            self.proj = init()
        else:
            epsg_num = get_epsg_num(srs_code)
            self.proj = Proj(init='epsg:%d' % epsg_num)

    def transform_to(self, other_srs, points):
        """
        :type points: ``(x, y)`` or ``[(x1, y1), (x2, y2), …]``

        >>> srs1 = SRS(4326)
        >>> srs2 = SRS(900913)
        >>> [str(round(x, 5)) for x in srs1.transform_to(srs2, (8.22, 53.15))]
        ['915046.21432', '7010792.20171']
        >>> srs1.transform_to(srs1, (8.25, 53.5))
        (8.25, 53.5)
        >>> [(str(round(x, 5)), str(round(y, 5))) for x, y in
        ...  srs1.transform_to(srs2, [(8.2, 53.1), (8.22, 53.15), (8.3, 53.2)])]
        ... #doctest: +NORMALIZE_WHITESPACE
        [('912819.8245', '7001516.67745'),
         ('915046.21432', '7010792.20171'),
         ('923951.77358', '7020078.53264')]
        """
        if self == other_srs:
            return points
        if isinstance(points[0], (int, float)) and 2 >= len(points) <= 3:
            return transform(self.proj, other_srs.proj, *points)

        x = [p[0] for p in points]
        y = [p[1] for p in points]
        transf_pts = transform(self.proj, other_srs.proj, x, y)
        return izip(transf_pts[0], transf_pts[1])

    def transform_bbox_to(self, other_srs, bbox, with_points=16):
        """

        :param with_points: the number of points to use for the transformation.
            A bbox transformation with only two or four points may cut off some
            parts due to distortions.

        >>> ['%.3f' % x for x in
        ...  SRS(4326).transform_bbox_to(SRS(900913), (-180.0, -90.0, 180.0, 90.0))]
        ['-20037508.343', '-147730762.670', '20037508.343', '147730758.195']
        >>> ['%.5f' % x for x in
        ...  SRS(4326).transform_bbox_to(SRS(900913), (8.2, 53.1, 8.3, 53.2))]
        ['912819.82450', '7001516.67745', '923951.77358', '7020078.53264']
        >>> SRS(4326).transform_bbox_to(SRS(4326), (8.25, 53.0, 8.5, 53.75))
        (8.25, 53.0, 8.5, 53.75)
        """
        if self == other_srs:
            return bbox
        bbox = self.align_bbox(bbox)
        points = generate_envelope_points(bbox, with_points)
        transf_pts = self.transform_to(other_srs, points)
        result = calculate_bbox(transf_pts)

        log_proj.debug('transformed from %r to %r (%s -> %s)' %
                       (self, other_srs, bbox, result))

        return result

    def align_bbox(self, bbox):
        """
        Align bbox to reasonable values to prevent errors in transformations.
        E.g. transformations from EPSG:4326 with lat=90 or -90 will fail, so
        we subtract a tiny delta.

        At the moment only EPSG:4326 bbox will be modifyed.

        >>> bbox = SRS(4326).align_bbox((-180, -90, 180, 90))
        >>> -90 < bbox[1] < -89.99999998
        True
        >>> 90 > bbox[3] > 89.99999998
        True
        """
        # TODO should not be needed anymore since we transform with +over
        # still a few tests depend on the rounding behavior of this
        if self.srs_code == 'EPSG:4326':
            delta = 0.00000001
            (minx, miny, maxx, maxy) = bbox
            if abs(miny - -90.0) < 1e-6:
                miny = -90.0 + delta
            if abs(maxy - 90.0) < 1e-6:
                maxy = 90.0 - delta
            bbox = minx, miny, maxx, maxy
        return bbox

    @property
    def is_latlong(self):
        """
        >>> SRS(4326).is_latlong
        True
        >>> SRS(31466).is_latlong
        False
        """
        return self.proj.is_latlong()

    @property
    def is_axis_order_ne(self):
        """
        Returns `True` if the axis order is North, then East
        (i.e. y/x or lat/lon).

        >>> SRS(4326).is_axis_order_ne
        True
        >>> SRS('CRS:84').is_axis_order_ne
        False
        >>> SRS(31468).is_axis_order_ne
        True
        >>> SRS(31463).is_axis_order_ne
        False
        >>> SRS(25831).is_axis_order_ne
        False
        """
        if self.srs_code in base_config().srs.axis_order_ne:
            return True
        if self.srs_code in base_config().srs.axis_order_en:
            return False
        if self.is_latlong:
            return True
        return False

    @property
    def is_axis_order_en(self):
        """
        Returns `True` if the axis order is East then North
        (i.e. x/y or lon/lat).
        """
        return not self.is_axis_order_ne

    def __eq__(self, other):
        """
        >>> SRS(4326) == SRS("EpsG:4326")
        True
        >>> SRS(4326) == SRS("4326")
        True
        >>> SRS(4326) == SRS(3857)
        False
        """
        if isinstance(other, _SRS):
            return self.proj.srs == other.proj.srs
        else:
            return NotImplemented

    def __ne__(self, other):
        """
        >>> SRS(3857) != SRS(3857)
        False
        >>> SRS(4326) != SRS(900913)
        True
        """
        equal_result = self.__eq__(other)
        if equal_result is NotImplemented:
            return NotImplemented
        else:
            return not equal_result

    def __str__(self):
        #pylint: disable-msg=E1101
        return "SRS %s ('%s')" % (self.srs_code, self.proj.srs)

    def __repr__(self):
        """
        >>> repr(SRS(4326))
        "SRS('EPSG:4326')"
        """
        return "SRS('%s')" % (self.srs_code, )

    def __hash__(self):
        return hash(self.srs_code)
Example #4
0
class _SRS(object):
    # http://trac.openlayers.org/wiki/SphericalMercator
    proj_init = {
                 'EPSG:4326': lambda: Proj('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +over'),
                 'CRS:84': lambda: Proj('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +over'),
                }
    for _epsg in WEBMERCATOR_EPSG:
        proj_init[_epsg] = lambda: Proj(
            '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 '
            '+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m '
            '+nadgrids=@null +no_defs +over')

    """
    This class represents a Spatial Reference System.
    """
    def __init__(self, srs_code):
        """
        Create a new SRS with the given `srs_code` code.
        """
        self.srs_code = srs_code

        init = _SRS.proj_init.get(srs_code, None)
        if init is not None:
            self.proj = init()
        else:
            epsg_num = get_epsg_num(srs_code)
            self.proj = Proj(init='epsg:%d' % epsg_num)

    def transform_to(self, other_srs, points):
        """
        :type points: ``(x, y)`` or ``[(x1, y1), (x2, y2), …]``

        >>> srs1 = SRS(4326)
        >>> srs2 = SRS(900913)
        >>> [str(round(x, 5)) for x in srs1.transform_to(srs2, (8.22, 53.15))]
        ['915046.21432', '7010792.20171']
        >>> srs1.transform_to(srs1, (8.25, 53.5))
        (8.25, 53.5)
        >>> [(str(round(x, 5)), str(round(y, 5))) for x, y in
        ...  srs1.transform_to(srs2, [(8.2, 53.1), (8.22, 53.15), (8.3, 53.2)])]
        ... #doctest: +NORMALIZE_WHITESPACE
        [('912819.8245', '7001516.67745'),
         ('915046.21432', '7010792.20171'),
         ('923951.77358', '7020078.53264')]
        """
        if self == other_srs:
            return points
        if isinstance(points[0], (int, float)) and 2 >= len(points) <= 3:
            return transform(self.proj, other_srs.proj, *points)

        x = [p[0] for p in points]
        y = [p[1] for p in points]
        transf_pts = transform(self.proj, other_srs.proj, x, y)
        return izip(transf_pts[0], transf_pts[1])

    def transform_bbox_to(self, other_srs, bbox, with_points=16):
        """

        :param with_points: the number of points to use for the transformation.
            A bbox transformation with only two or four points may cut off some
            parts due to distortions.

        >>> ['%.3f' % x for x in
        ...  SRS(4326).transform_bbox_to(SRS(900913), (-180.0, -90.0, 180.0, 90.0))]
        ['-20037508.343', '-147730762.670', '20037508.343', '147730758.195']
        >>> ['%.5f' % x for x in
        ...  SRS(4326).transform_bbox_to(SRS(900913), (8.2, 53.1, 8.3, 53.2))]
        ['912819.82450', '7001516.67745', '923951.77358', '7020078.53264']
        >>> SRS(4326).transform_bbox_to(SRS(4326), (8.25, 53.0, 8.5, 53.75))
        (8.25, 53.0, 8.5, 53.75)
        """
        if self == other_srs:
            return bbox
        bbox = self.align_bbox(bbox)
        points = generate_envelope_points(bbox, with_points)
        transf_pts = self.transform_to(other_srs, points)
        result = calculate_bbox(transf_pts)

        log_proj.debug('transformed from %r to %r (%s -> %s)' %
                  (self, other_srs, bbox, result))

        return result

    def align_bbox(self, bbox):
        """
        Align bbox to reasonable values to prevent errors in transformations.
        E.g. transformations from EPSG:4326 with lat=90 or -90 will fail, so
        we subtract a tiny delta.

        At the moment only EPSG:4326 bbox will be modifyed.

        >>> bbox = SRS(4326).align_bbox((-180, -90, 180, 90))
        >>> -90 < bbox[1] < -89.99999998
        True
        >>> 90 > bbox[3] > 89.99999998
        True
        """
        # TODO should not be needed anymore since we transform with +over
        # still a few tests depend on the rounding behavior of this
        if self.srs_code == 'EPSG:4326':
            delta = 0.00000001
            (minx, miny, maxx, maxy) = bbox
            if abs(miny - -90.0) < 1e-6:
                miny = -90.0 + delta
            if abs(maxy - 90.0) < 1e-6:
                maxy = 90.0 - delta
            bbox = minx, miny, maxx, maxy
        return bbox

    @property
    def is_latlong(self):
        """
        >>> SRS(4326).is_latlong
        True
        >>> SRS(31466).is_latlong
        False
        """
        return self.proj.is_latlong()

    @property
    def is_axis_order_ne(self):
        """
        Returns `True` if the axis order is North, then East
        (i.e. y/x or lat/lon).

        >>> SRS(4326).is_axis_order_ne
        True
        >>> SRS('CRS:84').is_axis_order_ne
        False
        >>> SRS(31468).is_axis_order_ne
        True
        >>> SRS(31463).is_axis_order_ne
        False
        >>> SRS(25831).is_axis_order_ne
        False
        """
        if self.srs_code in base_config().srs.axis_order_ne:
            return True
        if self.srs_code in base_config().srs.axis_order_en:
            return False
        if self.is_latlong:
            return True
        return False

    @property
    def is_axis_order_en(self):
        """
        Returns `True` if the axis order is East then North
        (i.e. x/y or lon/lat).
        """
        return not self.is_axis_order_ne

    def __eq__(self, other):
        """
        >>> SRS(4326) == SRS("EpsG:4326")
        True
        >>> SRS(4326) == SRS("4326")
        True
        >>> SRS(4326) == SRS(900913)
        False
        >>> SRS(3857) == SRS(900913)
        True
        >>> SRS(900913) == SRS(3857)
        True

        """
        if isinstance(other, _SRS):
            if (self.srs_code in WEBMERCATOR_EPSG
                and other.srs_code in WEBMERCATOR_EPSG):
                return True
            return self.proj.srs == other.proj.srs
        else:
            return NotImplemented
    def __ne__(self, other):
        """
        >>> SRS(900913) != SRS(900913)
        False
        >>> SRS(4326) != SRS(900913)
        True
        """
        equal_result = self.__eq__(other)
        if equal_result is NotImplemented:
            return NotImplemented
        else:
            return not equal_result
    def __str__(self):
        #pylint: disable-msg=E1101
        return "SRS %s ('%s')" % (self.srs_code, self.proj.srs)

    def __repr__(self):
        """
        >>> repr(SRS(4326))
        "SRS('EPSG:4326')"
        """
        return "SRS('%s')" % (self.srs_code,)

    def __hash__(self):
        return hash(self.srs_code)