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
Interval.cc
Go to the documentation of this file.
1/*
2 * Developed for the LSST Data Management System.
3 * This product includes software developed by the LSST Project
4 * (https://www.lsst.org).
5 * See the COPYRIGHT file at the top-level directory of this distribution
6 * for details of code ownership.
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 GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <cmath>
23#include <limits>
24#include <type_traits>
25
26#include "boost/format.hpp"
27
29#include "lsst/geom/Interval.h"
30
31namespace lsst {
32namespace geom {
33
34namespace {
35
36using BigElement = long long;
37
38// Templated so we can check both floating point and BigElement values.
39// Should never be invoked with IntervalI::Element values, as that won't
40// accomplish anything.
41template <typename T>
42void checkForOverflow(T x, char const* where) {
43 static_assert(sizeof(T) > sizeof(IntervalI::Element) || !std::is_integral<T>::value);
46 throw LSST_EXCEPT(pex::exceptions::OverflowError,
47 (boost::format("Integer overflow (%d) in interval %s.") % x % where).str());
48 }
49}
50
51} // namespace
52
54 return _fromMinMaxChecked(static_cast<BigElement>(min), static_cast<BigElement>(max));
55}
56
58 if (size <= 0) {
59 return IntervalI();
60 }
61 BigElement max = static_cast<BigElement>(min) + static_cast<BigElement>(size) - 1;
62 checkForOverflow(max, "maximum");
63 return IntervalI(min, size);
64}
65
67 if (size <= 0) {
68 return IntervalI();
69 }
70 BigElement min = static_cast<BigElement>(max) - static_cast<BigElement>(size) + 1;
71 checkForOverflow(min, "minimum");
72 return IntervalI(static_cast<Element>(min), size);
73}
74
76 if (size <= 0) {
77 return IntervalI();
78 }
79 double min = center - 0.5 * size;
80 // compensate for IntervalI's coordinate conventions (where max = min + size - 1)
81 min += 0.5;
82 checkForOverflow(min, "minimum");
83 checkForOverflow(min + size - 1, "maximum");
84 return IntervalI(static_cast<BigElement>(min), size);
85}
86
87IntervalI::IntervalI(IntervalD const& other, EdgeHandlingEnum edgeHandling) : _min(), _size() {
88 if (other.isEmpty()) {
89 *this = IntervalI();
90 return;
91 }
92 if (!std::isfinite(other.getMin()) || !std::isfinite(other.getMax())) {
94 "Cannot convert non-finite IntervalD to IntervalI");
95 }
96 BigElement min, max;
97 switch (edgeHandling) {
99 min = static_cast<BigElement>(std::ceil(other.getMin() - 0.5));
100 max = static_cast<BigElement>(std::floor(other.getMax() + 0.5));
101 break;
103 min = static_cast<BigElement>(std::ceil(other.getMin() + 0.5));
104 max = static_cast<BigElement>(std::floor(other.getMax() - 0.5));
105 break;
106 default:
107 throw pex::exceptions::LogicError("Invalid enum value.");
108 }
109 *this = _fromMinMaxChecked(min, max);
110}
111
112ndarray::View<boost::fusion::vector1<ndarray::index::Range>> IntervalI::getSlice() const {
113 return ndarray::view(getBegin(), getEnd());
114}
115
116bool IntervalI::contains(Element point) const noexcept {
117 // The case where this->isEmpty() is handled implicitly by the invariant
118 // that empty intervals have max < min.
119 return point >= this->getMin() && point <= this->getMax();
120}
121
122bool IntervalI::contains(IntervalI const& other) const noexcept {
123 // The case where this->isEmpty() is handled implicitly by the invariant
124 // that empty intervals have max < min.
125 return other.isEmpty() || (other.getMin() >= this->getMin() && other.getMax() <= this->getMax());
126}
127
128bool IntervalI::overlaps(IntervalI const& other) const noexcept { return !isDisjointFrom(other); }
129
130bool IntervalI::isDisjointFrom(IntervalI const& other) const noexcept {
131 if (isEmpty() || other.isEmpty()) {
132 return true;
133 }
134 return getMin() > other.getMax() || getMax() < other.getMin();
135}
136
138 if (isEmpty()) {
139 return IntervalI();
140 }
141 BigElement min = static_cast<BigElement>(getMin()) - buffer;
142 BigElement max = static_cast<BigElement>(getMax()) + buffer;
143 return _fromMinMaxChecked(min, max);
144}
145
147 if (isEmpty()) {
148 return IntervalI();
149 }
150 BigElement min = static_cast<BigElement>(getMin()) + offset;
151 BigElement max = static_cast<BigElement>(getMax()) + offset;
152 checkForOverflow(min, "minimum");
153 checkForOverflow(max, "maximum");
154 return IntervalI(static_cast<Element>(min), getSize());
155}
156
158 if (isEmpty()) {
159 return IntervalI();
160 }
161 BigElement max = 2 * static_cast<BigElement>(point) - getMin();
162 BigElement min = 2 * static_cast<BigElement>(point) - getMax();
163 return _fromMinMaxChecked(min, max);
164}
165
167 if (isEmpty()) {
168 return IntervalI(point, 1);
169 }
170 return _fromMinMaxChecked(std::min(static_cast<BigElement>(point), static_cast<BigElement>(getMin())),
171 std::max(static_cast<BigElement>(point), static_cast<BigElement>(getMax())));
172}
173
175 if (other.isEmpty()) {
176 return *this;
177 }
178 if (this->isEmpty()) {
179 return other;
180 }
181 return _fromMinMaxChecked(
182 std::min(static_cast<BigElement>(other.getMin()), static_cast<BigElement>(getMin())),
183 std::max(static_cast<BigElement>(other.getMax()), static_cast<BigElement>(getMax())));
184}
185
186IntervalI IntervalI::clippedTo(IntervalI const& other) const noexcept {
187 if (isEmpty() || other.isEmpty()) {
188 return IntervalI();
189 }
190 return fromMinMax(std::max(getMin(), other.getMin()), std::min(getMax(), other.getMax()));
191}
192
193bool IntervalI::operator==(IntervalI const& other) const noexcept {
194 return other._min == this->_min && other._size == this->_size;
195}
196
197bool IntervalI::operator!=(IntervalI const& other) const noexcept { return !(other == *this); }
198
200 // Completely arbitrary seed
201 return utils::hashCombine(17, _min, _size);
202}
203
205 return (boost::format("(min=%s, max=%s)") % getMin() % getMax()).str();
206}
207
208template <typename T>
209IntervalI IntervalI::_fromMinMaxChecked(T min, T max) {
210 if (max < min) {
211 return IntervalI();
212 }
213 checkForOverflow(min, "minimum");
214 checkForOverflow(max, "maximum");
215 T size = 1 + max - min;
216 checkForOverflow(size, "size");
217 return IntervalI(static_cast<Element>(min), static_cast<Element>(size));
218}
219
220IntervalI::IntervalI(Element min, Element size) : _min(min), _size(size) {}
221
223 : _min(std::numeric_limits<IntervalD::Element>::quiet_NaN()),
224 _max(std::numeric_limits<IntervalD::Element>::quiet_NaN()) {}
225
227
229 if (std::isinf(min) || (std::isinf(size) && size > 0)) {
231 "Ambiguously infinite interval parameters; use fromMinMax to "
232 "construct infinite intervals instead.");
233 }
234 return IntervalD(min, min + size);
235}
236
238 if (std::isinf(max) || (std::isinf(size) && size > 0)) {
240 "Ambiguously infinite interval parameters; use fromMinMax to "
241 "construct infinite intervals instead.");
242 }
243 return IntervalD(max - size, max);
244}
245
247 if (std::isinf(center) || std::isinf(size)) {
248 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Infinite values not supported.");
249 }
250 Element min = center - 0.5 * size;
252}
253
254IntervalD::IntervalD(IntervalI const& other) noexcept
255 : _min(other.getMin() - 0.5), _max(other.getMax() + 0.5) {
256 if (other.isEmpty()) *this = IntervalD();
257}
258
259IntervalD::Element IntervalD::getSize() const noexcept { return isEmpty() ? 0.0 : (_max - _min); }
260
261IntervalD::Element IntervalD::getCenter() const noexcept { return 0.5 * (_min + _max); }
262
263bool IntervalD::contains(Element point) const {
264 if (std::isnan(point)) {
266 "Cannot test whether an interval contains NaN.");
267 }
268 return point >= this->getMin() && point <= this->getMax();
269}
270
271bool IntervalD::contains(IntervalD const& other) const noexcept {
272 return other.isEmpty() || (other.getMin() >= this->getMin() && other.getMax() <= this->getMax());
273}
274
275bool IntervalD::overlaps(IntervalD const& other) const noexcept { return !isDisjointFrom(other); }
276
277bool IntervalD::isDisjointFrom(IntervalD const& other) const noexcept {
278 if (isEmpty() || other.isEmpty()) {
279 return true;
280 }
281 return getMin() > other.getMax() || getMax() < other.getMin();
282}
283
285 if (!std::isfinite(buffer)) {
287 "Cannot dilate or erode with a non-finite buffer.");
288 }
289 return fromMinMax(_min - buffer, _max + buffer);
290}
291
293 if (!std::isfinite(offset)) {
294 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Cannot shift with a non-finite offset.");
295 }
296 if (!isEmpty()) {
297 return fromMinMax(_min + offset, _max + offset);
298 } else {
299 return IntervalD();
300 }
301}
302
304 if (!std::isfinite(point)) {
305 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Cannot reflect about a non-finite point.");
306 }
307 if (!isEmpty()) {
308 return fromMinMax(2 * point - _max, 2 * point - _min);
309 } else {
310 return IntervalD();
311 }
312}
313
315 if (!std::isfinite(point)) {
316 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Cannot expand to a non-finite point.");
317 }
318 if (isEmpty()) {
319 return fromMinMax(point, point);
320 } else {
321 return fromMinMax(std::min(point, _min), std::max(point, _max));
322 }
323}
324
325IntervalD IntervalD::expandedTo(IntervalD const& other) const noexcept {
326 if (other.isEmpty()) {
327 return *this;
328 } else if (this->isEmpty()) {
329 return other;
330 } else {
331 return fromMinMax(std::min(this->getMin(), other.getMin()), std::max(this->getMax(), other.getMax()));
332 }
333}
334
335IntervalD IntervalD::clippedTo(IntervalD const& other) const noexcept {
336 if (this->isEmpty() || other.isEmpty()) {
337 return IntervalD();
338 } else {
339 return fromMinMax(std::max(this->getMin(), other.getMin()), std::min(this->getMax(), other.getMax()));
340 }
341}
342
343bool IntervalD::operator==(IntervalD const& other) const noexcept {
344 return (other.isEmpty() && this->isEmpty()) || (other._min == this->_min && other._max == this->_max);
345}
346
347bool IntervalD::operator!=(IntervalD const& other) const noexcept { return !(other == *this); }
348
350 // Completely arbitrary seed
351 return utils::hashCombine(17, _min, _max);
352}
353
355 return (boost::format("(min=%s, max=%s)") % getMin() % getMax()).str();
356}
357
358IntervalD::IntervalD(Element min, Element max) : _min(min), _max(max) {
359 if (max < min || std::isnan(min) || std::isnan(max)) {
360 *this = IntervalD();
361 } else if (std::isinf(min) && min > 0.0) {
363 "Cannot set interval minimum to +infinity.");
364 } else if (std::isinf(max) && max < 0.0) {
365 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
366 "Cannot set interval maximum to -infinity.");
367 }
368}
369
371 if (interval.isEmpty()) return os << "IntervalI()";
372 return os << "IntervalI" << interval.toString();
373}
374
376 if (interval.isEmpty()) return os << "IntervalD()";
377 return os << "IntervalD" << interval.toString();
378}
379
380} // namespace geom
381} // namespace lsst
int min
int max
double x
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
std::ostream * os
Definition: Schema.cc:557
T ceil(T... args)
A floating-point coordinate rectangle geometry.
Definition: Interval.h:413
Element getMin() const noexcept
Return the size of the interval.
Definition: Interval.h:559
IntervalD reflectedAbout(Element point) const
Reflect an interval about a point (returning a new object).
Definition: Interval.cc:303
bool operator==(IntervalD const &other) const noexcept
Compare two intervals for equality.
Definition: Interval.cc:343
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Interval.cc:349
static IntervalD fromMaxSize(Element max, Element size)
Construct an interval from its upper bound and size.
Definition: Interval.cc:237
bool isDisjointFrom(IntervalD const &other) const noexcept
Return true if there are no points in both this and other.
Definition: Interval.cc:277
static IntervalD fromMinMax(Element min, Element max)
Construct an interval from its lower and upper bounds.
Definition: Interval.cc:226
bool operator!=(IntervalD const &other) const noexcept
Compare two intervals for equality.
Definition: Interval.cc:347
bool overlaps(IntervalD const &other) const noexcept
Return true if any points in other are also in this.
Definition: Interval.cc:275
Element getMax() const noexcept
Return the size of the interval.
Definition: Interval.h:560
Element getSize() const noexcept
Return the size of the interval.
Definition: Interval.cc:259
IntervalD() noexcept
Construct an empty interval.
Definition: Interval.cc:222
bool contains(Element point) const
Return true if the interval contains the point.
Definition: Interval.cc:263
std::string toString() const
Return the size of the interval.
Definition: Interval.cc:354
static IntervalD fromCenterSize(double center, Element size)
Construct an interval centered on a particular point.
Definition: Interval.cc:246
IntervalD dilatedBy(Element buffer) const
Increase the size of the interval by the given amount in both directions (returning a new object).
Definition: Interval.cc:284
IntervalD clippedTo(IntervalD const &other) const noexcept
Shrink an interval to ensure that it is contained by other (returning a new object).
Definition: Interval.cc:335
IntervalD expandedTo(Element other) const
Expand an interval to ensure that contains(other) is true.
Definition: Interval.cc:314
bool isEmpty() const noexcept
Return true if the interval contains no points.
Definition: Interval.h:579
IntervalD shiftedBy(Element offset) const
Shift the position of the interval by the given offset (returning a new object).
Definition: Interval.cc:292
Element getCenter() const noexcept
Return the center coordinate of the interval.
Definition: Interval.cc:261
static IntervalD fromMinSize(Element min, Element size)
Construct an interval from its lower bound and size.
Definition: Interval.cc:228
A 1-d integer coordinate range.
Definition: Interval.h:50
bool contains(Element point) const noexcept
Return true if the interval contains the point.
Definition: Interval.cc:116
static IntervalI fromMinSize(Element min, Element size)
Construct an interval from its lower bound and size.
Definition: Interval.cc:57
bool overlaps(IntervalI const &other) const noexcept
Return true if there are any points in both this and other.
Definition: Interval.cc:128
ndarray::View< boost::fusion::vector1< ndarray::index::Range > > getSlice() const
Return slice to extract the interval's region from an ndarray::Array.
Definition: Interval.cc:112
IntervalI() noexcept
Construct an empty interval.
Definition: Interval.h:77
IntervalI clippedTo(IntervalI const &other) const noexcept
Shrink an interval to ensure that it is contained by other (returning a new)
Definition: Interval.cc:186
IntervalI dilatedBy(Element buffer) const
Increase the size of the interval by the given amount in both directions (returning a new object).
Definition: Interval.cc:137
bool isEmpty() const noexcept
Return true if the interval contains no points.
Definition: Interval.h:262
bool isDisjointFrom(IntervalI const &other) const noexcept
Return true if there are no points in both this and other.
Definition: Interval.cc:130
Element getMax() const noexcept
Definition: Interval.h:228
bool operator!=(IntervalI const &other) const noexcept
Compare two intervals for equality.
Definition: Interval.cc:197
EdgeHandlingEnum
Enum used to indicate how to handle conversions from floating-point to integer intervals.
Definition: Interval.h:64
@ SHRINK
Include only pixels that are wholly contained by the floating-point interval.
@ EXPAND
Include all pixels that overlap the floating-point interval at all.
bool operator==(IntervalI const &other) const noexcept
Compare two intervals for equality.
Definition: Interval.cc:193
Element getSize() const noexcept
Return slice to extract the interval's region from an ndarray::Array.
Definition: Interval.h:247
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Interval.cc:199
static IntervalI fromMaxSize(Element max, Element size)
Construct an interval from its upper bound and size.
Definition: Interval.cc:66
Element getEnd() const noexcept
Definition: Interval.h:239
std::string toString() const
Return slice to extract the interval's region from an ndarray::Array.
Definition: Interval.cc:204
static IntervalI fromCenterSize(double center, Element size)
Create an interval centered as closely as possible on a particular point.
Definition: Interval.cc:75
static IntervalI fromMinMax(Element min, Element max)
Construct an interval from its lower and upper bounds.
Definition: Interval.cc:53
IntervalI shiftedBy(Element offset) const
Shift the position of the interval by the given offset (returning a new object).)
Definition: Interval.cc:146
Element getBegin() const noexcept
Definition: Interval.h:238
IntervalI expandedTo(Element other) const
Expand an interval to ensure that contains(other) is true (returning a new object).
Definition: Interval.cc:166
Element getMin() const noexcept
Definition: Interval.h:227
IntervalI reflectedAbout(Element point) const
Reflect an interval about a point (returning a new object).
Definition: Interval.cc:157
Reports invalid arguments.
Definition: Runtime.h:66
Reports errors in the logical structure of the program.
Definition: Runtime.h:46
T floor(T... args)
T isfinite(T... args)
T isinf(T... args)
T isnan(T... args)
T max(T... args)
T min(T... args)
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
Definition: hashCombine.h:35
std::ostream & operator<<(std::ostream &os, lsst::geom::AffineTransform const &transform)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
A base class for image defects.
STL namespace.
table::Key< table::Array< int > > _size
Definition: PsfexPsf.cc:364