diff --git a/src/UglyToad.PdfPig.Core/PdfPoint.cs b/src/UglyToad.PdfPig.Core/PdfPoint.cs
index 60fc5f9b..7286bcd8 100644
--- a/src/UglyToad.PdfPig.Core/PdfPoint.cs
+++ b/src/UglyToad.PdfPig.Core/PdfPoint.cs
@@ -67,7 +67,7 @@
{
return new PdfPoint(X + dx, Y);
}
-
+
///
/// Creates a new which is the current point moved in the y direction relative to its current position by a value.
///
diff --git a/src/UglyToad.PdfPig.Tests/Geometry/PdfPointTests.cs b/src/UglyToad.PdfPig.Tests/Geometry/PdfPointTests.cs
index a43c6fb1..600ce40e 100644
--- a/src/UglyToad.PdfPig.Tests/Geometry/PdfPointTests.cs
+++ b/src/UglyToad.PdfPig.Tests/Geometry/PdfPointTests.cs
@@ -528,6 +528,52 @@
}
}
};
+
+ public static IEnumerable Issue458Data => new[]
+ {
+ new object[]
+ {
+ new PdfPoint[]
+ {
+ new PdfPoint(134.74199999999985, 1611.657),
+ new PdfPoint(277.58043749999985, 1611.657),
+ new PdfPoint(314.74199999999985, 1611.657),
+ new PdfPoint(507.0248828124999, 1611.657),
+ new PdfPoint(545.1419999999998, 1611.657),
+ new PdfPoint(632.9658281249997, 1611.657),
+ new PdfPoint(668.5709999999998, 1611.657),
+ new PdfPoint(831.3395078125002, 1611.657),
+ new PdfPoint(868.1139999999998, 1611.657),
+ new PdfPoint(892.8907187499999, 1611.657),
+ new PdfPoint(1010.0569999999999, 1611.6569999999997),
+ new PdfPoint(1046.2174003906248, 1611.7654812011715),
+ new PdfPoint(1010.0569999999999, 1611.657),
+ new PdfPoint(1046.2174003906248, 1611.7654812011717),
+ new PdfPoint(1085.145, 1611.8822639999996),
+ new PdfPoint(1255.484941406251, 1612.3932838242179),
+ new PdfPoint(1301.144, 1612.5302609999994),
+ new PdfPoint(1359.0006406250002, 1612.7038309218747),
+ new PdfPoint(1301.144, 1612.5302609999997),
+ new PdfPoint(1359.0006406250002, 1612.703830921875),
+ new PdfPoint(1400.915, 1612.8295739999996),
+ new PdfPoint(1505.379062499999, 1613.1429661874993),
+ new PdfPoint(1400.915, 1612.8295739999999),
+ new PdfPoint(1505.379062499999, 1613.1429661874995),
+ new PdfPoint(1543.886, 1613.2584869999996),
+ new PdfPoint(1600.9401015625003, 1613.4296493046872),
+ new PdfPoint(1641.597, 1613.5516199999997),
+ new PdfPoint(1764.5577421874998, 1613.9205022265612),
+ new PdfPoint(1641.597, 1613.55162),
+ new PdfPoint(1764.5577421874998, 1613.9205022265614)
+ },
+ new PdfPoint[]
+ {
+ new PdfPoint(134.74199999999985, 1611.657),
+ new PdfPoint(1010.0569999999999, 1611.6569999999997),
+ new PdfPoint(1764.5577421874998, 1613.9205022265614),
+ }
+ }
+ };
#endregion
[Fact]
@@ -570,7 +616,6 @@
}
}
-
[Theory]
[MemberData(nameof(MinimumAreaRectangleData))]
public void MinimumAreaRectangle(PdfPoint[] points, PdfPoint[] expected)
@@ -585,5 +630,51 @@
Assert.Equal(expected[i], mar[i], PointComparer);
}
}
+
+ [Theory]
+ [MemberData(nameof(Issue458Data))]
+ public void Issue458(PdfPoint[] points, PdfPoint[] expected)
+ {
+ /*
+ * https://github.com/UglyToad/PdfPig/issues/458
+ * An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in System.Linq.dll: 'Specified argument was out of the range of valid values.'
+ * at System.Linq.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument)
+ * at System.Linq.Enumerable.ElementAt[TSource](IEnumerable`1 source, Int32 index)
+ */
+
+ var result = GeometryExtensions.GrahamScan(points);
+
+ // Data is noisy so we just check it does not throw an exception
+ // and that key points are present (other points might be present,
+ // e.g. 'not enough equal dupplicates' or 'not collinear enough' points)
+ foreach (var point in expected)
+ {
+ Assert.Contains(point, result);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(Issue458Data))]
+ public void Issue458_Inv(PdfPoint[] points, PdfPoint[] expected)
+ {
+ /*
+ * https://github.com/UglyToad/PdfPig/issues/458
+ * An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in System.Linq.dll: 'Specified argument was out of the range of valid values.'
+ * at System.Linq.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument)
+ * at System.Linq.Enumerable.ElementAt[TSource](IEnumerable`1 source, Int32 index)
+ */
+ var pointsInv = points.Select(p => new PdfPoint(p.Y, p.X)).ToArray();
+ var expectedInv = expected.Select(p => new PdfPoint(p.Y, p.X)).ToArray();
+
+ var result = GeometryExtensions.GrahamScan(pointsInv);
+
+ // Data is noisy so we just check it does not throw an exception
+ // and that key points are present (other points might be present,
+ // e.g. 'not enough equal dupplicates' or 'not collinear enough' points)
+ foreach (var point in expectedInv)
+ {
+ Assert.Contains(point, result);
+ }
+ }
}
}
diff --git a/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs b/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs
index 283cc6d2..68846ce1 100644
--- a/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs
+++ b/src/UglyToad.PdfPig/Geometry/GeometryExtensions.cs
@@ -269,11 +269,12 @@
double polarAngle(PdfPoint point1, PdfPoint point2)
{
+ // This is used for grouping, we could use Math.Round()
return Math.Atan2(point2.Y - point1.Y, point2.X - point1.X) % Math.PI;
}
- Stack stack = new Stack();
- var sortedPoints = points.OrderBy(p => p.Y).ThenBy(p => p.X).ToList();
+ var stack = new Stack();
+ var sortedPoints = points.OrderBy(p => p.X).ThenBy(p => p.Y).ToList();
var P0 = sortedPoints[0];
var groups = sortedPoints.Skip(1).GroupBy(p => polarAngle(P0, p)).OrderBy(g => g.Key);
@@ -309,7 +310,7 @@
for (int i = 2; i < sortedPoints.Count; i++)
{
var point = sortedPoints[i];
- while (!ccw(stack.ElementAt(1), stack.Peek(), point))
+ while (stack.Count > 1 && !ccw(stack.ElementAt(1), stack.Peek(), point))
{
stack.Pop();
}