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; }
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; }