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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 2572a48 Linearization should be attempted only when instructed by
conventions for a given netCDF file.
2572a48 is described below
commit 2572a480a1ba3705df24c73c5b3068de9c430485
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sun Mar 31 15:56:42 2019 +0200
Linearization should be attempted only when instructed by conventions for a
given netCDF file.
---
.../operation/builder/ProjectedTransformTry.java | 2 +-
.../org/apache/sis/internal/netcdf/Convention.java | 15 ++++
.../java/org/apache/sis/internal/netcdf/Grid.java | 12 ++-
.../org/apache/sis/internal/netcdf/Linearizer.java | 96 ++++++++++++++--------
4 files changed, 88 insertions(+), 37 deletions(-)
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java
index 50a97e1..ef87a95 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/ProjectedTransformTry.java
@@ -314,7 +314,7 @@ final class ProjectedTransformTry implements
Comparable<ProjectedTransformTry> {
}
/**
- * Order by the inverse of correlation coefficients. Highest coefficients
(best correlations)
+ * Orders by the inverse of correlation coefficients. Highest coefficients
(best correlations)
* are first, lower coefficients are next, {@link Float#NaN} values are
last.
*/
@Override
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 d5f7625..17d8877 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,7 +17,9 @@
package org.apache.sis.internal.netcdf;
import java.util.Map;
+import java.util.Set;
import java.util.Iterator;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.awt.image.DataBuffer;
import org.apache.sis.internal.referencing.LazySet;
@@ -449,4 +451,17 @@ public class Convention {
if (!Double.isNaN(offset)) tr.setOffset(offset);
return tr;
}
+
+ /**
+ * Returns an enumeration of two-dimensional non-linear transforms that
may be tried in attempts to make
+ * localization grid more linear. Default implementation returns an empty
set. If this method is overridden,
+ * the enumerated transforms will be tested in "trials and errors" and the
one resulting in best correlation
+ * coefficients will be selected.
+ *
+ * @param decoder the netCDF file for which to determine linearizers
that may possibly apply.
+ * @return enumeration of two-dimensional non-linear transforms to try.
+ */
+ public Set<Linearizer> linearizers(final Decoder decoder) {
+ return Collections.emptySet();
+ }
}
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
index 5c50d31..bc9c2b3 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Grid.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.internal.netcdf;
+import java.util.Set;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
@@ -397,6 +398,12 @@ findFree: for (int srcDim : axis.sourceDimensions) {
if (nonLinears.get(i) == null) {
for (int j=i; ++j < nonLinears.size();) {
if (nonLinears.get(j) == null) {
+ /*
+ * Found a pair of axes. Prepare an array of
length 2, to be reordered later in the
+ * axis order declared in 'sourceDimensions'. This
is not necessarily the same order
+ * than iteration order because it depends on
values of 'axis.sourceDimensions[0]'.
+ * Those values take in account what is the "main"
dimension of each axis.
+ */
final Axis[] gridAxes = new Axis[] {
axes[deferred[i]],
axes[deferred[j]]
@@ -410,11 +417,14 @@ findFree: for (int srcDim : axis.sourceDimensions) {
}
final LocalizationGridBuilder grid =
gridAxes[0].createLocalizationGrid(gridAxes[1]);
if (grid != null) {
+ final Set<Linearizer> linearizers =
decoder.convention().linearizers(decoder);
+ if (!linearizers.isEmpty()) {
+ Linearizer.applyTo(linearizers, grid,
gridAxes);
+ }
/*
* Replace the first transform by the
two-dimensional localization grid and
* remove the other transform. Removals need
to be done in arrays too.
*/
- Linearizer.applyTo(grid, gridAxes);
nonLinears.set(i, grid.create(factory));
nonLinears.remove(j);
final int n = nonLinears.size() - j;
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
index dcaf27e..d59bf99 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.internal.netcdf;
+import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import org.opengis.util.FactoryException;
@@ -32,13 +33,13 @@ import org.apache.sis.util.logging.Logging;
/**
* Two-dimensional non-linear transforms to try in attempts to make a
localization grid more linear.
- * We use spherical formulas instead than ellipsoidal formulas because the
spherical ones are faster
- * and more stable (the inverse transforms are exact, up to rounding errors).
Non-linear transforms
- * are tested in "trials and errors" and the one resulting in the best
correlation coefficients is
- * selected.
+ * Non-linear transforms are tested in "trials and errors" and the one
resulting in best correlation
+ * coefficients is selected. This enumeration identifies which linearizers to
try for a given file.
*
- * <p>Current implementation provides a hard-coded list of linearized, but
future version may allow
- * customization depending on the netCDF file being decoded.</p>
+ * <p>When a non-linear transform exists in spherical or ellipsoidal variants,
we use the spherical
+ * formulas instead than ellipsoidal formulas because the spherical ones are
faster and more stable
+ * (because the inverse transforms are exact, up to rounding errors). The
errors caused by the use
+ * of spherical formulas are compensated by the localization grid used after
the linearizer.</p>
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.0
@@ -48,29 +49,52 @@ import org.apache.sis.util.logging.Logging;
* @since 1.0
* @module
*/
-final class Linearizer {
+public enum Linearizer {
/**
- * Hard-coded set of transforms that may help in making localization grids
more linear.
- * Operations defined in this map require (<var>longitude</var>,
<var>latitude</var>) axis order.
+ * Mercator (Spherical) projection. Inputs are latitude and longitude in
any order (axis order will
+ * be detected by inspection of {@link Axis} elements). Outputs are
projected coordinates.
*/
- private static final Map<String,MathTransform> PROJECTIONS = new
HashMap<>(4);
- static {
- final MathTransformFactory factory =
DefaultFactories.forClass(MathTransformFactory.class);
- if (factory != null) { // Should never be null, but be tolerant to
configuration oddity.
- final String[] projections = new String[] {
- "Mercator (Spherical)"
- // More projections may be added in the future.
- };
- /*
- * The exact value of sphere radius does not matter because a
linear regression will
- * be applied anyway. However it matter to define a sphere instead
than an ellipsoid
- * because the spherical equations are simpler (consequently
faster and more stable).
- */
- for (final String operation : projections) try {
- final ParameterValueGroup pg =
factory.getDefaultParameters(operation);
+ MERCATOR("Mercator (Spherical)");
+
+ /**
+ * The map projection method to use for constructing {@link #transform},
or {@code null} if the operation
+ * is not a map projection or has already be constructed. If non-null,
the identified operation requires
+ * (<var>longitude</var>, <var>latitude</var>) axis order.
+ */
+ private String projection;
+
+ /**
+ * The transform to apply, or {@code null} if none or not yet created.
This is created by {@link #transform()}
+ * when first needed. The value after initialization may still be {@code
null} if initialization failed.
+ */
+ private MathTransform transform;
+
+ /**
+ * Creates a new linearizer for the given projection method.
+ */
+ private Linearizer(final String projection) {
+ this.projection = projection;
+ }
+
+ /**
+ * Returns the hard-coded transform represented by this enumeration that
may help to make a localization grid
+ * more linear.
+ */
+ private synchronized MathTransform transform() {
+ final String p = projection;
+ if (p != null) {
+ projection = null; // Set to null now
in case of failure.
+ final MathTransformFactory factory =
DefaultFactories.forClass(MathTransformFactory.class);
+ if (factory != null) try { // Should never be null, but be
tolerant to configuration oddity.
+ /*
+ * The exact value of sphere radius does not matter because a
linear regression will
+ * be applied anyway. However it matter to define a sphere
instead than an ellipsoid
+ * because the spherical equations are simpler (consequently
faster and more stable).
+ */
+ final ParameterValueGroup pg = factory.getDefaultParameters(p);
pg.parameter(Constants.SEMI_MAJOR).setValue(ReferencingServices.AUTHALIC_RADIUS);
pg.parameter(Constants.SEMI_MINOR).setValue(ReferencingServices.AUTHALIC_RADIUS);
- PROJECTIONS.put(operation,
factory.createParameterizedTransform(pg));
+ transform = factory.createParameterizedTransform(pg);
} catch (FactoryException e) {
/*
* Should never happen. But if it happens anyway, do not cause
the whole netCDF reader
@@ -80,21 +104,17 @@ final class Linearizer {
Logging.unexpectedException(Logging.getLogger(Modules.NETCDF),
Variable.class, "getGridGeometry", e);
}
}
- }
-
- /**
- * Do not allow instantiation of this class.
- */
- private Linearizer() {
+ return transform;
}
/**
* Applies non-linear transform candidates to the given localization grid.
*
- * @param grid the grid on which to add non-linear transform candidates.
- * @param axes coordinate system axes in CRS order.
+ * @param linearizers the linearizers to apply.
+ * @param grid the grid on which to add non-linear transform
candidates.
+ * @param axes coordinate system axes in CRS order.
*/
- static void applyTo(final LocalizationGridBuilder grid, final Axis[] axes)
{
+ static void applyTo(final Set<Linearizer> linearizers, final
LocalizationGridBuilder grid, final Axis[] axes) {
int xdim = -1, ydim = -1;
for (int i=axes.length; --i >= 0;) {
switch (axes[i].abbreviation) {
@@ -103,7 +123,13 @@ final class Linearizer {
}
}
if (xdim >= 0 && ydim >= 0) {
- grid.addLinearizers(PROJECTIONS, xdim, ydim);
+ final Map<String,MathTransform> projections = new HashMap<>();
+ for (final Linearizer linearizer : linearizers) {
+ if (linearizer.transform != null) {
+ projections.put(linearizer.name(), linearizer.transform());
+ }
+ }
+ grid.addLinearizers(projections, xdim, ydim);
}
}
}