bool Wml::TestIntersection (const Sphere3<Real>& rkS0, const Sphere3<Real>& rkS1, Real fTime, const Vector3<Real>& rkV0, const Vector3<Real>& rkV1) { Vector3<Real> kVDiff = rkV1 - rkV0; Real fA = kVDiff.SquaredLength(); Vector3<Real> kCDiff = rkS1.Center() - rkS0.Center(); Real fC = kCDiff.SquaredLength(); Real fRSum = rkS0.Radius() + rkS1.Radius(); Real fRSumSqr = fRSum*fRSum; if ( fA > (Real)0.0 ) { Real fB = kCDiff.Dot(kVDiff); if ( fB <= (Real)0.0 ) { if ( -fTime*fA <= fB ) return fA*fC - fB*fB <= fA*fRSumSqr; else return fTime*(fTime*fA + ((Real)2.0)*fB) + fC <= fRSumSqr; } } return fC <= fRSumSqr; }
bool Wml::TestIntersection (const Triangle3<Real>& rkTri, const Sphere3<Real>& rkSphere) { Real fSqrDist = SqrDistance(rkSphere.Center(),rkTri); Real fRSqr = rkSphere.Radius()*rkSphere.Radius(); return fSqrDist < fRSqr; }
bool Wml::TestIntersection (const Sphere3<Real>& rkS0, const Sphere3<Real>& rkS1) { Vector3<Real> kDiff = rkS1.Center() - rkS0.Center(); Real fSqrLen = kDiff.SquaredLength(); Real fRSum = rkS0.Radius() + rkS1.Radius(); Real fRSumSqr = fRSum*fRSum; return fSqrLen <= fRSumSqr; }
bool Wml::FindIntersection (const Sphere3<Real>& rkS0, const Sphere3<Real>& rkS1, Vector3<Real>& rkU, Vector3<Real>& rkV, Vector3<Real>& rkC, Real& rfR) { // plane of intersection must have N as its normal Vector3<Real> kN = rkS1.Center() - rkS0.Center(); Real fNSqrLen = kN.SquaredLength(); Real fRSum = rkS0.Radius() + rkS1.Radius(); if ( fNSqrLen > fRSum*fRSum ) { // sphere centers are too far apart for intersection return false; } Real fR0Sqr = rkS0.Radius()*rkS0.Radius(); Real fR1Sqr = rkS1.Radius()*rkS1.Radius(); Real fInvNSqrLen = ((Real)1.0)/fNSqrLen; Real fT = ((Real)0.5)*((Real)1.0+(fR0Sqr-fR1Sqr)*fInvNSqrLen); if ( fT < (Real)0.0 || fT > (Real)1.0 ) return false; Real fRSqr = fR0Sqr - fT*fT*fNSqrLen; if ( fRSqr < (Real)0.0 ) return false; // center and radius of circle of intersection rkC = rkS0.Center() + fT*kN; rfR = Math<Real>::Sqrt(fRSqr); // compute U and V for plane of circle kN *= Math<Real>::Sqrt(fInvNSqrLen); Vector3<Real>::GenerateOrthonormalBasis(rkU,rkV,kN,true); return true; }
static bool FindSphereVertexIntersection (const Vector3<Real>& rkVertex, const Sphere3<Real>& rkSphere, const Vector3<Real>& rkSphVelocity, const Vector3<Real>& rkTriVelocity, Real& rfTFirst, Real fTMax, int& riQuantity, Vector3<Real> akP[6]) { // Finds the time and place (and possible occurance, it may miss) of an // intersection between a sphere of fRadius at rkOrigin moving in rkDir // towards a vertex at rkVertex. Vector3<Real> kVel = rkSphVelocity - rkTriVelocity; Vector3<Real> kD = rkSphere.Center() - rkVertex; Vector3<Real> kCross = kD.Cross(kVel); Real fRSqr = rkSphere.Radius()*rkSphere.Radius(); Real fVSqr = kVel.SquaredLength(); if ( kCross.SquaredLength() > fRSqr*fVSqr ) { // ray overshoots the sphere return false; } // find time of intersection Real fDot = kD.Dot(kVel); Real fDiff = kD.SquaredLength() - fRSqr; Real fInv = Math<Real>::InvSqrt(Math<Real>::FAbs(fDot*fDot-fVSqr*fDiff)); rfTFirst = fDiff*fInv/((Real)1.0-fDot*fInv); if ( rfTFirst > fTMax ) { // intersection after max time return false; } // place of intersection is triangle vertex riQuantity = 1; akP[0] = rkVertex + rfTFirst*rkTriVelocity; return true; }
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; }
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; } } } }
static bool FindTriSphrCoplanarIntersection (int iVertex, const Vector3<Real> akV[3], const Vector3<Real>& /* rkNormal */, const Vector3<Real>& rkSideNorm, const Vector3<Real>& rkSide, const Sphere3<Real>& rkSphere, const Vector3<Real>& rkTriVelocity, const Vector3<Real>& rkSphVelocity, Real& rfTFirst, Real fTMax, int& riQuantity, Vector3<Real> akP[6]) { // TO DO. The parameter rkNormal is not used here. Is this an error? // Or does the caller make some adjustments to the other inputs to // account for the normal? // iVertex is the "hinge" vertex that the two potential edges that can // be intersected by the sphere connect to, and it indexes into akV. // rkSideNorm is the normal of the plane formed by (iVertex,iVertex+1) // and the tri norm, passed so as not to recalculate // check for intersections at time 0 Vector3<Real> kDist = akV[iVertex] - rkSphere.Center(); if ( kDist.SquaredLength() < rkSphere.Radius()*rkSphere.Radius() ) { // already intersecting that vertex rfTFirst = (Real)0.0; return false; } // Tri stationary, sphere moving Vector3<Real> kVel = rkSphVelocity - rkTriVelocity; // check for easy out if ( kVel.Dot(kDist) <= (Real)0.0 ) { // moving away return false; } // find intersection of velocity ray and side normal // project ray and plane onto the plane normal Real fPlane = rkSideNorm.Dot(akV[iVertex]); Real fCenter = rkSideNorm.Dot(rkSphere.Center()); Real fVel = rkSideNorm.Dot(kVel); Real fFactor = (fPlane - fCenter)/fVel; Vector3<Real> kPoint = rkSphere.Center() + fFactor*kVel; // now, find which side of the hinge vertex this lies by projecting // both the vertex and this new point onto the triangle edge (the same // edge whose "normal" was used to find this point) Real fVertex = rkSide.Dot(akV[iVertex]); Real fPoint = rkSide.Dot(kPoint); Segment3<Real> kSeg; if ( fPoint >= fVertex ) { // intersection with edge (iVertex,iVertex+1) kSeg.Origin() = akV[iVertex]; kSeg.Direction() = akV[(iVertex+1)%3] - akV[iVertex]; } else { // intersection with edge (iVertex-1,iVertex) if ( iVertex != 0 ) kSeg.Origin() = akV[iVertex-1]; else kSeg.Origin() = akV[2]; kSeg.Direction() = akV[iVertex] - kSeg.Origin(); } // This could be either an sphere-edge or a sphere-vertex intersection // (this test isn't enough to differentiate), so use the full-on // line-sphere test. return FindIntersection(kSeg,rkTriVelocity,rkSphere,rkSphVelocity, rfTFirst,fTMax,riQuantity,akP); }
bool Wml::FindIntersection (const Triangle3<Real>& rkTri, const Vector3<Real>& rkTriVelocity, const Sphere3<Real>& rkSphere, const Vector3<Real>& rkSphVelocity, Real& rfTFirst, Real fTMax, int& riQuantity, Vector3<Real> akP[6]) { // triangle vertices Vector3<Real> akV[3] = { rkTri.Origin(), rkTri.Origin() + rkTri.Edge0(), rkTri.Origin() + rkTri.Edge1() }; // triangle edges Vector3<Real> akE[3] = { akV[1] - akV[0], akV[2] - akV[1], akV[0] - akV[2] }; // triangle normal Vector3<Real> kN = akE[1].Cross(akE[0]); // sphere center projection on triangle normal Real fNdC = kN.Dot(rkSphere.Center()); // Radius projected length in normal direction. This defers the square // root to normalize kN until absolutely needed. Real fNormRadiusSqr = kN.SquaredLength()*rkSphere.Radius()*rkSphere.Radius(); // triangle projection on triangle normal Real fNdT = kN.Dot(akV[0]); // Distance from sphere to triangle along the normal Real fDist = fNdC - fNdT; // normals for the plane formed by edge i and the triangle normal Vector3<Real> akExN[3] = { akE[0].Cross(kN), akE[1].Cross(kN), akE[2].Cross(kN) }; Segment3<Real> kSeg; if ( fDist*fDist <= fNormRadiusSqr ) { // sphere currently intersects the plane of the triangle // see which edges the sphere center is inside/outside of bool bInside[3]; for (int i = 0; i < 3; i++ ) { bInside[i] = ( akExN[i].Dot(rkSphere.Center()) >= akExN[i].Dot(akV[i]) ); } if ( bInside[0] ) { if ( bInside[1] ) { if ( bInside[2] ) { // triangle inside sphere return false; } else // !bInside[2] { // potential intersection with edge 2 kSeg.Origin() = akV[2]; kSeg.Direction() = akE[2]; return FindIntersection(kSeg,rkTriVelocity,rkSphere, rkSphVelocity,rfTFirst,fTMax,riQuantity,akP); } } else // !bInside[1] { if ( bInside[2] ) { // potential intersection with edge 1 kSeg.Origin() = akV[1]; kSeg.Direction() = akE[1]; return FindIntersection(kSeg,rkTriVelocity,rkSphere, rkSphVelocity,rfTFirst,fTMax,riQuantity,akP); } else // !bInside[2] { // potential intersection with edges 1,2 return FindTriSphrCoplanarIntersection(2,akV,kN,akExN[2], akE[2],rkSphere,rkTriVelocity,rkSphVelocity,rfTFirst, fTMax,riQuantity,akP); } } } else // !bInside[0] { if ( bInside[1] ) { if ( bInside[2] ) { // potential intersection with edge 0 kSeg.Origin() = akV[0]; kSeg.Direction() = akE[0]; return FindIntersection(kSeg,rkTriVelocity,rkSphere, rkSphVelocity,rfTFirst,fTMax,riQuantity,akP); } else // !bInside[2] { // potential intersection with edges 2,0 return FindTriSphrCoplanarIntersection(0,akV,kN,akExN[0], akE[0],rkSphere,rkTriVelocity,rkSphVelocity,rfTFirst, fTMax,riQuantity,akP); } } else // !bInside[1] { if ( bInside[2] ) { // potential intersection with edges 0,1 return FindTriSphrCoplanarIntersection(1,akV,kN,akExN[1], akE[1],rkSphere,rkTriVelocity,rkSphVelocity,rfTFirst, fTMax,riQuantity,akP); } else // !bInside[2] { // we should not get here assert( false ); return false; } } } } else { // sphere does not currently intersect the plane of the triangle // sphere moving, triangle stationary Vector3<Real> kVel = rkSphVelocity - rkTriVelocity; // Find point of intersection of the sphere and the triangle // plane. Where this point occurs on the plane relative to the // triangle determines the potential kind of intersection. kN.Normalize(); // Point on sphere we care about intersecting the triangle plane Vector3<Real> kSpherePoint; // Which side of the triangle is the sphere on? if ( fNdC > fNdT ) { // positive side if ( kVel.Dot(kN) >= (Real)0.0 ) { // moving away, easy out return false; } kSpherePoint = rkSphere.Center() - rkSphere.Radius()*kN; } else { // negative side if ( kVel.Dot(kN) <= (Real)0.0 ) { // moving away, easy out return false; } kSpherePoint = rkSphere.Center() + rkSphere.Radius()*kN; } // find intersection of velocity ray and triangle plane // project ray and plane onto the plane normal Real fPlane = kN.Dot(akV[0]); Real fPoint = kN.Dot(kSpherePoint); Real fVel = kN.Dot(kVel); Real fTime = (fPlane - fPoint)/fVel; // where this intersects Vector3<Real> kIntrPoint = kSpherePoint + fTime*kVel; // see which edges this intersection point is inside/outside of bool bInside[3]; for (int i = 0; i < 3; i++ ) bInside[i] = (akExN[i].Dot(kIntrPoint) >= akExN[i].Dot(akV[i])); if ( bInside[0] ) { if ( bInside[1] ) { if ( bInside[2] ) { // intersects face at time fTime if ( fTime > fTMax ) { // intersection after tMax return false; } else { rfTFirst = fTime; riQuantity = 1; // kIntrPoint is the point in space, assuming that // TriVel is 0. Re-adjust the point to where it // should be, were it not. akP[0] = kIntrPoint + fTime*rkTriVelocity; return true; } } else // !bInside[2] { // potential intersection with edge 2 kSeg.Origin() = akV[2]; kSeg.Direction() = akE[2]; return FindIntersection(kSeg,rkTriVelocity,rkSphere, rkSphVelocity,rfTFirst,fTMax,riQuantity,akP); } } else // !bInside[1] { if ( bInside[2] ) { // potential intersection with edge 1 kSeg.Origin() = akV[1]; kSeg.Direction() = akE[1]; return FindIntersection(kSeg,rkTriVelocity,rkSphere, rkSphVelocity,rfTFirst,fTMax,riQuantity,akP); } else // !bInside[2] { // potential intersection with vertex 2 return FindSphereVertexIntersection(akV[2],rkSphere, rkSphVelocity,rkTriVelocity,rfTFirst,fTMax, riQuantity,akP); } } } else // !bInside[0] { if ( bInside[1] ) { if ( bInside[2] ) { // potential intersection with edge 0 kSeg.Origin() = akV[0]; kSeg.Direction() = akE[0]; return FindIntersection(kSeg,rkTriVelocity,rkSphere, rkSphVelocity,rfTFirst,fTMax,riQuantity,akP); } else // !bInside[2] { // potential intersection with vertex 0 return FindSphereVertexIntersection(akV[0],rkSphere, rkSphVelocity,rkTriVelocity,rfTFirst,fTMax, riQuantity,akP); } } else // !bInside[1] { if ( bInside[2] ) { // potential intersection with vertex 1 return FindSphereVertexIntersection(akV[1],rkSphere, rkSphVelocity,rkTriVelocity,rfTFirst,fTMax, riQuantity,akP); } else // !bInside[2] { // we should not get here assert( false ); return false; } } } } }
bool Wml::FindIntersection (const Sphere3<Real>& rkS0, const Sphere3<Real>& rkS1, Real fTime, const Vector3<Real>& rkV0, const Vector3<Real>& rkV1, Real& rfFirstTime, Vector3<Real>& rkFirstPoint) { Vector3<Real> kVDiff = rkV1 - rkV0; Real fA = kVDiff.SquaredLength(); Vector3<Real> kCDiff = rkS1.Center() - rkS0.Center(); Real fC = kCDiff.SquaredLength(); Real fRSum = rkS0.Radius() + rkS1.Radius(); Real fRSumSqr = fRSum*fRSum; if ( fA > (Real)0.0 ) { Real fB = kCDiff.Dot(kVDiff); if ( fB <= (Real)0.0 ) { if ( -fTime*fA <= fB || fTime*(fTime*fA + ((Real)2.0)*fB) + fC <= fRSumSqr ) { Real fCDiff = fC - fRSumSqr; Real fDiscr = fB*fB - fA*fCDiff; if ( fDiscr >= (Real)0.0 ) { if ( fCDiff <= (Real)0.0 ) { // The spheres are initially intersecting. Estimate a // point of contact by using the midpoint of the line // segment connecting the sphere centers. rfFirstTime = (Real)0.0; rkFirstPoint = ((Real)0.5)*(rkS0.Center() + rkS1.Center()); } else { // The first time of contact is in [0,fTime]. rfFirstTime = -(fB + Math<Real>::Sqrt(fDiscr))/fA; if ( rfFirstTime < (Real)0.0 ) rfFirstTime = (Real)0.0; else if ( rfFirstTime > fTime ) rfFirstTime = fTime; Vector3<Real> kNewCDiff = kCDiff + rfFirstTime*kVDiff; rkFirstPoint = rkS0.Center() + rfFirstTime*rkV0 + (rkS0.Radius()/fRSum)*kNewCDiff; } return true; } } return false; } } if ( fC <= fRSumSqr ) { // The spheres are initially intersecting. Estimate a point of // contact by using the midpoint of the line segment connecting the // sphere centers. rfFirstTime = (Real)0.0; rkFirstPoint = ((Real)0.5)*(rkS0.Center() + rkS1.Center()); return true; } return false; }