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