namespace Otter {
///
/// Class for a simple line with two points.
///
public class Line2 {
#region Public Fields
///
/// The X position for the first point.
///
public float X1;
///
/// The Y position for the first point.
///
public float Y1;
///
/// The X position for the second point.
///
public float X2;
///
/// The Y position for the second point.
///
public float Y2;
#endregion
#region Public Properties
///
/// The first point of the line as a vector2.
///
public Vector2 PointA {
get { return new Vector2(X1, Y1); }
set { X1 = (float)value.X; Y1 = (float)value.Y; }
}
///
/// The second point of a line as a vector2.
///
public Vector2 PointB {
get { return new Vector2(X2, Y2); }
set { X2 = (float)value.X; Y2 = (float)value.Y; }
}
///
/// A in the line equation Ax + By = C.
///
public float A {
get { return Y2 - Y1; }
}
///
/// B in the line equation Ax + By = C.
///
public float B {
get { return X1 - X2; }
}
///
/// C in the line equation Ax + By = C.
///
public float C {
get { return A * X1 + B * Y1; }
}
#endregion
#region Constructors
///
/// Create a new Line2.
///
/// X of the first point
/// Y of the first point
/// X of the second point
/// Y of the second point
public Line2(float x1, float y1, float x2, float y2) {
X1 = x1; X2 = x2; Y1 = y1; Y2 = y2;
}
///
/// Create a new Line2.
///
/// X,Y of the first point
/// X,Y of the second point
public Line2(Vector2 xy1, Vector2 xy2) {
PointA = xy1; PointB = xy2;
}
#endregion
#region Public Methods
///
/// Intersection test on another line. (http://ideone.com/PnPJgb)
///
/// The line to test against
///
public bool Intersects(Line2 other) {
//A = X1, Y1; B = X2, Y2; C = other.X1, other.Y1; D = other.X2, other.Y2;
Vector2 A = new Vector2(X1, Y1);
Vector2 B = new Vector2(X2, Y2);
Vector2 C = new Vector2(other.X1, other.Y1);
Vector2 D = new Vector2(other.X2, other.Y2);
Vector2 CmP = new Vector2(C.X - A.X, C.Y - A.Y);
Vector2 r = new Vector2(B.X - A.X, B.Y - A.Y);
Vector2 s = new Vector2(D.X - C.X, D.Y - C.Y);
float CmPxr = (float)CmP.X * (float)r.Y - (float)CmP.Y * (float)r.X;
float CmPxs = (float)CmP.X * (float)s.Y - (float)CmP.Y * (float)s.X;
float rxs = (float)r.X * (float)s.Y - (float)r.Y * (float)s.X;
if (CmPxr == 0f) {
// Lines are collinear, and so intersect if they have any overlap
return ((C.X - A.X < 0f) != (C.X - B.X < 0f))
|| ((C.Y - A.Y < 0f) != (C.Y - B.Y < 0f));
}
if (rxs == 0f)
return false; // Lines are parallel.
float rxsr = 1f / rxs;
float t = CmPxs * rxsr;
float u = CmPxr * rxsr;
return (t >= 0f) && (t <= 1f) && (u >= 0f) && (u <= 1f);
}
public override string ToString() {
return "{X1: " + X1 + " Y1: " + Y1 + " X2: " + X2 + " Y2: " + Y2 + "}";
}
///
/// Check intersection against a rectangle.
///
/// X Position of the rectangle.
/// Y Position of the rectangle.
/// Width of the rectangle.
/// Height of the rectangle.
/// True if the line intersects any line on the rectangle, or if the line is inside the rectangle.
public bool IntersectsRect(float x, float y, float width, float height) {
if (Util.InRect(X1, Y1, x, y, width, height)) return true;
if (Util.InRect(X2, Y2, x, y, width, height)) return true;
if (Intersects(new Line2(x, y, x + width, y))) return true;
if (Intersects(new Line2(x + width, y, x + width, y + height))) return true;
if (Intersects(new Line2(x + width, y + height, x, y + height))) return true;
if (Intersects(new Line2(x, y + height, x, y))) return true;
return false;
}
///
/// Check the intersection against a circle.
///
///
///
///
public bool IntersectCircle(Vector2 circle, float radius) {
// find the closest point on the line segment to the center of the circle
Vector2 line = PointB - PointA;
float lineLength = (float)line.Length;
Vector2 lineNorm = (1 / lineLength) * line;
Vector2 segmentToCircle = circle - PointA;
float closestPointOnSegment = (float)Vector2.Dot(segmentToCircle, line) / lineLength;
// Special cases where the closest point happens to be the end points
Vector2 closest;
if (closestPointOnSegment < 0) closest = PointA;
else if (closestPointOnSegment > lineLength) closest = PointB;
else closest = PointA + closestPointOnSegment * lineNorm;
// Find that distance. If it is less than the radius, then we
// are within the circle
var distanceFromClosest = circle - closest;
var distanceFromClosestLength = distanceFromClosest.Length;
if (distanceFromClosestLength > radius) return false;
return true;
}
#endregion
}
}