Skip to content

Commit e987bd8

Browse files
Merge pull request #171 from SixLabors/af/fix-SkipEdgesBeforeMinY
Fix SkipEdgesBeforeMinY algorithm
2 parents eb510f3 + 8bb6407 commit e987bd8

4 files changed

Lines changed: 71 additions & 6 deletions

File tree

src/ImageSharp.Drawing/Shapes/Rasterization/PolygonScanner.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,24 +139,37 @@ private void SkipEdgesBeforeMinY()
139139
int i0 = 1;
140140
int i1 = 0;
141141

142-
// Do fake scans for the lines belonging to edge start and endpoints before minY
142+
// Do fake scans of the lines that start before minY.
143+
// Instead of fake scanning at every possible subpixel Y location,
144+
// only "scan" at start edge Y positions (defined by values in sorted0) and end Y positions (defined by values in sorted1).
145+
// Walk the two lists simultaneously following mergesort logic.
143146
while (this.SubPixelY < this.minY)
144147
{
145148
this.EnterEdges();
146149
this.LeaveEdges();
147150
this.activeEdges.RemoveLeavingEdges();
148151

149-
float y0 = this.edges[this.sorted0[i0]].Y0;
150-
float y1 = this.edges[this.sorted1[i1]].Y1;
152+
bool hasMore0 = i0 < this.sorted0.Length;
153+
bool hasMore1 = i1 < this.sorted1.Length;
154+
155+
if (!hasMore0 && !hasMore1)
156+
{
157+
// The entire polygon is outside the scan region, we skipped all edges,
158+
// scanning will not find any intersections.
159+
break;
160+
}
161+
162+
float y0 = hasMore0 ? this.edges[this.sorted0[i0]].Y0 : float.MaxValue;
163+
float y1 = hasMore1 ? this.edges[this.sorted1[i1]].Y1 : float.MaxValue;
151164

152165
if (y0 < y1)
153166
{
154-
this.SubPixelY = y1;
167+
this.SubPixelY = y0;
155168
i0++;
156169
}
157170
else
158171
{
159-
this.SubPixelY = y0;
172+
this.SubPixelY = y1;
160173
i1++;
161174
}
162175
}

tests/ImageSharp.Drawing.Tests/Drawing/DrawPathTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Numerics;
66
using SixLabors.ImageSharp.Drawing.Processing;
77
using SixLabors.ImageSharp.PixelFormats;
8+
using SixLabors.ImageSharp.Processing;
89
using Xunit;
910

1011
namespace SixLabors.ImageSharp.Drawing.Tests.Drawing
@@ -74,5 +75,25 @@ public void PathExtendingOffEdgeOfImageShouldNotBeCropped<TPixel>(TestImageProvi
7475
appendPixelTypeToFileName: false,
7576
appendSourceFileOrDescription: false);
7677
}
78+
79+
[Theory]
80+
[WithSolidFilledImages(40, 40, "White", PixelTypes.Rgba32)]
81+
public void DrawPathClippedOnTop<TPixel>(TestImageProvider<TPixel> provider)
82+
where TPixel : unmanaged, IPixel<TPixel>
83+
{
84+
PointF[] points =
85+
{
86+
new PointF(10f, -10f),
87+
new PointF(20f, 20f),
88+
new PointF(30f, -30f)
89+
};
90+
91+
IPath path = new PathBuilder().AddLines(points).Build();
92+
93+
provider.VerifyOperation(
94+
image => image.Mutate(x => x.Draw(Color.Black, 1, path)),
95+
appendSourceFileOrDescription: false,
96+
appendPixelTypeToFileName: false);
97+
}
7798
}
7899
}

tests/ImageSharp.Drawing.Tests/Shapes/Scan/PolygonScannerTests.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ public void NegativeOrientation01(IntersectionRule intersectionRule)
427427
}
428428

429429
[Fact]
430-
public void OutOfBounds()
430+
public void OutOfBounds1()
431431
{
432432
IPath poly = PolygonFactory.CreatePolygon((1, -5), (5, -5), (5, -3), (10, -1), (10, 2), (12, 4), (1, 4));
433433

@@ -445,6 +445,34 @@ public void OutOfBounds()
445445
this.TestScan(poly, 0, 3, 2, expected);
446446
}
447447

448+
[Fact]
449+
public void OutOfBounds2()
450+
{
451+
IPath poly = PolygonFactory.CreatePolygon((3, -3), (3, 1), (1, 1), (1, -1), (2, -1.5f), (2, 0.5f), (3, -3));
452+
FuzzyFloat[][] expected =
453+
{
454+
new FuzzyFloat[] { 1, 2, 2.14285707, 3 },
455+
new FuzzyFloat[] { 1, 2, 2, 3 },
456+
new FuzzyFloat[] { 1, 3 }
457+
};
458+
459+
this.TestScan(poly, 0, 1, 2, expected);
460+
}
461+
462+
[Fact]
463+
public void AllOutOfBounds()
464+
{
465+
IPath poly = PolygonFactory.CreatePolygon((1, -3), (3, -3), (2, -1));
466+
FuzzyFloat[][] expected =
467+
{
468+
Array.Empty<FuzzyFloat>(),
469+
Array.Empty<FuzzyFloat>(),
470+
Array.Empty<FuzzyFloat>(),
471+
};
472+
473+
this.TestScan(poly, 0, 1, 2, expected);
474+
}
475+
448476
private static (float Y, FuzzyFloat[] X) Empty(float y) => (y, Array.Empty<FuzzyFloat>());
449477

450478
private static FuzzyFloat F(float x, float eps) => new(x, eps);
Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)