You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2018/06/18 21:02:30 UTC
[sis] 08/33: Take axis direction in account when computing the
geographic bounding box.
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 7f9281ca60cf77bf13f18d1f582af58587e016f7
Author: Martin Desruisseaux <de...@apache.org>
AuthorDate: Mon May 28 13:44:53 2018 +0000
Take axis direction in account when computing the geographic bounding box.
git-svn-id: https://svn.apache.org/repos/asf/sis/branches/JDK8@1832397 13f79535-47bb-0310-9956-ffa450edef68
---
.../java/org/apache/sis/internal/netcdf/Axis.java | 29 ++++-
.../org/apache/sis/internal/netcdf/Decoder.java | 25 +---
.../sis/internal/netcdf/impl/GridGeometryInfo.java | 2 +-
.../sis/internal/netcdf/impl/package-info.java | 2 +-
.../apache/sis/internal/netcdf/package-info.java | 6 +-
.../sis/internal/netcdf/ucar/package-info.java | 7 +-
.../apache/sis/storage/netcdf/MetadataReader.java | 128 +++++++++++++--------
.../apache/sis/storage/netcdf/package-info.java | 2 +-
.../internal/netcdf/impl/ChannelDecoderTest.java | 3 +-
9 files changed, 118 insertions(+), 86 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 7376e3e..5939443 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
@@ -17,9 +17,12 @@
package org.apache.sis.internal.netcdf;
import java.io.IOException;
-import org.apache.sis.util.ArraysExt;
+import org.opengis.referencing.cs.AxisDirection;
+import org.apache.sis.internal.metadata.AxisDirections;
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;
/**
@@ -29,7 +32,7 @@ import org.apache.sis.storage.DataStoreException;
* {@link ucar.nc2.dataset.CoordinateAxis1D} or {@link ucar.nc2.dataset.CoordinateAxis2D} respectively.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
*
* @see GridGeometry#getAxes()
*
@@ -96,4 +99,26 @@ public final class Axis {
}
}
}
+
+ /**
+ * Returns the axis direction for the given unit of measurement as a sign relative to the given direction.
+ * This method performs the second half of the work of parsing "degrees_east" or "degrees_west" units.
+ *
+ * @param unit the string representation of the netCDF unit, or {@code null}.
+ * @param positive the direction to take as positive value: {@link AxisDirection#EAST} or {@link AxisDirection#NORTH}.
+ * @return the axis direction as a sign relative to the positive direction, or 0 if unrecognized.
+ */
+ public static int direction(final String unit, final AxisDirection positive) {
+ if (unit != null) {
+ final int s = unit.indexOf('_');
+ if (s > 0) {
+ final AxisDirection dir = Types.forCodeName(AxisDirection.class, unit.substring(s+1), false);
+ if (dir != null) {
+ if (dir.equals(positive)) return +1;
+ if (dir.equals(AxisDirections.opposite(positive))) return -1;
+ }
+ }
+ }
+ return 0;
+ }
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
index e596c77..45dd2ae 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
@@ -21,9 +21,6 @@ import java.util.Objects;
import java.util.Collection;
import java.io.Closeable;
import java.io.IOException;
-import javax.measure.Unit;
-import javax.measure.format.ParserException;
-import org.apache.sis.measure.Units;
import org.apache.sis.setup.GeometryLibrary;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStoreException;
@@ -37,7 +34,7 @@ import org.apache.sis.util.logging.WarningListeners;
* Synchronizations are caller's responsibility.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -154,26 +151,6 @@ public abstract class Decoder implements Closeable {
public abstract Date dateValue(final String name);
/**
- * Returns the value of the attribute of the given name as a unit of measurement, or {@code null} if none.
- *
- * @param name the name of the attribute to search, or {@code null}.
- * @return the attribute value, or {@code null} if none or unparsable or if the given name was null.
- *
- * @todo Current Units.valueOf(String) implementation ignore direction in "degrees_east" or "degrees_west".
- * We may need to take that in account (with "degrees_west" to "degrees_east" converter that reverse
- * the sign).
- */
- public final Unit<?> unitValue(final String name) {
- final String unit = stringValue(name);
- if (unit != null) try {
- return Units.valueOf(unit);
- } catch (ParserException e) {
- listeners.warning(null, e);
- }
- return null;
- }
-
- /**
* Converts the given numerical values to date, using the information provided in the given unit symbol.
* The unit symbol is typically a string like <cite>"days since 1970-01-01T00:00:00Z"</cite>.
*
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 23c683e..d221142 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
@@ -178,7 +178,7 @@ final class GridGeometryInfo extends GridGeometry {
*/
@Override
protected double coordinateForAxis(final Object axis, final int j, final int i) throws IOException, DataStoreException {
- final VariableInfo v = ((VariableInfo) axis);
+ final VariableInfo v = (VariableInfo) axis;
final int n = v.dimensions[0].length;
return v.read().doubleValue(j + n*i);
}
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java
index a9e953b..3a34638 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/package-info.java
@@ -29,7 +29,7 @@
*
* @author Johann Sorel (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/package-info.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/package-info.java
index d64d02f..3a164ec 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/package-info.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/package-info.java
@@ -34,11 +34,11 @@
* ISO 19123 <cite>"domain"</cite>, the netCDF coordinate system <cite>"domain"</cite> is closer to
* ISO 19123 <cite>"grid envelope"</cite> and the ISO 19123 <cite>"range"</cite> is rather related
* to the netCDF variable minimum and maximum values. Trying to use OGC/ISO and netCDF objects in
- * the same code appears to be <strong>very</strong> confusing. This isolation layer allows our code
- * to use a more consistent vocabulary (compared to the rest of Apache SIS).</p>
+ * the same code appears to be very confusing. This isolation layer allows our code to use a more
+ * consistent vocabulary (more similar to the rest of Apache SIS).</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/package-info.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/package-info.java
index e419e83..f6e3b2e 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/package-info.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/package-info.java
@@ -20,8 +20,11 @@
* as wrappers around the UCAR netCDF library.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
- * @since 0.3
+ * @version 1.0
+ *
+ * @see <a href="https://www.unidata.ucar.edu/software/thredds/current/netcdf-java/javadoc/index.html">UCAR javadoc</a>
+ *
+ * @since 0.3
* @module
*/
package org.apache.sis.internal.netcdf.ucar;
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 48d59f5..0158a85 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
@@ -45,6 +45,7 @@ import org.opengis.metadata.citation.*;
import org.opengis.metadata.identification.*;
import org.opengis.metadata.maintenance.ScopeCode;
import org.opengis.metadata.constraint.Restriction;
+import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.crs.VerticalCRS;
import org.apache.sis.util.iso.Types;
@@ -281,6 +282,14 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
}
/**
+ * Reads the numeric value for the given value, or returns {@code NaN} if none.
+ */
+ private double numericValue(final String name) {
+ final Number v = decoder.numericValue(name);
+ return (v != null) ? v.doubleValue() : Double.NaN;
+ }
+
+ /**
* Returns the enumeration constant for the given name, or {@code null} if the given name is not recognized.
* In the later case, this method emits a warning.
*/
@@ -711,9 +720,23 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
final AttributeNames.Dimension attributeNames = axis.attributeNames;
if (attributeNames != null) {
setAxisName(dim, attributeNames.DEFAULT_NAME_TYPE);
- final Number value = decoder.numericValue(attributeNames.RESOLUTION);
- if (value != null) {
- setAxisResolution(dim, value.doubleValue());
+ 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;
+ if (s < 0) {
+ value = numericValue(attributeNames.RESOLUTION);
+ } else {
+ value = Double.parseDouble(res.substring(0, s));
+ // TODO: parse units and build a Quantity object.
+ }
+ setAxisResolution(dim, value);
+ } catch (NumberFormatException e) {
+ warning(e);
}
}
}
@@ -728,35 +751,22 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
*/
private boolean addExtent() {
addExtent(stringValue(GEOGRAPHIC_IDENTIFIER));
+ final double[] extent = new double[4];
/*
- * If at least one geographic ordinates is available, add a GeographicBoundingBox.
+ * If at least one geographic coordinate is available, add a GeographicBoundingBox.
*/
- final Number xmin = decoder.numericValue(LONGITUDE.MINIMUM);
- final Number xmax = decoder.numericValue(LONGITUDE.MAXIMUM);
- final Number ymin = decoder.numericValue(LATITUDE .MINIMUM);
- final Number ymax = decoder.numericValue(LATITUDE .MAXIMUM);
- final Number zmin = decoder.numericValue(VERTICAL .MINIMUM);
- final Number zmax = decoder.numericValue(VERTICAL .MAXIMUM);
- boolean hasExtent = (xmin != null || xmax != null || ymin != null || ymax != null);
+ boolean hasExtent;
+ hasExtent = fillExtent(LONGITUDE, Units.DEGREE, AxisDirection.EAST, extent, 0);
+ hasExtent |= fillExtent(LATITUDE, Units.DEGREE, AxisDirection.NORTH, extent, 2);
if (hasExtent) {
- final UnitConverter xConv = getConverterTo(decoder.unitValue(LONGITUDE.UNITS), Units.DEGREE);
- final UnitConverter yConv = getConverterTo(decoder.unitValue(LATITUDE .UNITS), Units.DEGREE);
- addExtent(new double[] {valueOf(xmin, xConv), valueOf(xmax, xConv),
- valueOf(ymin, yConv), valueOf(ymax, yConv)}, 0);
+ addExtent(extent, 0);
+ hasExtent = true;
}
/*
- * If at least one vertical ordinates above is available, add a VerticalExtent.
+ * If at least one vertical coordinate is available, add a VerticalExtent.
*/
- if (zmin != null || zmax != null) {
- final UnitConverter c = getConverterTo(decoder.unitValue(VERTICAL.UNITS), Units.METRE);
- double min = valueOf(zmin, c);
- double max = valueOf(zmax, c);
- if (CF.POSITIVE_DOWN.equals(stringValue(VERTICAL.POSITIVE))) {
- final double tmp = min;
- min = -max;
- max = -tmp;
- }
- addVerticalExtent(min, max, VERTICAL_CRS);
+ if (fillExtent(VERTICAL, Units.METRE, null, extent, 0)) {
+ addVerticalExtent(extent[0], extent[1], VERTICAL_CRS);
hasExtent = true;
}
/*
@@ -778,8 +788,8 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
}
}
/*
- * If at least one time values above is available, add a temporal extent.
- * This operation requires the the sis-temporal module. If not available,
+ * If at least one time value above is available, add a temporal extent.
+ * This operation requires the sis-temporal module. If not available,
* we will report a warning and leave the temporal extent missing.
*/
if (startTime != null || endTime != null) try {
@@ -792,31 +802,49 @@ split: while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
}
/**
- * Returns the converter from the given source unit (which may be {@code null}) to the
- * given target unit, or {@code null} if none or incompatible.
- */
- private UnitConverter getConverterTo(final Unit<?> source, final Unit<?> target) {
- if (source != null) try {
- return source.getConverterToAny(target);
- } catch (IncommensurableException e) {
- warning(e);
- }
- return null;
- }
-
- /**
- * Returns the values of the given number if non-null, or NaN if null. If the given
- * converter is non-null, it is applied.
+ * Fills one dimension of the geographic bounding box or vertical extent.
+ * The extent values are written in the given {@code extent} array.
+ *
+ * @param dim the dimension for which to get the extent.
+ * @param targetUnit the destination unit of the extent.
+ * @param positive the direction considered positive, or {@code null} if the unit symbol is not expected to contain a direction.
+ * @param extent where to store the minimum and maximum values.
+ * @param index index where to store the minimum value in {@code extent}. The maximum value is stored at {@code index+1}.
+ * @return {@code true} if a minimum or a maximum value has been found.
*/
- private static double valueOf(final Number value, final UnitConverter converter) {
- double n = Double.NaN;
- if (value != null) {
- n = value.doubleValue();
- if (converter != null) {
- n = converter.convert(n);
+ private boolean fillExtent(final AttributeNames.Dimension dim, final Unit<?> targetUnit, final AxisDirection positive,
+ final double[] extent, final int index)
+ {
+ double min = numericValue(dim.MINIMUM);
+ double max = numericValue(dim.MAXIMUM);
+ boolean hasExtent = !Double.isNaN(min) || !Double.isNaN(max);
+ if (hasExtent) {
+ final String symbol = stringValue(dim.UNITS);
+ if (symbol != null) {
+ try {
+ final UnitConverter c = Units.valueOf(symbol).getConverterToAny(targetUnit);
+ min = c.convert(min);
+ max = c.convert(max);
+ } catch (ParserException | IncommensurableException e) {
+ warning(e);
+ }
+ boolean reverse = false;
+ if (positive != null) {
+ reverse = Axis.direction(symbol, positive) < 0;
+ } else if (dim.POSITIVE != null) {
+ // For now, only the vertical axis have a "positive" attribute.
+ reverse = CF.POSITIVE_DOWN.equals(stringValue(dim.POSITIVE));
+ }
+ if (reverse) {
+ final double tmp = min;
+ min = -max;
+ max = -tmp;
+ }
}
}
- return n;
+ extent[index ] = min;
+ extent[index+1] = max;
+ return hasExtent;
}
/**
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java
index 1e164c0..fd04b6c 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/package-info.java
@@ -48,7 +48,7 @@
* Care must be taken for avoiding confusion when using SIS and UCAR libraries together.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.3
* @module
*/
diff --git a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
index 8588a92..4e3a61c 100644
--- a/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
+++ b/storage/sis-netcdf/src/test/java/org/apache/sis/internal/netcdf/impl/ChannelDecoderTest.java
@@ -31,8 +31,7 @@ import org.opengis.test.dataset.TestData;
/**
* Tests the {@link ChannelDecoder} implementation. This test shall be executed only if the
- * {@link ChannelDecoder} tests, which use the UCAR library has a reference implementation,
- * passed.
+ * {@link DecoderTest}, which use the UCAR library has a reference implementation, passed.
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.0