NVIDIA Iray: Math API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
bbox.h
Go to the documentation of this file.
1 //*****************************************************************************
2 // Copyright 1986, 2014 NVIDIA Corporation. All rights reserved.
3 //*****************************************************************************
10 //*****************************************************************************
11 
12 #ifndef MI_MATH_BBOX_H
13 #define MI_MATH_BBOX_H
14 
15 #include <mi/base/types.h>
16 #include <mi/math/assert.h>
17 #include <mi/math/function.h>
18 #include <mi/math/vector.h>
19 #include <mi/math/matrix.h>
20 
21 namespace mi {
22 
23 namespace math {
24 
37 //------- POD struct that provides storage for bbox elements ----------
38 
47 template <typename T, Size DIM>
48 struct Bbox_struct
49 {
52 };
53 
54 
74 template <typename T, Size DIM>
75 class Bbox
76 {
77 public:
80  typedef Vector value_type;
81  typedef Size size_type;
83  typedef Vector * pointer;
84  typedef const Vector * const_pointer;
85  typedef Vector & reference;
86  typedef const Vector & const_reference;
87 
88  static const Size DIMENSION = DIM;
89  static const Size SIZE = 2;
90 
92  static inline Size size() { return SIZE; }
93 
95  static inline Size max_size() { return SIZE; }
96 
103  };
104 
107 
114  inline void clear()
115  {
116  for( Size i = 0; i < DIM; i++) {
119  }
120  }
121 
128  inline Bbox() { clear(); }
129 
131  inline explicit Bbox( Uninitialized_tag) { }
132 
134  inline Bbox( const Bbox_struct<T,DIM>& bbox_struct )
135  {
136  min = bbox_struct.min;
137  max = bbox_struct.max;
138  }
139 
141  inline explicit Bbox(
142  const Vector& point)
143  {
144  min = point;
145  max = point;
146  }
147 
149  inline Bbox(
150  const Vector& nmin,
151  const Vector& nmax)
152  {
153  min = nmin;
154  max = nmax;
155  }
156 
161  inline Bbox(
162  T min_x,
163  T max_x)
164  {
165  mi_static_assert(DIM == 1);
166  min = Vector( min_x);
167  max = Vector( max_x);
168  }
169 
174  inline Bbox(
175  T min_x,
176  T min_y,
177  T max_x,
178  T max_y)
179  {
180  mi_static_assert(DIM == 2);
181  min = Vector( min_x, min_y);
182  max = Vector( max_x, max_y);
183  }
184 
189  inline Bbox(
190  T min_x,
191  T min_y,
192  T min_z,
193  T max_x,
194  T max_y,
195  T max_z)
196  {
197  mi_static_assert(DIM == 3);
198  min = Vector( min_x, min_y, min_z);
199  max = Vector( max_x, max_y, max_z);
200  }
201 
209  template <typename InputIterator>
210  Bbox(
211  InputIterator first,
212  InputIterator last);
213 
216  template <typename T2>
217  inline explicit Bbox( const Bbox<T2,DIM>& other)
218  {
219  min = Vector( other.min);
220  max = Vector( other.max);
221  }
222 
224  inline Bbox& operator=( const Bbox& other)
225  {
226  min = other.min;
227  max = other.max;
228  return *this;
229  }
230 
232  inline Bbox& operator=( const Bbox_struct<T,DIM>& other)
233  {
234  min = other.min;
235  max = other.max;
236  return *this;
237  }
238 
240  inline operator Bbox_struct<T,DIM>() const
241  {
242  Bbox_struct<T,DIM> result;
243  result.min = min;
244  result.max = max;
245  return result;
246  }
247 
249  inline Vector* begin() { return &min; }
250 
252  inline const Vector* begin() const { return &min; }
253 
257  inline Vector* end() { return begin() + SIZE; }
258 
262  inline const Vector* end() const { return begin() + SIZE; }
263 
265  inline Vector& operator[]( Size i)
266  {
267  mi_math_assert_msg( i < SIZE, "precondition");
268  return begin()[i];
269  }
270 
272  inline const Vector& operator[]( Size i) const
273  {
274  mi_math_assert_msg( i < SIZE, "precondition");
275  return begin()[i];
276  }
277 
281  inline bool empty() const
282  {
283  for( Size i = 0; i < DIM; i++) {
285  return false;
287  return false;
288  }
289  return true;
290  }
291 
298  inline Size rank() const
299  {
300  Size rank = 0;
301  for( Size i = 0; i < DIM; i++)
302  rank += (min[i] < max[i]);
303  return rank;
304  }
305 
307  inline bool is_point() const { return min == max; }
308 
312  inline bool is_line() const { return rank() == 1u; }
313 
317  inline bool is_plane() const { return rank() == 2u; }
318 
322  inline bool is_volume() const { return rank() == 3u; }
323 
325  inline bool contains( const Vector& vec) const
326  {
327  for( Size i = 0; i < DIM; i++) {
328  if( vec[i] < min[i] || vec[i] > max[i])
329  return false;
330  }
331  return true;
332  }
333 
336  inline bool intersects( const Bbox& other) const
337  {
338  for( Size i = 0; i < DIM; i++) {
339  if( min[i] > (other.max)[i] || max[i] < (other.min)[i])
340  return false;
341  }
342  return true;
343  }
344 
346  inline void insert( const Bbox& other)
347  {
348  min = elementwise_min( min, (other.min));
349  max = elementwise_max( max, (other.max));
350  }
351 
353  inline void insert( const Vector& point)
354  {
355  min = elementwise_min( min, point);
356  max = elementwise_max( max, point);
357  }
358 
366  template <typename InputIterator>
367  void insert(
368  InputIterator first,
369  InputIterator last);
370 
371 
380  const Bbox& vbox,
381  T t) const
382  {
383  mi_math_assert_msg( ! empty(), "precondition");
384  mi_math_assert_msg( ! vbox.empty(), "precondition");
385  return t < 0 ? Bbox(min + (vbox.max) * t, max + (vbox.min) * t) //-V547 PVS
386  : Bbox(min + (vbox.min) * t, max + (vbox.max) * t);
387  }
388 
394  inline void push_back( const Bbox& other)
395  {
396  return insert( other);
397  }
398 
408  void robust_grow( T eps = T(1.0e-5f));
409 
411  inline T volume() const
412  {
413  Vector diag = max - min;
414  T vol = base::max MI_PREVENT_MACRO_EXPAND ( T(0), diag[0]);
415  for( Size i = 1; i < DIM; i++)
416  vol *= base::max MI_PREVENT_MACRO_EXPAND ( T(0), diag[i]);
417  return vol;
418  }
419 
423  inline T diagonal_length() const
424  {
425  mi_math_assert_msg( !empty(), "precondition");
426  Vector diag = max - min;
427  return length( diag);
428  }
429 
432  inline Size largest_extent_index() const
433  {
434  Vector diag = max - min;
435  T maxval = diag[0];
436  Size maxidx = 0;
437  for( Size i = 1; i < DIM; i++) {
438  if (maxval < diag[i]) {
439  maxval = diag[i];
440  maxidx = i;
441  }
442  }
443  return maxidx;
444  }
445 
447  inline Vector center() const { return (max + min) * T(0.5);}
448 
449 };
450 
451 //------ Operator declarations for Bbox ---------------------------------------
452 
457 template <typename T, Size DIM>
458 inline Bbox<T,DIM> operator+( const Bbox<T,DIM>& bbox, T value)
459 {
460  mi_math_assert_msg( !bbox.empty(), "precondition");
462  for( Size i = 0; i < DIM; i++) {
463  (result.min)[i] = (bbox.min)[i] - value;
464  (result.max)[i] = (bbox.max)[i] + value;
465  }
466  return result;
467 }
468 
473 template <typename T, Size DIM>
474 inline Bbox<T,DIM> operator-( const Bbox<T,DIM>& bbox, T value)
475 {
476  mi_math_assert_msg( !bbox.empty(), "precondition");
478  for( Size i = 0; i < DIM; i++) {
479  (result.min)[i] = (bbox.min)[i] + value;
480  (result.max)[i] = (bbox.max)[i] - value;
481  }
482  return result;
483 }
484 
489 template <typename T, Size DIM>
490 inline Bbox<T,DIM> operator*( const Bbox<T,DIM>& bbox, T factor)
491 {
492  mi_math_assert_msg( !bbox.empty(), "precondition");
494  for( Size i = 0; i < DIM; i++) {
495  (result.min)[i] = (bbox.min)[i] * factor;
496  (result.max)[i] = (bbox.max)[i] * factor;
497  }
498  return result;
499 }
500 
505 template <typename T, Size DIM>
506 inline Bbox<T,DIM> operator/( const Bbox<T,DIM>& bbox, T divisor)
507 {
508  mi_math_assert_msg( !bbox.empty(), "precondition");
509  mi_math_assert_msg( divisor != T(0), "precondition");
511  for( Size i = 0; i < DIM; i++) {
512  (result.min)[i] = (bbox.min)[i] / divisor;
513  (result.max)[i] = (bbox.max)[i] / divisor;
514  }
515  return result;
516 }
517 
522 template <typename T, Size DIM>
523 inline Bbox<T,DIM>& operator+=( Bbox<T,DIM>& bbox, T value)
524 {
525  mi_math_assert_msg( !bbox.empty(), "precondition");
526  for( Size i = 0; i < DIM; i++) {
527  (bbox.min)[i] -= value;
528  (bbox.max)[i] += value;
529  }
530  return bbox;
531 }
532 
537 template <typename T, Size DIM>
538 inline Bbox<T,DIM>& operator-=( Bbox<T,DIM>& bbox, T value)
539 {
540  mi_math_assert_msg( !bbox.empty(), "precondition");
541  for( Size i = 0; i < DIM; i++) {
542  (bbox.min)[i] += value;
543  (bbox.max)[i] -= value;
544  }
545  return bbox;
546 }
547 
551 template <typename T, Size DIM>
552 inline Bbox<T,DIM>& operator*=( Bbox<T,DIM>& bbox, T factor)
553 {
554  mi_math_assert_msg( !bbox.empty(), "precondition");
555  for( Size i = 0; i < DIM; i++) {
556  (bbox.min)[i] *= factor;
557  (bbox.max)[i] *= factor;
558  }
559  return bbox;
560 }
561 
565 template <typename T, Size DIM>
566 inline Bbox<T,DIM>& operator/=( Bbox<T,DIM>& bbox, T divisor)
567 {
568  mi_math_assert_msg( !bbox.empty(), "precondition");
569  mi_math_assert_msg( divisor != T(0), "precondition");
570  for( Size i = 0; i < DIM; i++) {
571  (bbox.min)[i] /= divisor;
572  (bbox.max)[i] /= divisor;
573  }
574  return bbox;
575 }
576 
578 template <typename T, Size DIM>
579 inline bool operator==(const Bbox<T,DIM>& lhs, const Bbox<T,DIM>& rhs)
580 {
581  return (lhs.min) == (rhs.min) && (lhs.max) == (rhs.max);
582 }
583 
585 template <typename T, Size DIM>
586 inline bool operator!=(const Bbox<T,DIM>& lhs, const Bbox<T,DIM>& rhs)
587 {
588  return (lhs.min) != (rhs.min) || (lhs.max) != (rhs.max);
589 }
590 
594 template <typename T, Size DIM>
595 inline bool operator< ( const Bbox<T,DIM> & lhs, const Bbox<T,DIM> & rhs)
596 {
597  for( Size i = 0; i < DIM; i++) {
598  if ( (lhs.min)[i] < (rhs.min)[i])
599  return true;
600  if ( (lhs.min)[i] > (rhs.min)[i])
601  return false;
602  }
603  for( Size i = 0; i < DIM; i++) {
604  if ( lhs.max[i] < rhs.max[i])
605  return true;
606  if ( lhs.max[i] > rhs.max[i])
607  return false;
608  }
609  return false;
610 }
611 
615 template <typename T, Size DIM>
616 inline bool operator<=( const Bbox<T,DIM>& lhs, const Bbox<T,DIM>& rhs)
617 {
618  return ! (rhs < lhs);
619 }
620 
624 template <typename T, Size DIM>
625 inline bool operator>( const Bbox<T,DIM> & lhs, const Bbox<T,DIM> & rhs)
626 {
627  return rhs < lhs;
628 }
629 
633 template <typename T, Size DIM>
634 inline bool operator>=( const Bbox<T,DIM>& lhs, const Bbox<T,DIM>& rhs)
635 {
636  return ! (lhs < rhs);
637 }
638 
639 
640 //------ Free Functions for Bbox ----------------------------------------------
641 
642 
647 template <typename T, Size DIM>
649  const Bbox<T,DIM> &bbox1,
650  const Bbox<T,DIM> &bbox2,
651  T t)
652 {
653  mi_math_assert_msg( !bbox1.empty(), "precondition");
654  mi_math_assert_msg( !bbox2.empty(), "precondition");
655  T t2 = T(1) - t;
656  return Bbox<T,DIM>( (bbox1.min)*t2 + (bbox2.min)*t, (bbox1.max)*t2 + (bbox2.max)*t);
657 }
658 
659 
662 template <typename T, Size DIM>
664  const Bbox<T,DIM> &bbox1,
665  const Bbox<T,DIM> &bbox2)
666 {
668  for( Size i = 0; i < DIM; i++) {
669  result.min[i] = base::max MI_PREVENT_MACRO_EXPAND (bbox1.min[i], bbox2.min[i]);
670  result.max[i] = base::min MI_PREVENT_MACRO_EXPAND (bbox1.max[i], bbox2.max[i]);
671  if (result.max[i] < result.min[i]) { // the bbox is empty
672  result.clear();
673  return result;
674  }
675  }
676 
677  return result;
678 }
679 
692 template <typename TT, typename T>
693 Bbox<T,3> transform_point( const Matrix<TT,4,4>& mat, const Bbox<T,3>& bbox);
694 
695 
704 template <typename TT, typename T>
705 Bbox<T,3> transform_vector( const Matrix<TT,4,4>& mat, const Bbox<T,3>& bbox);
706 
707 
708 
709 //------ Definitions of non-inline function -----------------------------------
710 
711 #ifndef MI_FOR_DOXYGEN_ONLY
712 
713 template <typename T, Size DIM>
714 template <typename InputIterator>
715 void Bbox<T,DIM>::insert( InputIterator first, InputIterator last)
716 {
717  for( ; first != last; ++first)
718  insert( *first);
719 }
720 
721 template <typename T, Size DIM>
722 template <typename InputIterator>
723 Bbox<T,DIM>::Bbox( InputIterator first, InputIterator last)
724 {
725  clear();
726  insert( first, last);
727 }
728 
729 template <typename T, Size DIM>
730 void Bbox<T, DIM>::robust_grow( T eps)
731 {
732  // Just enlarging the bounding box by epsilon * (largest box extent) is not sufficient, since
733  // there may be cancelation errors if the box is far away from the origin. Hence we take into
734  // account the distance of the box from the origin: the further the box is away, the larger we
735  // have to make it. We just add the two contributions. If we are very far away, then distance
736  // will dominate. For very large boxes, the extent will dominate. We neglect exact weight
737  // factors. We are just a bit less generous with the epsilon to compensate for the extra stuff
738  // we added. If we have objects that in some direction are several orders of magnitude larger
739  // than in the others, this method will not be perfect.
740  //
741  // compute size heuristic for each dimension
742  Vector dist;
743  for( Size i = 0; i < DIM; i++)
744  dist[i] = base::abs(min[i]) + base::abs(max[i])
745  + base::abs(max[i] - min[i]);
746  // compute the grow factor
747  T max_dist = T(0);
748  for( Size i = 0; i < DIM; i++)
749  max_dist = base::max MI_PREVENT_MACRO_EXPAND (max_dist, dist[i]);
750  const T margin = max_dist * eps;
751  // grow the bounding box
752  *this += margin;
753 }
754 
755 #endif // MI_FOR_DOXYGEN_ONLY
756 
757 template <typename TT, typename T>
759 {
760  if( bbox.empty())
761  return bbox;
762 
763  // Transforms all eight corner points, and finds then the bounding box of these eight points.
764  // The corners are computed in an optimized manner which factorizes computations.
765  //
766  // The transformation is decomposed into the transformation of (min,1) and the transformation of
767  // bounding box difference vectors (max.x-min.x,0,0,0),(0, max.y-min.y,0,0),(0,0,max.z-min.z,0).
768  // The transformation of max is the sum of all 4 transformed vectors. The division by the
769  // homogeneous w is deferred to the end.
770  Vector<T,3> corners[8];
771  corners[0] = transform_vector( mat, bbox.min);
772  corners[0].x += T(mat.wx);
773  corners[0].y += T(mat.wy);
774  corners[0].z += T(mat.wz);
775 
776  // difference vectors between min and max
777  Vector<T,3> dx = transform_vector( mat, Vector<T,3>( (bbox.max).x - (bbox.min).x, 0, 0));
778  Vector<T,3> dy = transform_vector( mat, Vector<T,3>( 0, (bbox.max).y - (bbox.min).y, 0));
779  Vector<T,3> dz = transform_vector( mat, Vector<T,3>( 0, 0, (bbox.max).z - (bbox.min).z));
780 
781  corners[1] = corners[0] + dz; // vertex 001
782  corners[2] = corners[0] + dy; // vertex 010
783  corners[3] = corners[0] + dy + dz; // vertex 011
784  corners[4] = corners[0] + dx; // vertex 100
785  corners[5] = corners[0] + dx + dz; // vertex 101
786  corners[6] = corners[0] + dx + dy; // vertex 110
787  corners[7] = corners[0] + dx + dy + dz; // vertex 110
788 
789  // compute the w-coordinates separately. This is done to avoid copying from 4D to 3D vectors.
790  // Again, the computation is decomposed.
791  //
792  // w-coordinate for difference vectors between min and max
793  T wx = T( mat.xw * ((bbox.max).x - (bbox.min).x));
794  T wy = T( mat.yw * ((bbox.max).y - (bbox.min).y));
795  T wz = T( mat.zw * ((bbox.max).z - (bbox.min).z));
796  // w-coordinate for corners
797  T w[8];
798  w[0] = T(mat.xw * (bbox.min).x + mat.yw * (bbox.min).y + mat.zw * (bbox.min).z + mat.ww);
799  w[1] = w[0] + wz; // vertex 001
800  w[2] = w[0] + wy; // vertex 010
801  w[3] = w[0] + wy + wz; // vertex 011
802  w[4] = w[0] + wx; // vertex 100
803  w[5] = w[0] + wx + wz; // vertex 101
804  w[6] = w[0] + wx + wy; // vertex 110
805  w[7] = w[0] + wx + wy + wz; // vertex 111
806 
807  // divide the other coordinates (x,y,z) by w to obtain 3D coordinates
808  for( unsigned int i=0; i<8; ++i) {
809  if( w[i]!=0 && w[i]!=1) {
810  T inv = T(1) / w[i];
811  corners[i].x *= inv;
812  corners[i].y *= inv;
813  corners[i].z *= inv;
814  }
815  }
816  Bbox<T,3> result( corners, corners+8);
817  return result;
818 }
819 
820 template <typename TT, typename T>
822 {
823  // See transform_point() above for implementation notes.
824  if( bbox.empty())
825  return bbox;
826 
827  Vector<T,3> corners[8];
828  corners[0] = transform_vector( mat, (bbox.min));
829 
830  Vector<T,3> dx = transform_vector( mat, Vector<T,3>( (bbox.max).x - (bbox.min).x, 0, 0));
831  Vector<T,3> dy = transform_vector( mat, Vector<T,3>( 0, (bbox.max).y - (bbox.min).y, 0));
832  Vector<T,3> dz = transform_vector( mat, Vector<T,3>( 0, 0, (bbox.max).z - (bbox.min).z));
833 
834  corners[1] = corners[0] + dz;
835  corners[2] = corners[0] + dy;
836  corners[3] = corners[0] + dy + dz;
837  corners[4] = corners[0] + dx;
838  corners[5] = corners[0] + dx + dz;
839  corners[6] = corners[0] + dx + dy;
840  corners[7] = corners[0] + dx + dy + dz;
841 
842  Bbox<T,3> result( corners, corners+8);
843  return result;
844 }
845  // end group mi_math_bbox
847 
848 } // namespace math
849 
850 } // namespace mi
851 
852 #endif // MI_MATH_BBOX_H