source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/AxisAlignedBox3.cpp @ 2802

Revision 2802, 27.5 KB checked in by mattausch, 17 years ago (diff)

worked on renderqueue

Line 
1#include <cassert>
2#include <iostream>
3#include "AxisAlignedBox3.h"
4#include "Plane3.h"
5
6
7using namespace std;
8
9
10namespace CHCDemoEngine
11{
12
13// Overload << operator for C++-style output
14ostream& operator<< (ostream &s, const AxisAlignedBox3 &A)
15{
16        return s << '[' << A.mMin.x << ", " << A.mMin.y << ", " << A.mMin.z << "]["
17                << A.mMax.x << ", " << A.mMax.y << ", " << A.mMax.z << ']';
18}
19
20
21// Overload >> operator for C++-style input
22istream& operator>> (istream &s, AxisAlignedBox3 &A)
23{
24        char a;
25        // read "[min.x, min.y, min.z][mMax.x, mMax.y, mMax.z]"
26        return s >> a >> A.mMin.x >> a >> A.mMin.y >> a >> A.mMin.z >> a >> a
27                >> A.mMax.x >> a >> A.mMax.y >> a >> A.mMax.z >> a;
28}
29
30
31AxisAlignedBox3::AxisAlignedBox3()
32{ }
33
34
35AxisAlignedBox3::AxisAlignedBox3(const Vector3 &nMin, const Vector3 &nMax)
36: mMin(nMin), mMax(nMax)
37{}
38
39
40
41bool AxisAlignedBox3::Unbounded() const
42{
43        return (mMin == Vector3(-MAXFLOAT)) ||
44                (mMax == Vector3(-MAXFLOAT));
45}
46
47
48void AxisAlignedBox3::Include(const Vector3 &newpt)
49{
50        Minimize(mMin, newpt);
51        Maximize(mMax, newpt);
52}
53
54
55void AxisAlignedBox3::Include(const AxisAlignedBox3 &bbox)
56{
57        Minimize(mMin, bbox.mMin);
58        Maximize(mMax, bbox.mMax);
59}
60
61
62bool AxisAlignedBox3::IsCorrect()
63{
64        if ( (mMin.x > mMax.x) ||
65                (mMin.y > mMax.y) ||
66                (mMin.z > mMax.z) )
67                return false; // box is not formed
68        return true;
69}
70
71
72void AxisAlignedBox3::GetEdge(const int edge, Vector3 *a, Vector3 *b) const
73{
74        switch(edge) {
75  case 0:
76          a->SetValue(mMin.x, mMin.y, mMin.z);
77          b->SetValue(mMin.x, mMin.y, mMax.z);
78          break;
79  case 1:
80          a->SetValue(mMin.x, mMin.y, mMin.z);
81          b->SetValue(mMin.x, mMax.y, mMin.z);
82          break;
83  case 2:
84          a->SetValue(mMin.x, mMin.y, mMin.z);
85          b->SetValue(mMax.x, mMin.y, mMin.z);
86          break;
87  case 3:
88          a->SetValue(mMax.x, mMax.y, mMax.z);
89          b->SetValue(mMax.x, mMax.y, mMin.z);
90          break;
91  case 4:
92          a->SetValue(mMax.x, mMax.y, mMax.z);
93          b->SetValue(mMax.x, mMin.y, mMax.z);
94          break;
95  case 5:
96          a->SetValue(mMax.x, mMax.y, mMax.z);
97          b->SetValue(mMin.x, mMax.y, mMax.z);
98          break;
99
100  case 6:
101          a->SetValue(mMin.x, mMin.y, mMax.z);
102          b->SetValue(mMin.x, mMax.y, mMax.z);
103          break;
104  case 7:
105          a->SetValue(mMin.x, mMin.y, mMax.z);
106          b->SetValue(mMax.x, mMin.y, mMax.z);
107          break;
108  case 8:
109          a->SetValue(mMin.x, mMax.y, mMin.z);
110          b->SetValue(mMin.x, mMax.y, mMax.z);
111          break;
112  case 9:
113          a->SetValue(mMin.x, mMax.y, mMin.z);
114          b->SetValue(mMax.x, mMax.y, mMin.z);
115          break;
116  case 10:
117          a->SetValue(mMax.x, mMin.y, mMin.z);
118          b->SetValue(mMax.x, mMax.y, mMin.z);
119          break;
120  case 11:
121          a->SetValue(mMax.x, mMin.y, mMin.z);
122          b->SetValue(mMax.x, mMin.y, mMax.z);
123          break;
124        }
125}
126
127// returns the vertex indices in the range <0..7>, v = 4.x + 2.y + z, where
128// x,y,z are either 0 or 1; (0 .. min coordinate, 1 .. max coordinate)
129void
130AxisAlignedBox3::GetEdge(const int edge, int  &aIdx, int &bIdx) const
131{
132        switch(edge) {
133  case 0: aIdx = 0; bIdx = 1; break;
134  case 1: aIdx = 0; bIdx = 2; break;
135  case 2: aIdx = 0; bIdx = 4; break;
136  case 3: aIdx = 7; bIdx = 6; break;
137  case 4: aIdx = 7; bIdx = 5; break;
138  case 5: aIdx = 7; bIdx = 3; break;
139  case 6: aIdx = 1; bIdx = 3; break;
140  case 7: aIdx = 1; bIdx = 5; break;
141  case 8: aIdx = 2; bIdx = 3; break;
142  case 9: aIdx = 2; bIdx = 6; break;
143  case 10: aIdx = 4; bIdx = 6; break;
144  case 11: aIdx = 4; bIdx = 5; break;
145        }
146}
147
148void
149AxisAlignedBox3::Include(const int &axis, const float &newBound)
150{
151        switch (axis) {
152        case 0: { // x-axis
153                if (mMin.x > newBound)
154                        mMin.x = newBound;
155                if (mMax.x < newBound)
156                        mMax.x = newBound;
157                break;
158                        }
159        case 1: { // y-axis
160                if (mMin.y > newBound)
161                        mMin.y = newBound;
162                if (mMax.y < newBound)
163                        mMax.y = newBound;
164                break;
165                        }
166        case 2: { // z-axis
167                if (mMin.z > newBound)
168                        mMin.z = newBound;
169                if (mMax.z < newBound)
170                        mMax.z = newBound;
171                break;
172                        }
173        }
174}
175
176
177void AxisAlignedBox3::Describe(ostream &app, int ind) const
178{
179        indent(app, ind);
180        app << "AxisAlignedBox3: min at(" << mMin << "), max at(" << mMax << ")\n";
181}
182
183int
184AxisAlignedBox3::IsInside(const Vector3 &v) const
185{
186        return ! ((v.x < mMin.x) ||
187                (v.x > mMax.x) ||
188                (v.y < mMin.y) ||
189                (v.y > mMax.y) ||
190                (v.z < mMin.z) ||
191                (v.z > mMax.z));
192}
193
194
195bool AxisAlignedBox3::Includes(const AxisAlignedBox3 &b) const
196{
197        return (b.mMin.x >= mMin.x &&
198                b.mMin.y >= mMin.y &&
199                b.mMin.z >= mMin.z &&
200                b.mMax.x <= mMax.x &&
201                b.mMax.y <= mMax.y &&
202                b.mMax.z <= mMax.z);
203}
204
205
206// compute the coordinates of one vertex of the box
207Vector3 AxisAlignedBox3::GetVertex(int xAxis, int yAxis, int zAxis) const
208{
209        Vector3 p;
210        if (xAxis)
211                p.x = mMax.x;
212        else
213                p.x = mMin.x;
214
215        if (yAxis)
216                p.y = mMax.y;
217        else
218                p.y = mMin.y;
219
220        if (zAxis)
221                p.z = mMax.z;
222        else
223                p.z = mMin.z;
224        return p;
225}
226
227
228// compute the vertex for number N = <0..7>, N = 4.x + 2.y + z, where
229// x,y,z are either 0 or 1; (0 .. min coordinate, 1 .. max coordinate)
230void AxisAlignedBox3::GetVertex(const int N, Vector3 &vertex) const
231{
232        switch (N)
233        {
234        case 0: vertex = mMin; break;
235        case 1: vertex.SetValue(mMin.x, mMin.y, mMax.z); break;
236        case 2: vertex.SetValue(mMin.x, mMax.y, mMin.z); break;
237        case 3: vertex.SetValue(mMin.x, mMax.y, mMax.z); break;
238        case 4: vertex.SetValue(mMax.x, mMin.y, mMin.z); break;
239        case 5: vertex.SetValue(mMax.x, mMin.y, mMax.z); break;
240        case 6: vertex.SetValue(mMax.x, mMax.y, mMin.z); break;
241        case 7: vertex = mMax; break;
242        default:
243                {
244                        cerr << "ERROR in AxisAlignedBox3::GetVertex N=" << N <<  "\n";
245                }
246        }
247}
248
249
250float AxisAlignedBox3::SurfaceArea() const
251{
252        Vector3 ext = mMax - mMin;
253
254        return 2.0f * (ext.x * ext.y +
255                ext.x * ext.z +
256                ext.y * ext.z);
257}
258
259
260float AxisAlignedBox3::GetVolume() const
261{
262        return (mMax.x - mMin.x) * (mMax.y - mMin.y) * (mMax.z - mMin.z);
263}
264
265
266const int AxisAlignedBox3::bvertices[27][9] =
267{                   // region number.. position
268        {5,1,3,2,6,4,-1,-1,-1},      // 0 .. x=0 y=0 z=0
269        {4,5,1,3,2,0,-1,-1,-1},      // 1 .. x=0 y=0 z=1
270        {4,5,7,3,2,0,-1,-1,-1},      // 2 .. x=0 y=0 z=2
271
272        {0,1,3,2,6,4,-1,-1,-1},      // 3 .. x=0 y=1 z=0
273        {0,1,3,2,-1,-1,-1,-1,-1},    // 4 .. x=0 y=1 z=1
274        {1,5,7,3,2,0,-1,-1,-1},      // 5 .. x=0 y=1 z=2
275
276        {0,1,3,7,6,4,-1,-1,-1},      // 6 .. x=0 y=2 z=0
277        {0,1,3,7,6,2,-1,-1,-1},      // 7 .. x=0 y=2 z=1
278        {1,5,7,6,2,0,-1,-1,-1},      // 8 .. x=0 y=2 z=2
279
280        // the regions number <9,17>
281        {5,1,0,2,6,4,-1,-1,-1},      // 9  .. x=1 y=0 z=0
282        {5,1,0,4,-1,-1,-1,-1,-1},    // 10 .. x=1 y=0 z=1
283        {7,3,1,0,4,5,-1,-1,-1},      // 11 .. x=1 y=0 z=2
284
285        {4,0,2,6,-1,-1,-1,-1,-1},    // 12 .. x=1 y=1 z=0
286        {0,2,3,1,5,4,6,7,-1},        // 13 .. x=1 y=1 z=1 .. inside the box
287        {1,5,7,3,-1,-1,-1,-1,-1},    // 14 .. x=1 y=1 z=2
288
289        {4,0,2,3,7,6,-1,-1,-1},      // 15 .. x=1 y=2 z=0
290        {6,2,3,7,-1,-1,-1,-1,-1},    // 16 .. x=1 y=2 z=1
291        {1,5,7,6,2,3,-1,-1,-1},      // 17 .. x=1 y=2 z=2
292
293        // the regions number <18,26>
294        {1,0,2,6,7,5,-1,-1,-1},      // 18 .. x=2 y=0 z=0
295        {1,0,4,6,7,5,-1,-1,-1},      // 19 .. x=2 y=0 z=1
296        {0,4,6,7,3,1,-1,-1,-1},      // 20 .. x=2 y=0 z=2
297
298        {4,0,2,6,7,5,-1,-1,-1},      // 21 .. x=2 y=1 z=0
299        {5,4,6,7,-1,-1,-1,-1,-1},    // 22 .. x=2 y=1 z=1
300        {5,4,6,7,3,1,-1,-1,-1},      // 23 .. x=2 y=1 z=2
301
302        {4,0,2,3,7,5,-1,-1,-1},      // 24 .. x=2 y=2 z=0
303        {5,4,6,2,3,7,-1,-1,-1},      // 25 .. x=2 y=2 z=1
304        {5,4,6,2,3,1,-1,-1,-1},      // 26 .. x=2 y=2 z=2
305};
306
307// the visibility of boundary faces from a given region
308// one to three triples: (axis, min_vertex, max_vertex), axis==-1(terminator)
309const int AxisAlignedBox3::bfaces[27][10] =
310{                              // region number .. position
311        {0,0,3,1,0,5,2,0,6,-1},      // 0 .. x=0 y=0 z=0
312        {0,0,3,1,0,5,-1,-1,-1,-1},   // 1 .. x=0 y=0 z=1
313        {0,0,3,1,0,5,2,1,7,-1},      // 2 .. x=0 y=0 z=2
314
315        {0,0,3,2,0,6,-1,-1,-1,-1},   // 3 .. x=0 y=1 z=0
316        {0,0,3,-1,-1,-1,-1,-1,-1,-1},// 4 .. x=0 y=1 z=1
317        {0,0,3,2,1,7,-1,-1,-1,-1},   // 5 .. x=0 y=1 z=2
318
319        {0,0,3,1,2,7,2,0,6,-1},      // 6 .. x=0 y=2 z=0
320        {0,0,3,1,2,7,-1,-1,-1,-1},   // 7 .. x=0 y=2 z=1
321        {0,0,3,1,2,7,2,1,7,-1},      // 8 .. x=0 y=2 z=2
322
323        // the regions number <9,17>
324        {1,0,5,2,0,6,-1,-1,-1,-1},   // 9  .. x=1 y=0 z=0
325        {1,0,5,-1,-1,-1,-1,-1,-1,-1},// 10 .. x=1 y=0 z=1
326        {1,0,5,2,1,7,-1,-1,-1,-1},   // 11 .. x=1 y=0 z=2
327
328        {2,0,6,-1,-1,-1,-1,-1,-1,-1},// 12 .. x=1 y=1 z=0
329        {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},// 13 .. x=1 y=1 z=1 .. inside the box
330        {2,1,7,-1,-1,-1,-1,-1,-1,-1},// 14 .. x=1 y=1 z=2
331
332        {1,2,7,2,0,6,-1,-1,-1,-1},   // 15 .. x=1 y=2 z=0
333        {1,2,7,-1,-1,-1,-1,-1,-1,-1},// 16 .. x=1 y=2 z=1
334        {1,2,7,2,1,7,-1,-1,-1,-1},   // 17 .. x=1 y=2 z=2
335
336        // the region number <18,26>
337        {0,4,7,1,0,5,2,0,6,-1},      // 18 .. x=2 y=0 z=0
338        {0,4,7,1,0,5,-1,-1,-1,-1},   // 19 .. x=2 y=0 z=1
339        {0,4,7,1,0,5,2,1,7,-1},      // 20 .. x=2 y=0 z=2
340
341        {0,4,7,2,0,6,-1,-1,-1,-1},   // 21 .. x=2 y=1 z=0
342        {0,4,7,-1,-1,-1,-1,-1,-1,-1},// 22 .. x=2 y=1 z=1
343        {0,4,7,2,1,7,-1,-1,-1,-1},   // 23 .. x=2 y=1 z=2
344
345        {0,4,7,1,2,7,2,0,6,-1},      // 24 .. x=2 y=2 z=0
346        {0,4,7,1,2,7,-1,-1,-1,-1},   // 25 .. x=2 y=2 z=1
347        {0,4,7,1,2,7,2,1,7,-1},      // 26 .. x=2 y=2 z=2
348};
349
350// the correct corners indexing from entry face to exit face
351// first index determines entry face, second index exit face, and
352// the two numbers (indx, inc) determines: ind = the index on the exit
353// face, when starting from the vertex 0 on entry face, 'inc' is
354// the increment when we go on entry face in order 0,1,2,3 to create
355// convex shaft with the rectangle on exit face. That is, inc = -1 or 1.
356const int AxisAlignedBox3::pairFaceRects[6][6][2] = {
357        { // entry face = 0
358                {-1,0}, // exit face 0 .. no meaning
359                {0,-1}, // 1
360                {0,-1}, // 2
361                {0,1}, // 3 .. opposite face
362                {3,1}, // 4
363                {1,1} // 5
364        },
365        { // entry face = 1
366                {0,-1}, // exit face 0
367                {-1,0}, // 1 .. no meaning
368                {0,-1}, // 2
369                {1,1}, // 3
370                {0,1}, // 4 .. opposite face
371                {3,1} // 5
372        },
373        { // entry face = 2
374                {0,-1}, // 0
375                {0,-1}, // 1
376                {-1,0}, // 2 .. no meaning
377                {3,1}, // 3
378                {1,1}, // 4
379                {0,1} // 5 .. opposite face
380        },
381        { // entry face = 3
382                {0,1}, // 0 .. opposite face
383                {3,-1}, // 1
384                {1,1}, // 2
385                {-1,0}, // 3  .. no meaning
386                {0,-1}, // 4
387                {0,-1} // 5
388        },
389        { // entry face = 4
390                {1,1}, // 0
391                {0,1}, // 1 .. opposite face
392                {3,1}, // 2
393                {0,-1}, // 3
394                {-1,0}, // 4 .. no meaning
395                {0,-1} // 5
396        },
397        { // entry face = 5
398                {3,-1}, // 0
399                {1,1}, // 1
400                {0,1}, // 2  .. opposite face
401                {0,-1}, // 3
402                {0,-1}, // 4
403                {-1,0} // 5 .. no meaning
404        }
405};
406
407
408// ------------------------------------------------------------
409// The vertices that form CLOSEST points with respect to the region
410// for all the regions possible, number of regions is 3^3 = 27,
411// since two parallel sides of bbox forms three disjoint spaces.
412// The vertices are given in anti-clockwise order, stopped by value 15,
413// at most 8 points, at least 1 point.
414// The table includes the closest 1/2/4/8 points, followed possibly
415// by the set of coordinates that should be used for testing for
416// the proximity queries. The coordinates to be tested are described by
417// the pair (a,b), when a=0, we want to test min vector of the box,
418//                 when a=1, we want to test max vector of the box
419//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
420// The sequence is ended by 15, number -1 is used as the separator
421// between the vertices and coordinates.
422const int
423AxisAlignedBox3::cvertices[27][9] =
424{                   // region number.. position
425        {0,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D one vertex
426        {0,1,-1,0,0,0,1,15,15},      // 1 .. x=0 y=0 z=1 D two vertices foll. by 2
427        {1,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D one vertex
428
429        {0,2,-1,0,0,0,2,15,15},      // 3 .. x=0 y=1 z=0 D
430        {0,1,3,2,-1,0,0,15,15},      // 4 .. x=0 y=1 z=1 D
431        {1,3,-1,0,0,1,2,15,15},      // 5 .. x=0 y=1 z=2 D
432
433        {2,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
434        {2,3,-1,0,0,1,1,15,15},      // 7 .. x=0 y=2 z=1 D
435        {3,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
436
437        // the regions number <9,17>
438        {0,4,-1,0,1,0,2,15,15},      // 9  .. x=1 y=0 z=0 D
439        {5,1,0,4,-1,0,1,15,15},      // 10 .. x=1 y=0 z=1 D
440        {1,5,-1,0,1,1,2,15,15},      // 11 .. x=1 y=0 z=2 D
441
442        {4,0,2,6,-1,0,2,15,15},      // 12 .. x=1 y=1 z=0 D
443        {0,2,3,1,5,4,6,7,15},        // 13 .. x=1 y=1 z=1 .. inside the box
444        {1,5,7,3,-1,1,2,15,15},      // 14 .. x=1 y=1 z=2 D
445
446        {6,2,-1,0,2,1,1,15,15},      // 15 .. x=1 y=2 z=0 D
447        {6,2,3,7,-1,1,1,15,15},      // 16 .. x=1 y=2 z=1 D
448        {3,7,-1,1,1,1,2,15,15},      // 17 .. x=1 y=2 z=2 D
449
450        // the regions number <18,26>
451        {4,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
452        {4,5,-1,0,1,1,0,15,15},      // 19 .. x=2 y=0 z=1 D
453        {5,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
454
455        {4,6,-1,0,2,1,0,15,15},      // 21 .. x=2 y=1 z=0 D
456        {5,4,6,7,-1,1,0,15,15},      // 22 .. x=2 y=1 z=1 D
457        {7,5,-1,1,0,1,2,15,15},      // 23 .. x=2 y=1 z=2 D
458
459        {6,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
460        {6,7,-1,1,0,1,1,15,15},      // 25 .. x=2 y=2 z=1 D
461        {7,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
462};
463
464// Table for Sphere-AABB intersection based on the region knowledge
465// Similar array to previous cvertices, but we omit the surfaces
466// which are not necessary for testing. First are vertices,
467// they are finished with -1. Second, there are indexes in
468// the pair (a,b), when a=0, we want to test min vector of the box,
469//                 when a=1, we want to test max vector of the box
470//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
471//
472// So either we check the vertices or only the distance in specified
473// dimensions. There are at all four possible cases:
474//
475//   1) we check one vertex - then sequence start with non-negative index
476//      and is finished with 15
477//   2) we check two coordinates of min/max vector describe by the pair
478//         (a,b) .. a=min/max(0/1) b=x/y/z (0/1/2), sequence starts with 8
479//      and finishes with 15
480//   3) we check only one coordinate of min/max, as for 2), sequence start
481//      with 9 and ends with 15
482//   4) Position 13 - sphere is inside the box, intersection always exist
483//        the sequence start with 15 .. no further testing is necessary
484//        in this case
485const int
486AxisAlignedBox3::csvertices[27][6] =
487{                   // region number.. position
488        {0,15,15,15,15,15},  // 0 .. x=0 y=0 z=0 D vertex only
489        {8,0,0,0,1,15},      // 1 .. x=0 y=0 z=1 D two coords.
490        {1,15,15,15,15,15},  // 2 .. x=0 y=0 z=2 D vertex only
491
492        {8,0,0,0,2,15},      // 3 .. x=0 y=1 z=0 D two coords
493        {9,0,0,15,15,15},    // 4 .. x=0 y=1 z=1 D one coord
494        {8,0,0,1,2,15},      // 5 .. x=0 y=1 z=2 D two coords.
495
496        {2,15,15,15,15,15},  // 6 .. x=0 y=2 z=0 D one vertex
497        {8,0,0,1,1,15},      // 7 .. x=0 y=2 z=1 D two coords
498        {3,15,15,15,15,15},  // 8 .. x=0 y=2 z=2 D one vertex
499
500        // the regions number <9,17>
501        {8,0,1,0,2,15},      // 9  .. x=1 y=0 z=0 D two coords
502        {9,0,1,15,15,15},    // 10 .. x=1 y=0 z=1 D one coord
503        {8,0,1,1,2,15},      // 11 .. x=1 y=0 z=2 D two coords
504
505        {9,0,2,15,15,15},    // 12 .. x=1 y=1 z=0 D one coord
506        {15,15,15,15,15,15}, // 13 .. x=1 y=1 z=1 inside the box, special case/value
507        {9,1,2,15,15,15},    // 14 .. x=1 y=1 z=2 D one corrd
508
509        {8,0,2,1,1,15},      // 15 .. x=1 y=2 z=0 D two coords
510        {9,1,1,15,15},       // 16 .. x=1 y=2 z=1 D one coord
511        {8,1,1,1,2,15},      // 17 .. x=1 y=2 z=2 D two coords
512
513        // the regions number <18,26>
514        {4,15,15,15,15,15},  // 18 .. x=2 y=0 z=0 D one vertex
515        {8,0,1,1,0,15},      // 19 .. x=2 y=0 z=1 D two coords
516        {5,15,15,15,15,15},  // 20 .. x=2 y=0 z=2 D one vertex
517
518        {8,0,2,1,0,15},      // 21 .. x=2 y=1 z=0 D two coords
519        {9,1,0,15,15,15},    // 22 .. x=2 y=1 z=1 D one coord
520        {8,1,0,1,2,15},      // 23 .. x=2 y=1 z=2 D two coords
521
522        {6,15,15,15,15,15},  // 24 .. x=2 y=2 z=0 D one vertex
523        {8,1,0,1,1,15},      // 25 .. x=2 y=2 z=1 D two coords
524        {7,15,15,15,15,15},  // 26 .. x=2 y=2 z=2 D one vertex
525};
526
527
528// The vertices that form all FARTHEST points with respect to the region
529// for all the regions possible, number of regions is 3^3 = 27,
530// since two parallel sides of bbox forms three disjoint spaces.
531// The vertices are given in anti-clockwise order, stopped by value 15,
532// at most 8 points, at least 1 point.
533// For testing, if the AABB is whole in the sphere, it is enough
534// to test only vertices, either 1,2,4, or 8.
535const int
536AxisAlignedBox3::fvertices[27][9] =
537{                   // region number.. position
538        {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D
539        {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D
540        {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D
541
542        {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D
543        {4,5,7,6,15,15,15,15,15},    // 4 .. x=0 y=1 z=1 D
544        {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D
545
546        {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
547        {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D
548        {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
549
550        // the regions number <9,17>
551        {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D
552        {7,3,2,6,15,15,15,15,15},    // 10 .. x=1 y=0 z=1 D
553        {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D
554
555        {5,1,3,7,15,15,15,15,15},    // 12 .. x=1 y=1 z=0 D
556        {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
557        {0,4,6,2,15,15,15,15,15},    // 14 .. x=1 y=1 z=2 D
558
559        {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D
560        {4,0,1,5,15,15,15,15,15},    // 16 .. x=1 y=2 z=1 D
561        {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D
562
563        // the regions number <18,26>
564        {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
565        {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D
566        {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
567
568        {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D
569        {1,0,2,3,15,15,15,15,15},    // 22 .. x=2 y=1 z=1 D
570        {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D
571
572        {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
573        {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D
574        {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
575};
576
577// Similar table as above, farthest points, but only the ones
578// necessary for testing the intersection problem. If we do
579// not consider the case 13, center of the sphere is inside the
580// box, then we can always test at most 2 box vertices to say whether
581// the whole box is inside the sphere.
582// The number of vertices is minimized using some assumptions
583// about the ortogonality of vertices and sphere properties.
584const int
585AxisAlignedBox3::fsvertices[27][9] =
586{                   // region number.. position
587        {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D 1 vertex
588        {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D 2 vertices
589        {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D 1 vertex
590
591        {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D 2 vertices
592        {4,7,15,5,6,15,15,15,15},    // 4 .. x=0 y=1 z=1 D 4/2 vertices
593        {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D 2 vertices
594
595        {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D 1 vertex
596        {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D 2 vertices
597        {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D 1 vertex
598
599        // the regions number <9,17>
600        {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D 2 vertices
601        {7,2,15,3,6,15,15,15,15},    // 10 .. x=1 y=0 z=1 D 4/2 vertices
602        {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D 2 vertices
603
604        {5,3,15,1,7,15,15,15,15},    // 12 .. x=1 y=1 z=0 D 4/2 vertices
605        {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
606        {0,6,15,4,2,15,15,15,15},    // 14 .. x=1 y=1 z=2 D 4/2 vertices
607
608        {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D 2 vertices
609        {4,1,15,0,5,15,15,15,15},    // 16 .. x=1 y=2 z=1 D 4/2 vertices
610        {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D 2 vertices
611
612        // the regions number <18,26>
613        {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D 1 vertex
614        {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D 2 vertices
615        {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D 1 vertex
616
617        {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D 2 vertices
618        {1,2,15,0,3,15,15,15,15},    // 22 .. x=2 y=1 z=1 D 4/2 vertices
619        {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D 2 vertices
620
621        {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D 1 vertex
622        {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D 2 vertices
623        {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D 1 vertex
624};
625
626
627// The fast computation of arctangent .. the maximal error is less
628// than 4.1 degrees, according to Graphics GEMSII, 1991, pages 389--391
629// Ron Capelli: "Fast approximation to the arctangent"
630float atan22(const float& y)
631{
632        const float x = 1.0;
633        const float c = (float)(M_PI * 0.25);
634
635        if (y < 0.0) {
636                if (y < -1.0)
637                        return c * (-2.0f + x / y); // for angle in <-PI/2, -PI/4)
638                else
639                        return c * (y / x); // for angle in <-PI/4 , 0>
640        }
641        else {
642                if (y > 1.0)
643                        return c * (2.0f - x / y); // for angle in <PI/4, PI/2>
644                else
645                        return c * (y / x); // for angle in <0, PI/2>
646        }
647}
648
649
650// This definition allows to be a point when answering true
651bool
652AxisAlignedBox3::IsCorrectAndNotPoint() const
653{
654        if ( (mMin.x > mMax.x) ||
655                (mMin.y > mMax.y) ||
656                (mMin.z > mMax.z) )
657                return false; // box is not formed
658
659        if ( (mMin.x == mMax.x) &&
660                (mMin.y == mMax.y) &&
661                (mMin.z == mMax.z) )
662                return false; // degenerates to a point
663
664        return true;
665}
666
667// This definition allows to be a point when answering true
668bool AxisAlignedBox3::IsPoint() const
669{
670        if ( (mMin.x == mMax.x) &&
671                (mMin.y == mMax.y) &&
672                (mMin.z == mMax.z) )
673                return true; // degenerates to a point
674
675        return false;
676}
677
678// This definition requires shape of non-zero volume
679bool AxisAlignedBox3::IsSingularOrIncorrect() const
680{
681        if ( (mMin.x >= mMax.x) ||
682                (mMin.y >= mMax.y) ||
683                (mMin.z >= mMax.z) )
684                return true; // box is not formed
685
686        return false; // has non-zero volume
687}
688
689
690void AxisAlignedBox3::GetSqrDistances(const Vector3 &point,
691                                                                          float &minDistance,
692                                                                          float &maxDistance) const
693{
694        // some overlap is possible, check the distance of vertices
695        float sumMin = 0;
696        float sumMax = 0;
697
698        // Try to minimize the function of a distance
699        // from the sphere center
700
701        const float *minp = &(mMin.x);
702        const float *maxp = &(mMax.x);
703        const float *pcenter = &(point.x);
704
705        // for x-axis
706        for (int i = 0; i < 3; i++, minp++, maxp++, pcenter++) {
707                float minsqr = sqr(*minp - *pcenter);
708                float maxsqr = sqr(*maxp - *pcenter);
709                if (*pcenter < *minp)
710                        sumMin += minsqr;
711                else
712                        if (*pcenter > *maxp)
713                                sumMin += maxsqr;
714                sumMax += (minsqr > maxsqr) ? minsqr : maxsqr;
715        }
716
717        minDistance = sumMin;
718        maxDistance = sumMax;
719}
720
721
722void AxisAlignedBox3::Scale(const float scale)
723{
724        Vector3 newSize = Size()*(scale*0.5f);
725        Vector3 center = Center();
726        mMin = center - newSize;
727        mMax = center + newSize;
728}
729
730
731void AxisAlignedBox3::Scale(const Vector3 &scale)
732{
733        Vector3 newSize = Size()*(scale*0.5f);
734        Vector3 center = Center();
735        mMin = center - newSize;
736        mMax = center + newSize;
737}
738
739
740void AxisAlignedBox3::Translate(const Vector3 &shift)
741{
742        mMin += shift;
743        mMax += shift;
744}
745
746
747void AxisAlignedBox3::Initialize()
748{
749        mMin = Vector3(MAXFLOAT);
750        mMax = Vector3(-MAXFLOAT);
751}
752
753
754Vector3 AxisAlignedBox3::Center() const
755{
756        return 0.5 * (mMin + mMax);
757}
758
759
760Vector3 AxisAlignedBox3::Diagonal() const
761{
762        return (mMax - mMin);
763}
764
765
766float AxisAlignedBox3::Center(const int axis) const
767{
768        return  0.5f * (mMin[axis] + mMax[axis]);
769}
770
771
772float AxisAlignedBox3::Min(const int axis) const
773{
774        return mMin[axis];
775}
776
777
778float AxisAlignedBox3::Max(const int axis) const
779{
780        return  mMax[axis];
781}
782
783
784float AxisAlignedBox3::Size(const int axis) const
785{
786        return  Max(axis) - Min(axis);
787}
788
789// Read-only const access tomMin and max vectors using references
790const Vector3& AxisAlignedBox3::Min() const
791{
792        return mMin;
793}
794
795
796const Vector3& AxisAlignedBox3::Max() const
797{
798        return mMax;
799}
800
801
802void AxisAlignedBox3::Enlarge (const Vector3 &v)
803{
804        mMax += v;
805        mMin -= v;
806}
807
808
809void AxisAlignedBox3::EnlargeToMinSize()
810{
811        const float epsMin = 1e-7f;
812        const float epsAdd = 1e-6f;
813        const float epsMul = 1.000005f;
814        float dir = mMax.x - mMin.x;
815
816        assert(dir >= 0.f);
817
818        if (dir < epsMin)
819        {
820                if (mMax.x > 0)
821                {
822                        mMax.x *= epsMul;
823                        mMax.x += epsAdd;
824                }
825                else
826                {
827                        mMin.x *= epsMul;
828                        mMin.x -= epsAdd;
829                }
830               
831                assert(mMin.x < mMax.x);
832        }
833
834        dir = mMax.y - mMin.y;
835        assert(dir >= 0.f);
836       
837        if (dir < epsMin)
838        {
839                if (mMax.y > 0)
840                {
841                        mMax.y *= epsMul;
842                        mMax.y += epsAdd;
843                }
844                else
845                {
846                        mMin.y *= epsMul;
847                        mMin.y -= epsAdd;
848                }
849                assert(mMin.y < mMax.y);
850        }
851       
852        dir = mMax.z - mMin.z;
853        assert(dir >= 0.f);
854       
855        if (dir < epsMin)
856        {
857                if (mMax.z > 0)
858                {
859                        mMax.z *= epsMul;
860                        mMax.z += epsAdd;
861                }
862                else
863                {
864                        mMin.z *= epsMul;
865                        mMin.z -= epsAdd;
866                }
867               
868                assert(mMin.z < mMax.z);
869        }
870}
871
872
873void AxisAlignedBox3::SetMin(const Vector3 &v)
874{
875        mMin = v;
876}
877
878
879void AxisAlignedBox3::SetMax(const Vector3 &v)
880{
881        mMax = v;
882}
883
884
885void AxisAlignedBox3::SetMin(int axis, const float value)
886{
887        mMin[axis] = value;
888}
889
890
891void AxisAlignedBox3::SetMax(int axis, const float value)
892{
893        mMax[axis] = value;
894}
895
896
897// Decrease box by given splitting plane
898void AxisAlignedBox3::Reduce(int axis, int right, float value)
899{
900        if ((value >=mMin[axis]) && (value <= mMax[axis]))
901        {
902                if (right)
903                        mMin[axis] = value;
904                else
905                        mMax[axis] = value;
906        }
907}
908
909
910Vector3 AxisAlignedBox3::Size() const
911{
912        return mMax - mMin;
913}
914
915
916Vector3 AxisAlignedBox3::GetRandomPoint() const
917{
918        Vector3 size = Size();
919
920        return mMin + Vector3(RandomValue(0.0f, 1.0f),
921                                  RandomValue(0.0f, 1.0f),
922                                                  RandomValue(0.0f, 1.0f)) * Size();
923}
924
925
926bool AxisAlignedBox3::Intersects(const Vector3 &lStart,
927                                                                 const Vector3 &lEnd) const
928{
929        float st, et, fst = 0, fet = 1;
930        float const *bmin = &mMin.x;
931        float const *bmax = &mMax.x;
932        float const *si = &lStart.x;
933        float const *ei = &lEnd.x;
934
935        for (int i = 0; i < 3; ++ i)
936        {
937                if (*si < *ei)
938                {
939                        if (*si > *bmax || *ei < *bmin)
940                                return false;
941
942                        const float di = *ei - *si;
943
944                        st = (*si < *bmin)? (*bmin - *si) / di : 0;
945                        et = (*ei > *bmax)? (*bmax - *si) / di : 1;
946                }
947                else
948                {
949                        if (*ei > *bmax || *si < *bmin)
950                                return false;
951
952                        const float di = *ei - *si;
953
954                        st = (*si > *bmax)? (*bmax - *si) / di : 0;
955                        et = (*ei < *bmin)? (*bmin - *si) / di : 1;
956                }
957
958                if (st > fst) fst = st;
959                if (et < fet) fet = et;
960                if (fet < fst)
961                        return false;
962
963                ++ bmin; ++ bmax;
964                ++ si; ++ ei;
965        }
966
967        //*time = fst;
968        return true;
969}
970
971
972Vector3 AxisAlignedBox3::GetVertex(const int N) const
973{
974        Vector3 v;
975        GetVertex(N, v);
976
977        return v;
978}
979
980
981float AxisAlignedBox3::GetExtent(int face) const
982{
983        if (face < 3)
984                return mMin[face];
985        else
986                return mMax[face - 3];
987}
988
989
990int AxisAlignedBox3::GetIndexNearestVertex(const Vector3 &vecPlaneNormal)
991{
992        int x, y, z;
993
994        x = (vecPlaneNormal.x > 0.0f) ? 0 : 1;
995        y = (vecPlaneNormal.y > 0.0f) ? 0 : 1;
996        z = (vecPlaneNormal.z > 0.0f) ? 0 : 1;
997       
998        return 4 * x + 2 * y + z;
999}
1000
1001
1002int AxisAlignedBox3::GetIndexFarthestVertex(const Vector3 &vecPlaneNormal)
1003{
1004        int x, y, z;
1005
1006        x = (vecPlaneNormal.x <= 0.0f) ? 0 : 1;
1007        y = (vecPlaneNormal.y <= 0.0f) ? 0 : 1;
1008        z = (vecPlaneNormal.z <= 0.0f) ? 0 : 1;
1009       
1010        return 4 * x + 2 * y + z;
1011}
1012
1013
1014float AxisAlignedBox3::GetDistance(int index, const Plane3 &plane) const
1015{
1016        return plane.Distance(GetVertex(index));
1017}
1018
1019
1020float AxisAlignedBox3::GetMinVisibleDistance(const Plane3 &near) const
1021{
1022        return  near.mNormal.x * ((near.mNormal.x > 0.0f) ? mMin.x : mMax.x) +
1023                        near.mNormal.y * ((near.mNormal.y > 0.0f) ? mMin.y : mMax.y) +
1024                        near.mNormal.z * ((near.mNormal.z > 0.0f) ? mMin.z : mMax.z) +
1025                        near.mD;
1026}
1027
1028}
1029
Note: See TracBrowser for help on using the repository browser.