//---------------------------------------------------------------------------- bool Mgc::FindIntersection (const Plane& rkPlane0, const Plane& rkPlane1, Line3& rkLine) { // If Cross(N0,N1) is zero, then either planes are parallel and separated // or the same plane. In both cases, 'false' is returned. Otherwise, // the intersection line is // // L(t) = t*Cross(N0,N1) + c0*N0 + c1*N1 // // for some coefficients c0 and c1 and for t any real number (the line // parameter). Taking dot products with the normals, // // d0 = Dot(N0,L) = c0*Dot(N0,N0) + c1*Dot(N0,N1) // d1 = Dot(N1,L) = c0*Dot(N0,N1) + c1*Dot(N1,N1) // // which are two equations in two unknowns. The solution is // // c0 = (Dot(N1,N1)*d0 - Dot(N0,N1)*d1)/det // c1 = (Dot(N0,N0)*d1 - Dot(N0,N1)*d0)/det // // where det = Dot(N0,N0)*Dot(N1,N1)-Dot(N0,N1)^2. Real fN00 = rkPlane0.Normal().SquaredLength(); Real fN01 = rkPlane0.Normal().Dot(rkPlane1.Normal()); Real fN11 = rkPlane1.Normal().SquaredLength(); Real fDet = fN00*fN11 - fN01*fN01; if ( Math::FAbs(fDet) < gs_fEpsilon ) return false; Real fInvDet = 1.0f/fDet; Real fC0 = (fN11*rkPlane0.Constant() - fN01*rkPlane1.Constant())*fInvDet; Real fC1 = (fN00*rkPlane1.Constant() - fN01*rkPlane0.Constant())*fInvDet; rkLine.Direction() = rkPlane0.Normal().Cross(rkPlane1.Normal()); rkLine.Origin() = fC0*rkPlane0.Normal() + fC1*rkPlane1.Normal(); return true; }
//---------------------------------------------------------------------------- bool Mgc::Culled (const Plane& rkPlane, const Sphere& rkSphere, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fTmp = kNormal.Dot(rkSphere.Center()) - fConstant; return fTmp <= -rkSphere.Radius(); }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Plane& rkPlane, const Sphere& rkSphere, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fPseudoDistance = kNormal.Dot(rkSphere.Center()) - fConstant; return Math::FAbs(fPseudoDistance) <= rkSphere.Radius(); }
//---------------------------------------------------------------------------- bool Mgc::Culled (const Plane& rkPlane, const Ellipsoid& rkEllipsoid, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fDiscr = kNormal.Dot(rkEllipsoid.InverseA()*kNormal); Real fRoot = Math::Sqrt(Math::FAbs(fDiscr)); Real fSDist = kNormal.Dot(rkEllipsoid.Center()) - fConstant; return fSDist <= -fRoot; }
//---------------------------------------------------------------------------- bool Mgc::Culled (const Plane& rkPlane, const Lozenge& rkLozenge, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Real fTmp00 = kNormal.Dot(rkLozenge.Origin()) - fConstant; if ( fTmp00 < 0.0f ) { Real fDotNE0 = kNormal.Dot(rkLozenge.Edge0()); Real fTmp10 = fTmp00 + fDotNE0; if ( fTmp10 < 0.0f ) { Real fDotNE1 = kNormal.Dot(rkLozenge.Edge1()); Real fTmp01 = fTmp00 + fDotNE1; if ( fTmp01 < 0.0f ) { Real fTmp11 = fTmp10 + fDotNE1; if ( fTmp11 < 0.0f ) { // all four lozenge corners on negative side of plane if ( fTmp00 <= fTmp10 ) { if ( fTmp00 <= fTmp01 ) return fTmp00 <= -rkLozenge.Radius(); else return fTmp01 <= -rkLozenge.Radius(); } else { if ( fTmp10 <= fTmp11 ) return fTmp10 <= -rkLozenge.Radius(); else return fTmp11 <= -rkLozenge.Radius(); } } } } } return false; }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Plane& rkPlane, const Lozenge& rkLozenge, bool bUnitNormal) { Vector3 kNormal = rkPlane.Normal(); Real fConstant = rkPlane.Constant(); if ( !bUnitNormal ) { Real fLength = kNormal.Unitize(); fConstant /= fLength; } Vector3 kC10 = rkLozenge.Origin() + rkLozenge.Edge0(); Vector3 kC01 = rkLozenge.Origin() + rkLozenge.Edge1(); Vector3 kC11 = kC10 + rkLozenge.Edge1(); Real fTmp00 = kNormal.Dot(rkLozenge.Origin()) - fConstant; Real fTmp10 = kNormal.Dot(kC10) - fConstant; if ( fTmp00*fTmp10 <= 0.0f ) { // two lozenge ends on opposite sides of the plane return true; } Real fTmp01 = kNormal.Dot(kC01) - fConstant; if ( fTmp00*fTmp01 <= 0.0f ) { // two lozenge ends on opposite sides of the plane return true; } Real fTmp11 = kNormal.Dot(kC11) - fConstant; if ( fTmp10*fTmp11 <= 0.0f ) { // two lozenge ends on opposite sides of the plane return true; } return Math::FAbs(fTmp00) <= rkLozenge.Radius() || Math::FAbs(fTmp10) <= rkLozenge.Radius() || Math::FAbs(fTmp01) <= rkLozenge.Radius() || Math::FAbs(fTmp11) <= rkLozenge.Radius(); }
//---------------------------------------------------------------------------- void Mgc::PerspProjEllipsoid (const GeneralEllipsoid& rkEllipsoid, const Vector3& rkEye, const Plane& rkPlane, GeneralEllipse& rkEllipse) { // compute matrix M Vector3 kAE = rkEllipsoid.m_kA*rkEye; Real fEAE = rkEye.Dot(kAE); Real fBE = rkEllipsoid.m_kB.Dot(rkEye); Real fTmp = 4.0f*(fEAE + fBE + rkEllipsoid.m_fC); Vector3 kTmp = rkEllipsoid.m_kB + 2.0f*kAE; Matrix3 kMat; kMat[0][0] = kTmp.x*kTmp.x - fTmp*rkEllipsoid.m_kA[0][0]; kMat[0][1] = kTmp.x*kTmp.y - fTmp*rkEllipsoid.m_kA[0][1]; kMat[0][2] = kTmp.x*kTmp.z - fTmp*rkEllipsoid.m_kA[0][2]; kMat[1][1] = kTmp.y*kTmp.y - fTmp*rkEllipsoid.m_kA[1][1]; kMat[1][2] = kTmp.y*kTmp.z - fTmp*rkEllipsoid.m_kA[1][2]; kMat[2][2] = kTmp.z*kTmp.z - fTmp*rkEllipsoid.m_kA[2][2]; kMat[1][0] = kMat[0][1]; kMat[2][0] = kMat[0][2]; kMat[2][1] = kMat[1][2]; // Normalize N and construct U and V so that {U,V,N} forms a // right-handed, orthonormal basis. Vector3 kU, kV, kN = rkPlane.Normal(); Vector3::GenerateOrthonormalBasis(kU,kV,kN,false); // compute coefficients for projected ellipse Vector3 kMU = kMat*kU, kMV = kMat*kV, kMN = kMat*kN; Real fDmNE = rkPlane.Constant() - kN.Dot(rkEye); rkEllipse.m_kA[0][0] = kU.Dot(kMU); rkEllipse.m_kA[0][1] = kU.Dot(kMV); rkEllipse.m_kA[1][1] = kV.Dot(kMV); rkEllipse.m_kA[1][0] = rkEllipse.m_kA[0][1]; rkEllipse.m_kB.x = 2.0f*fDmNE*(kU.Dot(kMN)); rkEllipse.m_kB.y = 2.0f*fDmNE*(kV.Dot(kMN)); rkEllipse.m_fC = fDmNE*fDmNE*(kN.Dot(kMN)); }