sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 04/05: Refactor Variable.getValidValues() by moving more code to Convention and making clear that the remaining code in Variable is used only as a fallback. Move back GridResource.addQuantitativeInfo(…) into createSampleDimension(…) for now since they work together in building a SampleDimension and may share more information in the future. In particular, the code in Variable.getRangeFallback() which avoid collision with "no data value" may move into GridResource.createSampleDimension() in ord [...]
Date Fri, 15 Feb 2019 19:23:48 GMT
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 6db4039f49204da5db20acf22cff04dacf05ffee
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Feb 15 20:12:32 2019 +0100

    Refactor Variable.getValidValues() by moving more code to Convention and making clear
that the remaining code in Variable is used only as a fallback.
    Move back GridResource.addQuantitativeInfo(…) into createSampleDimension(…) for now
since they work together in building a SampleDimension and may share more information in the
future.
    In particular, the code in Variable.getRangeFallback() which avoid collision with "no
data value" may move into GridResource.createSampleDimension() in order to be more robust
to netCDF files providing incorrect information in their "min/max valid value" attributes.
---
 .../org/apache/sis/internal/netcdf/Convention.java | 132 +++++++++++++++++----
 .../org/apache/sis/internal/netcdf/Variable.java   |  90 ++------------
 .../sis/internal/netcdf/ucar/VariableWrapper.java  |  21 ++--
 .../apache/sis/storage/netcdf/GridResource.java    | 108 +++++++++--------
 4 files changed, 187 insertions(+), 164 deletions(-)

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 14c3733..26ae579 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
@@ -17,10 +17,11 @@
 package org.apache.sis.internal.netcdf;
 
 import java.util.Iterator;
-import java.util.Optional;
 import org.apache.sis.internal.referencing.LazySet;
-import org.apache.sis.measure.NumberRange;
 import org.apache.sis.referencing.operation.transform.TransferFunction;
+import org.apache.sis.measure.MeasurementRange;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.util.Numbers;
 import ucar.nc2.constants.CDM;
 
 
@@ -41,6 +42,7 @@ import ucar.nc2.constants.CDM;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
+ * @author  Alexis Manin (Geomatys)
  * @version 1.0
  *
  * @see <a href="https://issues.apache.org/jira/browse/SIS-315">SIS-315</a>
@@ -60,6 +62,18 @@ public class Convention {
     private static final Convention DEFAULT = new Convention();
 
     /**
+     * Names of attributes where to fetch minimum and maximum sample values, in preference
order.
+     *
+     * @see #getValidValues(Variable)
+     */
+    private static final String[] RANGE_ATTRIBUTES = {
+        "valid_range",      // Expected "reasonable" range for variable.
+        "actual_range",     // Actual data range for variable.
+        "valid_min",        // Fallback if "valid_range" is not specified.
+        "valid_max"
+    };
+
+    /**
      * For subclass constructors.
      */
     protected Convention() {
@@ -125,12 +139,97 @@ public class Convention {
     }
 
     /**
-     * Build a function aiming to convert values packed in given variable into geophysical
measures.
+     * Returns the range of valid values, or {@code null} if unknown.
+     * The default implementation takes the range of values from the following properties,
in precedence order:
+     *
+     * <ol>
+     *   <li>{@code "valid_range"}  — expected "reasonable" range for variable.</li>
+     *   <li>{@code "actual_range"} — actual data range for variable.</li>
+     *   <li>{@code "valid_min"}    — ignored if {@code "valid_range"} is present,
as specified in UCAR documentation.</li>
+     *   <li>{@code "valid_max"}    — idem.</li>
+     * </ol>
+     *
+     * Whether the returned range is a range of packed values or a range of real values is
ambiguous.
+     * An heuristic rule is documented in UCAR {@link ucar.nc2.dataset.EnhanceScaleMissing}
interface.
+     * If both type of ranges are available, then this method should return the range of
packed value.
+     * Otherwise if this method returns the range of real values, then that range shall be
an instance
+     * of {@link MeasurementRange} for allowing the caller to distinguish the two cases.
+     *
+     * @param  source  the variable to get valid range of values for.
+     * @return the range of valid values, or {@code null} if unknown.
+     *
+     * @see Variable#getRangeFallback()
+     */
+    public NumberRange<?> getValidValues(final Variable source) {
+        Number minimum = null;
+        Number maximum = null;
+        Class<? extends Number> type = null;
+        for (final String attribute : RANGE_ATTRIBUTES) {
+            for (final Object element : source.getAttributeValues(attribute, true)) {
+                if (element instanceof Number) {
+                    Number value = (Number) element;
+                    if (element instanceof Float) {
+                        final float fp = (Float) element;
+                        if      (fp == +Float.MAX_VALUE) value = Float.POSITIVE_INFINITY;
+                        else if (fp == -Float.MAX_VALUE) value = Float.NEGATIVE_INFINITY;
+                    } else if (element instanceof Double) {
+                        final double fp = (Double) element;
+                        if      (fp == +Double.MAX_VALUE) value = Double.POSITIVE_INFINITY;
+                        else if (fp == -Double.MAX_VALUE) value = Double.NEGATIVE_INFINITY;
+                    }
+                    type = Numbers.widestClass(type, value.getClass());
+                    minimum = Numbers.cast(minimum, type);
+                    maximum = Numbers.cast(maximum, type);
+                    value   = Numbers.cast(value,   type);
+                    if (!attribute.endsWith("max") && (minimum == null || compare(value,
minimum) < 0)) minimum = value;
+                    if (!attribute.endsWith("min") && (maximum == null || compare(value,
maximum) > 0)) maximum = value;
+                }
+            }
+            if (minimum != null && maximum != null) {
+                /*
+                 * Heuristic rule defined in UCAR documentation (see EnhanceScaleMissing
interface):
+                 * if the type of the range is equal to the type of the scale, and the type
of the
+                 * data is not wider, then assume that the minimum and maximum are real values.
+                 */
+                final int rangeType = Numbers.getEnumConstant(type);
+                if (rangeType >= source.getDataType().number &&
+                    rangeType >= Math.max(Numbers.getEnumConstant(source.getAttributeType(CDM.SCALE_FACTOR)),
+                                          Numbers.getEnumConstant(source.getAttributeType(CDM.ADD_OFFSET))))
+                {
+                    @SuppressWarnings({"unchecked", "rawtypes"})
+                    final NumberRange<?> range = new MeasurementRange(type, minimum,
true, maximum, true, source.getUnit());
+                    return range;
+                } else {
+                    @SuppressWarnings({"unchecked", "rawtypes"})
+                    final NumberRange<?> range = new NumberRange(type, minimum, true,
maximum, true);
+                    return range;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Compares two numbers which shall be of the same class.
+     * This is a helper method for {@link #getValidValues(Variable)}.
+     */
+    @SuppressWarnings("unchecked")
+    private static int compare(final Number n1, final Number n2) {
+        return ((Comparable) n1).compareTo((Comparable) n2);
+    }
+
+    /**
+     * Builds the function converting values from their packed formats in the variable to
"real" values.
+     * The transfer function is typically built from the {@code "scale_factor"} and {@code
"add_offset"}
+     * attributes associated to the given variable, but other conventions could use different
attributes.
+     * The returned function will be a component of the {@link org.apache.sis.coverage.SampleDimension}
+     * to be created for each variable.
      *
-     * @param source The variable specifying the transfer function.
+     * @param  source  the variable from which to determine the transfer function.
      *
-     * @return A transfer function matching given variable. Note that if we cannot find any
information in input
-     * variable, we return an identity transform. Never null.
+     * @return a transfer function built from the attributes defined in the given variable.
Never null;
+     *         if no information is found in the given {@code source} variable, then the
return value
+     *         shall be an identity function.
      */
     public TransferFunction getTransferFunction(final Variable source) {
         /*
@@ -138,25 +237,10 @@ public class Convention {
          * a "packed" variable. Otherwise the transfer function is the identity transform.
          */
         final TransferFunction tr = new TransferFunction();
-        final double scale = source.getAttributeAsNumber(CDM.SCALE_FACTOR);
+        final double scale  = source.getAttributeAsNumber(CDM.SCALE_FACTOR);
         final double offset = source.getAttributeAsNumber(CDM.ADD_OFFSET);
-        if (!Double.isNaN(scale)) {
-            tr.setScale(scale);
-        }
-        if (!Double.isNaN(offset)) {
-            tr.setOffset(offset);
-        }
-
+        if (!Double.isNaN(scale))  tr.setScale (scale);
+        if (!Double.isNaN(offset)) tr.setOffset(offset);
         return tr;
     }
-
-    /**
-     * Search in given variable for information about its range of valid values.
-     *
-     * @param source The variable to get valid range of values for.
-     * @return The range of expected measures, or nothing if we didn't find any related information.
-     */
-    public Optional<NumberRange<?>> getValidValues(final Variable source) {
-        return Optional.ofNullable(source.getValidValues());
-    }
 }
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 5595ff1..657065c 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
@@ -31,7 +31,6 @@ import org.apache.sis.coverage.grid.GridExtent;
 import org.apache.sis.math.Vector;
 import org.apache.sis.math.MathFunctions;
 import org.apache.sis.math.DecimalFunctions;
-import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ArraysExt;
@@ -64,18 +63,6 @@ public abstract class Variable extends NamedElement {
     protected static final WeakHashSet<Vector> SHARED_VECTORS = new WeakHashSet<>(Vector.class);
 
     /**
-     * Names of attributes where to fetch minimum and maximum sample values, in preference
order.
-     *
-     * @see #getValidValues()
-     */
-    private static final String[] RANGE_ATTRIBUTES = {
-        "valid_range",      // Expected "reasonable" range for variable.
-        "actual_range",     // Actual data range for variable.
-        "valid_min",        // Fallback if "valid_range" is not specified.
-        "valid_max"
-    };
-
-    /**
      * Names of attributes where to fetch missing or pad values. Order matter since it determines
the bits to be set
      * in the map returned by {@link #getNodataValues()}. The main bit is bit 0, which identify
the background value.
      */
@@ -318,7 +305,7 @@ public abstract class Variable extends NamedElement {
      * to this method.
      *
      * <p>This method has protected access because it should not be invoked directly
except in overridden methods.
-     * Code using variable role should invoke {@link Decoder#roleOf(Variable)} instead, for
allowing specialization
+     * Code using variable role should invoke {@link Convention#roleOf(Variable)} instead,
for allowing specialization
      * by {@link Convention}.</p>
      *
      * @return the role of this variable.
@@ -465,74 +452,21 @@ public abstract class Variable extends NamedElement {
     }
 
     /**
-     * Returns the range of valid values, or {@code null} if unknown.
-     * The range of values is taken from the following properties, in precedence order:
-     *
-     * <ol>
-     *   <li>{@code "valid_range"}  — expected "reasonable" range for variable.</li>
-     *   <li>{@code "actual_range"} — actual data range for variable.</li>
-     *   <li>{@code "valid_min"}    — ignored if {@code "valid_range"} is present,
as specified in UCAR documentation.</li>
-     *   <li>{@code "valid_max"}    — idem.</li>
-     * </ol>
+     * Returns the range of values as determined by the data type or other means, or {@code
null} if unknown.
+     * This method is invoked only as a fallback if {@link Convention#getValidValues(Variable)}
did not found
+     * a range of values by application of CF conventions. The returned range may be a range
of packed values
+     * or a range of real values. In the later case, the range shall be an instance of
+     * {@link org.apache.sis.measure.MeasurementRange}.
      *
-     * Whether the returned range is a range of packed values or a range of real values is
ambiguous.
-     * An heuristic rule is documented in UCAR {@link ucar.nc2.dataset.EnhanceScaleMissing}
interface.
-     * If both type of ranges are available, this method should return the range of packed
value.
-     * Otherwise if this method return the range of real values, then that range shall be
an instance
-     * of {@link MeasurementRange} for allowing the caller to distinguish the two cases.
+     * <p>The default implementation returns the range of values that can be stored
with the {@linkplain #getDataType()
+     * data type} of this variable, if that type is an integer type. The range of {@linkplain
#getNodataValues() no data
+     * values} are subtracted.</p>
      *
      * @return the range of valid values, or {@code null} if unknown.
+     *
+     * @see Convention#getValidValues(Variable)
      */
-    public NumberRange<?> getValidValues() {
-        Number minimum = null;
-        Number maximum = null;
-        Class<? extends Number> type = null;
-        for (final String attribute : RANGE_ATTRIBUTES) {
-            for (final Object element : getAttributeValues(attribute, true)) {
-                if (element instanceof Number) {
-                    Number value = (Number) element;
-                    if (element instanceof Float) {
-                        final float fp = (Float) element;
-                        if      (fp == +Float.MAX_VALUE) value = Float.POSITIVE_INFINITY;
-                        else if (fp == -Float.MAX_VALUE) value = Float.NEGATIVE_INFINITY;
-                    } else if (element instanceof Double) {
-                        final double fp = (Double) element;
-                        if      (fp == +Double.MAX_VALUE) value = Double.POSITIVE_INFINITY;
-                        else if (fp == -Double.MAX_VALUE) value = Double.NEGATIVE_INFINITY;
-                    }
-                    type = Numbers.widestClass(type, value.getClass());
-                    minimum = Numbers.cast(minimum, type);
-                    maximum = Numbers.cast(maximum, type);
-                    value   = Numbers.cast(value,   type);
-                    if (!attribute.endsWith("max") && (minimum == null || compare(value,
minimum) < 0)) minimum = value;
-                    if (!attribute.endsWith("min") && (maximum == null || compare(value,
maximum) > 0)) maximum = value;
-                }
-            }
-            if (minimum != null && maximum != null) {
-                /*
-                 * Heuristic rule defined in UCAR documentation (see EnhanceScaleMissing
interface):
-                 * if the type of the range is equal to the type of the scale, and the type
of the
-                 * data is not wider, then assume that the minimum and maximum are real values.
-                 */
-                final int rangeType = Numbers.getEnumConstant(type);
-                if (rangeType >= getDataType().number &&
-                    rangeType >= Math.max(Numbers.getEnumConstant(getAttributeType(CDM.SCALE_FACTOR)),
-                                          Numbers.getEnumConstant(getAttributeType(CDM.ADD_OFFSET))))
-                {
-                    @SuppressWarnings({"unchecked", "rawtypes"})
-                    final NumberRange<?> range = new MeasurementRange(type, minimum,
true, maximum, true, getUnit());
-                    return range;
-                } else {
-                    @SuppressWarnings({"unchecked", "rawtypes"})
-                    final NumberRange<?> range = new NumberRange(type, minimum, true,
maximum, true);
-                    return range;
-                }
-            }
-        }
-        /*
-         * If we found no explicit range attribute and if the variable type is an integer
type,
-         * then infer the range from the variable type and exclude the ranges of nodata values.
-         */
+    public NumberRange<?> getRangeFallback() {
         final DataType dataType = getDataType();
         if (dataType.isInteger) {
             final int size = dataType.size() * Byte.SIZE;
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
index 258868a..2940862 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
@@ -128,7 +128,6 @@ final class VariableWrapper extends Variable {
         if (d != null && (d = d.trim()).isEmpty()) {
             d = null;
         }
-
         return d;
     }
 
@@ -346,23 +345,21 @@ final class VariableWrapper extends Variable {
     }
 
     /**
-     * Returns the minimum and maximum values as determined by Apache SIS, using the UCAR
library as a fallback.
-     * This method gives precedence to the range computed by Apache SIS instead than the
range provided by UCAR
-     * because we need the range of packed values instead than the range of converted values.
Only if Apache SIS
-     * can not determine that range, we use the UCAR library and returns the value in a {@link
MeasurementRange}
-     * instance of signaling the caller that this is converted values.
+     * Returns the minimum and maximum values as determined by UCAR library, or inferred
from the integer type otherwise.
+     * This method is invoked only as a fallback; we give precedence to the range computed
by Apache SIS instead than the
+     * range provided by UCAR because we need the range of packed values instead than the
range of converted values. Only
+     * if Apache SIS can not determine that range, that method is invoked.
      */
     @Override
-    public NumberRange<?> getValidValues() {
-        NumberRange<?> range = super.getValidValues();
-        if (range == null && variable instanceof EnhanceScaleMissing) {
+    public NumberRange<?> getRangeFallback() {
+        if (variable instanceof EnhanceScaleMissing) {
             final EnhanceScaleMissing ev = (EnhanceScaleMissing) variable;
             if (ev.hasInvalidData()) {
-                range = MeasurementRange.create(ev.getValidMin(), true, ev.getValidMax(),
true, getUnit());
+                // Returns a MeasurementRange instance for signaling the caller that this
is converted values.
+                return MeasurementRange.create(ev.getValidMin(), true, ev.getValidMax(),
true, getUnit());
             }
         }
-        return range;
-
+        return super.getRangeFallback();
     }
 
     /**
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/GridResource.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/GridResource.java
index dcde33c..d0bf1b8 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/GridResource.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/GridResource.java
@@ -27,7 +27,6 @@ import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.operation.MathTransform1D;
 import org.opengis.referencing.operation.TransformException;
-import org.apache.sis.referencing.operation.transform.TransferFunction;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.internal.netcdf.Decoder;
 import org.apache.sis.internal.netcdf.Grid;
@@ -62,6 +61,7 @@ import org.apache.sis.internal.util.UnmodifiableArrayList;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
+ * @author  Alexis Manin (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
@@ -128,8 +128,8 @@ final class GridResource extends AbstractGridResource implements ResourceOnFileS
     private final Path location;
 
     /**
-     * Allow to fetch referencing information from source variables. It's mostly useful to
handle multiple
-     * NetCDF structures (CF, GCOM, etc.)
+     * Allows to fetch referencing information from source variables. It's mostly useful
for handling netCDF files
+     * structured in ways different than CF-convention (for example GCOM, <i>etc.</i>).
      */
     private final Convention convention;
 
@@ -258,65 +258,71 @@ final class GridResource extends AbstractGridResource implements ResourceOnFileS
      */
     @Override
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    public List<SampleDimension> getSampleDimensions() {
+    public List<SampleDimension> getSampleDimensions() throws DataStoreException {
         SampleDimension.Builder builder = null;
-        for (int i=0; i<ranges.length; i++) {
-            if (ranges[i] == null) {
-                if (builder == null) builder = new SampleDimension.Builder();
-                ranges[i] = createSampleDimension(builder, data[i]);
-                builder.clear();
+        try {
+            for (int i=0; i<ranges.length; i++) {
+                if (ranges[i] == null) {
+                    if (builder == null) builder = new SampleDimension.Builder();
+                    ranges[i] = createSampleDimension(builder, data[i]);
+                    builder.clear();
+                }
             }
+        } catch (TransformException e) {
+            throw new DataStoreReferencingException(e);
         }
         return UnmodifiableArrayList.wrap(ranges);
     }
 
     /**
-     * Try to add information about valid values in a given sample dimension builder.
-     * 
-     * @param target The builder to add information into.
-     * @param range Base range for valid values.
-     * @param data Variable to use in order to improve quantitative information.
-     */
-    private void addQuantitativeInfo(final SampleDimension.Builder target, NumberRange<?>
range, final Variable data) {
-        final TransferFunction tr = convention.getTransferFunction(data);
-        final MathTransform1D mt = tr.getTransform();
-        if (!mt.isIdentity() && range instanceof MeasurementRange<?>) {
-            /*
-             * Heuristic rule defined in UCAR documentation (see EnhanceScaleMissing interface):
-             * if the type of the range is equal to the type of the scale, and the type of
the
-             * data is not wider, then assume that the minimum and maximum are real values.
-             * This is identified in Apache SIS by the range given as a MeasurementRange.
-             */
-            final boolean isMinIncluded = range.isMinIncluded();
-            final boolean isMaxIncluded = range.isMaxIncluded();
-            double minimum = (range.getMinDouble() - tr.getOffset()) / tr.getScale();
-            double maximum = (range.getMaxDouble() - tr.getOffset()) / tr.getScale();
-            if (maximum < minimum) {
-                final double swap = maximum;
-                maximum = minimum;
-                minimum = swap;
-            }
-            if (data.getDataType().number < Numbers.FLOAT && minimum >= Long.MIN_VALUE
&& maximum <= Long.MAX_VALUE) {
-                range = NumberRange.create(Math.round(minimum), isMinIncluded, Math.round(maximum),
isMaxIncluded);
-            } else {
-                range = NumberRange.create(minimum, isMinIncluded, maximum, isMaxIncluded);
-            }
-        }
-        String name = data.getDescription();
-        if (name == null) name = data.getName();
-        target.addQuantitative(name, range, mt, data.getUnit());
-    }
-
-    /**
      * Creates a single sample dimension for the given variable.
      *
      * @param  builder  the builder to use for creating the sample dimension.
      * @param  data     the data for which to create a sample dimension.
+     * @throws TransformException if an error occurred while using the transfer function.
      */
-    private SampleDimension createSampleDimension(final SampleDimension.Builder builder,
final Variable data) {
-        convention.getValidValues(data)
-                .ifPresent(range -> addQuantitativeInfo(builder, range, data));
-
+    private SampleDimension createSampleDimension(final SampleDimension.Builder builder,
final Variable data) throws TransformException {
+        /*
+         * Take the minimum and maximum values as determined by Apache SIS through the Convention
class.  The UCAR library
+         * is used only as a fallback. We give precedence to the range computed by Apache
SIS instead than the range given
+         * by UCAR because we need the range of packed values instead than the range of converted
values.
+         */
+        NumberRange<?> range = convention.getValidValues(data);
+        if (range == null) {
+            range = data.getRangeFallback();                                // Fallback to
UCAR library may happen here.
+        }
+        if (range != null) {
+            final MathTransform1D mt = convention.getTransferFunction(data).getTransform();
+            if (!mt.isIdentity() && range instanceof MeasurementRange<?>) {
+                /*
+                 * Heuristic rule defined in UCAR documentation (see EnhanceScaleMissing
interface):
+                 * if the type of the range is equal to the type of the scale, and the type
of the
+                 * data is not wider, then assume that the minimum and maximum are real values.
+                 * This is identified in Apache SIS by the range given as a MeasurementRange.
+                 */
+                final MathTransform1D inverse = mt.inverse();
+                boolean isMinIncluded = range.isMinIncluded();
+                boolean isMaxIncluded = range.isMaxIncluded();
+                double minimum = inverse.transform(range.getMinDouble());
+                double maximum = inverse.transform(range.getMaxDouble());
+                if (maximum < minimum) {
+                    final double swap = maximum;
+                    maximum = minimum;
+                    minimum = swap;
+                    final boolean sb = isMaxIncluded;
+                    isMaxIncluded = isMinIncluded;
+                    isMinIncluded = sb;
+                }
+                if (data.getDataType().number < Numbers.FLOAT && minimum >=
Long.MIN_VALUE && maximum <= Long.MAX_VALUE) {
+                    range = NumberRange.create(Math.round(minimum), isMinIncluded, Math.round(maximum),
isMaxIncluded);
+                } else {
+                    range = NumberRange.create(minimum, isMinIncluded, maximum, isMaxIncluded);
+                }
+            }
+            String name = data.getDescription();
+            if (name == null) name = data.getName();
+            builder.addQuantitative(name, range, mt, data.getUnit());
+        }
         /*
          * Adds the "missing value" or "fill value" as qualitative categories.  If a value
has both roles, use "missing value"
          * as category name. If the sample values are already real values, then the "no data"
values have been replaced by NaN
@@ -414,6 +420,8 @@ final class GridResource extends AbstractGridResource implements ResourceOnFileS
             imageBuffer = RasterFactory.wrap(dataType.rasterDataType, samples);
         } catch (IOException e) {
             throw new DataStoreException(e);
+        } catch (TransformException e) {
+            throw new DataStoreReferencingException(e);
         } catch (RuntimeException e) {                  // Many exceptions thrown by RasterFactory.wrap(…).
             final Throwable cause = e.getCause();
             if (cause instanceof TransformException) {


Mime
View raw message