[GH-3112] RS_AsRaster fills uncovered pixels with noDataValue#3114
[GH-3112] RS_AsRaster fills uncovered pixels with noDataValue#3114james-willis wants to merge 6 commits into
Conversation
…against rasterio" This reverts commit 7085eab.
# Conflicts: # common/src/test/java/org/apache/sedona/common/raster/RasterConstructorsTest.java
…ead of coercing Validate the noDataValue against the target pixel type before it is used as the background fill and the band nodata metadata. An out-of-range value (for example -1.0 or 300.0 on an unsigned 8-bit band) or a fractional value on an integer band would previously be silently coerced into the sample, so the background read back as data while the recorded nodata disagreed. Reject such a value with an IllegalArgumentException naming the value and pixel type, and reuse the validated value for both the fill and the metadata.
…aValue omitted The overloads without a noDataValue argument now inherit the reference raster's first band nodata value, using it both as the output band's nodata metadata and as the fill for the pixels the geometry does not cover, and error when the reference band has no nodata value to inherit. An explicit null noDataValue on the widest overload still opts out of a nodata value and keeps a zero background. RS_Clip and RS_SetValues rasterize a 0-background mask, so they now pass an explicit null noDataValue to keep that zero background instead of relying on the omitted-argument default.
| "noDataValue %s is not representable in pixel type '%s' (32-bit float, valid range %s..%s)", | ||
| noDataValue, pixelType, -Float.MAX_VALUE, Float.MAX_VALUE)); | ||
| } | ||
| return noDataValue; |
There was a problem hiding this comment.
Could we round-trip this through float before returning it? This passes validation:
RasterConstructors.asRaster(geom, ref, "F", false, 1d, 0.1d, false)
but then fails while constructing the nodata metadata with Range [0.1 .. 0.1] is not valid. Returning (double) (float) noDataValue makes the stored pixel and metadata agree. A test with 0.1 should catch it.
| * or zero background keeps the zero-initialized allocation as-is. | ||
| */ | ||
| private static void fillBackground(WritableRaster writableRaster, Double backgroundValue) { | ||
| if (backgroundValue == null || backgroundValue == 0) { |
There was a problem hiding this comment.
backgroundValue == 0 also matches -0.0. For F/D, that leaves the zero-initialized pixels as +0.0 while the nodata metadata remains -0.0. RS_Count(..., true) uses Double.compare, so the hole is counted as data (9 instead of 8 in the 3x3 polygon-with-hole repro). Could we either normalize signed zero before both uses, or skip only positive zero here?
Did you read the Contributor Guide?
Is this PR related to a ticket?
[GH-XXX] my subject. Closes RS_AsRaster: pixels not covered by the geometry get value 0 instead of noDataValue #3112What changes were proposed in this PR?
RS_AsRasterpreviously only attachednoDataValueas band metadata; pixels not covered by the geometry kept the allocation default of0, a valid pixel value indistinguishable from data. NowRasterizationfills the freshly-allocated raster with thenoDataValuebefore burning the geometry, so uncovered pixels (including interior holes) read back as the declared nodata — matching PostGISST_AsRaster(nodatavalfills untouched cells) and thegdal_rasterize -init <nodata> -a_nodata <nodata>idiom. Passing nonoDataValuekeeps the current all-zero background.The fill happens before burning (not after) because a burn
valueof0would otherwise be indistinguishable from background.RS_SetValuesinternally rasterized its geometry mask with the band's nodata attached; since it reads that raster purely as a mask where0means "outside the geometry", it now uses the overload without a nodata, preserving its behavior exactly.Existing test expectations that asserted
0backgrounds alongside a non-zeronoDataValueare updated to expect the nodata — those expectations were pinning the bug from #3112.How was this patch tested?
testAsRasterBackgroundIsNoDataValue: a polygon with an interior hole where the hole and the outside must read back as the nodata; avalue = 0burn that must stay distinguishable from the nodata background; the geometry-extent output path; and the null-nodata default keeping0. The test was written first and fails on master.commonmodule suite passes.PixelFunctionEditorsTest(RS_SetValues),RasterBandAccessorsTest(zonal stats, which passesnullnodata and relies on0backgrounds), andRasterBandEditorsTest(RS_Clip, which never passes a nodata) pass unchanged — the consumers that depend on0-backed masks are unaffected.Did this PR include necessary documentation updates?