Hermes
bbox.h
1 /*
2  * Copyright (c) 2017 FilipeCN
3  *
4  * The MIT License (MIT)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21  * THE SOFTWARE.
22  *
23  */
24 
25 #ifndef HERMES_GEOMETRY_BBOX_H
26 #define HERMES_GEOMETRY_BBOX_H
27 
28 #include <hermes/geometry/point.h>
29 
30 #include <algorithm>
31 #include <iostream>
32 
33 namespace hermes {
34 
35 // *********************************************************************************************************************
36 // BBox1
37 // *********************************************************************************************************************
38 template<typename T> class BBox1 {
39 public:
40  // *******************************************************************************************************************
41  // STATIC METHODS
42  // *******************************************************************************************************************
43  HERMES_DEVICE_CALLABLE static BBox1 unitBox() { return BBox1<T>(0, 1); }
44  // *******************************************************************************************************************
45  // CONSTRUCTORS
46  // *******************************************************************************************************************
48  lower = Numbers::greatest<T>();
49  upper = Numbers::lowest<T>();
50  }
51  HERMES_DEVICE_CALLABLE explicit BBox1(const T &p) : lower(p), upper(p) {}
52  HERMES_DEVICE_CALLABLE BBox1(const T &p1, const T &p2) : lower(std::min(p1, p2)),
53  upper(std::max(p1, p2)) {}
54  // *******************************************************************************************************************
55  // OPERATORS
56  // *******************************************************************************************************************
57  // *******************************************************************************************************************
58  // QUERIES
59  // *******************************************************************************************************************
60  HERMES_DEVICE_CALLABLE bool contains(const T &p) const { return p >= lower && p <= upper; }
61  // *******************************************************************************************************************
62  // GEOMETRY
63  // *******************************************************************************************************************
64  [[nodiscard]] HERMES_DEVICE_CALLABLE real_t size() const {
65  return upper - lower;
66  }
67  HERMES_DEVICE_CALLABLE T extends() const { return upper - lower; }
68  HERMES_DEVICE_CALLABLE T center() const { return lower + (upper - lower) * 0.5; }
69  HERMES_DEVICE_CALLABLE T centroid() const { return lower * .5 + upper * .5; }
70  // *******************************************************************************************************************
71  // ACCESS
72  // *******************************************************************************************************************
73  HERMES_DEVICE_CALLABLE const T &operator[](int i) const { return (&lower)[i]; }
74  HERMES_DEVICE_CALLABLE T &operator[](int i) { return (&lower)[i]; }
75  // *******************************************************************************************************************
76  // PUBLIC FIELDS
77  // *******************************************************************************************************************
78  T lower, upper;
79 };
80 
81 // *********************************************************************************************************************
82 // BBox2
83 // *********************************************************************************************************************
84 template<typename T> class BBox2 {
85 public:
86  // *******************************************************************************************************************
87  // STATIC METHODS
88  // *******************************************************************************************************************
89  HERMES_DEVICE_CALLABLE static BBox2<T> unitBox() {
90  return {Point2<T>(), Point2<T>(1, 1)};
91  }
92  // *******************************************************************************************************************
93  // CONSTRUCTORS
94  // *******************************************************************************************************************
96  lower = Point2<T>(Numbers::greatest<T>());
97  upper = Point2<T>(Numbers::lowest<T>());
98  }
99  HERMES_DEVICE_CALLABLE explicit BBox2(const Point2 <T> &p) : lower(p), upper(p) {}
100  HERMES_DEVICE_CALLABLE BBox2(const Point2 <T> &p1, const Point2 <T> &p2) {
101 #ifdef HERMES_DEVICE_ENABLED
102  lower = Point2<T>(fminf(p1.x, p2.x), fminf(p1.y, p2.y));
103  upper = Point2<T>(fmaxf(p1.x, p2.x), fmaxf(p1.y, p2.y));
104 #else
105  lower = Point2<T>(std::min(p1.x, p2.x), std::min(p1.y, p2.y));
106  upper = Point2<T>(std::max(p1.x, p2.x), std::max(p1.y, p2.y));
107 #endif
108  }
109  template<typename U>
111  lower{range.lower()}, upper{range.upper() - Index2<U>(1, 1)} {}
112 // *******************************************************************************************************************
113 // OPERATORS
114 // *******************************************************************************************************************
115  // assignment
116  template<typename U>
117  HERMES_DEVICE_CALLABLE BBox2 &operator=(const Index2Range <U> &range) {
118  lower = range.lower();
119  upper = range.upper();
120  return *this;
121  }
122  // casting
123  template<typename U>
124  HERMES_DEVICE_CALLABLE explicit operator Index2Range<U>() const {
125  return Index2Range<U>(lower, Index2<U>(upper.x + 1, upper.y + 1));
126  }
127  // access
128  HERMES_DEVICE_CALLABLE const Point2 <T> &operator[](int i) const {
129  return (i == 0) ? lower : upper;
130  }
131  HERMES_DEVICE_CALLABLE Point2 <T> &operator[](int i) { return (i == 0) ? lower : upper; }
132  // arithmetic
133 #define ARITHMETIC_OP(OP, O) \
134  HERMES_DEVICE_CALLABLE BBox2& operator OP##= (const O& o) { *this = make_union(*this, o); return *this; } \
135  HERMES_DEVICE_CALLABLE BBox2 operator OP (const O& o) { return make_union(*this, o); }
136  ARITHMETIC_OP(+, BBox2)
138 #undef ARITHMETIC_OP
139  // relational
140  HERMES_DEVICE_CALLABLE bool operator==(const BBox2 &b) const {
141  return lower == b.lower && upper == b.upper;
142  }
143 // *******************************************************************************************************************
144 // QUERIES
145 // *******************************************************************************************************************
146  [[nodiscard]] HERMES_DEVICE_CALLABLE bool contains(const Point2 <T> &p) const {
147  return (p.x >= lower.x && p.x <= upper.x && p.y >= lower.y
148  && p.y <= upper.y);
149  }
150 // *******************************************************************************************************************
151 // GEOMETRY
152 // *******************************************************************************************************************
153  [[nodiscard]] HERMES_DEVICE_CALLABLE real_t size(int d) const {
154 #ifdef HERMES_DEVICE_ENABLED
155  d = fmaxf(0, fminf(1, d));
156 #else
157  d = std::max(0, std::min(1, d));
158 #endif
159  return upper[d] - lower[d];
160  }
161  [[nodiscard]] HERMES_DEVICE_CALLABLE Vector2 <T> extends() const {
162  return upper - lower;
163  }
164  [[nodiscard]] HERMES_DEVICE_CALLABLE Point2 <T> center() const {
165  return lower + (upper - lower) * .5f;
166  }
167  [[nodiscard]] HERMES_DEVICE_CALLABLE Point2 <T> centroid() const {
168  return lower * .5f + vec2(upper * .5f);
169  }
170  [[nodiscard]] HERMES_DEVICE_CALLABLE int maxExtent() const {
171  Vector2<T> diag = upper - lower;
172  if (diag.x > diag.y)
173  return 0;
174  return 1;
175  }
176 // *******************************************************************************************************************
177 // PUBLIC FIELDS
178 // *******************************************************************************************************************
179  Point2 <T> lower, upper;
180 };
181 
182 // *********************************************************************************************************************
183 // BBox3
184 // *********************************************************************************************************************
187 template<typename T> class BBox3 {
188 public:
189  // *******************************************************************************************************************
190  // STATIC METHODS
191  // *******************************************************************************************************************
192  HERMES_DEVICE_CALLABLE static BBox3 unitBox(bool centroid_center = false) {
193  if (centroid_center)
194  return {Point3<T>(-0.5), Point3<T>(0.5)};
195  return {Point3<T>(), Point3<T>(1, 1, 1)};
196  }
197  // *******************************************************************************************************************
198  // CONSTRUCTORS
199  // *******************************************************************************************************************
202  lower = Point3<T>(Numbers::greatest<T>());
203  upper = Point3<T>(Numbers::lowest<T>());
204  }
207  HERMES_DEVICE_CALLABLE explicit BBox3(const Point3 <T> &p) : lower(p), upper(p) {}
212  lower = c - Vector3<T>(r, r, r);
213  upper = c + Vector3<T>(r, r, r);
214  }
219 #ifdef HERMES_DEVICE_ENABLED
220  lower = Point3<T>(fminf(p1.x, p2.x), fminf(p1.y, p2.y),
221  fminf(p1.z, p2.z));
222  upper = Point3<T>(fmaxf(p1.x, p2.x), fmaxf(p1.y, p2.y),
223  fmaxf(p1.z, p2.z));
224 #else
225  lower = Point3<T>(std::min(p1.x, p2.x), std::min(p1.y, p2.y),
226  std::min(p1.z, p2.z));
227  upper = Point3<T>(std::max(p1.x, p2.x), std::max(p1.y, p2.y),
228  std::max(p1.z, p2.z));
229 #endif
230  }
231  // *******************************************************************************************************************
232  // OPERATORS
233  // *******************************************************************************************************************
234  // *******************************************************************************************************************
235  // QUERIES
236  // *******************************************************************************************************************
239  [[nodiscard]] HERMES_DEVICE_CALLABLE bool contains(const Point3 <T> &p) const {
240  return (p.x >= lower.x && p.x <= upper.x && p.y >= lower.y &&
241  p.y <= upper.y && p.z >= lower.z && p.z <= upper.z);
242  }
245  [[nodiscard]] HERMES_DEVICE_CALLABLE bool contains(const BBox3 &b) const {
246  return contains(b.lower) && contains(b.upper);
247  }
251  [[nodiscard]] HERMES_DEVICE_CALLABLE bool containsExclusive(const Point3 <T> &p) const {
252  return (p.x >= lower.x && p.x < upper.x && p.y >= lower.y && p.y < upper.y
253  && p.z >= lower.z && p.z < upper.z);
254  }
255  // *******************************************************************************************************************
256  // GEOMETRY
257  // *******************************************************************************************************************
261  lower -= Vector3<T>(delta, delta, delta);
262  upper += Vector3<T>(delta, delta, delta);
263  }
266  return upper - lower;
267  }
269  [[nodiscard]] HERMES_DEVICE_CALLABLE int maxExtent() const {
270  Vector3<T> diag = upper - lower;
271  if (diag.x > diag.y && diag.x > diag.z)
272  return 0;
273  else if (diag.y > diag.z)
274  return 1;
275  return 2;
276  }
280  [[nodiscard]] HERMES_DEVICE_CALLABLE Vector3 <T> offset(const Point3 <T> &p) const {
281  hermes::Vector3<T> o = p - lower;
282  if (upper.x > lower.x)
283  o.x /= upper.x - lower.x;
284  if (upper.y > lower.y)
285  o.y /= upper.y - lower.y;
286  if (upper.z > lower.z)
287  o.z /= upper.z - lower.z;
288  return o;
289  }
291  [[nodiscard]] HERMES_DEVICE_CALLABLE T surfaceArea() const {
292  Vector3<T> d = upper - lower;
293  return 2 * (d.x * d.y + d.x * d.z + d.y * d.z);
294  }
296  [[nodiscard]] HERMES_DEVICE_CALLABLE T volume() const {
297  Vector3<T> d = upper - lower;
298  return d.x * d.y * d.z;
299  }
310  [[nodiscard]] std::vector<BBox3> splitBy8() const {
311  auto mid = center();
312  std::vector<BBox3 < T>>
313  children;
314  children.emplace_back(lower, mid);
315  children.emplace_back(Point3<T>(mid.x, lower.y, lower.z),
316  Point3<T>(upper.x, mid.y, mid.z));
317  children.emplace_back(Point3<T>(lower.x, mid.y, lower.z),
318  Point3<T>(mid.x, upper.y, mid.z));
319  children.emplace_back(Point3<T>(mid.x, mid.y, lower.z),
320  Point3<T>(upper.x, upper.y, mid.z));
321  children.emplace_back(Point3<T>(lower.x, lower.y, mid.z),
322  Point3<T>(mid.x, mid.y, upper.z));
323  children.emplace_back(Point3<T>(mid.x, lower.y, mid.z),
324  Point3<T>(upper.x, mid.y, upper.z));
325  children.emplace_back(Point3<T>(lower.x, mid.y, mid.z),
326  Point3<T>(mid.x, upper.y, upper.z));
327  children.emplace_back(Point3<T>(mid.x, mid.y, mid.z),
328  Point3<T>(upper.x, upper.y, upper.z));
329  return children;
330  }
331  [[nodiscard]] HERMES_DEVICE_CALLABLE Point3 <T> center() const {
332  return lower + (upper - lower) * .5f;
333  }
334  [[nodiscard]] HERMES_DEVICE_CALLABLE Point3 <T> centroid() const {
335  return lower * .5f + vec3(upper * .5f);
336  }
337  [[nodiscard]] HERMES_DEVICE_CALLABLE T size(u32 d) const {
338  return upper[d] - lower[d];
339  }
340  // *******************************************************************************************************************
341  // ACCESS
342  // *******************************************************************************************************************
346  return (i == 0) ? lower : upper;
347  }
351  return (i == 0) ? lower : upper;
352  }
355  [[nodiscard]] HERMES_DEVICE_CALLABLE Point3 <T> corner(int c) const {
356  return Point3<T>((*this)[(c & 1)].x, (*this)[(c & 2) ? 1 : 0].y,
357  (*this)[(c & 4) ? 1 : 0].z);
358  }
359  [[nodiscard]] HERMES_DEVICE_CALLABLE BBox2<T> xy() const {
360  return BBox2<T>(lower.xy(), upper.xy());
361  }
362  [[nodiscard]] HERMES_DEVICE_CALLABLE BBox2<T> yz() const {
363  return BBox2<T>(lower.yz(), upper.yz());
364  }
365  [[nodiscard]] HERMES_DEVICE_CALLABLE BBox2<T> xz() const {
366  return BBox2<T>(lower.xz(), upper.xz());
367  }
368  // *******************************************************************************************************************
369  // PUBLIC FIELDS
370  // *******************************************************************************************************************
371  Point3 <T> lower, upper;
372 };
373 
374 // *********************************************************************************************************************
375 // EXTERNAL FUNCTIONS
376 // *********************************************************************************************************************
377 template<typename T>
378 HERMES_DEVICE_CALLABLE BBox1<T> make_union(const BBox1<T> &b, const T &p) {
379  BBox1 ret = b;
380  ret.lower = std::min(b.lower, p);
381  ret.upper = std::max(b.upper, p);
382  return ret;
383 }
384 template<typename T>
385 HERMES_DEVICE_CALLABLE BBox1<T> make_union(const BBox1<T> &a, const BBox1<T> &b) {
386  BBox1 ret = make_union(a, b.lower);
387  return make_union(ret, b.upper);
388 }
389 
390 template<typename T>
391 HERMES_DEVICE_CALLABLE inline BBox2<T> make_union(const BBox2<T> &b, const Point2 <T> &p) {
392  BBox2<T> ret = b;
393 #ifdef HERMES_DEVICE_ENABLED
394  ret.lower.x = fminf(b.lower.x, p.x);
395  ret.lower.y = fminf(b.lower.y, p.y);
396  ret.upper.x = fmaxf(b.upper.x, p.x);
397  ret.upper.y = fmaxf(b.upper.y, p.y);
398 #else
399  ret.lower.x = std::min(b.lower.x, p.x);
400  ret.lower.y = std::min(b.lower.y, p.y);
401  ret.upper.x = std::max(b.upper.x, p.x);
402  ret.upper.y = std::max(b.upper.y, p.y);
403 #endif
404  return ret;
405 }
406 
407 template<typename T>
408 HERMES_DEVICE_CALLABLE inline BBox2<T> make_union(const BBox2<T> &a, const BBox2<T> &b) {
409  BBox2<T> ret = make_union(a, b.lower);
410  return make_union(ret, b.upper);
411 }
412 
417 template<typename T>
418 HERMES_DEVICE_CALLABLE bool overlaps(const BBox3<T> &a, const BBox3<T> &b) {
419  bool x = (a.upper.x >= b.lower.x) && (a.lower.x <= b.upper.x);
420  bool y = (a.upper.y >= b.lower.y) && (a.lower.y <= b.upper.y);
421  bool z = (a.upper.z >= b.lower.z) && (a.lower.z <= b.upper.z);
422  return (x && y && z);
423 }
428 template<typename T>
429 HERMES_DEVICE_CALLABLE BBox3<T> make_union(const BBox3<T> &b, const Point3 <T> &p) {
430  BBox3 <T> ret = b;
431 #ifdef HERMES_DEVICE_ENABLED
432  ret.lower.x = fminf(b.lower.x, p.x);
433  ret.lower.y = fminf(b.lower.y, p.y);
434  ret.lower.z = fminf(b.lower.z, p.z);
435  ret.upper.x = fmaxf(b.upper.x, p.x);
436  ret.upper.y = fmaxf(b.upper.y, p.y);
437  ret.upper.z = fmaxf(b.upper.z, p.z);
438 #else
439  ret.lower.x = std::min(b.lower.x, p.x);
440  ret.lower.y = std::min(b.lower.y, p.y);
441  ret.lower.z = std::min(b.lower.z, p.z);
442  ret.upper.x = std::max(b.upper.x, p.x);
443  ret.upper.y = std::max(b.upper.y, p.y);
444  ret.upper.z = std::max(b.upper.z, p.z);
445 #endif
446  return ret;
447 }
452 template<typename T>
453 HERMES_DEVICE_CALLABLE inline BBox3<T> make_union(const BBox3<T> &a, const BBox3<T> &b) {
454  BBox3 <T> ret = make_union(a, b.lower);
455  return make_union(ret, b.upper);
456 }
461 template<typename T>
462 HERMES_DEVICE_CALLABLE BBox3<T> intersect(const BBox3<T> &a, const BBox3<T> &b) {
463 #ifdef HERMES_DEVICE_ENABLED
464  return BBox3<T>(
465  Point3<T>(max(a.lower.x, b.lower.x), max(a.lower.x, b.lower.y),
466  max(a.lower.z, b.lower.z)),
467  Point3<T>(min(a.upper.x, b.upper.x), min(a.upper.x, b.upper.y),
468  min(a.upper.z, b.upper.z)));
469 #else
470  return BBox3<T>(
471  Point3<T>(std::max(a.lower.x, b.lower.x), std::max(a.lower.x, b.lower.y),
472  std::max(a.lower.z, b.lower.z)),
473  Point3<T>(std::min(a.upper.x, b.upper.x), std::min(a.upper.x, b.upper.y),
474  std::min(a.upper.z, b.upper.z)));
475 #endif
476 }
477 // *********************************************************************************************************************
478 // IO
479 // *********************************************************************************************************************
480 template<typename T>
481 std::ostream &operator<<(std::ostream &os, const BBox1<T> &b) {
482  os << "BBox1(" << b.lower << ", " << b.upper << ")";
483  return os;
484 }
485 template<typename T>
486 std::ostream &operator<<(std::ostream &os, const BBox2<T> &b) {
487  os << "BBox2(" << b.lower << ", " << b.upper << ")";
488  return os;
489 }
490 template<typename T>
491 std::ostream &operator<<(std::ostream &os, const BBox3<T> &b) {
492  os << "BBox3(" << b.lower << ", " << b.upper << ")";
493  return os;
494 }
495 
496 // *********************************************************************************************************************
497 // TYPEDEFS
498 // *********************************************************************************************************************
499 typedef BBox1<real_t> bbox1;
500 typedef BBox2<real_t> bbox2;
501 typedef BBox3<real_t> bbox3;
502 typedef BBox3<float> bbox3f;
503 
504 } // namespace hermes
505 
506 #endif
Definition: bbox.h:38
Definition: bbox.h:84
Definition: bbox.h:187
std::vector< BBox3 > splitBy8() const
Definition: bbox.h:310
HERMES_DEVICE_CALLABLE Vector3< T > diagonal() const
Definition: bbox.h:265
HERMES_DEVICE_CALLABLE bool containsExclusive(const Point3< T > &p) const
Definition: bbox.h:251
HERMES_DEVICE_CALLABLE Vector3< T > offset(const Point3< T > &p) const
Definition: bbox.h:280
HERMES_DEVICE_CALLABLE T surfaceArea() const
Definition: bbox.h:291
HERMES_DEVICE_CALLABLE bool contains(const BBox3 &b) const
Definition: bbox.h:245
HERMES_DEVICE_CALLABLE T volume() const
Definition: bbox.h:296
HERMES_DEVICE_CALLABLE Point3< T > & operator[](int i)
Definition: bbox.h:350
HERMES_DEVICE_CALLABLE BBox3(const Point3< T > &p)
Definition: bbox.h:207
HERMES_DEVICE_CALLABLE const Point3< T > & operator[](int i) const
Definition: bbox.h:345
HERMES_DEVICE_CALLABLE BBox3(const Point3< T > &c, real_t r)
Definition: bbox.h:211
HERMES_DEVICE_CALLABLE BBox3()
Creates an empty bounding box.
Definition: bbox.h:201
HERMES_DEVICE_CALLABLE BBox3(const Point3< T > &p1, const Point3< T > &p2)
Definition: bbox.h:218
HERMES_DEVICE_CALLABLE void expand(real_t delta)
Definition: bbox.h:260
HERMES_DEVICE_CALLABLE Point3< T > corner(int c) const
Definition: bbox.h:355
HERMES_DEVICE_CALLABLE int maxExtent() const
Definition: bbox.h:269
HERMES_DEVICE_CALLABLE bool contains(const Point3< T > &p) const
Definition: bbox.h:239
Represents a closed-open range of indices [lower, upper)
Definition: index.h:283
HERMES_DEVICE_CALLABLE const Index2< T > & upper() const
Definition: index.h:346
HERMES_DEVICE_CALLABLE const Index2< T > & lower() const
Definition: index.h:344
Geometric 2-dimensional point (x, y)
Definition: point.h:49
T y
1-th component
Definition: point.h:140
T x
0-th component
Definition: point.h:139
Geometric 3-dimensional vector (x, y, z)
Definition: point.h:148
T x
0-th component
Definition: point.h:270
T y
1-th component
Definition: point.h:271
T z
2-th component
Definition: point.h:272
Geometric 2-dimensional vector (x, y)
Definition: vector.h:54
T x
0-th component
Definition: vector.h:155
T y
1-th component
Definition: vector.h:156
Geometric 3-dimensional vector (x, y, z)
Definition: vector.h:166
T x
0-th component
Definition: vector.h:415
T z
2-th component
Definition: vector.h:417
T y
1-th component
Definition: vector.h:416
std::ostream & operator<<(std::ostream &o, const LaunchInfo &info)
LaunchInfo support for std::ostream << operator.
Definition: cuda_utils.h:234
float real_t
default floating point type
Definition: defs.h:75
#define HERMES_DEVICE_CALLABLE
Specifies that the function can be called from both host and device sides.
Definition: defs.h:45
uint32_t u32
32 bit size unsigned integer type
Definition: defs.h:88
#define ARITHMETIC_OP(OP)
asd
Definition: index.h:408
Geometric point classes.
Holds 2-dimensional integer index coordinates.
Definition: index.h:50