source: GTP/trunk/App/Demos/Vis/CHC_revisited/src/AxisAlignedBox3.cpp @ 2782

Revision 2782, 27.9 KB checked in by mattausch, 16 years ago (diff)
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                        exit(0);
246                }
247        }
248}
249
250
251float AxisAlignedBox3::SurfaceArea() const
252{
253        Vector3 ext = mMax - mMin;
254
255        return 2.0f * (ext.x * ext.y +
256                ext.x * ext.z +
257                ext.y * ext.z);
258}
259
260
261float AxisAlignedBox3::GetVolume() const
262{
263        return (mMax.x - mMin.x) * (mMax.y - mMin.y) * (mMax.z - mMin.z);
264}
265
266
267const int AxisAlignedBox3::bvertices[27][9] =
268{                   // region number.. position
269        {5,1,3,2,6,4,-1,-1,-1},      // 0 .. x=0 y=0 z=0
270        {4,5,1,3,2,0,-1,-1,-1},      // 1 .. x=0 y=0 z=1
271        {4,5,7,3,2,0,-1,-1,-1},      // 2 .. x=0 y=0 z=2
272
273        {0,1,3,2,6,4,-1,-1,-1},      // 3 .. x=0 y=1 z=0
274        {0,1,3,2,-1,-1,-1,-1,-1},    // 4 .. x=0 y=1 z=1
275        {1,5,7,3,2,0,-1,-1,-1},      // 5 .. x=0 y=1 z=2
276
277        {0,1,3,7,6,4,-1,-1,-1},      // 6 .. x=0 y=2 z=0
278        {0,1,3,7,6,2,-1,-1,-1},      // 7 .. x=0 y=2 z=1
279        {1,5,7,6,2,0,-1,-1,-1},      // 8 .. x=0 y=2 z=2
280
281        // the regions number <9,17>
282        {5,1,0,2,6,4,-1,-1,-1},      // 9  .. x=1 y=0 z=0
283        {5,1,0,4,-1,-1,-1,-1,-1},    // 10 .. x=1 y=0 z=1
284        {7,3,1,0,4,5,-1,-1,-1},      // 11 .. x=1 y=0 z=2
285
286        {4,0,2,6,-1,-1,-1,-1,-1},    // 12 .. x=1 y=1 z=0
287        {0,2,3,1,5,4,6,7,-1},        // 13 .. x=1 y=1 z=1 .. inside the box
288        {1,5,7,3,-1,-1,-1,-1,-1},    // 14 .. x=1 y=1 z=2
289
290        {4,0,2,3,7,6,-1,-1,-1},      // 15 .. x=1 y=2 z=0
291        {6,2,3,7,-1,-1,-1,-1,-1},    // 16 .. x=1 y=2 z=1
292        {1,5,7,6,2,3,-1,-1,-1},      // 17 .. x=1 y=2 z=2
293
294        // the regions number <18,26>
295        {1,0,2,6,7,5,-1,-1,-1},      // 18 .. x=2 y=0 z=0
296        {1,0,4,6,7,5,-1,-1,-1},      // 19 .. x=2 y=0 z=1
297        {0,4,6,7,3,1,-1,-1,-1},      // 20 .. x=2 y=0 z=2
298
299        {4,0,2,6,7,5,-1,-1,-1},      // 21 .. x=2 y=1 z=0
300        {5,4,6,7,-1,-1,-1,-1,-1},    // 22 .. x=2 y=1 z=1
301        {5,4,6,7,3,1,-1,-1,-1},      // 23 .. x=2 y=1 z=2
302
303        {4,0,2,3,7,5,-1,-1,-1},      // 24 .. x=2 y=2 z=0
304        {5,4,6,2,3,7,-1,-1,-1},      // 25 .. x=2 y=2 z=1
305        {5,4,6,2,3,1,-1,-1,-1},      // 26 .. x=2 y=2 z=2
306};
307
308// the visibility of boundary faces from a given region
309// one to three triples: (axis, min_vertex, max_vertex), axis==-1(terminator)
310const int AxisAlignedBox3::bfaces[27][10] =
311{                              // region number .. position
312        {0,0,3,1,0,5,2,0,6,-1},      // 0 .. x=0 y=0 z=0
313        {0,0,3,1,0,5,-1,-1,-1,-1},   // 1 .. x=0 y=0 z=1
314        {0,0,3,1,0,5,2,1,7,-1},      // 2 .. x=0 y=0 z=2
315
316        {0,0,3,2,0,6,-1,-1,-1,-1},   // 3 .. x=0 y=1 z=0
317        {0,0,3,-1,-1,-1,-1,-1,-1,-1},// 4 .. x=0 y=1 z=1
318        {0,0,3,2,1,7,-1,-1,-1,-1},   // 5 .. x=0 y=1 z=2
319
320        {0,0,3,1,2,7,2,0,6,-1},      // 6 .. x=0 y=2 z=0
321        {0,0,3,1,2,7,-1,-1,-1,-1},   // 7 .. x=0 y=2 z=1
322        {0,0,3,1,2,7,2,1,7,-1},      // 8 .. x=0 y=2 z=2
323
324        // the regions number <9,17>
325        {1,0,5,2,0,6,-1,-1,-1,-1},   // 9  .. x=1 y=0 z=0
326        {1,0,5,-1,-1,-1,-1,-1,-1,-1},// 10 .. x=1 y=0 z=1
327        {1,0,5,2,1,7,-1,-1,-1,-1},   // 11 .. x=1 y=0 z=2
328
329        {2,0,6,-1,-1,-1,-1,-1,-1,-1},// 12 .. x=1 y=1 z=0
330        {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},// 13 .. x=1 y=1 z=1 .. inside the box
331        {2,1,7,-1,-1,-1,-1,-1,-1,-1},// 14 .. x=1 y=1 z=2
332
333        {1,2,7,2,0,6,-1,-1,-1,-1},   // 15 .. x=1 y=2 z=0
334        {1,2,7,-1,-1,-1,-1,-1,-1,-1},// 16 .. x=1 y=2 z=1
335        {1,2,7,2,1,7,-1,-1,-1,-1},   // 17 .. x=1 y=2 z=2
336
337        // the region number <18,26>
338        {0,4,7,1,0,5,2,0,6,-1},      // 18 .. x=2 y=0 z=0
339        {0,4,7,1,0,5,-1,-1,-1,-1},   // 19 .. x=2 y=0 z=1
340        {0,4,7,1,0,5,2,1,7,-1},      // 20 .. x=2 y=0 z=2
341
342        {0,4,7,2,0,6,-1,-1,-1,-1},   // 21 .. x=2 y=1 z=0
343        {0,4,7,-1,-1,-1,-1,-1,-1,-1},// 22 .. x=2 y=1 z=1
344        {0,4,7,2,1,7,-1,-1,-1,-1},   // 23 .. x=2 y=1 z=2
345
346        {0,4,7,1,2,7,2,0,6,-1},      // 24 .. x=2 y=2 z=0
347        {0,4,7,1,2,7,-1,-1,-1,-1},   // 25 .. x=2 y=2 z=1
348        {0,4,7,1,2,7,2,1,7,-1},      // 26 .. x=2 y=2 z=2
349};
350
351// the correct corners indexing from entry face to exit face
352// first index determines entry face, second index exit face, and
353// the two numbers (indx, inc) determines: ind = the index on the exit
354// face, when starting from the vertex 0 on entry face, 'inc' is
355// the increment when we go on entry face in order 0,1,2,3 to create
356// convex shaft with the rectangle on exit face. That is, inc = -1 or 1.
357const int AxisAlignedBox3::pairFaceRects[6][6][2] = {
358        { // entry face = 0
359                {-1,0}, // exit face 0 .. no meaning
360                {0,-1}, // 1
361                {0,-1}, // 2
362                {0,1}, // 3 .. opposite face
363                {3,1}, // 4
364                {1,1} // 5
365        },
366        { // entry face = 1
367                {0,-1}, // exit face 0
368                {-1,0}, // 1 .. no meaning
369                {0,-1}, // 2
370                {1,1}, // 3
371                {0,1}, // 4 .. opposite face
372                {3,1} // 5
373        },
374        { // entry face = 2
375                {0,-1}, // 0
376                {0,-1}, // 1
377                {-1,0}, // 2 .. no meaning
378                {3,1}, // 3
379                {1,1}, // 4
380                {0,1} // 5 .. opposite face
381        },
382        { // entry face = 3
383                {0,1}, // 0 .. opposite face
384                {3,-1}, // 1
385                {1,1}, // 2
386                {-1,0}, // 3  .. no meaning
387                {0,-1}, // 4
388                {0,-1} // 5
389        },
390        { // entry face = 4
391                {1,1}, // 0
392                {0,1}, // 1 .. opposite face
393                {3,1}, // 2
394                {0,-1}, // 3
395                {-1,0}, // 4 .. no meaning
396                {0,-1} // 5
397        },
398        { // entry face = 5
399                {3,-1}, // 0
400                {1,1}, // 1
401                {0,1}, // 2  .. opposite face
402                {0,-1}, // 3
403                {0,-1}, // 4
404                {-1,0} // 5 .. no meaning
405        }
406};
407
408
409// ------------------------------------------------------------
410// The vertices that form CLOSEST points with respect to the region
411// for all the regions possible, number of regions is 3^3 = 27,
412// since two parallel sides of bbox forms three disjoint spaces.
413// The vertices are given in anti-clockwise order, stopped by value 15,
414// at most 8 points, at least 1 point.
415// The table includes the closest 1/2/4/8 points, followed possibly
416// by the set of coordinates that should be used for testing for
417// the proximity queries. The coordinates to be tested are described by
418// the pair (a,b), when a=0, we want to test min vector of the box,
419//                 when a=1, we want to test max vector of the box
420//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
421// The sequence is ended by 15, number -1 is used as the separator
422// between the vertices and coordinates.
423const int
424AxisAlignedBox3::cvertices[27][9] =
425{                   // region number.. position
426        {0,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D one vertex
427        {0,1,-1,0,0,0,1,15,15},      // 1 .. x=0 y=0 z=1 D two vertices foll. by 2
428        {1,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D one vertex
429
430        {0,2,-1,0,0,0,2,15,15},      // 3 .. x=0 y=1 z=0 D
431        {0,1,3,2,-1,0,0,15,15},      // 4 .. x=0 y=1 z=1 D
432        {1,3,-1,0,0,1,2,15,15},      // 5 .. x=0 y=1 z=2 D
433
434        {2,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
435        {2,3,-1,0,0,1,1,15,15},      // 7 .. x=0 y=2 z=1 D
436        {3,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
437
438        // the regions number <9,17>
439        {0,4,-1,0,1,0,2,15,15},      // 9  .. x=1 y=0 z=0 D
440        {5,1,0,4,-1,0,1,15,15},      // 10 .. x=1 y=0 z=1 D
441        {1,5,-1,0,1,1,2,15,15},      // 11 .. x=1 y=0 z=2 D
442
443        {4,0,2,6,-1,0,2,15,15},      // 12 .. x=1 y=1 z=0 D
444        {0,2,3,1,5,4,6,7,15},        // 13 .. x=1 y=1 z=1 .. inside the box
445        {1,5,7,3,-1,1,2,15,15},      // 14 .. x=1 y=1 z=2 D
446
447        {6,2,-1,0,2,1,1,15,15},      // 15 .. x=1 y=2 z=0 D
448        {6,2,3,7,-1,1,1,15,15},      // 16 .. x=1 y=2 z=1 D
449        {3,7,-1,1,1,1,2,15,15},      // 17 .. x=1 y=2 z=2 D
450
451        // the regions number <18,26>
452        {4,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
453        {4,5,-1,0,1,1,0,15,15},      // 19 .. x=2 y=0 z=1 D
454        {5,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
455
456        {4,6,-1,0,2,1,0,15,15},      // 21 .. x=2 y=1 z=0 D
457        {5,4,6,7,-1,1,0,15,15},      // 22 .. x=2 y=1 z=1 D
458        {7,5,-1,1,0,1,2,15,15},      // 23 .. x=2 y=1 z=2 D
459
460        {6,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
461        {6,7,-1,1,0,1,1,15,15},      // 25 .. x=2 y=2 z=1 D
462        {7,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
463};
464
465// Table for Sphere-AABB intersection based on the region knowledge
466// Similar array to previous cvertices, but we omit the surfaces
467// which are not necessary for testing. First are vertices,
468// they are finished with -1. Second, there are indexes in
469// the pair (a,b), when a=0, we want to test min vector of the box,
470//                 when a=1, we want to test max vector of the box
471//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
472//
473// So either we check the vertices or only the distance in specified
474// dimensions. There are at all four possible cases:
475//
476//   1) we check one vertex - then sequence start with non-negative index
477//      and is finished with 15
478//   2) we check two coordinates of min/max vector describe by the pair
479//         (a,b) .. a=min/max(0/1) b=x/y/z (0/1/2), sequence starts with 8
480//      and finishes with 15
481//   3) we check only one coordinate of min/max, as for 2), sequence start
482//      with 9 and ends with 15
483//   4) Position 13 - sphere is inside the box, intersection always exist
484//        the sequence start with 15 .. no further testing is necessary
485//        in this case
486const int
487AxisAlignedBox3::csvertices[27][6] =
488{                   // region number.. position
489        {0,15,15,15,15,15},  // 0 .. x=0 y=0 z=0 D vertex only
490        {8,0,0,0,1,15},      // 1 .. x=0 y=0 z=1 D two coords.
491        {1,15,15,15,15,15},  // 2 .. x=0 y=0 z=2 D vertex only
492
493        {8,0,0,0,2,15},      // 3 .. x=0 y=1 z=0 D two coords
494        {9,0,0,15,15,15},    // 4 .. x=0 y=1 z=1 D one coord
495        {8,0,0,1,2,15},      // 5 .. x=0 y=1 z=2 D two coords.
496
497        {2,15,15,15,15,15},  // 6 .. x=0 y=2 z=0 D one vertex
498        {8,0,0,1,1,15},      // 7 .. x=0 y=2 z=1 D two coords
499        {3,15,15,15,15,15},  // 8 .. x=0 y=2 z=2 D one vertex
500
501        // the regions number <9,17>
502        {8,0,1,0,2,15},      // 9  .. x=1 y=0 z=0 D two coords
503        {9,0,1,15,15,15},    // 10 .. x=1 y=0 z=1 D one coord
504        {8,0,1,1,2,15},      // 11 .. x=1 y=0 z=2 D two coords
505
506        {9,0,2,15,15,15},    // 12 .. x=1 y=1 z=0 D one coord
507        {15,15,15,15,15,15}, // 13 .. x=1 y=1 z=1 inside the box, special case/value
508        {9,1,2,15,15,15},    // 14 .. x=1 y=1 z=2 D one corrd
509
510        {8,0,2,1,1,15},      // 15 .. x=1 y=2 z=0 D two coords
511        {9,1,1,15,15},       // 16 .. x=1 y=2 z=1 D one coord
512        {8,1,1,1,2,15},      // 17 .. x=1 y=2 z=2 D two coords
513
514        // the regions number <18,26>
515        {4,15,15,15,15,15},  // 18 .. x=2 y=0 z=0 D one vertex
516        {8,0,1,1,0,15},      // 19 .. x=2 y=0 z=1 D two coords
517        {5,15,15,15,15,15},  // 20 .. x=2 y=0 z=2 D one vertex
518
519        {8,0,2,1,0,15},      // 21 .. x=2 y=1 z=0 D two coords
520        {9,1,0,15,15,15},    // 22 .. x=2 y=1 z=1 D one coord
521        {8,1,0,1,2,15},      // 23 .. x=2 y=1 z=2 D two coords
522
523        {6,15,15,15,15,15},  // 24 .. x=2 y=2 z=0 D one vertex
524        {8,1,0,1,1,15},      // 25 .. x=2 y=2 z=1 D two coords
525        {7,15,15,15,15,15},  // 26 .. x=2 y=2 z=2 D one vertex
526};
527
528
529// The vertices that form all FARTHEST points with respect to the region
530// for all the regions possible, number of regions is 3^3 = 27,
531// since two parallel sides of bbox forms three disjoint spaces.
532// The vertices are given in anti-clockwise order, stopped by value 15,
533// at most 8 points, at least 1 point.
534// For testing, if the AABB is whole in the sphere, it is enough
535// to test only vertices, either 1,2,4, or 8.
536const int
537AxisAlignedBox3::fvertices[27][9] =
538{                   // region number.. position
539        {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D
540        {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D
541        {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D
542
543        {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D
544        {4,5,7,6,15,15,15,15,15},    // 4 .. x=0 y=1 z=1 D
545        {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D
546
547        {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
548        {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D
549        {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
550
551        // the regions number <9,17>
552        {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D
553        {7,3,2,6,15,15,15,15,15},    // 10 .. x=1 y=0 z=1 D
554        {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D
555
556        {5,1,3,7,15,15,15,15,15},    // 12 .. x=1 y=1 z=0 D
557        {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
558        {0,4,6,2,15,15,15,15,15},    // 14 .. x=1 y=1 z=2 D
559
560        {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D
561        {4,0,1,5,15,15,15,15,15},    // 16 .. x=1 y=2 z=1 D
562        {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D
563
564        // the regions number <18,26>
565        {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
566        {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D
567        {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
568
569        {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D
570        {1,0,2,3,15,15,15,15,15},    // 22 .. x=2 y=1 z=1 D
571        {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D
572
573        {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
574        {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D
575        {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
576};
577
578// Similar table as above, farthest points, but only the ones
579// necessary for testing the intersection problem. If we do
580// not consider the case 13, center of the sphere is inside the
581// box, then we can always test at most 2 box vertices to say whether
582// the whole box is inside the sphere.
583// The number of vertices is minimized using some assumptions
584// about the ortogonality of vertices and sphere properties.
585const int
586AxisAlignedBox3::fsvertices[27][9] =
587{                   // region number.. position
588        {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D 1 vertex
589        {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D 2 vertices
590        {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D 1 vertex
591
592        {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D 2 vertices
593        {4,7,15,5,6,15,15,15,15},    // 4 .. x=0 y=1 z=1 D 4/2 vertices
594        {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D 2 vertices
595
596        {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D 1 vertex
597        {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D 2 vertices
598        {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D 1 vertex
599
600        // the regions number <9,17>
601        {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D 2 vertices
602        {7,2,15,3,6,15,15,15,15},    // 10 .. x=1 y=0 z=1 D 4/2 vertices
603        {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D 2 vertices
604
605        {5,3,15,1,7,15,15,15,15},    // 12 .. x=1 y=1 z=0 D 4/2 vertices
606        {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
607        {0,6,15,4,2,15,15,15,15},    // 14 .. x=1 y=1 z=2 D 4/2 vertices
608
609        {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D 2 vertices
610        {4,1,15,0,5,15,15,15,15},    // 16 .. x=1 y=2 z=1 D 4/2 vertices
611        {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D 2 vertices
612
613        // the regions number <18,26>
614        {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D 1 vertex
615        {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D 2 vertices
616        {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D 1 vertex
617
618        {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D 2 vertices
619        {1,2,15,0,3,15,15,15,15},    // 22 .. x=2 y=1 z=1 D 4/2 vertices
620        {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D 2 vertices
621
622        {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D 1 vertex
623        {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D 2 vertices
624        {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D 1 vertex
625};
626
627
628// The fast computation of arctangent .. the maximal error is less
629// than 4.1 degrees, according to Graphics GEMSII, 1991, pages 389--391
630// Ron Capelli: "Fast approximation to the arctangent"
631float atan22(const float& y)
632{
633        const float x = 1.0;
634        const float c = (float)(M_PI * 0.25);
635
636        if (y < 0.0) {
637                if (y < -1.0)
638                        return c * (-2.0f + x / y); // for angle in <-PI/2, -PI/4)
639                else
640                        return c * (y / x); // for angle in <-PI/4 , 0>
641        }
642        else {
643                if (y > 1.0)
644                        return c * (2.0f - x / y); // for angle in <PI/4, PI/2>
645                else
646                        return c * (y / x); // for angle in <0, PI/2>
647        }
648}
649
650
651// This definition allows to be a point when answering true
652bool
653AxisAlignedBox3::IsCorrectAndNotPoint() const
654{
655        if ( (mMin.x > mMax.x) ||
656                (mMin.y > mMax.y) ||
657                (mMin.z > mMax.z) )
658                return false; // box is not formed
659
660        if ( (mMin.x == mMax.x) &&
661                (mMin.y == mMax.y) &&
662                (mMin.z == mMax.z) )
663                return false; // degenerates to a point
664
665        return true;
666}
667
668// This definition allows to be a point when answering true
669bool AxisAlignedBox3::IsPoint() const
670{
671        if ( (mMin.x == mMax.x) &&
672                (mMin.y == mMax.y) &&
673                (mMin.z == mMax.z) )
674                return true; // degenerates to a point
675
676        return false;
677}
678
679// This definition requires shape of non-zero volume
680bool AxisAlignedBox3::IsSingularOrIncorrect() const
681{
682        if ( (mMin.x >= mMax.x) ||
683                (mMin.y >= mMax.y) ||
684                (mMin.z >= mMax.z) )
685                return true; // box is not formed
686
687        return false; // has non-zero volume
688}
689
690
691void AxisAlignedBox3::GetSqrDistances(const Vector3 &point,
692                                                                          float &minDistance,
693                                                                          float &maxDistance) const
694{
695        // some overlap is possible, check the distance of vertices
696        float sumMin = 0;
697        float sumMax = 0;
698
699        // Try to minimize the function of a distance
700        // from the sphere center
701
702        const float *minp = &(mMin.x);
703        const float *maxp = &(mMax.x);
704        const float *pcenter = &(point.x);
705
706        // for x-axis
707        for (int i = 0; i < 3; i++, minp++, maxp++, pcenter++) {
708                float minsqr = sqr(*minp - *pcenter);
709                float maxsqr = sqr(*maxp - *pcenter);
710                if (*pcenter < *minp)
711                        sumMin += minsqr;
712                else
713                        if (*pcenter > *maxp)
714                                sumMin += maxsqr;
715                sumMax += (minsqr > maxsqr) ? minsqr : maxsqr;
716        }
717
718        minDistance = sumMin;
719        maxDistance = sumMax;
720}
721
722
723void AxisAlignedBox3::Scale(const float scale)
724{
725        Vector3 newSize = Size()*(scale*0.5f);
726        Vector3 center = Center();
727        mMin = center - newSize;
728        mMax = center + newSize;
729}
730
731
732void AxisAlignedBox3::Scale(const Vector3 &scale)
733{
734        Vector3 newSize = Size()*(scale*0.5f);
735        Vector3 center = Center();
736        mMin = center - newSize;
737        mMax = center + newSize;
738}
739
740
741void AxisAlignedBox3::Translate(const Vector3 &shift)
742{
743        mMin += shift;
744        mMax += shift;
745}
746
747
748void AxisAlignedBox3::Initialize()
749{
750        mMin = Vector3(MAXFLOAT);
751        mMax = Vector3(-MAXFLOAT);
752}
753
754
755Vector3 AxisAlignedBox3::Center() const
756{
757        return 0.5 * (mMin + mMax);
758}
759
760
761Vector3 AxisAlignedBox3::Diagonal() const
762{
763        return (mMax - mMin);
764}
765
766
767float AxisAlignedBox3::Center(const int axis) const
768{
769        return  0.5f * (mMin[axis] + mMax[axis]);
770}
771
772
773float AxisAlignedBox3::Min(const int axis) const
774{
775        return mMin[axis];
776}
777
778
779float AxisAlignedBox3::Max(const int axis) const
780{
781        return  mMax[axis];
782}
783
784
785float AxisAlignedBox3::Size(const int axis) const
786{
787        return  Max(axis) - Min(axis);
788}
789
790// Read-only const access tomMin and max vectors using references
791const Vector3& AxisAlignedBox3::Min() const
792{
793        return mMin;
794}
795
796
797const Vector3& AxisAlignedBox3::Max() const
798{
799        return mMax;
800}
801
802
803void AxisAlignedBox3::Enlarge (const Vector3 &v)
804{
805        mMax += v;
806        mMin -= v;
807}
808
809
810void AxisAlignedBox3::EnlargeToMinSize()
811{
812        const float epsMin = 1e-7f;
813        const float epsAdd = 1e-6f;
814        const float epsMul = 1.000005f;
815        float dir = mMax.x - mMin.x;
816
817        assert(dir >= 0.f);
818
819        if (dir < epsMin)
820        {
821                if (mMax.x > 0)
822                {
823                        mMax.x *= epsMul;
824                        mMax.x += epsAdd;
825                }
826                else
827                {
828                        mMin.x *= epsMul;
829                        mMin.x -= epsAdd;
830                }
831               
832                assert(mMin.x < mMax.x);
833        }
834
835        dir = mMax.y - mMin.y;
836        assert(dir >= 0.f);
837       
838        if (dir < epsMin)
839        {
840                if (mMax.y > 0)
841                {
842                        mMax.y *= epsMul;
843                        mMax.y += epsAdd;
844                }
845                else
846                {
847                        mMin.y *= epsMul;
848                        mMin.y -= epsAdd;
849                }
850                assert(mMin.y < mMax.y);
851        }
852       
853        dir = mMax.z - mMin.z;
854        assert(dir >= 0.f);
855       
856        if (dir < epsMin)
857        {
858                if (mMax.z > 0)
859                {
860                        mMax.z *= epsMul;
861                        mMax.z += epsAdd;
862                }
863                else
864                {
865                        mMin.z *= epsMul;
866                        mMin.z -= epsAdd;
867                }
868               
869                assert(mMin.z < mMax.z);
870        }
871}
872
873
874void AxisAlignedBox3::SetMin(const Vector3 &v)
875{
876        mMin = v;
877}
878
879
880void AxisAlignedBox3::SetMax(const Vector3 &v)
881{
882        mMax = v;
883}
884
885
886void AxisAlignedBox3::SetMin(int axis, const float value)
887{
888        mMin[axis] = value;
889}
890
891
892void AxisAlignedBox3::SetMax(int axis, const float value)
893{
894        mMax[axis] = value;
895}
896
897
898// Decrease box by given splitting plane
899void AxisAlignedBox3::Reduce(int axis, int right, float value)
900{
901        if ((value >=mMin[axis]) && (value <= mMax[axis]))
902        {
903                if (right)
904                        mMin[axis] = value;
905                else
906                        mMax[axis] = value;
907        }
908}
909
910
911Vector3 AxisAlignedBox3::Size() const
912{
913        return mMax - mMin;
914}
915
916
917Vector3 AxisAlignedBox3::GetRandomPoint() const
918{
919        Vector3 size = Size();
920
921        return mMin + Vector3(RandomValue(0.0f, 1.0f),
922                                  RandomValue(0.0f, 1.0f),
923                                                  RandomValue(0.0f, 1.0f)) * Size();
924}
925
926
927bool AxisAlignedBox3::Intersects(const Vector3 &lStart,
928                                                                 const Vector3 &lEnd) const
929{
930        float st, et, fst = 0, fet = 1;
931        float const *bmin = &mMin.x;
932        float const *bmax = &mMax.x;
933        float const *si = &lStart.x;
934        float const *ei = &lEnd.x;
935
936        for (int i = 0; i < 3; ++ i)
937        {
938                if (*si < *ei)
939                {
940                        if (*si > *bmax || *ei < *bmin)
941                                return false;
942
943                        const float di = *ei - *si;
944
945                        st = (*si < *bmin)? (*bmin - *si) / di : 0;
946                        et = (*ei > *bmax)? (*bmax - *si) / di : 1;
947                }
948                else
949                {
950                        if (*ei > *bmax || *si < *bmin)
951                                return false;
952
953                        const float di = *ei - *si;
954
955                        st = (*si > *bmax)? (*bmax - *si) / di : 0;
956                        et = (*ei < *bmin)? (*bmin - *si) / di : 1;
957                }
958
959                if (st > fst) fst = st;
960                if (et < fet) fet = et;
961                if (fet < fst)
962                        return false;
963
964                ++ bmin; ++ bmax;
965                ++ si; ++ ei;
966        }
967
968        //*time = fst;
969        return true;
970}
971
972
973Vector3 AxisAlignedBox3::GetVertex(const int N) const
974{
975        Vector3 v;
976        GetVertex(N, v);
977
978        return v;
979}
980
981
982float AxisAlignedBox3::GetExtent(int face) const
983{
984        if (face < 3)
985                return mMin[face];
986        else
987                return mMax[face - 3];
988}
989
990//int AxisAlignedBox3::GetIndexFarthestVertex(const Vector3 &vecPlaneNormal)
991int AxisAlignedBox3::GetIndexNearestVertex(const Vector3 &vecPlaneNormal)
992{
993        int x, y, z;
994
995        x = (vecPlaneNormal.x > 0.0f) ? 0 : 1;
996        y = (vecPlaneNormal.y > 0.0f) ? 0 : 1;
997        z = (vecPlaneNormal.z > 0.0f) ? 0 : 1;
998       
999        return 4 * x + 2 * y + z;
1000}
1001
1002
1003//int AxisAlignedBox3::GetIndexNearestVertex(const Vector3 &vecPlaneNormal)
1004int AxisAlignedBox3::GetIndexFarthestVertex(const Vector3 &vecPlaneNormal)
1005{
1006        int x, y, z;
1007
1008        x = (vecPlaneNormal.x <= 0.0f) ? 0 : 1;
1009        y = (vecPlaneNormal.y <= 0.0f) ? 0 : 1;
1010        z = (vecPlaneNormal.z <= 0.0f) ? 0 : 1;
1011       
1012        return 4 * x + 2 * y + z;
1013
1014        /*int index;
1015
1016        if (vecPlaneNormal.x <= 0.0f)
1017                index = (vecPlaneNormal.y <= 0.0f) ? 0 : 3;
1018        else
1019                index = (vecPlaneNormal.y <= 0.0f) ? 1 : 2;
1020
1021        return (vecPlaneNormal.z <= 0.0f) ? index : 7 - index;*/
1022}
1023
1024
1025float AxisAlignedBox3::GetDistance(int index, const Plane3 &plane) const
1026{
1027        return plane.Distance(GetVertex(index));
1028}
1029
1030
1031float AxisAlignedBox3::GetMinVisibleDistance(const Plane3 &near) const
1032{
1033        return  near.mNormal.x * ((near.mNormal.x > 0.0f) ? mMin.x : mMax.x) +
1034                        near.mNormal.y * ((near.mNormal.y > 0.0f) ? mMin.y : mMax.y) +
1035                        near.mNormal.z * ((near.mNormal.z > 0.0f) ? mMin.z : mMax.z) +
1036                        near.mD;
1037}
1038
1039}
1040
Note: See TracBrowser for help on using the repository browser.