You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
6.6 KiB
C#
191 lines
6.6 KiB
C#
namespace Otter {
|
|
/// <summary>
|
|
/// Class for a simple line with two points.
|
|
/// </summary>
|
|
public class Line2 {
|
|
|
|
#region Public Fields
|
|
|
|
/// <summary>
|
|
/// The X position for the first point.
|
|
/// </summary>
|
|
public float X1;
|
|
|
|
/// <summary>
|
|
/// The Y position for the first point.
|
|
/// </summary>
|
|
public float Y1;
|
|
|
|
/// <summary>
|
|
/// The X position for the second point.
|
|
/// </summary>
|
|
public float X2;
|
|
|
|
/// <summary>
|
|
/// The Y position for the second point.
|
|
/// </summary>
|
|
public float Y2;
|
|
|
|
#endregion
|
|
|
|
#region Public Properties
|
|
|
|
/// <summary>
|
|
/// The first point of the line as a vector2.
|
|
/// </summary>
|
|
public Vector2 PointA {
|
|
get { return new Vector2(X1, Y1); }
|
|
set { X1 = (float)value.X; Y1 = (float)value.Y; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The second point of a line as a vector2.
|
|
/// </summary>
|
|
public Vector2 PointB {
|
|
get { return new Vector2(X2, Y2); }
|
|
set { X2 = (float)value.X; Y2 = (float)value.Y; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// A in the line equation Ax + By = C.
|
|
/// </summary>
|
|
public float A {
|
|
get { return Y2 - Y1; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// B in the line equation Ax + By = C.
|
|
/// </summary>
|
|
public float B {
|
|
get { return X1 - X2; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// C in the line equation Ax + By = C.
|
|
/// </summary>
|
|
public float C {
|
|
get { return A * X1 + B * Y1; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Constructors
|
|
|
|
/// <summary>
|
|
/// Create a new Line2.
|
|
/// </summary>
|
|
/// <param name="x1">X of the first point</param>
|
|
/// <param name="y1">Y of the first point</param>
|
|
/// <param name="x2">X of the second point</param>
|
|
/// <param name="y2">Y of the second point</param>
|
|
public Line2(float x1, float y1, float x2, float y2) {
|
|
X1 = x1; X2 = x2; Y1 = y1; Y2 = y2;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a new Line2.
|
|
/// </summary>
|
|
/// <param name="xy1">X,Y of the first point</param>
|
|
/// <param name="xy2">X,Y of the second point</param>
|
|
public Line2(Vector2 xy1, Vector2 xy2) {
|
|
PointA = xy1; PointB = xy2;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Intersection test on another line. (http://ideone.com/PnPJgb)
|
|
/// </summary>
|
|
/// <param name="other">The line to test against</param>
|
|
/// <returns></returns>
|
|
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 + "}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check intersection against a rectangle.
|
|
/// </summary>
|
|
/// <param name="x">X Position of the rectangle.</param>
|
|
/// <param name="y">Y Position of the rectangle.</param>
|
|
/// <param name="width">Width of the rectangle.</param>
|
|
/// <param name="height">Height of the rectangle.</param>
|
|
/// <returns>True if the line intersects any line on the rectangle, or if the line is inside the rectangle.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check the intersection against a circle.
|
|
/// </summary>
|
|
/// <param name="circle"></param>
|
|
/// <param name="radius"></param>
|
|
/// <returns></returns>
|
|
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
|
|
|
|
}
|
|
}
|