@@ -99,7 +99,7 @@ public static long getCount(GridCoverage2D raster, int band) {
99
99
* @return An array with all the stats for the region
100
100
* @throws FactoryException
101
101
*/
102
- public static double [] getZonalStatsAll (
102
+ public static Double [] getZonalStatsAll (
103
103
GridCoverage2D raster ,
104
104
Geometry roi ,
105
105
int band ,
@@ -114,18 +114,35 @@ public static double[] getZonalStatsAll(
114
114
DescriptiveStatistics stats = (DescriptiveStatistics ) objects .get (0 );
115
115
double [] pixelData = (double []) objects .get (1 );
116
116
117
+ // Shortcut for an edge case where ROI barely intersects with raster's extent, but it doesn't
118
+ // intersect with the centroid of the pixel.
119
+ // This happens when allTouched parameter is false.
120
+ if (pixelData .length == 0 ) {
121
+ return new Double [] {0.0 , null , null , null , null , null , null , null , null };
122
+ }
123
+
117
124
// order of stats
118
125
// count, sum, mean, median, mode, stddev, variance, min, max
119
- double [] result = new double [9 ];
120
- result [0 ] = stats .getN ();
121
- result [1 ] = stats .getSum ();
122
- result [2 ] = stats .getMean ();
123
- result [3 ] = stats .getPercentile (50 );
126
+ Double [] result = new Double [9 ];
127
+ result [0 ] = (double ) stats .getN ();
128
+ if (stats .getN () == 0 ) {
129
+ result [1 ] = null ;
130
+ } else {
131
+ result [1 ] = stats .getSum ();
132
+ }
133
+ double mean = stats .getMean ();
134
+ result [2 ] = Double .isNaN (mean ) ? null : mean ;
135
+ double median = stats .getPercentile (50 );
136
+ result [3 ] = Double .isNaN (median ) ? null : median ;
124
137
result [4 ] = zonalMode (pixelData );
125
- result [5 ] = stats .getStandardDeviation ();
126
- result [6 ] = stats .getVariance ();
127
- result [7 ] = stats .getMin ();
128
- result [8 ] = stats .getMax ();
138
+ double stdDev = stats .getStandardDeviation ();
139
+ result [5 ] = Double .isNaN (stdDev ) ? null : stats .getStandardDeviation ();
140
+ double variance = stats .getVariance ();
141
+ result [6 ] = Double .isNaN (variance ) ? null : variance ;
142
+ double min = stats .getMin ();
143
+ result [7 ] = Double .isNaN (min ) ? null : min ;
144
+ double max = stats .getMax ();
145
+ result [8 ] = Double .isNaN (max ) ? null : max ;
129
146
130
147
return result ;
131
148
}
@@ -139,7 +156,7 @@ public static double[] getZonalStatsAll(
139
156
* @return An array with all the stats for the region
140
157
* @throws FactoryException
141
158
*/
142
- public static double [] getZonalStatsAll (
159
+ public static Double [] getZonalStatsAll (
143
160
GridCoverage2D raster , Geometry roi , int band , boolean allTouched , boolean excludeNoData )
144
161
throws FactoryException {
145
162
return getZonalStatsAll (raster , roi , band , allTouched , excludeNoData , true );
@@ -153,7 +170,7 @@ public static double[] getZonalStatsAll(
153
170
* @return An array with all the stats for the region, excludeNoData is set to true
154
171
* @throws FactoryException
155
172
*/
156
- public static double [] getZonalStatsAll (
173
+ public static Double [] getZonalStatsAll (
157
174
GridCoverage2D raster , Geometry roi , int band , boolean allTouched ) throws FactoryException {
158
175
return getZonalStatsAll (raster , roi , band , allTouched , true );
159
176
}
@@ -165,7 +182,7 @@ public static double[] getZonalStatsAll(
165
182
* @return An array with all the stats for the region, excludeNoData is set to true
166
183
* @throws FactoryException
167
184
*/
168
- public static double [] getZonalStatsAll (GridCoverage2D raster , Geometry roi , int band )
185
+ public static Double [] getZonalStatsAll (GridCoverage2D raster , Geometry roi , int band )
169
186
throws FactoryException {
170
187
return getZonalStatsAll (raster , roi , band , false );
171
188
}
@@ -177,7 +194,7 @@ public static double[] getZonalStatsAll(GridCoverage2D raster, Geometry roi, int
177
194
* set to 1
178
195
* @throws FactoryException
179
196
*/
180
- public static double [] getZonalStatsAll (GridCoverage2D raster , Geometry roi )
197
+ public static Double [] getZonalStatsAll (GridCoverage2D raster , Geometry roi )
181
198
throws FactoryException {
182
199
return getZonalStatsAll (raster , roi , 1 );
183
200
}
@@ -213,26 +230,36 @@ public static Double getZonalStats(
213
230
214
231
switch (statType .toLowerCase ()) {
215
232
case "sum" :
216
- return stats .getSum ();
233
+ if (pixelData .length == 0 ) {
234
+ return null ;
235
+ } else {
236
+ return stats .getSum ();
237
+ }
217
238
case "average" :
218
239
case "avg" :
219
240
case "mean" :
220
- return stats .getMean ();
241
+ double mean = stats .getMean ();
242
+ return Double .isNaN (mean ) ? null : mean ;
221
243
case "count" :
222
244
return (double ) stats .getN ();
223
245
case "max" :
224
- return stats .getMax ();
246
+ double max = stats .getMax ();
247
+ return Double .isNaN (max ) ? null : max ;
225
248
case "min" :
226
- return stats .getMin ();
249
+ double min = stats .getMin ();
250
+ return Double .isNaN (min ) ? null : min ;
227
251
case "stddev" :
228
252
case "sd" :
229
- return stats .getStandardDeviation ();
253
+ double stdDev = stats .getStandardDeviation ();
254
+ return Double .isNaN (stdDev ) ? null : stdDev ;
230
255
case "median" :
231
- return stats .getPercentile (50 );
256
+ double median = stats .getPercentile (50 );
257
+ return Double .isNaN (median ) ? null : median ;
232
258
case "mode" :
233
259
return zonalMode (pixelData );
234
260
case "variance" :
235
- return stats .getVariance ();
261
+ double variance = stats .getVariance ();
262
+ return Double .isNaN (variance ) ? null : variance ;
236
263
default :
237
264
throw new IllegalArgumentException (
238
265
"Please select from the accepted options. Some of the valid options are sum, mean, stddev, etc." );
@@ -310,8 +337,13 @@ public static Double getZonalStats(GridCoverage2D raster, Geometry roi, String s
310
337
* @return Mode of the pixel values. If there is multiple with same occurrence, then the largest
311
338
* value will be returned.
312
339
*/
313
- private static double zonalMode (double [] pixelData ) {
340
+ private static Double zonalMode (double [] pixelData ) {
314
341
double [] modes = StatUtils .mode (pixelData );
342
+ // Return NaN when ROI and raster's extent overlap, but there's no pixel data.
343
+ // This behavior only happens when allTouched parameter is false.
344
+ if (modes .length == 0 ) {
345
+ return null ;
346
+ }
315
347
return modes [modes .length - 1 ];
316
348
}
317
349
0 commit comments