LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
NormalizedAngleInterval.cc
Go to the documentation of this file.
1/*
2 * LSST Data Management System
3 * Copyright 2014-2015 AURA/LSST.
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 */
22
25
27
28#include <ostream>
29#include <stdexcept>
30
31
32namespace lsst {
33namespace sphgeom {
34
36 if (x.isNan() || y.isNan()) {
37 *this = empty();
38 return;
39 }
40 if (!x.isNormalized() || !y.isNormalized()) {
41 if (x > y) {
43 "invalid NormalizedAngleInterval endpoints");
44 }
45 if (y - x >= Angle(2.0 * PI)) {
46 *this = full();
47 return;
48 }
49 }
50 _a = NormalizedAngle(x);
51 _b = NormalizedAngle(y);
52}
53
55 NormalizedAngleInterval const & x) const
56{
57 if (x.isEmpty()) {
58 return true;
59 }
60 if (isEmpty()) {
61 return false;
62 }
63 if (x.wraps()) {
64 if (!wraps()) {
65 return isFull();
66 }
67 } else if (wraps()) {
68 return x._a >= _a || x._b <= _b;
69 }
70 return x._a >= _a && x._b <= _b;
71}
72
74 NormalizedAngleInterval const & x) const
75{
76 if (x.isEmpty() || isEmpty()) {
77 return true;
78 }
79 if (x.wraps()) {
80 return wraps() ? false : (x._a > _b && x._b < _a);
81 }
82 if (wraps()) {
83 return _a > x._b && _b < x._a;
84 }
85 return x._b < _a || x._a > _b;
86}
87
89 if (isEmpty()) {
90 if (x.isNan()) {
91 return CONTAINS | DISJOINT | WITHIN;
92 }
93 return DISJOINT | WITHIN;
94 }
95 if (x.isNan()) {
96 return CONTAINS | DISJOINT;
97 }
98 if (_a == x && _b == x) {
99 return CONTAINS | WITHIN;
100 }
101 if (intersects(x)) {
102 return CONTAINS;
103 }
104 return DISJOINT;
105}
106
108 NormalizedAngleInterval const & x) const
109{
110 if (isEmpty()) {
111 if (x.isEmpty()) {
112 return CONTAINS | DISJOINT | WITHIN;
113 }
114 return DISJOINT | WITHIN;
115 }
116 if (x.isEmpty()) {
117 return CONTAINS | DISJOINT;
118 }
119 if (_a == x._a && _b == x._b) {
120 return CONTAINS | WITHIN;
121 }
122 // The intervals are not the same, and neither is empty.
123 if (wraps()) {
124 if (x.wraps()) {
125 // Both intervals wrap.
126 if (_a <= x._a && _b >= x._b) {
127 return CONTAINS;
128 }
129 if (_a >= x._a && _b <= x._b) {
130 return WITHIN;
131 }
132 return INTERSECTS;
133 }
134 // x does not wrap.
135 if (x.isFull()) {
136 return WITHIN;
137 }
138 if (_a <= x._a || _b >= x._b) {
139 return CONTAINS;
140 }
141 return (_a > x._b && _b < x._a) ? DISJOINT : INTERSECTS;
142 }
143 if (x.wraps()) {
144 // This interval does not wrap.
145 if (isFull()) {
146 return CONTAINS;
147 }
148 if (x._a <= _a || x._b >= _b) {
149 return WITHIN;
150 }
151 return (x._a > _b && x._b < _a) ? DISJOINT : INTERSECTS;
152 }
153 // Neither interval wraps.
154 if (_a <= x._a && _b >= x._b) {
155 return CONTAINS;
156 }
157 if (_a >= x._a && _b <= x._b) {
158 return WITHIN;
159 }
160 return (_a <= x._b && _b >= x._a) ? INTERSECTS : DISJOINT;
161}
162
165{
166 if (x.isEmpty()) {
167 *this = empty();
168 } else if (contains(x._a)) {
169 if (contains(x._b)) {
170 // Both endpoints of x are in this interval. This interval
171 // either contains x, in which case x is the exact intersection,
172 // or the intersection consists of [_a,x._b] ⋃ [x._a,_b].
173 // In both cases, the envelope of the intersection is the shorter
174 // of the two intervals.
175 if (getSize() >= x.getSize()) {
176 *this = x;
177 }
178 } else {
179 _a = x._a;
180 }
181 } else if (contains(x._b)) {
182 _b = x._b;
183 } else if (x.isDisjointFrom(_a)) {
184 *this = empty();
185 }
186 return *this;
187}
188
191{
192 if (isEmpty()) {
193 *this = NormalizedAngleInterval(x);
194 } else if (!contains(x)) {
195 if (x.getAngleTo(_a) > _b.getAngleTo(x)) {
196 _b = x;
197 } else {
198 _a = x;
199 }
200 }
201 return *this;
202}
203
206{
207 if (!x.isEmpty()) {
208 if (contains(x._a)) {
209 if (contains(x._b)) {
210 // Both endpoints of x are in this interval. This interval
211 // either contains x, in which case this interval is the
212 // desired union, or the union is the full interval.
213 if (wraps() != x.wraps()) {
214 *this = full();
215 }
216 } else {
217 _b = x._b;
218 }
219 } else if (contains(x._b)) {
220 _a = x._a;
221 } else if (isEmpty() || x.contains(_a)) {
222 *this = x;
223 } else if (_b.getAngleTo(x._a) < x._b.getAngleTo(_a)) {
224 _b = x._b;
225 } else {
226 _a = x._a;
227 }
228 }
229 return *this;
230}
231
233 if (isEmpty() || isFull() || x == Angle(0.0) || x.isNan()) {
234 return *this;
235 }
236 Angle a = _a - x;
237 Angle b = _b + x;
238 if (x > Angle(0.0)) {
239 // x is a dilation.
240 if (x >= Angle(PI)) { return full(); }
241 if (wraps()) {
242 // The undilated interval wraps. If the dilated one does not,
243 // then decreasing a from _a and increasing b from _b has
244 // caused b and a to cross.
245 if (a <= b) { return full(); }
246 } else {
247 // The undilated interval does not wrap. If either a or b
248 // is not normalized then the dilated interval must either
249 // wrap or be full.
250 if (a < Angle(0.0)) {
251 a = a + Angle(2.0 * PI);
252 if (a <= b) { return full(); }
253 }
254 if (b > Angle(2.0 * PI)) {
255 b = b - Angle(2.0 * PI);
256 if (a <= b) { return full(); }
257 }
258 }
259 } else {
260 // x is an erosion.
261 if (x <= Angle(-PI)) { return empty(); }
262 if (wraps()) {
263 // The uneroded interval wraps. If either a or b is not
264 // normalized, then either the eroded interval does not wrap,
265 // or it is empty.
266 if (a > Angle(2.0 * PI)) {
267 a = a - Angle(2.0 * PI);
268 if (a > b) { return empty(); }
269 }
270 if (b < Angle(0.0)) {
271 b = b + Angle(2.0 * PI);
272 if (a > b) { return empty(); }
273 }
274 } else {
275 // The uneroded interval does not wrap. If the eroded one does,
276 // then increasing a from _a and decreasing b from _b has
277 // caused a and b to cross.
278 if (a > b) { return empty(); }
279 }
280 }
281 return NormalizedAngleInterval(a, b);
282}
283
285 NormalizedAngleInterval const & i)
286{
287 return os << '[' << i.getA() << ", " << i.getB() << ']';
288}
289
290}} // namespace lsst::sphgeom
double x
This file declares a class representing closed intervals of normalized angles, i.e.
std::ostream * os
Definition: Schema.cc:557
int y
Definition: SpanSet.cc:48
table::Key< int > b
table::Key< int > a
Angle represents an angle in radians.
Definition: Angle.h:43
NormalizedAngle is an angle that lies in the range [0, 2π), with one exception - a NormalizedAngle ca...
NormalizedAngle getAngleTo(NormalizedAngle const &a) const
getAngleTo computes the angle α ∈ [0, 2π) such that adding α to this angle and then normalizing the r...
NormalizedAngleInterval represents closed intervals of normalized angles, i.e.
static NormalizedAngleInterval empty()
bool isFull() const
isFull returns true if this interval contains all normalized angles.
bool isDisjointFrom(NormalizedAngle x) const
NormalizedAngleInterval()
This constructor creates an empty interval.
bool wraps() const
wraps returns true if the interval "wraps" around the 0/2π angle discontinuity, i....
NormalizedAngleInterval & clipTo(NormalizedAngle x)
clipTo shrinks this interval until all its points are in x.
NormalizedAngle getA() const
getA returns the first endpoint of this interval.
NormalizedAngleInterval dilatedBy(Angle x) const
For positive x, dilatedBy returns the morphological dilation of this interval by [-x,...
Relationship relate(NormalizedAngle x) const
NormalizedAngle getSize() const
getSize returns the size (length, width) of this interval.
NormalizedAngleInterval & expandTo(NormalizedAngle x)
NormalizedAngle getB() const
getB returns the second endpoint of this interval.
static NormalizedAngleInterval full()
bool isEmpty() const
isEmpty returns true if this interval does not contain any normalized angles.
lsst::geom::Angle Angle
Definition: misc.h:33
std::ostream & operator<<(std::ostream &, Angle const &)
Definition: Angle.cc:34
constexpr double PI
Definition: constants.h:36
A base class for image defects.