From 0a2521d22e32f920b8571b4e3a7d575b0e102c02 Mon Sep 17 00:00:00 2001 From: f-frhs Date: Thu, 17 Aug 2023 23:11:06 +0900 Subject: [PATCH 01/25] Feat: Line2D.DistanceTo(point) --- src/Spatial.Tests/Euclidean/Line2DTests.cs | 25 ++++++++ src/Spatial/Euclidean/Line2D.cs | 67 ++++++++++++++++++++-- 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Line2DTests.cs b/src/Spatial.Tests/Euclidean/Line2DTests.cs index b4a5fc5..61def30 100644 --- a/src/Spatial.Tests/Euclidean/Line2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Line2DTests.cs @@ -210,5 +210,30 @@ public void ToStringCheck() Assert.AreEqual("StartPoint: (0,\u00A00), EndPoint: (1,\u00A01)", check); } + + [TestCase("0,0", "1,0", "0,1",-1)] + [TestCase("0,0", "1,0", "0,2", -2)] + [TestCase("0,0", "0,1", "2,0", +2)] + public void SignedDistanceTo(string sp1, string sp2, string sp, double expectedDistance) + { + var line = Line2D.Parse(sp1, sp2); + var point = Point2D.Parse(sp); + + var actual = line.SignedDistanceTo(point); + Assert.That(actual, Is.EqualTo(expectedDistance)); + } + + + [TestCase("0,0", "1,0", "0,1", 1)] + [TestCase("0,0", "1,0", "0,2", 2)] + [TestCase("0,0", "0,1", "2,0", 2)] + public void DistanceTo(string sp1, string sp2, string sp, double expectedDistance) + { + var line = Line2D.Parse(sp1, sp2); + var point = Point2D.Parse(sp); + + var actual = line.DistanceTo(point); + Assert.That(actual, Is.EqualTo(expectedDistance)); + } } } diff --git a/src/Spatial/Euclidean/Line2D.cs b/src/Spatial/Euclidean/Line2D.cs index d1c516a..488fe0e 100644 --- a/src/Spatial/Euclidean/Line2D.cs +++ b/src/Spatial/Euclidean/Line2D.cs @@ -1,12 +1,12 @@ -using System; -using System.Diagnostics.Contracts; -using System.Xml.Schema; -using System.Xml; -using System.Xml.Serialization; -using MathNet.Numerics; +using MathNet.Numerics; using MathNet.Spatial.Internals; using MathNet.Spatial.Units; +using System; +using System.Diagnostics.Contracts; +using System.Xml; using System.Xml.Linq; +using System.Xml.Schema; +using System.Xml.Serialization; namespace MathNet.Spatial.Euclidean { @@ -27,6 +27,21 @@ public struct Line2D : IEquatable, IXmlSerializable /// public Point2D EndPoint { get; private set; } + /// + /// The parameter `a` in the line equation: ax + by + c = 0 + /// + public double A { get; private set; } + + /// + /// The parameter `b` in the line equation: ax + by + c = 0 + /// + public double B { get; private set; } + + /// + /// The parameter `c` in the line equation: ax + by + c = 0 + /// + public double C { get; private set; } + /// /// Initializes a new instance of the struct. /// Throws an ArgumentException if the is equal to the . @@ -40,8 +55,27 @@ public Line2D(Point2D startPoint, Point2D endPoint) throw new ArgumentException("The Line2D starting and ending points cannot be identical"); } + //substitution + //points StartPoint = startPoint; EndPoint = endPoint; + + //doubles + var x1 = startPoint.X; + var x2 = endPoint.X; + var y1 = startPoint.Y; + var y2 = endPoint.Y; + + //computation + var a = y2 - y1; + var b = x1 - x2; + var c = (x2 - x1) * y1 - (y2 - y1) * x1; + + //normalize + var length = Math.Sqrt(a * a + b * b); + A = a / length; + B = b / length; + C = c / length; } /// @@ -294,5 +328,26 @@ void IXmlSerializable.WriteXml(XmlWriter writer) writer.WriteElement("StartPoint", StartPoint); writer.WriteElement("EndPoint", EndPoint); } + + /// + /// Compute the signed distance from this `line` to the given point `p`. If the sign of the distance is positive, the normal vector from the line is in the same side to the point. + /// + /// + /// + public double SignedDistanceTo(Point2D p) + { + var result = A * p.X + B * p.Y + C; + return result; + } + + /// + /// Compute the absolute distance from this `line` to the given point `p`. + /// + /// + /// + public double DistanceTo(Point2D p) + { + return Math.Abs(SignedDistanceTo(p)); + } } } From c3ad5902db4df7bbd96f8e5cc1cb4706dd644741 Mon Sep 17 00:00:00 2001 From: f-frhs Date: Thu, 23 Nov 2023 23:34:06 +0900 Subject: [PATCH 02/25] feat: Circle2D.IntersectWith(Line2D) --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 15 ++++++ src/Spatial/Euclidean/Circle2D.cs | 48 ++++++++++++++++++++ src/Spatial/Extensions/DoubleExtensions.cs | 21 +++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/Spatial/Extensions/DoubleExtensions.cs diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 7d3d0df..57c7f0e 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -58,5 +58,20 @@ public void CircleFromThreePointsArgumentException() Assert.Throws(() => { Circle2D.FromPoints(p1, p2, p3); }); } + + [TestCase("0,0", 1.41421356/*=sqrt(2)*/, "-1,-1", "+1,+1", "-1,-1", "+1,+1")] + [TestCase("0,0", 1, "-1,0", "+1,0", "-1,0", "+1,0")] + [TestCase("0,0", 1, "-1,0", "+1,0", "-1,0", "+1,0")] + public void CircleIntersectWithLine2D(string sc, double radius, string sps, string spe, string esp0, string esp1) + { + var circle = new Circle2D(Point2D.Parse(sc), radius); + var line = new Line2D(Point2D.Parse(sps), Point2D.Parse(spe)); + var actual = circle.IntersectWith(line); + Assert.That(actual.Length, Is.EqualTo(2)); + + var expected = new [] { Point2D.Parse(esp0), Point2D.Parse(esp1) }; + AssertGeometry.AreEqual(actual[0], expected[0]); + AssertGeometry.AreEqual(actual[1], expected[1]); + } } } diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index 96edea3..0391a4d 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -1,10 +1,12 @@ using MathNet.Spatial.Internals; using System; using System.Diagnostics.Contracts; +using System.Linq; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using HashCode = MathNet.Spatial.Internals.HashCode; +using MathNet.Spatial.Extensions; namespace MathNet.Spatial.Euclidean { @@ -131,6 +133,52 @@ public static Circle2D FromPoints(Point2D pointA, Point2D pointB, Point2D pointC return new Circle2D(center, radius); } + /// + /// Returns intersection as a point2D array if this circle and the given line have the intersections + /// + /// the given line + /// intersections as a Point2D Array, depending on the count. + public Point2D[] IntersectWith(Line2D line) + { + // These 2 equations in vector form can be described + // (p-cc)^2=r^2 (eq1) + // p=s+t*d (eq2) + // , where p is the point on the line and/or circle, + // cc is the center of the circle and + // r is the radius of the circle. + // Substituting (eq2) into (eq1) yields: + // ((s+t*d)-c)^2=r^2 (eq3) + // (eq3) reduces to the following quadratic equation: a*t^2 + b*t + c==0 + + var cc = Center.ToVector2D(); //center of circle + var s = line.StartPoint.ToVector2D(); + var d = line.Direction; + var r = Radius; + + var a = d.DotProduct(d); + var b = 2 * (s.DotProduct(d) - d.DotProduct(cc)); + var c = (s-cc).DotProduct(s-cc) - r * r; + + var discriminant = b * b - 4 * a * c; + if (discriminant < 0) + { + return new Point2D[] { }; // no intersections found. + } + + if (discriminant.IsNearlyEqualTo(0, 1e-6)) + { + var t = -b / (2 * a); + return new[] { Point2D.OfVector((s + t * d).ToVector()) }; + } + + + var t1 = (-b - Math.Sqrt(b * b - 4 * a * c)) / (2 * a); + var t2 = (-b + Math.Sqrt(b * b - 4 * a * c)) / (2 * a); + var ts = new double[] { t1, t2 }; + var result = ts.Select(t => Point2D.OfVector((s + t * d).ToVector())).ToArray(); + return result; + } + /// /// Returns a value to indicate if a pair of circles are equal /// diff --git a/src/Spatial/Extensions/DoubleExtensions.cs b/src/Spatial/Extensions/DoubleExtensions.cs new file mode 100644 index 0000000..c7a64ea --- /dev/null +++ b/src/Spatial/Extensions/DoubleExtensions.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MathNet.Spatial.Extensions +{ + internal static class DoubleExtensions + { + internal static bool IsNearlyEqualTo(this double d, double reference, double tolerance) + { + if (tolerance < 0) + { + throw new ArgumentOutOfRangeException(nameof(tolerance)); + } + return Math.Abs(d-reference) < tolerance; + } + } +} From 037d3c52c5d684b6f6220e3174cc1a3e45b7daac Mon Sep 17 00:00:00 2001 From: f-frhs Date: Fri, 24 Nov 2023 16:15:18 +0900 Subject: [PATCH 03/25] doc: fix xml comment --- src/Spatial/Euclidean/Circle2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index 0391a4d..aea4925 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -134,7 +134,7 @@ public static Circle2D FromPoints(Point2D pointA, Point2D pointB, Point2D pointC } /// - /// Returns intersection as a point2D array if this circle and the given line have the intersections + /// Returns intersection a point2D array if this circle and the given line have the intersections /// /// the given line /// intersections as a Point2D Array, depending on the count. From fb0314bb8a14bd9e06a1cd33a323061debab120b Mon Sep 17 00:00:00 2001 From: f-frhs Date: Sat, 25 Nov 2023 20:05:25 +0900 Subject: [PATCH 04/25] refactor: extract the private method findParameterTs(Line2D) Aleady existing test cases must be changed because of the implementation of FindRoots.Polynomial(coeffs), that is, the order of the solutions. --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 8 +++--- src/Spatial/Euclidean/Circle2D.cs | 30 ++++++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 57c7f0e..fa7d563 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using MathNet.Spatial.Euclidean; using NUnit.Framework; @@ -59,9 +59,9 @@ public void CircleFromThreePointsArgumentException() Assert.Throws(() => { Circle2D.FromPoints(p1, p2, p3); }); } - [TestCase("0,0", 1.41421356/*=sqrt(2)*/, "-1,-1", "+1,+1", "-1,-1", "+1,+1")] - [TestCase("0,0", 1, "-1,0", "+1,0", "-1,0", "+1,0")] - [TestCase("0,0", 1, "-1,0", "+1,0", "-1,0", "+1,0")] + [TestCase("0,0", 1.41421356 /*=sqrt(2)*/, "-1,-1", "+1,+1", "+1,+1", "-1,-1")] + [TestCase("0,0", 1, "-1,0", "+1,0", "+1,0", "-1,0")] + [TestCase("0,0", 1, "0,-1", "0,+1", "0,+1", "0,-1")] public void CircleIntersectWithLine2D(string sc, double radius, string sps, string spe, string esp0, string esp1) { var circle = new Circle2D(Point2D.Parse(sc), radius); diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index aea4925..ebf2bca 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -1,10 +1,11 @@ -using MathNet.Spatial.Internals; +using MathNet.Spatial.Internals; using System; using System.Diagnostics.Contracts; using System.Linq; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; +using MathNet.Numerics; using HashCode = MathNet.Spatial.Internals.HashCode; using MathNet.Spatial.Extensions; @@ -139,6 +140,15 @@ public static Circle2D FromPoints(Point2D pointA, Point2D pointB, Point2D pointC /// the given line /// intersections as a Point2D Array, depending on the count. public Point2D[] IntersectWith(Line2D line) + { + var ts = this.findParameterTs(line); + var result = ts + .Select(t => line.StartPoint + t * line.Direction) + .ToArray(); + return result; + } + + private double[] findParameterTs(Line2D line) { // These 2 equations in vector form can be described // (p-cc)^2=r^2 (eq1) @@ -150,20 +160,22 @@ public Point2D[] IntersectWith(Line2D line) // ((s+t*d)-c)^2=r^2 (eq3) // (eq3) reduces to the following quadratic equation: a*t^2 + b*t + c==0 - var cc = Center.ToVector2D(); //center of circle + var cc = this.Center.ToVector2D(); //center of circle var s = line.StartPoint.ToVector2D(); var d = line.Direction; - var r = Radius; + var r = this.Radius; var a = d.DotProduct(d); var b = 2 * (s.DotProduct(d) - d.DotProduct(cc)); - var c = (s-cc).DotProduct(s-cc) - r * r; + var c = (s - cc).DotProduct(s - cc) - r * r; - var discriminant = b * b - 4 * a * c; - if (discriminant < 0) - { - return new Point2D[] { }; // no intersections found. - } + var soluions = FindRoots.Polynomial(new[] { c, b, a }); + var ts = soluions + .Where(z => z.IsReal()) + .Select(z => z.Real) + .ToArray(); + return ts; + } if (discriminant.IsNearlyEqualTo(0, 1e-6)) { From baf660560fe8606bedf7efa512970e3a301591c6 Mon Sep 17 00:00:00 2001 From: f-frhs Date: Sat, 25 Nov 2023 20:07:48 +0900 Subject: [PATCH 05/25] feat: Circle2D.IntersectWith(LineSegment2D) --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 18 +++++++++++++-- src/Spatial/Euclidean/Circle2D.cs | 24 ++++++++++---------- src/Spatial/Euclidean/LineSegment2D.cs | 4 ++++ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index fa7d563..7f5322b 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using MathNet.Spatial.Euclidean; using NUnit.Framework; @@ -69,9 +69,23 @@ public void CircleIntersectWithLine2D(string sc, double radius, string sps, stri var actual = circle.IntersectWith(line); Assert.That(actual.Length, Is.EqualTo(2)); - var expected = new [] { Point2D.Parse(esp0), Point2D.Parse(esp1) }; + var expected = new[] { Point2D.Parse(esp0), Point2D.Parse(esp1) }; AssertGeometry.AreEqual(actual[0], expected[0]); AssertGeometry.AreEqual(actual[1], expected[1]); } + + [TestCase("0,0", 1.41421356 /*=sqrt(2)*/, "0,0", "+1,+1", "+1,+1")] + [TestCase("0,0", 1, "0,0", "+1,0", "+1,0")] + [TestCase("0,0", 1, "0,0", "0,+1", "0,+1")] + public void CircleIntersectWithLineSegment2D(string sCenter, double radius, string sStart, string sEnd, string sExpected) + { + var circle = new Circle2D(Point2D.Parse(sCenter), radius); + var segment = new LineSegment2D(Point2D.Parse(sStart), Point2D.Parse(sEnd)); + var actual = circle.IntersectWith(segment); + Assert.That(actual.Length, Is.EqualTo(1)); + + var expected = Point2D.Parse(sExpected); + AssertGeometry.AreEqual(actual[0], expected); + } } } diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index ebf2bca..df3ec63 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -1,4 +1,4 @@ -using MathNet.Spatial.Internals; +using MathNet.Spatial.Internals; using System; using System.Diagnostics.Contracts; using System.Linq; @@ -177,20 +177,20 @@ private double[] findParameterTs(Line2D line) return ts; } - if (discriminant.IsNearlyEqualTo(0, 1e-6)) - { - var t = -b / (2 * a); - return new[] { Point2D.OfVector((s + t * d).ToVector()) }; - } - - - var t1 = (-b - Math.Sqrt(b * b - 4 * a * c)) / (2 * a); - var t2 = (-b + Math.Sqrt(b * b - 4 * a * c)) / (2 * a); - var ts = new double[] { t1, t2 }; - var result = ts.Select(t => Point2D.OfVector((s + t * d).ToVector())).ToArray(); + /// + /// Returns intersection a point2D array if this circle and the given line have the intersections + /// + /// the given line-segment + /// intersections as a Point2D Array, depending on the count. + public Point2D[] IntersectWith(LineSegment2D line) + { + var ts = findParameterTs(line.ToLine2D()) + .Where(t => 0 <= t && t <= line.Length); + var result = ts.Select(t => line.StartPoint + t * line.Direction).ToArray(); return result; } + /// /// Returns a value to indicate if a pair of circles are equal /// diff --git a/src/Spatial/Euclidean/LineSegment2D.cs b/src/Spatial/Euclidean/LineSegment2D.cs index 2cc701c..22b4d4c 100644 --- a/src/Spatial/Euclidean/LineSegment2D.cs +++ b/src/Spatial/Euclidean/LineSegment2D.cs @@ -236,5 +236,9 @@ void IXmlSerializable.WriteXml(XmlWriter writer) writer.WriteElement("StartPoint", StartPoint); writer.WriteElement("EndPoint", EndPoint); } + + /// convert this to Line2D + /// converted Line2D object + public Line2D ToLine2D() => new Line2D(StartPoint, EndPoint); } } From c2612b61fa2c6f705522c5926f379ec404a77ca4 Mon Sep 17 00:00:00 2001 From: f-frhs Date: Tue, 28 Nov 2023 22:46:43 +0900 Subject: [PATCH 06/25] doc: fix the variable-name list in comment --- src/Spatial/Euclidean/Circle2D.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index df3ec63..a3d8fff 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -154,8 +154,11 @@ private double[] findParameterTs(Line2D line) // (p-cc)^2=r^2 (eq1) // p=s+t*d (eq2) // , where p is the point on the line and/or circle, - // cc is the center of the circle and - // r is the radius of the circle. + // c is the center of the circle, + // r is the radius of the circle, + // s is the starting point of the line, + // t is the parameter and + // d is the line direction. // Substituting (eq2) into (eq1) yields: // ((s+t*d)-c)^2=r^2 (eq3) // (eq3) reduces to the following quadratic equation: a*t^2 + b*t + c==0 From 46853020231c125173b804e8324c4496dba78165 Mon Sep 17 00:00:00 2001 From: f-frhs Date: Tue, 28 Nov 2023 22:48:58 +0900 Subject: [PATCH 07/25] fix: a typo --- src/Spatial/Euclidean/Circle2D.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index a3d8fff..ff0444a 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -154,13 +154,13 @@ private double[] findParameterTs(Line2D line) // (p-cc)^2=r^2 (eq1) // p=s+t*d (eq2) // , where p is the point on the line and/or circle, - // c is the center of the circle, + // cc is the center of the circle, // r is the radius of the circle, // s is the starting point of the line, // t is the parameter and // d is the line direction. // Substituting (eq2) into (eq1) yields: - // ((s+t*d)-c)^2=r^2 (eq3) + // ((s+t*d)-cc)^2=r^2 (eq3) // (eq3) reduces to the following quadratic equation: a*t^2 + b*t + c==0 var cc = this.Center.ToVector2D(); //center of circle From f3e4731f6b5a200841ca36fc8809ced68e479cea Mon Sep 17 00:00:00 2001 From: f-frhs Date: Tue, 28 Nov 2023 22:52:21 +0900 Subject: [PATCH 08/25] change: use the fact that dot-product of the unit vector is always 1.0 --- src/Spatial/Euclidean/Circle2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index ff0444a..24333f0 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -168,7 +168,7 @@ private double[] findParameterTs(Line2D line) var d = line.Direction; var r = this.Radius; - var a = d.DotProduct(d); + var a = 1d; var b = 2 * (s.DotProduct(d) - d.DotProduct(cc)); var c = (s - cc).DotProduct(s - cc) - r * r; From 847cdaf17e4784a1791d5dd11ddb8f398111cf18 Mon Sep 17 00:00:00 2001 From: f-frhs Date: Tue, 28 Nov 2023 22:54:20 +0900 Subject: [PATCH 09/25] Revert "Feat: Line2D.DistanceTo(point)" This reverts commit 0a2521d22e32f920b8571b4e3a7d575b0e102c02. --- src/Spatial.Tests/Euclidean/Line2DTests.cs | 25 -------- src/Spatial/Euclidean/Line2D.cs | 67 ++-------------------- 2 files changed, 6 insertions(+), 86 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Line2DTests.cs b/src/Spatial.Tests/Euclidean/Line2DTests.cs index 61def30..b4a5fc5 100644 --- a/src/Spatial.Tests/Euclidean/Line2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Line2DTests.cs @@ -210,30 +210,5 @@ public void ToStringCheck() Assert.AreEqual("StartPoint: (0,\u00A00), EndPoint: (1,\u00A01)", check); } - - [TestCase("0,0", "1,0", "0,1",-1)] - [TestCase("0,0", "1,0", "0,2", -2)] - [TestCase("0,0", "0,1", "2,0", +2)] - public void SignedDistanceTo(string sp1, string sp2, string sp, double expectedDistance) - { - var line = Line2D.Parse(sp1, sp2); - var point = Point2D.Parse(sp); - - var actual = line.SignedDistanceTo(point); - Assert.That(actual, Is.EqualTo(expectedDistance)); - } - - - [TestCase("0,0", "1,0", "0,1", 1)] - [TestCase("0,0", "1,0", "0,2", 2)] - [TestCase("0,0", "0,1", "2,0", 2)] - public void DistanceTo(string sp1, string sp2, string sp, double expectedDistance) - { - var line = Line2D.Parse(sp1, sp2); - var point = Point2D.Parse(sp); - - var actual = line.DistanceTo(point); - Assert.That(actual, Is.EqualTo(expectedDistance)); - } } } diff --git a/src/Spatial/Euclidean/Line2D.cs b/src/Spatial/Euclidean/Line2D.cs index 488fe0e..d1c516a 100644 --- a/src/Spatial/Euclidean/Line2D.cs +++ b/src/Spatial/Euclidean/Line2D.cs @@ -1,12 +1,12 @@ -using MathNet.Numerics; -using MathNet.Spatial.Internals; -using MathNet.Spatial.Units; -using System; +using System; using System.Diagnostics.Contracts; -using System.Xml; -using System.Xml.Linq; using System.Xml.Schema; +using System.Xml; using System.Xml.Serialization; +using MathNet.Numerics; +using MathNet.Spatial.Internals; +using MathNet.Spatial.Units; +using System.Xml.Linq; namespace MathNet.Spatial.Euclidean { @@ -27,21 +27,6 @@ public struct Line2D : IEquatable, IXmlSerializable /// public Point2D EndPoint { get; private set; } - /// - /// The parameter `a` in the line equation: ax + by + c = 0 - /// - public double A { get; private set; } - - /// - /// The parameter `b` in the line equation: ax + by + c = 0 - /// - public double B { get; private set; } - - /// - /// The parameter `c` in the line equation: ax + by + c = 0 - /// - public double C { get; private set; } - /// /// Initializes a new instance of the struct. /// Throws an ArgumentException if the is equal to the . @@ -55,27 +40,8 @@ public Line2D(Point2D startPoint, Point2D endPoint) throw new ArgumentException("The Line2D starting and ending points cannot be identical"); } - //substitution - //points StartPoint = startPoint; EndPoint = endPoint; - - //doubles - var x1 = startPoint.X; - var x2 = endPoint.X; - var y1 = startPoint.Y; - var y2 = endPoint.Y; - - //computation - var a = y2 - y1; - var b = x1 - x2; - var c = (x2 - x1) * y1 - (y2 - y1) * x1; - - //normalize - var length = Math.Sqrt(a * a + b * b); - A = a / length; - B = b / length; - C = c / length; } /// @@ -328,26 +294,5 @@ void IXmlSerializable.WriteXml(XmlWriter writer) writer.WriteElement("StartPoint", StartPoint); writer.WriteElement("EndPoint", EndPoint); } - - /// - /// Compute the signed distance from this `line` to the given point `p`. If the sign of the distance is positive, the normal vector from the line is in the same side to the point. - /// - /// - /// - public double SignedDistanceTo(Point2D p) - { - var result = A * p.X + B * p.Y + C; - return result; - } - - /// - /// Compute the absolute distance from this `line` to the given point `p`. - /// - /// - /// - public double DistanceTo(Point2D p) - { - return Math.Abs(SignedDistanceTo(p)); - } } } From 2d222ac60492d5ca6a2028cb6a2c7a25193ce640 Mon Sep 17 00:00:00 2001 From: f-frhs Date: Tue, 28 Nov 2023 23:00:20 +0900 Subject: [PATCH 10/25] remove: src/Spatial/Extensions/DoubleExtensions.cs --- src/Spatial/Euclidean/Circle2D.cs | 1 - src/Spatial/Extensions/DoubleExtensions.cs | 21 --------------------- 2 files changed, 22 deletions(-) delete mode 100644 src/Spatial/Extensions/DoubleExtensions.cs diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index 24333f0..f22df21 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -7,7 +7,6 @@ using System.Xml.Serialization; using MathNet.Numerics; using HashCode = MathNet.Spatial.Internals.HashCode; -using MathNet.Spatial.Extensions; namespace MathNet.Spatial.Euclidean { diff --git a/src/Spatial/Extensions/DoubleExtensions.cs b/src/Spatial/Extensions/DoubleExtensions.cs deleted file mode 100644 index c7a64ea..0000000 --- a/src/Spatial/Extensions/DoubleExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MathNet.Spatial.Extensions -{ - internal static class DoubleExtensions - { - internal static bool IsNearlyEqualTo(this double d, double reference, double tolerance) - { - if (tolerance < 0) - { - throw new ArgumentOutOfRangeException(nameof(tolerance)); - } - return Math.Abs(d-reference) < tolerance; - } - } -} From 571cf7d785a6d2f99ea30dfec9dff1f10ad313a8 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Fri, 1 Dec 2023 14:34:09 +0900 Subject: [PATCH 11/25] doc: revise xml comments --- src/Spatial/Euclidean/Circle2D.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index f22df21..e7d53e3 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -134,7 +134,7 @@ public static Circle2D FromPoints(Point2D pointA, Point2D pointB, Point2D pointC } /// - /// Returns intersection a point2D array if this circle and the given line have the intersections + /// Returns the intersections of this circle with the given line. /// /// the given line /// intersections as a Point2D Array, depending on the count. @@ -180,7 +180,7 @@ private double[] findParameterTs(Line2D line) } /// - /// Returns intersection a point2D array if this circle and the given line have the intersections + /// Returns the intersections of this circle with the given line segment, which lie within the segment. /// /// the given line-segment /// intersections as a Point2D Array, depending on the count. From 9e33c1b1daff669f22e59ed4051cf230c21f66f6 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Fri, 1 Dec 2023 17:08:38 +0900 Subject: [PATCH 12/25] fix a typo --- src/Spatial/Euclidean/Circle2D.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index e7d53e3..2872298 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -171,8 +171,8 @@ private double[] findParameterTs(Line2D line) var b = 2 * (s.DotProduct(d) - d.DotProduct(cc)); var c = (s - cc).DotProduct(s - cc) - r * r; - var soluions = FindRoots.Polynomial(new[] { c, b, a }); - var ts = soluions + var solutions = FindRoots.Polynomial(new[] { c, b, a }); + var ts = solutions .Where(z => z.IsReal()) .Select(z => z.Real) .ToArray(); From 7c5df6a1561cc3a50024f1259dc81064eac03a5d Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Sun, 3 Dec 2023 16:04:19 +0900 Subject: [PATCH 13/25] test: fix testcases to test number of intersections --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 7f5322b..1e1e754 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -1,4 +1,5 @@ -using System; +using System; +using System.Linq; using MathNet.Spatial.Euclidean; using NUnit.Framework; @@ -59,19 +60,19 @@ public void CircleFromThreePointsArgumentException() Assert.Throws(() => { Circle2D.FromPoints(p1, p2, p3); }); } - [TestCase("0,0", 1.41421356 /*=sqrt(2)*/, "-1,-1", "+1,+1", "+1,+1", "-1,-1")] - [TestCase("0,0", 1, "-1,0", "+1,0", "+1,0", "-1,0")] - [TestCase("0,0", 1, "0,-1", "0,+1", "0,+1", "0,-1")] - public void CircleIntersectWithLine2D(string sc, double radius, string sps, string spe, string esp0, string esp1) + [TestCase("0,0", 1, "-10,+10", "+10,+10", 0)] + [TestCase("0,0", 1, "-10,+1", "+10,+1", 1)] + [TestCase("0,0", 1, "-10,0", "+10,0", 2)] + [TestCase("0,0", 1, "-10,-1", "+10,-1", 1 )] + [TestCase("0,0", 1, "-10,-10", "+10,-10", 0)] + public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double radius, string sps, string spe, int expectedNumberOfIntersections) { var circle = new Circle2D(Point2D.Parse(sc), radius); var line = new Line2D(Point2D.Parse(sps), Point2D.Parse(spe)); + var actual = circle.IntersectWith(line); - Assert.That(actual.Length, Is.EqualTo(2)); - var expected = new[] { Point2D.Parse(esp0), Point2D.Parse(esp1) }; - AssertGeometry.AreEqual(actual[0], expected[0]); - AssertGeometry.AreEqual(actual[1], expected[1]); + Assert.That(actual.Count(), Is.EqualTo(expectedNumberOfIntersections)); } [TestCase("0,0", 1.41421356 /*=sqrt(2)*/, "0,0", "+1,+1", "+1,+1")] From 1a527b1a8e549eb9ca197d35bf12e78e01b72df9 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Sun, 3 Dec 2023 16:10:41 +0900 Subject: [PATCH 14/25] fix: IntersectionWith() to return a single point when a line tangent to the circle --- src/Spatial/Euclidean/Circle2D.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index 2872298..0a29154 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -175,6 +175,7 @@ private double[] findParameterTs(Line2D line) var ts = solutions .Where(z => z.IsReal()) .Select(z => z.Real) + .Distinct() .ToArray(); return ts; } From b27fdb183d8fe6f3526ebece8c29a90ef3981a09 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Sun, 3 Dec 2023 16:23:39 +0900 Subject: [PATCH 15/25] test: Add tests for intersection of Circle and LineSegment2D for the case where LineSegment contains some of obtained intersections. --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 28 +++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 1e1e754..1281047 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -75,18 +75,32 @@ public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double ra Assert.That(actual.Count(), Is.EqualTo(expectedNumberOfIntersections)); } - [TestCase("0,0", 1.41421356 /*=sqrt(2)*/, "0,0", "+1,+1", "+1,+1")] - [TestCase("0,0", 1, "0,0", "+1,0", "+1,0")] - [TestCase("0,0", 1, "0,0", "0,+1", "0,+1")] - public void CircleIntersectWithLineSegment2D(string sCenter, double radius, string sStart, string sEnd, string sExpected) + //segment contains the all intersections(same to the cases of circle and line) + [TestCase("0,0", 1, "-10,+10", "+10,+10", 0)] + [TestCase("0,0", 1, "-10,+1", "+10,+1", 1)] + [TestCase("0,0", 1, "-10,0", "+10,0", 2)] + [TestCase("0,0", 1, "-10,-1", "+10,-1", 1)] + [TestCase("0,0", 1, "-10,-10", "+10,-10", 0)] + //segments cross the circle's contour just 1 time + [TestCase("0,0", 1, "+0,+10", "+10,+10", 0)] + [TestCase("0,0", 1, "+0,+1", "+10,+1", 1)] + [TestCase("0,0", 1, "+0,0", "+10,0", 1)] + [TestCase("0,0", 1, "+0,-1", "+10,-1", 1)] + [TestCase("0,0", 1, "+0,-10", "+10,-10", 0)] + //segment contains no intersections(px of the startingPoint is too big to intersect with the circle) + [TestCase("0,0", 1, "+10,+10", "+100,+10", 0)] + [TestCase("0,0", 1, "+10,+01", "+100,+1", 0)] + [TestCase("0,0", 1, "+10,+00", "+100,0", 0)] + [TestCase("0,0", 1, "+10,-01", "+100,-1", 0)] + [TestCase("0,0", 1, "+10,-10", "+100,-10", 0)] + public void CircleIntersectWithLineSegment2D_NumberOfIntersections(string sCenter, double radius, string sStart, string sEnd, int expectedNumberOfIntersections) { var circle = new Circle2D(Point2D.Parse(sCenter), radius); var segment = new LineSegment2D(Point2D.Parse(sStart), Point2D.Parse(sEnd)); + var actual = circle.IntersectWith(segment); - Assert.That(actual.Length, Is.EqualTo(1)); - var expected = Point2D.Parse(sExpected); - AssertGeometry.AreEqual(actual[0], expected); + Assert.That(actual.Count(), Is.EqualTo(expectedNumberOfIntersections)); } } } From dc7ea8523cb90b612d3dedf7deb21374ebd7c6d2 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Sun, 3 Dec 2023 16:31:37 +0900 Subject: [PATCH 16/25] test: add TODO comment --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 1281047..7229fd0 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -73,6 +73,9 @@ public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double ra var actual = circle.IntersectWith(line); Assert.That(actual.Count(), Is.EqualTo(expectedNumberOfIntersections)); + //TODO: the intersection should be on the circle + Assert.That(actual.All(p => Math.Abs(circle.Center.DistanceTo(p) - circle.Radius) < 1e-6), Is.EqualTo(true), "distance between center and intersection"); + //TODO: the intersection should be on the line } //segment contains the all intersections(same to the cases of circle and line) From 5930b12914da065e776a033485fb6d65a05b60ca Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Sun, 3 Dec 2023 16:33:38 +0900 Subject: [PATCH 17/25] refactor: rename line to segment --- src/Spatial/Euclidean/Circle2D.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index 0a29154..a83987a 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -183,13 +183,13 @@ private double[] findParameterTs(Line2D line) /// /// Returns the intersections of this circle with the given line segment, which lie within the segment. /// - /// the given line-segment + /// the given line-segment /// intersections as a Point2D Array, depending on the count. - public Point2D[] IntersectWith(LineSegment2D line) + public Point2D[] IntersectWith(LineSegment2D segment) { - var ts = findParameterTs(line.ToLine2D()) - .Where(t => 0 <= t && t <= line.Length); - var result = ts.Select(t => line.StartPoint + t * line.Direction).ToArray(); + var ts = findParameterTs(segment.ToLine2D()) + .Where(t => 0 <= t && t <= segment.Length); + var result = ts.Select(t => segment.StartPoint + t * segment.Direction).ToArray(); return result; } From 0e7eb693efa625b138e4a86bc2e74674fcc851ad Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Thu, 7 Dec 2023 12:07:41 +0900 Subject: [PATCH 18/25] fix: type declaration (from 1d to 1.0) --- src/Spatial/Euclidean/Circle2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spatial/Euclidean/Circle2D.cs b/src/Spatial/Euclidean/Circle2D.cs index a83987a..35c9650 100644 --- a/src/Spatial/Euclidean/Circle2D.cs +++ b/src/Spatial/Euclidean/Circle2D.cs @@ -167,7 +167,7 @@ private double[] findParameterTs(Line2D line) var d = line.Direction; var r = this.Radius; - var a = 1d; + var a = 1.0; var b = 2 * (s.DotProduct(d) - d.DotProduct(cc)); var c = (s - cc).DotProduct(s - cc) - r * r; From 5c3cd704a153c0a747be37236a577b30a7d8e96f Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Thu, 7 Dec 2023 15:38:36 +0900 Subject: [PATCH 19/25] test: fix testcases to use expected points --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 48 +++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 7229fd0..d0453f1 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -79,31 +79,45 @@ public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double ra } //segment contains the all intersections(same to the cases of circle and line) - [TestCase("0,0", 1, "-10,+10", "+10,+10", 0)] - [TestCase("0,0", 1, "-10,+1", "+10,+1", 1)] - [TestCase("0,0", 1, "-10,0", "+10,0", 2)] - [TestCase("0,0", 1, "-10,-1", "+10,-1", 1)] - [TestCase("0,0", 1, "-10,-10", "+10,-10", 0)] + [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] + [TestCase("0,0", 1, "-10,0", "+10,0", "-1,0;+1,0")] + [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1")] + [TestCase("0,0", 1, "-10,-10", "+10,-10", "empty")] //segments cross the circle's contour just 1 time - [TestCase("0,0", 1, "+0,+10", "+10,+10", 0)] - [TestCase("0,0", 1, "+0,+1", "+10,+1", 1)] - [TestCase("0,0", 1, "+0,0", "+10,0", 1)] - [TestCase("0,0", 1, "+0,-1", "+10,-1", 1)] - [TestCase("0,0", 1, "+0,-10", "+10,-10", 0)] + [TestCase("0,0", 1, "+0,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "+0,+1", "+10,+1", "0,1")] + [TestCase("0,0", 1, "+0,0", "+10,0", "1,0")] + [TestCase("0,0", 1, "+0,-1", "+10,-1", "0,-1")] + [TestCase("0,0", 1, "+0,-10", "+10,-10", "empty")] //segment contains no intersections(px of the startingPoint is too big to intersect with the circle) - [TestCase("0,0", 1, "+10,+10", "+100,+10", 0)] - [TestCase("0,0", 1, "+10,+01", "+100,+1", 0)] - [TestCase("0,0", 1, "+10,+00", "+100,0", 0)] - [TestCase("0,0", 1, "+10,-01", "+100,-1", 0)] - [TestCase("0,0", 1, "+10,-10", "+100,-10", 0)] - public void CircleIntersectWithLineSegment2D_NumberOfIntersections(string sCenter, double radius, string sStart, string sEnd, int expectedNumberOfIntersections) + [TestCase("0,0", 1, "+10,+10", "+100,+10", "empty")] + [TestCase("0,0", 1, "+10,+01", "+100,+1", "empty")] + [TestCase("0,0", 1, "+10,+00", "+100,0", "empty")] + [TestCase("0,0", 1, "+10,-01", "+100,-1", "empty")] + [TestCase("0,0", 1, "+10,-10", "+100,-10", "empty")] + public void CircleIntersectWithLineSegment2D_NumberOfIntersections(string sCenter, double radius, string sStart, string sEnd, string expectedIntersectionsAsString) { var circle = new Circle2D(Point2D.Parse(sCenter), radius); var segment = new LineSegment2D(Point2D.Parse(sStart), Point2D.Parse(sEnd)); var actual = circle.IntersectWith(segment); - Assert.That(actual.Count(), Is.EqualTo(expectedNumberOfIntersections)); + var expected = parseToPointsArray(expectedIntersectionsAsString); + CollectionAssert.AreEquivalent(expected, actual); + } + + private Point2D[] parseToPointsArray(string input) + { + if (input.ToLower().Contains("empty")) + { + return new Point2D[] { }; + } + + var result = input.Split(';') + .Select(s => Point2D.Parse(s)) + .ToArray(); + return result; } } } From ab59a230c1685642d8c2049d183264ea0c3339e6 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Thu, 7 Dec 2023 15:44:59 +0900 Subject: [PATCH 20/25] test: fix testcases to use expected points --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index d0453f1..9e18e7c 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -60,19 +60,20 @@ public void CircleFromThreePointsArgumentException() Assert.Throws(() => { Circle2D.FromPoints(p1, p2, p3); }); } - [TestCase("0,0", 1, "-10,+10", "+10,+10", 0)] - [TestCase("0,0", 1, "-10,+1", "+10,+1", 1)] - [TestCase("0,0", 1, "-10,0", "+10,0", 2)] - [TestCase("0,0", 1, "-10,-1", "+10,-1", 1 )] - [TestCase("0,0", 1, "-10,-10", "+10,-10", 0)] - public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double radius, string sps, string spe, int expectedNumberOfIntersections) + [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] + [TestCase("0,0", 1, "-10,0", "+10,0", "-1,0;+1,0")] + [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1" )] + [TestCase("0,0", 1, "-10,-10", "+10,-10", "empty")] + public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double radius, string sps, string spe, string expectedIntersectionsAsString) { var circle = new Circle2D(Point2D.Parse(sc), radius); var line = new Line2D(Point2D.Parse(sps), Point2D.Parse(spe)); var actual = circle.IntersectWith(line); - Assert.That(actual.Count(), Is.EqualTo(expectedNumberOfIntersections)); + var expected = parseToPointsArray(expectedIntersectionsAsString); + CollectionAssert.AreEquivalent(expected, actual); //TODO: the intersection should be on the circle Assert.That(actual.All(p => Math.Abs(circle.Center.DistanceTo(p) - circle.Radius) < 1e-6), Is.EqualTo(true), "distance between center and intersection"); //TODO: the intersection should be on the line From 451a87d33bbd9f30f876e9f05c2f3374552d7229 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Thu, 7 Dec 2023 15:50:04 +0900 Subject: [PATCH 21/25] test: add testcases where the line is parallel to the Y-axis --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 9e18e7c..c60b3ab 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -60,11 +60,18 @@ public void CircleFromThreePointsArgumentException() Assert.Throws(() => { Circle2D.FromPoints(p1, p2, p3); }); } + //parallel to the X-axis [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] [TestCase("0,0", 1, "-10,0", "+10,0", "-1,0;+1,0")] [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1" )] [TestCase("0,0", 1, "-10,-10", "+10,-10", "empty")] + //parallel to the Y-axis + [TestCase("0,0", 1, "-10,-10", "-10,+10", "empty")] + [TestCase("0,0", 1, "-1,-10", "-1,+10", "-1,0")] + [TestCase("0,0", 1, "0,-10", "0,+10", "0,-1;0,+1")] + [TestCase("0,0", 1, "+1,-10", "+1,+10", "+1,0")] + [TestCase("0,0", 1, "+10,-10", "+10,+10", "empty")] public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double radius, string sps, string spe, string expectedIntersectionsAsString) { var circle = new Circle2D(Point2D.Parse(sc), radius); From 3d3748bca4569c6d5a7aed16c1c3957a1da9e8ff Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Thu, 7 Dec 2023 18:13:39 +0900 Subject: [PATCH 22/25] test: add testcases parallel to Y-axis and general cases --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 29 +++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index c60b3ab..b44d5e0 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using MathNet.Spatial.Euclidean; using NUnit.Framework; @@ -61,18 +62,24 @@ public void CircleFromThreePointsArgumentException() } //parallel to the X-axis - [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] - [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] - [TestCase("0,0", 1, "-10,0", "+10,0", "-1,0;+1,0")] - [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1" )] [TestCase("0,0", 1, "-10,-10", "+10,-10", "empty")] + [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1")] + [TestCase("0,0", 1, "-10,0", "+10,0", "+1,0;-1,0")] + [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] + [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] //parallel to the Y-axis [TestCase("0,0", 1, "-10,-10", "-10,+10", "empty")] [TestCase("0,0", 1, "-1,-10", "-1,+10", "-1,0")] - [TestCase("0,0", 1, "0,-10", "0,+10", "0,-1;0,+1")] + [TestCase("0,0", 1, "0,-10", "0,+10", "0,+1;0,-1")] [TestCase("0,0", 1, "+1,-10", "+1,+10", "+1,0")] [TestCase("0,0", 1, "+10,-10", "+10,+10", "empty")] - public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double radius, string sps, string spe, string expectedIntersectionsAsString) + //general cases + [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-1.414213562373095,0", "0,+1.414213562373095", "-0.707,0.707")] + [TestCase("0,0", 1, "-10,-10", "+10,+10", "+0.707,+0.707;-0.707,-0.707")] + [TestCase("0,0", 1, "0,-1.41421356", "+1.41421356,0", "+0.707,-0.707")] + [TestCase("0,0", 1, "0,-10", "+10,0", "empty")] + public void CircleIntersectWithLine2D(string sc, double radius, string sps, string spe, string expectedIntersectionsAsString) { var circle = new Circle2D(Point2D.Parse(sc), radius); var line = new Line2D(Point2D.Parse(sps), Point2D.Parse(spe)); @@ -80,10 +87,12 @@ public void CircleIntersectWithLine2D_NumberOfIntersections(string sc, double ra var actual = circle.IntersectWith(line); var expected = parseToPointsArray(expectedIntersectionsAsString); - CollectionAssert.AreEquivalent(expected, actual); - //TODO: the intersection should be on the circle - Assert.That(actual.All(p => Math.Abs(circle.Center.DistanceTo(p) - circle.Radius) < 1e-6), Is.EqualTo(true), "distance between center and intersection"); - //TODO: the intersection should be on the line + for (int i = 0; i < Math.Min(actual.Length, expected.Length); i++) + { + var a = actual[i]; + var e = expected[i]; + AssertGeometry.AreEqual(a, e, 1e-3); //needs to fix for the default tolerance + } } //segment contains the all intersections(same to the cases of circle and line) From 6b8c3db4922851adcba2304d2d81aca9b60a2a63 Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Thu, 7 Dec 2023 18:43:26 +0900 Subject: [PATCH 23/25] test: add testcases for Intersection of Circle2D with LIneSegment2D - parallel to X-axis - parallel to Y-axis - general cases (eg. x-y+c=0) test: rename method's name --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 57 +++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index b44d5e0..2c1f4f5 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -94,26 +94,64 @@ public void CircleIntersectWithLine2D(string sc, double radius, string sps, stri AssertGeometry.AreEqual(a, e, 1e-3); //needs to fix for the default tolerance } } - - //segment contains the all intersections(same to the cases of circle and line) + //parallel to X-axis + ////segment contains the all intersections(same to the cases of circle and line) [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] - [TestCase("0,0", 1, "-10,0", "+10,0", "-1,0;+1,0")] + [TestCase("0,0", 1, "-10,0", "+10,0", "+1,0;-1,0")] [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1")] [TestCase("0,0", 1, "-10,-10", "+10,-10", "empty")] - //segments cross the circle's contour just 1 time + ////segments cross the circle's contour just 1 time [TestCase("0,0", 1, "+0,+10", "+10,+10", "empty")] [TestCase("0,0", 1, "+0,+1", "+10,+1", "0,1")] [TestCase("0,0", 1, "+0,0", "+10,0", "1,0")] [TestCase("0,0", 1, "+0,-1", "+10,-1", "0,-1")] [TestCase("0,0", 1, "+0,-10", "+10,-10", "empty")] - //segment contains no intersections(px of the startingPoint is too big to intersect with the circle) + ////segment contains no intersections(px of the startingPoint is too big to intersect with the circle) [TestCase("0,0", 1, "+10,+10", "+100,+10", "empty")] [TestCase("0,0", 1, "+10,+01", "+100,+1", "empty")] [TestCase("0,0", 1, "+10,+00", "+100,0", "empty")] [TestCase("0,0", 1, "+10,-01", "+100,-1", "empty")] [TestCase("0,0", 1, "+10,-10", "+100,-10", "empty")] - public void CircleIntersectWithLineSegment2D_NumberOfIntersections(string sCenter, double radius, string sStart, string sEnd, string expectedIntersectionsAsString) + //parallel to Y-axis + ////segment contains the all intersections(same to the cases of circle and line) + [TestCase("0,0", 1, "-10,-10", "-10,+10", "empty")] + [TestCase("0,0", 1, "-1,-10", "-1,+10", "-1,0")] + [TestCase("0,0", 1, "0,-10", "0,+10", "0,+1;0,-1")] + [TestCase("0,0", 1, "+1,-10", "+1,+10", "+1,0")] + [TestCase("0,0", 1, "+10,-10", "+10,+10", "EMPTY")] + ////segments cross the circle's contour just 1 time + [TestCase("0,0", 1, "+10,0", "+10,+10", "empty")] + [TestCase("0,0", 1, "+1,0", "+1,+10", "+1,0")] + [TestCase("0,0", 1, "0,0", "0,+10", "0,+1")] + [TestCase("0,0", 1, "-1,0", "-1,+10", "-1,0")] + [TestCase("0,0", 1, "-10,0", "-10,+10", "empty")] + ////segment contains no intersections(py of the startingPoint is too big to intersect with the circle) + [TestCase("0,0", 1, "+10,+10", "+10,+100", "empty")] + [TestCase("0,0", 1, "+01,+10", "+1,+100", "empty")] + [TestCase("0,0", 1, "+00,+10", "0,+100", "empty")] + [TestCase("0,0", 1, "-01,+10", "-1,+100", "empty")] + [TestCase("0,0", 1, "-10,+10", "-10,+100", "empty")] + //general cases + ////segment contains the all intersections(same to the cases of circle and line) + [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-1.414213562373095,0", "0,+1.414213562373095", "-0.707,0.707")] + [TestCase("0,0", 1, "-10,-10", "+10,+10", "+0.707,+0.707;-0.707,-0.707")] + [TestCase("0,0", 1, "0,-1.41421356", "+1.41421356,0", "+0.707,-0.707")] + [TestCase("0,0", 1, "0,-10", "+10,0", "empty")] + ////segments cross the circle's contour just 1 time + [TestCase("0,0", 1, "+10,0", "+10,+10", "empty")] + [TestCase("0,0", 1, "+1,0", "+1,+10", "+1,0")] + [TestCase("0,0", 1, "0,0", "0,+10", "0,+1")] + [TestCase("0,0", 1, "-1,0", "-1,+10", "-1,0")] + [TestCase("0,0", 1, "-10,0", "-10,+10", "empty")] + ////segment contains no intersections(py of the startingPoint is too big to intersect with the circle) + [TestCase("0,0", 1, "+10,+10", "+10,+100", "empty")] + [TestCase("0,0", 1, "+01,+10", "+1,+100", "empty")] + [TestCase("0,0", 1, "+00,+10", "0,+100", "empty")] + [TestCase("0,0", 1, "-01,+10", "-1,+100", "empty")] + [TestCase("0,0", 1, "-10,+10", "-10,+100", "empty")] + public void CircleIntersectWithLineSegment2D(string sCenter, double radius, string sStart, string sEnd, string expectedIntersectionsAsString) { var circle = new Circle2D(Point2D.Parse(sCenter), radius); var segment = new LineSegment2D(Point2D.Parse(sStart), Point2D.Parse(sEnd)); @@ -121,7 +159,12 @@ public void CircleIntersectWithLineSegment2D_NumberOfIntersections(string sCente var actual = circle.IntersectWith(segment); var expected = parseToPointsArray(expectedIntersectionsAsString); - CollectionAssert.AreEquivalent(expected, actual); + for (int i = 0; i < Math.Min(actual.Length, expected.Length); i++) + { + var a = actual[i]; + var e = expected[i]; + AssertGeometry.AreEqual(a, e, 1e-3); //needs to fix for the default tolerance + } } private Point2D[] parseToPointsArray(string input) From f3815edfaac3955fbd2f08a14fd2280aac9d84bc Mon Sep 17 00:00:00 2001 From: Ippei FURUHASHI Date: Thu, 7 Dec 2023 18:39:28 +0900 Subject: [PATCH 24/25] test: replace +01 to +1 --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 2c1f4f5..1fadbaa 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -104,33 +104,33 @@ public void CircleIntersectWithLine2D(string sc, double radius, string sps, stri ////segments cross the circle's contour just 1 time [TestCase("0,0", 1, "+0,+10", "+10,+10", "empty")] [TestCase("0,0", 1, "+0,+1", "+10,+1", "0,1")] - [TestCase("0,0", 1, "+0,0", "+10,0", "1,0")] + [TestCase("0,0", 1, "+0,+0", "+10,+0", "1,0")] [TestCase("0,0", 1, "+0,-1", "+10,-1", "0,-1")] [TestCase("0,0", 1, "+0,-10", "+10,-10", "empty")] ////segment contains no intersections(px of the startingPoint is too big to intersect with the circle) [TestCase("0,0", 1, "+10,+10", "+100,+10", "empty")] - [TestCase("0,0", 1, "+10,+01", "+100,+1", "empty")] - [TestCase("0,0", 1, "+10,+00", "+100,0", "empty")] - [TestCase("0,0", 1, "+10,-01", "+100,-1", "empty")] + [TestCase("0,0", 1, "+10,+1", "+100,+1", "empty")] + [TestCase("0,0", 1, "+10,+0", "+100,0", "empty")] + [TestCase("0,0", 1, "+10,-1", "+100,-1", "empty")] [TestCase("0,0", 1, "+10,-10", "+100,-10", "empty")] //parallel to Y-axis ////segment contains the all intersections(same to the cases of circle and line) [TestCase("0,0", 1, "-10,-10", "-10,+10", "empty")] [TestCase("0,0", 1, "-1,-10", "-1,+10", "-1,0")] - [TestCase("0,0", 1, "0,-10", "0,+10", "0,+1;0,-1")] + [TestCase("0,0", 1, "+0,-10", "+0,+10", "0,+1;0,-1")] [TestCase("0,0", 1, "+1,-10", "+1,+10", "+1,0")] [TestCase("0,0", 1, "+10,-10", "+10,+10", "EMPTY")] ////segments cross the circle's contour just 1 time [TestCase("0,0", 1, "+10,0", "+10,+10", "empty")] [TestCase("0,0", 1, "+1,0", "+1,+10", "+1,0")] - [TestCase("0,0", 1, "0,0", "0,+10", "0,+1")] + [TestCase("0,0", 1, "+0,0", "+0,+10", "0,+1")] [TestCase("0,0", 1, "-1,0", "-1,+10", "-1,0")] [TestCase("0,0", 1, "-10,0", "-10,+10", "empty")] ////segment contains no intersections(py of the startingPoint is too big to intersect with the circle) [TestCase("0,0", 1, "+10,+10", "+10,+100", "empty")] - [TestCase("0,0", 1, "+01,+10", "+1,+100", "empty")] - [TestCase("0,0", 1, "+00,+10", "0,+100", "empty")] - [TestCase("0,0", 1, "-01,+10", "-1,+100", "empty")] + [TestCase("0,0", 1, "+1,+10", "+1,+100", "empty")] + [TestCase("0,0", 1, "+0,+10", "+0,+100", "empty")] + [TestCase("0,0", 1, "-1,+10", "-1,+100", "empty")] [TestCase("0,0", 1, "-10,+10", "-10,+100", "empty")] //general cases ////segment contains the all intersections(same to the cases of circle and line) @@ -142,14 +142,14 @@ public void CircleIntersectWithLine2D(string sc, double radius, string sps, stri ////segments cross the circle's contour just 1 time [TestCase("0,0", 1, "+10,0", "+10,+10", "empty")] [TestCase("0,0", 1, "+1,0", "+1,+10", "+1,0")] - [TestCase("0,0", 1, "0,0", "0,+10", "0,+1")] + [TestCase("0,0", 1, "+0,0", "+0,+10", "0,+1")] [TestCase("0,0", 1, "-1,0", "-1,+10", "-1,0")] [TestCase("0,0", 1, "-10,0", "-10,+10", "empty")] ////segment contains no intersections(py of the startingPoint is too big to intersect with the circle) [TestCase("0,0", 1, "+10,+10", "+10,+100", "empty")] - [TestCase("0,0", 1, "+01,+10", "+1,+100", "empty")] - [TestCase("0,0", 1, "+00,+10", "0,+100", "empty")] - [TestCase("0,0", 1, "-01,+10", "-1,+100", "empty")] + [TestCase("0,0", 1, "+1,+10", "+1,+100", "empty")] + [TestCase("0,0", 1, "+0,+10", "+0,+100", "empty")] + [TestCase("0,0", 1, "-1,+10", "-1,+100", "empty")] [TestCase("0,0", 1, "-10,+10", "-10,+100", "empty")] public void CircleIntersectWithLineSegment2D(string sCenter, double radius, string sStart, string sEnd, string expectedIntersectionsAsString) { @@ -163,7 +163,7 @@ public void CircleIntersectWithLineSegment2D(string sCenter, double radius, stri { var a = actual[i]; var e = expected[i]; - AssertGeometry.AreEqual(a, e, 1e-3); //needs to fix for the default tolerance + AssertGeometry.AreEqual(a, e, 1e-3); //FIXME! } } From acccdbf24cf19acb6622f4ca38ce59cc14b818d1 Mon Sep 17 00:00:00 2001 From: jkaliak Date: Sat, 9 Dec 2023 11:46:43 +0100 Subject: [PATCH 25/25] Minor changes in test --- src/Spatial.Tests/Euclidean/Circle2DTests.cs | 78 ++++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/Spatial.Tests/Euclidean/Circle2DTests.cs b/src/Spatial.Tests/Euclidean/Circle2DTests.cs index 1fadbaa..d1a2cdd 100644 --- a/src/Spatial.Tests/Euclidean/Circle2DTests.cs +++ b/src/Spatial.Tests/Euclidean/Circle2DTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using MathNet.Spatial.Euclidean; using NUnit.Framework; @@ -62,31 +61,31 @@ public void CircleFromThreePointsArgumentException() } //parallel to the X-axis - [TestCase("0,0", 1, "-10,-10", "+10,-10", "empty")] + [TestCase("0,0", 1, "-10,-10", "+10,-10", null)] [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1")] [TestCase("0,0", 1, "-10,0", "+10,0", "+1,0;-1,0")] [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] - [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-10,+10", "+10,+10", null)] //parallel to the Y-axis - [TestCase("0,0", 1, "-10,-10", "-10,+10", "empty")] + [TestCase("0,0", 1, "-10,-10", "-10,+10", null)] [TestCase("0,0", 1, "-1,-10", "-1,+10", "-1,0")] [TestCase("0,0", 1, "0,-10", "0,+10", "0,+1;0,-1")] [TestCase("0,0", 1, "+1,-10", "+1,+10", "+1,0")] - [TestCase("0,0", 1, "+10,-10", "+10,+10", "empty")] + [TestCase("0,0", 1, "+10,-10", "+10,+10", null)] //general cases - [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-10,+10", "+10,+10", null)] [TestCase("0,0", 1, "-1.414213562373095,0", "0,+1.414213562373095", "-0.707,0.707")] [TestCase("0,0", 1, "-10,-10", "+10,+10", "+0.707,+0.707;-0.707,-0.707")] [TestCase("0,0", 1, "0,-1.41421356", "+1.41421356,0", "+0.707,-0.707")] - [TestCase("0,0", 1, "0,-10", "+10,0", "empty")] - public void CircleIntersectWithLine2D(string sc, double radius, string sps, string spe, string expectedIntersectionsAsString) + [TestCase("0,0", 1, "0,-10", "+10,0", null)] + public void CircleIntersectWithLine2D(string sc, double radius, string sps, string spe, string intersections) { var circle = new Circle2D(Point2D.Parse(sc), radius); var line = new Line2D(Point2D.Parse(sps), Point2D.Parse(spe)); var actual = circle.IntersectWith(line); - var expected = parseToPointsArray(expectedIntersectionsAsString); + var expected = parseToPointsArray(intersections); for (int i = 0; i < Math.Min(actual.Length, expected.Length); i++) { var a = actual[i]; @@ -96,69 +95,69 @@ public void CircleIntersectWithLine2D(string sc, double radius, string sps, stri } //parallel to X-axis ////segment contains the all intersections(same to the cases of circle and line) - [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-10,+10", "+10,+10", null)] [TestCase("0,0", 1, "-10,+1", "+10,+1", "0,+1")] [TestCase("0,0", 1, "-10,0", "+10,0", "+1,0;-1,0")] [TestCase("0,0", 1, "-10,-1", "+10,-1", "0,-1")] - [TestCase("0,0", 1, "-10,-10", "+10,-10", "empty")] + [TestCase("0,0", 1, "-10,-10", "+10,-10", null)] ////segments cross the circle's contour just 1 time - [TestCase("0,0", 1, "+0,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "+0,+10", "+10,+10", null)] [TestCase("0,0", 1, "+0,+1", "+10,+1", "0,1")] [TestCase("0,0", 1, "+0,+0", "+10,+0", "1,0")] [TestCase("0,0", 1, "+0,-1", "+10,-1", "0,-1")] - [TestCase("0,0", 1, "+0,-10", "+10,-10", "empty")] + [TestCase("0,0", 1, "+0,-10", "+10,-10", null)] ////segment contains no intersections(px of the startingPoint is too big to intersect with the circle) - [TestCase("0,0", 1, "+10,+10", "+100,+10", "empty")] - [TestCase("0,0", 1, "+10,+1", "+100,+1", "empty")] - [TestCase("0,0", 1, "+10,+0", "+100,0", "empty")] - [TestCase("0,0", 1, "+10,-1", "+100,-1", "empty")] - [TestCase("0,0", 1, "+10,-10", "+100,-10", "empty")] + [TestCase("0,0", 1, "+10,+10", "+100,+10", null)] + [TestCase("0,0", 1, "+10,+1", "+100,+1", null)] + [TestCase("0,0", 1, "+10,+0", "+100,0", null)] + [TestCase("0,0", 1, "+10,-1", "+100,-1", null)] + [TestCase("0,0", 1, "+10,-10", "+100,-10", null)] //parallel to Y-axis ////segment contains the all intersections(same to the cases of circle and line) - [TestCase("0,0", 1, "-10,-10", "-10,+10", "empty")] + [TestCase("0,0", 1, "-10,-10", "-10,+10", null)] [TestCase("0,0", 1, "-1,-10", "-1,+10", "-1,0")] [TestCase("0,0", 1, "+0,-10", "+0,+10", "0,+1;0,-1")] [TestCase("0,0", 1, "+1,-10", "+1,+10", "+1,0")] - [TestCase("0,0", 1, "+10,-10", "+10,+10", "EMPTY")] + [TestCase("0,0", 1, "+10,-10", "+10,+10", null)] ////segments cross the circle's contour just 1 time - [TestCase("0,0", 1, "+10,0", "+10,+10", "empty")] + [TestCase("0,0", 1, "+10,0", "+10,+10", null)] [TestCase("0,0", 1, "+1,0", "+1,+10", "+1,0")] [TestCase("0,0", 1, "+0,0", "+0,+10", "0,+1")] [TestCase("0,0", 1, "-1,0", "-1,+10", "-1,0")] - [TestCase("0,0", 1, "-10,0", "-10,+10", "empty")] + [TestCase("0,0", 1, "-10,0", "-10,+10", null)] ////segment contains no intersections(py of the startingPoint is too big to intersect with the circle) - [TestCase("0,0", 1, "+10,+10", "+10,+100", "empty")] - [TestCase("0,0", 1, "+1,+10", "+1,+100", "empty")] - [TestCase("0,0", 1, "+0,+10", "+0,+100", "empty")] - [TestCase("0,0", 1, "-1,+10", "-1,+100", "empty")] - [TestCase("0,0", 1, "-10,+10", "-10,+100", "empty")] + [TestCase("0,0", 1, "+10,+10", "+10,+100", null)] + [TestCase("0,0", 1, "+1,+10", "+1,+100", null)] + [TestCase("0,0", 1, "+0,+10", "+0,+100", null)] + [TestCase("0,0", 1, "-1,+10", "-1,+100", null)] + [TestCase("0,0", 1, "-10,+10", "-10,+100", null)] //general cases ////segment contains the all intersections(same to the cases of circle and line) - [TestCase("0,0", 1, "-10,+10", "+10,+10", "empty")] + [TestCase("0,0", 1, "-10,+10", "+10,+10", null)] [TestCase("0,0", 1, "-1.414213562373095,0", "0,+1.414213562373095", "-0.707,0.707")] [TestCase("0,0", 1, "-10,-10", "+10,+10", "+0.707,+0.707;-0.707,-0.707")] [TestCase("0,0", 1, "0,-1.41421356", "+1.41421356,0", "+0.707,-0.707")] - [TestCase("0,0", 1, "0,-10", "+10,0", "empty")] + [TestCase("0,0", 1, "0,-10", "+10,0", null)] ////segments cross the circle's contour just 1 time - [TestCase("0,0", 1, "+10,0", "+10,+10", "empty")] + [TestCase("0,0", 1, "+10,0", "+10,+10", null)] [TestCase("0,0", 1, "+1,0", "+1,+10", "+1,0")] [TestCase("0,0", 1, "+0,0", "+0,+10", "0,+1")] [TestCase("0,0", 1, "-1,0", "-1,+10", "-1,0")] - [TestCase("0,0", 1, "-10,0", "-10,+10", "empty")] + [TestCase("0,0", 1, "-10,0", "-10,+10", null)] ////segment contains no intersections(py of the startingPoint is too big to intersect with the circle) - [TestCase("0,0", 1, "+10,+10", "+10,+100", "empty")] - [TestCase("0,0", 1, "+1,+10", "+1,+100", "empty")] - [TestCase("0,0", 1, "+0,+10", "+0,+100", "empty")] - [TestCase("0,0", 1, "-1,+10", "-1,+100", "empty")] - [TestCase("0,0", 1, "-10,+10", "-10,+100", "empty")] - public void CircleIntersectWithLineSegment2D(string sCenter, double radius, string sStart, string sEnd, string expectedIntersectionsAsString) + [TestCase("0,0", 1, "+10,+10", "+10,+100", null)] + [TestCase("0,0", 1, "+1,+10", "+1,+100", null)] + [TestCase("0,0", 1, "+0,+10", "+0,+100", null)] + [TestCase("0,0", 1, "-1,+10", "-1,+100", null)] + [TestCase("0,0", 1, "-10,+10", "-10,+100", null)] + public void CircleIntersectWithLineSegment2D(string sCenter, double radius, string sStart, string sEnd, string intersections) { var circle = new Circle2D(Point2D.Parse(sCenter), radius); var segment = new LineSegment2D(Point2D.Parse(sStart), Point2D.Parse(sEnd)); var actual = circle.IntersectWith(segment); - var expected = parseToPointsArray(expectedIntersectionsAsString); + var expected = parseToPointsArray(intersections); for (int i = 0; i < Math.Min(actual.Length, expected.Length); i++) { var a = actual[i]; @@ -169,7 +168,7 @@ public void CircleIntersectWithLineSegment2D(string sCenter, double radius, stri private Point2D[] parseToPointsArray(string input) { - if (input.ToLower().Contains("empty")) + if (input == null) { return new Point2D[] { }; } @@ -177,6 +176,7 @@ private Point2D[] parseToPointsArray(string input) var result = input.Split(';') .Select(s => Point2D.Parse(s)) .ToArray(); + return result; } }