newspeoplefor developersdocumentationdownloads

bbox.h

Go to the documentation of this file.
00001 #ifndef N_BBOX_H
00002 #define N_BBOX_H
00003 //------------------------------------------------------------------------------
00012 #include "mathlib/vector.h"
00013 #include "mathlib/matrix.h"
00014 #include "mathlib/line.h"
00015 #include "mathlib/plane.h"
00016 #include "util/narray.h"
00017 
00018 //------------------------------------------------------------------------------
00019 //  bbox3
00020 //------------------------------------------------------------------------------
00021 class bbox3
00022 {
00023 public:
00025     enum
00026     {
00027         ClipLeft   = (1<<0),
00028         ClipRight  = (1<<1),
00029         ClipBottom = (1<<2),
00030         ClipTop    = (1<<3),
00031         ClipNear   = (1<<4),
00032         ClipFar    = (1<<5),
00033     };
00035     enum ClipStatus
00036     {
00037         Outside,
00038         Inside,
00039         Clipped,
00040     };
00041 
00042     enum {
00043         OUTSIDE     = 0,
00044         ISEQUAL     = (1<<0),
00045         ISCONTAINED = (1<<1),
00046         CONTAINS    = (1<<2),
00047         CLIPS       = (1<<3),
00048     };
00049 
00051     bbox3();
00053     bbox3(const vector3& center, const vector3& extents);
00055     bbox3(const matrix44& m);
00057     vector3 center() const;
00059     vector3 extents() const;
00061     vector3 size() const;
00063     float diagonal_size() const;
00065     void set(const matrix44& m);
00067     void set(const vector3& center, const vector3& extents);
00069     void begin_extend();
00071     void extend(const vector3& v);
00073     void end_extend();
00075     void extend(float x, float y, float z);
00077     void extend(const bbox3& box);
00079     void transform(const matrix44& m);
00081     void transform_divw(const matrix44& m);
00083     bool intersects(const bbox3& box) const;
00085     bool contains(const bbox3& box) const;
00087     bool contains(const vector3& pos) const;
00089     ClipStatus clipstatus(const bbox3& other) const;
00091     ClipStatus clipstatus(const matrix44& viewProjection) const;
00093     matrix44 to_matrix44() const;
00095     vector3 corner_point(int index) const;
00097     void get_clipplanes(const matrix44& viewProjection, nArray<plane>& outPlanes) const;
00098 
00099     int line_test(float v0, float v1, float w0, float w1);
00100     int intersect(const bbox3& box);
00101     bool intersect(const line3& line, vector3& ipos) const;
00102 
00103     // get point of intersection of 3d line with planes
00104     // on const x,y,z
00105     bool isect_const_x(const float x, const line3& l, vector3& out) const
00106     {
00107         if (l.m.x != 0.0f)
00108         {
00109             float t = (x - l.b.x) / l.m.x;
00110             if ((t >= 0.0f) && (t <= 1.0f))
00111             {
00112                 // point of intersection...
00113                 out = l.ipol(t);
00114                 return true;
00115             }
00116         }
00117         return false;
00118     }
00119     bool isect_const_y(const float y, const line3& l, vector3& out) const
00120     {
00121         if (l.m.y != 0.0f)
00122         {
00123             float t = (y - l.b.y) / l.m.y;
00124             if ((t >= 0.0f) && (t <= 1.0f))
00125             {
00126                 // point of intersection...
00127                 out = l.ipol(t);
00128                 return true;
00129             }
00130         }
00131         return false;
00132     }
00133     bool isect_const_z(const float z, const line3& l, vector3& out) const
00134     {
00135         if (l.m.z != 0.0f)
00136         {
00137             float t = (z - l.b.z) / l.m.z;
00138             if ((t >= 0.0f) && (t <= 1.0f))
00139             {
00140                 // point of intersection...
00141                 out = l.ipol(t);
00142                 return true;
00143             }
00144         }
00145         return false;
00146     }
00147 
00148     // point in polygon check for sides with constant x,y and z
00149     bool pip_const_x(const vector3& p) const
00150     {
00151         if ((p.y >= vmin.y) && (p.y <= vmax.y) && (p.z >= vmin.z) && (p.z <= vmax.z)) return true;
00152         return false;
00153     }
00154     bool pip_const_y(const vector3& p) const
00155     {
00156         if ((p.x >= vmin.x) && (p.x <= vmax.x) && (p.z >= vmin.z) && (p.z <= vmax.z)) return true;
00157         return false;
00158     }
00159     bool pip_const_z(const vector3& p) const
00160     {
00161         if ((p.x >= vmin.x) && (p.x <= vmax.x) && (p.y >= vmin.y) && (p.y <= vmax.y)) return true;
00162         return false;
00163     }
00164 
00165     vector3 vmin;
00166     vector3 vmax;
00167 };
00168 
00169 //------------------------------------------------------------------------------
00172 inline
00173 bbox3::bbox3()
00174 {
00175     // empty
00176 }
00177 
00178 //------------------------------------------------------------------------------
00181 inline
00182 bbox3::bbox3(const vector3& center, const vector3& extents)
00183 {
00184     vmin = center - extents;
00185     vmax = center + extents;
00186 }
00187 
00188 //------------------------------------------------------------------------------
00194 inline
00195 void
00196 bbox3::set(const matrix44& m)
00197 {
00198     // get extents
00199     float xExtent = n_max(n_max(n_abs(m.M11), n_abs(m.M21)), n_abs(m.M31));
00200     float yExtent = n_max(n_max(n_abs(m.M12), n_abs(m.M22)), n_abs(m.M32));
00201     float zExtent = n_max(n_max(n_abs(m.M13), n_abs(m.M23)), n_abs(m.M33));
00202     vector3 extent(xExtent, yExtent, zExtent);
00203 
00204     vector3 center = m.pos_component();
00205     this->vmin = center - extent;
00206     this->vmax = center + extent;
00207 }
00208 
00209 //------------------------------------------------------------------------------
00212 inline
00213 bbox3::bbox3(const matrix44& m)
00214 {
00215     this->set(m);
00216 }
00217 
00218 //------------------------------------------------------------------------------
00221 inline
00222 vector3
00223 bbox3::center() const
00224 {
00225     return vector3((vmin + vmax) * 0.5f);
00226 }
00227 
00228 //------------------------------------------------------------------------------
00231 inline
00232 vector3
00233 bbox3::extents() const
00234 {
00235     return vector3((vmax - vmin) * 0.5f);
00236 }
00237 
00238 //------------------------------------------------------------------------------
00241 inline
00242 vector3
00243 bbox3::size() const
00244 {
00245     return vector3(vmax - vmin);
00246 }
00247 
00248 //------------------------------------------------------------------------------
00251 inline
00252 void
00253 bbox3::set(const vector3& center, const vector3& extents)
00254 {
00255     vmin = center - extents;
00256     vmax = center + extents;
00257 }
00258 
00259 //------------------------------------------------------------------------------
00262 inline
00263 void
00264 bbox3::begin_extend()
00265 {
00266     vmin.set( 1000000.0f,  1000000.0f,  1000000.0f);
00267     vmax.set(-1000000.0f, -1000000.0f, -1000000.0f);
00268 }
00269 
00270 //------------------------------------------------------------------------------
00275 inline
00276 void
00277 bbox3::end_extend()
00278 {
00279     if (vmin.isequal(vector3( 1000000.0f,  1000000.0f,  1000000.0f), TINY) &&
00280         vmax.isequal(vector3(-1000000.0f, -1000000.0f, -1000000.0f), TINY))
00281     {
00282         vmin.set(0.0f, 0.0f, 0.0f);
00283         vmax.set(0.0f, 0.0f, 0.0f);
00284     }
00285 }
00286 
00287 //------------------------------------------------------------------------------
00290 inline
00291 void
00292 bbox3::extend(const vector3& v)
00293 {
00294     if (v.x < vmin.x) vmin.x = v.x;
00295     if (v.x > vmax.x) vmax.x = v.x;
00296     if (v.y < vmin.y) vmin.y = v.y;
00297     if (v.y > vmax.y) vmax.y = v.y;
00298     if (v.z < vmin.z) vmin.z = v.z;
00299     if (v.z > vmax.z) vmax.z = v.z;
00300 }
00301 
00302 //------------------------------------------------------------------------------
00305 inline
00306 void
00307 bbox3::extend(float x, float y, float z)
00308 {
00309     if (x < vmin.x) vmin.x = x;
00310     if (x > vmax.x) vmax.x = x;
00311     if (y < vmin.y) vmin.y = y;
00312     if (y > vmax.y) vmax.y = y;
00313     if (z < vmin.z) vmin.z = z;
00314     if (z > vmax.z) vmax.z = z;
00315 }
00316 
00317 //------------------------------------------------------------------------------
00320 inline
00321 void
00322 bbox3::extend(const bbox3& box)
00323 {
00324     if (box.vmin.x < vmin.x) vmin.x = box.vmin.x;
00325     if (box.vmin.y < vmin.y) vmin.y = box.vmin.y;
00326     if (box.vmin.z < vmin.z) vmin.z = box.vmin.z;
00327     if (box.vmax.x > vmax.x) vmax.x = box.vmax.x;
00328     if (box.vmax.y > vmax.y) vmax.y = box.vmax.y;
00329     if (box.vmax.z > vmax.z) vmax.z = box.vmax.z;
00330 }
00331 
00332 //------------------------------------------------------------------------------
00336 inline
00337 vector3
00338 bbox3::corner_point(int index) const
00339 {
00340     n_assert((index >= 0) && (index < 8));
00341     switch (index)
00342     {
00343         case 0:     return this->vmin;
00344         case 1:     return vector3(this->vmin.x, this->vmax.y, this->vmin.z);
00345         case 2:     return vector3(this->vmax.x, this->vmax.y, this->vmin.z);
00346         case 3:     return vector3(this->vmax.x, this->vmin.y, this->vmin.z);
00347         case 4:     return this->vmax;
00348         case 5:     return vector3(this->vmin.x, this->vmax.y, this->vmax.z);
00349         case 6:     return vector3(this->vmin.x, this->vmin.y, this->vmax.z);
00350         default:    return vector3(this->vmax.x, this->vmin.y, this->vmax.z);
00351     }
00352 }
00353 
00354 //------------------------------------------------------------------------------
00358 inline
00359 void
00360 bbox3::get_clipplanes(const matrix44& viewProj, nArray<plane>& outPlanes) const
00361 {
00362     matrix44 inv = viewProj;
00363     inv.invert();
00364     inv.transpose();
00365 
00366     vector4 planes[6];
00367 
00368     planes[0].set(-1, 0, 0, +this->vmax.x);
00369     planes[1].set(+1, 0, 0, -this->vmin.x);
00370     planes[2].set(0, -1, 0, +this->vmax.y);
00371     planes[3].set(0, +1, 0, -this->vmin.y);
00372     planes[4].set(0, 0, -1, +this->vmax.z);
00373     planes[5].set(0, 0, +1, -this->vmin.z);
00374 
00375     for (int i = 0; i < 6; ++i)
00376     {
00377         vector4 v = inv * planes[i];
00378         outPlanes.Append(plane(v.x, v.y, v.z, v.w));
00379     }
00380 }
00381 
00382 //------------------------------------------------------------------------------
00395 inline
00396 void
00397 bbox3::transform(const matrix44& m)
00398 {
00399     /*  ?? BUG ??
00400     // get own extents vector
00401     vector3 extents = this->extents();
00402     vector3 center  = this->center();
00403 
00404     // Extent the matrix' (x,y,z) components by our own extent
00405     // vector.
00406     matrix44 extentMatrix(
00407         m.M11 * extents.x, m.M12 * extents.x, m.M13 * extents.x, 0.0f,
00408         m.M21 * extents.y, m.M22 * extents.y, m.M23 * extents.y, 0.0f,
00409         m.M31 * extents.z, m.M32 * extents.z, m.M33 * extents.z, 0.0f,
00410         m.M41 + center.x,  m.M42 + center.y,  m.M43 + center.z,  1.0f);
00411 
00412     this->set(extentMatrix);
00413     */
00414 
00415     vector3 temp, min, max, corners[8];
00416     bool first = true;
00417     int i;
00418 
00419     corners[0]   = this->vmin;
00420     corners[1].x = this->vmin.x; corners[1].y = this->vmax.y; corners[1].z = this->vmin.z;
00421     corners[2].x = this->vmax.x; corners[2].y = this->vmax.y; corners[2].z = this->vmin.z;
00422     corners[3].x = this->vmax.x; corners[3].y = this->vmin.y; corners[3].z = this->vmin.z;
00423     corners[4]   = this->vmax;
00424     corners[5].x = this->vmin.x; corners[5].y = this->vmax.y; corners[5].z = this->vmax.z;
00425     corners[6].x = this->vmin.x; corners[6].y = this->vmin.y; corners[6].z = this->vmax.z;
00426     corners[7].x = this->vmax.x; corners[7].y = this->vmin.y; corners[7].z = this->vmax.z;
00427 
00428     for (i = 0; i < 8; ++i)
00429     {
00430         // Transform and check extents
00431         temp = m * corners[i];
00432         if (first || temp.x > max.x)   max.x = temp.x;
00433         if (first || temp.y > max.y)   max.y = temp.y;
00434         if (first || temp.z > max.z)   max.z = temp.z;
00435         if (first || temp.x < min.x)   min.x = temp.x;
00436         if (first || temp.y < min.y)   min.y = temp.y;
00437         if (first || temp.z < min.z)   min.z = temp.z;
00438         first = false;
00439     }
00440 
00441     this->vmin = min;
00442     this->vmax = max;
00443 }
00444 
00445 //------------------------------------------------------------------------------
00450 inline
00451 void
00452 bbox3::transform_divw(const matrix44& m)
00453 {
00454     vector3 temp, min, max, corners[8];
00455     bool first = true;
00456     int i;
00457 
00458     corners[0]   = this->vmin;
00459     corners[1].x = this->vmin.x; corners[1].y = this->vmax.y; corners[1].z = this->vmin.z;
00460     corners[2].x = this->vmax.x; corners[2].y = this->vmax.y; corners[2].z = this->vmin.z;
00461     corners[3].x = this->vmax.x; corners[3].y = this->vmin.y; corners[3].z = this->vmin.z;
00462     corners[4]   = this->vmax;
00463     corners[5].x = this->vmin.x; corners[5].y = this->vmax.y; corners[5].z = this->vmax.z;
00464     corners[6].x = this->vmin.x; corners[6].y = this->vmin.y; corners[6].z = this->vmax.z;
00465     corners[7].x = this->vmax.x; corners[7].y = this->vmin.y; corners[7].z = this->vmax.z;
00466 
00467     for (i = 0; i < 8; ++i)
00468     {
00469         // Transform and check extents
00470         temp = m.mult_divw(corners[i]);
00471         if (first || temp.x > max.x)   max.x = temp.x;
00472         if (first || temp.y > max.y)   max.y = temp.y;
00473         if (first || temp.z > max.z)   max.z = temp.z;
00474         if (first || temp.x < min.x)   min.x = temp.x;
00475         if (first || temp.y < min.y)   min.y = temp.y;
00476         if (first || temp.z < min.z)   min.z = temp.z;
00477         first = false;
00478     }
00479 
00480     this->vmin = min;
00481     this->vmax = max;
00482 }
00483 
00484 //------------------------------------------------------------------------------
00489 inline
00490 bool
00491 bbox3::intersects(const bbox3& box) const
00492 {
00493     if ((this->vmax.x < box.vmin.x) || (this->vmin.x > box.vmax.x) ||
00494         (this->vmax.y < box.vmin.y) || (this->vmin.y > box.vmax.y) ||
00495         (this->vmax.z < box.vmin.z) || (this->vmin.z > box.vmax.z))
00496     {
00497         return false;
00498     }
00499     return true;
00500 }
00501 
00502 //------------------------------------------------------------------------------
00507 inline
00508 bool
00509 bbox3::contains(const bbox3& box) const
00510 {
00511     if ((this->vmin.x < box.vmin.x) && (this->vmax.x >= box.vmax.x) &&
00512         (this->vmin.y < box.vmin.y) && (this->vmax.y >= box.vmax.y) &&
00513         (this->vmin.z < box.vmin.z) && (this->vmax.z >= box.vmax.z))
00514     {
00515         return true;
00516     }
00517     return false;
00518 }
00519 
00520 //------------------------------------------------------------------------------
00524 inline
00525 bool
00526 bbox3::contains(const vector3& v) const
00527 {
00528     if ((this->vmin.x < v.x) && (this->vmax.x >= v.x) &&
00529         (this->vmin.y < v.y) && (this->vmax.y >= v.y) &&
00530         (this->vmin.z < v.z) && (this->vmax.z >= v.z))
00531     {
00532         return true;
00533     }
00534     return false;
00535 }
00536 
00537 //------------------------------------------------------------------------------
00541 inline
00542 bbox3::ClipStatus
00543 bbox3::clipstatus(const bbox3& other) const
00544 {
00545     if (this->contains(other))
00546     {
00547         return Inside;
00548     }
00549     if (this->intersects(other))
00550     {
00551         return Clipped;
00552     }
00553     return Outside;
00554 }
00555 
00556 //------------------------------------------------------------------------------
00561 inline
00562 bbox3::ClipStatus
00563 bbox3::clipstatus(const matrix44& viewProjection) const
00564 {
00565     int andFlags = 0xffff;
00566     int orFlags  = 0;
00567     int i;
00568     static vector4 v0;
00569     static vector4 v1;
00570     for (i = 0; i < 8; i++)
00571     {
00572         int clip = 0;
00573         v0.w = 1.0f;
00574         if (i & 1) v0.x = this->vmin.x;
00575         else       v0.x = this->vmax.x;
00576         if (i & 2) v0.y = this->vmin.y;
00577         else       v0.y = this->vmax.y;
00578         if (i & 4) v0.z = this->vmin.z;
00579         else       v0.z = this->vmax.z;
00580 
00581         v1 = viewProjection * v0;
00582 
00583         if (v1.x < -v1.w)       clip |= ClipLeft;
00584         else if (v1.x > v1.w)   clip |= ClipRight;
00585         if (v1.y < -v1.w)       clip |= ClipBottom;
00586         else if (v1.y > v1.w)   clip |= ClipTop;
00587         if (v1.z < -v1.w)       clip |= ClipFar;
00588         else if (v1.z > v1.w)   clip |= ClipNear;
00589         andFlags &= clip;
00590         orFlags  |= clip;
00591     }
00592     if (0 == orFlags) return Inside;
00593     if (0 != andFlags) return Outside;
00594     return Clipped;
00595 }
00596 
00597 //------------------------------------------------------------------------------
00602 inline
00603 matrix44
00604 bbox3::to_matrix44() const
00605 {
00606     matrix44 m;
00607     m.scale(this->size());
00608     m.translate(this->center());
00609     return m;
00610 }
00611 
00612 //------------------------------------------------------------------------------
00620 inline bool bbox3::intersect(const line3& line, vector3& ipos) const
00621 {
00622     // Handle special case for start point inside box
00623     if (line.b.x >= vmin.x && line.b.y >= vmin.y && line.b.z >= vmin.z &&
00624         line.b.x <= vmax.x && line.b.y <= vmax.y && line.b.z <= vmax.z)
00625     {
00626         ipos = line.b;
00627         return true;
00628     }
00629 
00630     // Order planes to check, closest three only
00631     int plane[3];
00632     if (line.m.x > 0) plane[0] = 0;
00633     else              plane[0] = 1;
00634     if (line.m.y > 0) plane[1] = 2;
00635     else              plane[1] = 3;
00636     if (line.m.z > 0) plane[2] = 4;
00637     else              plane[2] = 5;
00638 
00639     for (int i = 0; i < 3; ++i)
00640     {
00641         switch (plane[i])
00642         {
00643             case 0:
00644                 if (isect_const_x(vmin.x,line,ipos) && pip_const_x(ipos)) return true;
00645                 break;
00646             case 1:
00647                 if (isect_const_x(vmax.x,line,ipos) && pip_const_x(ipos)) return true;
00648                 break;
00649             case 2:
00650                 if (isect_const_y(vmin.y,line,ipos) && pip_const_y(ipos)) return true;
00651                 break;
00652             case 3:
00653                 if (isect_const_y(vmax.y,line,ipos) && pip_const_y(ipos)) return true;
00654                 break;
00655             case 4:
00656                 if (isect_const_z(vmin.z,line,ipos) && pip_const_z(ipos)) return true;
00657                 break;
00658             case 5:
00659                 if (isect_const_z(vmax.z,line,ipos) && pip_const_z(ipos)) return true;
00660                 break;
00661         }
00662     }
00663 
00664     return false;
00665 }
00666 
00667 //------------------------------------------------------------------------------
00670 inline
00671 int bbox3::line_test(float v0, float v1, float w0, float w1)
00672 {
00673     // quick rejection test
00674     if ((v1 < w0) || (v0 > w1)) return OUTSIDE;
00675     if ((v0 == w0) && (v1 == w1)) return ISEQUAL;
00676     if ((v0 >= w0) && (v1 <= w1)) return ISCONTAINED;
00677     if ((v0 <= w0) && (v1 >= w1)) return CONTAINS;
00678     return CLIPS;
00679 }
00680 
00681 //------------------------------------------------------------------------------
00687 inline
00688 int bbox3::intersect(const bbox3& box)
00689 {
00690     int and_code = 0xffff;
00691     int or_code = 0;
00692     int cx = line_test(vmin.x, vmax.x, box.vmin.x, box.vmax.x);
00693     and_code &= cx;
00694     or_code |= cx;
00695     int cy = line_test(vmin.y, vmax.y, box.vmin.y, box.vmax.y);
00696     and_code &= cy;
00697     or_code |= cy;
00698     int cz = line_test(vmin.z, vmax.z, box.vmin.z, box.vmax.z);
00699     and_code &= cz;
00700     or_code |= cz;
00701     if (or_code == 0) return OUTSIDE;
00702     if (and_code != 0) return and_code;
00703     // only if all test produced a non-outside result,
00704     // an intersection has occurred
00705     if (cx && cy && cz) return CLIPS;
00706     return OUTSIDE;
00707 }
00708 
00709 //------------------------------------------------------------------------------
00712 inline
00713 float
00714 bbox3::diagonal_size() const
00715 {
00716     return vector3::distance(this->vmin, this->vmax);
00717 }
00718 //------------------------------------------------------------------------------
00719 #endif

Copyright © 1999-2005 by the contributing authors. Ideas, requests, problems: Send feedback.