Polygon Crucher SDK - Documentation
Documentation
Loading...
Searching...
No Matches
3DBBox.h
Go to the documentation of this file.
1//! @file 3DBBox.h
2//! @brief C3DBBoxT template class for handling bounding box.
3//
4//////////////////////////////////////////////////////////////////////
5
6#if !defined(BBOX_3D_H)
7#define BBOX_3D_H
8
9#ifdef _MSC_VER
10#pragma once
11#endif // _MSC_VER
12
13#include "3DPoint.h"
14
15BEGIN_MOOTOOLS_NAMESPACE
16
17//! @class C3DTBBox
18//! @brief The class defines a bounding box using int, float or double
19//!
20//! @tparam TYPE
21//! can be int (C3DBBoxI), float (C3DBBox or C3DBBoxF) or double (C3DBBoxD)
22 template <class TYPE>
23class DLL_3DFUNCTION C3DTBBox
24{
25 friend C3DTBBox<int>;
26 friend C3DTBBox<float>;
27 friend C3DTBBox<double>;
28
29protected:
30 bool init;
31 C3DTPoint<TYPE> min, max;
32
33public:
34
35 inline C3DTBBox()
36 {
37 init = false; // not initialized, but valid (null box)
38 }
39
40 inline C3DTBBox(const C3DTPoint<TYPE>& center, TYPE radius)
41 {
42 init = true;
43
44 min.x = center.x-radius;
45 min.y = center.y-radius;
46 min.z = center.z-radius;
47
48 max.x = center.x+radius;
49 max.y = center.y+radius;
50 max.z = center.z+radius;
51 }
52
53 inline C3DTBBox(const C3DTPoint<TYPE>& center, TYPE radiusx, TYPE radiusy, TYPE radiusz)
54 {
55 init = true;
56
57 min.x = center.x - radiusx;
58 min.y = center.y - radiusy;
59 min.z = center.z - radiusz;
60
61 max.x = center.x + radiusx;
62 max.y = center.y + radiusy;
63 max.z = center.z + radiusz;
64 }
65
66 inline void Reinit() //!< @brief Flag the bounding box as not initialized. Must be called to recompute the bbox with a new set of points, using AddPoints / EndPoints
67 {
68 init = false;
69 min = max = C3DTPoint<TYPE>(0, 0, 0); // Reinit the value too
70 }
71
72 inline void InitDone() //!< @brief Useful to call in case no points in bbox (this flag the bbox has initialized)
73 {
74 init = true;
75
76 #if _DEBUG
77 bool anormal = min.IsAnormal();
78 anormal |= max.IsAnormal();
79 XTRACE_IF(anormal, _T("C3DTBBox::InitDone: Invalid bounding box. An anormal coordinate (nan / -inf / inf was collected\n"))
80 #endif
81 }
82
83 inline void AddPoint(const C3DTPoint<TYPE>& pt) //!< @brief Add a point that belong to the bounding box and modify bounding box limit accordingly
84 {
85 if (!init)
86 {
87 init = true;
88 min = pt;
89 max = pt;
90 }
91 else
92 {
93 Min(min, pt);
94 Max(max, pt);
95 }
96 }
97
98 //////////////////////
99 // Mix type conversion (C3DTPoint<float> to C3DTPoint<double> for example)
100 template <class TYPE2> inline C3DTBBox(const C3DTBBox<TYPE2>& bbox)
101 {
102 init = bbox.init;
103 min = bbox.min;
104 max = bbox.max;
105 }
106
107 template <class TYPE2> inline C3DTBBox& operator=(const C3DTBBox<TYPE2>& bbox)
108 {
109 init = bbox.init;
110 min = bbox.min;
111 max = bbox.max;
112 }
113
114
115 inline bool operator==(const C3DTBBox<TYPE>& bbox) const
116 {
117 if (min == bbox.min && max == bbox.max)
118 return true;
119
120 return false;
121 }
122
123 inline bool IsInBox(const C3DTPoint<TYPE>& pt, bool strictlyInside = false) const //!< @brief Returns false if box is invalid or NULL, as it is considered as void box. If strictlyInside, the point cannot be on the box plane
124 {
125 if (!IsValid() || IsNull())
126 return false;
127
128 if (strictlyInside)
129 {
130 // <= => plane are excluded
131 if (pt.x <= min.x)
132 return false;
133 if (pt.y <= min.y)
134 return false;
135 if (pt.z <= min.z)
136 return false;
137
138 if (pt.x >= max.x)
139 return false;
140 if (pt.y >= max.y)
141 return false;
142 if (pt.z >= max.z)
143 return false;
144 }
145 else
146 {
147 // < => plane are included
148 if (pt.x < min.x)
149 return false;
150 if (pt.y < min.y)
151 return false;
152 if (pt.z < min.z)
153 return false;
154
155 if (pt.x > max.x)
156 return false;
157 if (pt.y > max.y)
158 return false;
159 if (pt.z > max.z)
160 return false;
161 }
162
163 return true;
164 }
165
166 inline C3DTVector<TYPE> GetDiagonal() const
167 {
168 if (!IsValid())
169 return C3DTVector<TYPE>(0.0, 0, 0);
170
171 return max-min;
172 }
173
174 inline double GetDiagonalLength() const
175 {
176 if (!IsValid())
177 return 0.0;
178
179 C3DTVector<TYPE> vector(min, max);
180 return vector.Length();
181 }
182
183 inline double GetRadius() const //!< @brief Returns the radius of the sphere that contains the whole bbox
184 {
185 return GetDiagonalLength()/2.0;
186 }
187
188 inline C3DTBBox<TYPE> GetGreaterUniformBBox() const //!< @brief Returns a bbox with same sizes on X,Y,Z axys. This bbox contains the referenced bbox
189 {
190 return C3DTBBox<TYPE>(GetCenter(), (TYPE)GetRadius());
191 }
192
193 inline const C3DTPoint<TYPE>& GetMin() const
194 {
195 return min;
196 }
197
198 inline const C3DTPoint<TYPE>& GetMax() const
199 {
200 return max;
201 }
202
203 inline void SetMinMax(const C3DTPoint<TYPE>& min, const C3DTPoint<TYPE>& max)
204 {
205 this->min = min;
206 this->max = max;
207 init = true;
208 }
209
210 inline double GetMinLength() const
211 {
212 if (!IsValid())
213 return 0.0;
214
215 double lengthx = max.x-min.x;
216 double lengthy = max.y-min.y;
217 double lengthz = max.z-min.z;
218
219 return __min(lengthx, __min(lengthy, lengthz));
220 }
221
222 inline double GetMaxLength() const
223 {
224 if (!IsValid())
225 return 0.0;
226
227 double lengthx = max.x-min.x;
228 double lengthy = max.y-min.y;
229 double lengthz = max.z-min.z;
230
231 return __max(lengthx, __max(lengthy, lengthz));
232 }
233
234
235 // 1 2 3
236 // +-------------+
237 // | |
238 // 4 | 0 | 5
239 // | |
240 // +-------------+
241 // 6 7 8
242 inline double GetProjectionDistance(const C3DTPoint<TYPE>& pt) //!< @brief Returns 0 if the point is inside the bbox, or the distance to a corner, or the distance to the face
243 {
244 double dx = __max(min.x - pt.x, __max(0, pt.x - max.x));
245 double dy = __max(min.y - pt.y, __max(0, pt.y - max.y));
246 double dz = __max(min.z - pt.z, __max(0, pt.z - max.z));
247
248 return sqrt(dx*dx + dy*dy + dz*dz);
249 }
250
251 // 1 2 3
252 // +------+------+
253 // | |
254 // 4 + 0 + 5
255 // | |
256 // +------+------+
257 // 6 7 8
258 inline const C3DTPoint<TYPE> GetProjection(const C3DTPoint<TYPE>& pt) //!< @brief Returns pt.x, pt.y, pt.z, if the point is inside the bbox, or one of the corner, or the projection of the point on the face depending on the situation
259 {
261 if (min.x - pt.x > __max(0, pt.x - max.x))
262 proj.x += (min.x - pt.x);
263 else if (pt.x - max.x > 0)
264 proj.x -= (pt.x - max.x);
265
266 if (min.y - pt.y > __max(0, pt.y - max.y))
267 proj.y += (min.y - pt.y);
268 else if (pt.y - max.y > 0)
269 proj.y -= (pt.y - max.y);
270
271 if (min.z - pt.z > __max(0, pt.z - max.z))
272 proj.z += (min.z - pt.z);
273 else if (pt.z - max.z > 0)
274 proj.z -= (pt.z - max.z);
275
276 return proj;
277 }
278
279 inline C3DTPoint<TYPE> GetClosestCorner(const C3DTPoint<TYPE>& pt) const //!< @brief Returns the closes point of the bbox to the given point
280 {
281 #ifdef _DEBUG
282 bool find = false;
283 #endif
284 double newlength, dist = HUGE_VAL;
285 unsigned char xyz = 0;
286
288 while (xyz < 7)
289 {
290 bboxCorner.x = (xyz & 0x1) ? min.x : max.x;
291 bboxCorner.y = (xyz & 0x2) ? min.y : max.y;
292 bboxCorner.z = (xyz & 0x4) ? min.z : max.z;
293
294 newlength = C3DVector(pt, bboxCorner).Length2();
295 if (newlength < dist)
296 {
297 dist = newlength;
299 #ifdef _DEBUG
300 find = true;
301 #endif
302 }
303
304 xyz++;
305 }
306
307 MOOTOOLS_PRIVATE_ASSERT(find);
308
309 return foundCorner;
310 }
311
312 inline bool GetCenter(C3DTPoint<TYPE>& center) const
313 {
314 if (IsValid())
315 {
316 center = (min + max) / 2.0;
317 return true;
318 }
319
320 center = C3DTPoint<TYPE>(0, 0, 0);
321 return false;
322 }
323
324 inline C3DTPoint<TYPE> GetCenter() const
325 {
326 C3DTPoint<TYPE> center;
327 GetCenter(center);
328
329 return center;
330 }
331
332 inline bool IsNull() const
333 {
334 return (min == max);
335 }
336
337 inline bool IsInitialized() const //!< @brief Useful to know if the bounding box has been computed
338 {
339 return (init != false);
340 }
341
342 //! @brief Invalid bounding box, means that min is greater than max.
343 //! @details If init = false, this only means that bounding box is empty, but it is valid.
344 //! If min == max, then it is valid but null
345 inline bool IsValid() const
346 {
347 if (min.x > max.x)
348 return false;
349 if (min.y > max.y)
350 return false;
351 if (min.z > max.z)
352 return false;
353
354 return true;
355 }
356
357 inline void Inflate(TYPE value)
358 {
359 min.Offset(-value);
360 max.Offset(value);
361 // Remain invalid if invalid
362 }
363
364 inline void Inflate(const C3DTPoint<TYPE>& vector)
365 {
366 min -= vector;
367 max += vector;
368 // Remain invalid if invalid
369 }
370
371 inline void Translate(const C3DTPoint<TYPE>& vector)
372 {
373 min += vector;
374 max += vector;
375 // Remain invalid if invalid
376 }
377
378 inline bool SelfUnion(const C3DTBBox<TYPE>& bbox)
379 {
380 if (!IsValid() || !bbox.IsValid())
381 return false;
382
383 XTRACE_IF(!IsInitialized() || !bbox.IsInitialized(), _T("C3DTBBox::SelfUnion called but bounding box has not been initialized.\nResults may be impredictable.\n"));
384
385 Min(min, bbox.min);
386 Max(max, bbox.max);
387
388 return true;
389 }
390
391 inline C3DTBBox<TYPE> Union(const C3DTBBox<TYPE>& bbox) const
392 {
394 unionBBox.SelfUnion(bbox);
395 return unionBBox;
396 }
397
398 inline bool SelfIntersect(const C3DTBBox<TYPE>& bbox)
399 {
400 if (!IsValid() || !bbox.IsValid())
401 return false;
402
403 XTRACE_IF(!IsInitialized() || !bbox.IsInitialized(), _T("C3DTBBox::SelfUnion called but bounding box has not been initialized.\nResults may be impredictable.\n"));
404
405 Max(min, bbox.min);
406 Min(max, bbox.max);
407
408 if (!IsValid())
409 {
410 max = min; // Make it NULL but still valid
411 return true;
412 }
413
414 return true;
415 }
416
417 inline C3DTBBox<TYPE> Intersect(const C3DTBBox<TYPE>& bbox) const
418 {
420 intersectBBox.SelfIntersect(bbox);
421 return intersectBBox;
422 }
423
424 inline void operator *=(const C4x4TMatrix<TYPE>& matrix)
425 {
426 if (!IsValid())
427 return;
428
429 min *= matrix;
430 max *= matrix;
431
432 C3DTBBox bbox;
433 bbox.AddPoint(min);
434 bbox.AddPoint(max);
435
436 *this = bbox;
437 }
438
439 //! @brief Return true only if ray intersect the bbox which is in front (otherwise dist < 0).
440 //! @details We can know the contact point using point = orig+dir*t
441 //! Note: RayIntersect might be called with the negation of a vector. In that case, 0.0 value is supposed to be always position 0 (+0.0), otherwise we can miss an intersection and t will be negative and it should be positive
442 inline bool RayIntersect(const C3DTPoint<TYPE>& orig, const C3DTVector<TYPE>& dir, double& t)
443 {
444 C3DTVector<TYPE> invDir = dir.InvertCheckZeroSign();
445
446 double tmin, tmax, tymin, tymax, tzmin, tzmax;
447
448 tmin = dir.x < 0 ? max.x : min.x;
449 tmin = (tmin - orig.x) * invDir.x;
450 tmax = dir.x < 0 ? min.x : max.x;
451 tmax = (tmax - orig.x) * invDir.x;
452
453 tymin = dir.y < 0 ? max.y : min.y;
454 tymin = (tymin - orig.y) * invDir.y;
455 tymax = dir.y < 0 ? min.y : max.y;
456 tymax = (tymax - orig.y) * invDir.y;
457
458 if ((tmin > tymax) || (tymin > tmax))
459 return false;
460
461 if (tymin > tmin)
462 tmin = tymin;
463 if (tymax < tmax)
464 tmax = tymax;
465
466 tzmin = dir.z < 0 ? max.z : min.z;
467 tzmin = (tzmin - orig.z) * invDir.z;
468 tzmax = dir.z < 0 ? min.z : max.z;
469 tzmax = (tzmax - orig.z) * invDir.z;
470
471 if ((tmin > tzmax) || (tzmin > tmax))
472 return false;
473
474 if (tzmin > tmin)
475 tmin = tzmin;
476 if (tzmax < tmax)
477 tmax = tzmax;
478
479 t = tmin;
480 if (t < 0)
481 {
482 t = tmax;
483 if (t < 0)
484 return false;
485 }
486
487 return true;
488 }
489
490 inline bool RayIntersect(const C3DTPoint<TYPE>& orig, const C3DTVector<TYPE>& dir, C3DTPoint<TYPE> *hitPt = NULL)
491 {
492 double t;
493 if (RayIntersect(orig, dir, t))
494 {
495 if (hitPt)
496 *hitPt = orig + (dir * t);
497
498 return true;
499 }
500
501 return false;
502 }
503
504#ifdef _DEBUG
505 void Dump() const
506 {
507 XTRACE(_T("Bounding box:\n"));
508 min.Dump();
509 max.Dump();
510 }
511#endif //_DEBUG
512
513};
514
515template<> inline
517{
518 return C3DTBBox<int>(GetCenter(), (int)ceil(GetRadius()));
519}
520
521END_MOOTOOLS_NAMESPACE
522
523#endif // !defined(BBOX_3D_H)
C3DTPoint template class definition for handling x, y, z 3D point coordinate.
The class defines a bounding box using int, float or double.
Definition 3DBBox.h:24
bool IsInBox(const C3DTPoint< TYPE > &pt, bool strictlyInside=false) const
<
Definition 3DBBox.h:123
double GetRadius() const
<
Definition 3DBBox.h:183
C3DTBBox< TYPE > GetGreaterUniformBBox() const
<
Definition 3DBBox.h:188
bool RayIntersect(const C3DTPoint< TYPE > &orig, const C3DTVector< TYPE > &dir, double &t)
Return true only if ray intersect the bbox which is in front (otherwise dist < 0).
Definition 3DBBox.h:442
bool IsValid() const
Invalid bounding box, means that min is greater than max.
Definition 3DBBox.h:345
C3DTPoint< TYPE > GetClosestCorner(const C3DTPoint< TYPE > &pt) const
<
Definition 3DBBox.h:279
bool IsInitialized() const
<
Definition 3DBBox.h:337
The class defines an x, y, z 3D point which can use int, float or double.
Definition 3DPoint.h:27
bool IsAnormal() const
either infinite or nan. Zero and denormalized value are allowed.
Definition 3DPoint.inl:177
void Offset(TYPE value)
Add value to x, y, z.
Definition 3DPoint.inl:169