예제 #1
0
class TestAzimuthalEquidistantProjection(unittest.TestCase):
    def setUp(self):
        self.origin = Point(0, 0)
        self.p = AzimuthalEquidistantProjection(reference_longitude=0, reference_scale=40)

    def test_pole(self):
        self.assertEqual(self.p.project(SphericalPoint(0, 90)), self.origin)

    def test_latitude(self):
        self.assertEqual(self.p.project(SphericalPoint(0, 50)), Point(1, 0))
        self.assertEqual(self.p.project(SphericalPoint(90, 50)), Point(0, 1))
        self.assertEqual(self.p.project(SphericalPoint(180, 50)), Point(-1, 0))
        self.assertEqual(self.p.project(SphericalPoint(270, 50)), Point(0, -1))
        self.p.celestial = True
        self.assertEqual(self.p.project(SphericalPoint(0, 50)), Point(1, 0))
        self.assertEqual(self.p.project(SphericalPoint(90, 50)), Point(0, -1))
        self.assertEqual(self.p.project(SphericalPoint(180, 50)), Point(-1, 0))
        self.assertEqual(self.p.project(SphericalPoint(270, 50)), Point(0, 1))

    def test_inverse_project(self):
        self.assertEqual(self.p.inverse_project(Point(1, 0)), SphericalPoint(0, 50))
        self.assertEqual(self.p.inverse_project(Point(0, 1)), SphericalPoint(90, 50))
        self.assertEqual(self.p.inverse_project(Point(-1, 0)), SphericalPoint(180, 50))
        self.assertEqual(self.p.inverse_project(Point(0, -1)), SphericalPoint(270, 50))

        p = SphericalPoint(225, 76)
        pp = self.p.project(p)
        ppp = self.p.inverse_project(pp)
        self.assertEqual(p, ppp)

        self.p.celestial = True
        self.assertEqual(self.p.inverse_project(Point(1, 0)), SphericalPoint(0, 50))
        self.assertEqual(self.p.inverse_project(Point(0, 1)), SphericalPoint(270, 50))
        self.assertEqual(self.p.inverse_project(Point(-1, 0)), SphericalPoint(180, 50))
        self.assertEqual(self.p.inverse_project(Point(0, -1)), SphericalPoint(90, 50))

        p = SphericalPoint(225, 76)
        pp = self.p.project(p)
        ppp = self.p.inverse_project(pp)
        self.assertEqual(p, ppp)

    def test_reference_longitude(self):
        self.p.reference_longitude = 40

        self.assertEqual(self.origin.distance(self.p.project(SphericalPoint(0, 50))), 1.0)
        self.assertEqual(self.p.project(SphericalPoint(40, 50)), Point(1, 0))
        self.assertEqual(self.p.project(SphericalPoint(130, 50)), Point(0, 1))
        self.assertEqual(self.p.project(SphericalPoint(220, 50)), Point(-1, 0))
        self.assertEqual(self.p.project(SphericalPoint(310, 50)), Point(0, -1))

        p = SphericalPoint(225, 76)
        pp = self.p.project(p)
        ppp = self.p.inverse_project(pp)
        self.assertEqual(p, ppp)

        self.p.celestial = True
        self.assertEqual(self.p.project(SphericalPoint(40, 50)), Point(1, 0))
        self.assertEqual(self.p.project(SphericalPoint(130, 50)), Point(0, -1))
        self.assertEqual(self.p.project(SphericalPoint(220, 50)), Point(-1, 0))
        self.assertEqual(self.p.project(SphericalPoint(310, 50)), Point(0, 1))

        p = SphericalPoint(225, 76)
        pp = self.p.project(p)
        ppp = self.p.inverse_project(pp)
        self.assertEqual(p, ppp)

        self.p.celestial = False
        self.p.reference_longitude = -40
        self.assertEqual(self.p.project(SphericalPoint(-40, 50)), Point(1, 0))
        self.assertEqual(self.p.project(SphericalPoint(50, 50)), Point(0, 1))
        self.assertEqual(self.p.project(SphericalPoint(140, 50)), Point(-1, 0))
        self.assertEqual(self.p.project(SphericalPoint(230, 50)), Point(0, -1))

    def test_south_pole(self):
        self.p = AzimuthalEquidistantProjection(north=False, reference_longitude=0, reference_scale=40)

        # Pole
        self.assertEqual(self.p.project(SphericalPoint(0, -90)), self.origin)

        # Project
        self.assertEqual(self.p.project(SphericalPoint(0, -50)), Point(1, 0))
        self.assertEqual(self.p.project(SphericalPoint(90, -50)), Point(0, -1))
        self.assertEqual(self.p.project(SphericalPoint(180, -50)), Point(-1, 0))
        self.assertEqual(self.p.project(SphericalPoint(270, -50)), Point(0, 1))
        self.p.celestial = True
        self.assertEqual(self.p.project(SphericalPoint(0, -50)), Point(1, 0))
        self.assertEqual(self.p.project(SphericalPoint(90, -50)), Point(0, 1))
        self.assertEqual(self.p.project(SphericalPoint(180, -50)), Point(-1, 0))
        self.assertEqual(self.p.project(SphericalPoint(270, -50)), Point(0, -1))

        # Inverse project
        self.p.celestial = False
        self.assertEqual(self.p.inverse_project(Point(1, 0)), SphericalPoint(0, -50))
        self.assertEqual(self.p.inverse_project(Point(0, -1)), SphericalPoint(90, -50))
        self.assertEqual(self.p.inverse_project(Point(-1, 0)), SphericalPoint(180, -50))
        self.assertEqual(self.p.inverse_project(Point(0, 1)), SphericalPoint(270, -50))
        p = SphericalPoint(225, -76)
        pp = self.p.project(p)
        ppp = self.p.inverse_project(pp)
        self.assertEqual(p, ppp)

        self.p.celestial = True
        self.assertEqual(self.p.inverse_project(Point(1, 0)), SphericalPoint(0, -50))
        self.assertEqual(self.p.inverse_project(Point(0, 1)), SphericalPoint(90, -50))
        self.assertEqual(self.p.inverse_project(Point(-1, 0)), SphericalPoint(180, -50))
        self.assertEqual(self.p.inverse_project(Point(0, -1)), SphericalPoint(270, -50))
        p = SphericalPoint(225, -76)
        pp = self.p.project(p)
        ppp = self.p.inverse_project(pp)
        self.assertEqual(p, ppp)

    def test_other_scale(self):
        self.p = AzimuthalEquidistantProjection(reference_longitude=0, reference_scale=80.0/190.0)
        self.assertEqual(self.p.project(SphericalPoint(0, 50)), Point(95, 0))
예제 #2
0
class AzimuthalEquidistantProjection(Projection):
    def __init__(
        self,
        center_longitude=0,
        center_latitude=90,
        standard_parallel1=None,
        standard_parallel2=None,
        reference_scale=45,
        horizontal_stretch=1.0,
        celestial=False,
    ):
        """Azimuthal equidistant map projection.

        Center of projection is the pole, which gets projected to the point (0, 0).

        Args:
            center_longitude: the longitude that points to the right
            center_latitude: the latitude at the center of the map (+ or - 90 degrees)
            standard_parallel1: not used
            standard_parallel2: not used
            reference_scale: degrees of latitude per unit distance
            horizontal_stretch: factor with which to expand the horizontal axis
            celestial: longitude increases clockwise around north pole
        """
        Projection.__init__(
            self,
            center_longitude,
            center_latitude,
            standard_parallel1,
            standard_parallel2,
            reference_scale,
            horizontal_stretch,
            celestial,
        )
        self.north = center_latitude > 0
        self.origin = Point(0, 0)

        if self.north:
            if self.reference_scale >= 90:
                raise ProjectionError(
                    f"Invalid reference scale {self.reference_scale} for north pole"
                )
        else:
            self.reference_scale *= -1
            if self.reference_scale <= -90:
                raise ProjectionError(
                    f"Invalid reference scale {self.reference_scale} for south pole"
                )

    @property
    def reverse_polar_direction(self):
        """Whether increasing longitude is clockwise or anticlockwise."""
        return self.north == self.celestial

    def project(self, skycoord):
        longitude = self.reduce_longitude(skycoord.ra.degree)
        latitude = skycoord.dec.degree

        rho = (self.center_latitude - latitude) / self.reference_scale
        theta = math.radians(longitude - self.center_longitude)
        if self.reverse_polar_direction:
            theta *= -1

        return Point(self.horizontal_stretch * rho * math.cos(theta),
                     rho * math.sin(theta))

    def backproject(self, point):
        rho = self.origin.distance(point)
        theta = ensure_angle_range(math.degrees(math.atan2(point.y, point.x)))

        if self.reverse_polar_direction:
            theta *= -1

        longitude = ensure_angle_range(theta + self.center_longitude)
        latitude = (-rho * self.reference_scale / self.horizontal_stretch +
                    self.center_latitude)
        return SkyCoordDeg(longitude, latitude)

    def parallel(self, latitude, min_longitude, max_longitude):
        p = self.project(SkyCoordDeg(0, latitude))
        return Circle(self.origin, self.origin.distance(p))