Flow123d
bounding_box.hh
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id: bounding_box.hh 1567 2012-02-28 13:24:58Z jan.brezina $
21  * $Revision: 1567 $
22  * $LastChangedBy: jan.brezina $
23  * $LastChangedDate: 2012-02-28 14:24:58 +0100 (Tue, 28 Feb 2012) $
24  *
25  *
26  */
27 
28 #ifndef BOX_ELEMENT_HH_
29 #define BOX_ELEMENT_HH_
30 
31 #include "system/system.hh"
32 #include "system/global_defs.h"
33 #include "mesh/point.hh"
34 
35 #include <vector>
36 #include <armadillo>
37 
38 /**
39  * @brief Bounding box in 3d ambient space.
40  *
41  * Primary intention is usage in BIHTree and various speedups of non-compatible
42  * intersections.
43  *
44  * Copy constructor and assignment are default provided by compiler.
45  * These can be used to set bounds latter on without particular method
46  * to this end:
47  *
48  * @code
49  * BoundingBox box; // non-initialized box
50  * box=BoundingBox( arma::vec3("0 1 2"), arma::vec3("4 5 6") );
51  * @endcode
52  *
53  * Don;t worry about performance, all is inlined.
54  */
55 class BoundingBox {
56 public:
57  TYPEDEF_ERR_INFO( EI_split_point, double);
58  TYPEDEF_ERR_INFO( EI_interval_left, double);
59  TYPEDEF_ERR_INFO( EI_interval_right, double);
60  DECLARE_EXCEPTION(ExcSplitting, << "Split point " << EI_split_point::val
61  << "out of bounds: <" << EI_interval_left::val
62  << ", " << EI_interval_right::val << ">\n");
63 
64  /// Currently we set dimension to 3.
65  static const unsigned int dimension = 3;
66  /// Currently we assume
68 
69  /**
70  * Default constructor.
71  * No initialization of vertices. Be very careful using this.
72  * One necessary usage is vector of BoundigBox.
73  */
75 
76  /**
77  * Constructor for point box.
78  */
80  : min_vertex_(min), max_vertex_(min)
81  {};
82 
83  /**
84  * Constructor.
85  *
86  * From given minimal and maximal vertex.
87  */
88  BoundingBox(const Point &min, const Point &max)
89  : min_vertex_(min), max_vertex_(max)
90  {
91  ASSERT( arma::min( min <= max ) , "Wrong coordinates in constructor.");
92  };
93 
94  /**
95  * Constructor.
96  *
97  * Make bounding box for set of points.
98  */
99  BoundingBox(const vector<Point> &points);
100 
101  /**
102  * Set maximum in given axis.
103  */
104  void set_max(unsigned int axis, double max) {
105  ASSERT_LESS(axis , dimension);
106  ASSERT_LE( min(axis) , max);
107  max_vertex_[axis] = max;
108  }
109 
110  /**
111  * Set minimum on given axis.
112  */
113  void set_min(unsigned int axis, double min) {
114  ASSERT_LESS(axis, dimension);
115  ASSERT_LE(min , max(axis));
116  min_vertex_[axis] = min;
117  }
118 
119  /**
120  * Return minimal vertex of the bounding box.
121  */
122  const Point &min() const {
123  return min_vertex_;
124  }
125 
126  /**
127  * Return maximal vertex of the bounding box.
128  */
129  const Point &max() const {
130  return max_vertex_;
131  }
132 
133  /**
134  * Return minimal value on given axis.
135  */
136  double min(unsigned int axis) const {
137  return min()[axis];
138  }
139 
140  /**
141  * Return maximal value on given axis.
142  */
143  double max(unsigned int axis) const {
144  return max()[axis];
145  }
146 
147 
148  /**
149  * Return size of the box in given axis.
150  */
151  double size(unsigned int axis) const {
152  return max()[axis] - min()[axis];
153  }
154 
155 
156  /**
157  * Return center of the bounding box.
158  */
159  Point center() const {
160  return (max_vertex_ + min_vertex_) / 2.0;
161  }
162 
163  /**
164  * Return center of projection of the bounding box to given @p axis.
165  * Axis coding is: 0 - axis x, 1 - axis y, 2 - axis z.
166  */
167  double projection_center(unsigned int axis) const {
168  ASSERT_LESS(axis, dimension);
169  return (max_vertex_[axis] + min_vertex_[axis])/2;
170  }
171 
172  /**
173  * Returns true is the box element contains @p point
174  *
175  * @param point Testing point
176  * @return True if box element contains point
177  */
178  bool contains_point(const Point &point) const
179  {
180  for (unsigned int i=0; i<dimension; i++) {
181  if ((point(i) + epsilon < min_vertex_(i)) ||
182  (point(i) > epsilon + max_vertex_(i))) return false;
183  }
184  return true;
185  }
186 
187  /**
188  * Returns true if two bounding boxes have intersection.
189  *
190  * This serves as an estimate of intersection of elements.
191  * To make it safe (do not exclude possible intersection) for
192  * 1d and 2d elements aligned with axes, we use some tolerance.
193  * Since this tolerance is fixed, there could be problem with
194  * highly refined meshes (get false positive result).
195  */
196  bool intersect(const BoundingBox &b2) const
197  {
198  for (unsigned int i=0; i<dimension; i++) {
199  //double delta = (max_vertex_(i) - min_vertex_(i)) *
200  if ( (min_vertex_(i) > b2.max_vertex_(i) + epsilon) ||
201  (b2.min_vertex_(i) > max_vertex_(i) + epsilon ) ) return false;
202  }
203  return true;
204  }
205 
206  /**
207  * Returns true if projection of the box to @p axis is an interval
208  * less then (with tolerance) to given @p value.
209  */
210  bool projection_lt(unsigned int axis, double value) const
211  {
212  return max_vertex_(axis) + epsilon < value;
213  }
214 
215  /**
216  * Returns true if projection of the box to @p axis is an interval
217  * greater then (with tolerance) to given @p value.
218  */
219  bool projection_gt(unsigned int axis, double value) const
220  {
221  return min_vertex_(axis) - epsilon > value;
222  }
223 
224  /**
225  * Split box into two boxes along @p axis by the
226  * plane going through @p splitting_point on the axis.
227  */
228  void split(unsigned int axis, double splitting_point,
229  BoundingBox &left, BoundingBox &right ) const
230  {
231  ASSERT_LESS(axis , dimension);
232  if (min_vertex_[axis] <= splitting_point && splitting_point <= max_vertex_[axis] ) {
233  left = *this;
234  right = *this;
235  left.max_vertex_[axis] = splitting_point;
236  right.min_vertex_[axis] = splitting_point;
237  } else {
238  THROW( ExcSplitting() << EI_interval_left(min_vertex_[axis])
239  << EI_interval_right(max_vertex_[axis])
240  << EI_split_point(splitting_point) );
241  }
242  }
243 
244  /**
245  * Expand bounding box to contain also given @p point.
246  */
247  void expand(const Point &point) {
248  for(unsigned int j=0; j<dimension; j++) {
249  min_vertex_(j) = std::min( min_vertex_[j], point[j] );
250  max_vertex_(j) = std::max( max_vertex_[j], point[j] );
251  }
252  }
253 
254  /**
255  * Return index of the axis in which the box has longest projection.
256  */
257  unsigned char longest_axis() const {
258  auto diff=max_vertex_ - min_vertex_;
259  return (diff[1] > diff[0])
260  ? ( diff[2] > diff[1] ? 2 : 1 )
261  : ( diff[2] > diff[0] ? 2 : 0 );
262  }
263 
264 private:
265  /// stabilization parameter
266  static const double epsilon;
267  /// minimal coordinates of bounding box
269  /// maximal coordinates of bounding box
271 };
272 
273 /// Overloads output operator for box.
274 inline ostream &operator<<(ostream &stream, const BoundingBox &box) {
275  stream << "Box("
276  << box.min(0) << " "
277  << box.min(1) << " "
278  << box.min(2) << "; "
279  << box.max(0) << " "
280  << box.max(1) << " "
281  << box.max(2) << ")";
282  return stream;
283 }
284 
285 #endif /* BOX_ELEMENT_HH_ */