Currently, brute force search is being used when calculating intersections, the scanline is being tested against all lines in the polygon for each row. This means O(h*n) intersection tests where h is the number of horizontal edges and n is the number of lines.
The fastest way to achieve significant improvement with a (relatively) scoped change is to refactor the intersection detection logic to use an "Active Edge Table". In short this means:
- Sorting edges by both minimum
y and maximum y
- Maintaining a list of edges which are currently intersected ("active") while iterating the scanlines
- .. so intersection tests are no longer needed, it's enough to calculate intersection points only for edges which are active.
This should reduce the number of intersection calculations to O(n*log(n) + h*p), where p is the highest number of intersection points in a row during the scan.
Some sources describing the algorithm:
Not in scope
Improving accuracy further (aka #5 and #15) is not my main goal here, the only criteria is to not regress. But I hope I can achieve better results, or at least get some insights.
Plan
- Expose an API on
IPath returning tessellation results to be consumed by a horizontal scanline rasterizer. These should be stored in a memory-efficient, cache friendly form. A data structure equivalent to (PointF, Orientation)[][] could probably do the job, where Orientation is always assuming a horizontal scanline crossing the point.
- Introduce a separate
ScanlineIterator class that takes the tessellation, and exposes an API to iterate the horizontal scanlines.
- Utilize
ScanlineIterator in drawing code where we currently use FindIntersections, particularly: FillRegionProcessor<T>, DrawTextProcessor<T>
Currently, brute force search is being used when calculating intersections, the scanline is being tested against all lines in the polygon for each row. This means
O(h*n)intersection tests wherehis the number of horizontal edges andnis the number of lines.The fastest way to achieve significant improvement with a (relatively) scoped change is to refactor the intersection detection logic to use an "Active Edge Table". In short this means:
yand maximumyThis should reduce the number of intersection calculations to
O(n*log(n) + h*p), wherepis the highest number of intersection points in a row during the scan.Some sources describing the algorithm:
Not in scope
Improving accuracy further (aka #5 and #15) is not my main goal here, the only criteria is to not regress. But I hope I can achieve better results, or at least get some insights.
Plan
IPathreturning tessellation results to be consumed by a horizontal scanline rasterizer. These should be stored in a memory-efficient, cache friendly form. A data structure equivalent to(PointF, Orientation)[][]could probably do the job, whereOrientationis always assuming a horizontal scanline crossing the point.ScanlineIteratorclass that takes the tessellation, and exposes an API to iterate the horizontal scanlines.ScanlineIteratorin drawing code where we currently useFindIntersections, particularly:FillRegionProcessor<T>,DrawTextProcessor<T>