Added pyrate as a direct dependency.
This commit is contained in:
0
pyrate/tests/plan/geometry/helpers/__init__.py
Normal file
0
pyrate/tests/plan/geometry/helpers/__init__.py
Normal file
171
pyrate/tests/plan/geometry/helpers/test_difference.py
Normal file
171
pyrate/tests/plan/geometry/helpers/test_difference.py
Normal file
@ -0,0 +1,171 @@
|
||||
"""This module asserts correct runtime behaviour of the :mod:`pyrate.plan.geometry.helpers` functions
|
||||
for calculating differences.
|
||||
"""
|
||||
|
||||
# Python standard
|
||||
from abc import ABC
|
||||
from abc import abstractmethod
|
||||
from math import isfinite
|
||||
from math import isnan
|
||||
import warnings
|
||||
|
||||
# Typing
|
||||
from typing import Callable
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
|
||||
# Generic testing
|
||||
from unittest import TestCase
|
||||
|
||||
# Numeric testing
|
||||
from numpy import allclose
|
||||
from numpy import array
|
||||
|
||||
# Hypothesis testing
|
||||
from hypothesis import given
|
||||
import hypothesis.strategies as st
|
||||
|
||||
# Test helpers
|
||||
from pyrate.plan.geometry.helpers import difference_direction
|
||||
from pyrate.plan.geometry.helpers import difference_latitude
|
||||
from pyrate.plan.geometry.helpers import difference_longitude
|
||||
from pyrate.plan.geometry.helpers import ScalarOrArray
|
||||
|
||||
|
||||
class TestDifference(TestCase, ABC):
|
||||
"""Makes sure the distance measure is well-behaved.
|
||||
|
||||
Keep in mind that it is formally not a metric since the triangle inequality does not hold.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def _get_difference_function(self) -> Callable[[ScalarOrArray, ScalarOrArray], ScalarOrArray]:
|
||||
"""Get the function to be tested."""
|
||||
|
||||
@abstractmethod
|
||||
def _get_max(self) -> float:
|
||||
"""Get the desired maximum value (inclusive)."""
|
||||
|
||||
@abstractmethod
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float, float]]:
|
||||
"""Get some concrete values to be tested as a sequence of ``(value a, value b, distance between)``."""
|
||||
|
||||
@given(st.floats(), st.floats())
|
||||
def test_distance_measuring_commutes_and_is_in_bounds(self, first: float, second: float) -> None:
|
||||
"""Assures flipping the sides when calculating distances does not make a significant difference."""
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
distance_1 = self._get_difference_function()(first, second)
|
||||
distance_2 = self._get_difference_function()(second, first)
|
||||
|
||||
if isfinite(distance_1) and isfinite(distance_1):
|
||||
# make sure it commutes
|
||||
self.assertAlmostEqual(distance_1, distance_2)
|
||||
|
||||
# make sure the distance is always positive
|
||||
self.assertGreaterEqual(distance_1, 0.0)
|
||||
self.assertGreaterEqual(distance_2, 0.0)
|
||||
|
||||
# make sure the distance is within bounds
|
||||
self.assertLessEqual(distance_1, self._get_max())
|
||||
self.assertLessEqual(distance_2, self._get_max())
|
||||
|
||||
else:
|
||||
self.assertTrue(isnan(distance_1))
|
||||
self.assertTrue(isnan(distance_2))
|
||||
|
||||
@given(st.floats())
|
||||
def test_distance_measuring_to_itself_is_zero(self, thing: float) -> None:
|
||||
"""Assures flipping the sides when calculating distances does not make a significant difference."""
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
distance = self._get_difference_function()(thing, thing)
|
||||
|
||||
# make sure the distance is always positive and very close to zero
|
||||
if isfinite(distance):
|
||||
self.assertGreaterEqual(distance, 0.0)
|
||||
self.assertAlmostEqual(distance, 0.0)
|
||||
else:
|
||||
self.assertTrue(isnan(distance))
|
||||
|
||||
def test_concrete_examples(self) -> None:
|
||||
"""Checks the result for the concrete examples given in :meth:`~_get_concrete_examples`."""
|
||||
function = self._get_difference_function()
|
||||
|
||||
for index, (value_a, value_b, expected_result) in enumerate(self._get_concrete_examples()):
|
||||
with self.subTest(f"example triple #{index}"):
|
||||
self.assertAlmostEqual(function(value_a, value_b), expected_result, delta=1e-12)
|
||||
|
||||
def test_concrete_examples_as_array(self) -> None:
|
||||
"""Checks the result for the concrete examples given in :meth:`~_get_concrete_examples`."""
|
||||
function = self._get_difference_function()
|
||||
data = array(self._get_concrete_examples()).T
|
||||
self.assertTrue(allclose(function(data[0, :], data[1, :]), data[2, :]))
|
||||
|
||||
|
||||
class TestDifferenceLatitude(TestDifference):
|
||||
"""Tests :func:`pyrate.plan.geometry.helpers.difference_latitude`."""
|
||||
|
||||
def _get_difference_function(self) -> Callable[[ScalarOrArray, ScalarOrArray], ScalarOrArray]:
|
||||
return difference_latitude
|
||||
|
||||
def _get_max(self) -> float:
|
||||
return 180.0
|
||||
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float, float]]:
|
||||
return [
|
||||
(0, 0, 0),
|
||||
(-90, 90, 180),
|
||||
(-89.5, 0, 89.5),
|
||||
(-89.5, 0.5, 90),
|
||||
(-89.5, -0.5, 89),
|
||||
(-45, 45, 90),
|
||||
]
|
||||
|
||||
|
||||
class TestDifferenceLongitude(TestDifference):
|
||||
"""Tests :func:`pyrate.plan.geometry.helpers.difference_longitude`."""
|
||||
|
||||
def _get_difference_function(self) -> Callable[[ScalarOrArray, ScalarOrArray], ScalarOrArray]:
|
||||
return difference_longitude
|
||||
|
||||
def _get_max(self) -> float:
|
||||
return 180.0
|
||||
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float, float]]:
|
||||
return [
|
||||
(0, 0, 0),
|
||||
(-90, 90, 180),
|
||||
(-89.5, 0, 89.5),
|
||||
(-89.5, 0.5, 90),
|
||||
(-89.5, -0.5, 89),
|
||||
(180, -180, 0),
|
||||
(100, -100, 160),
|
||||
(-45, 45, 90),
|
||||
]
|
||||
|
||||
|
||||
class TestDifferenceDirection(TestDifference):
|
||||
"""Tests :func:`pyrate.plan.geometry.helpers.difference_direction`."""
|
||||
|
||||
def _get_difference_function(self) -> Callable[[ScalarOrArray, ScalarOrArray], ScalarOrArray]:
|
||||
return difference_direction
|
||||
|
||||
def _get_max(self) -> float:
|
||||
return 180.0
|
||||
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float, float]]:
|
||||
return [
|
||||
(0, 0, 0),
|
||||
(-90, 90, 180),
|
||||
(0, 360, 0),
|
||||
(10, -10, 20),
|
||||
(10, 350, 20),
|
||||
(370, 20, 10),
|
||||
]
|
||||
|
||||
|
||||
# Do not execute the base class as a test, see https://stackoverflow.com/a/43353680/3753684
|
||||
del TestDifference
|
62
pyrate/tests/plan/geometry/helpers/test_distance.py
Normal file
62
pyrate/tests/plan/geometry/helpers/test_distance.py
Normal file
@ -0,0 +1,62 @@
|
||||
"""This module asserts correct runtime behaviour of the :mod:`pyrate.plan.geometry.helpers` functions
|
||||
for calculating distances.
|
||||
"""
|
||||
|
||||
# Python standard library
|
||||
from datetime import timedelta
|
||||
from math import radians
|
||||
|
||||
# Testing
|
||||
from unittest import TestCase
|
||||
|
||||
# Hypothesis testing
|
||||
from hypothesis import given
|
||||
from hypothesis import settings
|
||||
import hypothesis.strategies as st
|
||||
|
||||
# Scientific (testing)
|
||||
import numpy.testing
|
||||
|
||||
# Module under test
|
||||
from pyrate.plan.geometry.helpers import fast_distance_geo
|
||||
from pyrate.plan.geometry.helpers import haversine_numpy
|
||||
|
||||
# Own geometry
|
||||
from pyrate.plan.geometry.geospatial import MEAN_EARTH_CIRCUMFERENCE
|
||||
from pyrate.plan.geometry import PolarLocation
|
||||
|
||||
# Test helpers
|
||||
from pyrate.common.testing.strategies.geometry import geo_bearings
|
||||
from pyrate.common.testing.strategies.geometry import polar_locations
|
||||
|
||||
|
||||
class TestDistanceCalculation(TestCase):
|
||||
"""Tests the geographic helper methods."""
|
||||
|
||||
@given(polar_locations(), polar_locations())
|
||||
def test_haversine_formula(self, location_1: PolarLocation, location_2: PolarLocation) -> None:
|
||||
"""Test the correctness of the haversine formula."""
|
||||
dist = haversine_numpy(
|
||||
radians(location_1.latitude),
|
||||
radians(location_1.longitude),
|
||||
radians(location_2.latitude),
|
||||
radians(location_2.longitude),
|
||||
)
|
||||
self.assertLessEqual(dist, MEAN_EARTH_CIRCUMFERENCE / 2)
|
||||
numpy.testing.assert_allclose(location_1.distance(location_2), dist, atol=5.0, rtol=0.01)
|
||||
|
||||
@given(polar_locations(), geo_bearings(), st.floats(min_value=0.0, max_value=250_000.0))
|
||||
@settings(deadline=timedelta(seconds=1.0))
|
||||
# pylint: disable=no-self-use
|
||||
def test_fast_distance_geo(self, center: PolarLocation, direction: float, distance: float) -> None:
|
||||
"""Test the correctness of the fast great-circle approximation."""
|
||||
|
||||
other, _ = center.translate(direction, distance)
|
||||
|
||||
distance_calculated = fast_distance_geo(
|
||||
radians(other.latitude),
|
||||
radians(other.longitude),
|
||||
radians(center.latitude),
|
||||
radians(center.longitude),
|
||||
)
|
||||
numpy.testing.assert_allclose(distance, distance_calculated, atol=0.5, rtol=0.05)
|
182
pyrate/tests/plan/geometry/helpers/test_normalize.py
Normal file
182
pyrate/tests/plan/geometry/helpers/test_normalize.py
Normal file
@ -0,0 +1,182 @@
|
||||
"""This module asserts correct runtime behaviour of the :mod:`pyrate.plan.geometry.helpers` functions
|
||||
for normalization.
|
||||
"""
|
||||
|
||||
# Python standard
|
||||
from abc import ABC
|
||||
from abc import abstractmethod
|
||||
|
||||
# Typing
|
||||
from typing import Callable
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
|
||||
# Generic testing
|
||||
from unittest import TestCase
|
||||
|
||||
# Numeric testing
|
||||
from numpy import allclose
|
||||
from numpy import array
|
||||
|
||||
# Hypothesis testing
|
||||
from hypothesis import given
|
||||
import hypothesis.strategies as st
|
||||
|
||||
# Test helpers
|
||||
from pyrate.plan.geometry.helpers import normalize_direction
|
||||
from pyrate.plan.geometry.helpers import normalize_latitude
|
||||
from pyrate.plan.geometry.helpers import normalize_longitude
|
||||
from pyrate.plan.geometry.helpers import ScalarOrArray
|
||||
|
||||
|
||||
class TestNormalize(TestCase, ABC):
|
||||
"""Makes sure the normalizations are well-behaved."""
|
||||
|
||||
@abstractmethod
|
||||
def _get_normalization_function(self) -> Callable[[ScalarOrArray], ScalarOrArray]:
|
||||
"""Get the function to be tested."""
|
||||
|
||||
@abstractmethod
|
||||
def _get_min(self) -> float:
|
||||
"""Get the desired minimum value (inclusive)."""
|
||||
|
||||
@abstractmethod
|
||||
def _get_max(self) -> float:
|
||||
"""Get the desired maximum value, see :meth:`TestNormalize._max_is_inclusive`."""
|
||||
|
||||
def _max_is_inclusive(self) -> bool: # pylint: disable=no-self-use
|
||||
"""If :meth:`TestNormalize._get_max` is to be seen as inclusive or exclusive"""
|
||||
return False
|
||||
|
||||
@abstractmethod
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float]]:
|
||||
"""Get some concrete values to be tested as a sequence of ``(non-normalized, normalized)``."""
|
||||
|
||||
@given(st.floats(allow_infinity=False, allow_nan=False))
|
||||
def test_bounds(self, value: float) -> None:
|
||||
"""Assures that the normalized value is within its bounds."""
|
||||
|
||||
normalized = self._get_normalization_function()(value)
|
||||
|
||||
# make sure the normalized value is within bounds
|
||||
self.assertGreaterEqual(normalized, self._get_min())
|
||||
|
||||
if self._max_is_inclusive():
|
||||
self.assertLessEqual(normalized, self._get_max())
|
||||
else:
|
||||
self.assertLess(normalized, self._get_max())
|
||||
|
||||
@given(st.floats(allow_infinity=False, allow_nan=False))
|
||||
def test_normalizing_twice(self, value: float) -> None:
|
||||
"""Assures that normalizing twice does not really change the value."""
|
||||
|
||||
normalized = self._get_normalization_function()(value)
|
||||
normalized_twice = self._get_normalization_function()(normalized)
|
||||
|
||||
self.assertAlmostEqual(normalized, normalized_twice, places=10)
|
||||
|
||||
@given(st.floats(min_value=-400, max_value=+400))
|
||||
def test_already_normalized_values(self, value: float) -> None:
|
||||
"""Assures that values stay unchanged if and only if are already normalized (i.e. within bounds)."""
|
||||
below_max = value < self._get_max() or (self._max_is_inclusive() and value == self._get_max())
|
||||
if self._get_min() <= value and below_max:
|
||||
self.assertAlmostEqual(self._get_normalization_function()(value), value, delta=1e-12)
|
||||
else:
|
||||
self.assertNotEqual(self._get_normalization_function()(value), value)
|
||||
|
||||
def test_concrete_examples(self) -> None:
|
||||
"""Checks the result for the concrete examples given in :meth:`~_get_concrete_examples`."""
|
||||
function = self._get_normalization_function()
|
||||
|
||||
for index, (non_normalized, normalized) in enumerate(self._get_concrete_examples()):
|
||||
with self.subTest(f"example triple #{index}"):
|
||||
self.assertAlmostEqual(function(non_normalized), normalized, delta=1e-12)
|
||||
|
||||
def test_concrete_examples_as_array(self) -> None:
|
||||
"""Checks the result for the concrete examples given in :meth:`~_get_concrete_examples`."""
|
||||
function = self._get_normalization_function()
|
||||
data = array(self._get_concrete_examples()).T
|
||||
self.assertTrue(allclose(function(data[0, :]), data[1, :]))
|
||||
|
||||
|
||||
class TestNormalizeLatitude(TestNormalize):
|
||||
"""Tests :func:`pyrate.plan.geometry.helpers.normalize_latitude`."""
|
||||
|
||||
def _get_normalization_function(self) -> Callable[[ScalarOrArray], ScalarOrArray]:
|
||||
return normalize_latitude
|
||||
|
||||
def _get_min(self) -> float:
|
||||
return -90.0
|
||||
|
||||
def _get_max(self) -> float:
|
||||
return 90.0
|
||||
|
||||
def _max_is_inclusive(self) -> bool:
|
||||
return True
|
||||
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float]]:
|
||||
return [
|
||||
(0, 0),
|
||||
(90, 90),
|
||||
(-90, -90),
|
||||
(100, 80),
|
||||
(180, 0),
|
||||
(270, -90),
|
||||
(-180, 0),
|
||||
(-270, 90),
|
||||
(-10, -10),
|
||||
]
|
||||
|
||||
|
||||
class TestNormalizeLongitude(TestNormalize):
|
||||
"""Tests :func:`pyrate.plan.geometry.helpers.normalize_longitude`."""
|
||||
|
||||
def _get_normalization_function(self) -> Callable[[ScalarOrArray], ScalarOrArray]:
|
||||
return normalize_longitude
|
||||
|
||||
def _get_min(self) -> float:
|
||||
return -180.0
|
||||
|
||||
def _get_max(self) -> float:
|
||||
return 180.0
|
||||
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float]]:
|
||||
return [
|
||||
(0, 0),
|
||||
(90, 90),
|
||||
(-90, -90),
|
||||
(100, 100),
|
||||
(180, -180),
|
||||
(-180, -180),
|
||||
(270, -90),
|
||||
(-10, -10),
|
||||
]
|
||||
|
||||
|
||||
class TestNormalizeDirection(TestNormalize):
|
||||
"""Tests :func:`pyrate.plan.geometry.helpers.normalize_direction`."""
|
||||
|
||||
def _get_normalization_function(self) -> Callable[[ScalarOrArray], ScalarOrArray]:
|
||||
return normalize_direction
|
||||
|
||||
def _get_min(self) -> float:
|
||||
return 0.0
|
||||
|
||||
def _get_max(self) -> float:
|
||||
return 360.0
|
||||
|
||||
def _get_concrete_examples(self) -> Sequence[Tuple[float, float]]:
|
||||
return [
|
||||
(0, 0),
|
||||
(90, 90),
|
||||
(-90, 270),
|
||||
(100, 100),
|
||||
(180, 180),
|
||||
(-180, 180),
|
||||
(270, 270),
|
||||
(-10, 350),
|
||||
]
|
||||
|
||||
|
||||
# Do not execute the base class as a test, see https://stackoverflow.com/a/43353680/3753684
|
||||
del TestNormalize
|
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)
|
34
pyrate/tests/plan/geometry/helpers/test_translate.py
Normal file
34
pyrate/tests/plan/geometry/helpers/test_translate.py
Normal file
@ -0,0 +1,34 @@
|
||||
"""This module asserts correct runtime behaviour of the :mod:`pyrate.plan.geometry.helpers` functions
|
||||
for translation.
|
||||
|
||||
Note that most of the correctness is asserted by the use in
|
||||
:meth:`pyrate.plan.geometry.PolarPolygon.translate` and :meth:`pyrate.plan.geometry.PolarRoute.translate`.
|
||||
Also, no extensive tests are needed since we trust the underlying library due to its widespread adoption and
|
||||
maturity.
|
||||
We only need to check that the conversion of parameters and results works as expcted.
|
||||
"""
|
||||
|
||||
# Testing
|
||||
from unittest import TestCase
|
||||
|
||||
# Scientific (testing)
|
||||
from numpy import array
|
||||
|
||||
# Module under test
|
||||
from pyrate.plan.geometry.helpers import translate_numpy
|
||||
|
||||
|
||||
class TestTranslate(TestCase):
|
||||
"""Tests the translation helpers."""
|
||||
|
||||
COORDINATES = array([[1.0, 2.0], [3.0, -4.0], [-5.0, 6.0]])
|
||||
DIRECTIONS = array([0.0, 90.0, -90.0])
|
||||
DISTANCES = array([1.0, 100.0, 10000.0])
|
||||
|
||||
def test_translate_numpy(self) -> None: # pylint: disable=no-self-use
|
||||
"""Test that any combination of types of input are accepted."""
|
||||
|
||||
translate_numpy(TestTranslate.COORDINATES, TestTranslate.DIRECTIONS, TestTranslate.DISTANCES)
|
||||
translate_numpy(TestTranslate.COORDINATES, 90, TestTranslate.DISTANCES)
|
||||
translate_numpy(TestTranslate.COORDINATES, TestTranslate.DIRECTIONS, 100)
|
||||
translate_numpy(TestTranslate.COORDINATES, 90, 100)
|
Reference in New Issue
Block a user