RS_AsRaster segment clipping drops crossings and loses grid-line sidedness
- Dominant language
- Java
- Stars
- 2.4k
- Forks
- 784
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 58
Description
## Expected behavior
LineString segments, and polygon-boundary segments when `allTouched = true`, should be rasterized whenever their intersection with the raster window has positive length, regardless of whether either original endpoint is inside the window. Reversing a segment should produce the same band.
Segments that are disjoint from the window, or that only touch it at one corner point, should burn no cells. A segment clipped to a window edge should retain the exact side of nearby internal pixel grid lines.
## Actual behavior
`Rasterization.clipSegmentToRasterBounds` returns `null` whenever both endpoints are outside the raster extent. This drops valid segments that cross the raster from one side to another.
The current one-endpoint clipping path also stores an interpolated endpoint as ordinary `double` coordinates. If the unconstrained coordinate rounds onto an internal grid line, rasterization can select the wrong adjacent cell even though the segment remains strictly on one side of that line inside the raster.
## Steps to reproduce
On a 6 x 6 north-up unit raster, this horizontal line crosses all six columns but both endpoints are outside:
```sql
SELECT RS_BandAsArray(
RS_AsRaster(
ST_GeomFromWKT('LINESTRING (-1 2.5, 7 2.5)'),
RS_MakeEmptyRaster(1, 'B', 6, 6, 0.0, 6.0, 1.0, -1.0, 0.0, 0.0, 0),
'B', true, 1.0, 0.0, false),
1);
```
Expected: all six cells in zero-based row 3 are `1`.
Actual: every cell is `0`.
A secondary clipping case demonstrates loss of endpoint sidedness:
```sql
SELECT RS_BandAsArray(
RS_AsRaster(
ST_GeomFromWKT('LINESTRING (-1 3.0000000000000004, 1 3.0)'),
RS_MakeEmptyRaster(1, 'B', 6, 6, 0.0, 6.0, 1.0, -1.0, 0.0, 0.0, 0),
'B', true, 1.0, 0.0, false),
1);
```
Within the raster, the nondegenerate part of this line is strictly above `y = 3`, except at its final endpoint. It should therefore burn `(row 2, column 0)`. The clipped coordinate rounds to `y = 3`, and Sedona instead burns `(row 3, column 0)`. Reversing the input must preserve the correct result.
## Root cause
The clipper has three related numerical/topological limitations:
1. It treats "both endpoints outside" as equivalent to "no intersection."
2. It returns only rounded coordinates, losing whether an interpolated coordinate is exactly on, just below, or just above an internal grid line.
3. Once both-outside crossings are admitted, direct differences such as `x2 - x1` can overflow for valid finite endpoints such as `-1e308` and `1e308`.
## Acceptance criteria
- A nondegenerate segment with a positive-length window intersection is rasterized even when both source endpoints are outside.
- Disjoint and parallel-outside segments burn nothing.
- Corner-only tangencies burn nothing; boundary-coincident positive-length segments retain the established half-open side.
- Clipped endpoints preserve the side of internal grid lines, including exact, `Math.nextDown`, and `Math.nextUp` cases on both axes.
- Forward and reversed segments produce identical bands.
- An originally degenerate in-bounds LineString is distinguished from a nondegenerate segment collapsed to a tangent point by clipping.
- Clipping valid finite endpoints does not produce NaN-driven omissions or traversal streaks. Include horizontal and vertical `+/-1e308` crossings, or explicitly validate and document a smaller supported coordinate range.
- Tests use an independent exact-rational segment/window oracle. The oracle must not exclude intersections near grid lines.
- The replacement adds no arbitrary-precision or per-segment helper allocations on the ordinary finite-coordinate path; any exact fallback is limited to unresolved or overflow-prone cases.
## Related work
- #3118 replaced fixed-step sampling with exact cell traversal, but did not change segment clipping.
- #3120 and #3251 address endpoint-cell selection after coordinates are already in pixel space; #3251 deliberately leaves clipping unchanged.
## Settings
- Sedona version: PR #3251 head `72d9cc26541` / `2.0.0-SNAPSHOT` (the both-outside crossing omission also reproduces on current `master`)
- API type: SQL and Java
- JRE: 17
- Environment: local development checkout
I searched open and closed issues and did not find a duplicate.
Contributor guide
Research direction
Start at Rasterization.clipSegmentToRasterBounds and reproduce the SQL examples through RS_AsRaster and RS_BandAsArray. Review related work in #3118, #3120, and #3251, then build tests with an independent exact-rational segment/window oracle. Done means valid crossings rasterize consistently in both directions while tangencies, boundary cases, grid-line sidedness, and extreme finite coordinates meet the acceptance criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, sql
- Domain
- computer-graphics, data
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100