jiayuasu commented on code in PR #3114:
URL: https://github.com/apache/sedona/pull/3114#discussion_r3633904128


##########
common/src/main/java/org/apache/sedona/common/utils/RasterUtils.java:
##########
@@ -647,6 +647,75 @@ public static boolean isDataTypeIntegral(int dataTypeCode) 
{
     }
   }
 
+  /**
+   * Verifies that {@code noDataValue} can be stored in the pixel type named 
by {@code pixelType}
+   * without silent coercion, returning it unchanged when it can. Writing a 
value that is out of the
+   * pixel type's range, or fractional for an integer pixel type, coerces the 
stored sample to a
+   * different number than the value recorded as the band's nodata metadata 
(for example -1.0 or
+   * 300.0 wraps to 255 or 44 in an unsigned 8-bit band), so the background 
would then read back as
+   * data rather than nodata. Such a value is a correctness violation, not a 
per-row data condition,
+   * so this rejects it with an {@link IllegalArgumentException} instead of 
coercing.
+   *
+   * @param noDataValue the candidate nodata / background value
+   * @param pixelType a Sedona pixel type string accepted by {@link 
#getDataTypeCode(String)} (for
+   *     example {@code "B"}, {@code "I"}, {@code "D"})
+   * @return {@code noDataValue}, unchanged, when it is representable in the 
pixel type
+   * @throws IllegalArgumentException when {@code noDataValue} cannot be 
represented in the pixel
+   *     type
+   */
+  public static double assertNoDataValueRepresentable(double noDataValue, 
String pixelType) {
+    int dataTypeCode = getDataTypeCode(pixelType);
+    long min;
+    long max;
+    String description;
+    switch (dataTypeCode) {
+      case DataBuffer.TYPE_BYTE:
+        min = 0;
+        max = 255;
+        description = "unsigned 8-bit";
+        break;
+      case DataBuffer.TYPE_USHORT:
+        min = 0;
+        max = 65535;
+        description = "unsigned 16-bit";
+        break;
+      case DataBuffer.TYPE_SHORT:
+        min = Short.MIN_VALUE;
+        max = Short.MAX_VALUE;
+        description = "signed 16-bit";
+        break;
+      case DataBuffer.TYPE_INT:
+        min = Integer.MIN_VALUE;
+        max = Integer.MAX_VALUE;
+        description = "signed 32-bit";
+        break;
+      case DataBuffer.TYPE_FLOAT:
+        // 32-bit float represents NaN and the infinities; reject only a 
finite value whose
+        // magnitude overflows the float range (it would silently become an 
infinity). Rounding a
+        // value to the nearest float is the inherent, expected behavior of a 
float band.
+        if (Double.isFinite(noDataValue) && Math.abs(noDataValue) > 
Float.MAX_VALUE) {
+          throw new IllegalArgumentException(
+              String.format(
+                  "noDataValue %s is not representable in pixel type '%s' 
(32-bit float, valid range %s..%s)",
+                  noDataValue, pixelType, -Float.MAX_VALUE, Float.MAX_VALUE));
+        }
+        return noDataValue;

Review Comment:
   Could we round-trip this through `float` before returning it? This passes 
validation:
   
   `RasterConstructors.asRaster(geom, ref, "F", false, 1d, 0.1d, false)`
   
   but then fails while constructing the nodata metadata with `Range [0.1 .. 
0.1] is not valid`. Returning `(double) (float) noDataValue` makes the stored 
pixel and metadata agree. A test with `0.1` should catch it.



##########
common/src/main/java/org/apache/sedona/common/raster/Rasterization.java:
##########
@@ -85,6 +99,23 @@ protected static List<Object> rasterize(
     return objects;
   }
 
+  /**
+   * Fills every pixel of the freshly-allocated raster with the background 
value, so pixels never
+   * covered by the geometry read back as that value instead of the allocation 
default of 0. A null
+   * or zero background keeps the zero-initialized allocation as-is.
+   */
+  private static void fillBackground(WritableRaster writableRaster, Double 
backgroundValue) {
+    if (backgroundValue == null || backgroundValue == 0) {

Review Comment:
   `backgroundValue == 0` also matches `-0.0`. For `F`/`D`, that leaves the 
zero-initialized pixels as `+0.0` while the nodata metadata remains `-0.0`. 
`RS_Count(..., true)` uses `Double.compare`, so the hole is counted as data (9 
instead of 8 in the 3x3 polygon-with-hole repro). Could we either normalize 
signed zero before both uses, or skip only positive zero here?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to