Coverage for tests/test_ellipse.py: 14%
98 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-15 02:24 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-15 02:24 -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#
23import unittest
25import numpy as np
27import lsst.utils.tests
28import lsst.pex.exceptions
29import lsst.geom
30import lsst.afw.geom.ellipses
31import lsst.afw.image
34class EllipseTestCase(lsst.utils.tests.TestCase):
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)
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, atol=1e-15, rtol=1e-15)
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))
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())
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()))
150class MemoryTester(lsst.utils.tests.MemoryTestCase):
151 pass
154def setup_module(module):
155 lsst.utils.tests.init()
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()