void Wml::BoxProjection (const Vector3<Real>& rkAxis, const Box3<Real>& rkBox, Real& rfMin, Real& rfMax) { Real fOrigin = rkAxis.Dot(rkBox.Center()); Real fMaximumExtent = Math<Real>::FAbs(rkBox.Extent(0)*rkAxis.Dot(rkBox.Axis(0))) + Math<Real>::FAbs(rkBox.Extent(1)*rkAxis.Dot(rkBox.Axis(1))) + Math<Real>::FAbs(rkBox.Extent(2)*rkAxis.Dot(rkBox.Axis(2))); rfMin = fOrigin - fMaximumExtent; rfMax = fOrigin + fMaximumExtent; }
Box3<Real> Wml::ContOrientedBox (int iQuantity, const Vector3<Real>* akPoint) { Box3<Real> kBox; GaussPointsFit(iQuantity,akPoint,kBox.Center(),kBox.Axes(), kBox.Extents()); // Let C be the box center and let U0, U1, and U2 be the box axes. Each // input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The // following code computes min(y0), max(y0), min(y1), max(y1), min(y2), // and max(y2). The box center is then adjusted to be // C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 + // 0.5*(min(y2)+max(y2))*U2 Vector3<Real> kDiff = akPoint[0] - kBox.Center(); Real fY0Min = kDiff.Dot(kBox.Axis(0)), fY0Max = fY0Min; Real fY1Min = kDiff.Dot(kBox.Axis(1)), fY1Max = fY1Min; Real fY2Min = kDiff.Dot(kBox.Axis(2)), fY2Max = fY2Min; for (int i = 1; i < iQuantity; i++) { kDiff = akPoint[i] - kBox.Center(); Real fY0 = kDiff.Dot(kBox.Axis(0)); if ( fY0 < fY0Min ) fY0Min = fY0; else if ( fY0 > fY0Max ) fY0Max = fY0; Real fY1 = kDiff.Dot(kBox.Axis(1)); if ( fY1 < fY1Min ) fY1Min = fY1; else if ( fY1 > fY1Max ) fY1Max = fY1; Real fY2 = kDiff.Dot(kBox.Axis(2)); if ( fY2 < fY2Min ) fY2Min = fY2; else if ( fY2 > fY2Max ) fY2Max = fY2; } kBox.Center() += (((Real)0.5)*(fY0Min+fY0Max))*kBox.Axis(0) + (((Real)0.5)*(fY1Min+fY1Max))*kBox.Axis(1) + (((Real)0.5)*(fY2Min+fY2Max))*kBox.Axis(2); kBox.Extent(0) = ((Real)0.5)*(fY0Max - fY0Min); kBox.Extent(1) = ((Real)0.5)*(fY1Max - fY1Min); kBox.Extent(2) = ((Real)0.5)*(fY2Max - fY2Min); return kBox; }
bool Wml::Culled (const Plane3<Real>& rkPlane, const Box3<Real>& rkBox) { Real fTmp[3] = { rkBox.Extent(0)*(rkPlane.GetNormal().Dot(rkBox.Axis(0))), rkBox.Extent(1)*(rkPlane.GetNormal().Dot(rkBox.Axis(1))), rkBox.Extent(2)*(rkPlane.GetNormal().Dot(rkBox.Axis(2))) }; Real fRadius = Math<Real>::FAbs(fTmp[0]) + Math<Real>::FAbs(fTmp[1]) + Math<Real>::FAbs(fTmp[2]); Real fPseudoDistance = rkPlane.DistanceTo(rkBox.Center()); return fPseudoDistance <= -fRadius; }
//---------------------------------------------------------------------------- static void MinimalBoxForAngles (int iQuantity, const Vector3* akPoint, Real afAngle[3], Box3& rkBox) { Real fCos0 = Math::Cos(afAngle[0]); Real fSin0 = Math::Sin(afAngle[0]); Real fCos1 = Math::Cos(afAngle[1]); Real fSin1 = Math::Sin(afAngle[1]); Vector3 kAxis(fCos0*fSin1,fSin0*fSin1,fCos1); Matrix3 kRot; kRot.FromAxisAngle(kAxis,afAngle[2]); Vector3 kMin = akPoint[0]*kRot, kMax = kMin; for (int i = 1; i < iQuantity; i++) { Vector3 kTest = akPoint[i]*kRot; if ( kTest.x < kMin.x ) kMin.x = kTest.x; else if ( kTest.x > kMax.x ) kMax.x = kTest.x; if ( kTest.y < kMin.y ) kMin.y = kTest.y; else if ( kTest.y > kMax.y ) kMax.y = kTest.y; if ( kTest.z < kMin.z ) kMin.z = kTest.z; else if ( kTest.z > kMax.z ) kMax.z = kTest.z; } Vector3 kMid = 0.5f*(kMax + kMin); Vector3 kRng = 0.5f*(kMax - kMin); rkBox.Center() = kRot*kMid; rkBox.Axis(0) = kRot.GetColumn(0); rkBox.Axis(1) = kRot.GetColumn(1); rkBox.Axis(2) = kRot.GetColumn(2); rkBox.Extent(0) = kRng.x; rkBox.Extent(1) = kRng.y; rkBox.Extent(2) = kRng.z; }
void MinBox3<Real>::MinimalBoxForAngles (int iQuantity, const Vector3<Real>* akPoint, Real afAngle[3], Box3<Real>& rkBox) { Real fCos0 = Math<Real>::Cos(afAngle[0]); Real fSin0 = Math<Real>::Sin(afAngle[0]); Real fCos1 = Math<Real>::Cos(afAngle[1]); Real fSin1 = Math<Real>::Sin(afAngle[1]); Vector3<Real> kAxis(fCos0*fSin1,fSin0*fSin1,fCos1); Matrix3<Real> kRot(kAxis,afAngle[2]); Vector3<Real> kMin = akPoint[0]*kRot, kMax = kMin; for (int i = 1; i < iQuantity; i++) { Vector3<Real> kTest = akPoint[i]*kRot; if ( kTest.X() < kMin.X() ) kMin.X() = kTest.X(); else if ( kTest.X() > kMax.X() ) kMax.X() = kTest.X(); if ( kTest.Y() < kMin.Y() ) kMin.Y() = kTest.Y(); else if ( kTest.Y() > kMax.Y() ) kMax.Y() = kTest.Y(); if ( kTest.Z() < kMin.Z() ) kMin.Z() = kTest.Z(); else if ( kTest.Z() > kMax.Z() ) kMax.Z() = kTest.Z(); } Vector3<Real> kMid = ((Real)0.5)*(kMax + kMin); Vector3<Real> kRng = ((Real)0.5)*(kMax - kMin); rkBox.Center() = kRot*kMid; rkBox.Axis(0) = kRot.GetColumn(0); rkBox.Axis(1) = kRot.GetColumn(1); rkBox.Axis(2) = kRot.GetColumn(2); rkBox.Extent(0) = kRng.X(); rkBox.Extent(1) = kRng.Y(); rkBox.Extent(2) = kRng.Z(); }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Ray3& rkRay, const Box3& rkBox) { Real fWdU[3], fAWdU[3], fDdU[3], fADdU[3], fAWxDdU[3], fRhs; Vector3 kDiff = rkRay.Origin() - rkBox.Center(); fWdU[0] = rkRay.Direction().Dot(rkBox.Axis(0)); fAWdU[0] = Math::FAbs(fWdU[0]); fDdU[0] = kDiff.Dot(rkBox.Axis(0)); fADdU[0] = Math::FAbs(fDdU[0]); if ( fADdU[0] > rkBox.Extent(0) && fDdU[0]*fWdU[0] >= 0.0f ) return false; fWdU[1] = rkRay.Direction().Dot(rkBox.Axis(1)); fAWdU[1] = Math::FAbs(fWdU[1]); fDdU[1] = kDiff.Dot(rkBox.Axis(1)); fADdU[1] = Math::FAbs(fDdU[1]); if ( fADdU[1] > rkBox.Extent(1) && fDdU[1]*fWdU[1] >= 0.0f ) return false; fWdU[2] = rkRay.Direction().Dot(rkBox.Axis(2)); fAWdU[2] = Math::FAbs(fWdU[2]); fDdU[2] = kDiff.Dot(rkBox.Axis(2)); fADdU[2] = Math::FAbs(fDdU[2]); if ( fADdU[2] > rkBox.Extent(2) && fDdU[2]*fWdU[2] >= 0.0f ) return false; Vector3 kWxD = rkRay.Direction().Cross(kDiff); fAWxDdU[0] = Math::FAbs(kWxD.Dot(rkBox.Axis(0))); fRhs = rkBox.Extent(1)*fAWdU[2] + rkBox.Extent(2)*fAWdU[1]; if ( fAWxDdU[0] > fRhs ) return false; fAWxDdU[1] = Math::FAbs(kWxD.Dot(rkBox.Axis(1))); fRhs = rkBox.Extent(0)*fAWdU[2] + rkBox.Extent(2)*fAWdU[0]; if ( fAWxDdU[1] > fRhs ) return false; fAWxDdU[2] = Math::FAbs(kWxD.Dot(rkBox.Axis(2))); fRhs = rkBox.Extent(0)*fAWdU[1] + rkBox.Extent(1)*fAWdU[0]; if ( fAWxDdU[2] > fRhs ) return false; return true; }
//---------------------------------------------------------------------------- static void CaseNoZeros (Vector3& rkPnt, const Vector3& rkDir, const Box3& rkBox, Real* pfLParam, Real& rfSqrDistance) { Vector3 kPmE(rkPnt.x - rkBox.Extent(0), rkPnt.y - rkBox.Extent(1), rkPnt.z - rkBox.Extent(2)); Real fProdDxPy, fProdDyPx, fProdDzPx, fProdDxPz, fProdDzPy, fProdDyPz; fProdDxPy = rkDir.x*kPmE.y; fProdDyPx = rkDir.y*kPmE.x; if ( fProdDyPx >= fProdDxPy ) { fProdDzPx = rkDir.z*kPmE.x; fProdDxPz = rkDir.x*kPmE.z; if ( fProdDzPx >= fProdDxPz ) { // line intersects x = e0 Face(0,1,2,rkPnt,rkDir,rkBox,kPmE,pfLParam,rfSqrDistance); } else { // line intersects z = e2 Face(2,0,1,rkPnt,rkDir,rkBox,kPmE,pfLParam,rfSqrDistance); } } else { fProdDzPy = rkDir.z*kPmE.y; fProdDyPz = rkDir.y*kPmE.z; if ( fProdDzPy >= fProdDyPz ) { // line intersects y = e1 Face(1,2,0,rkPnt,rkDir,rkBox,kPmE,pfLParam,rfSqrDistance); } else { // line intersects z = e2 Face(2,0,1,rkPnt,rkDir,rkBox,kPmE,pfLParam,rfSqrDistance); } } }
bool Wml::InBox (const Vector3<Real>& rkPoint, const Box3<Real>& rkBox, Real fEpsilon) { Vector3<Real> kDiff = rkPoint - rkBox.Center(); for (int i = 0; i < 3; i++) { Real fCoeff = kDiff.Dot(rkBox.Axis(i)); if ( Math<Real>::FAbs(fCoeff) > rkBox.Extent(i) + fEpsilon ) return false; } return true; }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Segment3& rkSegment, const Box3& rkBox) { Real fAWdU[3], fADdU[3], fAWxDdU[3], fRhs; Vector3 kSDir = 0.5f*rkSegment.Direction(); Vector3 kSCen = rkSegment.Origin() + kSDir; Vector3 kDiff = kSCen - rkBox.Center(); fAWdU[0] = Math::FAbs(kSDir.Dot(rkBox.Axis(0))); fADdU[0] = Math::FAbs(kDiff.Dot(rkBox.Axis(0))); fRhs = rkBox.Extent(0) + fAWdU[0]; if ( fADdU[0] > fRhs ) return false; fAWdU[1] = Math::FAbs(kSDir.Dot(rkBox.Axis(1))); fADdU[1] = Math::FAbs(kDiff.Dot(rkBox.Axis(1))); fRhs = rkBox.Extent(1) + fAWdU[1]; if ( fADdU[1] > fRhs ) return false; fAWdU[2] = Math::FAbs(kSDir.Dot(rkBox.Axis(2))); fADdU[2] = Math::FAbs(kDiff.Dot(rkBox.Axis(2))); fRhs = rkBox.Extent(2) + fAWdU[2]; if ( fADdU[2] > fRhs ) return false; Vector3 kWxD = kSDir.Cross(kDiff); fAWxDdU[0] = Math::FAbs(kWxD.Dot(rkBox.Axis(0))); fRhs = rkBox.Extent(1)*fAWdU[2] + rkBox.Extent(2)*fAWdU[1]; if ( fAWxDdU[0] > fRhs ) return false; fAWxDdU[1] = Math::FAbs(kWxD.Dot(rkBox.Axis(1))); fRhs = rkBox.Extent(0)*fAWdU[2] + rkBox.Extent(2)*fAWdU[0]; if ( fAWxDdU[1] > fRhs ) return false; fAWxDdU[2] = Math::FAbs(kWxD.Dot(rkBox.Axis(2))); fRhs = rkBox.Extent(0)*fAWdU[1] + rkBox.Extent(1)*fAWdU[0]; if ( fAWxDdU[2] > fRhs ) return false; return true; }
//---------------------------------------------------------------------------- bool Mgc::TestIntersection (const Line3& rkLine, const Box3& rkBox) { Real fAWdU[3], fAWxDdU[3], fRhs; Vector3 kDiff = rkLine.Origin() - rkBox.Center(); Vector3 kWxD = rkLine.Direction().Cross(kDiff); fAWdU[1] = Math::FAbs(rkLine.Direction().Dot(rkBox.Axis(1))); fAWdU[2] = Math::FAbs(rkLine.Direction().Dot(rkBox.Axis(2))); fAWxDdU[0] = Math::FAbs(kWxD.Dot(rkBox.Axis(0))); fRhs = rkBox.Extent(1)*fAWdU[2] + rkBox.Extent(2)*fAWdU[1]; if ( fAWxDdU[0] > fRhs ) return false; fAWdU[0] = Math::FAbs(rkLine.Direction().Dot(rkBox.Axis(0))); fAWxDdU[1] = Math::FAbs(kWxD.Dot(rkBox.Axis(1))); fRhs = rkBox.Extent(0)*fAWdU[2] + rkBox.Extent(2)*fAWdU[0]; if ( fAWxDdU[1] > fRhs ) return false; fAWxDdU[2] = Math::FAbs(kWxD.Dot(rkBox.Axis(2))); fRhs = rkBox.Extent(0)*fAWdU[1] + rkBox.Extent(1)*fAWdU[0]; if ( fAWxDdU[2] > fRhs ) return false; return true; }
Vector3<Real> Wml::GetPoint (int iIndex, const Box3<Real>& rkBox) { Vector3<Real> kPoint = rkBox.Center(); if ( iIndex & 4 ) kPoint += rkBox.Extent(2)*rkBox.Axis(2); else kPoint -= rkBox.Extent(2)*rkBox.Axis(2); if ( iIndex & 2 ) kPoint += rkBox.Extent(1)*rkBox.Axis(1); else kPoint -= rkBox.Extent(1)*rkBox.Axis(1); if ( iIndex & 1 ) kPoint += rkBox.Extent(0)*rkBox.Axis(0); else kPoint -= rkBox.Extent(0)*rkBox.Axis(0); return kPoint; }
//---------------------------------------------------------------------------- static void Case000 (Vector3& rkPnt, const Box3& rkBox, Real& rfSqrDistance) { Real fDelta; if ( rkPnt.x < -rkBox.Extent(0) ) { fDelta = rkPnt.x + rkBox.Extent(0); rfSqrDistance += fDelta*fDelta; rkPnt.x = -rkBox.Extent(0); } else if ( rkPnt.x > rkBox.Extent(0) ) { fDelta = rkPnt.x - rkBox.Extent(0); rfSqrDistance += fDelta*fDelta; rkPnt.x = rkBox.Extent(0); } if ( rkPnt.y < -rkBox.Extent(1) ) { fDelta = rkPnt.y + rkBox.Extent(1); rfSqrDistance += fDelta*fDelta; rkPnt.y = -rkBox.Extent(1); } else if ( rkPnt.y > rkBox.Extent(1) ) { fDelta = rkPnt.y - rkBox.Extent(1); rfSqrDistance += fDelta*fDelta; rkPnt.y = rkBox.Extent(1); } if ( rkPnt.z < -rkBox.Extent(2) ) { fDelta = rkPnt.z + rkBox.Extent(2); rfSqrDistance += fDelta*fDelta; rkPnt.z = -rkBox.Extent(2); } else if ( rkPnt.z > rkBox.Extent(2) ) { fDelta = rkPnt.z - rkBox.Extent(2); rfSqrDistance += fDelta*fDelta; rkPnt.z = rkBox.Extent(2); } }
bool Wml::ContOrientedBox (int iQuantity, const Vector3<Real>* akPoint, const bool* abValid, Box3<Real>& rkBox) { if ( !GaussPointsFit(iQuantity,akPoint,abValid,rkBox.Center(), rkBox.Axes(),rkBox.Extents()) ) { return false; } // Let C be the box center and let U0, U1, and U2 be the box axes. Each // input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The // following code computes min(y0), max(y0), min(y1), max(y1), min(y2), // and max(y2). The box center is then adjusted to be // C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 + // 0.5*(min(y2)+max(y2))*U2 // get first valid vertex Vector3<Real> kDiff; Real fY0Min = (Real)0.0, fY0Max = (Real)0.0; Real fY1Min = (Real)0.0, fY1Max = (Real)0.0; Real fY2Min = (Real)0.0, fY2Max = (Real)0.0; int i; for (i = 0; i < iQuantity; i++) { if ( abValid[i] ) { kDiff = akPoint[i] - rkBox.Center(); fY0Min = kDiff.Dot(rkBox.Axis(0)); fY0Max = fY0Min; fY1Min = kDiff.Dot(rkBox.Axis(1)); fY1Max = fY1Min; fY2Min = kDiff.Dot(rkBox.Axis(2)); fY2Max = fY2Min; break; } } for (i++; i < iQuantity; i++) { if ( abValid[i] ) { kDiff = akPoint[i] - rkBox.Center(); Real fY0 = kDiff.Dot(rkBox.Axis(0)); if ( fY0 < fY0Min ) fY0Min = fY0; else if ( fY0 > fY0Max ) fY0Max = fY0; Real fY1 = kDiff.Dot(rkBox.Axis(1)); if ( fY1 < fY1Min ) fY1Min = fY1; else if ( fY1 > fY1Max ) fY1Max = fY1; Real fY2 = kDiff.Dot(rkBox.Axis(2)); if ( fY2 < fY2Min ) fY2Min = fY2; else if ( fY2 > fY2Max ) fY2Max = fY2; } } rkBox.Center() += (0.5f*(fY0Min+fY0Max))*rkBox.Axis(0) + (0.5f*(fY1Min+fY1Max))*rkBox.Axis(1) + (0.5f*(fY2Min+fY2Max))*rkBox.Axis(2); rkBox.Extent(0) = 0.5f*(fY0Max - fY0Min); rkBox.Extent(1) = 0.5f*(fY1Max - fY1Min); rkBox.Extent(2) = 0.5f*(fY2Max - fY2Min); return true; }
bool Wml::TestIntersection (const Box3<Real>& rkBox, const Sphere3<Real>& rkSphere) { // Test for intersection in the coordinate system of the box by // transforming the sphere into that coordinate system. Vector3<Real> kCDiff = rkSphere.Center() - rkBox.Center(); Real fAx = Math<Real>::FAbs(kCDiff.Dot(rkBox.Axis(0))); Real fAy = Math<Real>::FAbs(kCDiff.Dot(rkBox.Axis(1))); Real fAz = Math<Real>::FAbs(kCDiff.Dot(rkBox.Axis(2))); Real fDx = fAx - rkBox.Extent(0); Real fDy = fAy - rkBox.Extent(1); Real fDz = fAz - rkBox.Extent(2); if ( fAx <= rkBox.Extent(0) ) { if ( fAy <= rkBox.Extent(1) ) { if ( fAz <= rkBox.Extent(2) ) { // sphere center inside box return true; } else { // potential sphere-face intersection with face z return fDz <= rkSphere.Radius(); } } else { if ( fAz <= rkBox.Extent(2) ) { // potential sphere-face intersection with face y return fDy <= rkSphere.Radius(); } else { // potential sphere-edge intersection with edge formed // by faces y and z Real fRSqr = rkSphere.Radius()*rkSphere.Radius(); return fDy*fDy + fDz*fDz <= fRSqr; } } } else { if ( fAy <= rkBox.Extent(1) ) { if ( fAz <= rkBox.Extent(2) ) { // potential sphere-face intersection with face x return fDx <= rkSphere.Radius(); } else { // potential sphere-edge intersection with edge formed // by faces x and z Real fRSqr = rkSphere.Radius()*rkSphere.Radius(); return fDx*fDx + fDz*fDz <= fRSqr; } } else { if ( fAz <= rkBox.Extent(2) ) { // potential sphere-edge intersection with edge formed // by faces x and y Real fRSqr = rkSphere.Radius()*rkSphere.Radius(); return fDx*fDx + fDy*fDy <= fRSqr; } else { // potential sphere-vertex intersection at corner formed // by faces x,y,z Real fRSqr = rkSphere.Radius()*rkSphere.Radius(); return fDx*fDx + fDy*fDy + fDz*fDz <= fRSqr; } } } }
Box3<Real> Wml::MergeBoxes (const Box3<Real>& rkBox0, const Box3<Real>& rkBox1) { // construct a box that contains the input boxes Box3<Real> kBox; // The first guess at the box center. This value will be updated later // after the input box vertices are projected onto axes determined by an // average of box axes. kBox.Center() = ((Real)0.5)*(rkBox0.Center() + rkBox1.Center()); // A box's axes, when viewed as the columns of a matrix, form a rotation // matrix. The input box axes are converted to quaternions. The average // quaternion is computed, then normalized to unit length. The result is // the slerp of the two input quaternions with t-value of 1/2. The result // is converted back to a rotation matrix and its columns are selected as // the merged box axes. Quaternion<Real> kQ0, kQ1; kQ0.FromRotationMatrix(rkBox0.Axes()); kQ1.FromRotationMatrix(rkBox1.Axes()); if ( kQ0.Dot(kQ1) < 0.0f ) kQ1 = -kQ1; Quaternion<Real> kQ = kQ0 + kQ1; Real fInvLength = Math<Real>::InvSqrt(kQ.Dot(kQ)); kQ = fInvLength*kQ; kQ.ToRotationMatrix(kBox.Axes()); // Project the input box vertices onto the merged-box axes. Each axis // D[i] containing the current center C has a minimum projected value // pmin[i] and a maximum projected value pmax[i]. The corresponding end // points on the axes are C+pmin[i]*D[i] and C+pmax[i]*D[i]. The point C // is not necessarily the midpoint for any of the intervals. The actual // box center will be adjusted from C to a point C' that is the midpoint // of each interval, // C' = C + sum_{i=0}^2 0.5*(pmin[i]+pmax[i])*D[i] // The box extents are // e[i] = 0.5*(pmax[i]-pmin[i]) int i, j; Real fDot; Vector3<Real> akVertex[8], kDiff; Vector3<Real> kMin = Vector3<Real>::ZERO; Vector3<Real> kMax = Vector3<Real>::ZERO; rkBox0.ComputeVertices(akVertex); for (i = 0; i < 8; i++) { kDiff = akVertex[i] - kBox.Center(); for (j = 0; j < 3; j++) { fDot = kDiff.Dot(kBox.Axis(j)); if ( fDot > kMax[j] ) kMax[j] = fDot; else if ( fDot < kMin[j] ) kMin[j] = fDot; } } rkBox1.ComputeVertices(akVertex); for (i = 0; i < 8; i++) { kDiff = akVertex[i] - kBox.Center(); for (j = 0; j < 3; j++) { fDot = kDiff.Dot(kBox.Axis(j)); if ( fDot > kMax[j] ) kMax[j] = fDot; else if ( fDot < kMin[j] ) kMin[j] = fDot; } } // [kMin,kMax] is the axis-aligned box in the coordinate system of the // merged box axes. Update the current box center to be the center of // the new box. Compute the extens based on the new center. for (j = 0; j < 3; j++) { kBox.Center() += (((Real)0.5)*(kMax[j]+kMin[j]))*kBox.Axis(j); kBox.Extent(j) = ((Real)0.5)*(kMax[j]-kMin[j]); } return kBox; }
void Wml::GetBoxConfiguration (const Vector3<Real>& rkAxis, const Box3<Real>& rkBox, ContactConfig<Real>& rkConfig) { // Description of coordinate ordering scheme for ContactConfig.m_aiIndex. // // Vertex number (up/down) vs. sign of extent (only matters in mapping // back) // 012 // 0 --- // 1 +-- // 2 -+- // 3 ++- // 4 --+ // 5 +-+ // 6 -++ // 7 +++ // // When it returns an ordering in the ContactConfig, it is also // guarenteed to be in-order (if 4 vertices, then they are guarunteed in // an order that will create a box, e.g. 0,1,3,2). // // assert: akAxis is an array containing unit length vectors Real afAxis[3] = { rkAxis.Dot(rkBox.Axis(0)), rkAxis.Dot(rkBox.Axis(1)), rkAxis.Dot(rkBox.Axis(2)) }; Real afAAxis[3] = { Math<Real>::FAbs(afAxis[0]), Math<Real>::FAbs(afAxis[1]), Math<Real>::FAbs(afAxis[2]) }; Real fMaxProjectedExtent; if ( afAAxis[0] < Math<Real>::EPSILON ) { if ( afAAxis[1] < Math<Real>::EPSILON ) { // face-face rkConfig.m_kMap = m44; fMaxProjectedExtent = afAAxis[2]*rkBox.Extent(2); // faces have normals along axis[2] if ( afAxis[2] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 0; rkConfig.m_aiIndex[1] = 1; rkConfig.m_aiIndex[2] = 3; rkConfig.m_aiIndex[3] = 2; rkConfig.m_aiIndex[4] = 6; rkConfig.m_aiIndex[5] = 7; rkConfig.m_aiIndex[6] = 5; rkConfig.m_aiIndex[7] = 4; } else { rkConfig.m_aiIndex[0] = 6; rkConfig.m_aiIndex[1] = 7; rkConfig.m_aiIndex[2] = 5; rkConfig.m_aiIndex[3] = 4; rkConfig.m_aiIndex[4] = 0; rkConfig.m_aiIndex[5] = 1; rkConfig.m_aiIndex[6] = 3; rkConfig.m_aiIndex[7] = 2; } } else if ( afAAxis[2] < Math<Real>::EPSILON ) { // face-face rkConfig.m_kMap = m44; fMaxProjectedExtent = afAAxis[1]*rkBox.Extent(1); // faces have normals along axis[1] if ( afAxis[1] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 4; rkConfig.m_aiIndex[1] = 5; rkConfig.m_aiIndex[2] = 1; rkConfig.m_aiIndex[3] = 0; rkConfig.m_aiIndex[4] = 2; rkConfig.m_aiIndex[5] = 3; rkConfig.m_aiIndex[6] = 7; rkConfig.m_aiIndex[7] = 6; } else { rkConfig.m_aiIndex[0] = 2; rkConfig.m_aiIndex[1] = 3; rkConfig.m_aiIndex[2] = 7; rkConfig.m_aiIndex[3] = 6; rkConfig.m_aiIndex[4] = 4; rkConfig.m_aiIndex[5] = 5; rkConfig.m_aiIndex[6] = 1; rkConfig.m_aiIndex[7] = 0; } } else // only afAxis[0] is equal to 0 { // seg-seg rkConfig.m_kMap = m2_2; fMaxProjectedExtent = afAAxis[1]*rkBox.Extent(1) + afAAxis[2]*rkBox.Extent(2); // axis 0 is perpendicular to rkAxis if ( afAxis[1] > (Real)0.0 ) { if ( afAxis[2] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 0; rkConfig.m_aiIndex[1] = 1; rkConfig.m_aiIndex[6] = 6; rkConfig.m_aiIndex[7] = 7; } else { rkConfig.m_aiIndex[0] = 4; rkConfig.m_aiIndex[1] = 5; rkConfig.m_aiIndex[6] = 2; rkConfig.m_aiIndex[7] = 3; } } else // afAxis[1] < 0 { if ( afAxis[2] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 2; rkConfig.m_aiIndex[1] = 3; rkConfig.m_aiIndex[6] = 4; rkConfig.m_aiIndex[7] = 5; } else { rkConfig.m_aiIndex[0] = 6; rkConfig.m_aiIndex[1] = 7; rkConfig.m_aiIndex[6] = 0; rkConfig.m_aiIndex[7] = 1; } } } } else if ( afAAxis[1] < Math<Real>::EPSILON ) { if ( afAAxis[2] < Math<Real>::EPSILON ) { // face-face rkConfig.m_kMap = m44; fMaxProjectedExtent = afAAxis[0]*rkBox.Extent(0); // faces have normals along axis[0] if ( afAxis[0] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 0; rkConfig.m_aiIndex[1] = 2; rkConfig.m_aiIndex[2] = 6; rkConfig.m_aiIndex[3] = 4; rkConfig.m_aiIndex[4] = 5; rkConfig.m_aiIndex[5] = 7; rkConfig.m_aiIndex[6] = 3; rkConfig.m_aiIndex[7] = 1; } else { rkConfig.m_aiIndex[4] = 0; rkConfig.m_aiIndex[5] = 2; rkConfig.m_aiIndex[6] = 6; rkConfig.m_aiIndex[7] = 4; rkConfig.m_aiIndex[0] = 5; rkConfig.m_aiIndex[1] = 7; rkConfig.m_aiIndex[2] = 3; rkConfig.m_aiIndex[3] = 1; } } else // only afAxis[1] is equal to 0 { // seg-seg rkConfig.m_kMap = m2_2; fMaxProjectedExtent = afAAxis[0]*rkBox.Extent(0) + afAAxis[2]*rkBox.Extent(2); // axis 1 is perpendicular to rkAxis if ( afAxis[0] > (Real)0.0 ) { if ( afAxis[2] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 0; rkConfig.m_aiIndex[1] = 2; rkConfig.m_aiIndex[6] = 5; rkConfig.m_aiIndex[7] = 7; } else { rkConfig.m_aiIndex[0] = 4; rkConfig.m_aiIndex[1] = 6; rkConfig.m_aiIndex[6] = 1; rkConfig.m_aiIndex[7] = 3; } } else // afAxis[0] < 0 { if ( afAxis[2] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 1; rkConfig.m_aiIndex[1] = 3; rkConfig.m_aiIndex[6] = 4; rkConfig.m_aiIndex[7] = 6; } else { rkConfig.m_aiIndex[0] = 5; rkConfig.m_aiIndex[1] = 7; rkConfig.m_aiIndex[6] = 0; rkConfig.m_aiIndex[7] = 2; } } } } else if ( afAAxis[2] < Math<Real>::EPSILON ) // only axis2 less than zero { // seg-seg rkConfig.m_kMap = m2_2; fMaxProjectedExtent = afAAxis[0]*rkBox.Extent(0) + afAAxis[1]*rkBox.Extent(1); // axis 2 is perpendicular to rkAxis if ( afAxis[0] > (Real)0.0 ) { if ( afAxis[1] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 0; rkConfig.m_aiIndex[1] = 4; rkConfig.m_aiIndex[6] = 3; rkConfig.m_aiIndex[7] = 7; } else { rkConfig.m_aiIndex[0] = 2; rkConfig.m_aiIndex[1] = 6; rkConfig.m_aiIndex[6] = 1; rkConfig.m_aiIndex[7] = 5; } } else // afAxis[0] < 0 { if ( afAxis[1] > (Real)0.0 ) { rkConfig.m_aiIndex[0] = 1; rkConfig.m_aiIndex[1] = 5; rkConfig.m_aiIndex[6] = 2; rkConfig.m_aiIndex[7] = 6; } else { rkConfig.m_aiIndex[0] = 3; rkConfig.m_aiIndex[1] = 7; rkConfig.m_aiIndex[6] = 0; rkConfig.m_aiIndex[7] = 4; } } } else // no axis is equal to zero { // point-point (unique maximal and minimal vertex) rkConfig.m_kMap = m1_1; fMaxProjectedExtent = afAAxis[0]*rkBox.Extent(0) + afAAxis[1]*rkBox.Extent(1) + afAAxis[2]*rkBox.Extent(2); // only these two vertices matter, the rest are irrelevant rkConfig.m_aiIndex[0] = ( afAxis[0] > (Real)0.0 ? 0 : 1 ) + ( afAxis[1] > (Real)0.0 ? 0 : 2 ) + ( afAxis[2] > (Real)0.0 ? 0 : 4 ); // by ordering the vertices this way, opposite corners add up to 7 rkConfig.m_aiIndex[7] = 7 - rkConfig.m_aiIndex[0]; } // Find projections onto line Real fOrigin = rkAxis.Dot(rkBox.Center()); rkConfig.m_fMin = fOrigin - fMaxProjectedExtent; rkConfig.m_fMax = fOrigin + fMaxProjectedExtent; }
//---------------------------------------------------------------------------- static void Case00 (int i0, int i1, int i2, Vector3& rkPnt, const Vector3& rkDir, const Box3& rkBox, Real* pfLParam, Real& rfSqrDistance) { Real fDelta; if ( pfLParam ) *pfLParam = (rkBox.Extent(i0) - rkPnt[i0])/rkDir[i0]; rkPnt[i0] = rkBox.Extent(i0); if ( rkPnt[i1] < -rkBox.Extent(i1) ) { fDelta = rkPnt[i1] + rkBox.Extent(i1); rfSqrDistance += fDelta*fDelta; rkPnt[i1] = -rkBox.Extent(i1); } else if ( rkPnt[i1] > rkBox.Extent(i1) ) { fDelta = rkPnt[i1] - rkBox.Extent(i1); rfSqrDistance += fDelta*fDelta; rkPnt[i1] = rkBox.Extent(i1); } if ( rkPnt[i2] < -rkBox.Extent(i2) ) { fDelta = rkPnt[i2] + rkBox.Extent(i2); rfSqrDistance += fDelta*fDelta; rkPnt[i1] = -rkBox.Extent(i2); } else if ( rkPnt[i2] > rkBox.Extent(i2) ) { fDelta = rkPnt[i2] - rkBox.Extent(i2); rfSqrDistance += fDelta*fDelta; rkPnt[i2] = rkBox.Extent(i2); } }
//---------------------------------------------------------------------------- static void Case0 (int i0, int i1, int i2, Vector3& rkPnt, const Vector3& rkDir, const Box3& rkBox, Real* pfLParam, Real& rfSqrDistance) { Real fPmE0 = rkPnt[i0] - rkBox.Extent(i0); Real fPmE1 = rkPnt[i1] - rkBox.Extent(i1); Real fProd0 = rkDir[i1]*fPmE0; Real fProd1 = rkDir[i0]*fPmE1; Real fDelta, fInvLSqr, fInv; if ( fProd0 >= fProd1 ) { // line intersects P[i0] = e[i0] rkPnt[i0] = rkBox.Extent(i0); Real fPpE1 = rkPnt[i1] + rkBox.Extent(i1); fDelta = fProd0 - rkDir[i0]*fPpE1; if ( fDelta >= 0.0f ) { fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]); rfSqrDistance += fDelta*fDelta*fInvLSqr; if ( pfLParam ) { rkPnt[i1] = -rkBox.Extent(i1); *pfLParam = -(rkDir[i0]*fPmE0+rkDir[i1]*fPpE1)*fInvLSqr; } } else { if ( pfLParam ) { fInv = 1.0f/rkDir[i0]; rkPnt[i1] -= fProd0*fInv; *pfLParam = -fPmE0*fInv; } } } else { // line intersects P[i1] = e[i1] rkPnt[i1] = rkBox.Extent(i1); Real fPpE0 = rkPnt[i0] + rkBox.Extent(i0); fDelta = fProd1 - rkDir[i1]*fPpE0; if ( fDelta >= 0.0f ) { fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]); rfSqrDistance += fDelta*fDelta*fInvLSqr; if ( pfLParam ) { rkPnt[i0] = -rkBox.Extent(i0); *pfLParam = -(rkDir[i0]*fPpE0+rkDir[i1]*fPmE1)*fInvLSqr; } } else { if ( pfLParam ) { fInv = 1.0f/rkDir[i1]; rkPnt[i0] -= fProd1*fInv; *pfLParam = -fPmE1*fInv; } } } if ( rkPnt[i2] < -rkBox.Extent(i2) ) { fDelta = rkPnt[i2] + rkBox.Extent(i2); rfSqrDistance += fDelta*fDelta; rkPnt[i2] = -rkBox.Extent(i2); } else if ( rkPnt[i2] > rkBox.Extent(i2) ) { fDelta = rkPnt[i2] - rkBox.Extent(i2); rfSqrDistance += fDelta*fDelta; rkPnt[i2] = rkBox.Extent(i2); } }
//---------------------------------------------------------------------------- static void Face (int i0, int i1, int i2, Vector3& rkPnt, const Vector3& rkDir, const Box3& rkBox, const Vector3& rkPmE, Real* pfLParam, Real& rfSqrDistance) { Vector3 kPpE; Real fLSqr, fInv, fTmp, fParam, fT, fDelta; kPpE[i1] = rkPnt[i1] + rkBox.Extent(i1); kPpE[i2] = rkPnt[i2] + rkBox.Extent(i2); if ( rkDir[i0]*kPpE[i1] >= rkDir[i1]*rkPmE[i0] ) { if ( rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0] ) { // v[i1] >= -e[i1], v[i2] >= -e[i2] (distance = 0) if ( pfLParam ) { rkPnt[i0] = rkBox.Extent(i0); fInv = 1.0f/rkDir[i0]; rkPnt[i1] -= rkDir[i1]*rkPmE[i0]*fInv; rkPnt[i2] -= rkDir[i2]*rkPmE[i0]*fInv; *pfLParam = -rkPmE[i0]*fInv; } } else { // v[i1] >= -e[i1], v[i2] < -e[i2] fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i2]*rkDir[i2]; fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]); if ( fTmp <= 2.0f*fLSqr*rkBox.Extent(i1) ) { fT = fTmp/fLSqr; fLSqr += rkDir[i1]*rkDir[i1]; fTmp = kPpE[i1] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = fT - rkBox.Extent(i1); rkPnt[i2] = -rkBox.Extent(i2); } } else { fLSqr += rkDir[i1]*rkDir[i1]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = rkBox.Extent(i1); rkPnt[i2] = -rkBox.Extent(i2); } } } } else { if ( rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0] ) { // v[i1] < -e[i1], v[i2] >= -e[i2] fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]; fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]); if ( fTmp <= 2.0f*fLSqr*rkBox.Extent(i2) ) { fT = fTmp/fLSqr; fLSqr += rkDir[i2]*rkDir[i2]; fTmp = kPpE[i2] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = -rkBox.Extent(i1); rkPnt[i2] = fT - rkBox.Extent(i2); } } else { fLSqr += rkDir[i2]*rkDir[i2]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = -rkBox.Extent(i1); rkPnt[i2] = rkBox.Extent(i2); } } } else { // v[i1] < -e[i1], v[i2] < -e[i2] fLSqr = rkDir[i0]*rkDir[i0]+rkDir[i2]*rkDir[i2]; fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]); if ( fTmp >= 0.0f ) { // v[i1]-edge is closest if ( fTmp <= 2.0f*fLSqr*rkBox.Extent(i1) ) { fT = fTmp/fLSqr; fLSqr += rkDir[i1]*rkDir[i1]; fTmp = kPpE[i1] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = fT - rkBox.Extent(i1); rkPnt[i2] = -rkBox.Extent(i2); } } else { fLSqr += rkDir[i1]*rkDir[i1]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = rkBox.Extent(i1); rkPnt[i2] = -rkBox.Extent(i2); } } return; } fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]; fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]); if ( fTmp >= 0.0f ) { // v[i2]-edge is closest if ( fTmp <= 2.0f*fLSqr*rkBox.Extent(i2) ) { fT = fTmp/fLSqr; fLSqr += rkDir[i2]*rkDir[i2]; fTmp = kPpE[i2] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = -rkBox.Extent(i1); rkPnt[i2] = fT - rkBox.Extent(i2); } } else { fLSqr += rkDir[i2]*rkDir[i2]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = -rkBox.Extent(i1); rkPnt[i2] = rkBox.Extent(i2); } } return; } // (v[i1],v[i2])-corner is closest fLSqr += rkDir[i2]*rkDir[i2]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; if ( pfLParam ) { *pfLParam = fParam; rkPnt[i0] = rkBox.Extent(i0); rkPnt[i1] = -rkBox.Extent(i1); rkPnt[i2] = -rkBox.Extent(i2); } } } }
bool Wml::FindIntersection (const Box3<Real>& rkBox, const Vector3<Real>& rkBoxVelocity, const Sphere3<Real>& rkSphere, const Vector3<Real>& rkSphVelocity, Real& rfTFirst, Real fTMax, int& riQuantity, Vector3<Real>& rkP) { // Find intersections relative to the coordinate system of the box. // The sphere is transformed to the box coordinates and the velocity of // the sphere is relative to the box. Vector3<Real> kCDiff = rkSphere.Center() - rkBox.Center(); Vector3<Real> kVel = rkSphVelocity - rkBoxVelocity; Real fAx = kCDiff.Dot(rkBox.Axis(0)); Real fAy = kCDiff.Dot(rkBox.Axis(1)); Real fAz = kCDiff.Dot(rkBox.Axis(2)); Real fVx = kVel.Dot(rkBox.Axis(0)); Real fVy = kVel.Dot(rkBox.Axis(1)); Real fVz = kVel.Dot(rkBox.Axis(2)); // flip coordinate frame into the first octant int iSignX = 1; if ( fAx < (Real)0.0 ) { fAx = -fAx; fVx = -fVx; iSignX = -1; } int iSignY = 1; if ( fAy < (Real)0.0 ) { fAy = -fAy; fVy = -fVy; iSignY = -1; } int iSignZ = 1; if ( fAz < (Real)0.0 ) { fAz = -fAz; fVz = -fVz; iSignZ = -1; } // intersection coordinates Real fIx, fIy, fIz; int iRetVal; if ( fAx <= rkBox.Extent(0) ) { if ( fAy <= rkBox.Extent(1) ) { if ( fAz <= rkBox.Extent(2) ) { // sphere center inside box rfTFirst = (Real)0.0; riQuantity = 0; return false; } else { // sphere above face on axis Z iRetVal = FindFaceRegionIntersection(rkBox.Extent(0), rkBox.Extent(1),rkBox.Extent(2),fAx,fAy,fAz,fVx,fVy,fVz, rfTFirst,rkSphere.Radius(),fIx,fIy,fIz,true); } } else { if ( fAz <= rkBox.Extent(2) ) { // sphere above face on axis Y iRetVal = FindFaceRegionIntersection(rkBox.Extent(0), rkBox.Extent(2),rkBox.Extent(1),fAx,fAz,fAy,fVx,fVz,fVy, rfTFirst,rkSphere.Radius(),fIx,fIz,fIy,true); } else { // sphere is above the edge formed by faces y and z iRetVal = FindEdgeRegionIntersection(rkBox.Extent(1), rkBox.Extent(0),rkBox.Extent(2),fAy,fAx,fAz,fVy,fVx,fVz, rfTFirst,rkSphere.Radius(),fIy,fIx,fIz,true); } } } else { if ( fAy <= rkBox.Extent(1) ) { if ( fAz <= rkBox.Extent(2) ) { // sphere above face on axis X iRetVal = FindFaceRegionIntersection(rkBox.Extent(1), rkBox.Extent(2),rkBox.Extent(0),fAy,fAz,fAx,fVy,fVz,fVx, rfTFirst,rkSphere.Radius(),fIy,fIz,fIx,true); } else { // sphere is above the edge formed by faces x and z iRetVal = FindEdgeRegionIntersection(rkBox.Extent(0), rkBox.Extent(1),rkBox.Extent(2),fAx,fAy,fAz,fVx,fVy,fVz, rfTFirst,rkSphere.Radius(),fIx,fIy,fIz,true); } } else { if ( fAz <= rkBox.Extent(2) ) { // sphere is above the edge formed by faces x and y iRetVal = FindEdgeRegionIntersection(rkBox.Extent(0), rkBox.Extent(2),rkBox.Extent(1),fAx,fAz,fAy,fVx,fVz,fVy, rfTFirst,rkSphere.Radius(),fIx,fIz,fIy,true); } else { // sphere is above the corner formed by faces x,y,z iRetVal = FindVertexRegionIntersection(rkBox.Extent(0), rkBox.Extent(1),rkBox.Extent(2),fAx,fAy,fAz,fVx,fVy,fVz, rfTFirst,rkSphere.Radius(),fIx,fIy,fIz); } } } if ( iRetVal != 1 || rfTFirst > fTMax ) { riQuantity = 0; return false; } // calculate actual intersection (move point back into world coordinates) riQuantity = 1; rkP = rkBox.Center() + (iSignX*fIx)*rkBox.Axis(0) + (iSignY*fIy)*rkBox.Axis(1) + (iSignZ*fIz)*rkBox.Axis(2); return true; }