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

Revision 2755, 28.3 KB checked in by mattausch, 17 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 CHCDemo
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#if TOIMPLEMENT
723int AxisAlignedBox3::Side(const Plane3 &plane) const
724{
725        Vector3 v;
726        int i, m=3, M=-3, s;
727
728        for (i=0;i<8;i++) {
729                GetVertex(i, v);
730                if((s = plane.Side(v)) < m)
731                        m=s;
732                if(s > M)
733                        M=s;
734                if (m && m==-M)
735                        return 0;
736        }
737
738        return (m == M) ? m : m + M;
739}
740
741
742Plane3 AxisAlignedBox3::GetPlane(const int face) const
743{
744        switch (face)
745        {
746
747        case 0:
748                return Plane3(Vector3(-1, 0, 0), mMin);
749        case 1:
750                return Plane3(Vector3(1, 0, 0), mMax);
751        case 2:
752                return Plane3(Vector3(0, -1, 0), mMin);
753        case 3:
754                return Plane3(Vector3(0, 1, 0), mMax);
755        case 4:
756                return Plane3(Vector3(0, 0, -1), mMin);
757        case 5:
758                return Plane3(Vector3(0, 0, 1), mMax);
759        }
760
761        // should not come here
762        return Plane3();
763}
764#endif
765
766
767void AxisAlignedBox3::Scale(const float scale)
768{
769        Vector3 newSize = Size()*(scale*0.5f);
770        Vector3 center = Center();
771        mMin = center - newSize;
772        mMax = center + newSize;
773}
774
775
776void AxisAlignedBox3::Scale(const Vector3 &scale)
777{
778        Vector3 newSize = Size()*(scale*0.5f);
779        Vector3 center = Center();
780        mMin = center - newSize;
781        mMax = center + newSize;
782}
783
784
785void AxisAlignedBox3::Translate(const Vector3 &shift)
786{
787        mMin += shift;
788        mMax += shift;
789}
790
791
792void AxisAlignedBox3::Initialize()
793{
794        mMin = Vector3(MAXFLOAT);
795        mMax = Vector3(-MAXFLOAT);
796}
797
798
799Vector3 AxisAlignedBox3::Center() const
800{
801        return 0.5 * (mMin + mMax);
802}
803
804
805Vector3 AxisAlignedBox3::Diagonal() const
806{
807        return (mMax - mMin);
808}
809
810
811float AxisAlignedBox3::Center(const int axis) const
812{
813        return  0.5f * (mMin[axis] + mMax[axis]);
814}
815
816
817float AxisAlignedBox3::Min(const int axis) const
818{
819        return mMin[axis];
820}
821
822
823float AxisAlignedBox3::Max(const int axis) const
824{
825        return  mMax[axis];
826}
827
828
829float AxisAlignedBox3::Size(const int axis) const
830{
831        return  Max(axis) - Min(axis);
832}
833
834// Read-only const access tomMin and max vectors using references
835const Vector3& AxisAlignedBox3::Min() const
836{
837        return mMin;
838}
839
840
841const Vector3& AxisAlignedBox3::Max() const
842{
843        return mMax;
844}
845
846
847void AxisAlignedBox3::Enlarge (const Vector3 &v)
848{
849        mMax += v;
850        mMin -= v;
851}
852
853
854void AxisAlignedBox3::EnlargeToMinSize()
855{
856        const float epsMin = 1e-7f;
857        const float epsAdd = 1e-6f;
858        const float epsMul = 1.000005f;
859        float dir = mMax.x - mMin.x;
860
861        assert(dir >= 0.f);
862
863        if (dir < epsMin)
864        {
865                if (mMax.x > 0)
866                {
867                        mMax.x *= epsMul;
868                        mMax.x += epsAdd;
869                }
870                else
871                {
872                        mMin.x *= epsMul;
873                        mMin.x -= epsAdd;
874                }
875               
876                assert(mMin.x < mMax.x);
877        }
878
879        dir = mMax.y - mMin.y;
880        assert(dir >= 0.f);
881       
882        if (dir < epsMin)
883        {
884                if (mMax.y > 0)
885                {
886                        mMax.y *= epsMul;
887                        mMax.y += epsAdd;
888                }
889                else
890                {
891                        mMin.y *= epsMul;
892                        mMin.y -= epsAdd;
893                }
894                assert(mMin.y < mMax.y);
895        }
896       
897        dir = mMax.z - mMin.z;
898        assert(dir >= 0.f);
899       
900        if (dir < epsMin)
901        {
902                if (mMax.z > 0)
903                {
904                        mMax.z *= epsMul;
905                        mMax.z += epsAdd;
906                }
907                else
908                {
909                        mMin.z *= epsMul;
910                        mMin.z -= epsAdd;
911                }
912               
913                assert(mMin.z < mMax.z);
914        }
915}
916
917
918void AxisAlignedBox3::SetMin(const Vector3 &v)
919{
920        mMin = v;
921}
922
923
924void AxisAlignedBox3::SetMax(const Vector3 &v)
925{
926        mMax = v;
927}
928
929
930void AxisAlignedBox3::SetMin(int axis, const float value)
931{
932        mMin[axis] = value;
933}
934
935
936void AxisAlignedBox3::SetMax(int axis, const float value)
937{
938        mMax[axis] = value;
939}
940
941
942// Decrease box by given splitting plane
943void AxisAlignedBox3::Reduce(int axis, int right, float value)
944{
945        if ((value >=mMin[axis]) && (value <= mMax[axis]))
946        {
947                if (right)
948                        mMin[axis] = value;
949                else
950                        mMax[axis] = value;
951        }
952}
953
954
955Vector3 AxisAlignedBox3::Size() const
956{
957        return mMax - mMin;
958}
959
960
961Vector3 AxisAlignedBox3::GetRandomPoint() const
962{
963        Vector3 size = Size();
964
965        return mMin + Vector3(RandomValue(0.0f, 1.0f),
966                                  RandomValue(0.0f, 1.0f),
967                                                  RandomValue(0.0f, 1.0f)) * Size();
968}
969
970
971bool AxisAlignedBox3::Intersects(const Vector3 &lStart,
972                                                                 const Vector3 &lEnd) const
973{
974        float st, et, fst = 0, fet = 1;
975        float const *bmin = &mMin.x;
976        float const *bmax = &mMax.x;
977        float const *si = &lStart.x;
978        float const *ei = &lEnd.x;
979
980        for (int i = 0; i < 3; ++ i)
981        {
982                if (*si < *ei)
983                {
984                        if (*si > *bmax || *ei < *bmin)
985                                return false;
986
987                        const float di = *ei - *si;
988
989                        st = (*si < *bmin)? (*bmin - *si) / di : 0;
990                        et = (*ei > *bmax)? (*bmax - *si) / di : 1;
991                }
992                else
993                {
994                        if (*ei > *bmax || *si < *bmin)
995                                return false;
996
997                        const float di = *ei - *si;
998
999                        st = (*si > *bmax)? (*bmax - *si) / di : 0;
1000                        et = (*ei < *bmin)? (*bmin - *si) / di : 1;
1001                }
1002
1003                if (st > fst) fst = st;
1004                if (et < fet) fet = et;
1005                if (fet < fst)
1006                        return false;
1007
1008                ++ bmin; ++ bmax;
1009                ++ si; ++ ei;
1010        }
1011
1012        //*time = fst;
1013        return true;
1014}
1015
1016
1017Vector3 AxisAlignedBox3::GetVertex(const int N) const
1018{
1019        Vector3 v;
1020        GetVertex(N, v);
1021
1022        return v;
1023}
1024
1025
1026float AxisAlignedBox3::GetExtent(int face) const
1027{
1028        if (face < 3)
1029                return mMin[face];
1030        else
1031                return mMax[face - 3];
1032}
1033
1034
1035int AxisAlignedBox3::GetIndexNearestVertex(const Vector3 &vecPlaneNormal)
1036{
1037        int index;
1038
1039        if (vecPlaneNormal.x > 0.0f)
1040                index = (vecPlaneNormal.y > 0.0f) ? 0 : 3;
1041        else
1042                index = (vecPlaneNormal.y > 0.0f) ? 1 : 2;
1043
1044        return (vecPlaneNormal.z > 0.0f) ? index : 7 - index;
1045}
1046
1047
1048int AxisAlignedBox3::GetIndexFarthestVertex(const Vector3 &vecPlaneNormal)
1049{
1050        int index;
1051
1052        if (vecPlaneNormal.x <= 0.0f)
1053                index = (vecPlaneNormal.y <= 0.0f) ? 0 : 3;
1054        else
1055                index = (vecPlaneNormal.y <= 0.0f) ? 1 : 2;
1056
1057        return (vecPlaneNormal.z <= 0.0f) ? index : 7 - index;
1058}
1059
1060
1061float AxisAlignedBox3::GetDistance(int index, const Plane3 &plane) const
1062{
1063        return plane.Distance(GetVertex(index));
1064}
1065
1066
1067float AxisAlignedBox3::GetMinVisibleDistance(const Plane3 &near) const
1068{
1069        return  near.mNormal.x * ((near.mNormal.x > 0.0f) ? mMin.x : mMax.x) +
1070                        near.mNormal.y * ((near.mNormal.y > 0.0f) ? mMin.y : mMax.y) +
1071                        near.mNormal.z * ((near.mNormal.z > 0.0f) ? mMin.z : mMax.z) +
1072                        near.mD;
1073}
1074
1075}
1076
Note: See TracBrowser for help on using the repository browser.