示例#1
0
    def testSeparationValueGeneric(self):
        """Test if separation() returns the correct value.
        """
        # This should cover arcs over the meridian, across the pole, etc.
        # Do not use sphgeom as an oracle, in case SpherePoint uses it
        # internally.
        for lon1, lat1 in self._dataset:
            point1 = SpherePoint(lon1, lat1)
            x1, y1, z1 = SpherePointTestSuite.toVector(lon1, lat1)
            for lon2, lat2 in self._dataset:
                point2 = SpherePoint(lon2, lat2)
                if lon1 != lon2 or lat1 != lat2:
                    # Numerically unstable at small angles, but that's ok.
                    x2, y2, z2 = SpherePointTestSuite.toVector(lon2, lat2)
                    expected = math.acos(x1*x2 + y1*y2 + z1*z2)
                else:
                    expected = 0.0

                sep = point1.separation(point2)
                self.assertIsInstance(sep, geom.Angle)
                if point1.isFinite() and point2.isFinite():
                    self.assertGreaterEqual(sep.asDegrees(), 0.0)
                    self.assertLessEqual(sep.asDegrees(), 180.0)
                    self.assertAlmostEqual(expected, sep.asRadians())
                    self.assertAnglesAlmostEqual(
                        sep, point2.separation(point1))
                else:
                    self.assertTrue(math.isnan(sep.asRadians()))
                    self.assertTrue(math.isnan(
                        point2.separation(point1).asRadians()))
示例#2
0
    def testSeparationValueGeneric(self):
        """Test if separation() returns the correct value.
        """
        # This should cover arcs over the meridian, across the pole, etc.
        # Do not use sphgeom as an oracle, in case SpherePoint uses it
        # internally.
        for lon1, lat1 in self._dataset:
            point1 = SpherePoint(lon1, lat1)
            x1, y1, z1 = SpherePointTestSuite.toVector(lon1, lat1)
            for lon2, lat2 in self._dataset:
                point2 = SpherePoint(lon2, lat2)
                if lon1 != lon2 or lat1 != lat2:
                    # Numerically unstable at small angles, but that's ok.
                    x2, y2, z2 = SpherePointTestSuite.toVector(lon2, lat2)
                    expected = math.acos(x1*x2 + y1*y2 + z1*z2)
                else:
                    expected = 0.0

                sep = point1.separation(point2)
                self.assertIsInstance(sep, geom.Angle)
                if point1.isFinite() and point2.isFinite():
                    self.assertGreaterEqual(sep.asDegrees(), 0.0)
                    self.assertLessEqual(sep.asDegrees(), 180.0)
                    self.assertAlmostEqual(expected, sep.asRadians())
                    self.assertAnglesAlmostEqual(
                        sep, point2.separation(point1))
                else:
                    self.assertTrue(math.isnan(sep.asRadians()))
                    self.assertTrue(math.isnan(
                        point2.separation(point1).asRadians()))
示例#3
0
    def testFieldAngleToVector(self):
        sp00 = SpherePoint(0, 0, degrees)
        degList = (-90, -89.9, -20, 0, 10, 89.9, 90)
        for xdeg, ydeg, flipX in itertools.product(degList, degList, (False, True)):
            with self.subTest(xdeg=xdeg, ydeg=ydeg, flipX=flipX):
                xrad = xdeg * RAD_PER_DEG
                signx = -1 if flipX else 1
                testOrientation = xdeg != 0 or ydeg != 0
                yrad = ydeg * RAD_PER_DEG
                fieldAngle = (xrad, yrad)
                vector = coordUtils.fieldAngleToVector(fieldAngle, flipX)
                self.assertAlmostEqual(np.linalg.norm(vector), 1)
                if testOrientation:
                    # Orientation should match.
                    orientationFromFieldAngle = math.atan2(yrad, signx*xrad)*radians
                    # Field angle x = vector y, field angle y = vector z.
                    orientationFromVector = math.atan2(vector[2], vector[1])*radians
                    self.assertAnglesAlmostEqual(orientationFromVector, orientationFromFieldAngle)

                # Now test as spherical geometry.
                sp = SpherePoint(Vector3d(*vector))
                separation = sp00.separation(sp)
                predictedSeparation = math.hypot(xrad, yrad)*radians
                self.assertAnglesAlmostEqual(predictedSeparation, separation)
                if testOrientation:
                    bearing = sp00.bearingTo(sp)
                    self.assertAnglesAlmostEqual(orientationFromFieldAngle, bearing)

                # Test round trip through vectorToFieldAngle.
                fieldAngleFromVector = coordUtils.vectorToFieldAngle(vector, flipX)
                np.testing.assert_allclose(fieldAngleFromVector, fieldAngle, atol=1e-15)
示例#4
0
    def testSeparationPoles(self):
        """White-box test: all representations of a pole should have the same distance to another point.
        """
        southPole1 = SpherePoint(-30.0, -90.0, degrees)
        southPole2 = SpherePoint(183.0, -90.0, degrees)
        regularPoint = SpherePoint(42.0, 45.0, degrees)
        expectedSep = (45.0 + 90.0)*degrees

        self.assertAnglesAlmostEqual(
            expectedSep, southPole1.separation(regularPoint))
        self.assertAnglesAlmostEqual(
            expectedSep, regularPoint.separation(southPole1))
        self.assertAnglesAlmostEqual(
            expectedSep, southPole2.separation(regularPoint))
        self.assertAnglesAlmostEqual(
            expectedSep, regularPoint.separation(southPole2))
示例#5
0
    def testSeparationPoles(self):
        """White-box test: all representations of a pole should have the same distance to another point.
        """
        southPole1 = SpherePoint(-30.0, -90.0, degrees)
        southPole2 = SpherePoint(183.0, -90.0, degrees)
        regularPoint = SpherePoint(42.0, 45.0, degrees)
        expectedSep = (45.0 + 90.0)*degrees

        self.assertAnglesAlmostEqual(
            expectedSep, southPole1.separation(regularPoint))
        self.assertAnglesAlmostEqual(
            expectedSep, regularPoint.separation(southPole1))
        self.assertAnglesAlmostEqual(
            expectedSep, southPole2.separation(regularPoint))
        self.assertAnglesAlmostEqual(
            expectedSep, regularPoint.separation(southPole2))
示例#6
0
 def testComputeAzAltFromPupilBase(self):
     """Test computeAzAltFromBasePupil with general values
     """
     # transform the pupil vector back to the base vector
     # using the computed internal az/alt position
     for vectorPupil, vectorBase, pupilMagFactor, baseMagFactor in itertools.product(
         ((1, 0, 0), (2, 1, 0), (2, 0, 1), (2, 0.7, -0.8)),
         ((1, 0, 0), (0, 1, 0), (1, -0.7, 0.8)),
         (1, 1000),
         (1, 1000),
     ):
         with self.subTest(vectorPupil=vectorPupil, vectorBase=vectorBase, pupilMagFactor=pupilMagFactor,
                           baseMagFactor=baseMagFactor):
             vectorPupilScaled = np.array(vectorPupil, dtype=float) * pupilMagFactor
             pupilMag = np.linalg.norm(vectorPupilScaled)
             vectorBaseScaled = np.array(vectorBase, dtype=float) * baseMagFactor
             pupilAzAlt = coordUtils.computeAzAltFromBasePupil(vectorPupil=vectorPupilScaled,
                                                               vectorBase=vectorBaseScaled)
             # Check the round trip; note that the magnitude
             # of the returned vector will equal
             # the magnitude of the input vector.
             vectorBaseRoundTrip = coordUtils.convertVectorFromPupilToBase(
                 vectorPupil=vectorPupilScaled,
                 pupilAzAlt=pupilAzAlt)
             vectorBaseRoundTripMag = np.linalg.norm(vectorBaseRoundTrip)
             self.assertAlmostEqual(vectorBaseRoundTripMag, pupilMag, delta=1e-15*pupilMag)
             spBase = SpherePoint(Vector3d(*vectorBase))
             spBaseRoundTrip = SpherePoint(Vector3d(*vectorBaseRoundTrip))
             sep = spBase.separation(spBaseRoundTrip)
             self.assertLess(sep.asRadians(), 2e-15)
示例#7
0
    def testSeparationValueAbsolute(self):
        """Test if separation() returns specific values.
        """
        # Test from "Meeus, p. 110" (test originally written for coord::Coord;
        # don't know exact reference)
        spica = SpherePoint(201.2983, -11.1614, degrees)
        arcturus = SpherePoint(213.9154, 19.1825, degrees)

        # Verify to precision of quoted distance and positions.
        self.assertAlmostEqual(
            32.7930, spica.separation(arcturus).asDegrees(), 4)

        # Verify small angles: along a constant ra, add an arcsec to spica dec.
        epsilon = 1.0*geom.arcseconds
        spicaPlus = SpherePoint(spica.getLongitude(),
                                spica.getLatitude() + epsilon)

        self.assertAnglesAlmostEqual(epsilon, spicaPlus.separation(spica))
示例#8
0
    def testSeparationValueAbsolute(self):
        """Test if separation() returns specific values.
        """
        # Test from "Meeus, p. 110" (test originally written for coord::Coord;
        # don't know exact reference)
        spica = SpherePoint(201.2983, -11.1614, degrees)
        arcturus = SpherePoint(213.9154, 19.1825, degrees)

        # Verify to precision of quoted distance and positions.
        self.assertAlmostEqual(
            32.7930, spica.separation(arcturus).asDegrees(), 4)

        # Verify small angles: along a constant ra, add an arcsec to spica dec.
        epsilon = 1.0*geom.arcseconds
        spicaPlus = SpherePoint(spica.getLongitude(),
                                spica.getLatitude() + epsilon)

        self.assertAnglesAlmostEqual(epsilon, spicaPlus.separation(spica))
示例#9
0
    def testBearingToValueOnEquator(self):
        """Test if bearingTo() returns the expected value from a point on the equator
        """
        lon0 = 90.0
        lat0 = 0.0   # These tests only work from the equator.
        arcLen = 10.0

        trials = [
            # Along celestial equator
            dict(lon=lon0, lat=lat0, bearing=0.0,
                 lonEnd=lon0+arcLen, latEnd=lat0),
            # Along a meridian
            dict(lon=lon0, lat=lat0, bearing=90.0,
                 lonEnd=lon0, latEnd=lat0+arcLen),
            # 180 degree arc (should go to antipodal point)
            dict(lon=lon0, lat=lat0, bearing=45.0,
                 lonEnd=lon0+180.0, latEnd=-lat0),
            #
            dict(lon=lon0, lat=lat0, bearing=45.0,
                 lonEnd=lon0+90.0, latEnd=lat0 + 45.0),
            dict(lon=lon0, lat=lat0, bearing=225.0,
                 lonEnd=lon0-90.0, latEnd=lat0 - 45.0),
            dict(lon=lon0, lat=np.nextafter(-90.0, inf),
                 bearing=90.0, lonEnd=lon0, latEnd=0.0),
            dict(lon=lon0, lat=np.nextafter(-90.0, inf),
                 bearing=0.0, lonEnd=lon0 + 90.0, latEnd=0.0),
            # Argument at a pole should work
            dict(lon=lon0, lat=lat0, bearing=270.0, lonEnd=lon0, latEnd=-90.0),
            # Support for non-finite values
            dict(lon=lon0, lat=nan, bearing=nan, lonEnd=lon0, latEnd=45.0),
            dict(lon=lon0, lat=lat0, bearing=nan, lonEnd=nan, latEnd=90.0),
            dict(lon=inf, lat=lat0, bearing=nan, lonEnd=lon0, latEnd=42.0),
            dict(lon=lon0, lat=lat0, bearing=nan, lonEnd=-inf, latEnd=42.0),
        ]

        for trial in trials:
            origin = SpherePoint(trial['lon']*degrees, trial['lat']*degrees)
            end = SpherePoint(trial['lonEnd']*degrees, trial['latEnd']*degrees)
            bearing = origin.bearingTo(end)

            self.assertIsInstance(bearing, geom.Angle)
            if origin.isFinite() and end.isFinite():
                self.assertGreaterEqual(bearing.asDegrees(), 0.0)
                self.assertLess(bearing.asDegrees(), 360.0)
            if origin.separation(end).asDegrees() != 180.0:
                if not math.isnan(trial['bearing']):
                    self.assertAlmostEqual(
                        trial['bearing'], bearing.asDegrees(), 12)
                else:
                    self.assertTrue(math.isnan(bearing.asRadians()))
示例#10
0
    def testBearingToValueOnEquator(self):
        """Test if bearingTo() returns the expected value from a point on the equator
        """
        lon0 = 90.0
        lat0 = 0.0   # These tests only work from the equator.
        arcLen = 10.0

        trials = [
            # Along celestial equator
            dict(lon=lon0, lat=lat0, bearing=0.0,
                 lonEnd=lon0+arcLen, latEnd=lat0),
            # Along a meridian
            dict(lon=lon0, lat=lat0, bearing=90.0,
                 lonEnd=lon0, latEnd=lat0+arcLen),
            # 180 degree arc (should go to antipodal point)
            dict(lon=lon0, lat=lat0, bearing=45.0,
                 lonEnd=lon0+180.0, latEnd=-lat0),
            #
            dict(lon=lon0, lat=lat0, bearing=45.0,
                 lonEnd=lon0+90.0, latEnd=lat0 + 45.0),
            dict(lon=lon0, lat=lat0, bearing=225.0,
                 lonEnd=lon0-90.0, latEnd=lat0 - 45.0),
            dict(lon=lon0, lat=np.nextafter(-90.0, inf),
                 bearing=90.0, lonEnd=lon0, latEnd=0.0),
            dict(lon=lon0, lat=np.nextafter(-90.0, inf),
                 bearing=0.0, lonEnd=lon0 + 90.0, latEnd=0.0),
            # Argument at a pole should work
            dict(lon=lon0, lat=lat0, bearing=270.0, lonEnd=lon0, latEnd=-90.0),
            # Support for non-finite values
            dict(lon=lon0, lat=nan, bearing=nan, lonEnd=lon0, latEnd=45.0),
            dict(lon=lon0, lat=lat0, bearing=nan, lonEnd=nan, latEnd=90.0),
            dict(lon=inf, lat=lat0, bearing=nan, lonEnd=lon0, latEnd=42.0),
            dict(lon=lon0, lat=lat0, bearing=nan, lonEnd=-inf, latEnd=42.0),
        ]

        for trial in trials:
            origin = SpherePoint(trial['lon']*degrees, trial['lat']*degrees)
            end = SpherePoint(trial['lonEnd']*degrees, trial['latEnd']*degrees)
            bearing = origin.bearingTo(end)

            self.assertIsInstance(bearing, geom.Angle)
            if origin.isFinite() and end.isFinite():
                self.assertGreaterEqual(bearing.asDegrees(), 0.0)
                self.assertLess(bearing.asDegrees(), 360.0)
            if origin.separation(end).asDegrees() != 180.0:
                if not math.isnan(trial['bearing']):
                    self.assertAlmostEqual(
                        trial['bearing'], bearing.asDegrees(), 12)
                else:
                    self.assertTrue(math.isnan(bearing.asRadians()))
示例#11
0
    def testTicket1761(self):
        """Regression test for Ticket 1761.

        Checks for math errors caused by unnormalized vectors.
        """
        refPoint = SpherePoint(lsst.sphgeom.Vector3d(0, 1, 0))

        point1 = SpherePoint(lsst.sphgeom.Vector3d(0.1, 0.1, 0.1))
        point2 = SpherePoint(lsst.sphgeom.Vector3d(0.6, 0.6, 0.6))
        sep1 = refPoint.separation(point1)
        sep2 = refPoint.separation(point2)
        sepTrue = 54.735610317245339*degrees

        self.assertAnglesAlmostEqual(sepTrue, sep1)
        self.assertAnglesAlmostEqual(sepTrue, sep2)
示例#12
0
    def testTicket1761(self):
        """Regression test for Ticket 1761.

        Checks for math errors caused by unnormalized vectors.
        """
        refPoint = SpherePoint(lsst.sphgeom.Vector3d(0, 1, 0))

        point1 = SpherePoint(lsst.sphgeom.Vector3d(0.1, 0.1, 0.1))
        point2 = SpherePoint(lsst.sphgeom.Vector3d(0.6, 0.6, 0.6))
        sep1 = refPoint.separation(point1)
        sep2 = refPoint.separation(point2)
        sepTrue = 54.735610317245339*degrees

        self.assertAnglesAlmostEqual(sepTrue, sep1)
        self.assertAnglesAlmostEqual(sepTrue, sep2)
示例#13
0
 def testComputeAzAltFromPupilBaseWithBaseEqualsPupil(self):
     """Test computeAzAltFromBasePupil with baseVector=pupilVector,
     so the telescope will to internal az, alt=0
     """
     zeroSp = SpherePoint(0, 0, radians)
     for vector, pupilMagFactor, baseMagFactor in itertools.product(
         ((1, 0, 0), (0.1, -1, 0), (0.1, -0.5, 0.5), (0.5, 0, 0.5), (1, 0.7, -0.8)),
         (1, 1000),
         (1, 1000),
     ):
         with self.subTest(vector=vector, pupilMagFactor=pupilMagFactor, baseMagFactor=baseMagFactor):
             vectorPupil = np.array(vector, dtype=float) * pupilMagFactor
             vectorBase = np.array(vector, dtype=float) * baseMagFactor
             obs = coordUtils.computeAzAltFromBasePupil(vectorPupil=vectorPupil,
                                                        vectorBase=vectorBase)
             sep = zeroSp.separation(obs).asRadians()
             self.assertLess(sep, 1e-14)
示例#14
0
    def testOffsetValue(self):
        """Test if offset() returns the expected value.
        """
        # This should cover arcs over the meridian, across the pole, etc.
        for lon1, lat1 in self._dataset:
            point1 = SpherePoint(lon1, lat1)
            for lon2, lat2 in self._dataset:
                if lon1 == lon2 and lat1 == lat2:
                    continue
                point2 = SpherePoint(lon2, lat2)
                bearing = point1.bearingTo(point2)
                distance = point1.separation(point2)

                # offsetting point1 by bearing and distance should produce the same result as point2
                newPoint = point1.offset(bearing, distance)
                self.assertIsInstance(newPoint, SpherePoint)
                self.assertSpherePointsAlmostEqual(point2, newPoint)
                if newPoint.atPole():
                    self.assertAnglesAlmostEqual(newPoint.getLongitude(), 0*degrees)

                # measuring the separation and bearing from point1 to the new point
                # should produce the requested separation and bearing
                measuredDistance = point1.separation(newPoint)
                self.assertAnglesAlmostEqual(measuredDistance, distance)
                if abs(measuredDistance.asDegrees() - 180) > 1e-5:
                    # The two points are not opposite each other on the sphere,
                    # so the bearing has a well defined value
                    measuredBearing = point1.bearingTo(newPoint)
                    self.assertAnglesAlmostEqual(measuredBearing, bearing)

                # offset by a negative amount in the opposite direction should produce the same result
                newPoint2 = point1.offset(bearing + 180 * degrees, -distance)
                self.assertIsInstance(newPoint2, SpherePoint)
                # check angular separation (longitude is checked below)
                self.assertSpherePointsAlmostEqual(newPoint, newPoint2)

                if point1.isFinite() and point2.isFinite():
                    if not point2.atPole():
                        self.assertAnglesAlmostEqual(
                            point2.getLongitude(), newPoint.getLongitude())
                        self.assertAnglesAlmostEqual(
                            point2.getLongitude(), newPoint2.getLongitude())
                    self.assertAnglesAlmostEqual(
                        point2.getLatitude(), newPoint.getLatitude())
                    self.assertAnglesAlmostEqual(
                        point2.getLatitude(), newPoint2.getLatitude())
                else:
                    self.assertTrue(math.isnan(
                        newPoint.getLongitude().asRadians()))
                    self.assertTrue(math.isnan(
                        newPoint2.getLongitude().asRadians()))
                    self.assertTrue(math.isnan(
                        newPoint.getLatitude().asRadians()))
                    self.assertTrue(math.isnan(
                        newPoint2.getLatitude().asRadians()))

        # Test precision near the poles
        lon = 123.0*degrees
        almostPole = SpherePoint(lon, self.nextDown(90.0*degrees))
        goSouth = almostPole.offset(-90.0*degrees, 90.0*degrees)
        self.assertAnglesAlmostEqual(lon, goSouth.getLongitude())
        self.assertAnglesAlmostEqual(0.0*degrees, goSouth.getLatitude())
        goEast = almostPole.offset(0.0*degrees, 90.0*degrees)
        self.assertAnglesAlmostEqual(lon + 90.0*degrees, goEast.getLongitude())
        self.assertAnglesAlmostEqual(0.0*degrees, goEast.getLatitude())
示例#15
0
    def testRotatedValue(self):
        """Test if rotated() returns the expected value.
        """
        # Try rotating about the equatorial pole (ie. along a parallel).
        longitude = 90.0
        latitudes = [0.0, 30.0, 60.0]
        arcLen = 10.0
        pole = SpherePoint(0.0*degrees, 90.0*degrees)
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            newPoint = point.rotated(pole, arcLen*degrees)

            self.assertIsInstance(newPoint, SpherePoint)
            self.assertAlmostEqual(
                longitude + arcLen, newPoint.getLongitude().asDegrees())
            self.assertAlmostEqual(
                latitude, newPoint.getLatitude().asDegrees())

        # Try with pole = vernal equinox and rotate up the 90 degree meridian.
        pole = SpherePoint(0.0*degrees, 0.0*degrees)
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            newPoint = point.rotated(pole, arcLen*degrees)

            self.assertAlmostEqual(
                longitude, newPoint.getLongitude().asDegrees())
            self.assertAlmostEqual(
                latitude + arcLen, newPoint.getLatitude().asDegrees())

        # Test accuracy close to coordinate pole
        point = SpherePoint(90.0*degrees, np.nextafter(90.0, -inf)*degrees)
        newPoint = point.rotated(pole, 90.0*degrees)
        self.assertAlmostEqual(270.0, newPoint.getLongitude().asDegrees())
        self.assertAlmostEqual(90.0 - np.nextafter(90.0, -inf),
                               newPoint.getLatitude().asDegrees())

        # Generic pole; can't predict position, but test for rotation
        # invariant.
        pole = SpherePoint(283.5*degrees, -23.6*degrees)
        for lon, lat in self._dataset:
            point = SpherePoint(lon, lat)
            dist = point.separation(pole)
            newPoint = point.rotated(pole, -32.4*geom.radians)

            self.assertNotAlmostEqual(point.getLongitude().asDegrees(),
                                      newPoint.getLongitude().asDegrees())
            self.assertNotAlmostEqual(point.getLatitude().asDegrees(),
                                      newPoint.getLatitude().asDegrees())
            self.assertAnglesAlmostEqual(dist, newPoint.separation(pole))

        # Non-finite values give undefined rotations
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            nanPoint = point.rotated(pole, nan*degrees)
            infPoint = point.rotated(pole, inf*degrees)

            self.assertTrue(math.isnan(nanPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(nanPoint.getLatitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLatitude().asRadians()))

        # Non-finite points rotate into non-finite points
        for point in [
            SpherePoint(-inf*degrees, 1.0*radians),
            SpherePoint(32.0*degrees, nan*radians),
        ]:
            newPoint = point.rotated(pole, arcLen*degrees)
            self.assertTrue(math.isnan(nanPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(nanPoint.getLatitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLatitude().asRadians()))

        # Rotation around non-finite poles undefined
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            for pole in [
                SpherePoint(-inf*degrees, 1.0*radians),
                SpherePoint(32.0*degrees, nan*radians),
            ]:
                newPoint = point.rotated(pole, arcLen*degrees)
                self.assertTrue(math.isnan(
                    nanPoint.getLongitude().asRadians()))
                self.assertTrue(math.isnan(nanPoint.getLatitude().asRadians()))
                self.assertTrue(math.isnan(
                    infPoint.getLongitude().asRadians()))
                self.assertTrue(math.isnan(infPoint.getLatitude().asRadians()))
示例#16
0
    def testRotatedValue(self):
        """Test if rotated() returns the expected value.
        """
        # Try rotating about the equatorial pole (ie. along a parallel).
        longitude = 90.0
        latitudes = [0.0, 30.0, 60.0]
        arcLen = 10.0
        pole = SpherePoint(0.0*degrees, 90.0*degrees)
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            newPoint = point.rotated(pole, arcLen*degrees)

            self.assertIsInstance(newPoint, SpherePoint)
            self.assertAlmostEqual(
                longitude + arcLen, newPoint.getLongitude().asDegrees())
            self.assertAlmostEqual(
                latitude, newPoint.getLatitude().asDegrees())

        # Try with pole = vernal equinox and rotate up the 90 degree meridian.
        pole = SpherePoint(0.0*degrees, 0.0*degrees)
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            newPoint = point.rotated(pole, arcLen*degrees)

            self.assertAlmostEqual(
                longitude, newPoint.getLongitude().asDegrees())
            self.assertAlmostEqual(
                latitude + arcLen, newPoint.getLatitude().asDegrees())

        # Test accuracy close to coordinate pole
        point = SpherePoint(90.0*degrees, np.nextafter(90.0, -inf)*degrees)
        newPoint = point.rotated(pole, 90.0*degrees)
        self.assertAlmostEqual(270.0, newPoint.getLongitude().asDegrees())
        self.assertAlmostEqual(90.0 - np.nextafter(90.0, -inf),
                               newPoint.getLatitude().asDegrees())

        # Generic pole; can't predict position, but test for rotation
        # invariant.
        pole = SpherePoint(283.5*degrees, -23.6*degrees)
        for lon, lat in self._dataset:
            point = SpherePoint(lon, lat)
            dist = point.separation(pole)
            newPoint = point.rotated(pole, -32.4*geom.radians)

            self.assertNotAlmostEqual(point.getLongitude().asDegrees(),
                                      newPoint.getLongitude().asDegrees())
            self.assertNotAlmostEqual(point.getLatitude().asDegrees(),
                                      newPoint.getLatitude().asDegrees())
            self.assertAnglesAlmostEqual(dist, newPoint.separation(pole))

        # Non-finite values give undefined rotations
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            nanPoint = point.rotated(pole, nan*degrees)
            infPoint = point.rotated(pole, inf*degrees)

            self.assertTrue(math.isnan(nanPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(nanPoint.getLatitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLatitude().asRadians()))

        # Non-finite points rotate into non-finite points
        for point in [
            SpherePoint(-inf*degrees, 1.0*radians),
            SpherePoint(32.0*degrees, nan*radians),
        ]:
            newPoint = point.rotated(pole, arcLen*degrees)
            self.assertTrue(math.isnan(nanPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(nanPoint.getLatitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLongitude().asRadians()))
            self.assertTrue(math.isnan(infPoint.getLatitude().asRadians()))

        # Rotation around non-finite poles undefined
        for latitude in latitudes:
            point = SpherePoint(longitude*degrees, latitude*degrees)
            for pole in [
                SpherePoint(-inf*degrees, 1.0*radians),
                SpherePoint(32.0*degrees, nan*radians),
            ]:
                newPoint = point.rotated(pole, arcLen*degrees)
                self.assertTrue(math.isnan(
                    nanPoint.getLongitude().asRadians()))
                self.assertTrue(math.isnan(nanPoint.getLatitude().asRadians()))
                self.assertTrue(math.isnan(
                    infPoint.getLongitude().asRadians()))
                self.assertTrue(math.isnan(infPoint.getLatitude().asRadians()))
示例#17
0
    def testOffsetValue(self):
        """Test if offset() returns the expected value.
        """
        # This should cover arcs over the meridian, across the pole, etc.
        for lon1, lat1 in self._dataset:
            point1 = SpherePoint(lon1, lat1)
            for lon2, lat2 in self._dataset:
                if lon1 == lon2 and lat1 == lat2:
                    continue
                point2 = SpherePoint(lon2, lat2)
                bearing = point1.bearingTo(point2)
                distance = point1.separation(point2)

                # offsetting point1 by bearing and distance should produce the same result as point2
                newPoint = point1.offset(bearing, distance)
                self.assertIsInstance(newPoint, SpherePoint)
                self.assertSpherePointsAlmostEqual(point2, newPoint)
                if newPoint.atPole():
                    self.assertAnglesAlmostEqual(newPoint.getLongitude(), 0*degrees)

                # measuring the separation and bearing from point1 to the new point
                # should produce the requested separation and bearing
                measuredDistance = point1.separation(newPoint)
                self.assertAnglesAlmostEqual(measuredDistance, distance)
                if abs(measuredDistance.asDegrees() - 180) > 1e-5:
                    # The two points are not opposite each other on the sphere,
                    # so the bearing has a well defined value
                    measuredBearing = point1.bearingTo(newPoint)
                    self.assertAnglesAlmostEqual(measuredBearing, bearing)

                # offset by a negative amount in the opposite direction should produce the same result
                newPoint2 = point1.offset(bearing + 180 * degrees, -distance)
                self.assertIsInstance(newPoint2, SpherePoint)
                # check angular separation (longitude is checked below)
                self.assertSpherePointsAlmostEqual(newPoint, newPoint2)

                if point1.isFinite() and point2.isFinite():
                    if not point2.atPole():
                        self.assertAnglesAlmostEqual(
                            point2.getLongitude(), newPoint.getLongitude())
                        self.assertAnglesAlmostEqual(
                            point2.getLongitude(), newPoint2.getLongitude())
                    self.assertAnglesAlmostEqual(
                        point2.getLatitude(), newPoint.getLatitude())
                    self.assertAnglesAlmostEqual(
                        point2.getLatitude(), newPoint2.getLatitude())
                else:
                    self.assertTrue(math.isnan(
                        newPoint.getLongitude().asRadians()))
                    self.assertTrue(math.isnan(
                        newPoint2.getLongitude().asRadians()))
                    self.assertTrue(math.isnan(
                        newPoint.getLatitude().asRadians()))
                    self.assertTrue(math.isnan(
                        newPoint2.getLatitude().asRadians()))

        # Test precision near the poles
        lon = 123.0*degrees
        almostPole = SpherePoint(lon, self.nextDown(90.0*degrees))
        goSouth = almostPole.offset(-90.0*degrees, 90.0*degrees)
        self.assertAnglesAlmostEqual(lon, goSouth.getLongitude())
        self.assertAnglesAlmostEqual(0.0*degrees, goSouth.getLatitude())
        goEast = almostPole.offset(0.0*degrees, 90.0*degrees)
        self.assertAnglesAlmostEqual(lon + 90.0*degrees, goEast.getLongitude())
        self.assertAnglesAlmostEqual(0.0*degrees, goEast.getLatitude())