sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 02/02: Initial implementation of netCDF GridResource.getSampleDimensions().
Date Thu, 06 Dec 2018 01:01:14 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 8482f7a9511205833db9e3fced0b9b0430b8b11c
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Thu Dec 6 02:00:40 2018 +0100

    Initial implementation of netCDF GridResource.getSampleDimensions().
---
 .../org/apache/sis/coverage/SampleDimension.java   |  4 +-
 .../org/apache/sis/coverage/SampleRangeFormat.java |  8 +-
 .../org/apache/sis/coverage/grid/GridGeometry.java |  2 +-
 .../sis/storage/geotiff/ImageFileDirectory.java    | 12 ++-
 .../java/org/apache/sis/internal/netcdf/Axis.java  |  4 +-
 .../org/apache/sis/internal/netcdf/Variable.java   | 53 +++++++++++-
 .../apache/sis/internal/netcdf/impl/GridInfo.java  |  2 +-
 .../sis/internal/netcdf/impl/VariableInfo.java     | 11 ++-
 .../sis/internal/netcdf/ucar/VariableWrapper.java  | 13 ---
 .../apache/sis/storage/netcdf/GridResource.java    | 96 +++++++++++++++++++++-
 .../apache/sis/storage/netcdf/MetadataReader.java  | 12 +--
 .../apache/sis/storage/GridCoverageResource.java   | 40 ++++++++-
 12 files changed, 211 insertions(+), 46 deletions(-)

diff --git a/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleDimension.java b/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleDimension.java
index 8b361d9..b1ba2f5 100644
--- a/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleDimension.java
+++ b/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleDimension.java
@@ -236,7 +236,7 @@ public class SampleDimension implements Serializable {
     }
 
     /**
-     * Returns the offset and scale factors of the transfer function.
+     * Returns the scale factor and offset of the transfer function.
      * The formula returned by this method does <strong>not</strong> take
      * "{@linkplain #getNoDataValues() no data values}" in account.
      * For a more generic transfer function, see {@link #getTransferFunction()}.
@@ -594,7 +594,7 @@ public class SampleDimension implements Serializable {
          * @param  upper   the upper sample value, exclusive.
          * @param  scale   the scale value which is multiplied to sample values for the category.
Must be different than zero.
          * @param  offset  the offset value to add to sample values for this category.
-         * @param  units   the units of measurement of values after conversion by the offset
and scale factor.
+         * @param  units   the units of measurement of values after conversion by the scale
factor and offset.
          * @return {@code this}, for method call chaining.
          * @throws IllegalArgumentException if {@code lower} is not smaller than {@code upper},
          *         or if {@code scale} or {@code offset} are not real numbers, or if {@code
scale} is zero.
diff --git a/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleRangeFormat.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleRangeFormat.java
index c6dd944..d8b7fa9 100644
--- a/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleRangeFormat.java
+++ b/core/sis-raster/src/main/java/org/apache/sis/coverage/SampleRangeFormat.java
@@ -80,7 +80,7 @@ final class SampleRangeFormat extends RangeFormat {
                                    / ( category.maximum -  category.minimum);
             if (!Double.isNaN(increment)) {
                 hasQuantitative = true;
-                final int n = -Numerics.toExp10(Math.getExponent(increment));
+                final int n = 1 - Numerics.toExp10(Math.getExponent(increment));
                 if (n > ndigits) {
                     ndigits = n;
                     if (n >= MAX_DIGITS) {
@@ -155,9 +155,9 @@ final class SampleRangeFormat extends RangeFormat {
     void format(final InternationalString title, final CategoryList categories, final Appendable
out) throws IOException {
         final String lineSeparator = System.lineSeparator();
         out.append(title.toString(getLocale())).append(lineSeparator);
-        final TableAppender table  = new TableAppender(out);
+        final TableAppender table  = new TableAppender(out, " │ ");
         final boolean hasQuantitative = prepare(categories);
-        table.nextLine('═');
+        table.appendHorizontalSeparator();
         table.setCellAlignment(TableAppender.ALIGN_CENTER);
         table.append(words.getString(Vocabulary.Keys.Values)).nextColumn();
         if (hasQuantitative) {
@@ -177,7 +177,7 @@ final class SampleRangeFormat extends RangeFormat {
             table.append(category.name.toString(getLocale()));
             table.nextLine();
         }
-        table.nextLine('═');
+        table.appendHorizontalSeparator();
         table.flush();
     }
 }
diff --git a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index 9e6b715..9f10131 100644
--- a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++ b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -62,7 +62,7 @@ import static org.apache.sis.referencing.CRS.findOperation;
  * Valid extent of grid coordinates together with the transform from those grid coordinates
  * to real world coordinates. {@code GridGeometry} contains:
  *
- * <ul>
+ * <ul class="verbose">
  *   <li>A {@linkplain #getExtent() grid extent} (a.k.a. <cite>grid envelope</cite>),
  *       often inferred from the {@link RenderedImage} size.</li>
  *   <li>A {@linkplain #getGridToCRS grid to CRS} transform,
diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index a0be1a4..edfb70b 100644
--- a/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++ b/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -18,6 +18,7 @@ package org.apache.sis.storage.geotiff;
 
 import java.io.IOException;
 import java.text.ParseException;
+import java.util.List;
 import java.util.Arrays;
 import java.util.Locale;
 import java.util.logging.Level;
@@ -36,6 +37,7 @@ import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.math.Vector;
 import org.apache.sis.measure.Units;
 
@@ -1225,7 +1227,7 @@ final class ImageFileDirectory extends AbstractGridResource {
     }
 
     /**
-     * Returns the grid geometry for this image.
+     * Returns an object containing the image size, the CRS and the conversion from pixel
indices to CRS coordinates.
      */
     @Override
     public GridGeometry getGridGeometry() throws DataStoreContentException {
@@ -1243,6 +1245,14 @@ final class ImageFileDirectory extends AbstractGridResource {
     }
 
     /**
+     * Returns the ranges of sample values together with the conversion from samples to real
values.
+     */
+    @Override
+    public List<SampleDimension> getSampleDimensions() throws DataStoreContentException
{
+        throw new DataStoreContentException("Not supported yet.");
+    }
+
+    /**
      * Reports a warning with a message created from the given resource keys and parameters.
      *
      * @param  level       the logging level for the message to log.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
index 999267f..fa90581 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Axis.java
@@ -272,7 +272,7 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
         final Map<String,Object> properties = new HashMap<>(4);
         properties.put(CoordinateSystemAxis.NAME_KEY, name);                        // Intentionally
no namespace.
         final List<GenericName> aliases = new ArrayList<>(2);
-        final String standardName = coordinates.getAttributeString(CF.STANDARD_NAME);
+        final String standardName = coordinates.getAttributeAsString(CF.STANDARD_NAME);
         if (standardName != null) {
             final NamedIdentifier std = new NamedIdentifier(Citations.NETCDF, standardName);
             if (standardName.equals(name)) {
@@ -285,7 +285,7 @@ public final class Axis extends NamedElement implements Comparable<Axis>
{
          * The long name is stored as an optional description of the primary name.
          * It is also stored as an alias if not redundant with other names.
          */
-        final String alt = coordinates.getAttributeString(CDM.LONG_NAME);
+        final String alt = coordinates.getAttributeAsString(CDM.LONG_NAME);
         if (alt != null && !similar(alt, name)) {
             properties.put(org.opengis.metadata.Identifier.DESCRIPTION_KEY, alt);   // Description
associated to primary name.
             if (!similar(alt, standardName)) {
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 8d8ca0d..c79fbd4 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
@@ -25,6 +25,7 @@ import java.time.Instant;
 import javax.measure.Unit;
 import org.opengis.referencing.operation.Matrix;
 import org.apache.sis.math.Vector;
+import org.apache.sis.math.DecimalFunctions;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.logging.WarningListeners;
 import org.apache.sis.util.resources.Errors;
@@ -301,22 +302,68 @@ public abstract class Variable extends NamedElement {
     /**
      * Returns the sequence of values for the given attribute, or an empty array if none.
      * The elements will be of class {@link String} if {@code numeric} is {@code false},
-     * or {@link Number} if {@code numeric} is {@code true}.
+     * or {@link Number} if {@code numeric} is {@code true}. Some elements may be null
+     * if they are not of the expected type.
      *
      * @param  attributeName  the name of the attribute for which to get the values.
      * @param  numeric        {@code true} if the values are expected to be numeric, or {@code
false} for strings.
      * @return the sequence of {@link String} or {@link Number} values for the named attribute.
+     *         May contain null elements.
      */
     public abstract Object[] getAttributeValues(String attributeName, boolean numeric);
 
     /**
+     * Returns the singleton value for the given attribute, or {@code null} if none or ambiguous.
+     *
+     * @param  attributeName  the name of the attribute for which to get the value.
+     * @param  numeric        {@code true} if the value is expected to be numeric, or {@code
false} for string.
+     * @return the {@link String} or {@link Number} value for the named attribute.
+     */
+    public final Object getAttributeValue(final String attributeName, final boolean numeric)
{
+        Object singleton = null;
+        for (final Object value : getAttributeValues(attributeName, numeric)) {
+            if (value != null) {
+                if (singleton != null && !singleton.equals(value)) {            
 // Paranoiac check.
+                    return null;
+                }
+                singleton = value;
+            }
+        }
+        return singleton;
+    }
+
+    /**
      * Returns the value of the given attribute as a string. This is a convenience method
      * for {@link #getAttributeValues(String, boolean)} when a singleton value is expected.
      *
-     * @param  attributeName  the name of the attribute for which to get the values.
+     * @param  attributeName  the name of the attribute for which to get the value.
      * @return the singleton attribute value, or {@code null} if none or ambiguous.
      */
-    public abstract String getAttributeString(final String attributeName);
+    public String getAttributeAsString(final String attributeName) {
+        final Object value = getAttributeValue(attributeName, false);
+        return (value != null) ? value.toString() : null;
+    }
+
+    /**
+     * 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 getAttributeAsNumber(final String attributeName) {
+        final Object value = getAttributeValue(attributeName, true);
+        if (value instanceof Number) {
+            double dp = ((Number) value).doubleValue();
+            final float sp = (float) dp;
+            if (sp == dp) {                              // May happen even if the number
was stored as a double.
+                dp = DecimalFunctions.floatToDouble(sp);
+            }
+            return dp;
+        }
+        return Double.NaN;
+    }
 
     /**
      * Whether {@link #read()} invoked {@link Vector#compress(double)} on the returned vector.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
index cddf008..b587d67 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridInfo.java
@@ -241,7 +241,7 @@ final class GridInfo extends Grid {
                     }
                 }
             }
-            axes[targetDim] = new Axis(this, axis, abbreviation, axis.getAttributeString(CF.POSITIVE),
+            axes[targetDim] = new Axis(this, axis, abbreviation, axis.getAttributeAsString(CF.POSITIVE),
                                        ArraysExt.resize(indices, i), ArraysExt.resize(sizes,
i));
         }
         if (sortAxes) {
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
index 38054cc..ba20c10 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
@@ -384,7 +384,7 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
      */
     @Override
     protected String getUnitsString() {
-        return getAttributeString(CDM.UNITS);
+        return getAttributeAsString(CDM.UNITS);
     }
 
     /**
@@ -455,7 +455,7 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
      * Returns the names of variables to use as axes for this variable, or an empty array
if none.
      */
     final CharSequence[] getCoordinateVariables() {
-        return CharSequences.split(getAttributeString(CF.COORDINATES), ' ');
+        return CharSequences.split(getAttributeAsString(CF.COORDINATES), ' ');
     }
 
     /**
@@ -557,7 +557,7 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
      * Returns the value of the given attribute as a string, or {@code null} if none.
      */
     @Override
-    public String getAttributeString(final String attributeName) {
+    public String getAttributeAsString(final String attributeName) {
         final Object value = getAttributeValue(attributeName);
         return (value instanceof String) ? (String) value : null;
     }
@@ -594,7 +594,10 @@ final class VariableInfo extends Variable implements Comparable<VariableInfo>
{
             if (value.getClass().isArray()) {
                 final Number[] values = new Number[Array.getLength(value)];
                 for (int i=0; i<values.length; i++) {
-                    values[i] = (Number) Array.get(value, i);
+                    final Object element = Array.get(value, i);
+                    if (element instanceof Number) {
+                        values[i] = (Number) element;
+                    }
                 }
                 return values;
             }
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 0f09b30..16e8119 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
@@ -293,19 +293,6 @@ final class VariableWrapper extends Variable {
     }
 
     /**
-     * Returns the value of the given attribute as a string. This is a convenience method
-     * for {@link #getAttributeValues(String, boolean)} when a singleton value is expected.
-     *
-     * @param  attributeName  the name of the attribute for which to get the values.
-     * @return the singleton attribute value, or {@code null} if none or ambiguous.
-     */
-    @Override
-    public String getAttributeString(final String attributeName) {
-        Object[] values = getAttributeValues(attributeName, false);
-        return (values.length == 1) ? values[0].toString() : null;
-    }
-
-    /**
      * Returns the names of all attributes in the given list.
      */
     static List<String> toNames(final List<Attribute> attributes) {
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 30b2a28..6eee206 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
@@ -18,21 +18,29 @@ package org.apache.sis.storage.netcdf;
 
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.io.IOException;
 import java.nio.file.Path;
 import org.opengis.util.GenericName;
+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;
 import org.apache.sis.internal.netcdf.Variable;
 import org.apache.sis.internal.storage.AbstractGridResource;
 import org.apache.sis.internal.storage.ResourceOnFileSystem;
+import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.Resource;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.util.Numbers;
+import ucar.nc2.constants.CDM;                      // We use only String constants.
 
 
 /**
- * A grid coverage in a netCDF file.
+ * A grid coverage in a netCDF file. We create one resource for each variable,
+ * unless we determine that two variables should be handled together (for example
+ * the <var>u</var> and <var>v</var> components of wind vectors).
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
@@ -41,13 +49,26 @@ import org.apache.sis.storage.Resource;
  */
 final class GridResource extends AbstractGridResource implements ResourceOnFileSystem {
     /**
-     * The identifier of this grid resource.
-     * This is the variable name.
+     * Names of attributes where to fetch minimum and maximum sample values, in preference
order.
+     */
+    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"
+    };
+
+    /**
+     * The identifier of this grid resource. This is the variable name.
+     *
+     * @see #getIdentifier()
      */
     private final GenericName identifier;
 
     /**
      * The grid geometry (size, CRS…) of the {@linkplain #data} cube.
+     *
+     * @see #getGridGeometry()
      */
     private final GridGeometry gridGeometry;
 
@@ -57,7 +78,16 @@ final class GridResource extends AbstractGridResource implements ResourceOnFileS
     private final Variable data;
 
     /**
+     * The sample dimension for the {@link #data} variable, created when first needed.
+     *
+     * @see #getSampleDimensions()
+     */
+    private SampleDimension definition;
+
+    /**
      * Path to the netCDF file for information purpose, or {@code null} if unknown.
+     *
+     * @see #getComponentFiles()
      */
     private final Path location;
 
@@ -104,11 +134,69 @@ final class GridResource extends AbstractGridResource implements ResourceOnFileS
      * Returns an object containing the grid size, the CRS and the conversion from grid indices
to CRS coordinates.
      */
     @Override
-    public GridGeometry getGridGeometry() throws DataStoreException {
+    public GridGeometry getGridGeometry() {
         return gridGeometry;
     }
 
     /**
+     * Returns the ranges of sample values together with the conversion from samples to real
values.
+     */
+    @Override
+    public List<SampleDimension> getSampleDimensions() {
+        if (definition == null) {
+            /*
+             * Gets minimum and maximum. If a "valid_range" attribute is present, it has
precedence
+             * over "valid_min" and "valid_max" as specified in the UCAR documentation.
+             */
+            Number minimum = null;
+            Number maximum = null;
+            Class<? extends Number> type = null;
+            for (final String attribute : RANGE_ATTRIBUTES) {
+                for (final Object element : data.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 (minimum == null || compare(value, minimum) < 0) minimum =
value;
+                        if (maximum == null || compare(value, maximum) > 0) maximum =
value;
+                    }
+                }
+                if (minimum != null && maximum != null) break;
+            }
+            @SuppressWarnings({"unchecked", "rawtypes"})
+            final NumberRange<?> range = new NumberRange(type, minimum, true, maximum,
true);
+            /*
+             * Conversion from sample values to real values. If no scale factor and offset
are specified,
+             * then the default will be the identity transform.
+             */
+            final TransferFunction tr = new TransferFunction();
+            double scale  = data.getAttributeAsNumber(CDM.SCALE_FACTOR);
+            double offset = data.getAttributeAsNumber(CDM.ADD_OFFSET);
+            if (!Double.isNaN(scale))  tr.setScale (scale);
+            if (!Double.isNaN(offset)) tr.setOffset(offset);
+            definition = new SampleDimension.Builder()
+                    .addQuantitative(data.getName(), range, tr.getTransform(), data.getUnit()).build();
+        }
+        return Collections.singletonList(definition);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static int compare(final Number n1, final Number n2) {
+        return ((Comparable) n1).compareTo((Comparable) n2);
+    }
+
+    /**
      * Gets the paths to files used by this resource, or an empty array if unknown.
      */
     @Override
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 1e64841..4c13091 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
@@ -938,21 +938,17 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value,
start, lengt
             final NameFactory f = decoder.nameFactory;
             setBandIdentifier(f.createMemberName(null, name, f.createTypeName(null, variable.getDataTypeName())));
         }
-        final String id = trim(variable.getAttributeString(CF.STANDARD_NAME));
+        final String id = trim(variable.getAttributeAsString(CF.STANDARD_NAME));
         if (id != null && !id.equals(name)) {
-            addBandName(variable.getAttributeString(ACDD.standard_name_vocabulary), id);
+            addBandName(variable.getAttributeAsString(ACDD.standard_name_vocabulary), id);
         }
         final String description = trim(variable.getDescription());
         if (description != null && !description.equals(name) && !description.equals(id))
{
             addBandDescription(description);
         }
         setSampleUnits(variable.getUnit());
-        double scale  = Double.NaN;
-        double offset = Double.NaN;
-        Object[] v;
-        v = variable.getAttributeValues(CDM.SCALE_FACTOR, true); if (v.length == 1) scale
 = ((Number) v[0]).doubleValue();
-        v = variable.getAttributeValues(CDM.ADD_OFFSET,   true); if (v.length == 1) offset
= ((Number) v[0]).doubleValue();
-        setTransferFunction(scale, offset);
+        setTransferFunction(variable.getAttributeAsNumber(CDM.SCALE_FACTOR),
+                            variable.getAttributeAsNumber(CDM.ADD_OFFSET));
         addContentType(forCodeName(CoverageContentType.class, stringValue(ACDD.coverage_content_type)));
     }
 
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java
b/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java
index 4945014..a6e10ec 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/GridCoverageResource.java
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.storage;
 
+import java.util.List;
+import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.coverage.grid.GridGeometry;
 
 
@@ -30,11 +32,43 @@ import org.apache.sis.coverage.grid.GridGeometry;
  */
 public interface GridCoverageResource extends DataSet {
     /**
-     * Returns the valid extent of grid coordinates together with the transform
-     * from those grid coordinates to real world coordinates.
+     * Returns the valid extent of grid coordinates together with the conversion from those
grid
+     * coordinates to real world coordinates. A grid geometry contains the following information:
      *
-     * @return grid coordinates valid extent and their mapping to "real world" coordinates.
+     * <ul class="verbose">
+     *   <li>The minimum and maximum grid coordinates as integers (the <cite>Grid
Extent</cite>).
+     *       The minimum coordinates are typically (0,0, …, 0) but not necessarily.</li>
+     *   <li>The minimum and maximum "real world" coordinates (the <cite>Envelope</cite>).
+     *       Those coordinates are typically, but not necessarily, latitudes and longitudes
+     *       or projected coordinates, together with altitudes and dates.</li>
+     *   <li>A description of the datum and axes of above "real world" coordinates
+     *       (the <cite>Coordinate Reference System</cite>).</li>
+     *   <li>The conversion from grid coordinates to "real world" coordinates. This
conversion is often,
+     *       but not necessarily, a linear relationship. Axis order or direction may be changed
by the conversion.
+     *       For example row indices may be increasing toward down while latitude coordinates
are increasing toward up.</li>
+     *   <li>An <em>estimation</em> of grid resolution for each "real world"
axis.</li>
+     * </ul>
+     *
+     * @return extent of grid coordinates together with their mapping to "real world" coordinates.
      * @throws DataStoreException if an error occurred while reading definitions from the
underlying data store.
      */
     GridGeometry getGridGeometry() throws DataStoreException;
+
+    /**
+     * Returns the ranges of sample values together with the conversion from samples to real
values.
+     * Sample dimensions contain the following information:
+     *
+     * <ul class="verbose">
+     *   <li>The range of valid <cite>sample values</cite>, typically but
not necessarily as positive integers.</li>
+     *   <li>A <cite>transfer function</cite> for converting sample values
to real values, for example measurements
+     *       of a geophysics phenomenon. The transfer function is typically defined by a
scale factor and an offset,
+     *       but is not restricted to such linear equations.</li>
+     *   <li>The units of measurement of "real world" values after their conversions
from sample values.</li>
+     *   <li>The sample values reserved for missing values.</li>
+     * </ul>
+     *
+     * @return ranges of sample values together with their mapping to "real values".
+     * @throws DataStoreException if an error occurred while reading definitions from the
underlying data store.
+     */
+    List<SampleDimension> getSampleDimensions() throws DataStoreException;
 }


Mime
View raw message