Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0a2521d
Feat: Line2D.DistanceTo(point)
f-frhs Aug 17, 2023
c3ad590
feat: Circle2D.IntersectWith(Line2D)
f-frhs Nov 23, 2023
037d3c5
doc: fix xml comment
f-frhs Nov 24, 2023
fb0314b
refactor: extract the private method findParameterTs(Line2D)
f-frhs Nov 25, 2023
baf6605
feat: Circle2D.IntersectWith(LineSegment2D)
f-frhs Nov 25, 2023
c2612b6
doc: fix the variable-name list in comment
f-frhs Nov 28, 2023
4685302
fix: a typo
f-frhs Nov 28, 2023
f3e4731
change: use the fact that dot-product of the unit vector is always 1.0
f-frhs Nov 28, 2023
847cdaf
Revert "Feat: Line2D.DistanceTo(point)"
f-frhs Nov 28, 2023
2d222ac
remove: src/Spatial/Extensions/DoubleExtensions.cs
f-frhs Nov 28, 2023
571cf7d
doc: revise xml comments
f-frhs Dec 1, 2023
9e33c1b
fix a typo
f-frhs Dec 1, 2023
7c5df6a
test: fix testcases to test number of intersections
f-frhs Dec 3, 2023
1a527b1
fix: IntersectionWith() to return a single point when a line tangent …
f-frhs Dec 3, 2023
b27fdb1
test: Add tests for intersection of Circle and LineSegment2D
f-frhs Dec 3, 2023
dc7ea85
test: add TODO comment
f-frhs Dec 3, 2023
5930b12
refactor: rename line to segment
f-frhs Dec 3, 2023
0e7eb69
fix: type declaration (from 1d to 1.0)
f-frhs Dec 7, 2023
5c3cd70
test: fix testcases to use expected points
f-frhs Dec 7, 2023
ab59a23
test: fix testcases to use expected points
f-frhs Dec 7, 2023
451a87d
test: add testcases where the line is parallel to the Y-axis
f-frhs Dec 7, 2023
3d3748b
test: add testcases parallel to Y-axis and general cases
f-frhs Dec 7, 2023
6b8c3db
test: add testcases for Intersection of Circle2D with LIneSegment2D
f-frhs Dec 7, 2023
f3815ed
test: replace +01 to +1
f-frhs Dec 7, 2023
acccdbf
Minor changes in test
jkalias Dec 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/Spatial.Tests/Euclidean/Circle2DTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,34 @@ public void CircleFromThreePointsArgumentException()

Assert.Throws<ArgumentException>(() => { 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)
{
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]);
}

[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);
}
}
}
25 changes: 25 additions & 0 deletions src/Spatial.Tests/Euclidean/Line2DTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
}
60 changes: 60 additions & 0 deletions src/Spatial/Euclidean/Circle2D.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
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;

namespace MathNet.Spatial.Euclidean
{
Expand Down Expand Up @@ -131,6 +134,63 @@ public static Circle2D FromPoints(Point2D pointA, Point2D pointB, Point2D pointC
return new Circle2D(center, radius);
}

/// <summary>
/// Returns intersection a point2D array if this circle and the given line have the intersections
/// </summary>
/// <param name="line">the given line</param>
/// <returns>intersections as a Point2D Array, depending on the count.</returns>
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)
// 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 = this.Center.ToVector2D(); //center of circle
var s = line.StartPoint.ToVector2D();
var d = line.Direction;
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 soluions = FindRoots.Polynomial(new[] { c, b, a });
var ts = soluions
.Where(z => z.IsReal())
.Select(z => z.Real)
.ToArray();
return ts;
}

/// <summary>
/// Returns intersection a point2D array if this circle and the given line have the intersections
/// </summary>
/// <param name="line">the given line-segment</param>
/// <returns>intersections as a Point2D Array, depending on the count.</returns>
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;
}


/// <summary>
/// Returns a value to indicate if a pair of circles are equal
/// </summary>
Expand Down
67 changes: 61 additions & 6 deletions src/Spatial/Euclidean/Line2D.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand All @@ -27,6 +27,21 @@ public struct Line2D : IEquatable<Line2D>, IXmlSerializable
/// </summary>
public Point2D EndPoint { get; private set; }

/// <summary>
/// The parameter `a` in the line equation: ax + by + c = 0
/// </summary>
public double A { get; private set; }

/// <summary>
/// The parameter `b` in the line equation: ax + by + c = 0
/// </summary>
public double B { get; private set; }

/// <summary>
/// The parameter `c` in the line equation: ax + by + c = 0
/// </summary>
public double C { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="Line2D"/> struct.
/// Throws an ArgumentException if the <paramref name="startPoint"/> is equal to the <paramref name="endPoint"/>.
Expand All @@ -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;
}

/// <summary>
Expand Down Expand Up @@ -294,5 +328,26 @@ void IXmlSerializable.WriteXml(XmlWriter writer)
writer.WriteElement("StartPoint", StartPoint);
writer.WriteElement("EndPoint", EndPoint);
}

/// <summary>
/// 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.
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public double SignedDistanceTo(Point2D p)
{
var result = A * p.X + B * p.Y + C;
return result;
}

/// <summary>
/// Compute the absolute distance from this `line` to the given point `p`.
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public double DistanceTo(Point2D p)
{
return Math.Abs(SignedDistanceTo(p));
}
}
}
4 changes: 4 additions & 0 deletions src/Spatial/Euclidean/LineSegment2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,5 +236,9 @@ void IXmlSerializable.WriteXml(XmlWriter writer)
writer.WriteElement("StartPoint", StartPoint);
writer.WriteElement("EndPoint", EndPoint);
}

/// <summary>convert this to Line2D </summary>
/// <returns>converted Line2D object</returns>
public Line2D ToLine2D() => new Line2D(StartPoint, EndPoint);
}
}
21 changes: 21 additions & 0 deletions src/Spatial/Extensions/DoubleExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}