LSSTApplications  12.1-5-gbdcc3ab+2,15.0+14,15.0+30,15.0-1-g19261fa+21,15.0-1-g417ea41,15.0-1-g60afb23+30,15.0-1-g615e0bb+22,15.0-1-g788a293+30,15.0-1-ga91101e+30,15.0-1-gae1598d+13,15.0-1-gd076f1f+28,15.0-1-gdf18595+5,15.0-12-g3681e7a+8,15.0-12-g7952b551+2,15.0-16-g6f0eb036+3,15.0-17-g076ea75+3,15.0-2-g100d730+23,15.0-2-g8aea5f4+1,15.0-2-gf38729e+25,15.0-2-gf60f3cf,15.0-3-g707930d+3,15.0-3-g9103c06+12,15.0-30-g9378914ca+1,15.0-4-g9ee0f43+3,15.0-4-gf6f1c6c+3,15.0-4-gf906033+2,15.0-5-g23e394c+18,15.0-5-g4be42a9+4,15.0-5-gae1eaf0+3,15.0-6-g09241ba+6,15.0-6-g69628aa+4,15.0-6-g81517ef+3,15.0-6-gc1213af+3,15.0-6-gfa9b38f+8,15.0-7-ged79c87+3,15.0-8-g13fca11+3,15.0-8-g67a62d3+5,15.0-8-gcf05001+5,15.0-9-g1e7c341+2,w.2018.25
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 
47  : _minimum(minimum), _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 ndarray::View<boost::fusion::vector2<ndarray::index::Range, ndarray::index::Range> > Box2I::getSlices()
96  const {
97  return ndarray::view(getBeginY(), getEndY())(getBeginX(), getEndX());
98 }
99 
100 bool Box2I::contains(Point2I const& point) const {
101  return all(point.ge(this->getMin())) && all(point.le(this->getMax()));
102 }
103 
104 bool Box2I::contains(Box2I const& other) const {
105  return other.isEmpty() ||
106  (all(other.getMin().ge(this->getMin())) && all(other.getMax().le(this->getMax())));
107 }
108 
109 bool Box2I::overlaps(Box2I const& other) const {
110  return !(other.isEmpty() || this->isEmpty() || any(other.getMax().lt(this->getMin())) ||
111  any(other.getMin().gt(this->getMax())));
112 }
113 
114 void Box2I::grow(Extent2I const& buffer) {
115  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
116  _minimum -= buffer;
117  _dimensions += buffer * 2;
118  if (any(_dimensions.le(0))) *this = Box2I();
119 }
120 
121 void Box2I::shift(Extent2I const& offset) {
122  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
123  _minimum += offset;
124 }
125 
126 void Box2I::flipLR(int xextent) {
127  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
128  // Apply flip about y-axis assumine parent coordinate system
129  _minimum[0] = xextent - (_minimum[0] + _dimensions[0]);
130  // _dimensions should remain unchanged
131 }
132 
133 void Box2I::flipTB(int yextent) {
134  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
135  // Apply flip about y-axis assumine parent coordinate system
136  _minimum[1] = yextent - (_minimum[1] + _dimensions[1]);
137  // _dimensions should remain unchanged
138 }
139 
140 void Box2I::include(Point2I const& point) {
141  if (isEmpty()) {
142  _minimum = point;
143  _dimensions = Extent2I(1);
144  return;
145  }
146  Point2I maximum(getMax());
147  for (int n = 0; n < 2; ++n) {
148  if (point[n] < _minimum[n]) {
149  _minimum[n] = point[n];
150  } else if (point[n] > maximum[n]) {
151  maximum[n] = point[n];
152  }
153  }
154  _dimensions = Extent2I(1) + maximum - _minimum;
155 }
156 
157 void Box2I::include(Box2I const& other) {
158  if (other.isEmpty()) return;
159  if (this->isEmpty()) {
160  *this = other;
161  return;
162  }
163  Point2I maximum(getMax());
164  Point2I const& otherMin = other.getMin();
165  Point2I const otherMax = other.getMax();
166  for (int n = 0; n < 2; ++n) {
167  if (otherMin[n] < _minimum[n]) {
168  _minimum[n] = otherMin[n];
169  }
170  if (otherMax[n] > maximum[n]) {
171  maximum[n] = otherMax[n];
172  }
173  }
174  _dimensions = Extent2I(1) + maximum - _minimum;
175 }
176 
177 void Box2I::clip(Box2I const& other) {
178  if (isEmpty()) return;
179  if (other.isEmpty()) {
180  *this = Box2I();
181  return;
182  }
183  Point2I maximum(getMax());
184  Point2I const& otherMin = other.getMin();
185  Point2I const otherMax = other.getMax();
186  for (int n = 0; n < 2; ++n) {
187  if (otherMin[n] > _minimum[n]) {
188  _minimum[n] = otherMin[n];
189  }
190  if (otherMax[n] < maximum[n]) {
191  maximum[n] = otherMax[n];
192  }
193  }
194  if (any(maximum.lt(_minimum))) {
195  *this = Box2I();
196  return;
197  }
198  _dimensions = Extent2I(1) + maximum - _minimum;
199 }
200 
201 bool Box2I::operator==(Box2I const& other) const {
202  return other._minimum == this->_minimum && other._dimensions == this->_dimensions;
203 }
204 
205 bool Box2I::operator!=(Box2I const& other) const {
206  return other._minimum != this->_minimum || other._dimensions != this->_dimensions;
207 }
208 
210  std::vector<Point2I> retVec;
211  retVec.push_back(getMin());
212  retVec.push_back(Point2I(getMaxX(), getMinY()));
213  retVec.push_back(getMax());
214  retVec.push_back(Point2I(getMinX(), getMaxY()));
215  return retVec;
216 }
217 
219 
221 
222 Box2D::Box2D() : _minimum(INVALID), _maximum(INVALID) {}
223 
224 Box2D::Box2D(Point2D const& minimum, Point2D const& maximum, bool invert)
225  : _minimum(minimum), _maximum(maximum) {
226  for (int n = 0; n < 2; ++n) {
227  if (_minimum[n] == _maximum[n]) {
228  *this = Box2D();
229  return;
230  } else if (_minimum[n] > _maximum[n]) {
231  if (invert) {
232  std::swap(_minimum[n], _maximum[n]);
233  } else {
234  *this = Box2D();
235  return;
236  }
237  }
238  }
239 }
240 
242  : _minimum(minimum), _maximum(minimum + dimensions) {
243  for (int n = 0; n < 2; ++n) {
244  if (_minimum[n] == _maximum[n]) {
245  *this = Box2D();
246  return;
247  } else if (_minimum[n] > _maximum[n]) {
248  if (invert) {
249  std::swap(_minimum[n], _maximum[n]);
250  } else {
251  *this = Box2D();
252  return;
253  }
254  }
255  }
256 }
257 
259  : _minimum(Point2D(other.getMin()) - Extent2D(0.5)),
260  _maximum(Point2D(other.getMax()) + Extent2D(0.5)) {
261  if (other.isEmpty()) *this = Box2D();
262 }
263 
264 bool Box2D::contains(Point2D const& point) const {
265  return all(point.ge(this->getMin())) && all(point.lt(this->getMax()));
266 }
267 
268 bool Box2D::contains(Box2D const& other) const {
269  return other.isEmpty() ||
270  (all(other.getMin().ge(this->getMin())) && all(other.getMax().le(this->getMax())));
271 }
272 
273 bool Box2D::overlaps(Box2D const& other) const {
274  return !(other.isEmpty() || this->isEmpty() || any(other.getMax().le(this->getMin())) ||
275  any(other.getMin().ge(this->getMax())));
276 }
277 
278 void Box2D::grow(Extent2D const& buffer) {
279  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
280  _minimum -= buffer;
281  _maximum += buffer;
282  if (any(_minimum.ge(_maximum))) *this = Box2D();
283 }
284 
285 void Box2D::shift(Extent2D const& offset) {
286  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
287  _minimum += offset;
288  _maximum += offset;
289 }
290 
291 void Box2D::flipLR(float xextent) {
292  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
293  // Swap min and max values for x dimension
294  _minimum[0] += _maximum[0];
295  _maximum[0] = _minimum[0] - _maximum[0];
296  _minimum[0] -= _maximum[0];
297  // Apply flip assuming coordinate system of parent.
298  _minimum[0] = xextent - _minimum[0];
299  _maximum[0] = xextent - _maximum[0];
300  // _dimensions should remain unchanged
301 }
302 
303 void Box2D::flipTB(float yextent) {
304  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
305  // Swap min and max values for y dimension
306  _minimum[1] += _maximum[1];
307  _maximum[1] = _minimum[1] - _maximum[1];
308  _minimum[1] -= _maximum[1];
309  // Apply flip assuming coordinate system of parent.
310  _minimum[1] = yextent - _minimum[1];
311  _maximum[1] = yextent - _maximum[1];
312  // _dimensions should remain unchanged
313 }
314 
315 void Box2D::include(Point2D const& point) {
316  if (isEmpty()) {
317  _minimum = point;
318  _maximum = point;
319  _tweakMax(0);
320  _tweakMax(1);
321  return;
322  }
323  for (int n = 0; n < 2; ++n) {
324  if (point[n] < _minimum[n]) {
325  _minimum[n] = point[n];
326  } else if (point[n] >= _maximum[n]) {
327  _maximum[n] = point[n];
328  _tweakMax(n);
329  }
330  }
331 }
332 
333 void Box2D::include(Box2D const& other) {
334  if (other.isEmpty()) return;
335  if (this->isEmpty()) {
336  *this = other;
337  return;
338  }
339  Point2D const& otherMin = other.getMin();
340  Point2D const& otherMax = other.getMax();
341  for (int n = 0; n < 2; ++n) {
342  if (otherMin[n] < _minimum[n]) {
343  _minimum[n] = otherMin[n];
344  }
345  if (otherMax[n] > _maximum[n]) {
346  _maximum[n] = otherMax[n];
347  }
348  }
349 }
350 
351 void Box2D::clip(Box2D const& other) {
352  if (isEmpty()) return;
353  if (other.isEmpty()) {
354  *this = Box2D();
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  if (any(_maximum.le(_minimum))) {
368  *this = Box2D();
369  return;
370  }
371 }
372 
373 bool Box2D::operator==(Box2D const& other) const {
374  return (other.isEmpty() && this->isEmpty()) ||
375  (other._minimum == this->_minimum && other._maximum == this->_maximum);
376 }
377 
378 bool Box2D::operator!=(Box2D const& other) const {
379  return !(other.isEmpty() && other.isEmpty()) &&
380  (other._minimum != this->_minimum || other._maximum != this->_maximum);
381 }
382 
384  std::vector<Point2D> retVec;
385  retVec.push_back(getMin());
386  retVec.push_back(Point2D(getMaxX(), getMinY()));
387  retVec.push_back(getMax());
388  retVec.push_back(Point2D(getMinX(), getMaxY()));
389  return retVec;
390 }
391 
393  if (box.isEmpty()) return os << "Box2I()";
394  return os << "Box2I(Point2I" << box.getMin() << ", Extent2I" << box.getDimensions() << ")";
395 }
396 
398  if (box.isEmpty()) return os << "Box2D()";
399  return os << "Box2D(Point2D" << box.getMin() << ", Extent2D" << box.getDimensions() << ")";
400 }
401 
402 } // namespace geom
403 } // namespace lsst
std::vector< Point2D > getCorners() const
Get the corner points.
Definition: Box.cc:383
Box2I()
Construct an empty box.
Definition: Box.h:63
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:44
Extent2I const getDimensions() const
Definition: Box.h:152
int getEndY() const
Definition: Box.h:143
void flipLR(int xExtent)
Flip a bounding box about the y-axis given a parent box of extent (xExtent).
Definition: Box.cc:126
int getMaxY() const
Definition: Box.h:128
CoordinateExpr< N > gt(Point< T, N > const &other) const
Definition: Point.cc:104
bool isEmpty() const
Return true if the box contains no points.
Definition: Box.h:162
void clip(Box2D const &other)
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:351
T ceil(T... args)
A floating-point coordinate rectangle geometry.
Definition: Box.h:265
Point2I const getMin() const
Definition: Box.h:122
T swap(T... args)
T epsilon(T... args)
A coordinate class intended to represent absolute positions.
Box2D()
Construct an empty box.
Definition: Box.cc:222
Extent2D const getDimensions() const
Definition: Box.h:352
Point2D const getMin() const
Definition: Box.h:337
bool operator!=(Box2D const &other) const
Compare two boxes for equality.
Definition: Box.cc:378
double getMinX() const
Definition: Box.h:338
T floor(T... args)
Relationship invert(Relationship r)
Given the relationship between two sets A and B (i.e.
Definition: Relationship.h:55
bool overlaps(Box2D const &other) const
Return true if any points in other are also in this.
Definition: Box.cc:273
void shift(Extent2D const &offset)
Shift the position of the box by the given offset.
Definition: Box.cc:285
std::vector< Point2I > getCorners() const
Get the corner points.
Definition: Box.cc:209
Point2I const getMax() const
Definition: Box.h:126
int getEndX() const
Definition: Box.h:142
Point< double, 2 > Point2D
Definition: Point.h:300
static double const EPSILON
Value the maximum coordinate is multiplied by to increase it by the smallest possible amount...
Definition: Box.h:275
bool contains(Point2D const &point) const
Return true if the box contains the point.
Definition: Box.cc:264
void flipLR(float xExtent)
Flip a bounding box about the y-axis given a parent box of extent (xExtent).
Definition: Box.cc:291
CoordinateExpr< N > le(Extent< T, N > const &other) const
Definition: Extent.cc:64
T push_back(T... args)
bool all(CoordinateExpr< N > const &expr)
Return true if all elements are true.
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
double getMaxX() const
Definition: Box.h:342
void grow(int buffer)
Increase the size of the box by the given buffer amount in all directions.
Definition: Box.h:187
int getMinX() const
Definition: Box.h:123
static double const INVALID
Value used to specify undefined coordinate values.
Definition: Box.h:278
void grow(double buffer)
Increase the size of the box by the given buffer amount in all directions.
Definition: Box.h:398
Point2D const getMax() const
Definition: Box.h:341
int getBeginY() const
Definition: Box.h:139
int getMinY() const
Definition: Box.h:124
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:297
CoordinateExpr< N > ge(Point< T, N > const &other) const
Definition: Point.cc:111
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:47
Extent< int, 2 > Extent2I
Definition: Extent.h:376
STL class.
bool contains(Point2I const &point) const
Return true if the box contains the point.
Definition: Box.cc:100
bool isEmpty() const
Return true if the box contains no points.
Definition: Box.h:373
void flipTB(float yExtent)
Flip a bounding box about the x-axis given a parent box of extent (yExtent).
Definition: Box.cc:303
int getMaxX() const
Definition: Box.h:127
void include(Point2I const &point)
Expand this to ensure that this->contains(point).
Definition: Box.cc:140
bool operator==(Box2D const &other) const
Compare two boxes for equality.
Definition: Box.cc:373
CoordinateExpr< N > le(Point< T, N > const &other) const
Definition: Point.cc:97
void shift(Extent2I const &offset)
Shift the position of the box by the given offset.
Definition: Box.cc:121
bool overlaps(Box2I const &other) const
Return true if any points in other are also in this.
Definition: Box.cc:109
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:95
Reports invalid arguments.
Definition: Runtime.h:66
ItemVariant const * other
Definition: Schema.cc:55
T quiet_NaN(T... args)
Extent< double, 2 > Extent2D
Definition: Extent.h:379
void include(Point2D const &point)
Expand this to ensure that this->contains(point).
Definition: Box.cc:315
bool operator==(Box2I const &other) const
Compare two boxes for equality.
Definition: Box.cc:201
void clip(Box2I const &other)
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:177
bool operator!=(Box2I const &other) const
Compare two boxes for equality.
Definition: Box.cc:205
CoordinateExpr< N > lt(Point< T, N > const &other) const
Definition: Point.cc:90
An integer coordinate rectangle.
Definition: Box.h:54
STL class.
double getMaxY() const
Definition: Box.h:343
std::ostream * os
Definition: Schema.cc:737
double getMinY() const
Definition: Box.h:339
void flipTB(int yExtent)
Flip a bounding box about the x-axis given a parent box of extent (yExtent).
Definition: Box.cc:133
int getBeginX() const
Definition: Box.h:138
bool any(CoordinateExpr< N > const &expr)
Return true if any elements are true.