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);
         }
     }
 }

Reply via email to