""" """ """ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ __author__ = "Théo de la Hogue" __credits__ = [] __copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)" __license__ = "GPLv3" import unittest import math from argaze.AreaOfInterest import AOIFeatures import numpy class TestAreaOfInterestClass(unittest.TestCase): """Test AreaOfInterest class.""" def test_new(self): """Test AreaOfInterest creation.""" # Check that 0D AreaOfInterest creation is considered as empty aoi_0D = AOIFeatures.AreaOfInterest() self.assertTrue(aoi_0D.is_empty()) # Check 1 point 1D AreaOfInterest creation aoi_1D = AOIFeatures.AreaOfInterest([[0]]) self.assertFalse(aoi_1D.is_empty()) self.assertEqual(aoi_1D.dimension, 1) self.assertEqual(aoi_1D.points_number, 1) self.assertIsNone(numpy.testing.assert_array_equal(aoi_1D.bounds, [[0], [0]])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_1D.center, [0])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_1D.size, [0])) with self.assertRaises(AssertionError): self.assertEqual(aoi_1D.bounding_box, 1) # Check 2 points 1D AreaOfInterest creation aoi_1D = AOIFeatures.AreaOfInterest([[0], [1]]) self.assertFalse(aoi_1D.is_empty()) self.assertEqual(aoi_1D.dimension, 1) self.assertEqual(aoi_1D.points_number, 2) self.assertIsNone(numpy.testing.assert_array_equal(aoi_1D.bounds, [[0], [1]])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_1D.center, [0.5])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_1D.size, [1])) with self.assertRaises(AssertionError): self.assertEqual(aoi_1D.bounding_box, 1) # Check 4 points 2D AreaOfInterest creation aoi_2D = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertFalse(aoi_2D.is_empty()) self.assertEqual(aoi_2D.dimension, 2) self.assertEqual(aoi_2D.points_number, 4) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2D.bounds, [[0, 0], [1, 1]])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2D.center, [0.5, 0.5])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2D.size, [1, 1])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2D.bounding_box, [[0, 0], [1, 0], [1, 1], [0, 1]])) # Check 8 points 3D AreaOfInterest creation aoi_3D = AOIFeatures.AreaOfInterest([[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0], [0, 0, 1], [0, 1, 1], [1, 0, 1], [1, 1, 1]]) self.assertFalse(aoi_3D.is_empty()) self.assertEqual(aoi_3D.dimension, 3) self.assertEqual(aoi_3D.points_number, 8) self.assertIsNone(numpy.testing.assert_array_equal(aoi_3D.bounds, [[0, 0, 0], [1, 1, 1]])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_3D.center, [0.5, 0.5, 0.5])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_3D.size, [1, 1, 1])) with self.assertRaises(AssertionError): self.assertEqual(aoi_3D.bounding_box, 1) def test___repr__(self): """Test AreaOfInterest string representation.""" aoi_2D_int = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertEqual(repr(aoi_2D_int), "[[0, 0], [0, 1], [1, 0], [1, 1]]") aoi_2D_float = AOIFeatures.AreaOfInterest([[0, 0], [0, math.pi], [math.pi, 0], [math.pi, math.pi]]) self.assertEqual(repr(aoi_2D_float), f'[[0.0, 0.0], [0.0, {repr(math.pi)}], [{repr(math.pi)}, 0.0], [{repr(math.pi)}, {repr(math.pi)}]]') def test___str__(self): """Test AreaOfInterest string display.""" aoi_2D_int = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 0], [1, 1]]) self.assertEqual(str(aoi_2D_int), "[[0, 0], [0, 1], [1, 0], [1, 1]]") aoi_2D_float = AOIFeatures.AreaOfInterest([[0, 0], [0, math.pi], [math.pi, 0], [math.pi, math.pi]]) self.assertEqual(str(aoi_2D_float), f'[[0.0, 0.0], [0.0, {str(math.pi)}], [{str(math.pi)}, 0.0], [{str(math.pi)}, {str(math.pi)}]]') def test_clockwise(self): """Test AreaOfInterest clockwise method.""" aoi_2D_clockwise = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 0], [1, 1]]).clockwise() self.assertEqual(type(aoi_2D_clockwise), AOIFeatures.AreaOfInterest) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2D_clockwise, [[0, 0], [1, 0], [1, 1], [0, 1]])) def test_contains_point(self): """Test AreaOfInterest contains_point method.""" aoi_2D = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) self.assertTrue(aoi_2D.contains_point((0.1, 0.9))) self.assertFalse(aoi_2D.contains_point((1.1, 0.9))) def test_inner_axis(self): aoi_2D = AOIFeatures.AreaOfInterest([[0, 0], [0, 2], [2, 2], [2, 0]]) self.assertEqual(aoi_2D.inner_axis(1, 1), (0.5, 0.5)) def test_outter_axis(self): aoi_2D = AOIFeatures.AreaOfInterest([[0, 0], [0, 2], [2, 2], [2, 0]]) self.assertEqual(aoi_2D.outter_axis(0.5, 0.5), (1, 1)) aoi_3D = AOIFeatures.AreaOfInterest([[1, 0, 0], [1, 0, 2], [1, 2, 2], [1, 2, 0]]) self.assertEqual(aoi_3D.outter_axis(0.5, 0.5), (1, 1, 1)) def test_circle_intersection(self): aoi_2D = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) intersection, aoi_ratio, circle_ratio = aoi_2D.circle_intersection((0, 0), 1) self.assertTrue(math.isclose(aoi_ratio, math.pi / 4, abs_tol=1e-2)) self.assertTrue(math.isclose(circle_ratio, 1 / 4, abs_tol=1e-3)) class TestAOISceneClass(unittest.TestCase): """Test AOIScene class.""" def test_new(self): """Test AOIScene creation.""" # Check that 0D AOIScene creation fails with self.assertRaises(AssertionError): aoi_0D_scene = AOIFeatures.AOIScene(0) # Check empty 2D AOIScene creation aoi_2d_scene = AOIFeatures.AOIScene(2) self.assertEqual(aoi_2d_scene.dimension, 2) self.assertEqual(len(aoi_2d_scene.items()), 0) self.assertEqual(len(vars(aoi_2d_scene)), 2 + len(aoi_2d_scene.items())) # Check 2D AOIScene creation aoi_2D = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) aoi_2d_scene = AOIFeatures.AOIScene(2, {"A": aoi_2D}) self.assertEqual(aoi_2d_scene.dimension, 2) self.assertEqual(len(aoi_2d_scene.items()), 1) self.assertEqual(list(aoi_2d_scene.keys()), ["A"]) self.assertEqual(len(vars(aoi_2d_scene)), 2 + len(aoi_2d_scene.items())) def test___set_item__(self): """Test AOIScene __set_item__ method.""" aoi_2d_scene = AOIFeatures.AOIScene(2,) # Check AOI with same dimension can be added aoi_2d_scene["A"] = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) # Check that AOI with different dimension fails with self.assertRaises(AssertionError): aoi_2d_scene["B"] = AOIFeatures.AreaOfInterest([[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0]]) def test_merge(self): """Test AOIScene merge operator.""" # Create first scene with A and B aoi aoi_2d_scene_AB = AOIFeatures.AOIScene(2,) aoi_2d_scene_AB["A"] = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) aoi_2d_scene_AB["B"] = AOIFeatures.AreaOfInterest([[0, 0], [0, 2], [2, 2], [2, 0]]) # Create second scene with C and D aoi aoi_2d_scene_CD = AOIFeatures.AOIScene(2,) aoi_2d_scene_CD["C"] = AOIFeatures.AreaOfInterest([[0, 0], [0, 3], [3, 3], [3, 0]]) aoi_2d_scene_CD["D"] = AOIFeatures.AreaOfInterest([[0, 0], [0, 4], [4, 4], [4, 0]]) # Merge first scene and second scene into a third scene aoi_2d_scene_ABCD = aoi_2d_scene_AB | aoi_2d_scene_CD # Check third scene self.assertEqual(aoi_2d_scene_ABCD.dimension, 2) self.assertEqual(len(aoi_2d_scene_ABCD.items()), 4) self.assertEqual(list(aoi_2d_scene_ABCD.keys()), ["A", "B", "C", "D"]) self.assertEqual(len(vars(aoi_2d_scene_ABCD)), 2 + len(aoi_2d_scene_ABCD.items())) # Merge second scene into first scene aoi_2d_scene_AB |= aoi_2d_scene_CD # Check first scene self.assertEqual(aoi_2d_scene_AB.dimension, 2) self.assertEqual(len(aoi_2d_scene_AB.items()), 4) self.assertEqual(list(aoi_2d_scene_AB.keys()), ["A", "B", "C", "D"]) self.assertEqual(len(vars(aoi_2d_scene_AB)), 2 + len(aoi_2d_scene_AB.items())) def test_expand(self): """Test AOIScene expand method.""" # Create 2D scene aoi_2d_scene = AOIFeatures.AOIScene(2,) aoi_2d_scene["A"] = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) aoi_2d_scene["B"] = AOIFeatures.AreaOfInterest([[0, 0], [0, 2], [2, 2], [2, 0]]) # Expand to 3D scene aoi_3d_scene = aoi_2d_scene.expand() self.assertEqual(aoi_3d_scene.dimension, 3) self.assertEqual(len(aoi_3d_scene.items()), 2) self.assertEqual(list(aoi_3d_scene.keys()), ["A", "B"]) self.assertEqual(aoi_3d_scene["A"].shape[1], 3) self.assertEqual(aoi_3d_scene["B"].shape[1], 3) def test___repr__(self): """Test AOIScene string representation.""" # Check empty 2D AOIScene representation self.assertEqual(repr(AOIFeatures.AOIScene(2)), "{}") # Check 2D AOIScene representation with integer AOI aoi_2D_int = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) aoi_2d_scene = AOIFeatures.AOIScene(2, {"A": aoi_2D_int}) self.assertEqual(repr(aoi_2d_scene), "{'A': [[0, 0], [0, 1], [1, 1], [1, 0]]}") # Check 2D AOIScene representation with float AOI aoi_2D_float = AOIFeatures.AreaOfInterest([[0, 0], [0, math.pi], [math.pi, 0], [math.pi, math.pi]]) aoi_2d_scene = AOIFeatures.AOIScene(2, {"A": aoi_2D_float}) expected_representation = "{'A': " + f'[[0.0, 0.0], [0.0, {repr(math.pi)}], [{repr(math.pi)}, 0.0], [{repr(math.pi)}, {repr(math.pi)}]]' + "}" self.assertEqual(repr(aoi_2d_scene), expected_representation) def test_properties(self): """Test AOIScene properties.""" aoi_2D_A = AOIFeatures.AreaOfInterest([[0, 0], [0, 1], [1, 1], [1, 0]]) aoi_2D_B = AOIFeatures.AreaOfInterest([[1, 1], [1, 2], [2, 2], [2, 1]]) aoi_2d_scene = AOIFeatures.AOIScene(2, {"A": aoi_2D_A, "B": aoi_2D_B}) self.assertEqual(aoi_2d_scene.dimension, 2) self.assertEqual(len(aoi_2d_scene.items()), 2) self.assertEqual(list(aoi_2d_scene.keys()), ["A", "B"]) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2d_scene.bounds, [[0, 0], [2, 2]])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2d_scene.center, [1, 1])) self.assertIsNone(numpy.testing.assert_array_equal(aoi_2d_scene.size, [2, 2])) if __name__ == '__main__': unittest.main()