Coverage for tests/test_ellipse.py: 16%

98 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-02 02:18 -0700

1# 

2# LSST Data Management System 

3# Copyright 2008-2017 LSST Corporation. 

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 <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22 

23import unittest 

24 

25import numpy as np 

26 

27import lsst.utils.tests 

28import lsst.pex.exceptions 

29import lsst.geom 

30import lsst.afw.geom.ellipses 

31import lsst.afw.image 

32 

33 

34class EllipseTestCase(lsst.utils.tests.TestCase): 

35 

36 def setUp(self): 

37 np.random.seed(500) 

38 self.cores = [ 

39 lsst.afw.geom.ellipses.Axes(4, 3, 1), 

40 lsst.afw.geom.ellipses.Quadrupole(5, 3, -1), 

41 # A line segment at 45-degrees: 

42 lsst.afw.geom.ellipses.Quadrupole(ixx=99.99999763706363, iyy=99.99999763706357, 

43 ixy=99.99999763706), 

44 # A horizontal line segment: 

45 lsst.afw.geom.ellipses.Quadrupole(5.0, 0.0, 0.0), 

46 # A vertical line segment: 

47 lsst.afw.geom.ellipses.Quadrupole(0.0, 7.0, 0.0), 

48 ] 

49 self.classes = [lsst.afw.geom.ellipses.Axes, 

50 lsst.afw.geom.ellipses.Quadrupole] 

51 for s in lsst.afw.geom.ellipses.Separable.values(): 

52 self.cores.append(s(0.5, 0.3, 2.1)) 

53 self.classes.append(s) 

54 

55 def testRadii(self): 

56 for core, det, trace in zip(self.cores, [144, 14], [25, 8]): 

57 with self.subTest(core=str(core)): 

58 detRadius = det**0.25 

59 traceRadius = (0.5 * trace)**0.5 

60 area = np.pi * det**0.5 

61 self.assertFloatsAlmostEqual( 

62 core.getDeterminantRadius(), detRadius) 

63 self.assertFloatsAlmostEqual(core.getTraceRadius(), traceRadius) 

64 self.assertFloatsAlmostEqual(core.getArea(), area) 

65 for cls in self.classes: 

66 conv = cls(core) 

67 self.assertFloatsAlmostEqual( 

68 conv.getDeterminantRadius(), detRadius) 

69 self.assertFloatsAlmostEqual( 

70 conv.getTraceRadius(), traceRadius) 

71 self.assertFloatsAlmostEqual(conv.getArea(), area) 

72 conv.scale(3.0) 

73 self.assertFloatsAlmostEqual( 

74 conv.getDeterminantRadius(), detRadius * 3) 

75 self.assertFloatsAlmostEqual( 

76 conv.getTraceRadius(), traceRadius * 3) 

77 self.assertFloatsAlmostEqual(conv.getArea(), area * 9) 

78 

79 def testAccessors(self): 

80 for core in self.cores: 

81 with self.subTest(core=str(core)): 

82 vec = np.random.randn(3) * 1E-3 + core.getParameterVector() 

83 core.setParameterVector(vec) 

84 self.assertImagesEqual(core.getParameterVector(), vec) 

85 center = lsst.geom.Point2D(*np.random.randn(2)) 

86 ellipse = lsst.afw.geom.ellipses.Ellipse(core, center) 

87 self.assertFloatsAlmostEqual( 

88 core.getParameterVector(), ellipse.getParameterVector()[:3]) 

89 self.assertEqual(tuple(center), tuple(ellipse.getCenter())) 

90 self.assertEqual(lsst.geom.Point2D, type(ellipse.getCenter())) 

91 newcore = lsst.afw.geom.ellipses.Axes(1, 2, 3) 

92 newcore.normalize() 

93 core.assign(newcore) 

94 ellipse.setCore(core) 

95 np.testing.assert_allclose( 

96 core.getParameterVector(), ellipse.getCore().getParameterVector()) 

97 self.assertFloatsAlmostEqual( 

98 core.clone().getParameterVector(), core.getParameterVector()) 

99 self.assertIsNot(core, core.clone()) 

100 self.assertFloatsAlmostEqual(lsst.afw.geom.ellipses.Ellipse(ellipse).getParameterVector(), 

101 ellipse.getParameterVector()) 

102 self.assertIsNot(ellipse, lsst.afw.geom.ellipses.Ellipse(ellipse)) 

103 

104 def testTransform(self): 

105 for core in self.cores: 

106 with self.subTest(core=str(core)): 

107 transform = lsst.geom.LinearTransform(np.random.randn(2, 2)) 

108 t1 = core.transform(transform) 

109 core.transformInPlace(transform) 

110 self.assertIsNot(t1, core) 

111 self.assertFloatsAlmostEqual( 

112 t1.getParameterVector(), core.getParameterVector()) 

113 

114 def testPixelRegion(self): 

115 for core in self.cores: 

116 with self.subTest(core=str(core)): 

117 e = lsst.afw.geom.ellipses.Ellipse( 

118 core, lsst.geom.Point2D(*np.random.randn(2))) 

119 region = lsst.afw.geom.ellipses.PixelRegion(e) 

120 bbox = region.getBBox() 

121 bbox.grow(2) 

122 array = np.zeros((bbox.getHeight(), bbox.getWidth()), dtype=bool) 

123 for span in region: 

124 for point in span: 

125 adjusted = point - bbox.getMin() 

126 array[adjusted.getY(), adjusted.getX()] = True 

127 self.assertLessEqual(span.getMinX(), span.getMaxX()) 

128 gt = e.getGridTransform() 

129 for i in range(bbox.getBeginY(), bbox.getEndY()): 

130 for j in range(bbox.getBeginX(), bbox.getEndX()): 

131 point = lsst.geom.Point2I(j, i) 

132 adjusted = point - bbox.getMin() 

133 transformed = gt(lsst.geom.Point2D(point)) 

134 r = (transformed.getX()**2 + transformed.getY()**2)**0.5 

135 if array[adjusted.getY(), adjusted.getX()]: 

136 self.assertLessEqual(r, 1.0, f"Point {point} is in region but r={r}") 

137 else: 

138 self.assertGreater(r, 1.0, f"Point {point} is outside region but r={r}") 

139 # Another ellipse at a different position, specifically to 

140 # reproduce the problem on DM-20246. 

141 e = lsst.afw.geom.Ellipse(core, lsst.geom.Point2D(100, 100)) 

142 region = lsst.afw.geom.ellipses.PixelRegion(e) 

143 bbox = region.getBBox() 

144 for span in region: 

145 self.assertLessEqual(span.getMinX(), span.getMaxX()) 

146 self.assertTrue(bbox.contains(span.getMin())) 

147 self.assertTrue(bbox.contains(span.getMax())) 

148 

149 

150class MemoryTester(lsst.utils.tests.MemoryTestCase): 

151 pass 

152 

153 

154def setup_module(module): 

155 lsst.utils.tests.init() 

156 

157 

158if __name__ == "__main__": 158 ↛ 159line 158 didn't jump to line 159, because the condition on line 158 was never true

159 lsst.utils.tests.init() 

160 unittest.main()