0031313: Foundation Classes - Dump improvement for classes
[occt.git] / src / BVH / BVH_Box.hxx
1 // Created on: 2013-12-20
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifndef _BVH_Box_Header
17 #define _BVH_Box_Header
18
19 #include <BVH_Constants.hxx>
20 #include <BVH_Types.hxx>
21 #include <Standard_Macro.hxx>
22 #include <Standard_Dump.hxx>
23 #include <Standard_ShortReal.hxx>
24
25 #include <limits>
26
27 //! Base class for BVH_Box (CRTP idiom is used).
28 //! @tparam T             Numeric data type
29 //! @tparam N             Vector dimension
30 //! @tparam TheDerivedBox Template of derived class that defined axis aligned bounding box.
31 template <class T, int N, template <class /*T*/, int /*N*/> class TheDerivedBox>
32 class BVH_BaseBox {};
33
34 // forward declaration
35 template <class T, int N> class BVH_Box;
36
37 //! Partial template specialization for BVH_Box when N = 3.
38 template <class T>
39 class BVH_BaseBox<T, 3, BVH_Box>
40 {
41 public:
42
43   //! Transforms this box with given transformation.
44   void Transform (const NCollection_Mat4<T>& theTransform)
45   {
46     if (theTransform.IsIdentity())
47     {
48       return;
49     }
50
51     BVH_Box<T, 3> *aThis = static_cast<BVH_Box<T, 3>*>(this);
52     if (!aThis->IsValid())
53     {
54       return;
55     }
56
57     BVH_Box<T, 3> aBox = Transformed (theTransform);
58
59     aThis->CornerMin() = aBox.CornerMin();
60     aThis->CornerMax() = aBox.CornerMax();
61   }
62
63   //! Returns a box which is the result of applying the
64   //! given transformation to this box.
65   BVH_Box<T, 3> Transformed (const NCollection_Mat4<T>& theTransform) const
66   {
67     BVH_Box<T, 3> aResultBox;
68
69     if (theTransform.IsIdentity())
70     {
71       return aResultBox;
72     }
73
74     const BVH_Box<T, 3> *aThis = static_cast<const BVH_Box<T, 3>*>(this);
75     if (!aThis->IsValid())
76     {
77       return aResultBox;
78     }
79
80     for (size_t aX = 0; aX <= 1; ++aX)
81     {
82       for (size_t aY = 0; aY <= 1; ++aY)
83       {
84         for (size_t aZ = 0; aZ <= 1; ++aZ)
85         {
86           typename BVH::VectorType<T, 4>::Type aPnt =
87             theTransform * typename BVH::VectorType<T, 4>::Type (aX ? aThis->CornerMax().x() : aThis->CornerMin().x(),
88                                                                  aY ? aThis->CornerMax().y() : aThis->CornerMin().y(),
89                                                                  aZ ? aThis->CornerMax().z() : aThis->CornerMin().z(),
90                                                                  static_cast<T> (1.0));
91
92           aResultBox.Add (aPnt.xyz());
93         }
94       }
95     }
96     return aResultBox;
97   }
98 };
99
100 //! Defines axis aligned bounding box (AABB) based on BVH vectors.
101 //! \tparam T Numeric data type
102 //! \tparam N Vector dimension
103 template<class T, int N>
104 class BVH_Box : public BVH_BaseBox<T, N, BVH_Box>
105 {
106 public:
107
108   typedef typename BVH::VectorType<T, N>::Type BVH_VecNt;
109
110 public:
111
112   //! Creates uninitialized bounding box.
113   BVH_Box() : myIsInited (Standard_False) {}
114
115   //! Creates bounding box of given point.
116   BVH_Box (const BVH_VecNt& thePoint)
117   : myMinPoint (thePoint),
118     myMaxPoint (thePoint),
119     myIsInited (Standard_True) {}
120
121   //! Creates copy of another bounding box.
122   BVH_Box (const BVH_Box& theBox)
123   : myMinPoint (theBox.myMinPoint),
124     myMaxPoint (theBox.myMaxPoint),
125     myIsInited (theBox.myIsInited) {}
126
127   //! Creates bounding box from corner points.
128   BVH_Box (const BVH_VecNt& theMinPoint,
129            const BVH_VecNt& theMaxPoint)
130   : myMinPoint (theMinPoint),
131     myMaxPoint (theMaxPoint),
132     myIsInited (Standard_True) {}
133
134 public:
135
136   //! Clears bounding box.
137   void Clear() { myIsInited = Standard_False; }
138
139   //! Is bounding box valid?
140   Standard_Boolean IsValid() const { return myIsInited; }
141
142   //! Appends new point to the bounding box.
143   void Add (const BVH_VecNt& thePoint)
144   {
145     if (!myIsInited)
146     {
147       myMinPoint = thePoint;
148       myMaxPoint = thePoint;
149       myIsInited = Standard_True;
150     }
151     else
152     {
153       myMinPoint = myMinPoint.cwiseMin (thePoint);
154       myMaxPoint = myMaxPoint.cwiseMax (thePoint);
155     }
156   }
157
158   //! Combines bounding box with another one.
159   void Combine (const BVH_Box& theBox);
160
161   //! Returns minimum point of bounding box.
162   const BVH_VecNt& CornerMin() const { return myMinPoint; }
163
164   //! Returns maximum point of bounding box.
165   const BVH_VecNt& CornerMax() const { return myMaxPoint; }
166
167   //! Returns minimum point of bounding box.
168   BVH_VecNt& CornerMin() { return myMinPoint; }
169
170   //! Returns maximum point of bounding box.
171   BVH_VecNt& CornerMax() { return myMaxPoint; }
172
173   //! Returns surface area of bounding box.
174   //! If the box is degenerated into line, returns the perimeter instead.
175   T Area() const;
176
177   //! Returns diagonal of bounding box.
178   BVH_VecNt Size() const { return myMaxPoint - myMinPoint; }
179
180   //! Returns center of bounding box.
181   BVH_VecNt Center() const { return (myMinPoint + myMaxPoint) * static_cast<T> (0.5); }
182
183   //! Returns center of bounding box along the given axis.
184   T Center (const Standard_Integer theAxis) const;
185
186   //! Dumps the content of me into the stream
187   void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const
188   {
189     (void)theDepth;
190     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsInited)
191
192     int n = Min (N, 3);
193     if (n == 1)
194     {
195       OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinPoint[0])
196       OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinPoint[0])
197     }
198     if (n == 2)
199     {
200       OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MinPoint", n, myMinPoint[0], myMinPoint[1])
201       OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MaxPoint", n, myMaxPoint[0], myMaxPoint[1])
202     }
203     if (n == 3)
204     {
205       OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MinPoint", n, myMinPoint[0], myMinPoint[1], myMinPoint[2])
206       OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MaxPoint", n, myMaxPoint[0], myMaxPoint[1], myMaxPoint[2])
207     }
208   }
209
210 public:
211
212   //! Checks if the Box is out of the other box.
213   Standard_Boolean IsOut (const BVH_Box<T, N>& theOther) const
214   {
215     if (!theOther.IsValid())
216       return Standard_True;
217
218     return IsOut (theOther.myMinPoint, theOther.myMaxPoint);
219   }
220
221   //! Checks if the Box is out of the other box defined by two points.
222   Standard_Boolean IsOut (const BVH_VecNt& theMinPoint,
223                           const BVH_VecNt& theMaxPoint) const
224   {
225     if (!IsValid())
226       return Standard_True;
227
228     int n = Min (N, 3);
229     for (int i = 0; i < n; ++i)
230     {
231       if (myMinPoint[i] > theMaxPoint[i] ||
232           myMaxPoint[i] < theMinPoint[i])
233         return Standard_True;
234     }
235     return Standard_False;
236   }
237
238   //! Checks if the Box fully contains the other box.
239   Standard_Boolean Contains (const BVH_Box<T, N>& theOther,
240                              Standard_Boolean& hasOverlap) const
241   {
242     hasOverlap = Standard_False;
243     if (!theOther.IsValid())
244       return Standard_False;
245
246     return Contains (theOther.myMinPoint, theOther.myMaxPoint, hasOverlap);
247   }
248
249   //! Checks if the Box is fully contains the other box.
250   Standard_Boolean Contains (const BVH_VecNt& theMinPoint,
251                              const BVH_VecNt& theMaxPoint,
252                              Standard_Boolean& hasOverlap) const
253   {
254     hasOverlap = Standard_False;
255     if (!IsValid())
256       return Standard_False;
257
258     Standard_Boolean isInside = Standard_True;
259
260     int n = Min (N, 3);
261     for (int i = 0; i < n; ++i)
262     {
263       hasOverlap = (myMinPoint[i] <= theMaxPoint[i] &&
264                     myMaxPoint[i] >= theMinPoint[i]);
265       if (!hasOverlap)
266         return Standard_False;
267
268       isInside = isInside && (myMinPoint[i] <= theMinPoint[i] &&
269                               myMaxPoint[i] >= theMaxPoint[i]);
270     }
271     return isInside;
272   }
273
274   //! Checks if the Point is out of the box.
275   Standard_Boolean IsOut (const BVH_VecNt& thePoint) const
276   {
277     if (!IsValid())
278       return Standard_True;
279
280     int n = Min (N, 3);
281     for (int i = 0; i < n; ++i)
282     {
283       if (thePoint[i] < myMinPoint[i] ||
284           thePoint[i] > myMaxPoint[i])
285         return Standard_True;
286     }
287     return Standard_False;
288   }
289
290
291 protected:
292
293   BVH_VecNt        myMinPoint; //!< Minimum point of bounding box
294   BVH_VecNt        myMaxPoint; //!< Maximum point of bounding box
295   Standard_Boolean myIsInited; //!< Is bounding box initialized?
296
297 };
298
299 namespace BVH
300 {
301   //! Tool class for calculating box center along the given axis.
302   //! \tparam T Numeric data type
303   //! \tparam N Vector dimension
304   template<class T, int N>
305   struct CenterAxis
306   {
307     // Not implemented
308   };
309
310   template<class T>
311   struct CenterAxis<T, 2>
312   {
313     static T Center (const BVH_Box<T, 2>& theBox, const Standard_Integer theAxis)
314     {
315       if (theAxis == 0)
316       {
317         return (theBox.CornerMin().x() + theBox.CornerMax().x()) * static_cast<T> (0.5);
318       }
319       else if (theAxis == 1)
320       {
321         return (theBox.CornerMin().y() + theBox.CornerMax().y()) * static_cast<T> (0.5);
322       }
323       return static_cast<T> (0.0);
324     }
325   };
326
327   template<class T>
328   struct CenterAxis<T, 3>
329   {
330     static T Center (const BVH_Box<T, 3>& theBox, const Standard_Integer theAxis)
331     {
332       if (theAxis == 0)
333       {
334         return (theBox.CornerMin().x() + theBox.CornerMax().x()) * static_cast<T> (0.5);
335       }
336       else if (theAxis == 1)
337       {
338         return (theBox.CornerMin().y() + theBox.CornerMax().y()) * static_cast<T> (0.5);
339       }
340       else if (theAxis == 2)
341       {
342         return (theBox.CornerMin().z() + theBox.CornerMax().z()) * static_cast<T> (0.5);
343       }
344       return static_cast<T> (0.0);
345     }
346   };
347
348   template<class T>
349   struct CenterAxis<T, 4>
350   {
351     static T Center (const BVH_Box<T, 4>& theBox, const Standard_Integer theAxis)
352     {
353       if (theAxis == 0)
354       {
355         return (theBox.CornerMin().x() + theBox.CornerMax().x()) * static_cast<T> (0.5);
356       }
357       else if (theAxis == 1)
358       {
359         return (theBox.CornerMin().y() + theBox.CornerMax().y()) * static_cast<T> (0.5);
360       }
361       else if (theAxis == 2)
362       {
363         return (theBox.CornerMin().z() + theBox.CornerMax().z()) * static_cast<T> (0.5);
364       }
365       return static_cast<T> (0.0);
366     }
367   };
368
369   //! Tool class for calculating surface area of the box.
370   //! \tparam T Numeric data type
371   //! \tparam N Vector dimension
372   template<class T, int N>
373   struct SurfaceCalculator
374   {
375     // Not implemented
376   };
377
378   template<class T>
379   struct SurfaceCalculator<T, 2>
380   {
381     static T Area (const typename BVH_Box<T, 2>::BVH_VecNt& theSize)
382     {
383       const T anArea = theSize.x() * theSize.y();
384
385       if (anArea < std::numeric_limits<T>::epsilon())
386       {
387         return theSize.x() + theSize.y();
388       }
389
390       return anArea;
391     }
392   };
393
394   template<class T>
395   struct SurfaceCalculator<T, 3>
396   {
397     static T Area (const typename BVH_Box<T, 3>::BVH_VecNt& theSize)
398     {
399       const T anArea = ( theSize.x() * theSize.y() +
400                          theSize.x() * theSize.z() +
401                          theSize.z() * theSize.y() ) * static_cast<T> (2.0);
402
403       if (anArea < std::numeric_limits<T>::epsilon())
404       {
405         return theSize.x() +
406                theSize.y() +
407                theSize.z();
408       }
409
410       return anArea;
411     }
412   };
413
414   template<class T>
415   struct SurfaceCalculator<T, 4>
416   {
417     static T Area (const typename BVH_Box<T, 4>::BVH_VecNt& theSize)
418     {
419       const T anArea = ( theSize.x() * theSize.y() +
420                          theSize.x() * theSize.z() +
421                          theSize.z() * theSize.y() ) * static_cast<T> (2.0);
422
423       if (anArea < std::numeric_limits<T>::epsilon())
424       {
425         return theSize.x() +
426                theSize.y() +
427                theSize.z();
428       }
429
430       return anArea;
431     }
432   };
433
434   //! Tool class for calculate component-wise vector minimum
435   //! and maximum (optimized version).
436   //! \tparam T Numeric data type
437   //! \tparam N Vector dimension
438   template<class T, int N>
439   struct BoxMinMax
440   {
441     typedef typename BVH::VectorType<T, N>::Type BVH_VecNt;
442
443     static void CwiseMin (BVH_VecNt& theVec1, const BVH_VecNt& theVec2)
444     {
445       theVec1.x() = Min (theVec1.x(), theVec2.x());
446       theVec1.y() = Min (theVec1.y(), theVec2.y());
447       theVec1.z() = Min (theVec1.z(), theVec2.z());
448     }
449
450     static void CwiseMax (BVH_VecNt& theVec1, const BVH_VecNt& theVec2)
451     {
452       theVec1.x() = Max (theVec1.x(), theVec2.x());
453       theVec1.y() = Max (theVec1.y(), theVec2.y());
454       theVec1.z() = Max (theVec1.z(), theVec2.z());
455     }
456   };
457
458   template<class T>
459   struct BoxMinMax<T, 2>
460   {
461     typedef typename BVH::VectorType<T, 2>::Type BVH_VecNt;
462
463     static void CwiseMin (BVH_VecNt& theVec1, const BVH_VecNt& theVec2)
464     {
465       theVec1.x() = Min (theVec1.x(), theVec2.x());
466       theVec1.y() = Min (theVec1.y(), theVec2.y());
467     }
468
469     static void CwiseMax (BVH_VecNt& theVec1, const BVH_VecNt& theVec2)
470     {
471       theVec1.x() = Max (theVec1.x(), theVec2.x());
472       theVec1.y() = Max (theVec1.y(), theVec2.y());
473     }
474   };
475 }
476
477 // =======================================================================
478 // function : Combine
479 // purpose  :
480 // =======================================================================
481 template<class T, int N>
482 void BVH_Box<T, N>::Combine (const BVH_Box& theBox)
483 {
484   if (theBox.myIsInited)
485   {
486     if (!myIsInited)
487     {
488       myMinPoint = theBox.myMinPoint;
489       myMaxPoint = theBox.myMaxPoint;
490       myIsInited = Standard_True;
491     }
492     else
493     {
494       BVH::BoxMinMax<T, N>::CwiseMin (myMinPoint, theBox.myMinPoint);
495       BVH::BoxMinMax<T, N>::CwiseMax (myMaxPoint, theBox.myMaxPoint);
496     }
497   }
498 }
499
500 // =======================================================================
501 // function : Area
502 // purpose  :
503 // =======================================================================
504 template<class T, int N>
505 T BVH_Box<T, N>::Area() const
506 {
507   return !myIsInited ? static_cast<T> (0.0) : BVH::SurfaceCalculator<T, N>::Area (myMaxPoint - myMinPoint);
508 }
509
510 // =======================================================================
511 // function : Center
512 // purpose  :
513 // =======================================================================
514 template<class T, int N>
515 T BVH_Box<T, N>::Center (const Standard_Integer theAxis) const
516 {
517   return BVH::CenterAxis<T, N>::Center (*this, theAxis);
518 }
519
520 #endif // _BVH_Box_Header