Skip to content

Commit 08865d0

Browse files
committed
fix: RS_ZonalStats and RS_ZonalStatsAll edge case
1 parent f8dccc5 commit 08865d0

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

common/src/main/java/org/apache/sedona/common/raster/RasterBandAccessors.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ public static double[] getZonalStatsAll(
114114
DescriptiveStatistics stats = (DescriptiveStatistics) objects.get(0);
115115
double[] pixelData = (double[]) objects.get(1);
116116

117+
// Shortcut for an edge case where ROI barely intersects with raster's extent, but it doesn't intersect with the
118+
// centroid of the pixel.
119+
// This happens when allTouched parameter is false.
120+
if (pixelData.length == 0) {
121+
return new double[] {0, 0, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN};
122+
}
123+
117124
// order of stats
118125
// count, sum, mean, median, mode, stddev, variance, min, max
119126
double[] result = new double[9];
@@ -312,6 +319,11 @@ public static Double getZonalStats(GridCoverage2D raster, Geometry roi, String s
312319
*/
313320
private static double zonalMode(double[] pixelData) {
314321
double[] modes = StatUtils.mode(pixelData);
322+
// Return NaN when ROI and raster's extent overlap, but there's no pixel data.
323+
// This behavior only happens when allTouched parameter is false.
324+
if (modes.length == 0) {
325+
return Double.NaN;
326+
}
315327
return modes[modes.length - 1];
316328
}
317329

common/src/test/java/org/apache/sedona/common/raster/RasterBandAccessorsTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,23 @@ public void testBandNoDataValueIllegalBand() throws FactoryException, IOExceptio
8484
assertEquals("Provided band index 2 is not present in the raster", exception.getMessage());
8585
}
8686

87+
@Test
88+
public void testZonalStatsIntersectingNoPixelData() throws FactoryException, ParseException {
89+
double[][] pixelsValues = new double[][] {
90+
new double[] {3, 7, 5, 40, 61, 70, 60, 80, 27, 55, 35, 44, 21, 36, 53, 54, 86, 28, 45, 24, 99, 22, 18, 98, 10}
91+
};
92+
GridCoverage2D raster = RasterConstructors.makeNonEmptyRaster(1, "", 5, 5, 1, -1, 1, -1, 0, 0, 0, pixelsValues);
93+
Geometry extent = Constructors.geomFromWKT("POLYGON ((5.822754 -6.620957, 6.965332 -6.620957, 6.965332 -5.834616, 5.822754 -5.834616, 5.822754 -6.620957))", 0);
94+
95+
double actualZonalStats = RasterBandAccessors.getZonalStats(raster, extent, "mode");
96+
assertTrue(Double.isNaN(actualZonalStats));
97+
98+
99+
double [] actualZonalStatsAll = RasterBandAccessors.getZonalStatsAll(raster, extent);
100+
double[] expectedZonalStatsAll = new double[] {0.0, 0.0, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN};
101+
assertArrayEquals(expectedZonalStatsAll, actualZonalStatsAll, FP_TOLERANCE);
102+
}
103+
87104
@Test
88105
public void testZonalStats() throws FactoryException, ParseException, IOException {
89106
GridCoverage2D raster =

0 commit comments

Comments
 (0)