Nori  23
bbox.h
1 /*
2  This file is part of Nori, a simple educational ray tracer
3 
4  Copyright (c) 2015 by Wenzel Jakob
5 
6  Nori is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Nori is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #if !defined(__NORI_BBOX_H)
20 #define __NORI_BBOX_H
21 
22 #include <nori/ray.h>
23 
24 NORI_NAMESPACE_BEGIN
25 
42 template <typename _PointType> struct TBoundingBox {
43  enum {
44  Dimension = _PointType::Dimension
45  };
46 
47  typedef _PointType PointType;
48  typedef typename PointType::Scalar Scalar;
49  typedef typename PointType::VectorType VectorType;
50 
59  reset();
60  }
61 
63  TBoundingBox(const PointType &p)
64  : min(p), max(p) { }
65 
67  TBoundingBox(const PointType &min, const PointType &max)
68  : min(min), max(max) {
69  }
70 
72  bool operator==(const TBoundingBox &bbox) const {
73  return min == bbox.min && max == bbox.max;
74  }
75 
77  bool operator!=(const TBoundingBox &bbox) const {
78  return min != bbox.min || max != bbox.max;
79  }
80 
82  Scalar getVolume() const {
83  return (max - min).prod();
84  }
85 
87  float getSurfaceArea() const {
88  VectorType d = max - min;
89  float result = 0.0f;
90  for (int i=0; i<Dimension; ++i) {
91  float term = 1.0f;
92  for (int j=0; j<Dimension; ++j) {
93  if (i == j)
94  continue;
95  term *= d[j];
96  }
97  result += term;
98  }
99  return 2.0f * result;
100  }
101 
103  PointType getCenter() const {
104  return (max + min) * (Scalar) 0.5f;
105  }
106 
115  bool contains(const PointType &p, bool strict = false) const {
116  if (strict) {
117  return (p.array() > min.array()).all()
118  && (p.array() < max.array()).all();
119  } else {
120  return (p.array() >= min.array()).all()
121  && (p.array() <= max.array()).all();
122  }
123  }
124 
136  bool contains(const TBoundingBox &bbox, bool strict = false) const {
137  if (strict) {
138  return (bbox.min.array() > min.array()).all()
139  && (bbox.max.array() < max.array()).all();
140  } else {
141  return (bbox.min.array() >= min.array()).all()
142  && (bbox.max.array() <= max.array()).all();
143  }
144  }
145 
154  bool overlaps(const TBoundingBox &bbox, bool strict = false) const {
155  if (strict) {
156  return (bbox.min.array() < max.array()).all()
157  && (bbox.max.array() > min.array()).all();
158  } else {
159  return (bbox.min.array() <= max.array()).all()
160  && (bbox.max.array() >= min.array()).all();
161  }
162  }
163 
168  Scalar squaredDistanceTo(const PointType &p) const {
169  Scalar result = 0;
170 
171  for (int i=0; i<Dimension; ++i) {
172  Scalar value = 0;
173  if (p[i] < min[i])
174  value = min[i] - p[i];
175  else if (p[i] > max[i])
176  value = p[i] - max[i];
177  result += value*value;
178  }
179 
180  return result;
181  }
182 
187  Scalar distanceTo(const PointType &p) const {
188  return std::sqrt(squaredDistanceTo(p));
189  }
190 
195  Scalar squaredDistanceTo(const TBoundingBox &bbox) const {
196  Scalar result = 0;
197 
198  for (int i=0; i<Dimension; ++i) {
199  Scalar value = 0;
200  if (bbox.max[i] < min[i])
201  value = min[i] - bbox.max[i];
202  else if (bbox.min[i] > max[i])
203  value = bbox.min[i] - max[i];
204  result += value*value;
205  }
206 
207  return result;
208  }
209 
214  Scalar distanceTo(const TBoundingBox &bbox) const {
215  return std::sqrt(squaredDistanceTo(bbox));
216  }
217 
227  bool isValid() const {
228  return (max.array() >= min.array()).all();
229  }
230 
232  bool isPoint() const {
233  return (max.array() == min.array()).all();
234  }
235 
237  bool hasVolume() const {
238  return (max.array() > min.array()).all();
239  }
240 
242  int getMajorAxis() const {
243  VectorType d = max - min;
244  int largest = 0;
245  for (int i=1; i<Dimension; ++i)
246  if (d[i] > d[largest])
247  largest = i;
248  return largest;
249  }
250 
252  int getMinorAxis() const {
253  VectorType d = max - min;
254  int shortest = 0;
255  for (int i=1; i<Dimension; ++i)
256  if (d[i] < d[shortest])
257  shortest = i;
258  return shortest;
259  }
260 
265  VectorType getExtents() const {
266  return max - min;
267  }
268 
270  void clip(const TBoundingBox &bbox) {
271  min = min.cwiseMax(bbox.min);
272  max = max.cwiseMin(bbox.max);
273  }
274 
282  void reset() {
283  min.setConstant( std::numeric_limits<Scalar>::infinity());
284  max.setConstant(-std::numeric_limits<Scalar>::infinity());
285  }
286 
288  void expandBy(const PointType &p) {
289  min = min.cwiseMin(p);
290  max = max.cwiseMax(p);
291  }
292 
294  void expandBy(const TBoundingBox &bbox) {
295  min = min.cwiseMin(bbox.min);
296  max = max.cwiseMax(bbox.max);
297  }
298 
300  static TBoundingBox merge(const TBoundingBox &bbox1, const TBoundingBox &bbox2) {
301  return TBoundingBox(
302  bbox1.min.cwiseMin(bbox2.min),
303  bbox1.max.cwiseMax(bbox2.max)
304  );
305  }
306 
308  int getLargestAxis() const {
309  VectorType extents = max-min;
310 
311  if (extents[0] >= extents[1] && extents[0] >= extents[2])
312  return 0;
313  else if (extents[1] >= extents[0] && extents[1] >= extents[2])
314  return 1;
315  else
316  return 2;
317  }
318 
320  PointType getCorner(int index) const {
321  PointType result;
322  for (int i=0; i<Dimension; ++i)
323  result[i] = (index & (1 << i)) ? max[i] : min[i];
324  return result;
325  }
326 
328  std::string toString() const {
329  if (!isValid())
330  return "BoundingBox[invalid]";
331  else
332  return tfm::format("BoundingBox[min=%s, max=%s]", min.toString(), max.toString());
333  }
334 
336  bool rayIntersect(const Ray3f &ray) const {
337  float nearT = -std::numeric_limits<float>::infinity();
338  float farT = std::numeric_limits<float>::infinity();
339 
340  for (int i=0; i<3; i++) {
341  float origin = ray.o[i];
342  float minVal = min[i], maxVal = max[i];
343 
344  if (ray.d[i] == 0) {
345  if (origin < minVal || origin > maxVal)
346  return false;
347  } else {
348  float t1 = (minVal - origin) * ray.dRcp[i];
349  float t2 = (maxVal - origin) * ray.dRcp[i];
350 
351  if (t1 > t2)
352  std::swap(t1, t2);
353 
354  nearT = std::max(t1, nearT);
355  farT = std::min(t2, farT);
356 
357  if (!(nearT <= farT))
358  return false;
359  }
360  }
361 
362  return ray.mint <= farT && nearT <= ray.maxt;
363  }
364 
366  bool rayIntersect(const Ray3f &ray, float &nearT, float &farT) const {
367  nearT = -std::numeric_limits<float>::infinity();
368  farT = std::numeric_limits<float>::infinity();
369 
370  for (int i=0; i<3; i++) {
371  float origin = ray.o[i];
372  float minVal = min[i], maxVal = max[i];
373 
374  if (ray.d[i] == 0) {
375  if (origin < minVal || origin > maxVal)
376  return false;
377  } else {
378  float t1 = (minVal - origin) * ray.dRcp[i];
379  float t2 = (maxVal - origin) * ray.dRcp[i];
380 
381  if (t1 > t2)
382  std::swap(t1, t2);
383 
384  nearT = std::max(t1, nearT);
385  farT = std::min(t2, farT);
386 
387  if (!(nearT <= farT))
388  return false;
389  }
390  }
391 
392  return true;
393  }
394 
395  PointType min;
396  PointType max;
397 };
398 
399 
400 NORI_NAMESPACE_END
401 
402 #endif /* __NORI_BBOX_H */
Generic n-dimensional bounding box data structure.
Definition: bbox.h:42
static TBoundingBox merge(const TBoundingBox &bbox1, const TBoundingBox &bbox2)
Merge two bounding boxes.
Definition: bbox.h:300
TBoundingBox()
Create a new invalid bounding box.
Definition: bbox.h:58
bool hasVolume() const
Check whether this bounding box has any associated volume.
Definition: bbox.h:237
bool contains(const TBoundingBox &bbox, bool strict=false) const
Check whether a specified bounding box lies on or within the current bounding box.
Definition: bbox.h:136
TBoundingBox(const PointType &p)
Create a collapsed bounding box from a single point.
Definition: bbox.h:63
bool isValid() const
Check whether this is a valid bounding box.
Definition: bbox.h:227
int getMajorAxis() const
Return the dimension index with the largest associated side length.
Definition: bbox.h:242
int getLargestAxis() const
Return the index of the largest axis.
Definition: bbox.h:308
void expandBy(const PointType &p)
Expand the bounding box to contain another point.
Definition: bbox.h:288
PointType getCenter() const
Return the center point.
Definition: bbox.h:103
Scalar distanceTo(const PointType &p) const
Calculate the smallest distance between the axis-aligned bounding box and the point p.
Definition: bbox.h:187
Scalar getVolume() const
Calculate the n-dimensional volume of the bounding box.
Definition: bbox.h:82
void reset()
Mark the bounding box as invalid.
Definition: bbox.h:282
int getMinorAxis() const
Return the dimension index with the shortest associated side length.
Definition: bbox.h:252
VectorType getExtents() const
Calculate the bounding box extents.
Definition: bbox.h:265
bool overlaps(const TBoundingBox &bbox, bool strict=false) const
Check two axis-aligned bounding boxes for possible overlap.
Definition: bbox.h:154
Scalar squaredDistanceTo(const TBoundingBox &bbox) const
Calculate the smallest square distance between the axis-aligned bounding box and bbox.
Definition: bbox.h:195
PointType getCorner(int index) const
Return the position of a bounding box corner.
Definition: bbox.h:320
void clip(const TBoundingBox &bbox)
Clip to another bounding box.
Definition: bbox.h:270
Scalar distanceTo(const TBoundingBox &bbox) const
Calculate the smallest distance between the axis-aligned bounding box and bbox.
Definition: bbox.h:214
std::string toString() const
Return a string representation of the bounding box.
Definition: bbox.h:328
bool contains(const PointType &p, bool strict=false) const
Check whether a point lies on or inside the bounding box.
Definition: bbox.h:115
bool operator==(const TBoundingBox &bbox) const
Test for equality against another bounding box.
Definition: bbox.h:72
PointType max
Component-wise maximum.
Definition: bbox.h:396
bool rayIntersect(const Ray3f &ray) const
Check if a ray intersects a bounding box.
Definition: bbox.h:336
PointType min
Component-wise minimum.
Definition: bbox.h:395
TBoundingBox(const PointType &min, const PointType &max)
Create a bounding box from two positions.
Definition: bbox.h:67
Scalar squaredDistanceTo(const PointType &p) const
Calculate the smallest squared distance between the axis-aligned bounding box and the point p.
Definition: bbox.h:168
bool isPoint() const
Check whether this bounding box has collapsed to a single point.
Definition: bbox.h:232
float getSurfaceArea() const
Calculate the n-1 dimensional volume of the boundary.
Definition: bbox.h:87
bool operator!=(const TBoundingBox &bbox) const
Test for inequality against another bounding box.
Definition: bbox.h:77
void expandBy(const TBoundingBox &bbox)
Expand the bounding box to contain another bounding box.
Definition: bbox.h:294
bool rayIntersect(const Ray3f &ray, float &nearT, float &farT) const
Return the overlapping region of the bounding box and an unbounded ray.
Definition: bbox.h:366
VectorType d
Ray direction.
Definition: ray.h:44
Scalar mint
Minimum position on the ray segment.
Definition: ray.h:46
Scalar maxt
Maximum position on the ray segment.
Definition: ray.h:47
VectorType dRcp
Componentwise reciprocals of the ray direction.
Definition: ray.h:45
PointType o
Ray origin.
Definition: ray.h:43