#region File Description
//-----------------------------------------------------------------------------
// CollisionMath.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using Microsoft.Xna.Framework;
#endregion
namespace NetRumble
{
///
/// A code container for collision-related mathematical functions.
///
static public class CollisionMath
{
#region Helper Types
///
/// Data defining a circle/line collision result.
///
/// Also used for circle/rectangles.
public struct CircleLineCollisionResult
{
public bool Collision;
public Vector2 Point;
public Vector2 Normal;
public float Distance;
}
#endregion
#region Collision Methods
///
/// Determines the point of intersection between two line segments,
/// as defined by four points.
///
/// The first point on the first line segment.
/// The second point on the first line segment.
/// The first point on the second line segment.
/// The second point on the second line segment.
/// The output value with the interesection, if any.
/// The output parameter "point" is only valid
/// when the return value is true.
/// True if intersecting, false otherwise.
public static bool LineLineIntersect(Vector2 a, Vector2 b, Vector2 c,
Vector2 d, out Vector2 point)
{
point = Vector2.Zero;
double r, s;
double denominator = (b.X - a.X) * (d.Y - c.Y) - (b.Y - a.Y) * (d.X - c.X);
// If the denominator in above is zero, AB & CD are colinear
if (denominator == 0)
{
return false;
}
double numeratorR = (a.Y - c.Y) * (d.X - c.X) - (a.X - c.X) * (d.Y - c.Y);
r = numeratorR / denominator;
double numeratorS = (a.Y - c.Y) * (b.X - a.X) - (a.X - c.X) * (b.Y - a.Y);
s = numeratorS / denominator;
// non-intersecting
if (r < 0 || r > 1 || s < 0 || s > 1)
{
return false;
}
// find intersection point
point.X = (float)(a.X + (r * (b.X - a.X)));
point.Y = (float)(a.Y + (r * (b.Y - a.Y)));
return true;
}
///
/// Determine if two circles intersect or contain each other.
///
/// The center of the first circle.
/// The radius of the first circle.
/// The center of the second circle.
/// The radius of the second circle.
/// True if the circles intersect or contain one another.
public static bool CircleCircleIntersect(Vector2 center1, float radius1,
Vector2 center2, float radius2)
{
Vector2 line = center2 - center1;
// we use LengthSquared to avoid a costly square-root call
return (line.LengthSquared() <= (radius1 + radius2) * (radius1 + radius2));
}
///
/// Determines if a circle and line segment intersect, and if so, how they do.
///
/// The center of the circle.
/// The radius of the circle.
/// The rectangle.
/// The result data for the collision.
/// True if a collision occurs, provided for convenience.
public static bool CircleRectangleCollide(Vector2 center, float radius,
Rectangle rectangle, ref CircleLineCollisionResult result)
{
float xVal = center.X;
if (xVal < rectangle.Left) xVal = rectangle.Left;
if (xVal > rectangle.Right) xVal = rectangle.Right;
float yVal = center.Y;
if (yVal < rectangle.Top) yVal = rectangle.Top;
if (yVal > rectangle.Bottom) yVal = rectangle.Bottom;
Vector2 direction = new Vector2(center.X-xVal,center.Y-yVal);
float distance = direction.Length();
if ((distance > 0) && (distance < radius))
{
result.Collision = true;
result.Distance = radius - distance;
result.Normal = Vector2.Normalize(direction);
result.Point = new Vector2(xVal, yVal);
}
else
{
result.Collision = false;
}
return result.Collision;
}
///
/// Determines if a circle and line segment intersect, and if so, how they do.
///
/// The center of the circle.
/// The radius of the circle.
/// The first point on the line segment.
/// The second point on the line segment.
/// The result data for the collision.
/// True if a collision occurs, provided for convenience.
public static bool CircleLineCollide(Vector2 center, float radius,
Vector2 lineStart, Vector2 lineEnd, ref CircleLineCollisionResult result)
{
Vector2 AC = center - lineStart;
Vector2 AB = lineEnd - lineStart;
float ab2 = AB.LengthSquared();
if (ab2 <= 0f)
{
return false;
}
float acab = Vector2.Dot(AC, AB);
float t = acab / ab2;
if (t < 0.0f)
t = 0.0f;
else if (t > 1.0f)
t = 1.0f;
result.Point = lineStart + t * AB;
result.Normal = center - result.Point;
float h2 = result.Normal.LengthSquared();
float r2 = radius * radius;
if ((h2 > 0) && (h2 <= r2))
{
result.Normal.Normalize();
result.Distance = (radius - (center - result.Point).Length());
result.Collision = true;
}
else
{
result.Collision = false;
}
return result.Collision;
}
#endregion
}
}