source: trunk/VUT/GtpVisibilityPreprocessor/src/AxisAlignedBox3.cpp @ 302

Revision 302, 44.9 KB checked in by mattausch, 19 years ago (diff)

added surface area heuristic for bsp

Line 
1
2// GOLEM library
3#include <assert.h>
4#include <iostream>
5using namespace std;
6#include "AxisAlignedBox3.h"
7#include "Ray.h"
8#include "Polygon3.h"
9
10#define FATAL Debug
11#define FATAL_ABORT exit(1)
12
13
14// AxisAlignedBox3 implementations
15
16// Overload << operator for C++-style output
17ostream&
18operator<< (ostream &s, const AxisAlignedBox3 &A)
19{
20  return s << '[' << A.mMin.x << ", " << A.mMin.y << ", " << A.mMin.z << "]["
21           << A.mMax.x << ", " << A.mMax.y << ", " << A.mMax.z << ']';
22}
23
24// Overload >> operator for C++-style input
25istream&
26operator>> (istream &s, AxisAlignedBox3 &A)
27{
28  char a;
29  // read "[min.x, min.y, min.z][mMax.x, mMax.y, mMax.z]"
30  return s >> a >> A.mMin.x >> a >> A.mMin.y >> a >> A.mMin.z >> a >> a
31    >> A.mMax.x >> a >> A.mMax.y >> a >> A.mMax.z >> a;
32}
33
34bool
35AxisAlignedBox3::Unbounded() const
36{
37  return (mMin == Vector3(-MAXFLOAT)) ||
38         (mMax == Vector3(-MAXFLOAT));
39}
40
41void
42AxisAlignedBox3::Include(const Vector3 &newpt)
43{
44  Minimize(mMin, newpt);
45  Maximize(mMax, newpt);
46}
47
48void
49AxisAlignedBox3::Include(const Polygon3 &newpoly)
50{
51        VertexContainer::const_iterator it, it_end = newpoly.mVertices.end();
52
53        for (it = newpoly.mVertices.begin(); it != it_end; ++ it)
54                Include(*it);
55}
56
57void
58AxisAlignedBox3::Include(const AxisAlignedBox3 &bbox)
59{
60  Minimize(mMin, bbox.mMin);
61  Maximize(mMax, bbox.mMax);
62}
63
64bool
65AxisAlignedBox3::IsCorrect()
66{
67  if ( (mMin.x > mMax.x) ||
68       (mMin.y > mMax.y) ||
69       (mMin.z > mMax.z) )
70    return false; // box is not formed
71  return true;
72}
73
74void
75AxisAlignedBox3::GetEdge(const int edge, Vector3 *a, Vector3 *b) const
76{
77  switch(edge) {
78  case 0:
79    a->SetValue(mMin.x, mMin.y, mMin.z);
80    b->SetValue(mMin.x, mMin.y, mMax.z);
81    break;
82  case 1:
83    a->SetValue(mMin.x, mMin.y, mMin.z);
84    b->SetValue(mMin.x, mMax.y, mMin.z);
85    break;
86  case 2:
87    a->SetValue(mMin.x, mMin.y, mMin.z);
88    b->SetValue(mMax.x, mMin.y, mMin.z);
89    break;
90  case 3:
91    a->SetValue(mMax.x, mMax.y, mMax.z);
92    b->SetValue(mMax.x, mMax.y, mMin.z);
93    break;
94  case 4:
95    a->SetValue(mMax.x, mMax.y, mMax.z);
96    b->SetValue(mMax.x, mMin.y, mMax.z);
97    break;
98  case 5:
99    a->SetValue(mMax.x, mMax.y, mMax.z);
100    b->SetValue(mMin.x, mMax.y, mMax.z);
101    break;
102   
103  case 6:
104    a->SetValue(mMin.x, mMin.y, mMax.z);
105    b->SetValue(mMin.x, mMax.y, mMax.z);
106    break;
107  case 7:
108    a->SetValue(mMin.x, mMin.y, mMax.z);
109    b->SetValue(mMax.x, mMin.y, mMax.z);
110    break;
111  case 8:
112    a->SetValue(mMin.x, mMax.y, mMin.z);
113    b->SetValue(mMin.x, mMax.y, mMax.z);
114    break;
115  case 9:
116    a->SetValue(mMin.x, mMax.y, mMin.z);
117    b->SetValue(mMax.x, mMax.y, mMin.z);
118    break;
119  case 10:
120    a->SetValue(mMax.x, mMin.y, mMin.z);
121    b->SetValue(mMax.x, mMax.y, mMin.z);
122    break;
123  case 11:
124    a->SetValue(mMax.x, mMin.y, mMin.z);
125    b->SetValue(mMax.x, mMin.y, mMax.z);
126    break;
127  }
128}
129
130void
131AxisAlignedBox3::Include(const int &axis, const float &newBound)
132{
133  switch (axis) {
134    case 0: { // x-axis
135      if (mMin.x > newBound)
136        mMin.x = newBound;
137      if (mMax.x < newBound)
138        mMax.x = newBound;
139      break;
140    }
141    case 1: { // y-axis
142      if (mMin.y > newBound)
143        mMin.y = newBound;
144      if (mMax.y < newBound)
145        mMax.y = newBound;
146      break;
147    }
148    case 2: { // z-axis
149      if (mMin.z > newBound)
150        mMin.z = newBound;
151      if (mMax.z < newBound)
152        mMax.z = newBound;
153      break;
154    }
155  }
156}
157
158#if 0
159// ComputeMinMaxT computes the minimum and maximum signed distances
160// of intersection with the ray; it returns 1 if the ray hits
161// the bounding box and 0 if it does not.
162int
163AxisAlignedBox3::ComputeMinMaxT(const Ray &ray,
164                                float *tmin,
165                                float *tmax) const
166{
167  float minx, maxx, miny, maxy, minz, maxz;
168
169  if (fabs(ray.dir.x) < 0.001) {
170    if (mMin.x < ray.loc.x && mMax.x > ray.loc.x) {
171      minx = -MAXFLOAT;
172      maxx = MAXFLOAT;
173    }
174    else
175      return 0;
176  }
177  else {
178    float t1 = (mMin.x - ray.loc.x) / ray.dir.x;
179    float t2 = (mMax.x - ray.loc.x) / ray.dir.x;
180    if (t1 < t2) {
181      minx = t1;
182      maxx = t2;
183    }
184    else {
185      minx = t2;
186      maxx = t1;
187    }
188    if (maxx < 0)
189      return 0;
190  }
191
192  if (fabs(ray.dir.y) < 0.001) {
193    if (mMin.y < ray.loc.y && mMax.y > ray.loc.y) {
194      miny = -MAXFLOAT;
195      maxy = MAXFLOAT;
196    }
197    else
198      return 0;
199  }
200  else {
201    float t1 = (mMin.y - ray.loc.y) / ray.dir.y;
202    float t2 = (mMax.y - ray.loc.y) / ray.dir.y;
203    if (t1 < t2) {
204      miny = t1;
205      maxy = t2;
206    }
207    else {
208      miny = t2;
209      maxy = t1;
210    }
211    if (maxy < 0.0)
212      return 0;
213  }
214
215  if (fabs(ray.dir.z) < 0.001) {
216    if (mMin.z < ray.loc.z && mMax.z > ray.loc.z) {
217      minz = -MAXFLOAT;
218      maxz = MAXFLOAT;
219    }
220    else
221      return 0;
222  }
223  else {
224    float t1 = (mMin.z - ray.loc.z) / ray.dir.z;
225    float t2 = (mMax.z - ray.loc.z) / ray.dir.z;
226    if (t1 < t2) {
227      minz = t1;
228      maxz = t2;
229    }
230    else {
231      minz = t2;
232      maxz = t1;
233    }
234    if (maxz < 0.0)
235      return 0;
236  }
237
238  *tmin = minx;
239  if (miny > *tmin)
240    *tmin = miny;
241  if (minz > *tmin)
242    *tmin = minz;
243
244  *tmax = maxx;
245  if (maxy < *tmax)
246    *tmax = maxy;
247  if (maxz < *tmax)
248    *tmax = maxz;
249
250  return 1; // yes, intersection was found
251}
252#else
253// another variant of the same, with less variables
254int
255AxisAlignedBox3::ComputeMinMaxT(const Ray &ray,
256                                float *tmin,
257                                float *tmax) const
258{
259  register float minx, maxx;
260  ray.ComputeInvertedDir();
261 
262  if (fabs(ray.dir.x) < 0.001) {
263    if (mMin.x < ray.loc.x && mMax.x > ray.loc.x) {
264      minx = -MAXFLOAT;
265      maxx = MAXFLOAT;
266    }
267    else
268      return 0;
269  }
270  else {
271    float t1 = (mMin.x - ray.loc.x) * ray.invDir.x;
272    float t2 = (mMax.x - ray.loc.x) * ray.invDir.x;
273    if (t1 < t2) {
274      minx = t1;
275      maxx = t2;
276    }
277    else {
278      minx = t2;
279      maxx = t1;
280    }
281    if (maxx < 0.0)
282      return 0;
283  }
284
285  *tmin = minx;
286  *tmax = maxx;
287 
288  if (fabs(ray.dir.y) < 0.001) {
289    if (mMin.y < ray.loc.y && mMax.y > ray.loc.y) {
290      minx = -MAXFLOAT;
291      maxx = MAXFLOAT;
292    }
293    else
294      return 0;
295  }
296  else {
297    float t1 = (mMin.y - ray.loc.y) * ray.invDir.y;
298    float t2 = (mMax.y - ray.loc.y) * ray.invDir.y;
299    if (t1 < t2) {
300      minx = t1;
301      maxx = t2;
302    }
303    else {
304      minx = t2;
305      maxx = t1;
306    }
307    if (maxx < 0.0)
308      return 0;
309  }
310
311  if (minx > *tmin)
312    *tmin = minx;
313  if (maxx < *tmax)
314    *tmax = maxx;
315 
316  if (fabs(ray.dir.z) < 0.001) {
317    if (mMin.z < ray.loc.z && mMax.z > ray.loc.z) {
318      minx = -MAXFLOAT;
319      maxx = MAXFLOAT;
320    }
321    else
322      return 0;
323  }
324  else {
325    float t1 = (mMin.z - ray.loc.z) * ray.invDir.z;
326    float t2 = (mMax.z - ray.loc.z) * ray.invDir.z;
327    if (t1 < t2) {
328      minx = t1;
329      maxx = t2;
330    }
331    else {
332      minx = t2;
333      maxx = t1;
334    }
335    if (maxx < 0.0)
336      return 0;
337  }
338
339  if (minx > *tmin)
340    *tmin = minx;
341  if (maxx < *tmax)
342    *tmax = maxx;
343
344  return 1; // yes, intersection was found
345}
346#endif
347
348// ComputeMinMaxT computes the minimum and maximum parameters
349// of intersection with the ray; it returns 1 if the ray hits
350// the bounding box and 0 if it does not.
351int
352AxisAlignedBox3::ComputeMinMaxT(const Ray &ray, float *tmin, float *tmax,
353                                EFaces &entryFace, EFaces &exitFace) const
354{
355  float minx, maxx, miny, maxy, minz, maxz;
356  int swapped[3];
357 
358  if (fabs(ray.dir.x) < 0.001) {
359    if (mMin.x < ray.loc.x && mMax.x > ray.loc.x) {
360      minx = -MAXFLOAT;
361      maxx = MAXFLOAT;
362    }
363    else
364      return 0;
365  }
366  else {
367    float t1 = (mMin.x - ray.loc.x) / ray.dir.x;
368    float t2 = (mMax.x - ray.loc.x) / ray.dir.x;
369    if (t1 < t2) {
370      minx = t1;
371      maxx = t2;
372      swapped[0] = 0;
373    }
374    else {
375      minx = t2;
376      maxx = t1;
377      swapped[0] = 1;
378    }
379    if (maxx < 0)
380      return 0;
381  }
382
383  if (fabs(ray.dir.y) < 0.001) {
384    if (mMin.y < ray.loc.y && mMax.y > ray.loc.y) {
385      miny = -MAXFLOAT;
386      maxy = MAXFLOAT;
387    }
388    else
389      return 0;
390  }
391  else {
392    float t1 = (mMin.y - ray.loc.y) / ray.dir.y;
393    float t2 = (mMax.y - ray.loc.y) / ray.dir.y;
394    if (t1 < t2) {
395      miny = t1;
396      maxy = t2;
397      swapped[1] = 0;
398    }
399    else {
400      miny = t2;
401      maxy = t1;
402      swapped[1] = 1;
403    }
404    if (maxy < 0.0)
405      return 0;
406  }
407
408  if (fabs(ray.dir.z) < 0.001) {
409    if (mMin.z < ray.loc.z && mMax.z > ray.loc.z) {
410      minz = -MAXFLOAT;
411      maxz = MAXFLOAT;
412    }
413    else
414      return 0;
415  }
416  else {
417    float t1 = (mMin.z - ray.loc.z) / ray.dir.z;
418    float t2 = (mMax.z - ray.loc.z) / ray.dir.z;
419    if (t1 < t2) {
420      minz = t1;
421      maxz = t2;
422      swapped[2] = 0;
423    }
424    else {
425      minz = t2;
426      maxz = t1;
427      swapped[2] = 1;
428    }
429    if (maxz < 0.0)
430      return 0;
431  }
432
433  *tmin = minx;
434  entryFace = ID_Back;
435  if (miny > *tmin) {
436    *tmin = miny;
437    entryFace = ID_Left;
438  }
439  if (minz > *tmin) {
440    *tmin = minz;
441    entryFace = ID_Bottom;
442  }
443 
444  *tmax = maxx;
445  exitFace = ID_Back;
446  if (maxy < *tmax) {
447    *tmax = maxy;
448    exitFace = ID_Left;
449  }
450  if (maxz < *tmax) {
451    *tmax = maxz;
452    exitFace = ID_Bottom;
453  }
454
455  if (swapped[entryFace])
456    entryFace = (EFaces)(entryFace + 3);
457 
458  if (!swapped[exitFace])
459    exitFace = (EFaces)(exitFace + 3);
460 
461  return 1; // yes, intersection was found
462}
463
464void
465AxisAlignedBox3::Describe(ostream &app, int ind) const
466{
467  indent(app, ind);
468  app << "AxisAlignedBox3: min at(" << mMin << "), max at(" << mMax << ")\n";
469}
470
471// computes the passing through parameters for case tmin<tmax and tmax>0
472int
473AxisAlignedBox3::GetMinMaxT(const Ray &ray, float *tmin, float *tmax) const
474{
475  if (!ComputeMinMaxT(ray, tmin, tmax))
476    return 0;
477  if ( *tmax < *tmin)
478    return 0; // the ray passes outside the box
479
480  if ( *tmax < 0.0)
481    return 0; // the intersection is not on the positive halfline
482
483  return 1; // ray hits the box .. origin can be outside or inside the box
484}
485
486// computes the signed distances for case tmin<tmax and tmax>0
487int
488AxisAlignedBox3::GetMinMaxT(const Ray &ray, float *tmin, float *tmax,
489                            EFaces &entryFace, EFaces &exitFace) const
490{
491  if (!ComputeMinMaxT(ray, tmin, tmax, entryFace, exitFace))
492    return 0;
493  if ( *tmax < *tmin)
494    return 0; // the ray passes outside the box
495 
496  if ( *tmax < 0.0)
497    return 0; // the intersection is not on the positive halfline
498 
499  return 1; // ray hits the box .. origin can be outside or inside the box
500}
501
502#if 0
503int
504AxisAlignedBox3::IsInside(const Vector3 &point) const
505{
506  return (point.x >= mMin.x) && (point.x <= mMax.x) &&
507         (point.y >= mMin.y) && (point.y <= mMax.y) &&
508         (point.z >= mMin.z) && (point.z <= mMax.z);
509}
510#else
511int
512AxisAlignedBox3::IsInside(const Vector3 &v) const
513{
514  return ! (v.x < mMin.x ||
515            v.x > mMax.x ||
516            v.y < mMin.y ||
517            v.y > mMax.y ||
518            v.z < mMin.z ||
519            v.z > mMax.z);
520}
521#endif
522
523bool
524AxisAlignedBox3::Includes(const AxisAlignedBox3 &b) const
525{
526  return (b.mMin.x >= mMin.x &&
527      b.mMin.y >= mMin.y &&
528      b.mMin.z >= mMin.z &&
529      b.mMax.x <= mMax.x &&
530      b.mMax.y <= mMax.y &&
531      b.mMax.z <= mMax.z);
532
533}
534
535
536// compute the coordinates of one vertex of the box
537Vector3
538AxisAlignedBox3::GetVertex(int xAxis, int yAxis, int zAxis) const
539{
540  Vector3 p;
541  if (xAxis)
542    p.x = mMax.x;
543  else
544    p.x = mMin.x;
545
546  if (yAxis)
547    p.y = mMax.y;
548  else
549    p.y = mMin.y;
550
551  if (zAxis)
552    p.z = mMax.z;
553  else
554    p.z = mMin.z;
555  return p;
556}
557
558// compute the vertex for number N = <0..7>, N = 4.x + 2.y + z, where
559// x,y,z are either 0 or 1; (0 .. min coordinate, 1 .. max coordinate)
560void
561AxisAlignedBox3::GetVertex(const int N, Vector3 &vertex) const
562{
563  switch (N) {
564    case 0: vertex = mMin; break;
565    case 1: vertex.SetValue(mMin.x, mMin.y, mMax.z); break;
566    case 2: vertex.SetValue(mMin.x, mMax.y, mMin.z); break;
567    case 3: vertex.SetValue(mMin.x, mMax.y, mMax.z); break;
568    case 4: vertex.SetValue(mMax.x, mMin.y, mMin.z); break;
569    case 5: vertex.SetValue(mMax.x, mMin.y, mMax.z); break;
570    case 6: vertex.SetValue(mMax.x, mMax.y, mMin.z); break;
571    case 7: vertex = mMax; break;
572    default: {
573      FATAL << "ERROR in AxisAlignedBox3::GetVertex N=" << N <<  "\n";
574      FATAL_ABORT;
575    }
576  }
577}
578
579// Returns region 0 .. 26 ; R = 9*x + 3*y + z ; (x,y,z) \in {0,1,2}
580int
581AxisAlignedBox3::GetRegionID(const Vector3 &point) const
582{
583  int ID = 0;
584
585  if (point.z >= mMin.z) {
586    if (point.z <= mMax.z)
587      ID += 1; // inside the two boundary planes
588    else
589      ID += 2; // outside
590  }
591
592  if (point.y >= mMin.y) {
593    if (point.y <= mMax.y)
594      ID += 3; // inside the two boundary planes
595    else
596      ID += 6; // outside
597  }
598
599  if (point.x >= mMin.x) {
600    if (point.x <= mMax.x)
601      ID += 9; // inside the two boundary planes
602    else
603      ID += 18; // outside
604  }
605  return ID;
606}
607
608
609
610// computes if a given box (smaller) lies at least in one
611// projection whole in the box (larger) = this encompasses given
612// ;-----;
613// | ;-; |
614// | '-' |
615// '-----'
616int
617AxisAlignedBox3::IsPiercedByBox(const AxisAlignedBox3 &box, int &axis) const
618{
619  // test on x-axis
620  if ( (mMax.x < box.mMin.x) ||
621       (mMin.x > box.mMax.x) )
622    return 0; // the boxes do not overlap at all at x-axis
623  if ( (box.mMin.y > mMin.y) &&
624       (box.mMax.y < mMax.y) &&
625       (box.mMin.z > mMin.z) &&
626       (box.mMax.z < mMax.z) ) {
627    axis = 0;
628    return 1; // the boxes overlap in x-axis
629  }
630  // test on y-axis
631  if ( (mMax.y < box.mMin.y) ||
632       (mMin.y > box.mMax.y) )
633    return 0; // the boxes do not overlap at all at y-axis
634  if ( (box.mMin.x > mMin.x) &&
635       (box.mMax.x < mMax.x) &&
636       (box.mMin.z > mMin.z) &&
637       (box.mMax.z < mMax.z) ) {
638    axis = 1;
639    return 1; // the boxes overlap in y-axis
640  }
641  // test on z-axis
642  if ( (mMax.z < box.mMin.z) ||
643       (mMin.z > box.mMax.z) )
644    return 0; // the boxes do not overlap at all at y-axis
645  if ( (box.mMin.x > mMin.x) &&
646       (box.mMax.x < mMax.x) &&
647       (box.mMin.y > mMin.y) &&
648       (box.mMax.y < mMax.y) ) {
649    axis = 2;
650    return 1; // the boxes overlap in z-axis
651  }
652  return 0;
653}
654
655float
656AxisAlignedBox3::SurfaceArea() const
657{
658  Vector3 ext = mMax - mMin;
659 
660  return 2.0 * (ext.x * ext.y +
661                ext.x * ext.z +
662                ext.y * ext.z);
663}
664
665const int AxisAlignedBox3::bvertices[27][9] =
666{                   // region number.. position
667  {5,1,3,2,6,4,-1,-1,-1},      // 0 .. x=0 y=0 z=0
668  {4,5,1,3,2,0,-1,-1,-1},      // 1 .. x=0 y=0 z=1
669  {4,5,7,3,2,0,-1,-1,-1},      // 2 .. x=0 y=0 z=2
670
671  {0,1,3,2,6,4,-1,-1,-1},      // 3 .. x=0 y=1 z=0
672  {0,1,3,2,-1,-1,-1,-1,-1},    // 4 .. x=0 y=1 z=1
673  {1,5,7,3,2,0,-1,-1,-1},      // 5 .. x=0 y=1 z=2
674
675  {0,1,3,7,6,4,-1,-1,-1},      // 6 .. x=0 y=2 z=0
676  {0,1,3,7,6,2,-1,-1,-1},      // 7 .. x=0 y=2 z=1
677  {1,5,7,6,2,0,-1,-1,-1},      // 8 .. x=0 y=2 z=2
678
679  // the regions number <9,17>
680  {5,1,0,2,6,4,-1,-1,-1},      // 9  .. x=1 y=0 z=0
681  {5,1,0,4,-1,-1,-1,-1,-1},    // 10 .. x=1 y=0 z=1
682  {7,3,1,0,4,5,-1,-1,-1},      // 11 .. x=1 y=0 z=2
683
684  {4,0,2,6,-1,-1,-1,-1,-1},    // 12 .. x=1 y=1 z=0
685  {0,2,3,1,5,4,6,7,-1},        // 13 .. x=1 y=1 z=1 .. inside the box
686  {1,5,7,3,-1,-1,-1,-1,-1},    // 14 .. x=1 y=1 z=2
687
688  {4,0,2,3,7,6,-1,-1,-1},      // 15 .. x=1 y=2 z=0
689  {6,2,3,7,-1,-1,-1,-1,-1},    // 16 .. x=1 y=2 z=1
690  {1,5,7,6,2,3,-1,-1,-1},      // 17 .. x=1 y=2 z=2
691
692  // the regions number <18,26>
693  {1,0,2,6,7,5,-1,-1,-1},      // 18 .. x=2 y=0 z=0
694  {1,0,4,6,7,5,-1,-1,-1},      // 19 .. x=2 y=0 z=1
695  {0,4,6,7,3,1,-1,-1,-1},      // 20 .. x=2 y=0 z=2
696
697  {4,0,2,6,7,5,-1,-1,-1},      // 21 .. x=2 y=1 z=0
698  {5,4,6,7,-1,-1,-1,-1,-1},    // 22 .. x=2 y=1 z=1
699  {5,4,6,7,3,1,-1,-1,-1},      // 23 .. x=2 y=1 z=2
700
701  {4,0,2,3,7,5,-1,-1,-1},      // 24 .. x=2 y=2 z=0
702  {5,4,6,2,3,7,-1,-1,-1},      // 25 .. x=2 y=2 z=1
703  {5,4,6,2,3,1,-1,-1,-1},      // 26 .. x=2 y=2 z=2
704};
705
706// the visibility of boundary faces from a given region
707// one to three triples: (axis, min_vertex, max_vertex), axis==-1(terminator)
708const int AxisAlignedBox3::bfaces[27][10] =
709{                              // region number .. position
710  {0,0,3,1,0,5,2,0,6,-1},      // 0 .. x=0 y=0 z=0
711  {0,0,3,1,0,5,-1,-1,-1,-1},   // 1 .. x=0 y=0 z=1
712  {0,0,3,1,0,5,2,1,7,-1},      // 2 .. x=0 y=0 z=2
713
714  {0,0,3,2,0,6,-1,-1,-1,-1},   // 3 .. x=0 y=1 z=0
715  {0,0,3,-1,-1,-1,-1,-1,-1,-1},// 4 .. x=0 y=1 z=1
716  {0,0,3,2,1,7,-1,-1,-1,-1},   // 5 .. x=0 y=1 z=2
717
718  {0,0,3,1,2,7,2,0,6,-1},      // 6 .. x=0 y=2 z=0
719  {0,0,3,1,2,7,-1,-1,-1,-1},   // 7 .. x=0 y=2 z=1
720  {0,0,3,1,2,7,2,1,7,-1},      // 8 .. x=0 y=2 z=2
721
722  // the regions number <9,17>
723  {1,0,5,2,0,6,-1,-1,-1,-1},   // 9  .. x=1 y=0 z=0
724  {1,0,5,-1,-1,-1,-1,-1,-1,-1},// 10 .. x=1 y=0 z=1
725  {1,0,5,2,1,7,-1,-1,-1,-1},   // 11 .. x=1 y=0 z=2
726
727  {2,0,6,-1,-1,-1,-1,-1,-1,-1},// 12 .. x=1 y=1 z=0
728  {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},// 13 .. x=1 y=1 z=1 .. inside the box
729  {2,1,7,-1,-1,-1,-1,-1,-1,-1},// 14 .. x=1 y=1 z=2
730
731  {1,2,7,2,0,6,-1,-1,-1,-1},   // 15 .. x=1 y=2 z=0
732  {1,2,7,-1,-1,-1,-1,-1,-1,-1},// 16 .. x=1 y=2 z=1
733  {1,2,7,2,1,7,-1,-1,-1,-1},   // 17 .. x=1 y=2 z=2
734
735  // the region number <18,26>
736  {0,4,7,1,0,5,2,0,6,-1},      // 18 .. x=2 y=0 z=0
737  {0,4,7,1,0,5,-1,-1,-1,-1},   // 19 .. x=2 y=0 z=1
738  {0,4,7,1,0,5,2,1,7,-1},      // 20 .. x=2 y=0 z=2
739
740  {0,4,7,2,0,6,-1,-1,-1,-1},   // 21 .. x=2 y=1 z=0
741  {0,4,7,-1,-1,-1,-1,-1,-1,-1},// 22 .. x=2 y=1 z=1
742  {0,4,7,2,1,7,-1,-1,-1,-1},   // 23 .. x=2 y=1 z=2
743
744  {0,4,7,1,2,7,2,0,6,-1},      // 24 .. x=2 y=2 z=0
745  {0,4,7,1,2,7,-1,-1,-1,-1},   // 25 .. x=2 y=2 z=1
746  {0,4,7,1,2,7,2,1,7,-1},      // 26 .. x=2 y=2 z=2
747};
748
749// the correct corners indexing from entry face to exit face
750// first index determines entry face, second index exit face, and
751// the two numbers (indx, inc) determines: ind = the index on the exit
752// face, when starting from the vertex 0 on entry face, 'inc' is
753// the increment when we go on entry face in order 0,1,2,3 to create
754// convex shaft with the rectangle on exit face. That is, inc = -1 or 1.
755const int AxisAlignedBox3::pairFaceRects[6][6][2] = {
756  { // entry face = 0
757    {-1,0}, // exit face 0 .. no meaning
758    {0,-1}, // 1
759    {0,-1}, // 2
760    {0,1}, // 3 .. opposite face
761    {3,1}, // 4
762    {1,1} // 5
763  },
764  { // entry face = 1
765    {0,-1}, // exit face 0
766    {-1,0}, // 1 .. no meaning
767    {0,-1}, // 2
768    {1,1}, // 3
769    {0,1}, // 4 .. opposite face
770    {3,1} // 5
771  },
772  { // entry face = 2
773    {0,-1}, // 0
774    {0,-1}, // 1
775    {-1,0}, // 2 .. no meaning
776    {3,1}, // 3
777    {1,1}, // 4
778    {0,1} // 5 .. opposite face
779  },
780  { // entry face = 3
781    {0,1}, // 0 .. opposite face
782    {3,-1}, // 1
783    {1,1}, // 2
784    {-1,0}, // 3  .. no meaning
785    {0,-1}, // 4
786    {0,-1} // 5
787  },
788  { // entry face = 4
789    {1,1}, // 0
790    {0,1}, // 1 .. opposite face
791    {3,1}, // 2
792    {0,-1}, // 3
793    {-1,0}, // 4 .. no meaning
794    {0,-1} // 5
795  },
796  { // entry face = 5
797    {3,-1}, // 0
798    {1,1}, // 1
799    {0,1}, // 2  .. opposite face
800    {0,-1}, // 3
801    {0,-1}, // 4
802    {-1,0} // 5 .. no meaning
803  }
804};
805
806
807// ------------------------------------------------------------
808// The vertices that form CLOSEST points with respect to the region
809// for all the regions possible, number of regions is 3^3 = 27,
810// since two parallel sides of bbox forms three disjoint spaces.
811// The vertices are given in anti-clockwise order, stopped by value 15,
812// at most 8 points, at least 1 point.
813// The table includes the closest 1/2/4/8 points, followed possibly
814// by the set of coordinates that should be used for testing for
815// the proximity queries. The coordinates to be tested are described by
816// the pair (a,b), when a=0, we want to test min vector of the box,
817//                 when a=1, we want to test max vector of the box
818//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
819// The sequence is ended by 15, number -1 is used as the separator
820// between the vertices and coordinates.
821const int
822AxisAlignedBox3::cvertices[27][9] =
823{                   // region number.. position
824  {0,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D one vertex
825  {0,1,-1,0,0,0,1,15,15},      // 1 .. x=0 y=0 z=1 D two vertices foll. by 2
826  {1,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D one vertex
827
828  {0,2,-1,0,0,0,2,15,15},      // 3 .. x=0 y=1 z=0 D
829  {0,1,3,2,-1,0,0,15,15},      // 4 .. x=0 y=1 z=1 D
830  {1,3,-1,0,0,1,2,15,15},      // 5 .. x=0 y=1 z=2 D
831
832  {2,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
833  {2,3,-1,0,0,1,1,15,15},      // 7 .. x=0 y=2 z=1 D
834  {3,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
835
836  // the regions number <9,17>
837  {0,4,-1,0,1,0,2,15,15},      // 9  .. x=1 y=0 z=0 D
838  {5,1,0,4,-1,0,1,15,15},      // 10 .. x=1 y=0 z=1 D
839  {1,5,-1,0,1,1,2,15,15},      // 11 .. x=1 y=0 z=2 D
840
841  {4,0,2,6,-1,0,2,15,15},      // 12 .. x=1 y=1 z=0 D
842  {0,2,3,1,5,4,6,7,15},        // 13 .. x=1 y=1 z=1 .. inside the box
843  {1,5,7,3,-1,1,2,15,15},      // 14 .. x=1 y=1 z=2 D
844
845  {6,2,-1,0,2,1,1,15,15},      // 15 .. x=1 y=2 z=0 D
846  {6,2,3,7,-1,1,1,15,15},      // 16 .. x=1 y=2 z=1 D
847  {3,7,-1,1,1,1,2,15,15},      // 17 .. x=1 y=2 z=2 D
848
849  // the regions number <18,26>
850  {4,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
851  {4,5,-1,0,1,1,0,15,15},      // 19 .. x=2 y=0 z=1 D
852  {5,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
853
854  {4,6,-1,0,2,1,0,15,15},      // 21 .. x=2 y=1 z=0 D
855  {5,4,6,7,-1,1,0,15,15},      // 22 .. x=2 y=1 z=1 D
856  {7,5,-1,1,0,1,2,15,15},      // 23 .. x=2 y=1 z=2 D
857
858  {6,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
859  {6,7,-1,1,0,1,1,15,15},      // 25 .. x=2 y=2 z=1 D
860  {7,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
861};
862
863// Table for Sphere-AABB intersection based on the region knowledge
864// Similar array to previous cvertices, but we omit the surfaces
865// which are not necessary for testing. First are vertices,
866// they are finished with -1. Second, there are indexes in
867// the pair (a,b), when a=0, we want to test min vector of the box,
868//                 when a=1, we want to test max vector of the box
869//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
870//
871// So either we check the vertices or only the distance in specified
872// dimensions. There are at all four possible cases:
873//
874//   1) we check one vertex - then sequence start with non-negative index
875//      and is finished with 15
876//   2) we check two coordinates of min/max vector describe by the pair
877//         (a,b) .. a=min/max(0/1) b=x/y/z (0/1/2), sequence starts with 8
878//      and finishes with 15
879//   3) we check only one coordinate of min/max, as for 2), sequence start
880//      with 9 and ends with 15
881//   4) Position 13 - sphere is inside the box, intersection always exist
882//        the sequence start with 15 .. no further testing is necessary
883//        in this case
884const int
885AxisAlignedBox3::csvertices[27][6] =
886{                   // region number.. position
887  {0,15,15,15,15,15},  // 0 .. x=0 y=0 z=0 D vertex only
888  {8,0,0,0,1,15},      // 1 .. x=0 y=0 z=1 D two coords.
889  {1,15,15,15,15,15},  // 2 .. x=0 y=0 z=2 D vertex only
890
891  {8,0,0,0,2,15},      // 3 .. x=0 y=1 z=0 D two coords
892  {9,0,0,15,15,15},    // 4 .. x=0 y=1 z=1 D one coord
893  {8,0,0,1,2,15},      // 5 .. x=0 y=1 z=2 D two coords.
894
895  {2,15,15,15,15,15},  // 6 .. x=0 y=2 z=0 D one vertex
896  {8,0,0,1,1,15},      // 7 .. x=0 y=2 z=1 D two coords
897  {3,15,15,15,15,15},  // 8 .. x=0 y=2 z=2 D one vertex
898
899  // the regions number <9,17>
900  {8,0,1,0,2,15},      // 9  .. x=1 y=0 z=0 D two coords
901  {9,0,1,15,15,15},    // 10 .. x=1 y=0 z=1 D one coord
902  {8,0,1,1,2,15},      // 11 .. x=1 y=0 z=2 D two coords
903
904  {9,0,2,15,15,15},    // 12 .. x=1 y=1 z=0 D one coord
905  {15,15,15,15,15,15}, // 13 .. x=1 y=1 z=1 inside the box, special case/value
906  {9,1,2,15,15,15},    // 14 .. x=1 y=1 z=2 D one corrd
907
908  {8,0,2,1,1,15},      // 15 .. x=1 y=2 z=0 D two coords
909  {9,1,1,15,15},       // 16 .. x=1 y=2 z=1 D one coord
910  {8,1,1,1,2,15},      // 17 .. x=1 y=2 z=2 D two coords
911
912  // the regions number <18,26>
913  {4,15,15,15,15,15},  // 18 .. x=2 y=0 z=0 D one vertex
914  {8,0,1,1,0,15},      // 19 .. x=2 y=0 z=1 D two coords
915  {5,15,15,15,15,15},  // 20 .. x=2 y=0 z=2 D one vertex
916
917  {8,0,2,1,0,15},      // 21 .. x=2 y=1 z=0 D two coords
918  {9,1,0,15,15,15},    // 22 .. x=2 y=1 z=1 D one coord
919  {8,1,0,1,2,15},      // 23 .. x=2 y=1 z=2 D two coords
920
921  {6,15,15,15,15,15},  // 24 .. x=2 y=2 z=0 D one vertex
922  {8,1,0,1,1,15},      // 25 .. x=2 y=2 z=1 D two coords
923  {7,15,15,15,15,15},  // 26 .. x=2 y=2 z=2 D one vertex
924};
925
926
927// The vertices that form all FARTHEST points with respect to the region
928// for all the regions possible, number of regions is 3^3 = 27,
929// since two parallel sides of bbox forms three disjoint spaces.
930// The vertices are given in anti-clockwise order, stopped by value 15,
931// at most 8 points, at least 1 point.
932// For testing, if the AABB is whole in the sphere, it is enough
933// to test only vertices, either 1,2,4, or 8.
934const int
935AxisAlignedBox3::fvertices[27][9] =
936{                   // region number.. position
937  {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D
938  {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D
939  {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D
940
941  {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D
942  {4,5,7,6,15,15,15,15,15},    // 4 .. x=0 y=1 z=1 D
943  {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D
944
945  {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
946  {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D
947  {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
948
949  // the regions number <9,17>
950  {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D
951  {7,3,2,6,15,15,15,15,15},    // 10 .. x=1 y=0 z=1 D
952  {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D
953
954  {5,1,3,7,15,15,15,15,15},    // 12 .. x=1 y=1 z=0 D
955  {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
956  {0,4,6,2,15,15,15,15,15},    // 14 .. x=1 y=1 z=2 D
957
958  {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D
959  {4,0,1,5,15,15,15,15,15},    // 16 .. x=1 y=2 z=1 D
960  {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D
961
962  // the regions number <18,26>
963  {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
964  {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D
965  {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
966
967  {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D
968  {1,0,2,3,15,15,15,15,15},    // 22 .. x=2 y=1 z=1 D
969  {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D
970
971  {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
972  {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D
973  {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
974};
975
976// Similar table as above, farthest points, but only the ones
977// necessary for testing the intersection problem. If we do
978// not consider the case 13, center of the sphere is inside the
979// box, then we can always test at most 2 box vertices to say whether
980// the whole box is inside the sphere.
981// The number of vertices is minimized using some assumptions
982// about the ortogonality of vertices and sphere properties.
983const int
984AxisAlignedBox3::fsvertices[27][9] =
985{                   // region number.. position
986  {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D 1 vertex
987  {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D 2 vertices
988  {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D 1 vertex
989
990  {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D 2 vertices
991  {4,7,15,5,6,15,15,15,15},    // 4 .. x=0 y=1 z=1 D 4/2 vertices
992  {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D 2 vertices
993
994  {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D 1 vertex
995  {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D 2 vertices
996  {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D 1 vertex
997
998  // the regions number <9,17>
999  {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D 2 vertices
1000  {7,2,15,3,6,15,15,15,15},    // 10 .. x=1 y=0 z=1 D 4/2 vertices
1001  {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D 2 vertices
1002
1003  {5,3,15,1,7,15,15,15,15},    // 12 .. x=1 y=1 z=0 D 4/2 vertices
1004  {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
1005  {0,6,15,4,2,15,15,15,15},    // 14 .. x=1 y=1 z=2 D 4/2 vertices
1006
1007  {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D 2 vertices
1008  {4,1,15,0,5,15,15,15,15},    // 16 .. x=1 y=2 z=1 D 4/2 vertices
1009  {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D 2 vertices
1010
1011  // the regions number <18,26>
1012  {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D 1 vertex
1013  {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D 2 vertices
1014  {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D 1 vertex
1015
1016  {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D 2 vertices
1017  {1,2,15,0,3,15,15,15,15},    // 22 .. x=2 y=1 z=1 D 4/2 vertices
1018  {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D 2 vertices
1019
1020  {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D 1 vertex
1021  {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D 2 vertices
1022  {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D 1 vertex
1023};
1024
1025// The fast computation of arctangent .. the maximal error is less
1026// than 4.1 degrees, according to Graphics GEMSII, 1991, pages 389--391
1027// Ron Capelli: "Fast approximation to the arctangent"
1028float
1029atan22(const float& y)
1030{
1031  const float x = 1.0;
1032  const float c = (float)(M_PI * 0.25);
1033 
1034  if (y < 0.0) {
1035    if (y < -1.0)
1036      return c * (-2.0 + x / y); // for angle in <-PI/2, -PI/4)
1037    else
1038      return c * (y / x); // for angle in <-PI/4 , 0>
1039  }
1040  else {
1041    if (y > 1.0)
1042      return c * (2.0 - x / y); // for angle in <PI/4, PI/2>
1043    else
1044      return c * (y / x); // for angle in <0, PI/2>
1045  }
1046}
1047
1048
1049float
1050AxisAlignedBox3::ProjectToSphereSA(const Vector3 &viewpoint, int *tcase) const
1051{
1052  int id = GetRegionID(viewpoint);
1053  *tcase = id;
1054
1055  // spherical projection .. SA represents solid angle
1056  if (id == 13) // .. inside the box
1057    return (float)(4.0*M_PI); // the whole sphere
1058  float SA = 0.0; // inital value
1059   
1060  int i = 0; // the pointer in the array of vertices
1061  while (bfaces[id][i] >= 0) {
1062    int axisO = bfaces[id][i++];
1063    int minvIdx = bfaces[id][i++];
1064    int maxvIdx = bfaces[id][i++];
1065    Vector3 vmin, vmax;
1066    GetVertex(minvIdx, vmin);
1067    GetVertex(maxvIdx, vmax);
1068    float h = fabs(vmin[axisO] - viewpoint[axisO]);
1069    int axis = (axisO + 1) % 3; // next axis
1070    float a = (vmin[axis] - viewpoint[axis]) / h; // minimum for v-range
1071    float b = (vmax[axis] - viewpoint[axis]) / h; // maximum for v-range
1072    //if (a > b) {
1073    //  FATAL << "ProjectToSphereSA::Error a > b\n";
1074    //  FATAL_ABORT;
1075    //}
1076    //if (vmin[axisO] != vmax[axisO]) {
1077    //  FATAL << "ProjectToSphereSA::Error a-axis != b-axis\n";
1078    //  FATAL_ABORT;     
1079    //}
1080    axis = (axisO + 2) % 3; // next second axis       
1081    float c = (vmin[axis] - viewpoint[axis]) / h; // minimum for u-range
1082    float d = (vmax[axis] - viewpoint[axis]) / h; // maximum for u-range
1083    //if (c > d) {
1084    //  FATAL << "ProjectToSphereSA::Error c > d\n";
1085    //  FATAL_ABORT;
1086    //}
1087    SA +=atan22(d*b/sqrt(b*b + d*d + 1.0)) - atan22(b*c/sqrt(b*b + c*c + 1.0))
1088      - atan22(d*a/sqrt(a*a + d*d + 1.0)) + atan22(a*c/sqrt(a*a + c*c + 1.0));
1089  }
1090
1091#if 0
1092  if ((SA > 2.0*M_PI) ||
1093      (SA < 0.0)) {
1094    FATAL << "The solid angle has strange value: ";
1095    FATAL << "SA = "<< SA << endl;
1096    FATAL_ABORT;
1097  }
1098#endif
1099 
1100  return SA;
1101}
1102
1103// Projects the box to a plane given a normal vector only and
1104// computes the surface area of the projected silhouette
1105// no clipping of the box is performed.
1106float
1107AxisAlignedBox3::ProjectToPlaneSA(const Vector3 &normal) const
1108{
1109  Vector3 size = Size();
1110
1111  // the surface area of the box to a yz-plane - perpendicular to x-axis
1112  float sax = size.y * size.z;
1113
1114  // the surface area of the box to a zx-plane - perpendicular to y-axis
1115  float say = size.z * size.x;
1116
1117  // the surface area of the box to a xy-plane - perpendicular to z-axis
1118  float saz = size.x * size.y;
1119 
1120  return sax * fabs(normal.x) + say * fabs(normal.y) + saz * fabs(normal.z);
1121}
1122
1123
1124
1125// This definition allows to be a point when answering true
1126bool
1127AxisAlignedBox3::IsCorrectAndNotPoint() const
1128{
1129  if ( (mMin.x > mMax.x) ||
1130       (mMin.y > mMax.y) ||
1131       (mMin.z > mMax.z) )
1132    return false; // box is not formed
1133
1134  if ( (mMin.x == mMax.x) &&
1135       (mMin.y == mMax.y) &&
1136       (mMin.z == mMax.z) )
1137    return false; // degenerates to a point
1138 
1139  return true;
1140}
1141
1142// This definition allows to be a point when answering true
1143bool
1144AxisAlignedBox3::IsPoint() const
1145{
1146  if ( (mMin.x == mMax.x) &&
1147       (mMin.y == mMax.y) &&
1148       (mMin.z == mMax.z) )
1149    return true; // degenerates to a point
1150 
1151  return false;
1152}
1153
1154// This definition requires shape of non-zero volume
1155bool
1156AxisAlignedBox3::IsSingularOrIncorrect() const
1157{
1158  if ( (mMin.x >= mMax.x) ||
1159       (mMin.y >= mMax.y) ||
1160       (mMin.z >= mMax.z) )
1161    return true; // box is not formed
1162
1163  return false; // has non-zero volume
1164}
1165
1166// returns true, when the sphere specified by the origin and radius
1167// fully contains the box
1168bool
1169AxisAlignedBox3::IsFullyContainedInSphere(const Vector3 &center, float rad) const
1170{
1171  int region = GetRegionID(center);
1172  float rad2 = rad*rad;
1173
1174  // vertex of the box
1175  Vector3 vertex;
1176
1177  int i = 0;
1178  for (i = 0 ; ; i++) {
1179    int a = fsvertices[region][i];
1180    if (a == 15)
1181      return true; // if was not false untill now, it must be contained
1182
1183    assert( (a>=0) && (a<8) );
1184   
1185    // normal vertex
1186    GetVertex(a, vertex);
1187
1188    if (SqrMagnitude(vertex - center) > rad2)
1189      return false;   
1190  } // for
1191 
1192}
1193
1194// returns true, when the volume of the sphere and volume of the
1195// axis aligned box has no intersection
1196bool
1197AxisAlignedBox3::HasNoIntersectionWithSphere(const Vector3 &center, float rad) const
1198{
1199  int region = GetRegionID(center);
1200  float rad2 = rad*rad;
1201
1202  // vertex of the box
1203  Vector3 vertex;
1204
1205  switch (csvertices[region][0]) {
1206  case 8: {
1207    // test two coordinates described within the field
1208    int face = 3*csvertices[region][1] + csvertices[region][2];
1209    float dist = GetExtent(face) - center[csvertices[region][2]];
1210    dist *= dist;
1211    face = 3 * (csvertices[region][3]) + csvertices[region][4];
1212    float dist2 = GetExtent(face) - center[csvertices[region][4]];
1213    dist += (dist2 * dist2);
1214    if (dist > rad2)
1215      return true; // no intersection is possible
1216  }
1217  case 9: {
1218    // test one coordinate described within the field
1219    int face = 3*csvertices[region][1] + csvertices[region][2];
1220    float dist = fabs(GetExtent(face) - center[csvertices[region][2]]);
1221    if (dist > rad)
1222      return true; // no intersection is possible
1223  }
1224  case 15:
1225    return false; // box and sphere surely has intersection
1226  default: {
1227    // test using normal vertices
1228    assert( (csvertices[region][0]>=0) && (csvertices[region][0]<8) );
1229
1230    // normal vertex
1231    GetVertex(csvertices[region][0], vertex);
1232
1233    if (SqrMagnitude(vertex - center) > rad2)
1234      return true; // no intersectino is possible   
1235    }
1236  } // switch
1237
1238  return false; // partial or full containtment
1239}
1240
1241#if 0
1242// Given the sphere, determine the mutual position between the
1243// sphere and box
1244
1245// SOME BUG IS INSIDE !!!! V.H. 25/4/2001
1246int
1247AxisAlignedBox3::MutualPositionWithSphere(const Vector3 &center, float rad) const
1248{
1249  int region = GetRegionID(center);
1250  float rad2 = rad*rad;
1251
1252  // vertex of the box
1253  Vector3 vertex;
1254
1255  // first testing for  full containtment - whether sphere fully
1256  // contains the box
1257  int countInside = 0; // how many points were found inside
1258 
1259  int i = 0;
1260  for (i = 0 ; ; i++) {
1261    int a = fsvertices[region][i];
1262    if (a == 15)
1263      return 1; // the sphere fully contain the box
1264
1265    assert( (a>=0) && (a<8) );
1266   
1267    // normal vertex
1268    GetVertex(a, vertex);
1269
1270    if (SqrMagnitude(vertex - center) <= rad2)
1271      countInside++; // the number of vertices inside the sphere
1272    else {
1273      if (countInside)
1274        return 0; // partiall overlap has been found
1275      // the sphere does not fully contain the box .. only way to break
1276      // this loop and go for other testing
1277      break;
1278    }
1279  } // for
1280
1281  // now only box and sphere can partially overlap or no intersection
1282  switch (csvertices[region][0]) {
1283  case 8: {
1284    // test two coordinates described within the field
1285    int face = 3*csvertices[region][1] + csvertices[region][2];
1286    float dist = GetExtent(face) - center[csvertices[region][2]];
1287    dist *= dist;
1288    face = 3 * (csvertices[region][3]) + csvertices[region][4];
1289    float dist2 = GetExtent(face) - center[csvertices[region][4]];
1290    dist += (dist2 * dist2);
1291    if (dist > rad2 )
1292      return -1; // no intersection is possible
1293  }
1294  case 9: {
1295    // test one coordinate described within the field
1296    int face = 3*csvertices[region][1] + csvertices[region][2];
1297    float dist = fabs(GetExtent(face) - center[csvertices[region][2]]);
1298    if (dist > rad)
1299      return -1; // no intersection is possible
1300  }
1301  case 15:
1302    return 0 ; // partial overlap is now guaranteed
1303  default: {
1304    // test using normal vertices
1305    assert( (csvertices[region][0]>=0) && (csvertices[region][0]<8) );
1306   
1307    // normal vertex
1308    GetVertex(csvertices[region][0], vertex);
1309
1310    if (SqrMagnitude(vertex - center) > rad2)
1311      return -1; // no intersection is possible   
1312    }
1313  } // switch
1314
1315  return 0; // partial intersection is guaranteed
1316}
1317#else
1318
1319// Some maybe smarter version, extendible easily to d-dimensional
1320// space!
1321// Given a sphere described by the center and radius,
1322// the fullowing function returns:
1323//   -1 ... the sphere and the box are completely separate
1324//    0 ... the sphere and the box only partially overlap
1325//    1 ... the sphere contains fully the box
1326//  Note: the case when box fully contains the sphere is not reported
1327//        since it was not required.
1328int
1329AxisAlignedBox3::MutualPositionWithSphere(const Vector3 &center, float rad) const
1330{
1331//#define SPEED_UP
1332
1333#ifndef SPEED_UP
1334  // slow version, instructively written 
1335#if 0
1336  // does it make sense to test
1337  // checking the sides of the box for possible non-intersection
1338  if ( ((center.x + rad) < mMin.x) ||
1339       ((center.x - rad) > mMax.x) ||
1340       ((center.y + rad) < mMin.y) ||
1341       ((center.y - rad) > mMax.y) ||
1342       ((center.z + rad) < mMin.z) ||
1343       ((center.z - rad) > mMax.z) ) {
1344    // cout << "r ";
1345    return -1;  // no overlap is possible
1346  }
1347#endif
1348 
1349  // someoverlap is possible, check the distance of vertices
1350  rad = rad*rad;
1351  float sumMin = 0;
1352  // Try to minimize the function of a distance
1353  // from the sphere center
1354
1355  // for x-axis
1356  float minSqrX = sqr(mMin.x - center.x);
1357  float maxSqrX = sqr(mMax.x - center.x);
1358  if (center.x < mMin.x)
1359    sumMin = minSqrX;
1360  else
1361    if (center.x > mMax.x)
1362      sumMin = maxSqrX;
1363
1364  // for y-axis
1365  float minSqrY = sqr(mMin.y - center.y);
1366  float maxSqrY = sqr(mMax.y - center.y);
1367  if (center.y < mMin.y)
1368    sumMin += minSqrY;
1369  else
1370    if (center.y > mMax.y)
1371      sumMin += maxSqrY;
1372
1373  // for z-axis
1374  float minSqrZ = sqr(mMin.z - center.z);
1375  float maxSqrZ = sqr(mMax.z - center.z);
1376  if (center.z < mMin.z)
1377    sumMin += minSqrZ;
1378  else
1379    if (center.z > mMax.z)
1380      sumMin += maxSqrZ;
1381
1382  if (sumMin > rad)
1383    return -1; // no intersection between sphere and box
1384
1385  // try to find out the maximum distance between the
1386  // sphere center and vertices
1387  float sumMax = 0;
1388 
1389  if (minSqrX > maxSqrX)
1390    sumMax = minSqrX;
1391  else
1392    sumMax = maxSqrX;
1393 
1394  if (minSqrY > maxSqrY)
1395    sumMax += minSqrY;
1396  else
1397    sumMax += maxSqrY;
1398 
1399  if (minSqrZ > maxSqrZ)
1400    sumMax += minSqrZ;
1401  else
1402    sumMax += maxSqrZ;
1403 
1404  // sumMin < rad
1405  if (sumMax < rad)
1406    return 1; // the sphere contains the box completely
1407
1408  // partial intersection, part of the box is outside the sphere
1409  return 0;
1410#else
1411
1412  // Optimized version of the test
1413 
1414#ifndef __VECTOR_HACK
1415#error "__VECTOR_HACK for Vector3 was not defined"
1416#endif
1417
1418  // some overlap is possible, check the distance of vertices
1419  rad = rad*rad;
1420  float sumMin = 0;
1421  float sumMax = 0;
1422  // Try to minimize the function of a distance
1423  // from the sphere center
1424
1425  const float *minp = &(min[0]);
1426  const float *maxp = &(max[0]);
1427  const float *pcenter = &(center[0]);
1428 
1429  // for x-axis
1430  for (int i = 0; i < 3; i++, minp++, maxp++, pcenter++) {
1431    float minsqr = sqr(*minp - *pcenter);
1432    float maxsqr = sqr(*maxp - *pcenter);
1433    if (*pcenter < *minp)
1434      sumMin += minsqr;
1435    else
1436      if (*pcenter > *maxp)
1437        sumMin += maxsqr;
1438    sumMax += (minsqr > maxsqr) ? minsqr : maxsqr;
1439  }
1440
1441  if (sumMin > rad)
1442    return -1; // no intersection between sphere and box
1443
1444  // sumMin < rad
1445  if (sumMax < rad)
1446    return 1; // the sphere contains the box completely
1447
1448  // partial intersection, part of the box is outside the sphere
1449  return 0;
1450#endif
1451}
1452#endif
1453
1454// Given the cube describe by the center and the half-sie,
1455// determine the mutual position between the cube and the box
1456int
1457AxisAlignedBox3::MutualPositionWithCube(const Vector3 &center, float radius) const
1458{
1459  // the cube is described by the center and the distance to the any face
1460  // along the axes
1461
1462  // Note on efficiency!
1463  // Can be quite optimized using tables, but I do not have time
1464  // V.H. 18/11/2001
1465
1466  AxisAlignedBox3 a =
1467    AxisAlignedBox3(Vector3(center.x - radius, center.y - radius, center.z - radius),
1468           Vector3(center.x + radius, center.y + radius, center.z + radius));
1469
1470  if (a.Includes(*this))
1471    return 1; // cube contains the box
1472
1473  if (OverlapS(a,*this))
1474    return 0; // cube partially overlap the box
1475
1476  return -1; // completely separate 
1477}
1478
1479void
1480AxisAlignedBox3::GetSqrDistances(const Vector3 &point,
1481                                 float &minDistance,
1482                                 float &maxDistance
1483                                 ) const
1484{
1485
1486 
1487#ifndef __VECTOR_HACK
1488#error "__VECTOR_HACK for Vector3 was not defined"
1489#endif
1490
1491  // some overlap is possible, check the distance of vertices
1492  float sumMin = 0;
1493  float sumMax = 0;
1494
1495  // Try to minimize the function of a distance
1496  // from the sphere center
1497
1498  const float *minp = &(mMin[0]);
1499  const float *maxp = &(mMax[0]);
1500  const float *pcenter = &(point[0]);
1501 
1502  // for x-axis
1503  for (int i = 0; i < 3; i++, minp++, maxp++, pcenter++) {
1504    float minsqr = sqr(*minp - *pcenter);
1505    float maxsqr = sqr(*maxp - *pcenter);
1506    if (*pcenter < *minp)
1507      sumMin += minsqr;
1508    else
1509      if (*pcenter > *maxp)
1510        sumMin += maxsqr;
1511    sumMax += (minsqr > maxsqr) ? minsqr : maxsqr;
1512  }
1513
1514  minDistance = sumMin;
1515  maxDistance = sumMax;
1516}
1517
1518
1519int
1520AxisAlignedBox3::Side(const Plane3 &plane) const
1521{
1522  Vector3 v;
1523  int i, m=3, M=-3, s;
1524 
1525  for (i=0;i<8;i++) {
1526    GetVertex(i, v);
1527    if((s = plane.Side(v)) < m)
1528      m=s;
1529    if(s > M)
1530      M=s;
1531    if (m && m==-M)
1532      return 0;
1533  }
1534 
1535  return (m == M) ? m : m + M;
1536}
1537
1538int
1539AxisAlignedBox3::GetFaceVisibilityMask(const Rectangle3 &rectangle) const
1540{
1541  int mask = 0;
1542  for (int i=0; i < 4; i++)
1543    mask |= GetFaceVisibilityMask(rectangle.mVertices[i]);
1544  return mask;
1545}
1546
1547int
1548AxisAlignedBox3::GetFaceVisibilityMask(const Vector3 &position) const {
1549 
1550  // assume that we are not inside the box
1551  int c=0;
1552 
1553  if (position.x<(mMin.x-Limits::Small))
1554    c|=1;
1555  else
1556    if (position.x>(mMax.x+Limits::Small))
1557      c|=2;
1558 
1559  if (position.y<(mMin.y-Limits::Small))
1560    c|=4;
1561  else
1562    if (position.y>(mMax.y+Limits::Small))
1563      c|=8;
1564 
1565  if (position.z<(mMin.z-Limits::Small))
1566    c|=16;
1567  else
1568    if (position.z>(mMax.z+Limits::Small))
1569      c|=32;
1570 
1571  return c;
1572}
1573
1574
1575Rectangle3
1576AxisAlignedBox3::GetFace(const int face) const
1577{
1578  Vector3 v[4];
1579  switch (face) {
1580   
1581  case 0:
1582    v[3].SetValue(mMin.x,mMin.y,mMin.z);
1583    v[2].SetValue(mMin.x,mMax.y,mMin.z);
1584    v[1].SetValue(mMin.x,mMax.y,mMax.z);
1585    v[0].SetValue(mMin.x,mMin.y,mMax.z);
1586    break;
1587   
1588  case 1:
1589    v[0].SetValue(mMax.x,mMin.y,mMin.z);
1590    v[1].SetValue(mMax.x,mMax.y,mMin.z);
1591    v[2].SetValue(mMax.x,mMax.y,mMax.z);
1592    v[3].SetValue(mMax.x,mMin.y,mMax.z);
1593    break;
1594   
1595  case 2:
1596    v[3].SetValue(mMin.x,mMin.y,mMin.z);
1597    v[2].SetValue(mMin.x,mMin.y,mMax.z);
1598    v[1].SetValue(mMax.x,mMin.y,mMax.z);
1599    v[0].SetValue(mMax.x,mMin.y,mMin.z);
1600    break;
1601 
1602  case 3:
1603    v[0].SetValue(mMin.x,mMax.y,mMin.z);
1604    v[1].SetValue(mMin.x,mMax.y,mMax.z);
1605    v[2].SetValue(mMax.x,mMax.y,mMax.z);
1606    v[3].SetValue(mMax.x,mMax.y,mMin.z);
1607    break;
1608
1609  case 4:
1610    v[3].SetValue(mMin.x,mMin.y,mMin.z);
1611    v[2].SetValue(mMax.x,mMin.y,mMin.z);
1612    v[1].SetValue(mMax.x,mMax.y,mMin.z);
1613    v[0].SetValue(mMin.x,mMax.y,mMin.z);
1614    break;
1615 
1616  case 5:
1617    v[0].SetValue(mMin.x,mMin.y,mMax.z);
1618    v[1].SetValue(mMax.x,mMin.y,mMax.z);
1619    v[2].SetValue(mMax.x,mMax.y,mMax.z);
1620    v[3].SetValue(mMin.x,mMax.y,mMax.z);
1621    break;
1622  }
1623 
1624  return Rectangle3(v[0], v[1], v[2], v[3]);
1625}
Note: See TracBrowser for help on using the repository browser.