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