sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 02/02: More work toward the creation of CoordinateReferenceSystem from netCDF variables.
Date Tue, 13 Nov 2018 18:17:08 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 e86bb5693897329c7a52de6711fd85ee5e59509f
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Tue Nov 13 19:16:30 2018 +0100

    More work toward the creation of CoordinateReferenceSystem from netCDF variables.
---
 .../java/org/apache/sis/internal/netcdf/Axis.java  | 40 ++++++-----
 .../apache/sis/internal/netcdf/GridGeometry.java   | 44 ++++++++++--
 .../sis/internal/netcdf/impl/GridGeometryInfo.java | 82 +++++++++++++++-------
 .../internal/netcdf/ucar/GridGeometryWrapper.java  | 12 ++--
 .../apache/sis/storage/netcdf/MetadataReader.java  | 57 ++++++++-------
 .../sis/internal/netcdf/GridGeometryTest.java      | 13 ++--
 6 files changed, 159 insertions(+), 89 deletions(-)

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 69ff891..bc6a54a 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
@@ -30,7 +30,6 @@ import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.apache.sis.internal.metadata.AxisDirections;
 import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.storage.netcdf.AttributeNames;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.ArraysExt;
@@ -54,7 +53,10 @@ import ucar.nc2.constants.CF;
  */
 public final class Axis extends NamedElement {
     /**
-     * The abbreviation, also used as a way to identify the axis type. Possible values are:
+     * The abbreviation, also used as a way to identify the axis type.
+     * This is a controlled vocabulary: if any abbreviation is changed,
+     * then we need to search for all usages in the code and update it.
+     * Possible values are:
      * <ul>
      *   <li>λ for longitude</li>
      *   <li>φ for latitude</li>
@@ -73,7 +75,7 @@ public final class Axis extends NamedElement {
      *
      * @see AxisDirections#fromAbbreviation(char)
      */
-    private final char abbreviation;
+    public final char abbreviation;
 
     /**
      * The axis direction, or {@code null} if unknown.
@@ -81,13 +83,6 @@ public final class Axis extends NamedElement {
     private final AxisDirection direction;
 
     /**
-     * The attributes to use for fetching dimension (in ISO 19115 sense) information, or
{@code null} if unknown.
-     * Example: {@code "geospatial_lat_min"}, {@code "geospatial_lat_resolution"}, {@code
DimensionNameType.ROW}.
-     * This is used by {@link org.apache.sis.storage.netcdf.MetadataReader} for information
purpose only.
-     */
-    public final AttributeNames.Dimension attributeNames;
-
-    /**
      * The indices of the grid dimension associated to this axis. The length of this array
is often 1.
      * But if more than one grid dimension is associated to this axis (i.e. if the wrapped
netCDF axis
      * is an instance of {@link ucar.nc2.dataset.CoordinateAxis2D}),  then the first value
is the grid
@@ -119,7 +114,6 @@ public final class Axis extends NamedElement {
      *
      * @param  owner             provides callback for the conversion from grid coordinates
to geodetic coordinates.
      * @param  axis              an implementation-dependent object representing the axis.
-     * @param  attributeNames    the attributes to use for fetching dimension information,
or {@code null} if unknown.
      * @param  abbreviation      axis abbreviation, also identifying its type. This is a
controlled vocabulary.
      * @param  direction         direction of positive values ("up" or "down"), or {@code
null} if unknown.
      * @param  sourceDimensions  the index of the grid dimension associated to this axis.
@@ -128,9 +122,8 @@ public final class Axis extends NamedElement {
      * @throws DataStoreException if a logical error occurred.
      * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE},
or other overflow occurs.
      */
-    public Axis(final GridGeometry owner, final Variable axis, final AttributeNames.Dimension
attributeNames,
-                char abbreviation, final String direction, final int[] sourceDimensions,
final int[] sourceSizes)
-                throws IOException, DataStoreException
+    public Axis(final GridGeometry owner, final Variable axis, char abbreviation, final String
direction,
+                final int[] sourceDimensions, final int[] sourceSizes) throws IOException,
DataStoreException
     {
         /*
          * Try to get the axis direction from one of the following sources,
@@ -174,7 +167,6 @@ public final class Axis extends NamedElement {
         }
         this.direction        = dir;
         this.abbreviation     = abbreviation;
-        this.attributeNames   = attributeNames;
         this.sourceDimensions = sourceDimensions;
         this.sourceSizes      = sourceSizes;
         this.coordinates      = axis;
@@ -226,11 +218,27 @@ public final class Axis extends NamedElement {
     }
 
     /**
+     * Creates ISO 19111 axes from the information stored in given netCDF axes.
+     *
+     * @param  axes     the axes to convert to ISO data structure.
+     * @param  factory  the factory to use for creating the coordinate system axis.
+     * @return the ISO axes.
+     */
+    static CoordinateSystemAxis[] toISO(final List<Axis> axes, final CSFactory factory)
throws FactoryException {
+        final CoordinateSystemAxis[] iso = new CoordinateSystemAxis[axes.size()];
+        for (int i=0; i<iso.length; i++) {
+            iso[i] = axes.get(i).toISO(factory);
+        }
+        return iso;
+    }
+
+    /**
      * Creates an ISO 19111 axis from the information stored in this netCDF axis.
      *
      * @param  factory  the factory to use for creating the coordinate system axis.
+     * @return the ISO axis.
      */
-    final CoordinateSystemAxis toISO(final CSFactory factory) throws FactoryException {
+    private CoordinateSystemAxis toISO(final CSFactory factory) throws FactoryException {
         /*
          * The axis name is stored without namespace, because the variable name in a netCDF
file can be anything;
          * this is not controlled vocabulary. However the standard name, if any, is stored
with "NetCDF" namespace
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridGeometry.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridGeometry.java
index 9a8dc7c..61a7d25 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridGeometry.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridGeometry.java
@@ -18,11 +18,15 @@ package org.apache.sis.internal.netcdf;
 
 import java.util.Map;
 import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
 import java.io.IOException;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.cs.CSFactory;
+import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.crs.CRSFactory;
 import org.apache.sis.storage.DataStoreException;
 
 
@@ -115,14 +119,42 @@ public abstract class GridGeometry extends NamedElement {
      */
     protected abstract double coordinateForAxis(Variable axis, int j, int i) throws IOException,
DataStoreException;
 
-    final CoordinateSystem createCoordinateSystem(final CSFactory factory) throws IOException,
DataStoreException, FactoryException {
-        final Axis[] axes = getAxes();
-        final CoordinateSystemAxis[] csAxes = new CoordinateSystemAxis[axes.length];
-        for (int i=0; i<axes.length; i++) {
-            csAxes[i] = axes[i].toISO(factory);
+    /**
+     * Creates the coordinate reference system.
+     *
+     * @param  csFactory   the factory to use for creating coordinate systems.
+     * @param  crsFactory  the factory to use for creating coordinate reference systems.
+     */
+    final void createCRS(final CSFactory csFactory, final CRSFactory crsFactory)
+            throws IOException, DataStoreException, FactoryException
+    {
+        final List<Axis> spherical   = new ArrayList<>();       // Spherical
latitude, longitude and radius.
+        final List<Axis> ellipsoidal = new ArrayList<>();       // Geodetic latitude
and longitude.
+        final List<Axis> projected   = new ArrayList<>();       // Easting and
northing.
+        final List<Axis> compound    = new ArrayList<>();       // Geoidal height
and/or time.
+        final List<Axis> engineering = new ArrayList<>();       // Everything
else.
+        for (final Axis axis : getAxes()) {
+            final List<Axis> addTo;
+            switch (axis.abbreviation) {
+                case 'E': case 'N':            addTo = projected;   break;
+                case 'λ': case 'φ':            addTo = ellipsoidal; break;
+                case 'θ': case 'Ω': case 'r':  addTo = spherical;   break;
+                case 'H': case 'D': case 't':  addTo = compound;    break;
+                case 'h': projected.add(axis); addTo = ellipsoidal; break;  // Can be ellipsoidal
or projected.
+                default:                       addTo = engineering; break;
+            }
+            addTo.add(axis);
         }
         final Map<String,Object> properties = new HashMap<>(4);
         properties.put(CoordinateSystem.NAME_KEY, getName());
-        return factory.createEllipsoidalCS(null, csAxes[0], csAxes[1]);
+        if (!ellipsoidal.isEmpty()) {
+            final CoordinateSystemAxis[] axes = Axis.toISO(ellipsoidal, csFactory);
+            final EllipsoidalCS cs;
+            switch (axes.length) {
+                case 2: cs = csFactory.createEllipsoidalCS(properties, axes[0], axes[1]);
         break;
+                case 3: cs = csFactory.createEllipsoidalCS(properties, axes[0], axes[1],
axes[2]); break;
+                default: // TODO
+            }
+        }
     }
 }
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridGeometryInfo.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridGeometryInfo.java
index 100f8cd..dc16c70 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridGeometryInfo.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/GridGeometryInfo.java
@@ -17,6 +17,9 @@
 package org.apache.sis.internal.netcdf.impl;
 
 import java.io.IOException;
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
 import java.util.TreeMap;
 import java.util.SortedMap;
 import org.apache.sis.util.ArraysExt;
@@ -25,7 +28,6 @@ import org.apache.sis.internal.netcdf.Variable;
 import org.apache.sis.internal.netcdf.GridGeometry;
 import org.apache.sis.internal.netcdf.Resources;
 import org.apache.sis.storage.DataStoreContentException;
-import org.apache.sis.storage.netcdf.AttributeNames;
 import org.apache.sis.storage.DataStoreException;
 import ucar.nc2.constants.CF;
 
@@ -43,17 +45,32 @@ import ucar.nc2.constants.CF;
  */
 final class GridGeometryInfo extends GridGeometry {
     /**
-     * Mapping from values of the {@code "_CoordinateAxisType"} attribute to the
-     * {@code AttributeNames.Dimension} constant.
+     * Mapping from values of the {@code "_CoordinateAxisType"} attribute or axis name to
the abbreviation.
+     * Keys are lower cases and values are controlled vocabulary documented in {@link Axis#abbreviation}.
+     *
+     * @see #getAxisType(String)
+     */
+    private static final Map<String,Character> AXIS_TYPES = new HashMap<>(26);
+    static {
+        addAxisTypes('λ', "longitude", "lon", "long");
+        addAxisTypes('φ', "latitude",  "lat");
+        addAxisTypes('H', "pressure", "height", "altitude", "elevation", "elev");
+        addAxisTypes('D', "depth");
+        addAxisTypes('t', "t", "time", "runtime");
+        addAxisTypes('x', "x", "geox");
+        addAxisTypes('y', "y", "geoy");
+        addAxisTypes('z', "z", "geoz");
+    }
+
+    /**
+     * Adds a sequence of axis types or variable names for the given abbreviation.
      */
-    private static final Object[] AXIS_TYPES = {
-        "Lon",      AttributeNames.LONGITUDE,
-        "Lat",      AttributeNames.LATITUDE,
-        "Pressure", AttributeNames.VERTICAL,
-        "Height",   AttributeNames.VERTICAL,
-        "RunTime",  AttributeNames.TIME,
-        "Time",     AttributeNames.TIME
-    };
+    private static void addAxisTypes(final char abbreviation, final String... names) {
+        final Character c = abbreviation;
+        for (final String name : names) {
+            AXIS_TYPES.put(name, c);
+        }
+    }
 
     /**
      * Describes the input values expected by the function converting grid indices to geodetic
coordinates.
@@ -94,7 +111,29 @@ final class GridGeometryInfo extends GridGeometry {
      */
     @Override
     public String getName() {
-        return getFilename();
+        final StringBuilder buffer = new StringBuilder();
+        for (final VariableInfo variable : range) {
+            if (buffer.length() != 0) {
+                buffer.append(' ');
+            }
+            buffer.append(variable.getName());
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Returns the axis type for an axis of the given name, or 0 if unknown.
+     * If non-zero, then the returned code is one of the controlled vocabulary
+     * documented in {@link Axis#abbreviation}.
+     */
+    private static char getAxisType(final String name) {
+        if (name != null) {
+            final Character abbreviation = AXIS_TYPES.get(name.toLowerCase(Locale.US));
+            if (abbreviation != null) {
+                return abbreviation;
+            }
+        }
+        return 0;
     }
 
     /**
@@ -156,19 +195,9 @@ final class GridGeometryInfo extends GridGeometry {
         for (final SortedMap.Entry<VariableInfo,Integer> entry : variables.entrySet())
{
             final int targetDim = entry.getValue();
             final VariableInfo axis = entry.getKey();
-            /*
-             * The AttributeNames are for ISO 19115 metadata. They are not used for locating
grid cells
-             * on Earth, but we nevertheless get them now for making MetadataReader work
easier.
-             */
-            AttributeNames.Dimension attributeNames = null;
-            final String type = axis.getAxisType();
-            if (type != null) {
-                for (int i=0; i<AXIS_TYPES.length; i+=2) {
-                    if (type.equalsIgnoreCase((String) AXIS_TYPES[i])) {
-                        attributeNames = (AttributeNames.Dimension) AXIS_TYPES[i+1];
-                        break;
-                    }
-                }
+            char abbreviation = getAxisType(axis.getAxisType());
+            if (abbreviation == 0) {
+                abbreviation = getAxisType(axis.getName());
             }
             /*
              * Get the grid dimensions (part of the "domain" in UCAR terminology) used for
computing
@@ -188,8 +217,7 @@ final class GridGeometryInfo extends GridGeometry {
                     }
                 }
             }
-            char abbreviation = 0;
-            axes[targetDim] = new Axis(this, axis, attributeNames, abbreviation, axis.getAttributeString(CF.POSITIVE),
+            axes[targetDim] = new Axis(this, axis, abbreviation, axis.getAttributeString(CF.POSITIVE),
                                        ArraysExt.resize(indices, i), ArraysExt.resize(sizes,
i));
         }
         return axes;
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridGeometryWrapper.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridGeometryWrapper.java
index 9087dd3..9d80ce8 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridGeometryWrapper.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/GridGeometryWrapper.java
@@ -26,7 +26,6 @@ import ucar.nc2.dataset.CoordinateSystem;
 import org.apache.sis.internal.netcdf.Axis;
 import org.apache.sis.internal.netcdf.Variable;
 import org.apache.sis.internal.netcdf.GridGeometry;
-import org.apache.sis.storage.netcdf.AttributeNames;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.ArraysExt;
 import ucar.nc2.VariableIF;
@@ -127,18 +126,17 @@ final class GridGeometryWrapper extends GridGeometry {
              * on Earth, but we nevertheless get them now for making MetadataReader work
easier.
              */
             char abbreviation = 0;
-            AttributeNames.Dimension attributeNames = null;
             final AxisType type = axis.getAxisType();
             if (type != null) switch (type) {
                 case GeoX:            abbreviation = 'x'; break;
                 case GeoY:            abbreviation = 'y'; break;
                 case GeoZ:            abbreviation = 'z'; break;
-                case Lon:             abbreviation = 'λ'; attributeNames = AttributeNames.LONGITUDE;
break;
-                case Lat:             abbreviation = 'φ'; attributeNames = AttributeNames.LATITUDE;
break;
+                case Lon:             abbreviation = 'λ'; break;
+                case Lat:             abbreviation = 'φ'; break;
                 case Pressure:        // Fallthrough: consider as Height
-                case Height:          abbreviation = 'H'; attributeNames = AttributeNames.VERTICAL;
break;
+                case Height:          abbreviation = 'H'; break;
                 case RunTime:         // Fallthrough: consider as Time
-                case Time:            abbreviation = 't'; attributeNames = AttributeNames.TIME;
break;
+                case Time:            abbreviation = 't'; break;
                 case RadialAzimuth:   abbreviation = 'θ'; break;    // Spherical longitude
                 case RadialElevation: abbreviation = 'Ω'; break;    // Spherical latitude
                 case RadialDistance:  abbreviation = 'r'; break;    // Geocentric radius
@@ -164,7 +162,7 @@ final class GridGeometryWrapper extends GridGeometry {
                  * package, we can proceed as if the dimension does not exist ('i' not incremented).
                  */
             }
-            axes[targetDim] = new Axis(this, decoder.getWrapperFor(axis), attributeNames,
abbreviation,
+            axes[targetDim] = new Axis(this, decoder.getWrapperFor(axis), abbreviation,
                     axis.getPositive(), ArraysExt.resize(indices, i), ArraysExt.resize(sizes,
i));
         }
         return axes;
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 f673325..e56ff50 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
@@ -715,34 +715,39 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value,
start, lengt
             if (axis.sourceSizes.length >= 1) {
                 setAxisLength(dim, axis.sourceSizes[0]);
             }
-            final AttributeNames.Dimension attributeNames = axis.attributeNames;
-            if (attributeNames != null) {
-                final DimensionNameType name = attributeNames.DEFAULT_NAME_TYPE;
-                setAxisName(dim, name);
-                final String res = stringValue(attributeNames.RESOLUTION);
-                if (res != null) try {
-                    /*
-                     * ACDD convention recommends to write units after the resolution.
-                     * Examples: "100 meters", "0.1 degree".
-                     */
-                    final int s = res.indexOf(' ');
-                    final double value;
-                    Unit<?> units = null;
-                    if (s < 0) {
-                        value = numericValue(attributeNames.RESOLUTION);
-                    } else {
-                        value = Double.parseDouble(res.substring(0, s).trim());
-                        final String symbol = res.substring(s+1).trim();
-                        if (!symbol.isEmpty()) try {
-                            units = Units.valueOf(symbol);
-                        } catch (ParserException e) {
-                            warning(Errors.Keys.CanNotAssignUnitToDimension_2, name, units,
e);
-                        }
+            final AttributeNames.Dimension attributeNames;
+            switch (axis.abbreviation) {
+                case 'λ': case 'θ':           attributeNames = AttributeNames.LONGITUDE;
break;
+                case 'φ': case 'Ω':           attributeNames = AttributeNames.LATITUDE;
 break;
+                case 'h': case 'H': case 'D': attributeNames = AttributeNames.VERTICAL; 
break;
+                case 't': case 'T':           attributeNames = AttributeNames.TIME;     
break;
+                default : continue;
+            }
+            final DimensionNameType name = attributeNames.DEFAULT_NAME_TYPE;
+            setAxisName(dim, name);
+            final String res = stringValue(attributeNames.RESOLUTION);
+            if (res != null) try {
+                /*
+                 * ACDD convention recommends to write units after the resolution.
+                 * Examples: "100 meters", "0.1 degree".
+                 */
+                final int s = res.indexOf(' ');
+                final double value;
+                Unit<?> units = null;
+                if (s < 0) {
+                    value = numericValue(attributeNames.RESOLUTION);
+                } else {
+                    value = Double.parseDouble(res.substring(0, s).trim());
+                    final String symbol = res.substring(s+1).trim();
+                    if (!symbol.isEmpty()) try {
+                        units = Units.valueOf(symbol);
+                    } catch (ParserException e) {
+                        warning(Errors.Keys.CanNotAssignUnitToDimension_2, name, units, e);
                     }
-                    setAxisResolution(dim, value, units);
-                } catch (NumberFormatException e) {
-                    warning(e);
                 }
+                setAxisResolution(dim, value, units);
+            } catch (NumberFormatException e) {
+                warning(e);
             }
         }
         setCellGeometry(CellGeometry.AREA);
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridGeometryTest.java
b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridGeometryTest.java
index dcf0efe..674e69b 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridGeometryTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/GridGeometryTest.java
@@ -18,7 +18,6 @@ package org.apache.sis.internal.netcdf;
 
 import java.io.IOException;
 import org.apache.sis.storage.DataStoreException;
-import org.apache.sis.storage.netcdf.AttributeNames;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.DependsOnMethod;
 import org.opengis.test.dataset.TestData;
@@ -85,8 +84,8 @@ public strictfp class GridGeometryTest extends TestCase {
         final Axis x = axes[1];
         final Axis y = axes[0];
 
-        assertSame(AttributeNames.LONGITUDE, x.attributeNames);
-        assertSame(AttributeNames.LATITUDE,  y.attributeNames);
+        assertEquals('λ', x.abbreviation);
+        assertEquals('φ', y.abbreviation);
 
         assertArrayEquals(new int[] {1}, x.sourceDimensions);
         assertArrayEquals(new int[] {0}, y.sourceDimensions);
@@ -111,10 +110,10 @@ public strictfp class GridGeometryTest extends TestCase {
         final Axis z = axes[1];
         final Axis t = axes[0];
 
-        assertNull("Not geographic",        x.attributeNames);
-        assertNull("Not geographic",        y.attributeNames);
-        assertSame(AttributeNames.VERTICAL, z.attributeNames);
-        assertSame(AttributeNames.TIME,     t.attributeNames);
+        assertEquals('x', x.abbreviation);
+        assertEquals('y', y.abbreviation);
+        assertEquals('H', z.abbreviation);
+        assertEquals('t', t.abbreviation);
 
         assertArrayEquals(new int[] {3}, x.sourceDimensions);
         assertArrayEquals(new int[] {2}, y.sourceDimensions);


Mime
View raw message