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

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

put out debug output. added new subdivision strategies

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  return 2.0 * (ext.x * ext.y +
660                ext.x * ext.z +
661                ext.y * ext.z);
662}
663
664const int AxisAlignedBox3::bvertices[27][9] =
665{                   // region number.. position
666  {5,1,3,2,6,4,-1,-1,-1},      // 0 .. x=0 y=0 z=0
667  {4,5,1,3,2,0,-1,-1,-1},      // 1 .. x=0 y=0 z=1
668  {4,5,7,3,2,0,-1,-1,-1},      // 2 .. x=0 y=0 z=2
669
670  {0,1,3,2,6,4,-1,-1,-1},      // 3 .. x=0 y=1 z=0
671  {0,1,3,2,-1,-1,-1,-1,-1},    // 4 .. x=0 y=1 z=1
672  {1,5,7,3,2,0,-1,-1,-1},      // 5 .. x=0 y=1 z=2
673
674  {0,1,3,7,6,4,-1,-1,-1},      // 6 .. x=0 y=2 z=0
675  {0,1,3,7,6,2,-1,-1,-1},      // 7 .. x=0 y=2 z=1
676  {1,5,7,6,2,0,-1,-1,-1},      // 8 .. x=0 y=2 z=2
677
678  // the regions number <9,17>
679  {5,1,0,2,6,4,-1,-1,-1},      // 9  .. x=1 y=0 z=0
680  {5,1,0,4,-1,-1,-1,-1,-1},    // 10 .. x=1 y=0 z=1
681  {7,3,1,0,4,5,-1,-1,-1},      // 11 .. x=1 y=0 z=2
682
683  {4,0,2,6,-1,-1,-1,-1,-1},    // 12 .. x=1 y=1 z=0
684  {0,2,3,1,5,4,6,7,-1},        // 13 .. x=1 y=1 z=1 .. inside the box
685  {1,5,7,3,-1,-1,-1,-1,-1},    // 14 .. x=1 y=1 z=2
686
687  {4,0,2,3,7,6,-1,-1,-1},      // 15 .. x=1 y=2 z=0
688  {6,2,3,7,-1,-1,-1,-1,-1},    // 16 .. x=1 y=2 z=1
689  {1,5,7,6,2,3,-1,-1,-1},      // 17 .. x=1 y=2 z=2
690
691  // the regions number <18,26>
692  {1,0,2,6,7,5,-1,-1,-1},      // 18 .. x=2 y=0 z=0
693  {1,0,4,6,7,5,-1,-1,-1},      // 19 .. x=2 y=0 z=1
694  {0,4,6,7,3,1,-1,-1,-1},      // 20 .. x=2 y=0 z=2
695
696  {4,0,2,6,7,5,-1,-1,-1},      // 21 .. x=2 y=1 z=0
697  {5,4,6,7,-1,-1,-1,-1,-1},    // 22 .. x=2 y=1 z=1
698  {5,4,6,7,3,1,-1,-1,-1},      // 23 .. x=2 y=1 z=2
699
700  {4,0,2,3,7,5,-1,-1,-1},      // 24 .. x=2 y=2 z=0
701  {5,4,6,2,3,7,-1,-1,-1},      // 25 .. x=2 y=2 z=1
702  {5,4,6,2,3,1,-1,-1,-1},      // 26 .. x=2 y=2 z=2
703};
704
705// the visibility of boundary faces from a given region
706// one to three triples: (axis, min_vertex, max_vertex), axis==-1(terminator)
707const int AxisAlignedBox3::bfaces[27][10] =
708{                              // region number .. position
709  {0,0,3,1,0,5,2,0,6,-1},      // 0 .. x=0 y=0 z=0
710  {0,0,3,1,0,5,-1,-1,-1,-1},   // 1 .. x=0 y=0 z=1
711  {0,0,3,1,0,5,2,1,7,-1},      // 2 .. x=0 y=0 z=2
712
713  {0,0,3,2,0,6,-1,-1,-1,-1},   // 3 .. x=0 y=1 z=0
714  {0,0,3,-1,-1,-1,-1,-1,-1,-1},// 4 .. x=0 y=1 z=1
715  {0,0,3,2,1,7,-1,-1,-1,-1},   // 5 .. x=0 y=1 z=2
716
717  {0,0,3,1,2,7,2,0,6,-1},      // 6 .. x=0 y=2 z=0
718  {0,0,3,1,2,7,-1,-1,-1,-1},   // 7 .. x=0 y=2 z=1
719  {0,0,3,1,2,7,2,1,7,-1},      // 8 .. x=0 y=2 z=2
720
721  // the regions number <9,17>
722  {1,0,5,2,0,6,-1,-1,-1,-1},   // 9  .. x=1 y=0 z=0
723  {1,0,5,-1,-1,-1,-1,-1,-1,-1},// 10 .. x=1 y=0 z=1
724  {1,0,5,2,1,7,-1,-1,-1,-1},   // 11 .. x=1 y=0 z=2
725
726  {2,0,6,-1,-1,-1,-1,-1,-1,-1},// 12 .. x=1 y=1 z=0
727  {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},// 13 .. x=1 y=1 z=1 .. inside the box
728  {2,1,7,-1,-1,-1,-1,-1,-1,-1},// 14 .. x=1 y=1 z=2
729
730  {1,2,7,2,0,6,-1,-1,-1,-1},   // 15 .. x=1 y=2 z=0
731  {1,2,7,-1,-1,-1,-1,-1,-1,-1},// 16 .. x=1 y=2 z=1
732  {1,2,7,2,1,7,-1,-1,-1,-1},   // 17 .. x=1 y=2 z=2
733
734  // the region number <18,26>
735  {0,4,7,1,0,5,2,0,6,-1},      // 18 .. x=2 y=0 z=0
736  {0,4,7,1,0,5,-1,-1,-1,-1},   // 19 .. x=2 y=0 z=1
737  {0,4,7,1,0,5,2,1,7,-1},      // 20 .. x=2 y=0 z=2
738
739  {0,4,7,2,0,6,-1,-1,-1,-1},   // 21 .. x=2 y=1 z=0
740  {0,4,7,-1,-1,-1,-1,-1,-1,-1},// 22 .. x=2 y=1 z=1
741  {0,4,7,2,1,7,-1,-1,-1,-1},   // 23 .. x=2 y=1 z=2
742
743  {0,4,7,1,2,7,2,0,6,-1},      // 24 .. x=2 y=2 z=0
744  {0,4,7,1,2,7,-1,-1,-1,-1},   // 25 .. x=2 y=2 z=1
745  {0,4,7,1,2,7,2,1,7,-1},      // 26 .. x=2 y=2 z=2
746};
747
748// the correct corners indexing from entry face to exit face
749// first index determines entry face, second index exit face, and
750// the two numbers (indx, inc) determines: ind = the index on the exit
751// face, when starting from the vertex 0 on entry face, 'inc' is
752// the increment when we go on entry face in order 0,1,2,3 to create
753// convex shaft with the rectangle on exit face. That is, inc = -1 or 1.
754const int AxisAlignedBox3::pairFaceRects[6][6][2] = {
755  { // entry face = 0
756    {-1,0}, // exit face 0 .. no meaning
757    {0,-1}, // 1
758    {0,-1}, // 2
759    {0,1}, // 3 .. opposite face
760    {3,1}, // 4
761    {1,1} // 5
762  },
763  { // entry face = 1
764    {0,-1}, // exit face 0
765    {-1,0}, // 1 .. no meaning
766    {0,-1}, // 2
767    {1,1}, // 3
768    {0,1}, // 4 .. opposite face
769    {3,1} // 5
770  },
771  { // entry face = 2
772    {0,-1}, // 0
773    {0,-1}, // 1
774    {-1,0}, // 2 .. no meaning
775    {3,1}, // 3
776    {1,1}, // 4
777    {0,1} // 5 .. opposite face
778  },
779  { // entry face = 3
780    {0,1}, // 0 .. opposite face
781    {3,-1}, // 1
782    {1,1}, // 2
783    {-1,0}, // 3  .. no meaning
784    {0,-1}, // 4
785    {0,-1} // 5
786  },
787  { // entry face = 4
788    {1,1}, // 0
789    {0,1}, // 1 .. opposite face
790    {3,1}, // 2
791    {0,-1}, // 3
792    {-1,0}, // 4 .. no meaning
793    {0,-1} // 5
794  },
795  { // entry face = 5
796    {3,-1}, // 0
797    {1,1}, // 1
798    {0,1}, // 2  .. opposite face
799    {0,-1}, // 3
800    {0,-1}, // 4
801    {-1,0} // 5 .. no meaning
802  }
803};
804
805
806// ------------------------------------------------------------
807// The vertices that form CLOSEST points with respect to the region
808// for all the regions possible, number of regions is 3^3 = 27,
809// since two parallel sides of bbox forms three disjoint spaces.
810// The vertices are given in anti-clockwise order, stopped by value 15,
811// at most 8 points, at least 1 point.
812// The table includes the closest 1/2/4/8 points, followed possibly
813// by the set of coordinates that should be used for testing for
814// the proximity queries. The coordinates to be tested are described by
815// the pair (a,b), when a=0, we want to test min vector of the box,
816//                 when a=1, we want to test max vector of the box
817//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
818// The sequence is ended by 15, number -1 is used as the separator
819// between the vertices and coordinates.
820const int
821AxisAlignedBox3::cvertices[27][9] =
822{                   // region number.. position
823  {0,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D one vertex
824  {0,1,-1,0,0,0,1,15,15},      // 1 .. x=0 y=0 z=1 D two vertices foll. by 2
825  {1,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D one vertex
826
827  {0,2,-1,0,0,0,2,15,15},      // 3 .. x=0 y=1 z=0 D
828  {0,1,3,2,-1,0,0,15,15},      // 4 .. x=0 y=1 z=1 D
829  {1,3,-1,0,0,1,2,15,15},      // 5 .. x=0 y=1 z=2 D
830
831  {2,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
832  {2,3,-1,0,0,1,1,15,15},      // 7 .. x=0 y=2 z=1 D
833  {3,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
834
835  // the regions number <9,17>
836  {0,4,-1,0,1,0,2,15,15},      // 9  .. x=1 y=0 z=0 D
837  {5,1,0,4,-1,0,1,15,15},      // 10 .. x=1 y=0 z=1 D
838  {1,5,-1,0,1,1,2,15,15},      // 11 .. x=1 y=0 z=2 D
839
840  {4,0,2,6,-1,0,2,15,15},      // 12 .. x=1 y=1 z=0 D
841  {0,2,3,1,5,4,6,7,15},        // 13 .. x=1 y=1 z=1 .. inside the box
842  {1,5,7,3,-1,1,2,15,15},      // 14 .. x=1 y=1 z=2 D
843
844  {6,2,-1,0,2,1,1,15,15},      // 15 .. x=1 y=2 z=0 D
845  {6,2,3,7,-1,1,1,15,15},      // 16 .. x=1 y=2 z=1 D
846  {3,7,-1,1,1,1,2,15,15},      // 17 .. x=1 y=2 z=2 D
847
848  // the regions number <18,26>
849  {4,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
850  {4,5,-1,0,1,1,0,15,15},      // 19 .. x=2 y=0 z=1 D
851  {5,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
852
853  {4,6,-1,0,2,1,0,15,15},      // 21 .. x=2 y=1 z=0 D
854  {5,4,6,7,-1,1,0,15,15},      // 22 .. x=2 y=1 z=1 D
855  {7,5,-1,1,0,1,2,15,15},      // 23 .. x=2 y=1 z=2 D
856
857  {6,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
858  {6,7,-1,1,0,1,1,15,15},      // 25 .. x=2 y=2 z=1 D
859  {7,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
860};
861
862// Table for Sphere-AABB intersection based on the region knowledge
863// Similar array to previous cvertices, but we omit the surfaces
864// which are not necessary for testing. First are vertices,
865// they are finished with -1. Second, there are indexes in
866// the pair (a,b), when a=0, we want to test min vector of the box,
867//                 when a=1, we want to test max vector of the box
868//                 b=0,1,2 corresponds to the axis (0=x,1=y,2=z)
869//
870// So either we check the vertices or only the distance in specified
871// dimensions. There are at all four possible cases:
872//
873//   1) we check one vertex - then sequence start with non-negative index
874//      and is finished with 15
875//   2) we check two coordinates of min/max vector describe by the pair
876//         (a,b) .. a=min/max(0/1) b=x/y/z (0/1/2), sequence starts with 8
877//      and finishes with 15
878//   3) we check only one coordinate of min/max, as for 2), sequence start
879//      with 9 and ends with 15
880//   4) Position 13 - sphere is inside the box, intersection always exist
881//        the sequence start with 15 .. no further testing is necessary
882//        in this case
883const int
884AxisAlignedBox3::csvertices[27][6] =
885{                   // region number.. position
886  {0,15,15,15,15,15},  // 0 .. x=0 y=0 z=0 D vertex only
887  {8,0,0,0,1,15},      // 1 .. x=0 y=0 z=1 D two coords.
888  {1,15,15,15,15,15},  // 2 .. x=0 y=0 z=2 D vertex only
889
890  {8,0,0,0,2,15},      // 3 .. x=0 y=1 z=0 D two coords
891  {9,0,0,15,15,15},    // 4 .. x=0 y=1 z=1 D one coord
892  {8,0,0,1,2,15},      // 5 .. x=0 y=1 z=2 D two coords.
893
894  {2,15,15,15,15,15},  // 6 .. x=0 y=2 z=0 D one vertex
895  {8,0,0,1,1,15},      // 7 .. x=0 y=2 z=1 D two coords
896  {3,15,15,15,15,15},  // 8 .. x=0 y=2 z=2 D one vertex
897
898  // the regions number <9,17>
899  {8,0,1,0,2,15},      // 9  .. x=1 y=0 z=0 D two coords
900  {9,0,1,15,15,15},    // 10 .. x=1 y=0 z=1 D one coord
901  {8,0,1,1,2,15},      // 11 .. x=1 y=0 z=2 D two coords
902
903  {9,0,2,15,15,15},    // 12 .. x=1 y=1 z=0 D one coord
904  {15,15,15,15,15,15}, // 13 .. x=1 y=1 z=1 inside the box, special case/value
905  {9,1,2,15,15,15},    // 14 .. x=1 y=1 z=2 D one corrd
906
907  {8,0,2,1,1,15},      // 15 .. x=1 y=2 z=0 D two coords
908  {9,1,1,15,15},       // 16 .. x=1 y=2 z=1 D one coord
909  {8,1,1,1,2,15},      // 17 .. x=1 y=2 z=2 D two coords
910
911  // the regions number <18,26>
912  {4,15,15,15,15,15},  // 18 .. x=2 y=0 z=0 D one vertex
913  {8,0,1,1,0,15},      // 19 .. x=2 y=0 z=1 D two coords
914  {5,15,15,15,15,15},  // 20 .. x=2 y=0 z=2 D one vertex
915
916  {8,0,2,1,0,15},      // 21 .. x=2 y=1 z=0 D two coords
917  {9,1,0,15,15,15},    // 22 .. x=2 y=1 z=1 D one coord
918  {8,1,0,1,2,15},      // 23 .. x=2 y=1 z=2 D two coords
919
920  {6,15,15,15,15,15},  // 24 .. x=2 y=2 z=0 D one vertex
921  {8,1,0,1,1,15},      // 25 .. x=2 y=2 z=1 D two coords
922  {7,15,15,15,15,15},  // 26 .. x=2 y=2 z=2 D one vertex
923};
924
925
926// The vertices that form all FARTHEST points with respect to the region
927// for all the regions possible, number of regions is 3^3 = 27,
928// since two parallel sides of bbox forms three disjoint spaces.
929// The vertices are given in anti-clockwise order, stopped by value 15,
930// at most 8 points, at least 1 point.
931// For testing, if the AABB is whole in the sphere, it is enough
932// to test only vertices, either 1,2,4, or 8.
933const int
934AxisAlignedBox3::fvertices[27][9] =
935{                   // region number.. position
936  {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D
937  {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D
938  {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D
939
940  {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D
941  {4,5,7,6,15,15,15,15,15},    // 4 .. x=0 y=1 z=1 D
942  {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D
943
944  {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D
945  {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D
946  {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D
947
948  // the regions number <9,17>
949  {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D
950  {7,3,2,6,15,15,15,15,15},    // 10 .. x=1 y=0 z=1 D
951  {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D
952
953  {5,1,3,7,15,15,15,15,15},    // 12 .. x=1 y=1 z=0 D
954  {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
955  {0,4,6,2,15,15,15,15,15},    // 14 .. x=1 y=1 z=2 D
956
957  {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D
958  {4,0,1,5,15,15,15,15,15},    // 16 .. x=1 y=2 z=1 D
959  {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D
960
961  // the regions number <18,26>
962  {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D
963  {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D
964  {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D
965
966  {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D
967  {1,0,2,3,15,15,15,15,15},    // 22 .. x=2 y=1 z=1 D
968  {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D
969
970  {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D
971  {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D
972  {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D
973};
974
975// Similar table as above, farthest points, but only the ones
976// necessary for testing the intersection problem. If we do
977// not consider the case 13, center of the sphere is inside the
978// box, then we can always test at most 2 box vertices to say whether
979// the whole box is inside the sphere.
980// The number of vertices is minimized using some assumptions
981// about the ortogonality of vertices and sphere properties.
982const int
983AxisAlignedBox3::fsvertices[27][9] =
984{                   // region number.. position
985  {7,15,15,15,15,15,15,15,15}, // 0 .. x=0 y=0 z=0 D 1 vertex
986  {6,7,15,15,15,15,15,15,15},  // 1 .. x=0 y=0 z=1 D 2 vertices
987  {6,15,15,15,15,15,15,15,15}, // 2 .. x=0 y=0 z=2 D 1 vertex
988
989  {5,7,15,15,15,15,15,15,15},  // 3 .. x=0 y=1 z=0 D 2 vertices
990  {4,7,15,5,6,15,15,15,15},    // 4 .. x=0 y=1 z=1 D 4/2 vertices
991  {4,6,15,15,15,15,15,15,15},  // 5 .. x=0 y=1 z=2 D 2 vertices
992
993  {5,15,15,15,15,15,15,15,15}, // 6 .. x=0 y=2 z=0 D 1 vertex
994  {4,5,15,15,15,15,15,15,15},  // 7 .. x=0 y=2 z=1 D 2 vertices
995  {4,15,15,15,15,15,15,15,15}, // 8 .. x=0 y=2 z=2 D 1 vertex
996
997  // the regions number <9,17>
998  {3,7,15,15,15,15,15,15,15},  // 9  .. x=1 y=0 z=0 D 2 vertices
999  {7,2,15,3,6,15,15,15,15},    // 10 .. x=1 y=0 z=1 D 4/2 vertices
1000  {2,6,15,15,15,15,15,15,15},  // 11 .. x=1 y=0 z=2 D 2 vertices
1001
1002  {5,3,15,1,7,15,15,15,15},    // 12 .. x=1 y=1 z=0 D 4/2 vertices
1003  {0,7,1,6,3,4,5,2,15},        // 13 .. x=1 y=1 z=1 .. inside the box
1004  {0,6,15,4,2,15,15,15,15},    // 14 .. x=1 y=1 z=2 D 4/2 vertices
1005
1006  {5,1,15,15,15,15,15,15,15},  // 15 .. x=1 y=2 z=0 D 2 vertices
1007  {4,1,15,0,5,15,15,15,15},    // 16 .. x=1 y=2 z=1 D 4/2 vertices
1008  {4,0,15,15,15,15,15,15,15},  // 17 .. x=1 y=2 z=2 D 2 vertices
1009
1010  // the regions number <18,26>
1011  {3,15,15,15,15,15,15,15,15}, // 18 .. x=2 y=0 z=0 D 1 vertex
1012  {2,3,15,15,15,15,15,15,15},  // 19 .. x=2 y=0 z=1 D 2 vertices
1013  {2,15,15,15,15,15,15,15,15}, // 20 .. x=2 y=0 z=2 D 1 vertex
1014
1015  {1,3,15,15,15,15,15,15,15},  // 21 .. x=2 y=1 z=0 D 2 vertices
1016  {1,2,15,0,3,15,15,15,15},    // 22 .. x=2 y=1 z=1 D 4/2 vertices
1017  {2,0,15,15,15,15,15,15,15},  // 23 .. x=2 y=1 z=2 D 2 vertices
1018
1019  {1,15,15,15,15,15,15,15,15}, // 24 .. x=2 y=2 z=0 D 1 vertex
1020  {0,1,15,15,15,15,15,15,15},  // 25 .. x=2 y=2 z=1 D 2 vertices
1021  {0,15,15,15,15,15,15,15,15}, // 26 .. x=2 y=2 z=2 D 1 vertex
1022};
1023
1024// The fast computation of arctangent .. the maximal error is less
1025// than 4.1 degrees, according to Graphics GEMSII, 1991, pages 389--391
1026// Ron Capelli: "Fast approximation to the arctangent"
1027float
1028atan22(const float& y)
1029{
1030  const float x = 1.0;
1031  const float c = (float)(M_PI * 0.25);
1032 
1033  if (y < 0.0) {
1034    if (y < -1.0)
1035      return c * (-2.0 + x / y); // for angle in <-PI/2, -PI/4)
1036    else
1037      return c * (y / x); // for angle in <-PI/4 , 0>
1038  }
1039  else {
1040    if (y > 1.0)
1041      return c * (2.0 - x / y); // for angle in <PI/4, PI/2>
1042    else
1043      return c * (y / x); // for angle in <0, PI/2>
1044  }
1045}
1046
1047
1048float
1049AxisAlignedBox3::ProjectToSphereSA(const Vector3 &viewpoint, int *tcase) const
1050{
1051  int id = GetRegionID(viewpoint);
1052  *tcase = id;
1053
1054  // spherical projection .. SA represents solid angle
1055  if (id == 13) // .. inside the box
1056    return (float)(4.0*M_PI); // the whole sphere
1057  float SA = 0.0; // inital value
1058   
1059  int i = 0; // the pointer in the array of vertices
1060  while (bfaces[id][i] >= 0) {
1061    int axisO = bfaces[id][i++];
1062    int minvIdx = bfaces[id][i++];
1063    int maxvIdx = bfaces[id][i++];
1064    Vector3 vmin, vmax;
1065    GetVertex(minvIdx, vmin);
1066    GetVertex(maxvIdx, vmax);
1067    float h = fabs(vmin[axisO] - viewpoint[axisO]);
1068    int axis = (axisO + 1) % 3; // next axis
1069    float a = (vmin[axis] - viewpoint[axis]) / h; // minimum for v-range
1070    float b = (vmax[axis] - viewpoint[axis]) / h; // maximum for v-range
1071    //if (a > b) {
1072    //  FATAL << "ProjectToSphereSA::Error a > b\n";
1073    //  FATAL_ABORT;
1074    //}
1075    //if (vmin[axisO] != vmax[axisO]) {
1076    //  FATAL << "ProjectToSphereSA::Error a-axis != b-axis\n";
1077    //  FATAL_ABORT;     
1078    //}
1079    axis = (axisO + 2) % 3; // next second axis       
1080    float c = (vmin[axis] - viewpoint[axis]) / h; // minimum for u-range
1081    float d = (vmax[axis] - viewpoint[axis]) / h; // maximum for u-range
1082    //if (c > d) {
1083    //  FATAL << "ProjectToSphereSA::Error c > d\n";
1084    //  FATAL_ABORT;
1085    //}
1086    SA +=atan22(d*b/sqrt(b*b + d*d + 1.0)) - atan22(b*c/sqrt(b*b + c*c + 1.0))
1087      - atan22(d*a/sqrt(a*a + d*d + 1.0)) + atan22(a*c/sqrt(a*a + c*c + 1.0));
1088  }
1089
1090#if 0
1091  if ((SA > 2.0*M_PI) ||
1092      (SA < 0.0)) {
1093    FATAL << "The solid angle has strange value: ";
1094    FATAL << "SA = "<< SA << endl;
1095    FATAL_ABORT;
1096  }
1097#endif
1098 
1099  return SA;
1100}
1101
1102// Projects the box to a plane given a normal vector only and
1103// computes the surface area of the projected silhouette
1104// no clipping of the box is performed.
1105float
1106AxisAlignedBox3::ProjectToPlaneSA(const Vector3 &normal) const
1107{
1108  Vector3 size = Size();
1109
1110  // the surface area of the box to a yz-plane - perpendicular to x-axis
1111  float sax = size.y * size.z;
1112
1113  // the surface area of the box to a zx-plane - perpendicular to y-axis
1114  float say = size.z * size.x;
1115
1116  // the surface area of the box to a xy-plane - perpendicular to z-axis
1117  float saz = size.x * size.y;
1118 
1119  return sax * fabs(normal.x) + say * fabs(normal.y) + saz * fabs(normal.z);
1120}
1121
1122
1123
1124// This definition allows to be a point when answering true
1125bool
1126AxisAlignedBox3::IsCorrectAndNotPoint() const
1127{
1128  if ( (mMin.x > mMax.x) ||
1129       (mMin.y > mMax.y) ||
1130       (mMin.z > mMax.z) )
1131    return false; // box is not formed
1132
1133  if ( (mMin.x == mMax.x) &&
1134       (mMin.y == mMax.y) &&
1135       (mMin.z == mMax.z) )
1136    return false; // degenerates to a point
1137 
1138  return true;
1139}
1140
1141// This definition allows to be a point when answering true
1142bool
1143AxisAlignedBox3::IsPoint() const
1144{
1145  if ( (mMin.x == mMax.x) &&
1146       (mMin.y == mMax.y) &&
1147       (mMin.z == mMax.z) )
1148    return true; // degenerates to a point
1149 
1150  return false;
1151}
1152
1153// This definition requires shape of non-zero volume
1154bool
1155AxisAlignedBox3::IsSingularOrIncorrect() const
1156{
1157  if ( (mMin.x >= mMax.x) ||
1158       (mMin.y >= mMax.y) ||
1159       (mMin.z >= mMax.z) )
1160    return true; // box is not formed
1161
1162  return false; // has non-zero volume
1163}
1164
1165// returns true, when the sphere specified by the origin and radius
1166// fully contains the box
1167bool
1168AxisAlignedBox3::IsFullyContainedInSphere(const Vector3 &center, float rad) const
1169{
1170  int region = GetRegionID(center);
1171  float rad2 = rad*rad;
1172
1173  // vertex of the box
1174  Vector3 vertex;
1175
1176  int i = 0;
1177  for (i = 0 ; ; i++) {
1178    int a = fsvertices[region][i];
1179    if (a == 15)
1180      return true; // if was not false untill now, it must be contained
1181
1182    assert( (a>=0) && (a<8) );
1183   
1184    // normal vertex
1185    GetVertex(a, vertex);
1186
1187    if (SqrMagnitude(vertex - center) > rad2)
1188      return false;   
1189  } // for
1190 
1191}
1192
1193// returns true, when the volume of the sphere and volume of the
1194// axis aligned box has no intersection
1195bool
1196AxisAlignedBox3::HasNoIntersectionWithSphere(const Vector3 &center, float rad) const
1197{
1198  int region = GetRegionID(center);
1199  float rad2 = rad*rad;
1200
1201  // vertex of the box
1202  Vector3 vertex;
1203
1204  switch (csvertices[region][0]) {
1205  case 8: {
1206    // test two coordinates described within the field
1207    int face = 3*csvertices[region][1] + csvertices[region][2];
1208    float dist = GetExtent(face) - center[csvertices[region][2]];
1209    dist *= dist;
1210    face = 3 * (csvertices[region][3]) + csvertices[region][4];
1211    float dist2 = GetExtent(face) - center[csvertices[region][4]];
1212    dist += (dist2 * dist2);
1213    if (dist > rad2)
1214      return true; // no intersection is possible
1215  }
1216  case 9: {
1217    // test one coordinate described within the field
1218    int face = 3*csvertices[region][1] + csvertices[region][2];
1219    float dist = fabs(GetExtent(face) - center[csvertices[region][2]]);
1220    if (dist > rad)
1221      return true; // no intersection is possible
1222  }
1223  case 15:
1224    return false; // box and sphere surely has intersection
1225  default: {
1226    // test using normal vertices
1227    assert( (csvertices[region][0]>=0) && (csvertices[region][0]<8) );
1228
1229    // normal vertex
1230    GetVertex(csvertices[region][0], vertex);
1231
1232    if (SqrMagnitude(vertex - center) > rad2)
1233      return true; // no intersectino is possible   
1234    }
1235  } // switch
1236
1237  return false; // partial or full containtment
1238}
1239
1240#if 0
1241// Given the sphere, determine the mutual position between the
1242// sphere and box
1243
1244// SOME BUG IS INSIDE !!!! V.H. 25/4/2001
1245int
1246AxisAlignedBox3::MutualPositionWithSphere(const Vector3 &center, float rad) const
1247{
1248  int region = GetRegionID(center);
1249  float rad2 = rad*rad;
1250
1251  // vertex of the box
1252  Vector3 vertex;
1253
1254  // first testing for  full containtment - whether sphere fully
1255  // contains the box
1256  int countInside = 0; // how many points were found inside
1257 
1258  int i = 0;
1259  for (i = 0 ; ; i++) {
1260    int a = fsvertices[region][i];
1261    if (a == 15)
1262      return 1; // the sphere fully contain the box
1263
1264    assert( (a>=0) && (a<8) );
1265   
1266    // normal vertex
1267    GetVertex(a, vertex);
1268
1269    if (SqrMagnitude(vertex - center) <= rad2)
1270      countInside++; // the number of vertices inside the sphere
1271    else {
1272      if (countInside)
1273        return 0; // partiall overlap has been found
1274      // the sphere does not fully contain the box .. only way to break
1275      // this loop and go for other testing
1276      break;
1277    }
1278  } // for
1279
1280  // now only box and sphere can partially overlap or no intersection
1281  switch (csvertices[region][0]) {
1282  case 8: {
1283    // test two coordinates described within the field
1284    int face = 3*csvertices[region][1] + csvertices[region][2];
1285    float dist = GetExtent(face) - center[csvertices[region][2]];
1286    dist *= dist;
1287    face = 3 * (csvertices[region][3]) + csvertices[region][4];
1288    float dist2 = GetExtent(face) - center[csvertices[region][4]];
1289    dist += (dist2 * dist2);
1290    if (dist > rad2 )
1291      return -1; // no intersection is possible
1292  }
1293  case 9: {
1294    // test one coordinate described within the field
1295    int face = 3*csvertices[region][1] + csvertices[region][2];
1296    float dist = fabs(GetExtent(face) - center[csvertices[region][2]]);
1297    if (dist > rad)
1298      return -1; // no intersection is possible
1299  }
1300  case 15:
1301    return 0 ; // partial overlap is now guaranteed
1302  default: {
1303    // test using normal vertices
1304    assert( (csvertices[region][0]>=0) && (csvertices[region][0]<8) );
1305   
1306    // normal vertex
1307    GetVertex(csvertices[region][0], vertex);
1308
1309    if (SqrMagnitude(vertex - center) > rad2)
1310      return -1; // no intersection is possible   
1311    }
1312  } // switch
1313
1314  return 0; // partial intersection is guaranteed
1315}
1316#else
1317
1318// Some maybe smarter version, extendible easily to d-dimensional
1319// space!
1320// Given a sphere described by the center and radius,
1321// the fullowing function returns:
1322//   -1 ... the sphere and the box are completely separate
1323//    0 ... the sphere and the box only partially overlap
1324//    1 ... the sphere contains fully the box
1325//  Note: the case when box fully contains the sphere is not reported
1326//        since it was not required.
1327int
1328AxisAlignedBox3::MutualPositionWithSphere(const Vector3 &center, float rad) const
1329{
1330//#define SPEED_UP
1331
1332#ifndef SPEED_UP
1333  // slow version, instructively written 
1334#if 0
1335  // does it make sense to test
1336  // checking the sides of the box for possible non-intersection
1337  if ( ((center.x + rad) < mMin.x) ||
1338       ((center.x - rad) > mMax.x) ||
1339       ((center.y + rad) < mMin.y) ||
1340       ((center.y - rad) > mMax.y) ||
1341       ((center.z + rad) < mMin.z) ||
1342       ((center.z - rad) > mMax.z) ) {
1343    // cout << "r ";
1344    return -1;  // no overlap is possible
1345  }
1346#endif
1347 
1348  // someoverlap is possible, check the distance of vertices
1349  rad = rad*rad;
1350  float sumMin = 0;
1351  // Try to minimize the function of a distance
1352  // from the sphere center
1353
1354  // for x-axis
1355  float minSqrX = sqr(mMin.x - center.x);
1356  float maxSqrX = sqr(mMax.x - center.x);
1357  if (center.x < mMin.x)
1358    sumMin = minSqrX;
1359  else
1360    if (center.x > mMax.x)
1361      sumMin = maxSqrX;
1362
1363  // for y-axis
1364  float minSqrY = sqr(mMin.y - center.y);
1365  float maxSqrY = sqr(mMax.y - center.y);
1366  if (center.y < mMin.y)
1367    sumMin += minSqrY;
1368  else
1369    if (center.y > mMax.y)
1370      sumMin += maxSqrY;
1371
1372  // for z-axis
1373  float minSqrZ = sqr(mMin.z - center.z);
1374  float maxSqrZ = sqr(mMax.z - center.z);
1375  if (center.z < mMin.z)
1376    sumMin += minSqrZ;
1377  else
1378    if (center.z > mMax.z)
1379      sumMin += maxSqrZ;
1380
1381  if (sumMin > rad)
1382    return -1; // no intersection between sphere and box
1383
1384  // try to find out the maximum distance between the
1385  // sphere center and vertices
1386  float sumMax = 0;
1387 
1388  if (minSqrX > maxSqrX)
1389    sumMax = minSqrX;
1390  else
1391    sumMax = maxSqrX;
1392 
1393  if (minSqrY > maxSqrY)
1394    sumMax += minSqrY;
1395  else
1396    sumMax += maxSqrY;
1397 
1398  if (minSqrZ > maxSqrZ)
1399    sumMax += minSqrZ;
1400  else
1401    sumMax += maxSqrZ;
1402 
1403  // sumMin < rad
1404  if (sumMax < rad)
1405    return 1; // the sphere contains the box completely
1406
1407  // partial intersection, part of the box is outside the sphere
1408  return 0;
1409#else
1410
1411  // Optimized version of the test
1412 
1413#ifndef __VECTOR_HACK
1414#error "__VECTOR_HACK for Vector3 was not defined"
1415#endif
1416
1417  // some overlap is possible, check the distance of vertices
1418  rad = rad*rad;
1419  float sumMin = 0;
1420  float sumMax = 0;
1421  // Try to minimize the function of a distance
1422  // from the sphere center
1423
1424  const float *minp = &(min[0]);
1425  const float *maxp = &(max[0]);
1426  const float *pcenter = &(center[0]);
1427 
1428  // for x-axis
1429  for (int i = 0; i < 3; i++, minp++, maxp++, pcenter++) {
1430    float minsqr = sqr(*minp - *pcenter);
1431    float maxsqr = sqr(*maxp - *pcenter);
1432    if (*pcenter < *minp)
1433      sumMin += minsqr;
1434    else
1435      if (*pcenter > *maxp)
1436        sumMin += maxsqr;
1437    sumMax += (minsqr > maxsqr) ? minsqr : maxsqr;
1438  }
1439
1440  if (sumMin > rad)
1441    return -1; // no intersection between sphere and box
1442
1443  // sumMin < rad
1444  if (sumMax < rad)
1445    return 1; // the sphere contains the box completely
1446
1447  // partial intersection, part of the box is outside the sphere
1448  return 0;
1449#endif
1450}
1451#endif
1452
1453// Given the cube describe by the center and the half-sie,
1454// determine the mutual position between the cube and the box
1455int
1456AxisAlignedBox3::MutualPositionWithCube(const Vector3 &center, float radius) const
1457{
1458  // the cube is described by the center and the distance to the any face
1459  // along the axes
1460
1461  // Note on efficiency!
1462  // Can be quite optimized using tables, but I do not have time
1463  // V.H. 18/11/2001
1464
1465  AxisAlignedBox3 a =
1466    AxisAlignedBox3(Vector3(center.x - radius, center.y - radius, center.z - radius),
1467           Vector3(center.x + radius, center.y + radius, center.z + radius));
1468
1469  if (a.Includes(*this))
1470    return 1; // cube contains the box
1471
1472  if (OverlapS(a,*this))
1473    return 0; // cube partially overlap the box
1474
1475  return -1; // completely separate 
1476}
1477
1478void
1479AxisAlignedBox3::GetSqrDistances(const Vector3 &point,
1480                                 float &minDistance,
1481                                 float &maxDistance
1482                                 ) const
1483{
1484
1485 
1486#ifndef __VECTOR_HACK
1487#error "__VECTOR_HACK for Vector3 was not defined"
1488#endif
1489
1490  // some overlap is possible, check the distance of vertices
1491  float sumMin = 0;
1492  float sumMax = 0;
1493
1494  // Try to minimize the function of a distance
1495  // from the sphere center
1496
1497  const float *minp = &(mMin[0]);
1498  const float *maxp = &(mMax[0]);
1499  const float *pcenter = &(point[0]);
1500 
1501  // for x-axis
1502  for (int i = 0; i < 3; i++, minp++, maxp++, pcenter++) {
1503    float minsqr = sqr(*minp - *pcenter);
1504    float maxsqr = sqr(*maxp - *pcenter);
1505    if (*pcenter < *minp)
1506      sumMin += minsqr;
1507    else
1508      if (*pcenter > *maxp)
1509        sumMin += maxsqr;
1510    sumMax += (minsqr > maxsqr) ? minsqr : maxsqr;
1511  }
1512
1513  minDistance = sumMin;
1514  maxDistance = sumMax;
1515}
1516
1517
1518int
1519AxisAlignedBox3::Side(const Plane3 &plane) const
1520{
1521  Vector3 v;
1522  int i, m=3, M=-3, s;
1523 
1524  for (i=0;i<8;i++) {
1525    GetVertex(i, v);
1526    if((s = plane.Side(v)) < m)
1527      m=s;
1528    if(s > M)
1529      M=s;
1530    if (m && m==-M)
1531      return 0;
1532  }
1533 
1534  return (m == M) ? m : m + M;
1535}
1536
1537int
1538AxisAlignedBox3::GetFaceVisibilityMask(const Rectangle3 &rectangle) const
1539{
1540  int mask = 0;
1541  for (int i=0; i < 4; i++)
1542    mask |= GetFaceVisibilityMask(rectangle.mVertices[i]);
1543  return mask;
1544}
1545
1546int
1547AxisAlignedBox3::GetFaceVisibilityMask(const Vector3 &position) const {
1548 
1549  // assume that we are not inside the box
1550  int c=0;
1551 
1552  if (position.x<(mMin.x-Limits::Small))
1553    c|=1;
1554  else
1555    if (position.x>(mMax.x+Limits::Small))
1556      c|=2;
1557 
1558  if (position.y<(mMin.y-Limits::Small))
1559    c|=4;
1560  else
1561    if (position.y>(mMax.y+Limits::Small))
1562      c|=8;
1563 
1564  if (position.z<(mMin.z-Limits::Small))
1565    c|=16;
1566  else
1567    if (position.z>(mMax.z+Limits::Small))
1568      c|=32;
1569 
1570  return c;
1571}
1572
1573
1574Rectangle3
1575AxisAlignedBox3::GetFace(const int face) const
1576{
1577  Vector3 v[4];
1578  switch (face) {
1579   
1580  case 0:
1581    v[3].SetValue(mMin.x,mMin.y,mMin.z);
1582    v[2].SetValue(mMin.x,mMax.y,mMin.z);
1583    v[1].SetValue(mMin.x,mMax.y,mMax.z);
1584    v[0].SetValue(mMin.x,mMin.y,mMax.z);
1585    break;
1586   
1587  case 1:
1588    v[0].SetValue(mMax.x,mMin.y,mMin.z);
1589    v[1].SetValue(mMax.x,mMax.y,mMin.z);
1590    v[2].SetValue(mMax.x,mMax.y,mMax.z);
1591    v[3].SetValue(mMax.x,mMin.y,mMax.z);
1592    break;
1593   
1594  case 2:
1595    v[3].SetValue(mMin.x,mMin.y,mMin.z);
1596    v[2].SetValue(mMin.x,mMin.y,mMax.z);
1597    v[1].SetValue(mMax.x,mMin.y,mMax.z);
1598    v[0].SetValue(mMax.x,mMin.y,mMin.z);
1599    break;
1600 
1601  case 3:
1602    v[0].SetValue(mMin.x,mMax.y,mMin.z);
1603    v[1].SetValue(mMin.x,mMax.y,mMax.z);
1604    v[2].SetValue(mMax.x,mMax.y,mMax.z);
1605    v[3].SetValue(mMax.x,mMax.y,mMin.z);
1606    break;
1607
1608  case 4:
1609    v[3].SetValue(mMin.x,mMin.y,mMin.z);
1610    v[2].SetValue(mMax.x,mMin.y,mMin.z);
1611    v[1].SetValue(mMax.x,mMax.y,mMin.z);
1612    v[0].SetValue(mMin.x,mMax.y,mMin.z);
1613    break;
1614 
1615  case 5:
1616    v[0].SetValue(mMin.x,mMin.y,mMax.z);
1617    v[1].SetValue(mMax.x,mMin.y,mMax.z);
1618    v[2].SetValue(mMax.x,mMax.y,mMax.z);
1619    v[3].SetValue(mMin.x,mMax.y,mMax.z);
1620    break;
1621  }
1622 
1623  return Rectangle3(v[0], v[1], v[2], v[3]);
1624}
Note: See TracBrowser for help on using the repository browser.