diff --git a/interfaces/IBounded2.cs b/interfaces/IBounded2.cs new file mode 100644 index 0000000..5143206 --- /dev/null +++ b/interfaces/IBounded2.cs @@ -0,0 +1,13 @@ +namespace GeometriCS +{ + /// + /// Interface for finite (bounded) entities in two-dimensional space. + /// + public interface IBounded2d + { + /// + /// Extents of the bounded entity. + /// + public Extents2d Extents { get; } + } +} diff --git a/intersections/IntersectionLine2ToLine2.cs b/intersections/IntersectionLine2ToLine2.cs index 117bd65..768e6a2 100644 --- a/intersections/IntersectionLine2ToLine2.cs +++ b/intersections/IntersectionLine2ToLine2.cs @@ -18,6 +18,10 @@ /// The two lines are parallel. /// PARALLEL, + /// + /// The two lines are colinear and intersect on their whole length. + /// + COLINEAR, } /// @@ -47,11 +51,37 @@ /// Second of the intersecting lines. 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; } } } diff --git a/intersections/IntersectionLine2ToLineSegment2.cs b/intersections/IntersectionLine2ToLineSegment2.cs index e517e7c..74e7d4a 100644 --- a/intersections/IntersectionLine2ToLineSegment2.cs +++ b/intersections/IntersectionLine2ToLineSegment2.cs @@ -1,7 +1,7 @@ namespace GeometriCS { /// - /// Intersection between a line and a line segment + /// Intersection between a line and a line segment. Double precision. /// public class IntersectionLine2ToLineSegment2d { @@ -19,6 +19,10 @@ /// PARALLEL, /// + /// The line segment is colinear with the line. + /// + COLINEAR, + /// /// The intersection would happen if the intersectors were unbounded, but not inside the bounds. /// 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; + } } } } diff --git a/intersections/IntersectionPlaneToPlane.cs b/intersections/IntersectionPlaneToPlane.cs index 059452e..34d2e4e 100644 --- a/intersections/IntersectionPlaneToPlane.cs +++ b/intersections/IntersectionPlaneToPlane.cs @@ -3,7 +3,7 @@ /// /// Intersection between two planes, double precision. /// - public struct IntersectionPlaneToPlaned + public class IntersectionPlaneToPlaned { /// /// Possible statuses the intersection can be. diff --git a/structs/Extents2.cs b/structs/Extents2.cs new file mode 100644 index 0000000..ff44231 --- /dev/null +++ b/structs/Extents2.cs @@ -0,0 +1,90 @@ +namespace GeometriCS +{ + /// + /// Geometric extents of a finitely large entity. Double precision. + /// + public struct Extents2d + { + /// + /// The point with the lowest Y and X. + /// + public Vector2d MinPoint { get; } + + /// + /// The point with the highest Y and X. + /// + public Vector2d MaxPoint { get; } + + /// + /// Take two points and create Extents from their bounding box. + /// + /// First point. + /// Second point. + /// Extents of the bounding box of the two points. + 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)); + } + + /// + /// Is there an overlap between the bounding boxes of these two extents? + /// + /// + /// true if there is an overlap, otherwise false. + 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)); + } + + /// + /// Does the bounding box contain the point. + /// + /// Point to test. + /// true if the point is inside of the bounding box, otherwise false. + public bool Contains(Vector2d point) + { + return point.X.IsInRange(MinPoint.X, MaxPoint.X) && point.Y.IsInRange(MinPoint.Y, MaxPoint.Y); + } + + /// + /// Constructor for the Extents2d. + /// + /// The point with the lowest X and Y. + /// The point with the greatest X and Y. + /// + /// The maxpoint is not greater in both dimensions than the minpoint. + /// + 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; + } + } +} diff --git a/structs/Line2.cs b/structs/Line2.cs index 62577ae..4f2d175 100644 --- a/structs/Line2.cs +++ b/structs/Line2.cs @@ -1,6 +1,4 @@ -using System.Runtime.CompilerServices; - -namespace GeometriCS +namespace GeometriCS { /// /// A line through a two-dimensional vector space. @@ -53,7 +51,8 @@ namespace GeometriCS /// Line passing through the two points. 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); } /// diff --git a/structs/LineSegment2.cs b/structs/LineSegment2.cs index d3d1e0f..f39b4bd 100644 --- a/structs/LineSegment2.cs +++ b/structs/LineSegment2.cs @@ -3,7 +3,7 @@ /// /// A segment of a two-dimensional line with double precision. /// - public class LineSegment2d + public class LineSegment2d : IBounded2d { /// /// Start point of the line. @@ -15,6 +15,10 @@ /// 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); + /// /// A constructor for a 2d line segment. /// @@ -22,8 +26,8 @@ /// Point at which the line ends. public LineSegment2d(Vector2d startPoint, Vector2d endPoint) { - StartPoint = (Vector2d) startPoint.Clone(); - EndPoint = (Vector2d) endPoint.Clone(); + StartPoint = startPoint; + EndPoint = endPoint; } /// diff --git a/structs/LineSegment3.cs b/structs/LineSegment3.cs index 6aae0f6..3ccef48 100644 --- a/structs/LineSegment3.cs +++ b/structs/LineSegment3.cs @@ -22,8 +22,8 @@ /// End point of the line. public LineSegment3d(Vector3d startPoint, Vector3d endPoint) { - StartPoint = (Vector3d) startPoint.Clone(); - EndPoint = (Vector3d) endPoint.Clone(); + StartPoint = startPoint; + EndPoint = endPoint; } /// diff --git a/structs/Vector2.cs b/structs/Vector2.cs index 824b3d0..4ceaea1 100644 --- a/structs/Vector2.cs +++ b/structs/Vector2.cs @@ -3,7 +3,7 @@ /// /// Two-dimensional vector with double precision. /// - public class Vector2d : ICloneable + public struct Vector2d : ICloneable { /// /// Vector with 0 length. @@ -30,6 +30,34 @@ /// public double Y { get; set; } + /// + /// Indexer for the vector. + /// + /// index + /// [0] is X; [1] is Y + /// Index was out of range {0, 1}. + 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(); + } + } + } + /// /// Length of the vector. /// diff --git a/structs/Vector3.cs b/structs/Vector3.cs index 8bb9050..7964d79 100644 --- a/structs/Vector3.cs +++ b/structs/Vector3.cs @@ -3,7 +3,7 @@ /// /// Three-dimensional vector with double precision. /// - public class Vector3d : ICloneable + public struct Vector3d : ICloneable { /// /// Vector with 0 length. @@ -40,6 +40,36 @@ /// public double Z { get; set; } + /// + /// Indexer for the vector. + /// + /// index + /// [0] is X; [1] is Y; [2] is Z + /// Index was out of range {0, 1, 3}. + 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(); + } + } + } + /// /// Length of the vector. /// diff --git a/utils/Utils.cs b/utils/Utils.cs index ac149b6..4fd37d0 100644 --- a/utils/Utils.cs +++ b/utils/Utils.cs @@ -3,13 +3,25 @@ /// /// Common utilities throughout the library. /// - internal static class Utils + public static class Utils { /// /// Default precision for double equality comparison. /// private const double DOUBLEPRECISION = 1E-5; + /// + /// Is this number in the range (inclusive). + /// + /// Number to compare + /// Lower end of the range. + /// Higher end of the range. + /// trueif number is in the range , false if it is outside. + public static bool IsInRange(this double num, double lower, double higher) + { + return num >= lower && num <= higher; + } + /// /// Tests whether the difference between two doubles is within a given limit. /// @@ -17,6 +29,22 @@ /// Second value to test. /// Maximum allowed difference. /// Do the values almost equal each other. - public static bool DoubleEquals(double a, double b, double prec = DOUBLEPRECISION) => Math.Abs(a - b) <= prec; + public static bool DoubleEquals(double a, double b, double prec = DOUBLEPRECISION) => Math.Abs(a - b) <= prec; + + /// + /// Returns the coefficients of a line defined by equation Ax + By + C = 0, + /// given two points that lie on the line. + /// + /// First point on the line. + /// Second point on the line. + /// Touple (Coeff_A, Coeff_B, Coeff_C). + 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); + } } }