// =================================================================== // $Id: sbbox.h $ // // sbbox.h // // Class: SBBox // // REPLACEMENT_STRING // // Copyright by Vlastimil Havran, 2007 - email to "vhavran AT seznam.cz" // Initial coding by Vlasta Havran, December 2005 #ifndef __SBBOX_H__ #define __SBBOX_H__ // ANSI C++ headers #include #include #include // GOLEM headers #include "configh.h" #include "common.h" #include "AxisAlignedBox3.h" #include "SimpleRay.h" #include "Vector3.h" namespace GtpVisibilityPreprocessor { // Forward declarations // -------------------------------------------------------- // The definition of the bounding box having 24 Bytes only struct SBBox { public: SBBox() {} SBBox(const Vector3 &a, const Vector3 &b) { pp[0] = a; pp[1] = b; } // member functions const Vector3& Min() const { return pp[0]; } const Vector3& Max() const { return pp[1]; } Vector3& Min() { return pp[0]; } Vector3& Max() { return pp[1]; } const float& Min(int i) const { return pp[0][i]; } const float& Max(int i) const { return pp[1][i]; } float& Min(int i) { return pp[0][i]; } float& Max(int i) { return pp[1][i]; } // Access to individual components, maybe it is not a good idea const float& MinX() const { return pp[0].x; } const float& MaxX() const { return pp[1].x; } float& MinX() { return pp[0].x; } float& MaxX() { return pp[1].x; } const float& MinY() const { return pp[0].y; } const float& MaxY() const { return pp[1].y; } float& MinY() { return pp[0].y; } float& MaxY() { return pp[1].y; } const float& MinZ() const { return pp[0].z; } const float& MaxZ() const { return pp[1].z; } float& MinZ() { return pp[0].z; } float& MaxZ() { return pp[1].z; } void SetMin(float x, float y, float z) { pp[0].x=x; pp[0].y=y; pp[0].z=z; } void SetMax(float x, float y, float z) { pp[1].x=x; pp[1].y=y; pp[1].z=z; } // initialization to the non existing bounding box inline void Initialize() { pp[0] = Vector3(MAXFLOAT); pp[1] = Vector3(-MAXFLOAT); } inline void Convert(const AxisAlignedBox3 &b) { pp[0] = b.Min(); pp[1] = b.Max(); } Vector3 Diagonal() const { return pp[1] - pp[0];} // Compute the center of the box void ComputeCentroid(Vector3 &c) const { c.x = (pp[0].x + pp[1].x)*0.5f; c.y = (pp[0].y + pp[1].y)*0.5f; c.z = (pp[0].z + pp[1].z)*0.5f; } // Compute half of surface area of the box float SA2() const { float t1 = (pp[1].x-pp[0].x); float t2 = (pp[1].y-pp[0].y); float t3 = (pp[1].z-pp[0].z); return t1*t2 + t2*t3 + t1*t3; } // Compute volume of the box float GetVolume() const { return (pp[1].x-pp[0].x)*(pp[1].y-pp[0].y)*(pp[1].z-pp[0].z); } void SetMin(int axis, const float value) { pp[0][axis] = value; } void SetMax(int axis, const float value) { pp[1][axis] = value; } // Write acess to min and max void SetMin(const Vector3& bmin) { pp[0] = bmin;} void SetMax(const Vector3& bmax) { pp[1] = bmax;} // Decrease box by given splitting plane void Reduce(int axis, int right, float value) { if ( (value >= pp[0][axis]) && (value <= pp[1][axis]) ) { if (right) pp[0][axis] = value; else pp[1][axis] = value; } } inline void Include(const AxisAlignedBox3 &bbox); inline void Include(const SBBox &bbox); inline bool RayIntersect(const SimpleRay &r, float &tmin, float &tmax) const; inline void ComputeMaxT(const SimpleRay &r, float &tmax) const; inline void ComputeMinT(const SimpleRay &r, float &tmin) const; // Query functions // Includes returns true if this box includes box b (completely) bool Includes(const SBBox &b) const; bool Includes(const SBBox &b, float eps) const; // Returns false if the box 'b' is fully contained in 'this', see the code inline bool ExcludesPartially(const SBBox &b) const; // Returs true if this box includes a point inline bool Includes(const Vector3 &vec) const; // Includes returns true if this box includes box b including boundary inline bool IncludesS(const Vector3 &vec) const; inline bool IncludesS(const Vector3 &vec, float eps) const; inline bool Equal(const SBBox &b, float eps = 0.f) const; // Returns the intersection of two axis-aligned boxes. friend inline SBBox Intersect(const SBBox &x, const SBBox &y); // Test if the box is really sensefull bool IsCorrect(); // Overlap returns 1 if the two axis-aligned boxes overlap .. only strongly friend inline bool OverlapS(const SBBox &, const SBBox &); protected: // pp[0] is minimum, pp[1] is maximum Vector3 pp[2]; }; // -------------------------------------------------------- // Inline functions inline void SBBox::Include(const AxisAlignedBox3 &bbox) { Minimize(pp[0], bbox.Min()); Maximize(pp[1], bbox.Max()); } inline void SBBox::Include(const SBBox &bbox) { Minimize(pp[0], bbox.pp[0]); Maximize(pp[1], bbox.pp[1]); } inline bool SBBox::Equal(const SBBox &b, float eps) const { if ( (!EpsilonEqual(pp[0].x, b.pp[0].x, eps)) || (!EpsilonEqual(pp[0].y, b.pp[0].y, eps)) || (!EpsilonEqual(pp[0].z, b.pp[0].z, eps)) || (!EpsilonEqual(pp[1].x, b.pp[1].x, eps)) || (!EpsilonEqual(pp[1].y, b.pp[1].y, eps)) || (!EpsilonEqual(pp[1].z, b.pp[1].z, eps)) ) return false; // they are not equal return true; } inline bool SBBox::IsCorrect() { if ( (pp[0].x > pp[1].x) || (pp[0].y > pp[1].y) || (pp[0].z > pp[1].z) ) return false; // box is not formed return true; } inline bool OverlapS(const SBBox &x, const SBBox &y) { if (x.pp[1].x <= y.pp[0].x || x.pp[0].x >= y.pp[1].x || x.pp[1].y <= y.pp[0].y || x.pp[0].y >= y.pp[1].y || x.pp[1].z <= y.pp[0].z || x.pp[0].z >= y.pp[1].z) { return false; } return true; } // Returns true if the boxes are either disjoint or only // share a single face ! inline bool SBBox::ExcludesPartially(const SBBox &b) const { if (b.pp[1].x <= pp[0].x || b.pp[1].y <= pp[0].y || b.pp[1].z <= pp[0].z || b.pp[0].x >= pp[1].x || b.pp[0].y >= pp[1].y || b.pp[0].z >= pp[1].z) // box 'b' is not fully contained in 'this', also true when neighboring faces return true; return false; // box 'b' contained in this box } inline bool SBBox::Includes(const Vector3 &vec) const { if (vec.x < pp[0].x || vec.x > pp[1].x || vec.y < pp[0].y || vec.y > pp[1].y || vec.z < pp[0].z || vec.z > pp[1].z) { return false; } return true; } inline bool SBBox::IncludesS(const Vector3 &vec) const { if (vec.x <= pp[0].x || vec.x >= pp[1].x || vec.y <= pp[0].y || vec.y >= pp[1].y || vec.z <= pp[0].z || vec.z >= pp[1].z) { return false; } return true; } inline bool SBBox::IncludesS(const Vector3 &vec, float eps) const { if (vec.x <= (pp[0].x-eps) || vec.x >= (pp[1].x+eps) || vec.y <= (pp[0].y-eps) || vec.y >= (pp[1].y+eps) || vec.z <= (pp[0].z-eps) || vec.z >= (pp[1].z+eps) ) { return false; // outside } return true; // point inside } // Function describing the box extern void Describe(const SBBox &b, std::ostream &app, int indent); // Function describing the box extern void DescribeXYZ(const SBBox &b, std::ostream &app, int indent); inline SBBox Intersect(const SBBox &x, const SBBox &y) { SBBox ret = x; if (OverlapS(ret, y)) { Maximize(ret.pp[0], y.pp[0]); Minimize(ret.pp[1], y.pp[1]); return ret; } // Null intersection. return SBBox(Vector3(0), Vector3(0)); } #if 1 // The implementation I, the first version implemented by Vlastimil // Havran, without looking into the literature inline bool SBBox::RayIntersect(const SimpleRay &ray, float &tmin, float &tmax) const { float interval_min = tmin; float interval_max = tmax; const Vector3 &rayLoc = ray.mOrigin; const Vector3 &rayDir = ray.mDirection; float t0, t1; if (rayDir.x > 0) { t0 = (pp[0].x - rayLoc.x) / rayDir.x; t1 = (pp[1].x - rayLoc.x) / rayDir.x; } else { t0 = (pp[1].x - rayLoc.x) / rayDir.x; t1 = (pp[0].x - rayLoc.x) / rayDir.x; } assert(t0 <= t1); if (t0 > interval_min) interval_min = t0; if (t1 < interval_max) interval_max = t1; if (interval_min > interval_max) return false; if (rayDir.y > 0) { t0 = (pp[0].y - rayLoc.y) / rayDir.y; t1 = (pp[1].y - rayLoc.y) / rayDir.y; } else { t0 = (pp[1].y - rayLoc.y) / rayDir.y; t1 = (pp[0].y - rayLoc.y) / rayDir.y; } assert(t0 <= t1); if (t0 > interval_min) interval_min = t0; if (t1 < interval_max) interval_max = t1; if (interval_min > interval_max) return false; if (rayDir.z > 0) { t0 = (pp[0].z - rayLoc.z) / rayDir.z; t1 = (pp[1].z - rayLoc.z) / rayDir.z; } else { t0 = (pp[1].z - rayLoc.z) / rayDir.z; t1 = (pp[0].z - rayLoc.z) / rayDir.z; } assert(t0 <= t1); if (t0 > interval_min) interval_min = t0; if (t1 < interval_max) interval_max = t1; // return true if the box is intersected // return false if not intersected by ray if ( (interval_max > 0.0f) && (interval_min <= interval_max) ) { // yes, intersected, update tmin and tmax for current node tmin = interval_min; tmax = interval_max; return true; // intersected } return false; // not intersected } #endif #if 1 // Here we compute exit signed distance along the ray // from the box inline void SBBox::ComputeMaxT(const SimpleRay &ray, float &tmax) const { float interval_max = tmax; const Vector3 &rayLoc = ray.mOrigin; const Vector3 &rayDir = ray.mDirection; float t; assert(pp[1].x >= pp[0].x); if (rayDir.x > 0) t = (pp[1].x - rayLoc.x) / rayDir.x; else t = (pp[0].x - rayLoc.x) / rayDir.x; if (t > interval_max) interval_max = t; assert(pp[1].y >= pp[0].y); if (rayDir.y > 0) t = (pp[1].y - rayLoc.y) / rayDir.y; else t = (pp[0].y - rayLoc.y) / rayDir.y; if (t > interval_max) interval_max = t; assert(pp[1].z >= pp[0].z); if (rayDir.z > 0) t = (pp[1].z - rayLoc.z) / rayDir.z; else t = (pp[0].z - rayLoc.z) / rayDir.z; if (t > interval_max) interval_max = t; } #endif #if 1 // Here we compute entry signed distance along the ray // into the box inline void SBBox::ComputeMinT(const SimpleRay &ray, float &tmin) const { float interval_min = tmin; const Vector3 &rayLoc = ray.mOrigin; const Vector3 &rayDir = ray.mDirection; float t; assert(pp[1].x >= pp[0].x); if (rayDir.x > 0) t = (pp[0].x - rayLoc.x) / rayDir.x; else t = (pp[1].x - rayLoc.x) / rayDir.x; if (t < interval_min) interval_min = t; assert(pp[1].y >= pp[0].y); if (rayDir.y > 0) t = (pp[0].y - rayLoc.y) / rayDir.y; else t = (pp[1].y - rayLoc.y) / rayDir.y; if (t < interval_min) interval_min = t; assert(pp[1].z >= pp[0].z); if (rayDir.z > 0) t = (pp[0].z - rayLoc.z) / rayDir.z; else t = (pp[1].z - rayLoc.z) / rayDir.z; if (t < interval_min) interval_min = t; } #endif } #endif // __SBBOX_H__