Removed the subdir.
This commit is contained in:
120
pyrate/tests/plan/geometry/helpers/test_other.py
Normal file
120
pyrate/tests/plan/geometry/helpers/test_other.py
Normal file
@ -0,0 +1,120 @@
|
||||
"""This module asserts correct runtime behaviour of various additional helpers."""
|
||||
|
||||
# Python Standard Library
|
||||
from math import tau
|
||||
|
||||
# Generic testing
|
||||
from unittest import TestCase
|
||||
|
||||
# Hypothesis testing
|
||||
import hypothesis.extra.numpy as st_numpy
|
||||
from hypothesis import given
|
||||
import hypothesis.strategies as st
|
||||
|
||||
# Scientific
|
||||
import numpy as np
|
||||
from numpy.testing import assert_almost_equal
|
||||
|
||||
# Module under test
|
||||
from pyrate.plan.geometry.helpers import cartesian_to_spherical
|
||||
from pyrate.plan.geometry.helpers import difference_latitude
|
||||
from pyrate.plan.geometry.helpers import difference_longitude
|
||||
from pyrate.plan.geometry.helpers import mean_angle
|
||||
from pyrate.plan.geometry.helpers import mean_coordinate
|
||||
from pyrate.plan.geometry.helpers import meters2rad
|
||||
from pyrate.plan.geometry.helpers import rad2meters
|
||||
|
||||
# Own strategies
|
||||
from pyrate.common.testing.strategies.geometry import geo_bearings
|
||||
|
||||
|
||||
_POSITIVE_FLOATS = st.floats(min_value=0.0, max_value=1e9, allow_infinity=False, allow_nan=False)
|
||||
|
||||
|
||||
class TestRadiansAndMeterConversion(TestCase):
|
||||
"""Makes sure the conversion between meters and radians works."""
|
||||
|
||||
@given(_POSITIVE_FLOATS)
|
||||
def test_is_reversible_float(self, meters: float) -> None:
|
||||
"""Tests that the two functions are the reverse of each other."""
|
||||
self.assertAlmostEqual(meters, rad2meters(meters2rad(meters)), places=5)
|
||||
|
||||
@given(st_numpy.arrays(dtype=float, shape=st_numpy.array_shapes(), elements=_POSITIVE_FLOATS))
|
||||
def test_is_reversible_numpy(self, meters: np.ndarray) -> None: # pylint: disable=no-self-use
|
||||
"""Tests that the two functions are the reverse of each other."""
|
||||
assert_almost_equal(meters, rad2meters(meters2rad(meters)), decimal=5)
|
||||
|
||||
|
||||
class TestCartesianToSpherical(TestCase):
|
||||
"""Makes sure the conversion from cartesian to spherical coordinates works."""
|
||||
|
||||
def test_raises_if_not_on_unit_sphere(self) -> None:
|
||||
"""Asserts that an exception is raised if values are not on the unit sphere."""
|
||||
with self.assertRaises(AssertionError):
|
||||
cartesian_to_spherical(np.array([(10, 20, 30)]))
|
||||
|
||||
def test_specific_values(self) -> None: # pylint: disable=no-self-use
|
||||
"""Asserts that an exception is raised if values are not on the unit sphere."""
|
||||
data_in = np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1), (0.5, 0.5, np.sqrt(1 - 0.5**2 - 0.5**2))])
|
||||
expected_data_out = np.array([(0, 0), (0, np.pi / 2), (-np.pi / 2, 0), (-np.pi / 4, np.pi / 4)]).T
|
||||
|
||||
assert_almost_equal(cartesian_to_spherical(data_in), expected_data_out)
|
||||
|
||||
|
||||
class TestAngleAndCoordinateMean(TestCase):
|
||||
"""Makes sure the mean computation and angles and coordinates works correctly."""
|
||||
|
||||
@given(geo_bearings(), st.floats(min_value=0.0, max_value=1e-9))
|
||||
def test_raises_if_ambiguous(self, angle: float, noise: float) -> None:
|
||||
"""Asserts that an exception is raised if no sensible mean can be calculated."""
|
||||
|
||||
ambiguous_pair = np.array([angle, (angle + 180 + noise) % 360])
|
||||
with self.assertRaises(ValueError):
|
||||
mean_angle(np.radians(ambiguous_pair))
|
||||
with self.assertRaises(ValueError):
|
||||
mean_coordinate(np.array([0.0, 67.2]), ambiguous_pair)
|
||||
|
||||
# But the methods should recover from an exception on the latitude mean computation
|
||||
latitude, _ = mean_coordinate(ambiguous_pair, np.array([0.0, 67.2]))
|
||||
self.assertAlmostEqual(latitude, 0.0)
|
||||
|
||||
@given(
|
||||
st_numpy.arrays(
|
||||
elements=st.floats(min_value=0.0, max_value=np.pi), dtype=float, shape=st_numpy.array_shapes()
|
||||
)
|
||||
)
|
||||
def test_mean_angle_is_in_valid_range(self, data: np.ndarray) -> None:
|
||||
"""Asserts that means are never negative and always between ``0°`` and ``360°``."""
|
||||
|
||||
try:
|
||||
mean = mean_angle(data)
|
||||
self.assertGreaterEqual(mean, 0.0)
|
||||
self.assertLessEqual(mean, np.pi)
|
||||
|
||||
except ValueError:
|
||||
pass # this might happen with the generated values and is okay
|
||||
|
||||
@given(geo_bearings(), st.floats(min_value=0.0, max_value=170))
|
||||
def test_obvious_values_angle(self, angle: float, difference: float) -> None:
|
||||
"""Asserts that the result is sensible for known values."""
|
||||
|
||||
mean = mean_angle(np.radians(np.array([angle, (angle + difference) % 360])))
|
||||
self.assertAlmostEqual(mean, np.radians((angle + difference / 2)) % tau, delta=1e-6)
|
||||
|
||||
@given(
|
||||
st.floats(min_value=-80.0, max_value=+80.0),
|
||||
st.floats(min_value=-170.0, max_value=+170.0),
|
||||
st.floats(min_value=-9.0, max_value=9.0),
|
||||
st.floats(min_value=-9.0, max_value=9.0),
|
||||
)
|
||||
def test_obvious_values_coordinate(
|
||||
self, latitude: float, longitude: float, lat_delta: float, lon_delta: float
|
||||
) -> None:
|
||||
"""Asserts that the result is sensible for known values."""
|
||||
|
||||
lat_mean, lon_mean = mean_coordinate(
|
||||
latitudes=np.array([latitude, latitude + lat_delta]),
|
||||
longitudes=np.array([longitude, longitude + lon_delta]),
|
||||
)
|
||||
self.assertLessEqual(difference_latitude(lat_mean, (latitude + lat_delta / 2)), 1e-6)
|
||||
self.assertLessEqual(difference_longitude(lon_mean, (longitude + lon_delta / 2)), 1e-6)
|
Reference in New Issue
Block a user