Improve contour FindPointInPolygon() reliability.

This commit is contained in:
wo80
2022-02-23 10:30:29 +01:00
parent 37ab83ae1f
commit bc955bb740
2 changed files with 67 additions and 2 deletions
@@ -1,5 +1,7 @@
using NUnit.Framework;
using TriangleNet.Geometry;
using System;
using System.Collections.Generic;
namespace TriangleNet.Tests.Geometry
{
@@ -23,5 +25,43 @@ namespace TriangleNet.Tests.Geometry
Assert.IsTrue(p.X > 0d && p.X < 1d && p.Y > 0d && p.Y < 1d);
}
[Test]
public void TestFindInteriorPointL()
{
// L-shaped contour (FindPointInPolygon() produces a test candidate
// which lies exactly on a segment where IsPointInPolygon() returns
// true, so IsPointOnSegment() is actually needed here).
var points = new List<Vertex>()
{
new Vertex(3, 1),
new Vertex(1, 1),
new Vertex(1, 3),
new Vertex(2, 3),
new Vertex(2, 2),
new Vertex(3, 2)
};
var contour = new Contour(points);
var poly = new Polygon(6);
poly.Add(contour, true);
var h = poly.Holes[0];
var p = RobustPredicates.Default;
int count = points.Count;
int i = count - 1;
for (int j = 0; j < count; j++)
{
double ccw = p.CounterClockwise(points[i], h, points[j]);
Assert.Greater(Math.Abs(ccw), 1e-12);
i = j;
}
}
}
}
+27 -2
View File
@@ -185,7 +185,7 @@ namespace TriangleNet.Geometry
test.x = bx + dx * h;
test.y = by + dy * h;
if (bounds.Contains(test) && IsPointInPolygon(test, contour))
if (bounds.Contains(test) && IsPointInPolygon(test, contour) && !IsPointOnSegment(test, contour))
{
return test;
}
@@ -194,7 +194,7 @@ namespace TriangleNet.Geometry
test.x = bx - dx * h;
test.y = by - dy * h;
if (bounds.Contains(test) && IsPointInPolygon(test, contour))
if (bounds.Contains(test) && IsPointInPolygon(test, contour) && !IsPointOnSegment(test, contour))
{
return test;
}
@@ -241,6 +241,31 @@ namespace TriangleNet.Geometry
return inside;
}
/// <summary>
/// Work around IsPointInPolygon() failing for points on segments.
/// </summary>
private static bool IsPointOnSegment(Point test, List<Vertex> contour, double esp = 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)
{
return true;
}
i = j;
}
return false;
}
#endregion
}
}