Improve contour FindPointInPolygon() reliability (2).
This commit is contained in:
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user