bool Intersects(const Ray2 &ray, const Circle &circle, float *distance) { const Vector2 &rayDir = ray.GetDirection(); // Adjust ray origin relative to circle center const Vector2 &rayOrig = ray.GetOrigin() - circle.GetCentre(); float radius = circle.GetRadius(); // Check origin inside first if (rayOrig.MagnitudeSquared() <= radius * radius) { SetPtrValue(distance, 0.0f); return true; } // Mmm, quadratics // Build coeffs which can be used with std quadratic solver // ie t = (-b +/- sqrt(b * b + 4ac)) / 2a float a = Vector2::DotProduct(rayDir, rayDir); float b = 2 * Vector2::DotProduct(rayOrig, rayDir); float c = Vector2::DotProduct(rayOrig, rayOrig) - radius * radius; // Calc determinant float d = (b * b) - (4 * a * c); if (d < 0) { // No intersection SetPtrValue(distance, 0.0f); return false; } else { // BTW, if d=0 there is one intersection, if d > 0 there are 2 // But we only want the closest one, so that's ok, just use the // '-' version of the solver float negB(-b); float sqrtD(Sqrt(d)); float twoA(2 * a); float t = (negB - sqrtD) / twoA; if (t < 0) { t = (negB + sqrtD) / twoA; } if (t > 0) { SetPtrValue(distance, t); return true; } return false; } }
bool Intersects(const LineSegment2 &lineSegment, bool singleSided, const Ray2 &ray, float *distance) { if (singleSided && Vector2::DotProduct(ray.GetDirection(), lineSegment.GetNormal()) >= 0.0f) { // Ray is pointing in the same direction as the line normal return false; } const Vector2 &P0 = ray.GetOrigin(); const Vector2 &D0 = ray.GetDirection(); const Vector2 &P1 = lineSegment.GetTail(); const Vector2 &D1 = lineSegment.GetVector(); Vector2 perpD0 = Perp(D0); Vector2 perpD1 = Perp(D1); if (Dot(perpD1, D0) != 0.0f) { Vector2 P1MinusP0 = P1 - P0; float s = Dot(perpD1, P1MinusP0) / Dot(perpD1,D0); float t = Dot(perpD0, P1MinusP0) / Dot(perpD1,D0); bool intersects = s >= 0.0f && 0.0f <= t && t <= 1.0f; if (intersects) { if (distance) { // We've probably already calculated the nearest point in terms of s & t but // I can't figure it out. *distance = s; // ((lineSegment.GetTail() + lineSegment.GetDirection() * t) - ray.GetOrigin()).Magnitude(); // *distance = (nearestPoint - ray.GetOrigin()).Magnitude(); } return true; } } return false; }
//---------------------------------------------------------------------------- bool Mgc::FindIntersection (const Ray2& rkRay0, const Ray2& rkRay1, int& riQuantity, Real afT[2]) { Vector2 kDiff; Real fD0SqrLen; bool bIntersects = Find(rkRay0.Origin(),rkRay0.Direction(), rkRay1.Origin(),rkRay1.Direction(),kDiff,fD0SqrLen,riQuantity,afT); if ( bIntersects ) { if ( riQuantity == 1 ) { if ( afT[0] < 0.0f || afT[1] < 0.0f ) { // lines intersect, but rays do not riQuantity = 0; } } else { // rays are on same line Real fDot = kDiff.Dot(rkRay0.Direction()); if ( rkRay0.Direction().Dot(rkRay1.Direction()) > 0.0f ) { // Rays point in same direction, get semiinfinite interval // of intersection. afT[0] = ( fDot >= 0.0f ? fDot/fD0SqrLen : 0.0f ); afT[1] = Math::MAX_REAL; } else { // test for overlap of opposite pointing rays if ( fDot > 0.0f ) { afT[0] = 0.0f; afT[1] = fDot/fD0SqrLen; } else if ( fDot < 0.0f ) { // no overlap riQuantity = 0; } else { // rays have a common origin riQuantity = 1; afT[0] = 0.0f; } } } } return riQuantity != 0; }
//---------------------------------------------------------------------------- bool Mgc::FindIntersection (const Line2& rkLine, const Ray2& rkRay, int& riQuantity, Real afT[2]) { Vector2 kDiff; Real fD0SqrLen; bool bIntersects = Find(rkLine.Origin(),rkLine.Direction(), rkRay.Origin(),rkRay.Direction(),kDiff,fD0SqrLen,riQuantity,afT); if ( bIntersects ) { if ( riQuantity == 1 ) { if ( afT[1] < 0.0f ) { // lines intersect, but ray does not intersect line riQuantity = 0; } } else { // ray is contained by line, adjust intersection interval if ( rkLine.Direction().Dot(rkRay.Direction()) > 0.0f ) { afT[0] = (kDiff.Dot(rkLine.Direction()))/fD0SqrLen; afT[1] = Math::MAX_REAL; } else { afT[0] = -Math::MAX_REAL; afT[1] = (kDiff.Dot(rkLine.Direction()))/fD0SqrLen; } } } return riQuantity != 0; }
//============================================================================= bool Ray2::intersectParam( const Ray2& ray1, const Ray2& ray2, double& parameter, bool onlyExistence) { double determinant = ray1.getDir().x()*ray2.getDir().y() - ray1.getDir().y()*ray2.getDir().x(); bool exists = true; if ( ( determinant > -10e-12 ) && ( determinant < 10e-12 ) ) exists = false; if (exists == false) return false; if (onlyExistence) return exists; Vector2F delta( ray2.origin_, ray1.origin_); parameter = ( delta.y()*ray2.getDir().x() - delta.x()*ray2.getDir().y() ) / determinant; return true; }
//---------------------------------------------------------------------------- bool Mgc::FindIntersection (const Ray2& rkRay, const Segment2& rkSegment, int& riQuantity, Real afT[2]) { Vector2 kDiff; Real fD0SqrLen; bool bIntersects = Find(rkRay.Origin(),rkRay.Direction(), rkSegment.Origin(),rkSegment.Direction(),kDiff,fD0SqrLen,riQuantity, afT); if ( bIntersects ) { if ( riQuantity == 1 ) { if ( afT[0] < 0.0f || afT[1] < 0.0f || afT[1] > 1.0f ) { // lines intersect, but ray and segment do not riQuantity = 0; } } else { // ray and segment are on the same line Real fDotRS = rkRay.Direction().Dot(rkSegment.Direction()); Real fDot0, fDot1; if ( fDotRS > 0.0f ) { fDot0 = kDiff.Dot(rkRay.Direction()); fDot1 = fDot0 + fDotRS; } else { fDot1 = kDiff.Dot(rkRay.Direction()); fDot0 = fDot1 + fDotRS; } // compute intersection of [t0,t1] and [0,+infinity] if ( fDot0 >= 0.0f ) { // complete overlap Real fInvLen = 1.0f/fD0SqrLen; afT[0] = fDot0*fInvLen; afT[1] = fDot1*fInvLen; } else if ( fDot1 > 0.0f ) { // partial overlap afT[0] = 0.0f; afT[1] = fDot1/fD0SqrLen; } else if ( fDot1 < 0.0f ) { // no overlap riQuantity = 0; } else { // overlap at a single end point riQuantity = 1; afT[0] = 0.0f; } } } return riQuantity != 0; }
Vector2 operator*(const Ray2 &ray, float distance) { return Vector2(ray.GetOrigin() + ray.GetDirection() * distance); }
// Ray Intersection bool Intersects(const Ray2 &ray, const AARect &rect, float *distance) { if (rect.IsNull()) { SetPtrValue(distance, 0.0f); return false; } float lowt = 0.0f; float t; bool hit = false; Vector2 hitpoint; const Vector2 &rectMin = rect.GetMinimum(); const Vector2 &rectMax = rect.GetMaximum(); const Vector2 &rayOrig = ray.GetOrigin(); const Vector2 &rayDir = ray.GetDirection(); // Check origin inside first if (rayOrig.x > rectMin.x && rayOrig.y > rectMin.y && rayOrig.x < rectMax.x && rayOrig.y < rectMax.y) { SetPtrValue(distance, 0.0f); return true; } // Check each face in turn, only check closest 3 // Min x if (rayOrig.x < rectMin.x && rayDir.x > 0) { t = (rectMin.x - rayOrig.x) / rayDir.x; if (t > 0) { // Substitute t back into ray and check bounds and dist hitpoint = rayOrig + rayDir * t; if (hitpoint.y >= rectMin.y && hitpoint.y <= rectMax.y /* && (!hit || t < lowt) */) { if (distance == NULL) { return true; } hit = true; lowt = t; } } } // Max x if (rayOrig.x > rectMax.x && rayDir.x < 0) { t = (rectMax.x - rayOrig.x) / rayDir.x; if (t > 0) { // Substitute t back into ray and check bounds and dist hitpoint = rayOrig + rayDir * t; if (hitpoint.y >= rectMin.y && hitpoint.y <= rectMax.y && (!hit || t < lowt)) { if (distance == NULL) { return true; } hit = true; lowt = t; } } } // Min y if (rayOrig.y < rectMin.y && rayDir.y > 0) { t = (rectMin.y - rayOrig.y) / rayDir.y; if (t > 0) { // Substitute t back into ray and check bounds and dist hitpoint = rayOrig + rayDir * t; if (hitpoint.x >= rectMin.x && hitpoint.x <= rectMax.x && (!hit || t < lowt)) { if (distance == NULL) { return true; } hit = true; lowt = t; } } } // Max y if (rayOrig.y > rectMax.y && rayDir.y < 0) { t = (rectMax.y - rayOrig.y) / rayDir.y; if (t > 0) { // Substitute t back into ray and check bounds and dist hitpoint = rayOrig + rayDir * t; if (hitpoint.x >= rectMin.x && hitpoint.x <= rectMax.x && (!hit || t < lowt)) { if (distance == NULL) { return true; } hit = true; lowt = t; } } } SetPtrValue(distance, lowt); return hit; }