//----------------------------------------------------------------------------- // Torque Game Engine // Copyright (C) GarageGames.com, Inc. //----------------------------------------------------------------------------- #ifndef _MPLANE_H_ #define _MPLANE_H_ #ifndef _MMATHFN_H_ #include "math/mMathFn.h" #endif #ifndef _MPOINT_H_ #include "math/mPoint.h" #endif //--------------------------------------------------------------------------- class PlaneF: public Point3F { public: F32 d; PlaneF(); PlaneF( const Point3F& p, const Point3F& n ); PlaneF( F32 _x, F32 _y, F32 _z, F32 _d); PlaneF( const Point3F& j, const Point3F& k, const Point3F& l ); // Comparison operators bool operator==(const PlaneF&a) const { return (a.x == x && a.y == y && a.z == z && a.d == d); } bool operator!=(const PlaneF&a) const { return (a.x != x || a.y != y || a.z != z || a.d == d); } // Methods void set(const F32 _x, const F32 _y, const F32 _z); void set( const Point3F& p, const Point3F& n); void set( const Point3F& k, const Point3F& j, const Point3F& l ); void setPoint(const Point3F &p); // assumes the x,y,z fields are already set // creates an un-normalized plane void setXY(F32 zz); void setYZ(F32 xx); void setXZ(F32 yy); void setXY(const Point3F& P, F32 dir); void setYZ(const Point3F& P, F32 dir); void setXZ(const Point3F& P, F32 dir); void shiftX(F32 xx); void shiftY(F32 yy); void shiftZ(F32 zz); void invert(); void neg(); Point3F project(Point3F pt); // project's the point onto the plane. F32 distToPlane( const Point3F& cp ) const; enum Side { Front = 1, On = 0, Back = -1 }; Side whichSide(const Point3F& cp) const; F32 intersect(const Point3F &start, const Point3F &end) const; bool isHorizontal() const; bool isVertical() const; Side whichSideBox(const Point3F& center, const Point3F& axisx, const Point3F& axisy, const Point3F& axisz, const Point3F& offset) const; }; #define PARALLEL_PLANE 1e20f #define PlaneSwitchCode(s, e) (s * 3 + e) //--------------------------------------------------------------------------- inline PlaneF::PlaneF() { } inline PlaneF:: PlaneF( F32 _x, F32 _y, F32 _z, F32 _d ) { x = _x; y = _y; z = _z; d = _d; } inline PlaneF::PlaneF( const Point3F& p, const Point3F& n ) { set(p,n); } inline PlaneF::PlaneF( const Point3F& j, const Point3F& k, const Point3F& l ) { set(j,k,l); } inline void PlaneF::setXY( F32 zz ) { x = y = 0.0f; z = 1.0f; d = -zz; } inline void PlaneF::setYZ( F32 xx ) { x = 1.0f; z = y = 0.0f; d = -xx; } inline void PlaneF::setXZ( F32 yy ) { x = z = 0.0f; y = 1.0f; d = -yy; } inline void PlaneF::setXY(const Point3F& point, F32 dir) // Normal = (0, 0, -1|1) { x = y = 0.0f; d = -((z = dir) * point.z); } inline void PlaneF::setYZ(const Point3F& point, F32 dir) // Normal = (-1|1, 0, 0) { z = y = 0.0f; d = -((x = dir) * point.x); } inline void PlaneF::setXZ(const Point3F& point, F32 dir) // Normal = (0, -1|1, 0) { x = z = 0.0f; d = -((y = dir) * point.y); } inline void PlaneF::shiftX( F32 xx ) { d -= xx * x; } inline void PlaneF::shiftY( F32 yy ) { d -= yy * y; } inline void PlaneF::shiftZ( F32 zz ) { d -= zz * z; } inline bool PlaneF::isHorizontal() const { return (x == 0.0f && y == 0.0f) ? true : false; } inline bool PlaneF::isVertical() const { return ((x != 0.0f || y != 0.0f) && z == 0.0f) ? true : false; } inline Point3F PlaneF::project(Point3F pt) { F32 dist = distToPlane(pt); return Point3F(pt.x - x * dist, pt.y - y * dist, pt.z - z * dist); } inline F32 PlaneF::distToPlane( const Point3F& cp ) const { // return mDot(*this,cp) + d; return (x * cp.x + y * cp.y + z * cp.z) + d; } inline PlaneF::Side PlaneF::whichSide(const Point3F& cp) const { F32 dist = distToPlane(cp); if (dist >= 0.005f) // if (mFabs(dist) < 0.005f) return Front; // return On; else if (dist <= -0.005f) // else if (dist > 0.0f) return Back; // return Front; else // else return On; // return Back; } inline void PlaneF::set(const F32 _x, const F32 _y, const F32 _z) { Point3F::set(_x,_y,_z); } //--------------------------------------------------------------------------- /// Calculate the coefficients of the plane passing through /// a point with the given normal. inline void PlaneF::setPoint(const Point3F &p) { d = -(p.x * x + p.y * y + p.z * z); } inline void PlaneF::set( const Point3F& p, const Point3F& n ) { x = n.x; y = n.y; z = n.z; normalize(); // Calculate the last plane coefficient. d = -(p.x * x + p.y * y + p.z * z); } //--------------------------------------------------------------------------- /// Calculate the coefficients of the plane passing through /// three points. Basically it calculates the normal to the three /// points then calculates a plane through the middle point with that /// normal. inline void PlaneF::set( const Point3F& k, const Point3F& j, const Point3F& l ) { // Point3F kj,lj,pv; // kj = k; // kj -= j; // lj = l; // lj -= j; // mCross( kj, lj, &pv ); // set(j,pv); // Above ends up making function calls up the %*#... // This is called often enough to be a little more direct // about it (sqrt should become intrinsic in the future)... const F32 ax = k.x-j.x; const F32 ay = k.y-j.y; const F32 az = k.z-j.z; const F32 bx = l.x-j.x; const F32 by = l.y-j.y; const F32 bz = l.z-j.z; x = ay*bz - az*by; y = az*bx - ax*bz; z = ax*by - ay*bx; m_point3F_normalize( (F32 *)(&x) ); d = -(j.x * x + j.y * y + j.z * z); } inline void PlaneF::invert() { x = -x; y = -y; z = -z; d = -d; } inline void PlaneF::neg() { invert(); } inline F32 PlaneF::intersect(const Point3F &p1, const Point3F &p2) const { const F32 den = mDot(p2 - p1, *this); if(den == 0.0f) return PARALLEL_PLANE; return -distToPlane(p1) / den; } inline PlaneF::Side PlaneF::whichSideBox(const Point3F& center, const Point3F& axisx, const Point3F& axisy, const Point3F& axisz, const Point3F& /*offset*/) const { F32 baseDist = distToPlane(center); F32 compDist = mFabs(mDot(axisx, *this)) + mFabs(mDot(axisy, *this)) + mFabs(mDot(axisz, *this)); if (baseDist >= compDist) return Front; else if (baseDist <= -compDist) return Back; else return On; } #endif