lsst.geom  16.0-2-ge920381
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  lsst::geom::Point2D corner(center);
97  corner.shift(-0.5 * lsst::geom::Extent2D(size));
98  // compensate for Box2I's coordinate conventions (where max = min + size - 1)
99  corner.shift(lsst::geom::Extent2D(0.5, 0.5));
100  return lsst::geom::Box2I(lsst::geom::Point2I(corner), size, false);
101 }
102 
103 ndarray::View<boost::fusion::vector2<ndarray::index::Range, ndarray::index::Range> > Box2I::getSlices()
104  const {
105  return ndarray::view(getBeginY(), getEndY())(getBeginX(), getEndX());
106 }
107 
108 bool Box2I::contains(Point2I const& point) const {
109  return all(point.ge(this->getMin())) && all(point.le(this->getMax()));
110 }
111 
112 bool Box2I::contains(Box2I const& other) const {
113  return other.isEmpty() ||
114  (all(other.getMin().ge(this->getMin())) && all(other.getMax().le(this->getMax())));
115 }
116 
117 bool Box2I::overlaps(Box2I const& other) const {
118  return !(other.isEmpty() || this->isEmpty() || any(other.getMax().lt(this->getMin())) ||
119  any(other.getMin().gt(this->getMax())));
120 }
121 
122 void Box2I::grow(Extent2I const& buffer) {
123  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
124  _minimum -= buffer;
125  _dimensions += buffer * 2;
126  if (any(_dimensions.le(0))) *this = Box2I();
127 }
128 
129 void Box2I::shift(Extent2I const& offset) {
130  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
131  _minimum += offset;
132 }
133 
134 void Box2I::flipLR(int xextent) {
135  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
136  // Apply flip about y-axis assumine parent coordinate system
137  _minimum[0] = xextent - (_minimum[0] + _dimensions[0]);
138  // _dimensions should remain unchanged
139 }
140 
141 void Box2I::flipTB(int yextent) {
142  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
143  // Apply flip about y-axis assumine parent coordinate system
144  _minimum[1] = yextent - (_minimum[1] + _dimensions[1]);
145  // _dimensions should remain unchanged
146 }
147 
148 void Box2I::include(Point2I const& point) {
149  if (isEmpty()) {
150  _minimum = point;
151  _dimensions = Extent2I(1);
152  return;
153  }
154  Point2I maximum(getMax());
155  for (int n = 0; n < 2; ++n) {
156  if (point[n] < _minimum[n]) {
157  _minimum[n] = point[n];
158  } else if (point[n] > maximum[n]) {
159  maximum[n] = point[n];
160  }
161  }
162  _dimensions = Extent2I(1) + maximum - _minimum;
163 }
164 
165 void Box2I::include(Box2I const& other) {
166  if (other.isEmpty()) return;
167  if (this->isEmpty()) {
168  *this = other;
169  return;
170  }
171  Point2I maximum(getMax());
172  Point2I const& otherMin = other.getMin();
173  Point2I const otherMax = other.getMax();
174  for (int n = 0; n < 2; ++n) {
175  if (otherMin[n] < _minimum[n]) {
176  _minimum[n] = otherMin[n];
177  }
178  if (otherMax[n] > maximum[n]) {
179  maximum[n] = otherMax[n];
180  }
181  }
182  _dimensions = Extent2I(1) + maximum - _minimum;
183 }
184 
185 void Box2I::clip(Box2I const& other) {
186  if (isEmpty()) return;
187  if (other.isEmpty()) {
188  *this = Box2I();
189  return;
190  }
191  Point2I maximum(getMax());
192  Point2I const& otherMin = other.getMin();
193  Point2I const otherMax = other.getMax();
194  for (int n = 0; n < 2; ++n) {
195  if (otherMin[n] > _minimum[n]) {
196  _minimum[n] = otherMin[n];
197  }
198  if (otherMax[n] < maximum[n]) {
199  maximum[n] = otherMax[n];
200  }
201  }
202  if (any(maximum.lt(_minimum))) {
203  *this = Box2I();
204  return;
205  }
206  _dimensions = Extent2I(1) + maximum - _minimum;
207 }
208 
209 bool Box2I::operator==(Box2I const& other) const {
210  return other._minimum == this->_minimum && other._dimensions == this->_dimensions;
211 }
212 
213 bool Box2I::operator!=(Box2I const& other) const {
214  return other._minimum != this->_minimum || other._dimensions != this->_dimensions;
215 }
216 
218  std::vector<Point2I> retVec;
219  retVec.push_back(getMin());
220  retVec.push_back(Point2I(getMaxX(), getMinY()));
221  retVec.push_back(getMax());
222  retVec.push_back(Point2I(getMinX(), getMaxY()));
223  return retVec;
224 }
225 
227 
229 
230 Box2D::Box2D() : _minimum(INVALID), _maximum(INVALID) {}
231 
232 Box2D::Box2D(Point2D const& minimum, Point2D const& maximum, bool invert)
233  : _minimum(minimum), _maximum(maximum) {
234  for (int n = 0; n < 2; ++n) {
235  if (_minimum[n] == _maximum[n]) {
236  *this = Box2D();
237  return;
238  } else if (_minimum[n] > _maximum[n]) {
239  if (invert) {
240  std::swap(_minimum[n], _maximum[n]);
241  } else {
242  *this = Box2D();
243  return;
244  }
245  }
246  }
247 }
248 
249 Box2D::Box2D(Point2D const& corner, Extent2D const& dimensions, bool invert)
250  : _minimum(corner), _maximum(corner + dimensions) {
251  for (int n = 0; n < 2; ++n) {
252  if (_minimum[n] == _maximum[n]) {
253  *this = Box2D();
254  return;
255  } else if (_minimum[n] > _maximum[n]) {
256  if (invert) {
257  std::swap(_minimum[n], _maximum[n]);
258  } else {
259  *this = Box2D();
260  return;
261  }
262  }
263  }
264 }
265 
266 Box2D::Box2D(Box2I const& other)
267  : _minimum(Point2D(other.getMin()) - Extent2D(0.5)),
268  _maximum(Point2D(other.getMax()) + Extent2D(0.5)) {
269  if (other.isEmpty()) *this = Box2D();
270 }
271 
272 Box2D Box2D::makeCenteredBox(Point2D const& center, Box2D::Extent const& size) {
273  lsst::geom::Point2D corner(center);
274  corner.shift(-0.5 * size);
275  return lsst::geom::Box2D(corner, size, false);
276 }
277 
278 bool Box2D::contains(Point2D const& point) const {
279  return all(point.ge(this->getMin())) && all(point.lt(this->getMax()));
280 }
281 
282 bool Box2D::contains(Box2D const& other) const {
283  return other.isEmpty() ||
284  (all(other.getMin().ge(this->getMin())) && all(other.getMax().le(this->getMax())));
285 }
286 
287 bool Box2D::overlaps(Box2D const& other) const {
288  return !(other.isEmpty() || this->isEmpty() || any(other.getMax().le(this->getMin())) ||
289  any(other.getMin().ge(this->getMax())));
290 }
291 
292 void Box2D::grow(Extent2D const& buffer) {
293  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
294  _minimum -= buffer;
295  _maximum += buffer;
296  if (any(_minimum.ge(_maximum))) *this = Box2D();
297 }
298 
299 void Box2D::shift(Extent2D const& offset) {
300  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
301  _minimum += offset;
302  _maximum += offset;
303 }
304 
305 void Box2D::flipLR(float xextent) {
306  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
307  // Swap min and max values for x dimension
308  _minimum[0] += _maximum[0];
309  _maximum[0] = _minimum[0] - _maximum[0];
310  _minimum[0] -= _maximum[0];
311  // Apply flip assuming coordinate system of parent.
312  _minimum[0] = xextent - _minimum[0];
313  _maximum[0] = xextent - _maximum[0];
314  // _dimensions should remain unchanged
315 }
316 
317 void Box2D::flipTB(float yextent) {
318  if (isEmpty()) return; // should we throw an exception here instead of a no-op?
319  // Swap min and max values for y dimension
320  _minimum[1] += _maximum[1];
321  _maximum[1] = _minimum[1] - _maximum[1];
322  _minimum[1] -= _maximum[1];
323  // Apply flip assuming coordinate system of parent.
324  _minimum[1] = yextent - _minimum[1];
325  _maximum[1] = yextent - _maximum[1];
326  // _dimensions should remain unchanged
327 }
328 
329 void Box2D::include(Point2D const& point) {
330  if (isEmpty()) {
331  _minimum = point;
332  _maximum = point;
333  _tweakMax(0);
334  _tweakMax(1);
335  return;
336  }
337  for (int n = 0; n < 2; ++n) {
338  if (point[n] < _minimum[n]) {
339  _minimum[n] = point[n];
340  } else if (point[n] >= _maximum[n]) {
341  _maximum[n] = point[n];
342  _tweakMax(n);
343  }
344  }
345 }
346 
347 void Box2D::include(Box2D const& other) {
348  if (other.isEmpty()) return;
349  if (this->isEmpty()) {
350  *this = other;
351  return;
352  }
353  Point2D const& otherMin = other.getMin();
354  Point2D const& otherMax = other.getMax();
355  for (int n = 0; n < 2; ++n) {
356  if (otherMin[n] < _minimum[n]) {
357  _minimum[n] = otherMin[n];
358  }
359  if (otherMax[n] > _maximum[n]) {
360  _maximum[n] = otherMax[n];
361  }
362  }
363 }
364 
365 void Box2D::clip(Box2D const& other) {
366  if (isEmpty()) return;
367  if (other.isEmpty()) {
368  *this = Box2D();
369  return;
370  }
371  Point2D const& otherMin = other.getMin();
372  Point2D const& otherMax = other.getMax();
373  for (int n = 0; n < 2; ++n) {
374  if (otherMin[n] > _minimum[n]) {
375  _minimum[n] = otherMin[n];
376  }
377  if (otherMax[n] < _maximum[n]) {
378  _maximum[n] = otherMax[n];
379  }
380  }
381  if (any(_maximum.le(_minimum))) {
382  *this = Box2D();
383  return;
384  }
385 }
386 
387 bool Box2D::operator==(Box2D const& other) const {
388  return (other.isEmpty() && this->isEmpty()) ||
389  (other._minimum == this->_minimum && other._maximum == this->_maximum);
390 }
391 
392 bool Box2D::operator!=(Box2D const& other) const {
393  return !(other.isEmpty() && other.isEmpty()) &&
394  (other._minimum != this->_minimum || other._maximum != this->_maximum);
395 }
396 
398  std::vector<Point2D> retVec;
399  retVec.push_back(getMin());
400  retVec.push_back(Point2D(getMaxX(), getMinY()));
401  retVec.push_back(getMax());
402  retVec.push_back(Point2D(getMinX(), getMaxY()));
403  return retVec;
404 }
405 
407  if (box.isEmpty()) return os << "Box2I()";
408  return os << "Box2I(Point2I" << box.getMin() << ", Extent2I" << box.getDimensions() << ")";
409 }
410 
412  if (box.isEmpty()) return os << "Box2D()";
413  return os << "Box2D(Point2D" << box.getMin() << ", Extent2D" << box.getDimensions() << ")";
414 }
415 
416 } // namespace geom
417 } // namespace lsst
std::vector< Point2D > getCorners() const
Get the corner points.
Definition: Box.cc:397
Box2I()
Construct an empty box.
Definition: Box.h:63
Extent2I const getDimensions() const
Definition: Box.h:166
void shift(Extent< T, N > const &offset)
Shift the point by the given offset.
Definition: Point.h:118
int getEndY() const
Definition: Box.h:157
void flipLR(int xExtent)
Flip a bounding box about the y-axis given a parent box of extent (xExtent).
Definition: Box.cc:134
int getMaxY() const
Definition: Box.h:142
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:176
void clip(Box2D const &other)
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:365
T ceil(T... args)
A floating-point coordinate rectangle geometry.
Definition: Box.h:279
Point2I const getMin() const
Definition: Box.h:136
T swap(T... args)
T epsilon(T... args)
A coordinate class intended to represent absolute positions.
Box2D()
Construct an empty box.
Definition: Box.cc:230
Extent2D const getDimensions() const
Definition: Box.h:380
Point2D const getMin() const
Definition: Box.h:365
bool operator!=(Box2D const &other) const
Compare two boxes for equality.
Definition: Box.cc:392
double getMinX() const
Definition: Box.h:366
T floor(T... args)
bool overlaps(Box2D const &other) const
Return true if any points in other are also in this.
Definition: Box.cc:287
void shift(Extent2D const &offset)
Shift the position of the box by the given offset.
Definition: Box.cc:299
std::vector< Point2I > getCorners() const
Get the corner points.
Definition: Box.cc:217
Point2I const getMax() const
Definition: Box.h:140
int getEndX() const
Definition: Box.h:156
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:289
bool contains(Point2D const &point) const
Return true if the box contains the point.
Definition: Box.cc:278
void flipLR(float xExtent)
Flip a bounding box about the y-axis given a parent box of extent (xExtent).
Definition: Box.cc:305
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.
double getMaxX() const
Definition: Box.h:370
void grow(int buffer)
Increase the size of the box by the given buffer amount in all directions.
Definition: Box.h:201
static Box2D makeCenteredBox(Point2D const &center, Extent const &size)
Create a box centered on a particular point.
Definition: Box.cc:272
int getMinX() const
Definition: Box.h:137
static double const INVALID
Value used to specify undefined coordinate values.
Definition: Box.h:292
void grow(double buffer)
Increase the size of the box by the given buffer amount in all directions.
Definition: Box.h:426
Point2D const getMax() const
Definition: Box.h:369
int getBeginY() const
Definition: Box.h:153
int getMinY() const
Definition: Box.h:138
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,...)
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:108
bool isEmpty() const
Return true if the box contains no points.
Definition: Box.h:401
void flipTB(float yExtent)
Flip a bounding box about the x-axis given a parent box of extent (yExtent).
Definition: Box.cc:317
int getMaxX() const
Definition: Box.h:141
void include(Point2I const &point)
Expand this to ensure that this->contains(point).
Definition: Box.cc:148
bool operator==(Box2D const &other) const
Compare two boxes for equality.
Definition: Box.cc:387
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:129
bool overlaps(Box2I const &other) const
Return true if any points in other are also in this.
Definition: Box.cc:117
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:103
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
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:329
bool operator==(Box2I const &other) const
Compare two boxes for equality.
Definition: Box.cc:209
void clip(Box2I const &other)
Shrink this to ensure that other.contains(*this).
Definition: Box.cc:185
bool operator!=(Box2I const &other) const
Compare two boxes for equality.
Definition: Box.cc:213
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:371
double getMinY() const
Definition: Box.h:367
void flipTB(int yExtent)
Flip a bounding box about the x-axis given a parent box of extent (yExtent).
Definition: Box.cc:141
int getBeginX() const
Definition: Box.h:152
bool any(CoordinateExpr< N > const &expr)
Return true if any elements are true.