Index: Core/Common/src/Core.Common.Base/Core.Common.Base.csproj =================================================================== diff -u -r93b256575fba3e4068baadeeb62140533336371a -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/src/Core.Common.Base/Core.Common.Base.csproj (.../Core.Common.Base.csproj) (revision 93b256575fba3e4068baadeeb62140533336371a) +++ Core/Common/src/Core.Common.Base/Core.Common.Base.csproj (.../Core.Common.Base.csproj) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -88,11 +88,13 @@ Properties\GlobalAssembly.cs + + Index: Core/Common/src/Core.Common.Base/Geometry/Intersection2DType.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Base/Geometry/Intersection2DType.cs (revision 0) +++ Core/Common/src/Core.Common.Base/Geometry/Intersection2DType.cs (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -0,0 +1,21 @@ +namespace Core.Common.Base.Geometry +{ + /// + /// Describes the type of intersection that has been calculated in 2D Euclidean space. + /// + public enum Intersection2DType + { + /// + /// No intersections have been found. + /// + NoIntersections, + /// + /// Intersections have been found. + /// + Intersects, + /// + /// There is some overlap between two elements. + /// + Overlapping + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Base/Geometry/Math2D.cs =================================================================== diff -u -rd36a95d2e88d98b7b92ff5d091abf711d1dd31d9 -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/src/Core.Common.Base/Geometry/Math2D.cs (.../Math2D.cs) (revision d36a95d2e88d98b7b92ff5d091abf711d1dd31d9) +++ Core/Common/src/Core.Common.Base/Geometry/Math2D.cs (.../Math2D.cs) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -24,6 +24,8 @@ using System.Collections.ObjectModel; using System.Linq; using Core.Common.Base.Properties; + +using MathNet.Numerics.LinearAlgebra; using MathNet.Numerics.LinearAlgebra.Double; namespace Core.Common.Base.Geometry @@ -225,6 +227,178 @@ return length; } + /// + /// Calculates the intersection between two 2D segments. + /// + /// The first 2D segment. + /// The second 2D segment. + /// The intersection calculation result. + /// Implementation from http://geomalgorithms.com/a05-_intersect-1.html + /// based on method intersect2D_2Segments. + public static Segment2DIntersectSegment2DResult GetIntersectionBetweenSegments(Segment2D segment1, Segment2D segment2) + { + Vector u = segment1.SecondPoint - segment1.FirstPoint; + Vector v = segment2.SecondPoint - segment2.FirstPoint; + Vector w = segment1.FirstPoint - segment2.FirstPoint; + double d = PerpDotProduct(u, v); + + if (Math.Abs(d) < epsilonForComparisons) + { + // Segments can be considered parallel... + if (AreCollinear(u, v, w)) + { + // ... and collinear ... + if (IsSegmentAsPointIntersectionDegenerateScenario(segment1, segment2)) + { + // ... but either or both segments are point degenerates: + return HandleSegmentAsPointIntersectionDegenerates(segment1, segment2); + } + + // ... so there is a possibility of overlapping or connected lines: + return HandleCollinearSegmentIntersection(segment1, segment2, v, w); + } + + // ... but not collinear, so no intersection possible: + return Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + } + else + { + // Segments are at an angle and may intersect: + double sI = PerpDotProduct(v, w) / d; + if (sI < 0.0 || sI > 1.0) + { + return Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + } + + double tI = PerpDotProduct(u, w) / d; + if (tI < 0.0 || tI > 1.0) + { + return Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + } + + Point2D intersectionPoint = segment1.FirstPoint + u.Multiply(sI); + return Segment2DIntersectSegment2DResult.CreateIntersectionResult(intersectionPoint); + } + } + + /// + /// Determines if two vectors are collinear. + /// + /// The first 2D vector. + /// The second 2D vector. + /// The vector from the tail of + /// to the tail of . + /// True if the vectors are collinear, false otherwise. + private static bool AreCollinear(Vector vector1, Vector vector2, Vector tailsVector) + { + return Math.Abs(PerpDotProduct(vector1, tailsVector)) < epsilonForComparisons && + Math.Abs(PerpDotProduct(vector2, tailsVector)) < epsilonForComparisons; + } + + private static Segment2DIntersectSegment2DResult HandleCollinearSegmentIntersection(Segment2D segment1, Segment2D segment2, Vector v, Vector w) + { + double t0, t1; + Vector w2 = segment1.SecondPoint - segment2.FirstPoint; + if (v[0] != 0.0) + { + t0 = w[0] / v[0]; + t1 = w2[0] / v[0]; + } + else + { + t0 = w[1] / v[1]; + t1 = w2[1] / v[1]; + } + // Require t0 to be smaller than t1, swapping if needed: + if (t0 > t1) + { + double tempSwapVariable = t0; + t0 = t1; + t1 = tempSwapVariable; + } + if (t0 > 1.0 || t1 < 0.0) + { + // There is no overlap: + return Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + } + + t0 = t0 < 0.0 ? 0.0 : t0; // Clip to minimum 0 + t1 = t1 > 1.0 ? 1.0 : t1; // Clip to maximum 1 + Point2D intersectionPoint1 = segment2.FirstPoint + v.Multiply(t0); + if (Math.Abs(t0 - t1) < epsilonForComparisons) + { + // Segments intersect at a point: + return Segment2DIntersectSegment2DResult.CreateIntersectionResult(intersectionPoint1); + } + else + { + // Segments overlap: + Point2D intersectionPoint2 = segment2.FirstPoint + v.Multiply(t1); + return Segment2DIntersectSegment2DResult.CreateOverlapResult(intersectionPoint1, intersectionPoint2); + } + } + + private static bool IsSegmentAsPointIntersectionDegenerateScenario(Segment2D segment1, Segment2D segment2) + { + return IsSegmentActuallyPointDegenerate(segment1) || IsSegmentActuallyPointDegenerate(segment2); + } + + private static bool IsSegmentActuallyPointDegenerate(Segment2D segment) + { + return segment.Length < epsilonForComparisons; + } + + private static Segment2DIntersectSegment2DResult HandleSegmentAsPointIntersectionDegenerates(Segment2D segment1, Segment2D segment2) + { + bool segment1IsPointDegenerate = IsSegmentActuallyPointDegenerate(segment1); + bool segment2IsPointDegenerate = IsSegmentActuallyPointDegenerate(segment2); + + if (segment1IsPointDegenerate) + { + if (segment2IsPointDegenerate) + { + // Both segments can be considered Point2D + return segment1.FirstPoint.Equals(segment2.FirstPoint) ? + Segment2DIntersectSegment2DResult.CreateIntersectionResult(segment1.FirstPoint) : + Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + } + { + return IsPointInCollinearSegment(segment1.FirstPoint, segment2) ? + Segment2DIntersectSegment2DResult.CreateIntersectionResult(segment1.FirstPoint) : + Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + } + + } + + return IsPointInCollinearSegment(segment2.FirstPoint, segment1) ? + Segment2DIntersectSegment2DResult.CreateIntersectionResult(segment2.FirstPoint) : + Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + } + + private static bool IsPointInCollinearSegment(Point2D point, Segment2D colinearSegment) + { + if (colinearSegment.IsVertical()) + { + double minY = Math.Min(colinearSegment.FirstPoint.Y, colinearSegment.SecondPoint.Y); + double maxY = Math.Max(colinearSegment.FirstPoint.Y, colinearSegment.SecondPoint.Y); + return minY <= point.Y && point.Y <= maxY; + } + else + { + double minX = Math.Min(colinearSegment.FirstPoint.X, colinearSegment.SecondPoint.X); + double maxX = Math.Max(colinearSegment.FirstPoint.X, colinearSegment.SecondPoint.X); + return minX <= point.X && point.X <= maxX; + } + } + + /// + /// Gets the intersection point. + /// + /// The segment1. + /// The segment2. + /// + /// Implementation from http://geomalgorithms.com/a05-_intersect-1.html + /// based on method intersect2D_2Segments. private static Point2D GetIntersectionPoint(Segment2D segment1, Segment2D segment2) { var aLine = (segment1.FirstPoint.Y - segment2.FirstPoint.Y)*(segment2.SecondPoint.X - segment2.FirstPoint.X) - (segment1.FirstPoint.X - segment2.FirstPoint.X)*(segment2.SecondPoint.Y - segment2.FirstPoint.Y); @@ -251,6 +425,33 @@ return null; } + /// + /// Performs the dot product between a vector and a perpendicularized vector. + /// + /// The vector. + /// The vector that will be made perpendicular before doing + /// the dot product operation. + /// The dot product between a vector and a perpendicularized vector. + private static double PerpDotProduct(Vector vector1, Vector vector2) + { + Vector perpendicularVectorForVector2 = ToPerpendicular(vector2); + return vector1.DotProduct(perpendicularVectorForVector2); + } + + /// + /// Creates a new based on a vector that is perpendicular. + /// + /// The vector. + /// A vector of the same length as . + private static Vector ToPerpendicular(Vector vector) + { + return new DenseVector(new[] + { + -vector[1], + vector[0] + }); + } + private static Point2D[][] SplitLineSegmentsAtLengths(Segment2D[] lineSegments, double[] lengths) { var splitResults = new Point2D[lengths.Length][]; @@ -310,11 +511,8 @@ private static Point2D GetInterpolatedPoint(Segment2D lineSegment, double splitDistance) { var interpolationFactor = splitDistance/lineSegment.Length; - Vector segmentVector = lineSegment.SecondPoint - lineSegment.FirstPoint; - double interpolatedX = lineSegment.FirstPoint.X + interpolationFactor*segmentVector[0]; - double interpolatedY = lineSegment.FirstPoint.Y + interpolationFactor*segmentVector[1]; - - return new Point2D(interpolatedX, interpolatedY); + Vector segmentVector = lineSegment.SecondPoint - lineSegment.FirstPoint; + return lineSegment.FirstPoint + segmentVector.Multiply(interpolationFactor); } /// Index: Core/Common/src/Core.Common.Base/Geometry/Point2D.cs =================================================================== diff -u -re04155c0cc0efa8bbd13e0a82cb8643711a2dfd6 -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/src/Core.Common.Base/Geometry/Point2D.cs (.../Point2D.cs) (revision e04155c0cc0efa8bbd13e0a82cb8643711a2dfd6) +++ Core/Common/src/Core.Common.Base/Geometry/Point2D.cs (.../Point2D.cs) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -21,6 +21,9 @@ using System; +using Core.Common.Base.Properties; + +using MathNet.Numerics.LinearAlgebra; using MathNet.Numerics.LinearAlgebra.Double; namespace Core.Common.Base.Geometry @@ -58,7 +61,7 @@ /// Head of the vector. /// Tail of the vector. /// A 2D vector. - public static Vector operator -(Point2D p1, Point2D p2) + public static Vector operator -(Point2D p1, Point2D p2) { var result = new DenseVector(2); result[0] = p1.X - p2.X; @@ -67,6 +70,29 @@ } /// + /// Determines the new 2D point given a point and a 2D vector. + /// + /// The point. + /// The 2D vector. + /// + /// A 2D point. + /// + /// When is + /// not a 2D vector. + public static Point2D operator +(Point2D point, Vector vector) + { + if (vector.Count != 2) + { + string message = string.Format(Resources.Point2D_AddVector_Vector_must_be_2D_but_has_Dimensionality_0_, + vector.Count); + throw new ArgumentException(message, "vector"); + } + double x = point.X + vector[0]; + double y = point.Y + vector[1]; + return new Point2D(x, y); + } + + /// /// Gets the euclidean distance from this point to another. /// /// The second point. @@ -79,7 +105,7 @@ throw new ArgumentNullException("secondPoint"); } - Vector vector = this - secondPoint; + Vector vector = this - secondPoint; return Math.Sqrt(vector.DotProduct(vector)); } Index: Core/Common/src/Core.Common.Base/Geometry/Segment2D.cs =================================================================== diff -u -re04155c0cc0efa8bbd13e0a82cb8643711a2dfd6 -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/src/Core.Common.Base/Geometry/Segment2D.cs (.../Segment2D.cs) (revision e04155c0cc0efa8bbd13e0a82cb8643711a2dfd6) +++ Core/Common/src/Core.Common.Base/Geometry/Segment2D.cs (.../Segment2D.cs) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -23,7 +23,7 @@ using Core.Common.Base.Properties; -using MathNet.Numerics.LinearAlgebra.Double; +using MathNet.Numerics.LinearAlgebra; namespace Core.Common.Base.Geometry { @@ -108,8 +108,8 @@ throw new ArgumentNullException("point"); } - Vector segmentVector = SecondPoint - FirstPoint; // Vector from FirstPoint to SecondPoint - Vector orientationVector = point - FirstPoint; // Vector from FirstPoint to 'point' + Vector segmentVector = SecondPoint - FirstPoint; // Vector from FirstPoint to SecondPoint + Vector orientationVector = point - FirstPoint; // Vector from FirstPoint to 'point' // Situation sketch, normalized along the segment: // A : B : C Index: Core/Common/src/Core.Common.Base/Geometry/Segment2DIntersectSegment2DResult.cs =================================================================== diff -u --- Core/Common/src/Core.Common.Base/Geometry/Segment2DIntersectSegment2DResult.cs (revision 0) +++ Core/Common/src/Core.Common.Base/Geometry/Segment2DIntersectSegment2DResult.cs (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -0,0 +1,65 @@ +namespace Core.Common.Base.Geometry +{ + /// + /// Class that captures the intersection calculation result between two + /// instances. + /// + public class Segment2DIntersectSegment2DResult + { + private Segment2DIntersectSegment2DResult(Intersection2DType type, Point2D[] points) + { + IntersectionType = type; + IntersectionPoints = points; + } + + /// + /// Gets the type of the intersection found. + /// + public Intersection2DType IntersectionType { get; private set; } + + /// + /// Gets the intersection points, if any. + /// + /// + /// If has a value of , + /// the array holds the single intersection points found. + /// If has a value of , + /// the array holds the two points defining the overlapping area for both segments. + /// + public Point2D[] IntersectionPoints { get; private set; } + + /// + /// Creates the calculation result for having found no intersections. + /// + public static Segment2DIntersectSegment2DResult CreateNoIntersectResult() + { + return new Segment2DIntersectSegment2DResult(Intersection2DType.NoIntersections, new Point2D[0]); + } + + /// + /// Creates the calculation result for having found a single intersection. + /// + /// The intersection point. + public static Segment2DIntersectSegment2DResult CreateIntersectionResult(Point2D intersectionPoint) + { + return new Segment2DIntersectSegment2DResult(Intersection2DType.Intersects, new[] + { + intersectionPoint + }); + } + + /// + /// Creates the calculation result for having found an overlap between the two segments. + /// + /// The start of the overlapping segment. + /// The end of the overlapping segment. + public static Segment2DIntersectSegment2DResult CreateOverlapResult(Point2D start, Point2D end) + { + return new Segment2DIntersectSegment2DResult(Intersection2DType.Overlapping, new[] + { + start, + end + }); + } + } +} \ No newline at end of file Index: Core/Common/src/Core.Common.Base/Properties/Resources.Designer.cs =================================================================== diff -u -rd36a95d2e88d98b7b92ff5d091abf711d1dd31d9 -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/src/Core.Common.Base/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision d36a95d2e88d98b7b92ff5d091abf711d1dd31d9) +++ Core/Common/src/Core.Common.Base/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.17929 +// Runtime Version:4.0.30319.18444 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -152,6 +152,15 @@ } /// + /// Looks up a localized string similar to Vector moet 2 dimensies hebben, maar heeft er {0}.. + /// + public static string Point2D_AddVector_Vector_must_be_2D_but_has_Dimensionality_0_ { + get { + return ResourceManager.GetString("Point2D_AddVector_Vector_must_be_2D_but_has_Dimensionality_0_", resourceCulture); + } + } + + /// /// Looks up a localized string similar to Project. /// public static string Project_Constructor_Default_name { Index: Core/Common/src/Core.Common.Base/Properties/Resources.resx =================================================================== diff -u -rd36a95d2e88d98b7b92ff5d091abf711d1dd31d9 -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/src/Core.Common.Base/Properties/Resources.resx (.../Resources.resx) (revision d36a95d2e88d98b7b92ff5d091abf711d1dd31d9) +++ Core/Common/src/Core.Common.Base/Properties/Resources.resx (.../Resources.resx) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -165,4 +165,7 @@ De tekst is een getal dat te groot of te klein is om gerepresenteerd te worden. + + Vector moet 2 dimensies hebben, maar heeft er {0}. + \ No newline at end of file Index: Core/Common/test/Core.Common.Base.Test/Core.Common.Base.Test.csproj =================================================================== diff -u -r93b256575fba3e4068baadeeb62140533336371a -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/test/Core.Common.Base.Test/Core.Common.Base.Test.csproj (.../Core.Common.Base.Test.csproj) (revision 93b256575fba3e4068baadeeb62140533336371a) +++ Core/Common/test/Core.Common.Base.Test/Core.Common.Base.Test.csproj (.../Core.Common.Base.Test.csproj) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -86,6 +86,7 @@ + Index: Core/Common/test/Core.Common.Base.Test/Geometry/Math2DTest.cs =================================================================== diff -u -rd36a95d2e88d98b7b92ff5d091abf711d1dd31d9 -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/test/Core.Common.Base.Test/Geometry/Math2DTest.cs (.../Math2DTest.cs) (revision d36a95d2e88d98b7b92ff5d091abf711d1dd31d9) +++ Core/Common/test/Core.Common.Base.Test/Geometry/Math2DTest.cs (.../Math2DTest.cs) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -570,6 +570,273 @@ } [Test] + [TestCase(1234.56789)] + [TestCase(1e-6)] + [TestCase(-1e-6)] + [TestCase(-98765.4321)] + public void GetIntersectionBetweenSegments_TwoHorizontalParallelSegments_ReturnNoIntersection( + double dy) + { + // Setup + const double y1 = 2.2; + double y2 = y1+dy; + + const double x1 = 1.1; + const double x2 = 3.3; + var horizontalSegment1 = new Segment2D(new Point2D(x1, y1), new Point2D(x2, y1)); + var horizontalSegment2 = new Segment2D(new Point2D(x1, y2), new Point2D(x2, y2)); + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(horizontalSegment1, horizontalSegment2); + + // Assert + Assert.AreEqual(Intersection2DType.NoIntersections, result.IntersectionType); + CollectionAssert.IsEmpty(result.IntersectionPoints); + } + + [Test] + [TestCase(1234.56789)] + [TestCase(1e-6)] + [TestCase(-1e-6)] + [TestCase(-98765.4321)] + public void GetIntersectionBetweenSegments_TwoVerticalParallelSegments_ReturnNoIntersection( + double dx) + { + // Setup + const double x1 = 1.1; + double x2 = x1 + dx; + + const double y1 = 2.2; + const double y2 = 3.3; + var horizontalSegment1 = new Segment2D(new Point2D(x1, y1), new Point2D(x1, y2)); + var horizontalSegment2 = new Segment2D(new Point2D(x2, y1), new Point2D(x2, y2)); + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(horizontalSegment1, horizontalSegment2); + + // Assert + Assert.AreEqual(Intersection2DType.NoIntersections, result.IntersectionType); + CollectionAssert.IsEmpty(result.IntersectionPoints); + } + + [Test] + public void GetIntersectionBetweenSegments_TwoParallelSegments_ReturnNoIntersection() + { + // Setup + var segment1 = new Segment2D(new Point2D(1.1, 3.3), new Point2D(2.2, 4.4)); + var segment2 = new Segment2D(new Point2D(1.1, 5.5), new Point2D(2.2, 6.6)); + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(segment1, segment2); + + // Assert + Assert.AreEqual(Intersection2DType.NoIntersections, result.IntersectionType); + CollectionAssert.IsEmpty(result.IntersectionPoints); + } + + [Test] + [TestCase(12.34)] + [TestCase(1.1 + 1e-6)] + [TestCase(-1.1 - 1e-6)] + [TestCase(-56.78)] + public void GetIntersectionBetweenSegments_TwoCollinearHorizontalLinesWithoutOverlap_ReturnNoIntersection(double dy) + { + // Setup + const double x1 = 1.1; + const double x2 = 2.2; + const double y = 3.3; + + double x3 = x1 + dy; + double x4 = x2 + dy; + var horizontalSegment1 = new Segment2D(new Point2D(x1, y), new Point2D(x2, y)); + var horizontalSegment2 = new Segment2D(new Point2D(x3, y), new Point2D(x4, y)); + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(horizontalSegment1, horizontalSegment2); + + // Assert + Assert.AreEqual(Intersection2DType.NoIntersections, result.IntersectionType); + CollectionAssert.IsEmpty(result.IntersectionPoints); + } + + [Test] + [TestCase(12.34)] + [TestCase(3.3 + 1e-6)] + [TestCase(-3.3 - 1e-6)] + [TestCase(-56.78)] + public void GetIntersectionBetweenSegments_TwoCollinearVerticalLinesWithoutOverlap_ReturnNoIntersection(double dy) + { + // Setup + const double y1 = 1.1; + const double y2 = 4.4; + const double x = 3.3; + + double y3 = y2 + dy; + double y4 = y1 + dy; + var horizontalSegment1 = new Segment2D(new Point2D(x, y1), new Point2D(x, y2)); + var horizontalSegment2 = new Segment2D(new Point2D(x, y3), new Point2D(x, y4)); + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(horizontalSegment1, horizontalSegment2); + + // Assert + Assert.AreEqual(Intersection2DType.NoIntersections, result.IntersectionType); + CollectionAssert.IsEmpty(result.IntersectionPoints); + } + + [Test] + [TestCase(-3.3)] + [TestCase(7.7)] + public void GetIntersectionBetweenSegments_TwoCollinearSegmentsWithoutOverlap_ReturnNoIntersection( + double dx) + { + // Setup + Func getY = x => 1.1 * x + 2.2; + const double x1 = 1.1; + const double x2 = 3.3; + var segment1 = new Segment2D(new Point2D(x1, getY(x1)), new Point2D(x2, getY(x2))); + + double x3 = x1 + dx; + double x4 = x2 + dx; + var segment2 = new Segment2D(new Point2D(x3, getY(x3)), new Point2D(x4, getY(x4))); + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(segment1, segment2); + + // Assert + Assert.AreEqual(Intersection2DType.NoIntersections, result.IntersectionType); + CollectionAssert.IsEmpty(result.IntersectionPoints); + } + + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + public void GetIntersectionBetweenSegments_TwoCollinearHorizontalSegmentsConnectedAtSegmentEnds_ReturnIntersectionPoint( + int configurationNumber) + { + // Setup + const double y = -6.7; + var segment1UniquePoint = new Point2D(-12.34, y); + var segmentCommonPoint = new Point2D(56.78, y); + var segment2UniquePoint = new Point2D(91.23, y); + + Segment2D horizontalSegment1, horizontalSegment2; + if (configurationNumber == 0 || configurationNumber == 3) + { + horizontalSegment1 = new Segment2D(segment1UniquePoint, segmentCommonPoint); + } + else + { + horizontalSegment1 = new Segment2D(segmentCommonPoint, segment1UniquePoint); + } + + if (configurationNumber == 0 || configurationNumber == 1) + { + horizontalSegment2 = new Segment2D(segment2UniquePoint, segmentCommonPoint); + } + else + { + horizontalSegment2 = new Segment2D(segmentCommonPoint, segment2UniquePoint); + } + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(horizontalSegment1, horizontalSegment2); + + // Assert + Assert.AreEqual(Intersection2DType.Intersects, result.IntersectionType); + CollectionAssert.AreEqual(new[] { segmentCommonPoint }, result.IntersectionPoints); + } + + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + public void GetIntersectionBetweenSegments_TwoCollinearVerticalSegmentsConnectedAtSegmentEnds_ReturnIntersectionPoint( + int configurationNumber) + { + // Setup + const double x = 5.5; + var segment1UniquePoint = new Point2D(x, -23.45); + var segmentCommonPoint = new Point2D(x, -12.34); + var segment2UniquePoint = new Point2D(x, 90.76); + + Segment2D verticalSegment1, verticalSegment2; + if (configurationNumber == 0 || configurationNumber == 3) + { + verticalSegment1 = new Segment2D(segment1UniquePoint, segmentCommonPoint); + } + else + { + verticalSegment1 = new Segment2D(segmentCommonPoint, segment1UniquePoint); + } + + if (configurationNumber == 0 || configurationNumber == 1) + { + verticalSegment2 = new Segment2D(segment2UniquePoint, segmentCommonPoint); + } + else + { + verticalSegment2 = new Segment2D(segmentCommonPoint, segment2UniquePoint); + } + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(verticalSegment1, verticalSegment2); + + // Assert + Assert.AreEqual(Intersection2DType.Intersects, result.IntersectionType); + CollectionAssert.AreEqual(new[] { segmentCommonPoint }, result.IntersectionPoints, + new Point2DComparerWithTolerance(1e-6)); + } + + [Test] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + public void GetIntersectionBetweenSegments_TwoCollinearSegmentsConnectedAtSegmentEnds_ReturnIntersectionPoint( + int configurationNumber) + { + // Setup + Func getY = x => 3.3 * x + 4.4; + + const double x1 = 5.5; + const double x2 = 6.6; + const double x3 = 8.8; + var segment1UniquePoint = new Point2D(x1, getY(x1)); + var segmentCommonPoint = new Point2D(x2, getY(x2)); + var segment2UniquePoint = new Point2D(x3, getY(x3)); + + Segment2D segment1, segment2; + if (configurationNumber == 0 || configurationNumber == 3) + { + segment1 = new Segment2D(segment1UniquePoint, segmentCommonPoint); + } + else + { + segment1 = new Segment2D(segmentCommonPoint, segment1UniquePoint); + } + + if (configurationNumber == 0 || configurationNumber == 1) + { + segment2 = new Segment2D(segment2UniquePoint, segmentCommonPoint); + } + else + { + segment2 = new Segment2D(segmentCommonPoint, segment2UniquePoint); + } + + // Call + Segment2DIntersectSegment2DResult result = Math2D.GetIntersectionBetweenSegments(segment1, segment2); + + // Assert + Assert.AreEqual(Intersection2DType.Intersects, result.IntersectionType); + CollectionAssert.AreEqual(new[]{segmentCommonPoint}, result.IntersectionPoints); + } + + [Test] public void AreEqualPoints_PointsEqual_ReturnsTrue() { // Call Index: Core/Common/test/Core.Common.Base.Test/Geometry/Point2DTest.cs =================================================================== diff -u -re04155c0cc0efa8bbd13e0a82cb8643711a2dfd6 -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Core/Common/test/Core.Common.Base.Test/Geometry/Point2DTest.cs (.../Point2DTest.cs) (revision e04155c0cc0efa8bbd13e0a82cb8643711a2dfd6) +++ Core/Common/test/Core.Common.Base.Test/Geometry/Point2DTest.cs (.../Point2DTest.cs) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -22,7 +22,9 @@ using System; using Core.Common.Base.Geometry; +using Core.Common.TestUtil; +using MathNet.Numerics.LinearAlgebra; using MathNet.Numerics.LinearAlgebra.Double; using NUnit.Framework; @@ -164,7 +166,7 @@ var point2 = new Point2D(1.0, 1.0); // Call - Vector vector = point1 - point2; + Vector vector = point1 - point2; // Assert Assert.AreEqual(2, vector.Count); @@ -173,6 +175,61 @@ } [Test] + public void AddOperator_PointWithZeroVector_ReturnEqualPoint( + [Random(-12345.6789, 9876.54321, 1)]double x, + [Random(-12345.6789, 9876.54321, 1)]double y) + { + // Setup + var originalPoint = new Point2D(x, y); + var zeroVector = new DenseVector(new []{ 0.0, 0.0 }); + + // Call + Point2D resultPoint = originalPoint + zeroVector; + + // Assert + Assert.AreNotSame(originalPoint, resultPoint); + Assert.AreEqual(x, resultPoint.X); + Assert.AreEqual(y, resultPoint.Y); + } + + [Test] + public void AddOperator_PointWithVector_ReturnEqualPoint( + [Random(-12345.6789, 98765.4321, 1)]double x, + [Random(-12345.6789, 98765.4321, 1)]double y) + { + // Setup + var originalPoint = new Point2D(x, y); + const double dx = 1.1; + const double dy = -2.2; + var vector = new DenseVector(new[] { dx, dy }); + + // Call + Point2D resultPoint = originalPoint + vector; + + // Assert + Assert.AreEqual(x+dx, resultPoint.X); + Assert.AreEqual(y+dy, resultPoint.Y); + } + + [Test] + public void AddOperator_PointWithInvalidVector_ThrowArgumentException() + { + // Setup + var originalPoint = new Point2D(0.0, 0.0); + var vector3D = new DenseVector(new []{1.1, 2.2, 3.3}); + + // Call + TestDelegate call = () => + { + Point2D result = originalPoint + vector3D; + }; + + // Assert + const string expectedMessage = "Vector moet 2 dimensies hebben, maar heeft er 3."; + TestHelper.AssertThrowsArgumentExceptionAndTestMessage(call, expectedMessage); + } + + [Test] public void GetEuclideanDistanceTo_Itself_ReturnZero() { // Setup Index: Core/Common/test/Core.Common.Base.Test/Geometry/Segment2DIntersectSegment2DResultTest.cs =================================================================== diff -u --- Core/Common/test/Core.Common.Base.Test/Geometry/Segment2DIntersectSegment2DResultTest.cs (revision 0) +++ Core/Common/test/Core.Common.Base.Test/Geometry/Segment2DIntersectSegment2DResultTest.cs (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -0,0 +1,50 @@ +using Core.Common.Base.Geometry; + +using NUnit.Framework; + +namespace Core.Common.Base.Test.Geometry +{ + [TestFixture] + public class Segment2DIntersectSegment2DResultTest + { + [Test] + public void CreateNoIntersectResult_ExpectedValues() + { + // Call + Segment2DIntersectSegment2DResult result = Segment2DIntersectSegment2DResult.CreateNoIntersectResult(); + + // Assert + Assert.AreEqual(Intersection2DType.NoIntersections, result.IntersectionType); + CollectionAssert.IsEmpty(result.IntersectionPoints); + } + + [Test] + public void CreateIntersectionResult_ExpectedValues() + { + // Setup + var point = new Point2D(1.1, 2.2); + + // Call + Segment2DIntersectSegment2DResult result = Segment2DIntersectSegment2DResult.CreateIntersectionResult(point); + + // Assert + Assert.AreEqual(Intersection2DType.Intersects, result.IntersectionType); + CollectionAssert.AreEqual(new[]{point}, result.IntersectionPoints); + } + + [Test] + public void CreateOverlapResult_ExpectedValues() + { + // Setup + var point1 = new Point2D(1.1, 2.2); + var point2 = new Point2D(1.1, 2.2); + + // Call + Segment2DIntersectSegment2DResult result = Segment2DIntersectSegment2DResult.CreateOverlapResult(point1, point2); + + // Assert + Assert.AreEqual(Intersection2DType.Overlapping, result.IntersectionType); + CollectionAssert.AreEqual(new[] { point1, point2 }, result.IntersectionPoints); + } + } +} \ No newline at end of file Index: Ringtoets/Piping/src/Ringtoets.Piping.Primitives/RingtoetsPipingSurfaceLine.cs =================================================================== diff -u -r10779bb6a6db2d00f4627b2bc190e7e35e1fee3e -r1b4f4720632f9a691837fa97e777a4637b6739c8 --- Ringtoets/Piping/src/Ringtoets.Piping.Primitives/RingtoetsPipingSurfaceLine.cs (.../RingtoetsPipingSurfaceLine.cs) (revision 10779bb6a6db2d00f4627b2bc190e7e35e1fee3e) +++ Ringtoets/Piping/src/Ringtoets.Piping.Primitives/RingtoetsPipingSurfaceLine.cs (.../RingtoetsPipingSurfaceLine.cs) (revision 1b4f4720632f9a691837fa97e777a4637b6739c8) @@ -24,7 +24,8 @@ using System.Collections.ObjectModel; using System.Linq; using Core.Common.Base.Geometry; -using MathNet.Numerics.LinearAlgebra.Double; + +using MathNet.Numerics.LinearAlgebra; using Ringtoets.Piping.Primitives.Exceptions; using Ringtoets.Piping.Primitives.Properties; @@ -371,14 +372,14 @@ // Determine the vectors from the first coordinate to each other coordinate point // in the XY world coordinate plane: Point2D[] worldCoordinates = Points.Select(p => new Point2D(p.X, p.Y)).ToArray(); - var worldCoordinateVectors = new Vector[worldCoordinates.Length - 1]; + var worldCoordinateVectors = new Vector[worldCoordinates.Length - 1]; for (int i = 1; i < worldCoordinates.Length; i++) { worldCoordinateVectors[i - 1] = worldCoordinates[i] - worldCoordinates[0]; } // Determine the 'spanning line' vector: - Vector spanningVector = worldCoordinateVectors[worldCoordinateVectors.Length - 1]; + Vector spanningVector = worldCoordinateVectors[worldCoordinateVectors.Length - 1]; double spanningVectorDotProduct = spanningVector.DotProduct(spanningVector); double length = Math.Sqrt(spanningVectorDotProduct);