Skip to content

[GH-3118] Rasterize line segments by exact cell traversal instead of fixed-step sampling#3119

Draft
james-willis wants to merge 8 commits into
apache:masterfrom
james-willis:fix/gh-3118-line-traversal
Draft

[GH-3118] Rasterize line segments by exact cell traversal instead of fixed-step sampling#3119
james-willis wants to merge 8 commits into
apache:masterfrom
james-willis:fix/gh-3118-line-traversal

Conversation

@james-willis

@james-willis james-willis commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Did you read the Contributor Guide?

Is this PR related to a ticket?

What changes were proposed in this PR?

Rasterization burned line/ring segments by sampling them at fixed 0.2-pixel steps and flooring each sample to a cell (drawLineBresenham). A cell is only burned if a sample lands inside it, so a cell the segment crosses over a chord shorter than the step could fall between two samples and be missed. This replaced the sampler with exact grid traversal (Amanatides–Woo): the segment is walked from one cell-boundary crossing to the next, so every cell it enters is burned. This fixes both LINESTRING rasterization and polygon-boundary selection under allTouched = true (which affects RS_AsRaster, RS_Clip, RS_ZonalStats/RS_ZonalStatsAll, and RS_SetValues).

This PR is stacked on #3113 (the non-square-pixel scanline fix); review that one first.

Small known deviation from GDAL: when a vertex lands exactly on a grid line, the geometry touches a cell only at a corner or edge. This exact traversal burns that cell (a superset consistent with the documented "all pixels touched by the geometry"), whereas GDAL omits it. This only occurs at exact grid-aligned vertices (never on general input) and GDAL's own behaviour there is inconsistent, so it is not pursued here — tracked in #3120.

How was this patch tested?

  • New testAsRasterTouchedPixelsExactTraversal: a polygon boundary and a LINESTRING that each clip a pixel over a sub-pixel chord, on a square unit grid; expected matrices from GDAL (rasterio.features.rasterize, all_touched=True). Written first, failed on the sampler.
  • The seeded 100-case allTouched fuzz added on [GH-3111] Fix scanline x-intercepts on rasters with non-square pixels #3113 (python/tests/sql/test_rasterize_parity.py) matches GDAL exactly with this fix; its two strict-xfail markers (the allTouched polygon corpus and the LineString case) become passing assertions here.
  • Existing RS_AsRaster/RS_Clip/RS_ZonalStats/RS_SetValues expectations that had encoded the sampler's missed boundary pixels are updated; each change was verified against GDAL/rasterio. RS_ZonalStats allTouched count on the edge-case geometry goes 1832 → 1842 (the 10 boundary pixels GDAL also selects). Full common module suite passes (1147 tests).

Did this PR include necessary documentation updates?

  • No, this PR does not affect any public API so no need to change the documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Line rasterization uses fixed-step sampling instead of exact cell traversal, dropping boundary pixels (allTouched and LINESTRING)

1 participant