Files
glitchy-engine-beef/Sandbox/src/Line2D.bf
T
2022-02-13 15:22:45 +01:00

213 lines
4.7 KiB
Beef
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using GlitchyEngine.Math;
namespace Sandbox
{
struct Line2D
{
public Vector2 Start;
public Vector2 End;
public this(Vector2 start, Vector2 end)
{
Start = start;
End = end;
}
/// Returns true if the given point lies on the line.
public bool OnLine(Vector2 point)
{
Vector2 startToPoint = point - Start;
Vector2 startToEnd = End - Start;
float cross = cross(startToPoint, startToEnd);
if(!MathHelper.IsZero(cross))
return false;
if(Math.Abs(startToEnd.X) >= Math.Abs(startToEnd.Y))
{
return (startToEnd.X > 0.0f) ?
(Start.X <= point.X && point.X <= End.X) :
(End.X <= point.X && point.X <= Start.X);
}
else
{
return (startToEnd.Y > 0.0f) ?
(Start.Y <= point.Y && point.Y <= End.Y) :
(End.Y <= point.Y && point.Y <= Start.Y);
}
}
[Inline]
private float cross(Vector2 v, Vector2 w)
{
return v.X * w.Y - v.Y * w.X;
}
public enum LineIntersection
{
case Collinear(Line2D IntersectionLine);
case CollinearNoIntersect;
case Parallel;
case Intersection(Vector2 Point);
case None;
}
private Result<(float Start, float End)> IntervalIntersection(float startA, float endA, float startB, float endB)
{
if(startB > endA || startA > endB)
return .Err;
else
{
float start = Math.Max(startA, startB);
float end = Math.Min(endA, endB);
return .Ok((start, end));
}
}
public LineIntersection Intersects(Line2D line)
{
Vector2 A = this.Start;
Vector2 B = this.End;
Vector2 C = line.Start;
Vector2 D = line.End;
float numR = ((A.Y-C.Y) * (D.X-C.X) - (A.X-C.X) * (D.Y-C.Y));
float den = ((B.X-A.X) * (D.Y-C.Y)-(B.Y-A.Y) * (D.X-C.X));
float r = numR / den;
float s = ((A.Y-C.Y) * (B.X-A.X) - (A.X-C.X) * (B.Y-A.Y)) / den;
if((0 <= r && r <= 1) && (0 <= s && s <= 1))
{
Vector2 P = A + r * (B - A);
return .Intersection(P);
}
else if(MathHelper.IsZero(den))
{
if(MathHelper.IsZero(numR))
{
Vector2 AtoB = B - A;
Vector2 CtoD = D - C;
float r_dot_r = Vector2.Dot(AtoB, AtoB);
// t0 = (q p) · r / (r · r)
float t0 = Vector2.Dot((C - A), AtoB) / r_dot_r;
// t1 = (q + s p) · r / (r · r) = t0 + s · r / (r · r)
float t1 = t0 + Vector2.Dot(CtoD, AtoB) / r_dot_r;
// do interval intersection
if(Vector2.Dot(CtoD, AtoB) < 0)
{
Swap!(t0, t1);
}
if(IntervalIntersection(t0, t1, 0, 1) case .Ok(let intersection))
{
return .Collinear(Line2D(A + intersection.Start * AtoB, A + intersection.End * AtoB));
}
else
{
return .CollinearNoIntersect;
}
}
else
{
return .Parallel;
}
}
return .None;
}
public static void TestIntersects()
{
{
Line2D line = .(.(0, 0), .(4, 0));
Line2D intersecting = .(.(2, 2), .(2, -2));
var result = line.Intersects(intersecting);
Vector2 intersection;
Runtime.Assert(result case .Intersection(out intersection));
Runtime.Assert(intersection == .(2, 0));
}
{
Line2D line = .(.(0, -1), .(5, 2));
Line2D intersecting = .(.(1, 3), .(4, -2));
var result = line.Intersects(intersecting);
Vector2 intersection;
Runtime.Assert(result case .Intersection(out intersection));
Runtime.Assert(intersection == .(2.5f, 0.5f));
}
{
Line2D line = .(.(-1, 0), .(1, 0));
Line2D collinear = .(.(2, 0), .( 4, 0));
var result = line.Intersects(collinear);
Runtime.Assert(result case .CollinearNoIntersect);
}
{
Line2D line = .(.(-1, 0), .(2, 0));
Line2D collinear = .(.(1, 0), .( 4, 0));
var result = line.Intersects(collinear);
Line2D intersection;
Runtime.Assert(result case .Collinear(out intersection));
Runtime.Assert(intersection.Start == .(1, 0));
Runtime.Assert(intersection.End == .(2, 0));
}
{
Line2D line = .(.(-1, 5), .(2, 5));
Line2D collinear = .(.(4, 5), .(1, 5));
var result = line.Intersects(collinear);
Line2D intersection;
Runtime.Assert(result case .Collinear(out intersection));
Runtime.Assert(intersection.Start == .(1, 5));
Runtime.Assert(intersection.End == .(2, 5));
}
}
/*
public bool Intersects(Line2D line)
{
float x1 = Start.X;
float x2 = End.X;
float x3 = line.Start.X;
float x4 = line.End.X;
float y1 = Start.Y;
float y2 = End.Y;
float y3 = line.Start.Y;
float y4 = line.End.Y;
float t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
float u = ((x1 - x3) * (y1 - y2) - (y1 - y3) * (x1 - x2)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
return (0.0f <= t && t <= 1.0f && 0.0f <= u && u <= 1.0f);
}
*/
}
}