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, afwGeom.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()))
def testBearingToValue(self): """Test if bearingTo() returns the expected value. """ 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, afwGeom.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()))
def testEquality(self): """Test if tests for equality treat SpherePoints as values. """ # (In)equality is determined by value, not identity. # See DM-2347, DM-2465. These asserts are testing the # functionality of `==` and `!=` and should not be changed. for lon1, lat1 in self._dataset: point1 = SpherePoint(lon1, lat1) self.assertIsInstance(point1 == point1, bool) self.assertIsInstance(point1 != point1, bool) if point1.isFinite(): self.assertTrue(point1 == point1) self.assertFalse(point1 != point1) pointCopy = copy.deepcopy(point1) self.assertIsNot(pointCopy, point1) self.assertEqual(pointCopy, point1) self.assertEqual(point1, pointCopy) self.assertFalse(pointCopy != point1) self.assertFalse(point1 != pointCopy) else: self.assertFalse(point1 == point1) self.assertTrue(point1 != point1) for lon2, lat2 in self._dataset: point2 = SpherePoint(lon2, lat2) if lon1 == lon2 and lat1 == lat2 and point1.isFinite( ) and point2.isFinite(): # note: the isFinite checks are needed because if longitude is infinite # then the resulting SpherePoint has nan as its longitude, due to wrapping self.assertFalse(point2 != point1) self.assertFalse(point1 != point2) self.assertTrue(point2 == point1) self.assertTrue(point1 == point2) else: self.assertTrue(point2 != point1) self.assertTrue(point1 != point2) self.assertFalse(point2 == point1) self.assertFalse(point1 == point2) # Test for transitivity (may be assumed by algorithms). for delta in [10.0**(0.1 * x) for x in range(-150, -49, 5)]: self.checkTransitive(delta * radians)
def testGetLatitudeValue(self): """Test if getLatitude() returns the expected value. """ for lon, lat in self._dataset: point = SpherePoint(lon, lat) self.assertIsInstance(point.getLatitude(), afwGeom.Angle) # Behavior for non-finite points is undefined; depends on internal # data representation if point.isFinite(): self.assertGreaterEqual(point.getLatitude().asDegrees(), -90.0) self.assertLessEqual(point.getLatitude().asDegrees(), 90.0) self.assertAnglesAlmostEqual(lat, point.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) 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 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 testGetLongitudeValue(self): """Test if getLongitude() returns the expected value. """ for lon, lat in self._dataset: point = SpherePoint(lon, lat) 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()) # Vector construction should return valid longitude even in edge cases. point = SpherePoint(afwGeom.Point3D(0.0, 0.0, -1.0)) self.assertGreaterEqual(point.getLongitude().asDegrees(), 0.0) self.assertLess(point.getLongitude().asDegrees(), 360.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())
def testDefaultConstructor(self): sp = SpherePoint() self.assertTrue(math.isnan(sp.getLongitude())) self.assertTrue(math.isnan(sp.getLatitude())) self.assertFalse(sp.isFinite())