Coverage for tests/test_CompoundRegion.py: 30%

84 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-05-02 03:12 -0700

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/>. 

27 

28import pickle 

29import unittest 

30 

31try: 

32 import yaml 

33except ImportError: 

34 yaml = None 

35 

36from lsst.sphgeom import ( 

37 CONTAINS, 

38 DISJOINT, 

39 INTERSECTS, 

40 WITHIN, 

41 Angle, 

42 AngleInterval, 

43 Box, 

44 Circle, 

45 CompoundRegion, 

46 IntersectionRegion, 

47 LonLat, 

48 NormalizedAngleInterval, 

49 Region, 

50 UnionRegion, 

51 UnitVector3d, 

52) 

53 

54 

55class CompoundRegionTestMixin: 

56 """Tests for both UnionRegion and IntersectionRegion. 

57 

58 Concrete TestCase subclasses are responsible for adding an `instance` 

59 attribute with a non-trivial instance of the `CompoundRegion` subclass 

60 being tested. 

61 """ 

62 

63 def setUp(self): 

64 self.point_in_circle = LonLat.fromDegrees(44.0, 45.0) 

65 self.point_in_box = LonLat.fromDegrees(46.0, 45.0) 

66 self.point_in_both = LonLat.fromDegrees(45.0, 45.0) 

67 self.point_in_neither = LonLat.fromDegrees(45.0, 48.0) 

68 self.circle = Circle(UnitVector3d(self.point_in_circle), Angle.fromDegrees(1.0)) 

69 self.box = Box.fromDegrees( 

70 self.point_in_box.getLon().asDegrees() - 1.5, 

71 self.point_in_box.getLat().asDegrees() - 1.5, 

72 self.point_in_box.getLon().asDegrees() + 1.5, 

73 self.point_in_box.getLat().asDegrees() + 1.5, 

74 ) 

75 self.faraway = Circle(UnitVector3d(self.point_in_neither), Angle.fromDegrees(0.1)) 

76 self.operands = (self.circle, self.box) 

77 

78 def assertOperandsEqual(self, region, operands): 

79 """Assert that a compound regions operands are equal to the given 

80 tuple of operands. 

81 """ 

82 self.assertCountEqual((region.cloneOperand(0), region.cloneOperand(1)), operands) 

83 

84 def assertCompoundRegionsEqual(self, a, b): 

85 """Assert that two compound regions are equal. 

86 

87 CompoundRegion does not implement equality comparison because 

88 regions in general do not, and hence it cannot delegate that operation 

89 to its operands. But the concrete operands (circle and box) we use in 

90 these tests do implement equality comparison. 

91 """ 

92 self.assertEqual(type(a), type(b)) 

93 self.assertOperandsEqual(a, (b.cloneOperand(0), b.cloneOperand(1))) 

94 

95 def testSetUp(self): 

96 """Test that the points and operand regions being tested have the 

97 relationships expected. 

98 """ 

99 self.assertTrue(self.circle.contains(UnitVector3d(self.point_in_circle))) 

100 self.assertTrue(self.circle.contains(UnitVector3d(self.point_in_both))) 

101 self.assertFalse(self.circle.contains(UnitVector3d(self.point_in_box))) 

102 self.assertFalse(self.circle.contains(UnitVector3d(self.point_in_neither))) 

103 self.assertTrue(self.box.contains(UnitVector3d(self.point_in_box))) 

104 self.assertTrue(self.box.contains(UnitVector3d(self.point_in_both))) 

105 self.assertFalse(self.box.contains(UnitVector3d(self.point_in_circle))) 

106 self.assertFalse(self.box.contains(UnitVector3d(self.point_in_neither))) 

107 self.assertEqual(self.circle.relate(self.circle), CONTAINS | WITHIN) 

108 self.assertEqual(self.circle.relate(self.box), INTERSECTS) 

109 self.assertEqual(self.circle.relate(self.faraway), DISJOINT) 

110 self.assertEqual(self.box.relate(self.circle), INTERSECTS) 

111 self.assertEqual(self.box.relate(self.box), CONTAINS | WITHIN) 

112 self.assertEqual(self.box.relate(self.faraway), DISJOINT) 

113 

114 def testOperands(self): 

115 """Test the cloneOperands accessor.""" 

116 self.assertOperandsEqual(self.instance, self.operands) 

117 

118 def testCodec(self): 

119 """Test that encode and decode round-trip.""" 

120 s = self.instance.encode() 

121 self.assertCompoundRegionsEqual(type(self.instance).decode(s), self.instance) 

122 self.assertCompoundRegionsEqual(CompoundRegion.decode(s), self.instance) 

123 self.assertCompoundRegionsEqual(Region.decode(s), self.instance) 

124 

125 def testPickle(self): 

126 """Test pickling round-trips.""" 

127 s = pickle.dumps(self.instance, pickle.HIGHEST_PROTOCOL) 

128 self.assertCompoundRegionsEqual(pickle.loads(s), self.instance) 

129 

130 def testString(self): 

131 """Test that repr returns a string that can be eval'd to yield an 

132 equivalent instance. 

133 """ 

134 self.assertCompoundRegionsEqual( 

135 self.instance, 

136 eval( 

137 repr(self.instance), 

138 { 

139 "UnionRegion": UnionRegion, 

140 "IntersectionRegion": IntersectionRegion, 

141 "Box": Box, 

142 "Circle": Circle, 

143 "UnitVector3d": UnitVector3d, 

144 "Angle": Angle, 

145 "AngleInterval": AngleInterval, 

146 "NormalizedAngleInterval": NormalizedAngleInterval, 

147 }, 

148 ), 

149 ) 

150 

151 @unittest.skipIf(not yaml, "YAML module can not be imported") 

152 def testYaml(self): 

153 """Test that YAML dump and load round-trip.""" 

154 self.assertCompoundRegionsEqual(yaml.safe_load(yaml.dump(self.instance)), self.instance) 

155 

156 

157class UnionRegionTestCase(CompoundRegionTestMixin, unittest.TestCase): 

158 """Test UnionRegion.""" 

159 

160 def setUp(self): 

161 CompoundRegionTestMixin.setUp(self) 

162 self.instance = UnionRegion(*self.operands) 

163 

164 def testContains(self): 

165 """Test point-in-region checks.""" 

166 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_both))) 

167 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_circle))) 

168 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_box))) 

169 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_neither))) 

170 

171 def testRelate(self): 

172 """Test region-region relationship checks.""" 

173 self.assertEqual(self.instance.relate(self.circle), CONTAINS) 

174 self.assertEqual(self.instance.relate(self.box), CONTAINS) 

175 self.assertEqual(self.instance.relate(self.faraway), DISJOINT) 

176 self.assertEqual(self.circle.relate(self.instance), WITHIN) 

177 self.assertEqual(self.box.relate(self.instance), WITHIN) 

178 self.assertEqual(self.faraway.relate(self.instance), DISJOINT) 

179 

180 

181class IntersectionRegionTestCase(CompoundRegionTestMixin, unittest.TestCase): 

182 """Test intersection region.""" 

183 

184 def setUp(self): 

185 CompoundRegionTestMixin.setUp(self) 

186 self.instance = IntersectionRegion(*self.operands) 

187 

188 def testContains(self): 

189 """Test point-in-region checks.""" 

190 self.assertTrue(self.instance.contains(UnitVector3d(self.point_in_both))) 

191 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_circle))) 

192 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_box))) 

193 self.assertFalse(self.instance.contains(UnitVector3d(self.point_in_neither))) 

194 

195 def testRelate(self): 

196 """Test region-region relationship checks.""" 

197 self.assertEqual(self.instance.relate(self.box), WITHIN) 

198 self.assertEqual(self.instance.relate(self.circle), WITHIN) 

199 self.assertEqual(self.instance.relate(self.faraway), DISJOINT) 

200 self.assertEqual(self.circle.relate(self.instance), CONTAINS) 

201 self.assertEqual(self.box.relate(self.instance), CONTAINS) 

202 self.assertEqual(self.faraway.relate(self.instance), DISJOINT) 

203 

204 

205if __name__ == "__main__": 

206 unittest.main()