Expected behavior
When RS_AsRaster is called with a noDataValue, pixels not covered by the geometry should be set to that value, so the output distinguishes "burned" from "background". This is what PostGIS ST_AsRaster does (nodataval is assigned to cells not touched by the geometry), and the GDAL equivalent (gdal_rasterize -init <nodata> -a_nodata <nodata>, or rasterio.features.rasterize(fill=nodata)).
Actual behavior
The noDataValue is only attached as band metadata. Background pixels keep Java's zero-initialized default, so they come out as 0 — a perfectly valid pixel value — while the band claims its nodata is something else.
A polygon with a hole makes the consequence concrete. Repro on a 7x6 grid (Sedona 1.9.0, Spark 4.0), burning 1 with nodata 9:
SELECT RS_BandAsArray(RS_AsRaster(
ST_GeomFromWKT('POLYGON ((100.2 499.5, 113.8 499.5, 113.8 482.4, 100.2 482.4, 100.2 499.5),
(104.1 496.9, 110.2 496.9, 110.2 487.8, 104.1 487.8, 104.1 496.9))'),
RS_MakeEmptyRaster(1, 'B', 7, 6, 100.0, 500.0, 2.0, -3.0, 0.0, 0.0, 0),
'B', false, 1.0, 9.0, false), 1)
Sedona returns (reshaped to 6x7, RS_BandNoDataValue reports 9.0):
1 1 1 1 1 1 1
1 1 0 0 0 1 1
1 1 0 0 0 1 1
1 1 0 0 0 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
PostGIS and GDAL/rasterio return:
1 1 1 1 1 1 1
1 1 9 9 9 1 1
1 1 9 9 9 1 1
1 1 9 9 9 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
The pixel selection itself is identical across engines here (all rings are axis-aligned), so the divergence is purely the background fill. The hole shows why this can't be worked around by choosing a tighter extent: the uncovered region is interior to the geometry, and it reads back as valid data 0 rather than nodata.
Root cause
RasterConstructors.asRaster burns the geometry into the WritableRaster returned by Rasterization.rasterize (whose backing Java array is zero-initialized), then only records the nodata as metadata via setBandNoDataValue — nothing ever writes the background (RasterConstructors.java#L133-L149 @ 0299fa8):
List<Object> objects =
Rasterization.rasterize(geom, raster, pixelType, value, useGeometryExtent, allTouched);
WritableRaster writableRaster = (WritableRaster) objects.get(0);
...
if (noDataValue != null) {
resultRaster = RasterBandEditors.setBandNoDataValue(resultRaster, 1, noDataValue);
}
This is entirely Sedona-side (no geotools constraint): the fix is to initialize the raster's pixels to noDataValue before burning whenever one is provided.
Impact
Any downstream consumer that respects nodata (stats, map algebra, export to GeoTIFF and reading in other tools) treats the entire background as valid zeros. When 0 is a legitimate data value there is no way to tell background from data, despite the caller having explicitly declared a nodata value.
Affected versions: reproduced on 1.9.0 (released jars); the same code is present on current master (0299fa8).
Expected behavior
When
RS_AsRasteris called with anoDataValue, pixels not covered by the geometry should be set to that value, so the output distinguishes "burned" from "background". This is what PostGISST_AsRasterdoes (nodatavalis assigned to cells not touched by the geometry), and the GDAL equivalent (gdal_rasterize -init <nodata> -a_nodata <nodata>, orrasterio.features.rasterize(fill=nodata)).Actual behavior
The
noDataValueis only attached as band metadata. Background pixels keep Java's zero-initialized default, so they come out as0— a perfectly valid pixel value — while the band claims its nodata is something else.A polygon with a hole makes the consequence concrete. Repro on a 7x6 grid (Sedona 1.9.0, Spark 4.0), burning 1 with nodata 9:
Sedona returns (reshaped to 6x7,
RS_BandNoDataValuereports 9.0):PostGIS and GDAL/rasterio return:
The pixel selection itself is identical across engines here (all rings are axis-aligned), so the divergence is purely the background fill. The hole shows why this can't be worked around by choosing a tighter extent: the uncovered region is interior to the geometry, and it reads back as valid data
0rather than nodata.Root cause
RasterConstructors.asRasterburns the geometry into theWritableRasterreturned byRasterization.rasterize(whose backing Java array is zero-initialized), then only records the nodata as metadata viasetBandNoDataValue— nothing ever writes the background (RasterConstructors.java#L133-L149 @ 0299fa8):This is entirely Sedona-side (no geotools constraint): the fix is to initialize the raster's pixels to
noDataValuebefore burning whenever one is provided.Impact
Any downstream consumer that respects nodata (stats, map algebra, export to GeoTIFF and reading in other tools) treats the entire background as valid zeros. When 0 is a legitimate data value there is no way to tell background from data, despite the caller having explicitly declared a nodata value.
Affected versions: reproduced on 1.9.0 (released jars); the same code is present on current master (
0299fa8).