IMP logo
IMP Reference Guide  2.16.0
The Integrative Modeling Platform
BoundingBoxD.h
Go to the documentation of this file.
1 /**
2  * \file IMP/algebra/BoundingBoxD.h \brief A bounding box in D dimensions.
3  *
4  * Copyright 2007-2021 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPALGEBRA_BOUNDING_BOX_D_H
9 #define IMPALGEBRA_BOUNDING_BOX_D_H
10 
11 #include <IMP/algebra/algebra_config.h>
12 #include "VectorD.h"
13 #include "internal/utility.h"
14 #include "algebra_macros.h"
15 #include <IMP/exception.h>
16 
17 IMPALGEBRA_BEGIN_NAMESPACE
18 
19 //! An axis-aligned bounding box.
20 /** The BoundingBoxD class provides a unified representation for bounding
21  boxes in \imp. Geometric objects should have an associated namespace
22  method like get_bounding_box() which returns the bounding boxes of objects.
23 
24  \note This class is a \ref geometricprimitives "geometric primitive".
25 */
26 template <int D>
27 class BoundingBoxD {
28  void make_empty() {
29  for (int i = 0; i < D; ++i) {
30  b_[0][i] = std::numeric_limits<double>::max();
31  b_[1][i] = -std::numeric_limits<double>::max();
32  }
33  }
34 
35  public:
36  //! Create an empty bounding box
38  /* Let SWIG make uninitialized BoundingBoxKD objects (see issue #843).
39  Otherwise, any function that returns a BoundingBoxKD will fail, since
40  SWIG generates code that looks like:
41  BoundingBoxKD result;
42  ...
43  result = call_imp_function()
44  The usage check for BoundingBoxKD is moved from here to the SWIG wrapper
45  itself, so a user still can't make a default-constructed BoundingBoxKD
46  in Python.
47  */
48 #if defined(IMP_SWIG_WRAPPER)
49  if (D > 0) {
50  make_empty();
51  }
52 #else
53  IMP_USAGE_CHECK(D > 0, "The constructor cannot be used "
54  << "with a variable dimension bounding box.");
55 
56  make_empty();
57 #endif
58  }
59  //! Create an empty bounding box
60  explicit BoundingBoxD(unsigned int d) {
61  IMP_USAGE_CHECK(D == -1, "The constructor can only be used "
62  << "with a variable dimension bounding box.");
63  Floats lb(d), ub(d);
64  for (unsigned int i = 0; i < d; ++i) {
65  lb[i] = std::numeric_limits<double>::max();
66  ub[i] = -std::numeric_limits<double>::max();
67  }
68  b_[0] = VectorD<D>(lb.begin(), lb.end());
69  b_[1] = VectorD<D>(ub.begin(), ub.end());
70  }
71  //! Make from the lower and upper corners
72  BoundingBoxD(const VectorD<D> &lb, const VectorD<D> &ub) {
73  b_[0] = lb;
74  b_[1] = ub;
76  for (unsigned int i = 0; i < lb.get_dimension(); ++i) {
77  IMP_USAGE_CHECK(lb[i] <= ub[i], "Invalid bounding box");
78  }
79  }
80  }
81  //! Creating a bounding box containing one point
82  explicit BoundingBoxD(const VectorD<D> &v) {
83  b_[0] = v;
84  b_[1] = v;
85  }
86 
87  //! Creating a bounding box from a set of points
88  BoundingBoxD(const Vector<VectorD<D> > &points) {
89  make_empty();
90  for (unsigned int j = 0; j < points.size(); j++) {
91  operator+=(points[j]);
92  }
93  }
94 
95  unsigned int get_dimension() const { return get_corner(0).get_dimension(); }
96 
97  //! Extend the current bounding box to include the other
99  for (unsigned int i = 0; i < get_dimension(); ++i) {
100  b_[0][i] = std::min(o.get_corner(0)[i], get_corner(0)[i]);
101  b_[1][i] = std::max(o.get_corner(1)[i], get_corner(1)[i]);
102  }
103  return *this;
104  }
105 
106  //! Extend the current bounding box to include the point
108  for (unsigned int i = 0; i < get_dimension(); ++i) {
109  b_[0][i] = std::min(o[i], b_[0][i]);
110  b_[1][i] = std::max(o[i], b_[1][i]);
111  }
112  return *this;
113  }
114 
115  //! Grow the bounding box by o on all sizes.
116  const BoundingBoxD<D> &operator+=(double o) {
117  for (unsigned int i = 0; i < get_dimension(); ++i) {
118  b_[0][i] = b_[0][i] - o;
119  b_[1][i] = b_[1][i] + o;
120  }
121  return *this;
122  }
123  //! Returning a bounding box containing both
124  template <class O>
125  const BoundingBoxD<D> operator+(const BoundingBoxD<D> &o) const {
126  BoundingBoxD<D> ret(*this);
127  ret += o;
128  return ret;
129  }
130  //! Return a bounding box grown by o on all sides
131  template <class O>
132  const BoundingBoxD<D> operator+(const O &o) const {
133  BoundingBoxD<D> ret(*this);
134  ret += o;
135  return ret;
136  }
137 
138  //! For 0 return lower corner and for 1, the upper corner
139  const VectorD<D> &get_corner(unsigned int i) const {
140  IMP_USAGE_CHECK(i < 2, "Can only use 0 or 1");
141  return b_[i];
142  }
143 
144  //! True if the point o is contained within this bounding box
145  bool get_contains(const VectorD<D> &o) const {
146  for (unsigned int i = 0; i < get_dimension(); ++i) {
147  if (o[i] < get_corner(0)[i] || o[i] > get_corner(1)[i]) return false;
148  }
149  return true;
150  }
151  //! True if the input bounding box is completely contained within this one
152  bool get_contains(const BoundingBoxD &bb) const {
153  return get_contains(bb.get_corner(0)) && get_contains(bb.get_corner(1));
154  }
155 
156  IMP_SHOWABLE_INLINE(BoundingBoxD, out << b_[0] << ": " << b_[1]);
157 
158  private:
159  VectorD<D> b_[2];
160 };
161 //! See BoundingBoxD
162 template <int D>
163 inline double get_volume(const BoundingBoxD<D> &bb) {
164  double v = 1;
165  for (unsigned int i = 0; i < bb.get_dimension(); ++i) {
166  v *= bb.get_corner(1)[i] - bb.get_corner(0)[i];
167  }
168  return v;
169 }
170 
171 IMP_VOLUME_GEOMETRY_METHODS_D(BoundingBox, bounding_box, IMP_UNUSED(g);
173  return (g.get_corner(1)[0] - g.get_corner(0)[0]) *
174  (g.get_corner(1)[1] - g.get_corner(0)[1]) *
175  (g.get_corner(1)[2] - g.get_corner(0)[2]),
176  return g);
177 
178 //! Box with radius one
179 /** \see BoundingBoxD */
180 template <unsigned int D>
182  return BoundingBoxD<D>(-get_ones_vector_d<D>(), get_ones_vector_d<D>());
183 }
184 
185 //! Box with radius one
186 /** \see BoundingBoxD */
187 inline BoundingBoxD<-1> get_unit_bounding_box_kd(unsigned int d) {
189 }
190 
191 //! Cube with radius of length \c radius
192 /** \see BoundingBoxD */
193 template <unsigned int D>
194 inline BoundingBoxD<D> get_cube_d(double radius) {
195  return BoundingBoxD<D>(-radius * get_ones_vector_d<D>(),
196  radius * get_ones_vector_d<D>());
197 }
198 
199 //! Cube with radius of length \c side
200 /** \see BoundingBoxD */
201 inline BoundingBoxD<-1> get_cube_kd(unsigned int d, double radius) {
202  return BoundingBoxD<-1>(-radius * get_ones_vector_kd(d),
203  radius * get_ones_vector_kd(d));
204 }
205 
206 //! Return true if they intersect
207 /** \see BoundingBoxD */
208 template <int D>
210  const BoundingBoxD<D> &b) {
211  IMP_USAGE_CHECK(a.get_dimension() == b.get_dimension(),
212  "Dimensions of bounding boxes don't match.");
213  for (unsigned int i = 0; i < a.get_dimension(); ++i) {
214  if (a.get_corner(0)[i] > b.get_corner(1)[i]) return false;
215  if (b.get_corner(0)[i] > a.get_corner(1)[i]) return false;
216  }
217  return true;
218 }
219 
220 //! Return the intersecting bounding box
221 /** \see BoundingBoxD */
222 template <int D>
224  const BoundingBoxD<D> &b) {
225  /* Make sure that for D=-1 the vectors ic[01] get the correct dimension */
226  VectorD<D> ic0 = a.get_corner(0);
227  VectorD<D> ic1 = a.get_corner(1);
228  // set low
229  int j = 0;
230  for (unsigned int i = 0; i < a.get_dimension(); ++i) {
231  if (a.get_corner(j)[i] > b.get_corner(j)[i]) {
232  ic0[i] = a.get_corner(j)[i];
233  } else {
234  ic0[i] = b.get_corner(j)[i];
235  }
236  }
237  // set top
238  j = 1;
239  for (unsigned int i = 0; i < a.get_dimension(); ++i) {
240  if (a.get_corner(j)[i] < b.get_corner(j)[i]) {
241  ic1[i] = a.get_corner(j)[i];
242  } else {
243  ic1[i] = b.get_corner(j)[i];
244  }
245  }
246  return BoundingBoxD<D>(ic0, ic1);
247 }
248 
249 //! Return the union bounding box
250 /** This is the same as doing a+b.
251  \see BoundingBoxD
252 */
253 template <int D>
255  a += b;
256  return a;
257 }
258 
259 //! Return the maximum axis aligned extent
260 /** \see BoundingBoxD */
261 template <int D>
262 inline double get_maximum_length(const BoundingBoxD<D> &a) {
263  double e = a.get_corner(1)[0] - a.get_corner(0)[0];
264  for (unsigned int i = 1; i < a.get_dimension(); ++i) {
265  double ce = a.get_corner(1)[0] - a.get_corner(0)[0];
266  e = std::max(ce, e);
267  }
268  return e;
269 }
270 
271 //! Return a list of the 2^D bounding points for the bounding box
272 /** \see BoundingBoxD */
273 template <int D>
275  if (D == 1) {
276  Vector<VectorD<D> > ret(2);
277  ret[0] = bb.get_corner(0);
278  ret[1] = bb.get_corner(1);
279  return ret;
280  }
281  if (D == -1) {
283  }
285  for (int i = 0; i < D - 1; ++i) {
286  c0[i] = bb.get_corner(0)[i];
287  c1[i] = bb.get_corner(1)[i];
288  }
291  Vector<VectorD<D> > ret;
292  for (unsigned int i = 0; i < recurse.size(); ++i) {
293  VectorD<D> cur;
294  for (int j = 0; j < D - 1; ++j) {
295  cur[j] = recurse[i][j];
296  }
297  cur[D - 1] = bb.get_corner(0)[D - 1];
298  ret.push_back(cur);
299  cur[D - 1] = bb.get_corner(1)[D - 1];
300  ret.push_back(cur);
301  }
302  return ret;
303 }
304 
305 //! Return the edges of the box as indices into the vertices list
306 /** \see BoundingBoxD */
308  static const IntPair edges[12] = {
309  IntPair(0, 1), IntPair(0, 2), IntPair(0, 4), IntPair(1, 3),
310  IntPair(1, 5), IntPair(2, 3), IntPair(2, 6), IntPair(3, 7),
311  IntPair(4, 5), IntPair(4, 6), IntPair(5, 7), IntPair(6, 7)};
312  static IntPairs ret(edges, edges + 12);
313  return ret;
314 }
315 
316 IMPALGEBRA_END_NAMESPACE
317 
318 #endif /* IMPALGEBRA_BOUNDING_BOX_D_H */
const BoundingBoxD< D > & operator+=(double o)
Grow the bounding box by o on all sizes.
Definition: BoundingBoxD.h:116
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
const VectorD< D > & get_corner(unsigned int i) const
For 0 return lower corner and for 1, the upper corner.
Definition: BoundingBoxD.h:139
#define IMP_IF_CHECK(level)
Execute the code block if a certain level checks are on.
Definition: check_macros.h:104
const BoundingBoxD< D > operator+(const BoundingBoxD< D > &o) const
Returning a bounding box containing both.
Definition: BoundingBoxD.h:125
bool get_contains(const BoundingBoxD &bb) const
True if the input bounding box is completely contained within this one.
Definition: BoundingBoxD.h:152
const BoundingBoxD< D > operator+(const O &o) const
Return a bounding box grown by o on all sides.
Definition: BoundingBoxD.h:132
Vector< VectorD< D > > get_vertices(const BoundingBoxD< D > &bb)
Return a list of the 2^D bounding points for the bounding box.
Definition: BoundingBoxD.h:274
double get_maximum_length(const BoundingBoxD< D > &a)
Return the maximum axis aligned extent.
Definition: BoundingBoxD.h:262
double get_volume(const Cone3D &g)
Definition: Cone3D.h:64
IntPairs get_edges(const BoundingBoxD< 3 > &)
Return the edges of the box as indices into the vertices list.
Definition: BoundingBoxD.h:307
BoundingBoxD< D > get_union(BoundingBoxD< D > a, const BoundingBoxD< D > &b)
Return the union bounding box.
Definition: BoundingBoxD.h:254
BoundingBoxD< D > get_cube_d(double radius)
Cube with radius of length radius.
Definition: BoundingBoxD.h:194
Exception definitions and assertions.
BoundingBoxD(unsigned int d)
Create an empty bounding box.
Definition: BoundingBoxD.h:60
const BoundingBoxD< D > & operator+=(const BoundingBoxD< D > &o)
Extend the current bounding box to include the other.
Definition: BoundingBoxD.h:98
VectorD< D > get_ones_vector_kd(unsigned int Di, double v=1)
Return a vector of ones (or another constant)
Definition: VectorD.h:309
BoundingBoxD< D > get_intersection(const BoundingBoxD< D > &a, const BoundingBoxD< D > &b)
Return the intersecting bounding box.
Definition: BoundingBoxD.h:223
const BoundingBoxD< D > & operator+=(const VectorD< D > &o)
Extend the current bounding box to include the point.
Definition: BoundingBoxD.h:107
bool get_interiors_intersect(const BoundingBoxD< D > &a, const BoundingBoxD< D > &b)
Return true if they intersect.
Definition: BoundingBoxD.h:209
A Cartesian vector in D-dimensions.
Definition: VectorD.h:52
BoundingBoxD()
Create an empty bounding box.
Definition: BoundingBoxD.h:37
#define IMP_UNUSED(variable)
#define IMP_VOLUME_GEOMETRY_METHODS_D(Name, name, area, volume, bounding_box)
Implement the needed namespace methods for a geometry type.
Simple D vector class.
BoundingBoxD<-1 > get_unit_bounding_box_kd(unsigned int d)
Box with radius one.
Definition: BoundingBoxD.h:187
BoundingBoxD<-1 > get_cube_kd(unsigned int d, double radius)
Cube with radius of length side.
Definition: BoundingBoxD.h:201
An axis-aligned bounding box.
Definition: BoundingBoxD.h:27
BoundingBoxD(const Vector< VectorD< D > > &points)
Creating a bounding box from a set of points.
Definition: BoundingBoxD.h:88
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
BoundingBoxD< D > get_unit_bounding_box_d()
Box with radius one.
Definition: BoundingBoxD.h:181
bool get_contains(const VectorD< D > &o) const
True if the point o is contained within this bounding box.
Definition: BoundingBoxD.h:145
#define IMP_NOT_IMPLEMENTED
Use this to mark that the method is not implemented yet.
Definition: check_macros.h:81
BoundingBoxD(const VectorD< D > &v)
Creating a bounding box containing one point.
Definition: BoundingBoxD.h:82
Various helper macros.
BoundingBoxD(const VectorD< D > &lb, const VectorD< D > &ub)
Make from the lower and upper corners.
Definition: BoundingBoxD.h:72