Coverage for tests / test_ivoa.py: 14%
60 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-14 23:29 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-14 23:29 +0000
1# This file is part of sphgeom.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This software is dual licensed under the GNU General Public License and also
10# under a 3-clause BSD license. Recipients may choose which of these licenses
11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12# respectively. If you choose the GPL option then the following text applies
13# (but note that there is still no warranty even if you opt for BSD instead):
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU General Public License as published by
17# the Free Software Foundation, either version 3 of the License, or
18# (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU General Public License for more details.
24#
25# You should have received a copy of the GNU General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
28import unittest
30from lsst.sphgeom import Box, Circle, ConvexPolygon, LonLat, Region, UnitVector3d
33class IvoaTestCase(unittest.TestCase):
34 """Test Box."""
36 def test_construction(self):
37 # Example POS strings found in IVOA documentation.
38 example_pos = (
39 "CIRCLE 12.0 34.0 0.5",
40 "RANGE 12.0 12.5 34.0 36.0",
41 "POLYGON 12.0 34.0 14.0 35.0 14. 36.0 12.0 35.0",
42 "RANGE 0 360.0 -2.0 2.0",
43 "RANGE 0 360.0 89.0 +Inf",
44 "RANGE -Inf +Inf -Inf +Inf",
45 "POLYGON 12 34 14 34 14 36 12 36",
46 "RANGE 0 360 89 90",
47 )
48 for pos in example_pos:
49 region = Region.from_ivoa_pos(pos)
50 self.assertIsInstance(region, Region)
52 # Badly formed strings raising ValueError.
53 bad_pos = (
54 "circle 12 34 0.5",
55 "CIRCLE 12 34 1 1",
56 "RANGE 0 360",
57 "POLYGON 0 1 2 3",
58 "POLYGON 0 1 2 3 4 5 6",
59 "CONVEXPOLYGON 0 1 2 3 4 5",
60 )
61 for pos in bad_pos:
62 with self.assertRaises(ValueError):
63 Region.from_ivoa_pos(pos)
65 def _split_pos(self, pos: str):
66 """Split POS into type and floats."""
67 region_type, *coordstr = pos.split()
68 coordinates = [float(c) for c in coordstr]
69 return region_type, coordinates
71 def assert_pos_equal(self, pos1: str, pos2: str):
72 """Compare two POS strings and check for equality taking into account
73 floating point differences.
74 """
75 region_type1, coords1 = self._split_pos(pos1)
76 region_type2, coords2 = self._split_pos(pos2)
77 self.assertEqual(region_type1, region_type2)
78 self.assertEqual(len(coords1), len(coords2))
79 for c1, c2 in zip(coords1, coords2, strict=True):
80 self.assertAlmostEqual(c1, c2)
82 def test_circle(self):
83 """Test circle construction."""
84 pos = "CIRCLE 12.0 34.0 5"
85 circle = Region.from_ivoa_pos(pos)
86 self.assertIsInstance(circle, Circle)
87 self.assertTrue(circle.contains(UnitVector3d(LonLat.fromDegrees(13.0, 33.0))))
88 self.assertFalse(circle.contains(UnitVector3d(LonLat.fromDegrees(12.0, 40.0))))
90 self.assert_pos_equal(circle.to_ivoa_pos(), pos)
92 def test_range(self):
93 """Test range construction."""
94 box = Region.from_ivoa_pos("RANGE 1 2 5 6")
95 self.assertIsInstance(box, Box)
96 self.assertTrue(box.contains(UnitVector3d(LonLat.fromDegrees(1.5, 5.4))))
97 self.assertFalse(box.contains(UnitVector3d(LonLat.fromDegrees(4, 10))))
98 self.assert_pos_equal(box.to_ivoa_pos(), "RANGE 1 2 5 6")
100 box = Region.from_ivoa_pos("RANGE 1 2 20 +Inf")
101 self.assertTrue(box.contains(UnitVector3d(LonLat.fromDegrees(1.7, 80))))
102 self.assertFalse(box.contains(UnitVector3d(LonLat.fromDegrees(1.7, 10))))
103 self.assert_pos_equal(box.to_ivoa_pos(), "RANGE 1 2 20 90")
105 box = Region.from_ivoa_pos("RANGE 50 +Inf 20 30")
106 self.assertTrue(box.contains(UnitVector3d(LonLat.fromDegrees(60, 25))))
107 self.assertFalse(box.contains(UnitVector3d(LonLat.fromDegrees(49, 21))))
108 self.assert_pos_equal(box.to_ivoa_pos(), "RANGE 50 360 20 30")
110 box = Region.from_ivoa_pos("RANGE -Inf +50 20 30")
111 self.assertTrue(box.contains(UnitVector3d(LonLat.fromDegrees(40, 25))))
112 self.assertFalse(box.contains(UnitVector3d(LonLat.fromDegrees(60, 21))))
113 self.assert_pos_equal(box.to_ivoa_pos(), "RANGE 0 50 20 30")
115 box = Region.from_ivoa_pos("RANGE -Inf +Inf 20 30")
116 self.assertTrue(box.contains(UnitVector3d(LonLat.fromDegrees(10, 25))))
117 self.assertTrue(box.contains(UnitVector3d(LonLat.fromDegrees(359, 25))))
118 self.assertFalse(box.contains(UnitVector3d(LonLat.fromDegrees(49, 19))))
119 self.assert_pos_equal(box.to_ivoa_pos(), "RANGE 0 360. 20 30")
121 def test_polygon(self):
122 """Test polygon construction."""
123 pos = "POLYGON 12.0 34.0 14.0 35.0 14. 36.0 12.0 35.0"
124 poly = Region.from_ivoa_pos(pos)
125 self.assertIsInstance(poly, ConvexPolygon)
126 self.assertTrue(poly.contains(UnitVector3d(LonLat.fromDegrees(13, 35))))
127 self.assertFalse(poly.contains(UnitVector3d(LonLat.fromDegrees(14, 34))))
128 self.assert_pos_equal(poly.to_ivoa_pos(), pos)
131if __name__ == "__main__":
132 unittest.main()