def testGetLongitudeValue(self): """Test if getLongitude() and getRa() return the expected value. """ for lon, lat in self._dataset: for point in ( SpherePoint(lon, lat), SpherePoint(lon.asDegrees(), lat.asDegrees(), degrees), SpherePoint(lon.asRadians(), lat.asRadians(), radians), ): self.assertIsInstance(point.getLongitude(), afwGeom.Angle) # Behavior for non-finite points is undefined; depends on internal # data representation if point.isFinite(): self.assertGreaterEqual(point.getLongitude().asDegrees(), 0.0) self.assertLess(point.getLongitude().asDegrees(), 360.0) # Longitude not guaranteed to match input at pole if not point.atPole(): # assertAnglesAlmostEqual handles angle wrapping internally self.assertAnglesAlmostEqual(lon, point.getLongitude()) self.assertAnglesAlmostEqual(lon, point.getRa()) # Vector construction should return valid longitude even in edge cases. point = SpherePoint(lsst.sphgeom.Vector3d(0.0, 0.0, -1.0)) self.assertGreaterEqual(point.getLongitude().asDegrees(), 0.0) self.assertLess(point.getLongitude().asDegrees(), 360.0)
def testVector3dConstructor(self): # test poles for z in (-11.3, -1.1, 0.1, 2.5): # arbitrary non-zero values sp = SpherePoint(lsst.sphgeom.Vector3d(0.0, 0.0, z)) self.assertTrue(sp.atPole()) self.assertEqual(sp.getLongitude().asRadians(), 0.0) if z < 0: self.assertAnglesAlmostEqual(sp.getLatitude(), -90 * degrees) else: self.assertAnglesAlmostEqual(sp.getLatitude(), 90 * degrees) spx = SpherePoint(lsst.sphgeom.Vector3d(11.1, 0.0, 0.0)) self.assertAnglesAlmostEqual(spx.getLongitude(), 0.0 * degrees) self.assertAnglesAlmostEqual(spx.getLatitude(), 0.0 * degrees) spy = SpherePoint(lsst.sphgeom.Vector3d(0.0, 234234.5, 0.0)) self.assertAnglesAlmostEqual(spy.getLongitude(), 90.0 * degrees) self.assertAnglesAlmostEqual(spy.getLatitude(), 0.0 * degrees) spxy = SpherePoint(lsst.sphgeom.Vector3d(7.5, -7.5, 0.0)) self.assertAnglesAlmostEqual(spxy.getLongitude(), -45.0 * degrees) self.assertAnglesAlmostEqual(spxy.getLatitude(), 0.0 * degrees) spxz = SpherePoint(lsst.sphgeom.Vector3d(100.0, 0.0, -100.0)) self.assertAnglesAlmostEqual(spxz.getLongitude(), 0.0 * degrees) self.assertAnglesAlmostEqual(spxz.getLatitude(), -45.0 * degrees) # Only one singularity: a vector of all zeros with self.assertRaises(pexEx.InvalidParameterError): SpherePoint(lsst.sphgeom.Vector3d(0.0, 0.0, 0.0))
def testStrValue(self): """Test if __str__ produces output consistent with its spec. This is necessarily a loose test, as the behavior of __str__ is (deliberately) incompletely specified. """ for lon, lat in self._dataset: point = SpherePoint(lon, lat) numbers = re.findall(r'(?:\+|-)?(?:[\d.]+|nan|inf)', str(point)) self.assertEqual(2, len(numbers), "String '%s' should have exactly two coordinates." % (point,)) # Low precision to allow for only a few digits in string. if not math.isnan(point.getLongitude().asRadians()): self.assertAlmostEqual( point.getLongitude().asDegrees(), float(numbers[0]), delta=1e-6) else: self.assertRegexpMatches(numbers[0], r'-?nan') if not math.isnan(point.getLatitude().asRadians()): self.assertAlmostEqual( point.getLatitude().asDegrees(), float(numbers[1]), delta=1e-6) # Latitude must be signed self.assertTrue(numbers[1].startswith("+") or numbers[1].startswith("-")) else: # Some C++ compilers will output NaN with a sign, others won't self.assertRegexpMatches(numbers[1], r'(?:\+|-)?nan')
def testIterResult(self): """Test if iteration returns the expected values. """ for lon, lat in self._dataset: point = SpherePoint(lon, lat) if point.isFinite(): # Test mechanics directly it = iter(point) self.assertEqual(point.getLongitude(), next(it)) self.assertEqual(point.getLatitude(), next(it)) with self.assertRaises(StopIteration): next(it) # Intended use case lon, lat = point self.assertEqual(point.getLongitude(), lon) self.assertEqual(point.getLatitude(), lat)
def testGetItemValue(self): """Test if indexing returns the expected value. """ for lon, lat in self._dataset: point = SpherePoint(lon, lat) self.assertIsInstance(point[-2], afwGeom.Angle) self.assertIsInstance(point[-1], afwGeom.Angle) self.assertIsInstance(point[0], afwGeom.Angle) self.assertIsInstance(point[1], afwGeom.Angle) if not math.isnan(point.getLongitude().asRadians()): self.assertEqual(point.getLongitude(), point[-2]) self.assertEqual(point.getLongitude(), point[0]) else: self.assertTrue(math.isnan(point[-2].asRadians())) self.assertTrue(math.isnan(point[0].asRadians())) if not math.isnan(point.getLatitude().asRadians()): self.assertEqual(point.getLatitude(), point[-1]) self.assertEqual(point.getLatitude(), point[1]) else: self.assertTrue(math.isnan(point[-1].asRadians())) self.assertTrue(math.isnan(point[1].asRadians()))
def testReprValue(self): """Test if __repr__ is a machine-readable representation. """ for lon, lat in self._dataset: point = SpherePoint(lon, lat) pointRepr = repr(point) self.assertIn("degrees", pointRepr) self.assertEqual(2, len(pointRepr.split(","))) spcopy = eval(pointRepr) self.assertAnglesAlmostEqual( point.getLongitude(), spcopy.getLongitude()) self.assertAnglesAlmostEqual( point.getLatitude(), spcopy.getLatitude())
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 * afwGeom.arcseconds spicaPlus = SpherePoint(spica.getLongitude(), spica.getLatitude() + epsilon) self.assertAnglesAlmostEqual(epsilon, spicaPlus.separation(spica))
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) if point1.atPole(): continue 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) newPoint = point1.offset(bearing, distance) self.assertIsInstance(newPoint, SpherePoint) if point1.isFinite() and point2.isFinite(): if not point2.atPole(): self.assertAnglesAlmostEqual( point2.getLongitude(), newPoint.getLongitude()) self.assertAnglesAlmostEqual( point2.getLatitude(), newPoint.getLatitude()) else: self.assertTrue(math.isnan( newPoint.getLongitude().asRadians())) self.assertTrue(math.isnan( newPoint.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())
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())
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 * afwGeom.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()))
def testDefaultConstructor(self): sp = SpherePoint() self.assertTrue(math.isnan(sp.getLongitude())) self.assertTrue(math.isnan(sp.getLatitude())) self.assertFalse(sp.isFinite())