LSSTApplications  19.0.0+10,19.0.0+80,19.0.0-1-g20d9b18+31,19.0.0-1-g49a97f9+4,19.0.0-1-g8c57eb9+31,19.0.0-1-g9a028c0+13,19.0.0-1-ga72da6b+3,19.0.0-1-gb77924a+15,19.0.0-1-gbfe0924+66,19.0.0-1-gc3516c3,19.0.0-1-gefe1d0d+49,19.0.0-1-gf8cb8b4+3,19.0.0-14-g7511ce4+6,19.0.0-16-g3dc1a33c+6,19.0.0-17-g59f0e8a+4,19.0.0-17-g9c22e3c+9,19.0.0-18-g35bb99870+2,19.0.0-19-g2772d4a+9,19.0.0-2-g260436e+53,19.0.0-2-g31cdcee,19.0.0-2-g9675b69+3,19.0.0-2-gaa2795f,19.0.0-2-gbcc4de1,19.0.0-2-gd6f004e+6,19.0.0-2-gde8e5e3+5,19.0.0-2-gff6972b+15,19.0.0-21-ge306cd8,19.0.0-21-gf122e69+2,19.0.0-3-g2d43a51+2,19.0.0-3-gf3b1435+6,19.0.0-4-g56feb96,19.0.0-4-gac56cce+17,19.0.0-49-gce872c1+1,19.0.0-5-g66946eb+6,19.0.0-5-gd8897ba+6,19.0.0-51-gfc4a647e,19.0.0-7-g686a884+5,19.0.0-7-g886f805+5,19.0.0-8-g305ff64,w.2020.17
LSSTDataManagementBasePackage
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 
32 namespace lsst {
33 namespace 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 
164  NormalizedAngleInterval const & x)
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 
205  NormalizedAngleInterval const & x)
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
bool isEmpty() const
isEmpty returns true if this interval does not contain any normalized angles.
bool isDisjointFrom(NormalizedAngle x) const
NormalizedAngle is an angle that lies in the range [0, 2π), with one exception - a NormalizedAngle ca...
bool isNan() const
isNan returns true if the angle value is NaN.
Definition: Angle.h:91
NormalizedAngle getB() const
getB returns the second endpoint of this interval.
table::Key< int > b
NormalizedAngleInterval & expandTo(NormalizedAngle x)
int y
Definition: SpanSet.cc:49
table::Key< int > a
std::ostream & operator<<(std::ostream &, Angle const &)
Definition: Angle.cc:34
bool isFull() const
isFull returns true if this interval contains all normalized angles.
NormalizedAngle getAngleTo(NormalizedAngle const &a) const
getAngleTo computes the angle α ∈ [0, 2π) such that adding α to this angle and then normalizing the ...
bool wraps() const
wraps returns true if the interval "wraps" around the 0/2π angle discontinuity, i.e.
bool isNan() const
isNan returns true if the angle value is NaN.
A base class for image defects.
NormalizedAngleInterval()
This constructor creates an empty interval.
constexpr double PI
Definition: constants.h:36
static NormalizedAngleInterval empty()
NormalizedAngleInterval dilatedBy(Angle x) const
For positive x, dilatedBy returns the morphological dilation of this interval by [-x,x].
Relationship relate(NormalizedAngle x) const
NormalizedAngleInterval represents closed intervals of normalized angles, i.e.
double x
This file declares a class representing closed intervals of normalized angles, i.e.
static NormalizedAngleInterval full()
Angle represents an angle in radians.
Definition: Angle.h:43
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.
lsst::geom::Angle Angle
Definition: misc.h:33
bool isNormalized() const
isNormalized returns true if this angle lies in the range [0, 2π).
Definition: Angle.h:88
std::ostream * os
Definition: Schema.cc:746
STL class.
STL class.
NormalizedAngle getSize() const
getSize returns the size (length, width) of this interval.