Coverage for tests/test_CompoundRegion.py: 30%
86 statements
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-19 10:38 +0000
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-19 10:38 +0000
1#
2# LSST Data Management System
3# See COPYRIGHT file at the top of the source tree.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <https://www.lsstcorp.org/LegalNotices/>.
21#
23import pickle
24import unittest
26try:
27 import yaml
28except ImportError:
29 yaml = None
31from lsst.sphgeom import (
32 CONTAINS,
33 DISJOINT,
34 INTERSECTS,
35 WITHIN,
36 Angle,
37 AngleInterval,
38 Box,
39 Circle,
40 CompoundRegion,
41 IntersectionRegion,
42 LonLat,
43 NormalizedAngleInterval,
44 Region,
45 UnionRegion,
46 UnitVector3d,
47)
50class CompoundRegionTestMixin:
51 """Tests for both UnionRegion and IntersectionRegion.
53 Concrete TestCase subclasses are responsible for adding an `instance`
54 attribute with a non-trivial instance of the `CompoundRegion` subclass
55 being tested.
56 """
58 def setUp(self):
59 self.point_in_circle = LonLat.fromDegrees(44.0, 45.0)
60 self.point_in_box = LonLat.fromDegrees(46.0, 45.0)
61 self.point_in_both = LonLat.fromDegrees(45.0, 45.0)
62 self.point_in_neither = LonLat.fromDegrees(45.0, 48.0)
63 self.circle = Circle(UnitVector3d(self.point_in_circle), Angle.fromDegrees(1.0))
64 self.box = Box.fromDegrees(
65 self.point_in_box.getLon().asDegrees() - 1.5,
66 self.point_in_box.getLat().asDegrees() - 1.5,
67 self.point_in_box.getLon().asDegrees() + 1.5,
68 self.point_in_box.getLat().asDegrees() + 1.5,
69 )
70 self.faraway = Circle(UnitVector3d(self.point_in_neither), Angle.fromDegrees(0.1))
71 self.operands = (self.circle, self.box)
73 def assertOperandsEqual(self, region, operands):
74 """Assert that a compound regions operands are equal to the given
75 tuple of operands.
76 """
77 self.assertCountEqual((region.cloneOperand(0), region.cloneOperand(1)), operands)
79 def assertCompoundRegionsEqual(self, a, b):
80 """Assert that two compound regions are equal.
82 CompoundRegion does not implement equality comparison because
83 regions in general do not, and hence it cannot delegate that operation
84 to its operands. But the concrete operands (circle and box) we use in
85 these tests do implement equality comparison.
86 """
87 self.assertEqual(type(a), type(b))
88 self.assertOperandsEqual(a, (b.cloneOperand(0), b.cloneOperand(1)))
90 def testSetUp(self):
91 """Test that the points and operand regions being tested have the
92 relationships expected.
93 """
94 self.assertTrue(self.circle.contains(UnitVector3d(self.point_in_circle)))
95 self.assertTrue(self.circle.contains(UnitVector3d(self.point_in_both)))
96 self.assertFalse(self.circle.contains(UnitVector3d(self.point_in_box)))
97 self.assertFalse(self.circle.contains(UnitVector3d(self.point_in_neither)))
98 self.assertTrue(self.box.contains(UnitVector3d(self.point_in_box)))
99 self.assertTrue(self.box.contains(UnitVector3d(self.point_in_both)))
100 self.assertFalse(self.box.contains(UnitVector3d(self.point_in_circle)))
101 self.assertFalse(self.box.contains(UnitVector3d(self.point_in_neither)))
102 self.assertEqual(self.circle.relate(self.circle), CONTAINS | WITHIN)
103 self.assertEqual(self.circle.relate(self.box), INTERSECTS)
104 self.assertEqual(self.circle.relate(self.faraway), DISJOINT)
105 self.assertEqual(self.box.relate(self.circle), INTERSECTS)
106 self.assertEqual(self.box.relate(self.box), CONTAINS | WITHIN)
107 self.assertEqual(self.box.relate(self.faraway), DISJOINT)
109 def testOperands(self):
110 """Test the cloneOperands accessor."""
111 self.assertOperandsEqual(self.instance, self.operands)
113 def testCodec(self):
114 """Test that encode and decode round-trip."""
115 s = self.instance.encode()
116 self.assertCompoundRegionsEqual(type(self.instance).decode(s), self.instance)
117 self.assertCompoundRegionsEqual(CompoundRegion.decode(s), self.instance)
118 self.assertCompoundRegionsEqual(Region.decode(s), self.instance)
120 def testPickle(self):
121 """Test pickling round-trips."""
122 s = pickle.dumps(self.instance, pickle.HIGHEST_PROTOCOL)
123 self.assertCompoundRegionsEqual(pickle.loads(s), self.instance)
125 def testString(self):
126 """Test that repr returns a string that can be eval'd to yield an
127 equivalent instance.
128 """
129 self.assertCompoundRegionsEqual(
130 self.instance,
131 eval(
132 repr(self.instance),
133 dict(
134 UnionRegion=UnionRegion,
135 IntersectionRegion=IntersectionRegion,
136 Box=Box,
137 Circle=Circle,
138 UnitVector3d=UnitVector3d,
139 Angle=Angle,
140 AngleInterval=AngleInterval,
141 NormalizedAngleInterval=NormalizedAngleInterval,
142 ),
143 ),
144 )
146 @unittest.skipIf(not yaml, "YAML module can not be imported")
147 def testYaml(self):
148 """Test that YAML dump and load round-trip."""
149 self.assertCompoundRegionsEqual(yaml.safe_load(yaml.dump(self.instance)), self.instance)
152class UnionRegionTestCase(CompoundRegionTestMixin, unittest.TestCase):
153 def setUp(self):
154 CompoundRegionTestMixin.setUp(self)
155 self.instance = UnionRegion(*self.operands)
157 def testContains(self):
158 """Test point-in-region checks."""
159 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_both)))
160 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_circle)))
161 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_box)))
162 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_neither)))
164 def testRelate(self):
165 """Test region-region relationship checks."""
166 self.assertEqual(self.instance.relate(self.circle), CONTAINS)
167 self.assertEqual(self.instance.relate(self.box), CONTAINS)
168 self.assertEqual(self.instance.relate(self.faraway), DISJOINT)
169 self.assertEqual(self.circle.relate(self.instance), WITHIN)
170 self.assertEqual(self.box.relate(self.instance), WITHIN)
171 self.assertEqual(self.faraway.relate(self.instance), DISJOINT)
174class IntersectionRegionTestCase(CompoundRegionTestMixin, unittest.TestCase):
175 def setUp(self):
176 CompoundRegionTestMixin.setUp(self)
177 self.instance = IntersectionRegion(*self.operands)
179 def testContains(self):
180 """Test point-in-region checks."""
181 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_both)))
182 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_circle)))
183 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_box)))
184 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_neither)))
186 def testRelate(self):
187 """Test region-region relationship checks."""
188 self.assertEqual(self.instance.relate(self.box), WITHIN)
189 self.assertEqual(self.instance.relate(self.circle), WITHIN)
190 self.assertEqual(self.instance.relate(self.faraway), DISJOINT)
191 self.assertEqual(self.circle.relate(self.instance), CONTAINS)
192 self.assertEqual(self.box.relate(self.instance), CONTAINS)
193 self.assertEqual(self.faraway.relate(self.instance), DISJOINT)
196if __name__ == "__main__": 196 ↛ 197line 196 didn't jump to line 197, because the condition on line 196 was never true
197 unittest.main()