Skip to content

RS_AsRaster segment clipping drops crossings and loses grid-line sidedness #3255

Description

@jiayuasu

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:

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:

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

Settings

I searched open and closed issues and did not find a duplicate.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions