This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 0c35e9fa7e224bd5a272fa245a6f2200d474f77b Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Sep 28 11:42:45 2022 +0200 Preserve the type of missing values in netCDF files. Before this commit, missing values in GCOM files were always represented as floating points. After this commit, missing values declared as integers stay integers. It makes a difference when computing which value is next. --- .../apache/sis/internal/earth/netcdf/GCOM_C.java | 20 +++++++-------- .../apache/sis/internal/earth/netcdf/GCOM_W.java | 4 +-- .../org/apache/sis/internal/netcdf/Convention.java | 6 ++--- .../java/org/apache/sis/internal/netcdf/Node.java | 29 ++++++++++++++++------ .../org/apache/sis/internal/netcdf/Variable.java | 6 ++--- .../apache/sis/storage/netcdf/MetadataReader.java | 4 +-- .../apache/sis/internal/netcdf/VariableTest.java | 4 +-- 7 files changed, 43 insertions(+), 30 deletions(-) diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java index 8672c85d57..0f47ed5f66 100644 --- a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java +++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java @@ -418,7 +418,7 @@ public final class GCOM_C extends Convention { public MathTransform gridToCRS(final Node node, final MathTransform baseToCRS) throws TransformException { final double[] corners = new double[CORNERS.length]; for (int i=0; i<corners.length; i++) { - corners[i] = node.getAttributeAsNumber(CORNERS[i]); + corners[i] = node.getAttributeAsDouble(CORNERS[i]); } baseToCRS.transform(corners, 0, corners, 0, corners.length / 2); /* @@ -431,8 +431,8 @@ public final class GCOM_C extends Convention { /* * Transform the spans into pixel sizes (resolution), then build the transform. */ - sx /= (node.getAttributeAsNumber("Number_of_pixels") - 1); - sy /= (node.getAttributeAsNumber("Number_of_lines") - 1); + sx /= (node.getAttributeAsDouble("Number_of_pixels") - 1); + sy /= (node.getAttributeAsDouble("Number_of_lines") - 1); if (Double.isFinite(sx) && Double.isFinite(sy)) { final Matrix3 m = new Matrix3(); m.m00 = sx; @@ -472,9 +472,9 @@ public final class GCOM_C extends Convention { public NumberRange<?> validRange(final Variable data) { NumberRange<?> range = super.validRange(data); if (range == null) { - final double min = data.getAttributeAsNumber("Minimum_valid_DN"); - final double max = data.getAttributeAsNumber("Maximum_valid_DN"); - if (Double.isFinite(min) && Double.isFinite(max)) { + final Number min = data.getAttributeAsNumber("Minimum_valid_DN"); + final Number max = data.getAttributeAsNumber("Maximum_valid_DN"); + if (min != null || max != null) { range = NumberRange.createBestFit(min, true, max, true); } } @@ -494,8 +494,8 @@ public final class GCOM_C extends Convention { final Map<Number, Object> pads = super.nodataValues(data); for (int i=0; i<NO_DATA.length; i++) { String name = NO_DATA[i]; - final double value = data.getAttributeAsNumber(name); - if (Double.isFinite(value)) { + final Number value = data.getAttributeAsNumber(name); + if (value != null) { final Object label; if (i != 0) { if (name.endsWith(SUFFIX)) { @@ -522,8 +522,8 @@ public final class GCOM_C extends Convention { public TransferFunction transferFunction(final Variable data) { final TransferFunction tr = super.transferFunction(data); if (tr.isIdentity()) { - final double slope = data.getAttributeAsNumber("Slope"); - final double offset = data.getAttributeAsNumber("Offset"); + final double slope = data.getAttributeAsDouble("Slope"); + final double offset = data.getAttributeAsDouble("Offset"); if (Double.isFinite(slope)) tr.setScale (slope); if (Double.isFinite(offset)) tr.setOffset(offset); } diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java index 82b485e1a5..6d8f432adb 100644 --- a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java +++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java @@ -255,8 +255,8 @@ public final class GCOM_W extends Convention { public TransferFunction transferFunction(final Variable data) { final TransferFunction tr = super.transferFunction(data); if (tr.isIdentity()) { - final double slope = data.getAttributeAsNumber("SCALE FACTOR"); - final double offset = data.getAttributeAsNumber("OFFSET"); + final double slope = data.getAttributeAsDouble("SCALE FACTOR"); + final double offset = data.getAttributeAsDouble("OFFSET"); if (Double.isFinite(slope)) tr.setScale (slope); if (Double.isFinite(offset)) tr.setOffset(offset); } diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java index 8570cbd890..35e1f97fa1 100644 --- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java +++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Convention.java @@ -351,7 +351,7 @@ public class Convention { * @return the "grid indices to data indices" scale factor, or {@link Double#NaN} if none. */ public double gridToDataIndices(final Variable axis) { - return axis.getAttributeAsNumber("resampling_interval"); + return axis.getAttributeAsDouble("resampling_interval"); } /** @@ -755,8 +755,8 @@ public class Convention { * a "packed" variable. Otherwise the transfer function is the identity transform. */ final TransferFunction tr = new TransferFunction(); - final double scale = data.getAttributeAsNumber(CDM.SCALE_FACTOR); - final double offset = data.getAttributeAsNumber(CDM.ADD_OFFSET); + final double scale = data.getAttributeAsDouble(CDM.SCALE_FACTOR); + final double offset = data.getAttributeAsDouble(CDM.ADD_OFFSET); if (!Double.isNaN(scale)) tr.setScale (scale); if (!Double.isNaN(offset)) tr.setOffset(offset); return tr; diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Node.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Node.java index 561a8761c5..d96e7cf015 100644 --- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Node.java +++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Node.java @@ -30,7 +30,7 @@ import org.apache.sis.internal.util.Strings; * The common characteristic of those objects is to have attributes. * * @author Martin Desruisseaux (Geomatys) - * @version 1.0 + * @version 1.3 * @since 1.0 * @module */ @@ -182,16 +182,16 @@ public abstract class Node extends NamedElement { } /** - * Returns the value of the given attribute as a number, or {@link Double#NaN}. - * If the number is stored with single-precision, it is assumed casted from a - * representation in base 10. + * Returns the value of the given attribute as a number, or {@code null}. + * This method returns a number of the type that most closely matches the + * type in the netCDF file. * * @param attributeName the name of the attribute for which to get the value. - * @return the singleton attribute value, or {@code NaN} if none or ambiguous. + * @return the singleton attribute value, or {@code null} if none or ambiguous. */ - public final double getAttributeAsNumber(final String attributeName) { - final Object value = getAttributeValue(attributeName); + public final Number getAttributeAsNumber(final String attributeName) { Number singleton = null; + final Object value = getAttributeValue(attributeName); if (value instanceof Number) { singleton = (Number) value; } else if (value instanceof String) { @@ -205,11 +205,24 @@ public abstract class Node extends NamedElement { if (singleton == null) { singleton = n; } else if (!singleton.equals(n)) { - return Double.NaN; + return null; } } } } + return singleton; + } + + /** + * Returns the value of the given attribute as a number, or {@link Double#NaN}. + * If the number is stored with single-precision, it is assumed casted from a + * representation in base 10. + * + * @param attributeName the name of the attribute for which to get the value. + * @return the singleton attribute value, or {@code NaN} if none or ambiguous. + */ + public final double getAttributeAsDouble(final String attributeName) { + Number singleton = getAttributeAsNumber(attributeName); if (singleton == null) { return Double.NaN; } diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java index 4305b22bfa..cda5fa818e 100644 --- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java +++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java @@ -434,10 +434,10 @@ public abstract class Variable extends Node { return convention.transferFunction(this).isIdentity(); } // Shortcut for common case. - double c = getAttributeAsNumber(CDM.SCALE_FACTOR); - if (Double.isNaN(c) || c == 1) { + Number c = getAttributeAsNumber(CDM.SCALE_FACTOR); + if (c == null || c.doubleValue() == 1) { c = getAttributeAsNumber(CDM.ADD_OFFSET); - return Double.isNaN(c) || c == 0; + return c == null || c.doubleValue() == 0; } } return false; diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java index d4996187bc..cc5409b623 100644 --- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java +++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java @@ -964,8 +964,8 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt addBandDescription(description); } setSampleUnits(variable.getUnit()); - setTransferFunction(variable.getAttributeAsNumber(CDM.SCALE_FACTOR), - variable.getAttributeAsNumber(CDM.ADD_OFFSET)); + setTransferFunction(variable.getAttributeAsDouble(CDM.SCALE_FACTOR), + variable.getAttributeAsDouble(CDM.ADD_OFFSET)); addContentType(forCodeName(CoverageContentType.class, stringValue(ACDD.coverage_content_type))); } diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java index d05cf6bcf3..1074a38cb3 100644 --- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java +++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/VariableTest.java @@ -266,7 +266,7 @@ public strictfp class VariableTest extends TestCase { assertArrayEquals("getAttributeAsStrings", new String[] {t}, variable.getAttributeAsStrings(name, ' ')); if (expected instanceof Number) { final double en = ((Number) expected).doubleValue(); - assertEquals("getAttributeAsNumber", en, variable.getAttributeAsNumber(name), STRICT); + assertEquals("getAttributeAsDouble", en, variable.getAttributeAsDouble(name), STRICT); final Vector vector = variable.getAttributeAsVector(name); assertNotNull("getAttributeAsVector", vector); assertEquals(1, vector.size()); @@ -284,7 +284,7 @@ public strictfp class VariableTest extends TestCase { final Vector values = variable.getAttributeAsVector(name); assertNotNull(name, values); assertEquals ("size", expected.length, values.size()); - assertTrue ("getAttributeAsNumber", Double.isNaN(variable.getAttributeAsNumber(name))); + assertTrue ("getAttributeAsDouble", Double.isNaN(variable.getAttributeAsDouble(name))); assertEquals ("getAttributeValue", values, variable.getAttributeValue(name)); final Object[] texts = Arrays.stream(expected).map(Object::toString).toArray(); assertArrayEquals("getAttributeAsStrings", texts, variable.getAttributeAsStrings(name, ' '));