Index: Core/Common/src/Core.Common.Geometry/AdvancedMath2D.cs
===================================================================
diff -u -r2016e52c40bafa21e1c6d49c9cdc54cc31c6f3a0 -red0d7390c14c7d453b3b21800a636de5c16e3ab5
--- Core/Common/src/Core.Common.Geometry/AdvancedMath2D.cs (.../AdvancedMath2D.cs) (revision 2016e52c40bafa21e1c6d49c9cdc54cc31c6f3a0)
+++ Core/Common/src/Core.Common.Geometry/AdvancedMath2D.cs (.../AdvancedMath2D.cs) (revision ed0d7390c14c7d453b3b21800a636de5c16e3ab5)
@@ -149,6 +149,39 @@
return new Point2D(interiorPoint.X, interiorPoint.Y);
}
+ ///
+ /// Gets an indicator whether the given lies in the polygon.
+ ///
+ /// The point to check.
+ /// The outer ring of the polygon.
+ /// The inner rings of the polygon.
+ /// true when the lies in the polygon; false otherwise.
+ /// Thrown when any parameter is null.
+ public static bool PointInPolygon(Point2D point, IEnumerable outerRing, IEnumerable> innerRings)
+ {
+ if (point == null)
+ {
+ throw new ArgumentNullException(nameof(point));
+ }
+
+ if (outerRing == null)
+ {
+ throw new ArgumentNullException(nameof(outerRing));
+ }
+
+ if (innerRings == null)
+ {
+ throw new ArgumentNullException(nameof(innerRings));
+ }
+
+ Polygon outerPolygon = PointsToPolygon(outerRing);
+ IEnumerable innerPolygons = innerRings.Select(PointsToPolygon).ToArray();
+
+ var polygon = new Polygon(outerPolygon.Shell, innerPolygons.Select(p => p.Shell).ToArray());
+
+ return polygon.Covers(new Point(point.X, point.Y));
+ }
+
private static IEnumerable GetPointsFromLine(IEnumerable line, double completingPointsLevel)
{
foreach (Point2D point in line)
Index: Core/Common/test/Core.Common.Geometry.Test/AdvancedMath2DTest.cs
===================================================================
diff -u -rb9ceec3c71d972d3d467c1520033ac48cf77b2e9 -red0d7390c14c7d453b3b21800a636de5c16e3ab5
--- Core/Common/test/Core.Common.Geometry.Test/AdvancedMath2DTest.cs (.../AdvancedMath2DTest.cs) (revision b9ceec3c71d972d3d467c1520033ac48cf77b2e9)
+++ Core/Common/test/Core.Common.Geometry.Test/AdvancedMath2DTest.cs (.../AdvancedMath2DTest.cs) (revision ed0d7390c14c7d453b3b21800a636de5c16e3ab5)
@@ -68,10 +68,10 @@
};
// Call
- TestDelegate test = () => AdvancedMath2D.PolygonIntersectionWithPolygon(polyB, polyA);
+ void Call() => AdvancedMath2D.PolygonIntersectionWithPolygon(polyB, polyA);
// Assert
- Assert.Throws(test);
+ Assert.Throws(Call);
}
[Test]
@@ -259,26 +259,24 @@
public void FromXToXY_WithoutPoints_ThrowsArgumentNullException()
{
// Call
- TestDelegate test = () => AdvancedMath2D.FromXToXY(null, new Point2D(0, 0), 3, 2);
+ void Call() => AdvancedMath2D.FromXToXY(null, new Point2D(0, 0), 3, 2);
// Assert
- string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
- test,
- "Cannot transform to coordinates without a source.").ParamName;
- Assert.AreEqual("xCoordinates", paramName);
+ var exception = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
+ Call, "Cannot transform to coordinates without a source.");
+ Assert.AreEqual("xCoordinates", exception.ParamName);
}
[Test]
public void FromXToXY_WithoutReferencePoint_ThrowsArgumentNullException()
{
// Call
- TestDelegate test = () => AdvancedMath2D.FromXToXY(new double[0], null, 3, 2);
+ void Call() => AdvancedMath2D.FromXToXY(new double[0], null, 3, 2);
// Assert
- string paramName = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
- test,
- "Cannot transform to coordinates without a reference point.").ParamName;
- Assert.AreEqual("referencePoint", paramName);
+ var exception = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(
+ Call, "Cannot transform to coordinates without a reference point.");
+ Assert.AreEqual("referencePoint", exception.ParamName);
}
[Test]
@@ -380,10 +378,10 @@
public void CompleteLineToPolygon_WithoutLine_ThrowsArgumentNullException()
{
// Call
- TestDelegate test = () => AdvancedMath2D.CompleteLineToPolygon(null, double.NaN).ToArray();
+ void Call() => AdvancedMath2D.CompleteLineToPolygon(null, double.NaN).ToArray();
// Assert
- var exception = Assert.Throws(test);
+ var exception = Assert.Throws(Call);
Assert.AreEqual("line", exception.ParamName);
}
@@ -394,11 +392,11 @@
IEnumerable points = Enumerable.Repeat(new Point2D(3, 2), pointCount);
// Call
- TestDelegate test = () => AdvancedMath2D.CompleteLineToPolygon(points, double.NaN).ToArray();
+ void Call() => AdvancedMath2D.CompleteLineToPolygon(points, double.NaN).ToArray();
// Assert
const string message = "The line needs to have at least two points to be able to create a complete polygon.";
- var exception = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(test, message);
+ var exception = TestHelper.AssertThrowsArgumentExceptionAndTestMessage(Call, message);
Assert.AreEqual("line", exception.ParamName);
}
@@ -468,12 +466,7 @@
public void GetPolygonInteriorPoint_TrianglePolygon_ReturnsInteriorPoint()
{
// Setup
- var outerRing = new[]
- {
- new Point2D(0, 0),
- new Point2D(3, 4),
- new Point2D(6, 0)
- };
+ Point2D[] outerRing = CreateTrianglePolygon();
// Call
Point2D interiorPoint = AdvancedMath2D.GetPolygonInteriorPoint(outerRing, new IEnumerable[0]);
@@ -486,43 +479,100 @@
public void GetPolygonInteriorPoint_PolygonWithHoles_ReturnsInteriorPoint()
{
// Setup
- var outerRing = new[]
- {
- new Point2D(0, 0),
- new Point2D(0, 4),
- new Point2D(2, 6),
- new Point2D(4, 4),
- new Point2D(4, 0),
- new Point2D(2, -2)
- };
+ Point2D[] outerRing = CreateCustomPolygon();
+ Point2D[][] innerRings = CreateInnerRings();
+
+ // Call
+ Point2D interiorPoint = AdvancedMath2D.GetPolygonInteriorPoint(outerRing, innerRings);
- var innerRing1 = new[]
- {
- new Point2D(1, 3),
- new Point2D(2, 4),
- new Point2D(3, 3),
- new Point2D(2, 2)
- };
+ // Assert
+ Assert.AreEqual(new Point2D(0.75, 2.5), interiorPoint);
+ }
- var innerRing2 = new[]
- {
- new Point2D(1, 1),
- new Point2D(2, 2),
- new Point2D(3, 1),
- new Point2D(2, 0)
- };
+ [Test]
+ public void PointInPolygon_PointNull_ThrowsArgumentNullException()
+ {
+ // Call
+ void Call() => AdvancedMath2D.PointInPolygon(null, Enumerable.Empty(), Enumerable.Empty>());
+ // Assert
+ var exception = Assert.Throws(Call);
+ Assert.AreEqual("point", exception.ParamName);
+ }
+
+ [Test]
+ public void PointInPolygon_OuterRingNull_ThrowsArgumentNullException()
+ {
// Call
- Point2D interiorPoint = AdvancedMath2D.GetPolygonInteriorPoint(outerRing, new[]
- {
- innerRing1,
- innerRing2
- });
+ void Call() => AdvancedMath2D.PointInPolygon(new Point2D(0, 0), null, Enumerable.Empty>());
// Assert
- Assert.AreEqual(new Point2D(0.75, 2.5), interiorPoint);
+ var exception = Assert.Throws(Call);
+ Assert.AreEqual("outerRing", exception.ParamName);
}
+ [Test]
+ public void PointInPolygon_InnerRingsNull_ThrowsArgumentNullException()
+ {
+ // Call
+ void Call() => AdvancedMath2D.PointInPolygon(new Point2D(0, 0), Enumerable.Empty(), null);
+
+ // Assert
+ var exception = Assert.Throws(Call);
+ Assert.AreEqual("innerRings", exception.ParamName);
+ }
+
+ [Test]
+ [TestCaseSource(nameof(GetPolygons))]
+ public void PointInPolygon_PointInPolygon_ReturnsTrue(IEnumerable outerRing, IEnumerable> innerRings)
+ {
+ // Setup
+ var point = new Point2D(1, 1);
+
+ // Call
+ bool pointInPolygon = AdvancedMath2D.PointInPolygon(point, outerRing, innerRings);
+
+ // Assert
+ Assert.IsTrue(pointInPolygon);
+ }
+
+ [Test]
+ [TestCaseSource(nameof(GetPolygons))]
+ public void PointInPolygon_PointOutsidePolygon_ReturnsFalse(IEnumerable outerRing, IEnumerable> innerRings)
+ {
+ // Setup
+ var point = new Point2D(-1, -1);
+
+ // Call
+ bool pointInPolygon = AdvancedMath2D.PointInPolygon(point, outerRing, innerRings);
+
+ // Assert
+ Assert.IsFalse(pointInPolygon);
+ }
+
+ [Test]
+ public void PointInPolygon_PointInHole_ReturnsFalse()
+ {
+ // Setup
+ Point2D[] outerRing = CreateCustomPolygon();
+ Point2D[][] innerRings = CreateInnerRings();
+
+ var point = new Point2D(2, 3);
+
+ // Call
+ bool pointInPolygon = AdvancedMath2D.PointInPolygon(point, outerRing, innerRings);
+
+ // Assert
+ Assert.IsFalse(pointInPolygon);
+ }
+
+ private static IEnumerable GetPolygons()
+ {
+ yield return new TestCaseData(CreateBasePolygon(), Enumerable.Empty>());
+ yield return new TestCaseData(CreateTrianglePolygon(), Enumerable.Empty>());
+ yield return new TestCaseData(CreateCustomPolygon(), CreateInnerRings());
+ }
+
private static double[] ThreeRandomXCoordinates()
{
var random = new Random(21);
@@ -559,5 +609,49 @@
new Point2D(4, 0)
};
}
+
+ private static Point2D[] CreateTrianglePolygon()
+ {
+ return new[]
+ {
+ new Point2D(0, 0),
+ new Point2D(3, 4),
+ new Point2D(6, 0)
+ };
+ }
+
+ private static Point2D[] CreateCustomPolygon()
+ {
+ return new[]
+ {
+ new Point2D(0, 0),
+ new Point2D(0, 4),
+ new Point2D(2, 6),
+ new Point2D(4, 4),
+ new Point2D(4, 0),
+ new Point2D(2, -2)
+ };
+ }
+
+ private static Point2D[][] CreateInnerRings()
+ {
+ return new[]
+ {
+ new[]
+ {
+ new Point2D(1, 3),
+ new Point2D(2, 4),
+ new Point2D(3, 3),
+ new Point2D(2, 2)
+ },
+ new[]
+ {
+ new Point2D(1, 1),
+ new Point2D(2, 2),
+ new Point2D(3, 1),
+ new Point2D(2, 0)
+ }
+ };
+ }
}
}
\ No newline at end of file