LSSTApplications  16.0-1-gce273f5+17,16.0-1-gf77f410+12,16.0-10-g5a5abec+8,16.0-10-gc1446dd+12,16.0-12-g1dc09ba+6,16.0-12-g569485f,16.0-12-ga22ed6e+1,16.0-13-g4c33ca5+12,16.0-13-gb122224+3,16.0-13-gd9b1b71+12,16.0-14-g22e2ff2,16.0-14-g71e547a+8,16.0-17-g0bdc215+4,16.0-17-g6a7bfb3b+12,16.0-2-g0febb12+14,16.0-2-g839ba83+50,16.0-2-g9d5294e+39,16.0-20-ga7ad2685,16.0-3-g404ea43+9,16.0-3-gbc759ec+10,16.0-3-gcfd6c53+37,16.0-4-g03cf288+28,16.0-4-g13a27c5+14,16.0-4-g5f3a788+13,16.0-4-g8a0f11a+34,16.0-4-ga3eb747+3,16.0-45-g4805a823c,16.0-5-g1991253+12,16.0-5-g1e9226d+1,16.0-5-g865efd9+12,16.0-5-gb3f8a4b+44,16.0-5-gd0f1235+6,16.0-6-gf0acd13+31,16.0-6-gf9cb114+13,16.0-7-g6043bfc,16.0-7-ga8e1655+8,16.0-8-g23bbf3f+3,16.0-8-g4dec96c+25,16.0-8-gfd407c0+2,master-g965b868a3d+1,master-gdc6be1965f+1,w.2018.39
LSSTDataManagementBasePackage
Box.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 
25 #include "lsst/geom/Box.h"
26 
27 namespace lsst {
28 namespace geom {
29 
30 Box2I::Box2I(Point2I const& minimum, Point2I const& maximum, bool invert)
31  : _minimum(minimum), _dimensions(maximum - minimum) {
32  for (int n = 0; n < 2; ++n) {
33  if (_dimensions[n] < 0) {
34  if (invert) {
35  _minimum[n] += _dimensions[n];
36  _dimensions[n] = -_dimensions[n];
37  } else {
38  *this = Box2I();
39  return;
40  }
41  }
42  }
43  _dimensions += Extent2I(1);
44 }
45 
46 Box2I::Box2I(Point2I const& corner, Extent2I const& dimensions, bool invert)
47  : _minimum(corner), _dimensions(dimensions) {
48  for (int n = 0; n < 2; ++n) {
49  if (_dimensions[n] == 0) {
50  *this = Box2I();
51  return;
52  } else if (_dimensions[n] < 0) {
53  if (invert) {
54  _minimum[n] += (_dimensions[n] + 1);
55  _dimensions[n] = -_dimensions[n];
56  } else {
57  *this = Box2I();
58  return;
59  }
60  }
61  }
62  if (!isEmpty() && any(getMin().gt(getMax()))) {
64  "Box dimensions too large; integer overflow detected.");
65  }
66 }
67 
68 Box2I::Box2I(Box2D const& other, EdgeHandlingEnum edgeHandling) : _minimum(), _dimensions() {
69  if (other.isEmpty()) {
70  *this = Box2I();
71  return;
72  }
73  if (!std::isfinite(other.getMinX()) || !std::isfinite(other.getMinY()) ||
74  !std::isfinite(other.getMaxX()) || !std::isfinite(other.getMaxY())) {
75  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Cannot convert non-finite Box2D to Box2I");
76  }
77  Point2D fpMin(other.getMin() + Extent2D(0.5));
78  Point2D fpMax(other.getMax() - Extent2D(0.5));
79  switch (edgeHandling) {
80  case EXPAND:
81  for (int n = 0; n < 2; ++n) {
82  _minimum[n] = static_cast<int>(std::floor(fpMin[n]));
83  _dimensions[n] = static_cast<int>(std::ceil(fpMax[n])) + 1 - _minimum[n];
84  }
85  break;
86  case SHRINK:
87  for (int n = 0; n < 2; ++n) {
88  _minimum[n] = static_cast<int>(std::ceil(fpMin[n]));
89  _dimensions[n] = static_cast<int>(std::floor(fpMax[n])) + 1 - _minimum[n];
90  }
91  break;
92  }
93 }
94 
95 Box2I Box2I::makeCenteredBox(Point2D const& center, Box2I::Extent const& size) {
96  if (!std::isfinite(center[0]) || !std::isfinite(center[1])) {
97  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Cannot make Box2I with non-finite center");
98  }
99 
100  lsst::geom::Point2D corner(center);
101  corner.shift(-0.5 * lsst::geom::Extent2D(size));
102  // compensate for Box2I's coordinate conventions (where max = min + size - 1)
103  corner.shift(lsst::geom::Extent2D(0.5, 0.5));
104  return lsst::geom::Box2I(lsst::geom::Point2I(corner), size, false);
105 }
106 
107 ndarray::View<boost::fusion::vector2<ndarray::index::Range, ndarray::index::Range> > Box2I::getSlices()
108  const {
109  return ndarray::view(getBeginY(), getEndY())(getBeginX(), getEndX());
110 }
111 
112 bool Box2I::contains(Point2I const& point) const noexcept {
113  return all(point.ge(this->getMin())) && all(point.le(this->getMax()));
114 }
115 
116 bool Box2I::contains(Box2I const& other) const noexcept {
117  return other.isEmpty() ||
118  (all(other.getMin().ge(this->getMin())) && all(other.getMax().le(this->getMax())));
119 }
120 
121 bool Box2I::overlaps(Box2I const& other) const noexcept {
122  return !(other.isEmpty() || this->isEmpty() || any(other.getMax().lt(this->getMin())) ||
123  any(other.getMin().gt(this->getMax())));
124 }
125 
126 void Box2I::grow(Extent2I const& buffer) {
127  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
128  _minimum -= buffer;
129  _dimensions += buffer * 2;
130  if (any(_dimensions.le(0))) *this = Box2I();
131 }
132 
133 void Box2I::shift(Extent2I const& offset) {
134  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
135  _minimum += offset;
136 }
137 
138 void Box2I::flipLR(int xextent) {
139  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
140  // Apply flip about y-axis assumine parent coordinate system
141  _minimum[0] = xextent - (_minimum[0] + _dimensions[0]);
142  // _dimensions should remain unchanged
143 }
144 
145 void Box2I::flipTB(int yextent) {
146  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
147  // Apply flip about y-axis assumine parent coordinate system
148  _minimum[1] = yextent - (_minimum[1] + _dimensions[1]);
149  // _dimensions should remain unchanged
150 }
151 
152 void Box2I::include(Point2I const& point) {
153  if (isEmpty()) {
154  _minimum = point;
155  _dimensions = Extent2I(1);
156  return;
157  }
158  Point2I maximum(getMax());
159  for (int n = 0; n < 2; ++n) {
160  if (point[n] < _minimum[n]) {
161  _minimum[n] = point[n];
162  } else if (point[n] > maximum[n]) {
163  maximum[n] = point[n];
164  }
165  }
166  _dimensions = Extent2I(1) + maximum - _minimum;
167 }
168 
169 void Box2I::include(Box2I const& other) {
170  if (other.isEmpty()) return;
171  if (this->isEmpty()) {
172  *this = other;
173  return;
174  }
175  Point2I maximum(getMax());
176  Point2I const& otherMin = other.getMin();
177  Point2I const otherMax = other.getMax();
178  for (int n = 0; n < 2; ++n) {
179  if (otherMin[n] < _minimum[n]) {
180  _minimum[n] = otherMin[n];
181  }
182  if (otherMax[n] > maximum[n]) {
183  maximum[n] = otherMax[n];
184  }
185  }
186  _dimensions = Extent2I(1) + maximum - _minimum;
187 }
188 
189 void Box2I::clip(Box2I const& other) noexcept {
190  if (isEmpty()) return;
191  if (other.isEmpty()) {
192  *this = Box2I();
193  return;
194  }
195  Point2I maximum(getMax());
196  Point2I const& otherMin = other.getMin();
197  Point2I const otherMax = other.getMax();
198  for (int n = 0; n < 2; ++n) {
199  if (otherMin[n] > _minimum[n]) {
200  _minimum[n] = otherMin[n];
201  }
202  if (otherMax[n] < maximum[n]) {
203  maximum[n] = otherMax[n];
204  }
205  }
206  if (any(maximum.lt(_minimum))) {
207  *this = Box2I();
208  return;
209  }
210  _dimensions = Extent2I(1) + maximum - _minimum;
211 }
212 
213 bool Box2I::operator==(Box2I const& other) const noexcept {
214  return other._minimum == this->_minimum && other._dimensions == this->_dimensions;
215 }
216 
217 bool Box2I::operator!=(Box2I const& other) const noexcept {
218  return other._minimum != this->_minimum || other._dimensions != this->_dimensions;
219 }
220 
222  std::vector<Point2I> retVec;
223  retVec.push_back(getMin());
224  retVec.push_back(Point2I(getMaxX(), getMinY()));
225  retVec.push_back(getMax());
226  retVec.push_back(Point2I(getMinX(), getMaxY()));
227  return retVec;
228 }
229 
231 
233 
234 Box2D::Box2D() noexcept : _minimum(INVALID), _maximum(INVALID) {}
235 
236 Box2D::Box2D(Point2D const& minimum, Point2D const& maximum, bool invert) noexcept
237  : _minimum(minimum), _maximum(maximum) {
238  for (int n = 0; n < 2; ++n) {
239  if (_minimum[n] == _maximum[n]) {
240  *this = Box2D();
241  return;
242  } else if (_minimum[n] > _maximum[n]) {
243  if (invert) {
244  std::swap(_minimum[n], _maximum[n]);
245  } else {
246  *this = Box2D();
247  return;
248  }
249  }
250  }
251 }
252 
253 Box2D::Box2D(Point2D const& corner, Extent2D const& dimensions, bool invert) noexcept
254  : _minimum(corner), _maximum(corner + dimensions) {
255  for (int n = 0; n < 2; ++n) {
256  if (_minimum[n] == _maximum[n]) {
257  *this = Box2D();
258  return;
259  } else if (_minimum[n] > _maximum[n]) {
260  if (invert) {
261  std::swap(_minimum[n], _maximum[n]);
262  } else {
263  *this = Box2D();
264  return;
265  }
266  }
267  }
268 }
269 
270 Box2D::Box2D(Box2I const& other) noexcept
271  : _minimum(Point2D(other.getMin()) - Extent2D(0.5)),
272  _maximum(Point2D(other.getMax()) + Extent2D(0.5)) {
273  if (other.isEmpty()) *this = Box2D();
274 }
275 
276 Box2D Box2D::makeCenteredBox(Point2D const& center, Box2D::Extent const& size) noexcept {
277  lsst::geom::Point2D corner(center);
278  corner.shift(-0.5 * size);
279  return lsst::geom::Box2D(corner, size, false);
280 }
281 
282 bool Box2D::contains(Point2D const& point) const noexcept {
283  return all(point.ge(this->getMin())) && all(point.lt(this->getMax()));
284 }
285 
286 bool Box2D::contains(Box2D const& other) const noexcept {
287  return other.isEmpty() ||
288  (all(other.getMin().ge(this->getMin())) && all(other.getMax().le(this->getMax())));
289 }
290 
291 bool Box2D::overlaps(Box2D const& other) const noexcept {
292  return !(other.isEmpty() || this->isEmpty() || any(other.getMax().le(this->getMin())) ||
293  any(other.getMin().ge(this->getMax())));
294 }
295 
296 void Box2D::grow(Extent2D const& buffer) {
297  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
298  _minimum -= buffer;
299  _maximum += buffer;
300  if (any(_minimum.ge(_maximum))) *this = Box2D();
301 }
302 
303 void Box2D::shift(Extent2D const& offset) {
304  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
305  _minimum += offset;
306  _maximum += offset;
307 }
308 
309 void Box2D::flipLR(float xextent) {
310  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
311  // Swap min and max values for x dimension
312  _minimum[0] += _maximum[0];
313  _maximum[0] = _minimum[0] - _maximum[0];
314  _minimum[0] -= _maximum[0];
315  // Apply flip assuming coordinate system of parent.
316  _minimum[0] = xextent - _minimum[0];
317  _maximum[0] = xextent - _maximum[0];
318  // _dimensions should remain unchanged
319 }
320 
321 void Box2D::flipTB(float yextent) {
322  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
323  // Swap min and max values for y dimension
324  _minimum[1] += _maximum[1];
325  _maximum[1] = _minimum[1] - _maximum[1];
326  _minimum[1] -= _maximum[1];
327  // Apply flip assuming coordinate system of parent.
328  _minimum[1] = yextent - _minimum[1];
329  _maximum[1] = yextent - _maximum[1];
330  // _dimensions should remain unchanged
331 }
332 
333 void Box2D::include(Point2D const& point) noexcept {
334  if (isEmpty()) {
335  _minimum = point;
336  _maximum = point;
337  _tweakMax(0);
338  _tweakMax(1);
339  return;
340  }
341  for (int n = 0; n < 2; ++n) {
342  if (point[n] < _minimum[n]) {
343  _minimum[n] = point[n];
344  } else if (point[n] >= _maximum[n]) {
345  _maximum[n] = point[n];
346  _tweakMax(n);
347  }
348  }
349 }
350 
351 void Box2D::include(Box2D const& other) noexcept {
352  if (other.isEmpty()) return;
353  if (this->isEmpty()) {
354  *this = other;
355  return;
356  }
357  Point2D const& otherMin = other.getMin();
358  Point2D const& otherMax = other.getMax();
359  for (int n = 0; n < 2; ++n) {
360  if (otherMin[n] < _minimum[n]) {
361  _minimum[n] = otherMin[n];
362  }
363  if (otherMax[n] > _maximum[n]) {
364  _maximum[n] = otherMax[n];
365  }
366  }
367 }
368 
369 void Box2D::clip(Box2D const& other) noexcept {
370  if (isEmpty()) return;
371  if (other.isEmpty()) {
372  *this = Box2D();
373  return;
374  }
375  Point2D const& otherMin = other.getMin();
376  Point2D const& otherMax = other.getMax();
377  for (int n = 0; n < 2; ++n) {
378  if (otherMin[n] > _minimum[n]) {
379  _minimum[n] = otherMin[n];
380  }
381  if (otherMax[n] < _maximum[n]) {
382  _maximum[n] = otherMax[n];
383  }
384  }
385  if (any(_maximum.le(_minimum))) {
386  *this = Box2D();
387  return;
388  }
389 }
390 
391 bool Box2D::operator==(Box2D const& other) const noexcept {
392  return (other.isEmpty() && this->isEmpty()) ||
393  (other._minimum == this->_minimum && other._maximum == this->_maximum);
394 }
395 
396 bool Box2D::operator!=(Box2D const& other) const noexcept {
397  return !(other.isEmpty() && other.isEmpty()) &&
398  (other._minimum != this->_minimum || other._maximum != this->_maximum);
399 }
400 
402  std::vector<Point2D> retVec;
403  retVec.push_back(getMin());
404  retVec.push_back(Point2D(getMaxX(), getMinY()));
405  retVec.push_back(getMax());
406  retVec.push_back(Point2D(getMinX(), getMaxY()));
407  return retVec;
408 }
409 
411  if (box.isEmpty()) return os << "Box2I()";
412  return os << "Box2I(Point2I" << box.getMin() << ", Extent2I" << box.getDimensions() << ")";
413 }
414 
416  if (box.isEmpty()) return os << "Box2D()";
417  return os << "Box2D(Point2D" << box.getMin() << ", Extent2D" << box.getDimensions() << ")";
418 }
419 
420 } // namespace geom
421 } // namespace lsst
bool operator==(Box2I const &other) const noexcept
Compare two boxes for equality.
Definition: Box.cc:213
double getMinY() const noexcept
Definition: Box.h:381
std::vector< Point2D > getCorners() const
Get the corner points.
Definition: Box.cc:401
Extent2I const getDimensions() const noexcept
Definition: Box.h:173
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:49
Point2I const getMax() const noexcept
Definition: Box.h:147
void flipLR(int xExtent)
Flip a bounding box about the y-axis given a parent box of extent (xExtent).
Definition: Box.cc:138
void shift(Extent< T, N > const &offset) noexcept(Super::IS_ELEMENT_NOTHROW_COPYABLE)
Shift the point by the given offset.
Definition: Point.h:132
T ceil(T... args)
A floating-point coordinate rectangle geometry.
Definition: Box.h:291
T swap(T... args)
double getMinX() const noexcept
Definition: Box.h:380
T epsilon(T... args)
A coordinate class intended to represent absolute positions.
CoordinateExpr< N > le(Extent< T, N > const &other) const noexcept
Definition: Extent.cc:67
void include(Point2D const &point) noexcept
Expand this to ensure that this->contains(point).
Definition: Box.cc:333
bool isEmpty() const noexcept
Return true if the box contains no points.
Definition: Box.h:183
double getMaxX() const noexcept
Definition: Box.h:384
Extent2D const getDimensions() const noexcept
Definition: Box.h:394
T floor(T... args)
Relationship invert(Relationship r)
Given the relationship between two sets A and B (i.e.
Definition: Relationship.h:55
Point2D const getMin() const noexcept
Definition: Box.h:379
void shift(Extent2D const &offset)
Shift the position of the box by the given offset.
Definition: Box.cc:303
std::vector< Point2I > getCorners() const
Get the corner points.
Definition: Box.cc:221
int getEndY() const noexcept
Definition: Box.h:164
void clip(Box2D const &other) noexcept
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:369
Point< double, 2 > Point2D
Definition: Point.h:324
static double const EPSILON
Value the maximum coordinate is multiplied by to increase it by the smallest possible amount...
Definition: Box.h:301
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
int getBeginY() const noexcept
Definition: Box.h:160
void flipLR(float xExtent)
Flip a bounding box about the y-axis given a parent box of extent (xExtent).
Definition: Box.cc:309
Point2I const getMin() const noexcept
Definition: Box.h:143
bool isEmpty() const noexcept
Return true if the box contains no points.
Definition: Box.h:417
T push_back(T... args)
bool all(CoordinateExpr< N > const &expr) noexcept
Return true if all elements are true.
double getMaxY() const noexcept
Definition: Box.h:385
A base class for image defects.
Definition: cameraGeom.dox:3
Reports when the result of an arithmetic operation is too large for the destination type...
Definition: Runtime.h:124
CoordinateExpr< N > ge(Point< T, N > const &other) const noexcept
Definition: Point.cc:111
void grow(int buffer)
Increase the size of the box by the given buffer amount in all directions.
Definition: Box.h:208
int getMaxY() const noexcept
Definition: Box.h:149
bool contains(Point2D const &point) const noexcept
Return true if the box contains the point.
Definition: Box.cc:282
static double const INVALID
Value used to specify undefined coordinate values.
Definition: Box.h:304
void grow(double buffer)
Increase the size of the box by the given buffer amount in all directions.
Definition: Box.h:442
int getBeginX() const noexcept
Definition: Box.h:159
static Box2D makeCenteredBox(Point2D const &center, Extent const &size) noexcept
Create a box centered on a particular point.
Definition: Box.cc:276
T isfinite(T... args)
std::ostream & operator<<(std::ostream &os, lsst::geom::AffineTransform const &transform)
A coordinate class intended to represent offsets and dimensions.
Point< int, 2 > Point2I
Definition: Point.h:321
int getMaxX() const noexcept
Definition: Box.h:148
Point2D const getMax() const noexcept
Definition: Box.h:383
bool operator!=(Box2I const &other) const noexcept
Compare two boxes for equality.
Definition: Box.cc:217
int getMinX() const noexcept
Definition: Box.h:144
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
Extent< int, 2 > Extent2I
Definition: Extent.h:393
STL class.
CoordinateExpr< N > lt(Point< T, N > const &other) const noexcept
Definition: Point.cc:90
void flipTB(float yExtent)
Flip a bounding box about the x-axis given a parent box of extent (yExtent).
Definition: Box.cc:321
int getEndX() const noexcept
Definition: Box.h:163
void include(Point2I const &point)
Expand this to ensure that this->contains(point).
Definition: Box.cc:152
bool overlaps(Box2D const &other) const noexcept
Return true if any points in other are also in this.
Definition: Box.cc:291
void shift(Extent2I const &offset)
Shift the position of the box by the given offset.
Definition: Box.cc:133
bool overlaps(Box2I const &other) const noexcept
Return true if any points in other are also in this.
Definition: Box.cc:121
bool contains(Point2I const &point) const noexcept
Return true if the box contains the point.
Definition: Box.cc:112
void clip(Box2I const &other) noexcept
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:189
ndarray::View< boost::fusion::vector2< ndarray::index::Range, ndarray::index::Range > > getSlices() const
Return slices to extract the box&#39;s region from an ndarray::Array.
Definition: Box.cc:107
Reports invalid arguments.
Definition: Runtime.h:66
ItemVariant const * other
Definition: Schema.cc:55
static Box2I makeCenteredBox(Point2D const &center, Extent const &size)
Create a box centered as closely as possible on a particular point.
Definition: Box.cc:95
Box2I() noexcept
Construct an empty box.
Definition: Box.h:63
T quiet_NaN(T... args)
Box2D() noexcept
Construct an empty box.
Definition: Box.cc:234
bool operator==(Box2D const &other) const noexcept
Compare two boxes for equality.
Definition: Box.cc:391
Extent< double, 2 > Extent2D
Definition: Extent.h:396
An integer coordinate rectangle.
Definition: Box.h:54
STL class.
int getMinY() const noexcept
Definition: Box.h:145
std::ostream * os
Definition: Schema.cc:737
void flipTB(int yExtent)
Flip a bounding box about the x-axis given a parent box of extent (yExtent).
Definition: Box.cc:145
bool operator!=(Box2D const &other) const noexcept
Compare two boxes for equality.
Definition: Box.cc:396