Improve contour FindPointInPolygon() reliability (2).

This commit is contained in:
wo80
2022-02-23 12:42:54 +01:00
parent bc955bb740
commit 2e83d7ee5e
3 changed files with 76 additions and 4 deletions
@@ -0,0 +1,41 @@
using NUnit.Framework;
using TriangleNet.Geometry;
using TriangleNet.Tools;
namespace TriangleNet.Tests.Tools
{
public class IntersectionHelperTest
{
[Test]
public void TestIsPointOnSegment()
{
var a = new Vertex(1.0, 1.0);
var b = new Vertex(2.0, 2.0);
// Test point = segment start point.
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(1.0, 1.0)));
// Test point = segment end point.
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0, 2.0)));
// Test point on segment.
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(1.5, 1.5)));
// Test point collinear, but not on segment.
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(0.0, 0.0)));
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(3.0, 3.0)));
// Test point not on segment.
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(1.5, 0.5)));
double eps = 1e-12;
// Test point collinear near endpoint, but not on segment.
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0 + eps, 2.0 + eps)));
Assert.IsFalse(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0 - eps, 2.0 + eps)));
// Test point collinear near endpoint on segment.
Assert.IsTrue(IntersectionHelper.IsPointOnSegment(a, b, new Vertex(2.0 - eps, 2.0 - eps)));
}
}
}
+3 -4
View File
@@ -8,6 +8,7 @@ namespace TriangleNet.Geometry
{
using System;
using System.Collections.Generic;
using TriangleNet.Tools;
public class Contour
{
@@ -245,17 +246,15 @@ namespace TriangleNet.Geometry
/// <summary>
/// Work around IsPointInPolygon() failing for points on segments.
/// </summary>
private static bool IsPointOnSegment(Point test, List<Vertex> contour, double esp = 1e-12)
private static bool IsPointOnSegment(Point test, List<Vertex> contour, double eps = 1e-12)
{
var p = RobustPredicates.Default;
int count = contour.Count;
int i = count - 1;
for (int j = 0; j < count; j++)
{
if (Math.Abs(p.CounterClockwise(contour[i], test, contour[j])) < esp)
if (IntersectionHelper.IsPointOnSegment(contour[i], contour[j], test, eps))
{
return true;
}
+32
View File
@@ -6,10 +6,42 @@
namespace TriangleNet.Tools
{
using System;
using TriangleNet.Geometry;
public static class IntersectionHelper
{
/// <summary>
/// Check if a given test point lies on a segment.
/// </summary>
/// <param name="a">The segment start point.</param>
/// <param name="b">The segment end point.</param>
/// <param name="test">The point to test.</param>
/// <param name="eps">Threshold to test collinearity (default = 1e-12).</param>
/// <returns></returns>
public static bool IsPointOnSegment(Point a, Point b, Point test, double eps = 1e-12)
{
// The cross product.
double cross = (test.Y - a.Y) * (b.X - a.X) - (test.X - a.X) * (b.Y - a.Y);
// Check if points are collinear.
if (Math.Abs(cross) > eps) return false;
// The dot product (projection of test point onto segment).
double dot = (test.X - a.X) * (b.X - a.X) + (test.Y - a.Y) * (b.Y - a.Y);
// Check if test point is actually between a and b (left of a).
if (dot < 0) return false;
// Length of the segment.
double ab = (b.X - a.X) * (b.X - a.X) + (b.Y - a.Y) * (b.Y - a.Y);
// Check if test point is actually between a and b (right of b).
if (dot > ab) return false;
return true;
}
/// <summary>
/// Compute intersection of two segments.
/// </summary>