Repository navigation
feat(rust/sedona-raster-functions): add RS_MinConvexHull - #1351
Merged
Merged
Conversation
This was referenced Sep 25, 2026
Find the data bounds by scanning in from each edge and stopping at the first data pixel, and skip bands once the grid is covered, so a mostly-data band costs a handful of pixels instead of a full scan (checked against a full scan for every mask of a 4x3 grid). Place north-up fixtures with bbox=, add a NaN-nodata xfail and a no-nodata parity case, anchor the NULL cases, and show trimming in the docs example. The shared pixel scan rejects negative shapes and lists its integer types explicitly.
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.
Adds
RS_MinConvexHull(raster[, band]), Sedona Spark's footprint of a raster's data pixels. It returns the polygon over the smallest pixel-aligned rectangle of the grid that holds every non-nodata pixel, in world coordinates. In effect it isRS_ConvexHullwith the nodata margin trimmed off. Without a band, a cell holds data if any band holds data there. The result is NULL when no pixel holds data, and a band with no nodata value covers the whole grid.The output matches
RS_ConvexHull: a planar geometry with the raster's CRS as an item-level CRS, and the same ring order (upper-left, upper-right, lower-right, lower-left), written throughfootprint::write_footprint_wkb. On a skewed grid the corners follow the grid axes.Each band is scanned inward from its edges and the scan stops at the first data pixel from each side: rows down from the top, rows up from the bottom, then columns in from the left and right over the rows in between. A band that is mostly data, the common case, costs a handful of pixels instead of a full scan, and a mostly-nodata band costs at most about two full scans. Without a band argument, bands stop being scanned once the whole grid is covered. The bottom and side scans read the band through reversed and transposed views of the same buffer. A unit test checks the result against a full scan for every data mask of a 4x3 grid.
The semantics follow Sedona's main branch, not the 1.9.1 release. apache/sedona#3366 made an all-nodata raster return NULL and fixed NaN nodata after 1.9.1 shipped. In 1.9.1 an all-nodata raster gives a polygon built from
Integer.MAX_VALUEsentinels, and a NaN nodata value matches no pixel, so both spark-parity cases arexfails until the suite's Sedona pin moves past it.Shared pixel scan
This adds
pixel_scan.rs, a crate-private helper that walks every pixel of a 2-D band through itsNdBufferstrides, plusNodataMatcher, which compares integer pixels to nodata by bytes and float pixels numerically. TheRS_BandIsNoData(#1350) andRS_SummaryStats(#1352) PRs carry the identical file, so whichever merges second rebases without conflicts in it.Tests
python/sedonadb/tests/functions/test_rs_minconvexhull.py: north-up and skewed GeoTIFFs read throughRS_FromPath, checked against rasterio's affine applied to numpy's data-pixel bounds (exact, dyadic coefficients).integration/spark-parity/test_rs_minconvexhull.py: anchored parity against Sedona Spark 1.9.1 for each band, all bands, skew, CRS, a band without nodata, a NULL band and an out-of-range band (8 pass, 2 xfail as described above). The skewed case uses exactly representable coefficients: SedonaDB and Spark order the affine additions differently, which can differ in the last bit for ordinary decimal skews (the same holds forRS_ConvexHull).