3c4e78f2 |
1 | // Created on: 2013-12-20 |
2 | // Created by: Denis BOGOLEPOV |
d5f74e42 |
3 | // Copyright (c) 2013-2014 OPEN CASCADE SAS |
3c4e78f2 |
4 | // |
5 | // This file is part of Open CASCADE Technology software library. |
6 | // |
d5f74e42 |
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 |
3c4e78f2 |
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 | |
5bd54bef |
16 | #ifndef BVH_Box_HeaderFile |
17 | #define BVH_Box_HeaderFile |
3c4e78f2 |
18 | |
f5b72419 |
19 | #include <BVH_Constants.hxx> |
3c4e78f2 |
20 | #include <BVH_Types.hxx> |
bc73b006 |
21 | #include <Standard_Macro.hxx> |
0904aa63 |
22 | #include <Standard_Dump.hxx> |
bc73b006 |
23 | #include <Standard_ShortReal.hxx> |
3c4e78f2 |
24 | |
0bb09048 |
25 | #include <limits> |
26 | |
2b5a58a3 |
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 | { |
3453354e |
67 | const BVH_Box<T, 3> *aThis = static_cast<const BVH_Box<T, 3>*>(this); |
2b5a58a3 |
68 | if (theTransform.IsIdentity()) |
69 | { |
3453354e |
70 | return *aThis; |
2b5a58a3 |
71 | } |
72 | |
2b5a58a3 |
73 | if (!aThis->IsValid()) |
74 | { |
3453354e |
75 | return *aThis; |
2b5a58a3 |
76 | } |
77 | |
3453354e |
78 | BVH_Box<T, 3> aResultBox; |
2b5a58a3 |
79 | for (size_t aX = 0; aX <= 1; ++aX) |
80 | { |
81 | for (size_t aY = 0; aY <= 1; ++aY) |
82 | { |
83 | for (size_t aZ = 0; aZ <= 1; ++aZ) |
84 | { |
85 | typename BVH::VectorType<T, 4>::Type aPnt = |
86 | theTransform * typename BVH::VectorType<T, 4>::Type (aX ? aThis->CornerMax().x() : aThis->CornerMin().x(), |
87 | aY ? aThis->CornerMax().y() : aThis->CornerMin().y(), |
88 | aZ ? aThis->CornerMax().z() : aThis->CornerMin().z(), |
89 | static_cast<T> (1.0)); |
90 | |
91 | aResultBox.Add (aPnt.xyz()); |
92 | } |
93 | } |
94 | } |
95 | return aResultBox; |
96 | } |
97 | }; |
98 | |
679d3878 |
99 | //! Defines axis aligned bounding box (AABB) based on BVH vectors. |
100 | //! \tparam T Numeric data type |
101 | //! \tparam N Vector dimension |
3c4e78f2 |
102 | template<class T, int N> |
2b5a58a3 |
103 | class BVH_Box : public BVH_BaseBox<T, N, BVH_Box> |
3c4e78f2 |
104 | { |
105 | public: |
106 | |
3a7a7013 |
107 | typedef typename BVH::VectorType<T, N>::Type BVH_VecNt; |
3c4e78f2 |
108 | |
109 | public: |
110 | |
111 | //! Creates uninitialized bounding box. |
679d3878 |
112 | BVH_Box() : myIsInited (Standard_False) {} |
3c4e78f2 |
113 | |
114 | //! Creates bounding box of given point. |
115 | BVH_Box (const BVH_VecNt& thePoint) |
679d3878 |
116 | : myMinPoint (thePoint), |
117 | myMaxPoint (thePoint), |
118 | myIsInited (Standard_True) {} |
3c4e78f2 |
119 | |
3c4e78f2 |
120 | //! Creates bounding box from corner points. |
121 | BVH_Box (const BVH_VecNt& theMinPoint, |
122 | const BVH_VecNt& theMaxPoint) |
679d3878 |
123 | : myMinPoint (theMinPoint), |
124 | myMaxPoint (theMaxPoint), |
125 | myIsInited (Standard_True) {} |
3c4e78f2 |
126 | |
127 | public: |
128 | |
129 | //! Clears bounding box. |
e28f12b3 |
130 | void Clear() { myIsInited = Standard_False; } |
3c4e78f2 |
131 | |
132 | //! Is bounding box valid? |
e28f12b3 |
133 | Standard_Boolean IsValid() const { return myIsInited; } |
3c4e78f2 |
134 | |
135 | //! Appends new point to the bounding box. |
e28f12b3 |
136 | void Add (const BVH_VecNt& thePoint) |
137 | { |
138 | if (!myIsInited) |
139 | { |
140 | myMinPoint = thePoint; |
141 | myMaxPoint = thePoint; |
142 | myIsInited = Standard_True; |
143 | } |
144 | else |
145 | { |
146 | myMinPoint = myMinPoint.cwiseMin (thePoint); |
147 | myMaxPoint = myMaxPoint.cwiseMax (thePoint); |
148 | } |
149 | } |
3c4e78f2 |
150 | |
151 | //! Combines bounding box with another one. |
e28f12b3 |
152 | void Combine (const BVH_Box& theBox); |
3c4e78f2 |
153 | |
154 | //! Returns minimum point of bounding box. |
e28f12b3 |
155 | const BVH_VecNt& CornerMin() const { return myMinPoint; } |
3c4e78f2 |
156 | |
157 | //! Returns maximum point of bounding box. |
e28f12b3 |
158 | const BVH_VecNt& CornerMax() const { return myMaxPoint; } |
3c4e78f2 |
159 | |
160 | //! Returns minimum point of bounding box. |
e28f12b3 |
161 | BVH_VecNt& CornerMin() { return myMinPoint; } |
3c4e78f2 |
162 | |
163 | //! Returns maximum point of bounding box. |
e28f12b3 |
164 | BVH_VecNt& CornerMax() { return myMaxPoint; } |
3c4e78f2 |
165 | |
166 | //! Returns surface area of bounding box. |
0bb09048 |
167 | //! If the box is degenerated into line, returns the perimeter instead. |
3c4e78f2 |
168 | T Area() const; |
169 | |
170 | //! Returns diagonal of bounding box. |
e28f12b3 |
171 | BVH_VecNt Size() const { return myMaxPoint - myMinPoint; } |
3c4e78f2 |
172 | |
173 | //! Returns center of bounding box. |
e28f12b3 |
174 | BVH_VecNt Center() const { return (myMinPoint + myMaxPoint) * static_cast<T> (0.5); } |
3c4e78f2 |
175 | |
679d3878 |
176 | //! Returns center of bounding box along the given axis. |
177 | T Center (const Standard_Integer theAxis) const; |
178 | |
0904aa63 |
179 | //! Dumps the content of me into the stream |
bc73b006 |
180 | void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const |
0904aa63 |
181 | { |
182 | (void)theDepth; |
bc73b006 |
183 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsInited) |
184 | |
185 | int n = Min (N, 3); |
186 | if (n == 1) |
187 | { |
188 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinPoint[0]) |
189 | OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMinPoint[0]) |
190 | } |
6b63dc83 |
191 | else if (n == 2) |
bc73b006 |
192 | { |
193 | OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MinPoint", n, myMinPoint[0], myMinPoint[1]) |
194 | OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MaxPoint", n, myMaxPoint[0], myMaxPoint[1]) |
195 | } |
6b63dc83 |
196 | else if (n == 3) |
bc73b006 |
197 | { |
198 | OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MinPoint", n, myMinPoint[0], myMinPoint[1], myMinPoint[2]) |
199 | OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "MaxPoint", n, myMaxPoint[0], myMaxPoint[1], myMaxPoint[2]) |
200 | } |
0904aa63 |
201 | } |
202 | |
6b63dc83 |
203 | //! Inits the content of me from the stream |
204 | Standard_Boolean InitFromJson (const Standard_SStream& theSStream, Standard_Integer& theStreamPos) |
205 | { |
206 | Standard_Integer aPos = theStreamPos; |
207 | |
208 | Standard_Integer anIsInited = 0; |
209 | TCollection_AsciiString aStreamStr = Standard_Dump::Text (theSStream); |
210 | |
211 | OCCT_INIT_FIELD_VALUE_INTEGER (aStreamStr, aPos, anIsInited); |
212 | myIsInited = anIsInited != 0; |
213 | |
214 | int n = Min (N, 3); |
215 | if (n == 1) |
216 | { |
217 | Standard_Real aValue; |
218 | OCCT_INIT_FIELD_VALUE_REAL (aStreamStr, aPos, aValue); |
219 | myMinPoint[0] = (T)aValue; |
220 | } |
221 | else if (n == 2) |
222 | { |
223 | Standard_Real aValue1, aValue2; |
224 | OCCT_INIT_VECTOR_CLASS (aStreamStr, "MinPoint", aPos, n, &aValue1, &aValue2); |
225 | myMinPoint[0] = (T)aValue1; |
226 | myMinPoint[1] = (T)aValue2; |
227 | |
228 | OCCT_INIT_VECTOR_CLASS (aStreamStr, "MaxPoint", aPos, n, &aValue1, &aValue2); |
229 | myMaxPoint[0] = (T)aValue1; |
230 | myMaxPoint[1] = (T)aValue2; |
231 | } |
232 | else if (n == 3) |
233 | { |
234 | Standard_Real aValue1, aValue2, aValue3; |
235 | OCCT_INIT_VECTOR_CLASS (aStreamStr, "MinPoint", aPos, n, &aValue1, &aValue2, &aValue3); |
236 | myMinPoint[0] = (T)aValue1; |
237 | myMinPoint[1] = (T)aValue2; |
238 | myMinPoint[2] = (T)aValue3; |
239 | |
240 | OCCT_INIT_VECTOR_CLASS (aStreamStr, "MaxPoint", aPos, n, &aValue1, &aValue2, &aValue3); |
241 | myMaxPoint[0] = (T)aValue1; |
242 | myMaxPoint[1] = (T)aValue2; |
243 | myMaxPoint[2] = (T)aValue3; |
244 | } |
245 | |
246 | theStreamPos = aPos; |
247 | return Standard_True; |
248 | } |
249 | |
7c1a8210 |
250 | public: |
251 | |
252 | //! Checks if the Box is out of the other box. |
253 | Standard_Boolean IsOut (const BVH_Box<T, N>& theOther) const |
254 | { |
255 | if (!theOther.IsValid()) |
256 | return Standard_True; |
257 | |
258 | return IsOut (theOther.myMinPoint, theOther.myMaxPoint); |
259 | } |
260 | |
261 | //! Checks if the Box is out of the other box defined by two points. |
262 | Standard_Boolean IsOut (const BVH_VecNt& theMinPoint, |
263 | const BVH_VecNt& theMaxPoint) const |
264 | { |
265 | if (!IsValid()) |
266 | return Standard_True; |
267 | |
268 | int n = Min (N, 3); |
269 | for (int i = 0; i < n; ++i) |
270 | { |
271 | if (myMinPoint[i] > theMaxPoint[i] || |
272 | myMaxPoint[i] < theMinPoint[i]) |
273 | return Standard_True; |
274 | } |
275 | return Standard_False; |
276 | } |
277 | |
278 | //! Checks if the Box fully contains the other box. |
279 | Standard_Boolean Contains (const BVH_Box<T, N>& theOther, |
280 | Standard_Boolean& hasOverlap) const |
281 | { |
282 | hasOverlap = Standard_False; |
283 | if (!theOther.IsValid()) |
284 | return Standard_False; |
285 | |
286 | return Contains (theOther.myMinPoint, theOther.myMaxPoint, hasOverlap); |
287 | } |
288 | |
289 | //! Checks if the Box is fully contains the other box. |
290 | Standard_Boolean Contains (const BVH_VecNt& theMinPoint, |
291 | const BVH_VecNt& theMaxPoint, |
292 | Standard_Boolean& hasOverlap) const |
293 | { |
294 | hasOverlap = Standard_False; |
295 | if (!IsValid()) |
296 | return Standard_False; |
297 | |
298 | Standard_Boolean isInside = Standard_True; |
299 | |
300 | int n = Min (N, 3); |
301 | for (int i = 0; i < n; ++i) |
302 | { |
303 | hasOverlap = (myMinPoint[i] <= theMaxPoint[i] && |
304 | myMaxPoint[i] >= theMinPoint[i]); |
305 | if (!hasOverlap) |
306 | return Standard_False; |
307 | |
308 | isInside = isInside && (myMinPoint[i] <= theMinPoint[i] && |
309 | myMaxPoint[i] >= theMaxPoint[i]); |
310 | } |
311 | return isInside; |
312 | } |
313 | |
314 | //! Checks if the Point is out of the box. |
315 | Standard_Boolean IsOut (const BVH_VecNt& thePoint) const |
316 | { |
317 | if (!IsValid()) |
318 | return Standard_True; |
319 | |
320 | int n = Min (N, 3); |
321 | for (int i = 0; i < n; ++i) |
322 | { |
323 | if (thePoint[i] < myMinPoint[i] || |
324 | thePoint[i] > myMaxPoint[i]) |
325 | return Standard_True; |
326 | } |
327 | return Standard_False; |
328 | } |
329 | |
330 | |
3c4e78f2 |
331 | protected: |
332 | |
679d3878 |
333 | BVH_VecNt myMinPoint; //!< Minimum point of bounding box |
334 | BVH_VecNt myMaxPoint; //!< Maximum point of bounding box |
335 | Standard_Boolean myIsInited; //!< Is bounding box initialized? |
3c4e78f2 |
336 | |
337 | }; |
338 | |
679d3878 |
339 | namespace BVH |
340 | { |
341 | //! Tool class for calculating box center along the given axis. |
342 | //! \tparam T Numeric data type |
343 | //! \tparam N Vector dimension |
344 | template<class T, int N> |
345 | struct CenterAxis |
346 | { |
347 | // Not implemented |
348 | }; |
349 | |
350 | template<class T> |
351 | struct CenterAxis<T, 2> |
352 | { |
353 | static T Center (const BVH_Box<T, 2>& theBox, const Standard_Integer theAxis) |
354 | { |
355 | if (theAxis == 0) |
356 | { |
357 | return (theBox.CornerMin().x() + theBox.CornerMax().x()) * static_cast<T> (0.5); |
358 | } |
359 | else if (theAxis == 1) |
360 | { |
361 | return (theBox.CornerMin().y() + theBox.CornerMax().y()) * static_cast<T> (0.5); |
362 | } |
363 | return static_cast<T> (0.0); |
364 | } |
365 | }; |
366 | |
367 | template<class T> |
368 | struct CenterAxis<T, 3> |
369 | { |
370 | static T Center (const BVH_Box<T, 3>& theBox, const Standard_Integer theAxis) |
371 | { |
372 | if (theAxis == 0) |
373 | { |
374 | return (theBox.CornerMin().x() + theBox.CornerMax().x()) * static_cast<T> (0.5); |
375 | } |
376 | else if (theAxis == 1) |
377 | { |
378 | return (theBox.CornerMin().y() + theBox.CornerMax().y()) * static_cast<T> (0.5); |
379 | } |
380 | else if (theAxis == 2) |
381 | { |
382 | return (theBox.CornerMin().z() + theBox.CornerMax().z()) * static_cast<T> (0.5); |
383 | } |
384 | return static_cast<T> (0.0); |
385 | } |
386 | }; |
387 | |
388 | template<class T> |
389 | struct CenterAxis<T, 4> |
390 | { |
391 | static T Center (const BVH_Box<T, 4>& theBox, const Standard_Integer theAxis) |
392 | { |
393 | if (theAxis == 0) |
394 | { |
395 | return (theBox.CornerMin().x() + theBox.CornerMax().x()) * static_cast<T> (0.5); |
396 | } |
397 | else if (theAxis == 1) |
398 | { |
399 | return (theBox.CornerMin().y() + theBox.CornerMax().y()) * static_cast<T> (0.5); |
400 | } |
401 | else if (theAxis == 2) |
402 | { |
403 | return (theBox.CornerMin().z() + theBox.CornerMax().z()) * static_cast<T> (0.5); |
404 | } |
405 | return static_cast<T> (0.0); |
406 | } |
407 | }; |
408 | |
409 | //! Tool class for calculating surface area of the box. |
410 | //! \tparam T Numeric data type |
411 | //! \tparam N Vector dimension |
412 | template<class T, int N> |
413 | struct SurfaceCalculator |
414 | { |
415 | // Not implemented |
416 | }; |
417 | |
418 | template<class T> |
419 | struct SurfaceCalculator<T, 2> |
420 | { |
421 | static T Area (const typename BVH_Box<T, 2>::BVH_VecNt& theSize) |
422 | { |
0bb09048 |
423 | const T anArea = theSize.x() * theSize.y(); |
424 | |
425 | if (anArea < std::numeric_limits<T>::epsilon()) |
426 | { |
427 | return theSize.x() + theSize.y(); |
428 | } |
429 | |
430 | return anArea; |
679d3878 |
431 | } |
432 | }; |
433 | |
434 | template<class T> |
435 | struct SurfaceCalculator<T, 3> |
436 | { |
437 | static T Area (const typename BVH_Box<T, 3>::BVH_VecNt& theSize) |
438 | { |
0bb09048 |
439 | const T anArea = ( theSize.x() * theSize.y() + |
440 | theSize.x() * theSize.z() + |
441 | theSize.z() * theSize.y() ) * static_cast<T> (2.0); |
442 | |
443 | if (anArea < std::numeric_limits<T>::epsilon()) |
444 | { |
445 | return theSize.x() + |
446 | theSize.y() + |
447 | theSize.z(); |
448 | } |
449 | |
450 | return anArea; |
679d3878 |
451 | } |
452 | }; |
453 | |
454 | template<class T> |
455 | struct SurfaceCalculator<T, 4> |
456 | { |
457 | static T Area (const typename BVH_Box<T, 4>::BVH_VecNt& theSize) |
458 | { |
0bb09048 |
459 | const T anArea = ( theSize.x() * theSize.y() + |
460 | theSize.x() * theSize.z() + |
461 | theSize.z() * theSize.y() ) * static_cast<T> (2.0); |
462 | |
463 | if (anArea < std::numeric_limits<T>::epsilon()) |
464 | { |
465 | return theSize.x() + |
466 | theSize.y() + |
467 | theSize.z(); |
468 | } |
469 | |
470 | return anArea; |
679d3878 |
471 | } |
472 | }; |
473 | |
474 | //! Tool class for calculate component-wise vector minimum |
475 | //! and maximum (optimized version). |
476 | //! \tparam T Numeric data type |
477 | //! \tparam N Vector dimension |
478 | template<class T, int N> |
479 | struct BoxMinMax |
480 | { |
481 | typedef typename BVH::VectorType<T, N>::Type BVH_VecNt; |
482 | |
483 | static void CwiseMin (BVH_VecNt& theVec1, const BVH_VecNt& theVec2) |
484 | { |
485 | theVec1.x() = Min (theVec1.x(), theVec2.x()); |
486 | theVec1.y() = Min (theVec1.y(), theVec2.y()); |
487 | theVec1.z() = Min (theVec1.z(), theVec2.z()); |
488 | } |
489 | |
490 | static void CwiseMax (BVH_VecNt& theVec1, const BVH_VecNt& theVec2) |
491 | { |
492 | theVec1.x() = Max (theVec1.x(), theVec2.x()); |
493 | theVec1.y() = Max (theVec1.y(), theVec2.y()); |
494 | theVec1.z() = Max (theVec1.z(), theVec2.z()); |
495 | } |
496 | }; |
497 | |
498 | template<class T> |
499 | struct BoxMinMax<T, 2> |
500 | { |
501 | typedef typename BVH::VectorType<T, 2>::Type BVH_VecNt; |
502 | |
503 | static void CwiseMin (BVH_VecNt& theVec1, const BVH_VecNt& theVec2) |
504 | { |
505 | theVec1.x() = Min (theVec1.x(), theVec2.x()); |
506 | theVec1.y() = Min (theVec1.y(), theVec2.y()); |
507 | } |
508 | |
509 | static void CwiseMax (BVH_VecNt& theVec1, const BVH_VecNt& theVec2) |
510 | { |
511 | theVec1.x() = Max (theVec1.x(), theVec2.x()); |
512 | theVec1.y() = Max (theVec1.y(), theVec2.y()); |
513 | } |
514 | }; |
515 | } |
516 | |
e28f12b3 |
517 | // ======================================================================= |
518 | // function : Combine |
519 | // purpose : |
520 | // ======================================================================= |
521 | template<class T, int N> |
522 | void BVH_Box<T, N>::Combine (const BVH_Box& theBox) |
523 | { |
524 | if (theBox.myIsInited) |
525 | { |
526 | if (!myIsInited) |
527 | { |
528 | myMinPoint = theBox.myMinPoint; |
529 | myMaxPoint = theBox.myMaxPoint; |
530 | myIsInited = Standard_True; |
531 | } |
532 | else |
533 | { |
534 | BVH::BoxMinMax<T, N>::CwiseMin (myMinPoint, theBox.myMinPoint); |
535 | BVH::BoxMinMax<T, N>::CwiseMax (myMaxPoint, theBox.myMaxPoint); |
536 | } |
537 | } |
538 | } |
539 | |
540 | // ======================================================================= |
541 | // function : Area |
542 | // purpose : |
543 | // ======================================================================= |
544 | template<class T, int N> |
545 | T BVH_Box<T, N>::Area() const |
546 | { |
547 | return !myIsInited ? static_cast<T> (0.0) : BVH::SurfaceCalculator<T, N>::Area (myMaxPoint - myMinPoint); |
548 | } |
549 | |
550 | // ======================================================================= |
551 | // function : Center |
552 | // purpose : |
553 | // ======================================================================= |
554 | template<class T, int N> |
555 | T BVH_Box<T, N>::Center (const Standard_Integer theAxis) const |
556 | { |
557 | return BVH::CenterAxis<T, N>::Center (*this, theAxis); |
558 | } |
3c4e78f2 |
559 | |
560 | #endif // _BVH_Box_Header |