[GH-3112] RS_AsRaster fills uncovered pixels with noDataValue - #3114
Merged
jiayuasu merged 13 commits intoJul 28, 2026
Conversation
james-willis
marked this pull request as ready for review
July 17, 2026 08:25
…against rasterio" This reverts commit 7085eab.
jiayuasu
reviewed
Jul 19, 2026
jiayuasu
reviewed
Jul 19, 2026
# 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.
jiayuasu
reviewed
Jul 22, 2026
jiayuasu
reviewed
Jul 22, 2026
Member
|
@james-willis address conflict? |
Collaborator
Author
I had a comment on the thread about no data values vs unburned value and how to represent. I want to resolve on that question. |
Resolve RasterConstructorsTest conflict: combine master's exact cell-traversal (DDA) burn positions with this branch's background fill. Uncovered pixels are filled with the band noDataValue (3.0 / 5.0), and the noDataValue call arguments master had flipped to 0d are restored so the fill is exercised.
fillBackground skipped the fill when the background compared equal to 0, which is true for both +0.0 and -0.0. A -0.0 noDataValue therefore left uncovered pixels at the zero-initialized +0.0 while the band's nodata metadata was -0.0. RS_Count(band, excludeNoData=true) compares pixels to the metadata with Double.compare, which distinguishes the two zeros, so the uncovered pixels were miscounted as data. Skip the fill only for +0.0 (Double.compare(x, 0.0) == 0), so -0.0 is explicitly filled and pixel value and nodata metadata agree.
… the band's float32 storage A nodata value is a sentinel that must round-trip exactly through the band's storage. On a 32-bit float band, assertNoDataValueRepresentable previously rejected only magnitudes that overflowed Float.MAX_VALUE, accepting values like 0.1 that are not exactly representable in float32 (stored as 0.10000000149...). The recorded sentinel then differed from the caller's value, so comparisons against it would miss, and 0.1 in particular crashed deep in GeoTools. Reject any finite value that does not survive the double->float->double round-trip. Overflow to +/-Infinity is caught by the same test; NaN and the infinities are exactly representable and remain allowed.
Member
|
@james-willis I am fine with the PostGIS behavior which treats the NoData value and unburned value the same. And that's the behavior we have been following. |
Member
|
Sorry, I missed that thread. I don't have strong feelings about what exactly this should do. |
…tion - Inherit path: rethrow an actionable inherit-specific error when the reference band nodata is not representable in the output pixel type, pointing at the explicit-noDataValue override. - Validate the burn value for representability (mirrors noDataValue) and reject a burn value equal to the noDataValue. - Reject non-finite (NaN / +/-Infinity) nodata and value on float/double bands up front instead of silently dropping (NaN) or crashing in GeoTools (Infinity). - Fix nodata-less RS_AsRaster tutorial examples that now error.
jiayuasu
reviewed
Jul 27, 2026
jiayuasu
reviewed
Jul 27, 2026
jiayuasu
reviewed
Jul 27, 2026
A burn value is ordinary pixel data, not a nodata sentinel, so validate it with RasterUtils.assertBurnValueRepresentable: a fractional value on a float/double band (e.g. 0.1 on 'F') is accepted and rounded to the pixel type, as PostGIS ST_AsRaster and gdal_rasterize do, while an out-of-range or fractional integer burn is still rejected. The noDataValue keeps the strict exact-storage check. Also reject negative zero as a noDataValue on integer pixel types: an integer sample cannot preserve the sign, so a -0.0 sentinel reads back as +0 and would be counted as data (it previously slipped past the range/fractional check since -0.0 compares equal to +0.0). It remains valid on float/double bands.
jiayuasu
approved these changes
Jul 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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. The fill happens before burning (not after) because a burnvalueof0would otherwise be indistinguishable from background.Omitted
noDataValuenow inherits the reference band's nodata (used for both the band metadata and the background fill) instead of leaving an all-zero background with no nodata metadata. If the reference band has no nodata value — or its nodata is not representable in the output pixel type — the call errors with guidance to pass an explicit representablenoDataValueto override (nullopts out of a nodata value, and is reachable only through the programmatic API / the widest overload).Representability validation. A
noDataValueor burnvaluethat cannot be represented exactly in the output pixel type is now rejected up front instead of silently coerced: an out-of-range or fractional value on an integer band, a value that does not round-trip through 32-bit float on anFband, or a non-finiteNaN/±Infinity. Silent coercion would store a different number than the caller set (so the background read back as data), and for some inputs previously crashed deep in GeoTools. A burnvalueequal to the resolvednoDataValueis also rejected, since every covered pixel would then read as nodata.Because this validation lives in the shared rasterization path,
RS_SetValueslikewise now rejects a non-representable or non-finitevaluefor the target band rather than silently coercing it — a consistency change to that function.RS_Clipis unaffected (its fixed mask marker is always representable).RS_SetValuesstill rasterizes its geometry mask with an explicitnullnodata and reads the result purely as a0/non-0mask, so its masking behavior is otherwise unchanged.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.-0.0) fill; representability rejection of out-of-range/fractional integer, non-exact-float, and non-finite values; the inherited-nodata error (no nodata to inherit, and inherited value not representable in the output type); and the burn-value == noDataValueguard.commonmodule raster suite and the SparkrasteralgebraTest/rasterIOTestsuites pass.RS_SetValues,RS_Clip, and the zonal-stats path (which passnullnodata and rely on0-backed masks) are unaffected in their masking behavior.Did this PR include necessary documentation updates?