Line intersections
Decided to revert to Vectors being structs after reconsidering the full implications.
This commit is contained in:
parent
ad0599f481
commit
a23ea94db4
11 changed files with 285 additions and 19 deletions
13
interfaces/IBounded2.cs
Normal file
13
interfaces/IBounded2.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace GeometriCS
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for finite (bounded) entities in two-dimensional space.
|
||||
/// </summary>
|
||||
public interface IBounded2d
|
||||
{
|
||||
/// <summary>
|
||||
/// Extents of the bounded entity.
|
||||
/// </summary>
|
||||
public Extents2d Extents { get; }
|
||||
}
|
||||
}
|
|
@ -18,6 +18,10 @@
|
|||
/// The two lines are parallel.
|
||||
/// </summary>
|
||||
PARALLEL,
|
||||
/// <summary>
|
||||
/// The two lines are colinear and intersect on their whole length.
|
||||
/// </summary>
|
||||
COLINEAR,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -47,11 +51,37 @@
|
|||
/// <param name="line1">Second of the intersecting lines.</param>
|
||||
public IntersectionLine2ToLine2d(Line2d line1, Line2d line2)
|
||||
{
|
||||
// Set the intersector references
|
||||
Line1 = line1;
|
||||
Line2 = line2;
|
||||
|
||||
// Process the intersection
|
||||
throw new NotImplementedException();
|
||||
// Check if lines are parallel
|
||||
// TODO: Check what happens if coeff_B == 0
|
||||
if(Utils.DoubleEquals(line1.Coeff_A / line1.Coeff_B, line2.Coeff_A / line2.Coeff_B))
|
||||
{
|
||||
// Null result
|
||||
Result = null;
|
||||
|
||||
// Check if lines are coincidental
|
||||
if (Utils.DoubleEquals(line1.Coeff_A / line2.Coeff_A, line1.Coeff_B / line2.Coeff_B) &&
|
||||
Utils.DoubleEquals(line1.Coeff_A / line2.Coeff_A, line1.Coeff_C / line2.Coeff_C))
|
||||
{
|
||||
Status = Statuses.COLINEAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = Statuses.PARALLEL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform the intersection calculation
|
||||
double divisor = line1.Coeff_A * line2.Coeff_B - line2.Coeff_A * line1.Coeff_B;
|
||||
double x0 = (line1.Coeff_B * line2.Coeff_C - line2.Coeff_B * line1.Coeff_C) / divisor;
|
||||
double y0 = (line1.Coeff_C * line2.Coeff_A - line2.Coeff_C * line1.Coeff_A) / divisor;
|
||||
Result = new Vector2d(x0, y0);
|
||||
Status = Statuses.SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace GeometriCS
|
||||
{
|
||||
/// <summary>
|
||||
/// Intersection between a line and a line segment
|
||||
/// Intersection between a line and a line segment. Double precision.
|
||||
/// </summary>
|
||||
public class IntersectionLine2ToLineSegment2d
|
||||
{
|
||||
|
@ -19,6 +19,10 @@
|
|||
/// </summary>
|
||||
PARALLEL,
|
||||
/// <summary>
|
||||
/// The line segment is colinear with the line.
|
||||
/// </summary>
|
||||
COLINEAR,
|
||||
/// <summary>
|
||||
/// The intersection would happen if the intersectors were unbounded, but not inside the bounds.
|
||||
/// </summary>
|
||||
OUTOFBOUNDS,
|
||||
|
@ -54,8 +58,48 @@
|
|||
Line = line;
|
||||
LineSegment = lineSegment;
|
||||
|
||||
// Process the intersection
|
||||
throw new NotImplementedException();
|
||||
// Construct line coefficients for the linesegment
|
||||
(double segment_A, double segment_B, double segment_C) =
|
||||
Utils.Line2CoefficientsFromTwoPoints(lineSegment.StartPoint, lineSegment.EndPoint);
|
||||
|
||||
// Check if lines are parallel
|
||||
// TODO: Check what happens if coeff_B == 0
|
||||
// TODO: Find a non-retarded way to put this into a function so
|
||||
// that it can be reused by all the 2d linear intersections.
|
||||
if (Utils.DoubleEquals(line.Coeff_A / line.Coeff_B, segment_A / segment_B))
|
||||
{
|
||||
// Null result
|
||||
Result = null;
|
||||
|
||||
// Check if lines are coincidental
|
||||
if (Utils.DoubleEquals(line.Coeff_A / segment_A, line.Coeff_B / segment_B) &&
|
||||
Utils.DoubleEquals(line.Coeff_A / segment_A, line.Coeff_C / segment_C))
|
||||
{
|
||||
Status = Statuses.COLINEAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = Statuses.PARALLEL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform the intersection calculation
|
||||
double divisor = line.Coeff_A * segment_B - segment_A * line.Coeff_B;
|
||||
double x0 = (line.Coeff_B * segment_C - segment_B * line.Coeff_C) / divisor;
|
||||
double y0 = (line.Coeff_C * segment_A - segment_C * line.Coeff_A) / divisor;
|
||||
Result = new Vector2d(x0, y0);
|
||||
|
||||
// Check if result is inside of the segment.
|
||||
if (lineSegment.Extents.Contains((Vector2d)Result))
|
||||
{
|
||||
Status = Statuses.SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = Statuses.OUTOFBOUNDS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
/// <summary>
|
||||
/// Intersection between two planes, double precision.
|
||||
/// </summary>
|
||||
public struct IntersectionPlaneToPlaned
|
||||
public class IntersectionPlaneToPlaned
|
||||
{
|
||||
/// <summary>
|
||||
/// Possible statuses the intersection can be.
|
||||
|
|
90
structs/Extents2.cs
Normal file
90
structs/Extents2.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
namespace GeometriCS
|
||||
{
|
||||
/// <summary>
|
||||
/// Geometric extents of a finitely large entity. Double precision.
|
||||
/// </summary>
|
||||
public struct Extents2d
|
||||
{
|
||||
/// <summary>
|
||||
/// The point with the lowest Y and X.
|
||||
/// </summary>
|
||||
public Vector2d MinPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The point with the highest Y and X.
|
||||
/// </summary>
|
||||
public Vector2d MaxPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Take two points and create Extents from their bounding box.
|
||||
/// </summary>
|
||||
/// <param name="pt1">First point.</param>
|
||||
/// <param name="pt2">Second point.</param>
|
||||
/// <returns>Extents of the bounding box of the two points.</returns>
|
||||
public static Extents2d FromTwoPoints(Vector2d pt1, Vector2d pt2)
|
||||
{
|
||||
// Find the smallest and largest x and y values.
|
||||
double minx = pt1.X < pt2.X ? pt1.X : pt2.X;
|
||||
double miny = pt1.Y < pt2.Y ? pt1.Y : pt2.Y;
|
||||
double maxx = pt1.X > pt2.X ? pt1.X : pt2.X;
|
||||
double maxy = pt1.Y > pt2.Y ? pt1.Y : pt2.Y;
|
||||
|
||||
// Create new points from them and create the extents.
|
||||
return new Extents2d(new Vector2d(minx, miny),
|
||||
new Vector2d(maxx, maxy));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is there an overlap between the bounding boxes of these two extents?
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
/// <returns><c>true</c> if there is an overlap, otherwise <c>false</c>.</returns>
|
||||
public bool Overlaps(Extents2d other)
|
||||
{
|
||||
// If at least one of my points are in others X band, or at least one of others points are in my X band
|
||||
// check whether at least one of my points are in others Y band, or at least one of the others points
|
||||
// are in my Y band. If both conditions are met, there is an overlap.
|
||||
return (MinPoint.X.IsInRange(other.MinPoint.X, other.MaxPoint.X) ||
|
||||
MaxPoint.X.IsInRange(other.MinPoint.X, other.MaxPoint.X) ||
|
||||
other.MinPoint.X.IsInRange(MinPoint.X, MaxPoint.X) ||
|
||||
other.MaxPoint.X.IsInRange(MinPoint.X, MaxPoint.X) ) && (
|
||||
MinPoint.Y.IsInRange(other.MinPoint.Y, other.MaxPoint.Y) ||
|
||||
MaxPoint.Y.IsInRange(other.MinPoint.Y, other.MaxPoint.Y) ||
|
||||
other.MinPoint.Y.IsInRange(MinPoint.Y, MaxPoint.Y) ||
|
||||
other.MaxPoint.Y.IsInRange(MinPoint.Y, MaxPoint.Y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does the bounding box contain the point.
|
||||
/// </summary>
|
||||
/// <param name="point">Point to test.</param>
|
||||
/// <returns><c>true</c> if the point is inside of the bounding box, otherwise <c>false</c>.</returns>
|
||||
public bool Contains(Vector2d point)
|
||||
{
|
||||
return point.X.IsInRange(MinPoint.X, MaxPoint.X) && point.Y.IsInRange(MinPoint.Y, MaxPoint.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the Extents2d.
|
||||
/// </summary>
|
||||
/// <param name="minPoint">The point with the lowest X and Y.</param>
|
||||
/// <param name="maxPoint">The point with the greatest X and Y.</param>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// The maxpoint is not greater in both dimensions than the minpoint.
|
||||
/// </exception>
|
||||
public Extents2d(Vector2d minPoint, Vector2d maxPoint)
|
||||
{
|
||||
/// Check validity
|
||||
if((minPoint.X > maxPoint.X && !Utils.DoubleEquals(minPoint.X, maxPoint.X)) ||
|
||||
(minPoint.Y > maxPoint.Y && !Utils.DoubleEquals(minPoint.Y, maxPoint.Y)))
|
||||
{
|
||||
throw new ArgumentException($"The minpoint {minPoint} has to " +
|
||||
$"have lesser both X and Y than the maxpoint {maxPoint}.");
|
||||
}
|
||||
|
||||
// Assign the properties.
|
||||
MinPoint = minPoint;
|
||||
MaxPoint = maxPoint;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace GeometriCS
|
||||
namespace GeometriCS
|
||||
{
|
||||
/// <summary>
|
||||
/// A line through a two-dimensional vector space.
|
||||
|
@ -53,7 +51,8 @@ namespace GeometriCS
|
|||
/// <returns>Line passing through the two points.</returns>
|
||||
public static Line2d FromTwoPoints(Vector2d firstPoint, Vector2d secondPoint)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
(double a, double b, double c) = Utils.Line2CoefficientsFromTwoPoints(firstPoint, secondPoint);
|
||||
return new Line2d(a, b, c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
/// <summary>
|
||||
/// A segment of a two-dimensional line with double precision.
|
||||
/// </summary>
|
||||
public class LineSegment2d
|
||||
public class LineSegment2d : IBounded2d
|
||||
{
|
||||
/// <summary>
|
||||
/// Start point of the line.
|
||||
|
@ -15,6 +15,10 @@
|
|||
/// </summary>
|
||||
public Vector2d EndPoint { get; set;}
|
||||
|
||||
// Consider pre-calculating this in point setters later on,
|
||||
// once we have group intersection support and can gauge performance effects.
|
||||
public Extents2d Extents => Extents2d.FromTwoPoints(StartPoint, EndPoint);
|
||||
|
||||
/// <summary>
|
||||
/// A constructor for a 2d line segment.
|
||||
/// </summary>
|
||||
|
@ -22,8 +26,8 @@
|
|||
/// <param name="endPoint">Point at which the line ends.</param>
|
||||
public LineSegment2d(Vector2d startPoint, Vector2d endPoint)
|
||||
{
|
||||
StartPoint = (Vector2d) startPoint.Clone();
|
||||
EndPoint = (Vector2d) endPoint.Clone();
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
/// <param name="endPoint">End point of the line.</param>
|
||||
public LineSegment3d(Vector3d startPoint, Vector3d endPoint)
|
||||
{
|
||||
StartPoint = (Vector3d) startPoint.Clone();
|
||||
EndPoint = (Vector3d) endPoint.Clone();
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
/// <summary>
|
||||
/// Two-dimensional vector with double precision.
|
||||
/// </summary>
|
||||
public class Vector2d : ICloneable
|
||||
public struct Vector2d : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// Vector with 0 length.
|
||||
|
@ -30,6 +30,34 @@
|
|||
/// </summary>
|
||||
public double Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indexer for the vector.
|
||||
/// </summary>
|
||||
/// <param name="i">index</param>
|
||||
/// <returns>[0] is X; [1] is Y</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Index was out of range {0, 1}.</exception>
|
||||
public double this [int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return X;
|
||||
case 1: return Y;
|
||||
default: throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: X = value; break;
|
||||
case 1: Y = value; break;
|
||||
default: throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Length of the vector.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
/// <summary>
|
||||
/// Three-dimensional vector with double precision.
|
||||
/// </summary>
|
||||
public class Vector3d : ICloneable
|
||||
public struct Vector3d : ICloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// Vector with 0 length.
|
||||
|
@ -40,6 +40,36 @@
|
|||
/// </summary>
|
||||
public double Z { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indexer for the vector.
|
||||
/// </summary>
|
||||
/// <param name="i">index</param>
|
||||
/// <returns>[0] is X; [1] is Y; [2] is Z</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">Index was out of range {0, 1, 3}.</exception>
|
||||
public double this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return X;
|
||||
case 1: return Y;
|
||||
case 2: return Z;
|
||||
default: throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: X = value; break;
|
||||
case 1: Y = value; break;
|
||||
case 2: Z = value; break;
|
||||
default: throw new IndexOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Length of the vector.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,13 +3,25 @@
|
|||
/// <summary>
|
||||
/// Common utilities throughout the library.
|
||||
/// </summary>
|
||||
internal static class Utils
|
||||
public static class Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Default precision for double equality comparison.
|
||||
/// </summary>
|
||||
private const double DOUBLEPRECISION = 1E-5;
|
||||
|
||||
/// <summary>
|
||||
/// Is this number in the range <lower; higher> (inclusive).
|
||||
/// </summary>
|
||||
/// <param name="num">Number to compare</param>
|
||||
/// <param name="lower">Lower end of the range.</param>
|
||||
/// <param name="higher">Higher end of the range.</param>
|
||||
/// <returns><c>true</c>if number is in the range <lower; higher>, <c>false</c> if it is outside.</returns>
|
||||
public static bool IsInRange(this double num, double lower, double higher)
|
||||
{
|
||||
return num >= lower && num <= higher;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests whether the difference between two doubles is within a given limit.
|
||||
/// </summary>
|
||||
|
@ -18,5 +30,21 @@
|
|||
/// <param name="prec">Maximum allowed difference.</param>
|
||||
/// <returns>Do the values almost equal each other.</returns>
|
||||
public static bool DoubleEquals(double a, double b, double prec = DOUBLEPRECISION) => Math.Abs(a - b) <= prec;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the coefficients of a line defined by equation Ax + By + C = 0,
|
||||
/// given two points that lie on the line.
|
||||
/// </summary>
|
||||
/// <param name="pt1">First point on the line.</param>
|
||||
/// <param name="pt2">Second point on the line.</param>
|
||||
/// <returns>Touple (Coeff_A, Coeff_B, Coeff_C).</returns>
|
||||
public static (double A, double B, double C) Line2CoefficientsFromTwoPoints(Vector2d pt1, Vector2d pt2)
|
||||
{
|
||||
double coeff_A = pt2.Y - pt1.Y;
|
||||
double coeff_B = pt1.X - pt2.X;
|
||||
double coeff_C = (pt1.Y * (pt2.X - pt1.X)) -
|
||||
(pt1.X * (pt2.Y - pt1.Y));
|
||||
return (coeff_A, coeff_B, coeff_C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue