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 670d050  Decoding of two-dimensional localization grid from netCDF 
file check if the grid stands for a Mercator projection.
670d050 is described below

commit 670d0504ed7428d931ee322b195adb67cd287598
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Mar 29 16:35:37 2019 +0100

    Decoding of two-dimensional localization grid from netCDF file check if the 
grid stands for a Mercator projection.
---
 .../operation/builder/LinearTransformBuilder.java  |  45 +++++----
 .../operation/builder/ProjectedTransformTry.java   |  54 +++++-----
 .../java/org/apache/sis/internal/netcdf/Axis.java  |   5 +
 .../java/org/apache/sis/internal/netcdf/Grid.java  |  16 +--
 .../org/apache/sis/internal/netcdf/Linearizer.java | 109 +++++++++++++++++++++
 5 files changed, 181 insertions(+), 48 deletions(-)

diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
index df447ae..b36d2ef 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
@@ -416,7 +416,10 @@ search: for (int j=numPoints; --j >= 0;) {
     }
 
     /**
-     * Returns the number of dimensions in source positions.
+     * Returns the number of dimensions in source positions. This is the 
length of the {@code source} array given in argument
+     * to {@link #getControlPoint(int[]) get}/{@link #setControlPoint(int[], 
double[]) setControlPoint(int[], …)} methods.
+     * This is also the number of dimensions of the {@link DirectPosition} 
<em>keys</em> in the {@link Map} exchanged by
+     * {@link #getControlPoints() get}/{@link #setControlPoints(Map)} methods.
      *
      * @return the dimension of source points.
      * @throws IllegalStateException if the number of source dimensions is not 
yet known.
@@ -432,7 +435,10 @@ search: for (int j=numPoints; --j >= 0;) {
     }
 
     /**
-     * Returns the number of dimensions in target positions.
+     * Returns the number of dimensions in target positions. This is the 
length of the {@code target} array exchanged by
+     * {@link #getControlPoint(int[]) get}/{@link #setControlPoint(int[], 
double[]) setControlPoint(…, double[])} methods.
+     * This is also the number of dimensions of the {@link DirectPosition} 
<em>values</em> in the {@link Map} exchanged by
+     * {@link #getControlPoints() get}/{@link #setControlPoints(Map)} methods.
      *
      * @return the dimension of target points.
      * @throws IllegalStateException if the number of target dimensions is not 
yet known.
@@ -447,7 +453,9 @@ search: for (int j=numPoints; --j >= 0;) {
     }
 
     /**
-     * Returns the envelope of source points. This method returns the known 
minimum and maximum values for each dimension,
+     * Returns the envelope of source points (<em>keys</em> of the map 
returned by {@link #getControlPoints()}).
+     * The number of dimensions is equal to {@link #getSourceDimensions()}.
+     * This method returns the known minimum and maximum values (inclusive) 
for each dimension,
      * <strong>not</strong> expanded to encompass full cell surfaces. In other 
words, the returned envelope encompasses only
      * {@linkplain org.opengis.referencing.datum.PixelInCell#CELL_CENTER cell 
centers}.
      *
@@ -475,7 +483,8 @@ search: for (int j=numPoints; --j >= 0;) {
     }
 
     /**
-     * Returns the envelope of target points. The lower and upper values are 
inclusive.
+     * Returns the envelope of target points (<em>values</em> of the map 
returned by {@link #getControlPoints()}).
+     * The number of dimensions is equal to {@link #getTargetDimensions()}. 
The lower and upper values are inclusive.
      * If a {@linkplain #linearizer() linearizer has been applied}, then 
coordinates of
      * the returned envelope are projected by that linearizer.
      *
@@ -1120,18 +1129,20 @@ search:         for (int j=domain(); --j >= 0;) {
      * method will try to apply each transform on target coordinates and check 
which one results in the best
      * {@linkplain #correlation() correlation} coefficients. It may be none.
      *
-     * <p>The linearizers are specified as {@link MathTransform}s from current 
target coordinates to other spaces
-     * where <cite>sources to new targets</cite> transforms may be more linear.
+     * <p>The linearizers are specified as {@link MathTransform}s from current 
{@linkplain #getTargetEnvelope()
+     * target coordinates} to other spaces where <cite>sources to new 
targets</cite> transforms may be more linear.
      * Keys in the map are arbitrary identifiers used in {@link #toString()} 
for debugging purpose.
-     * Values in the map are non-{@link LinearTransform} (linear transforms 
are not forbidden, but are useless for this process).
-     * The {@code dimensions} argument specifies which target dimensions to 
project and can be null or omitted
-     * if the projections shall be applied on all target coordinates. It is 
possible to invoke this method many
-     * times with different {@code dimensions} argument values.</p>
+     * Values in the map are non-{@link LinearTransform}s (linear transforms 
are not forbidden, but are useless for this process).</p>
+     *
+     * <p>The {@code projToGrid} argument maps {@code projections} dimensions 
to this builder target dimensions.
+     * For example if {@code projToGrid} array is {@code {2,1}}, then 
dimensions 0 and 1 of given {@code projections}
+     * (both source and target dimensions) will map to dimensions 2 and 1 of 
this builder target dimensions, respectively.
+     * The {@code projToGrid} argument can be omitted or null, in which {0, 1, 
2 … {@link #getTargetDimensions()} - 1} is assumed.
+     * All given {@code projections} shall have a number of source and target 
dimensions equals to the length of the given or assumed
+     * {@code projToGrid} array. It is possible to invoke this method many 
times with different {@code projToGrid} argument values.</p>
      *
      * @param  projections  projections from current target coordinates to 
other spaces which may result in more linear transforms.
-     * @param  dimensions   the target dimensions to project, or null or 
omitted for projecting all target dimensions.
-     *                      If non-null and non-empty, then all transforms in 
the {@code projections} map shall have a
-     *                      number of source and target dimensions equals to 
the length of this array.
+     * @param  projToGrid   the target dimensions to project, or null or 
omitted for projecting all target dimensions.
      * @throws IllegalStateException if {@link #create(MathTransformFactory) 
create(…)} has already been invoked.
      *
      * @see #linearizer()
@@ -1139,17 +1150,17 @@ search:         for (int j=domain(); --j >= 0;) {
      *
      * @since 1.0
      */
-    public void addLinearizers(final Map<String,MathTransform> projections, 
int... dimensions) {
+    public void addLinearizers(final Map<String,MathTransform> projections, 
int... projToGrid) {
         ensureModifiable();
         final int tgtDim = getTargetDimensions();
-        if (dimensions == null || dimensions.length == 0) {
-            dimensions = ArraysExt.range(0, tgtDim);
+        if (projToGrid == null || projToGrid.length == 0) {
+            projToGrid = ArraysExt.range(0, tgtDim);
         }
         if (linearizers == null) {
             linearizers = new ArrayList<>();
         }
         for (final Map.Entry<String,MathTransform> entry : 
projections.entrySet()) {
-            linearizers.add(new ProjectedTransformTry(entry.getKey(), 
entry.getValue(), dimensions, tgtDim));
+            linearizers.add(new ProjectedTransformTry(entry.getKey(), 
entry.getValue(), projToGrid, tgtDim));
         }
     }
 
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 4be4ecd..abeafcb 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
@@ -83,11 +83,11 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
 
     /**
      * Maps {@link #projection} dimensions to {@link LinearTransformBuilder} 
target dimensions.
-     * For example if this array is {@code {2,1}}, then dimensions 0 and 1 of 
{@code projection}
-     * map dimensions 2 and 1 of {@link LinearTransformBuilder#targets} 
respectively. The length
-     * of this array shall be equal to the number of {@link #projection} 
source dimensions.
+     * For example if this array is {@code {2,1}}, then dimensions 0 and 1 of 
{@link #projection}
+     * (both source and target dimensions) will map dimensions 2 and 1 of 
{@link LinearTransformBuilder#targets}, respectively.
+     * The length of this array shall be equal to the number of {@link 
#projection} source dimensions.
      */
-    private final int[] dimensions;
+    private final int[] projToGrid;
 
     /**
      * A global correlation factor, stored for information purpose only.
@@ -105,7 +105,7 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
     ProjectedTransformTry(final ProjectedTransformTry other) {
         name       = other.name;
         projection = other.projection;
-        dimensions = other.dimensions;
+        projToGrid = other.projToGrid;
     }
 
     /**
@@ -114,7 +114,7 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
      */
     ProjectedTransformTry(final float corr) {
         projection  = null;
-        dimensions  = null;
+        projToGrid  = null;
         correlation = corr;
     }
 
@@ -124,19 +124,19 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
      *
      * @param name               a name by witch this projection attempt is 
identified, or {@code null}.
      * @param projection         conversion from non-linear grid to something 
that may be more linear.
-     * @param dimensions         maps {@code projection} dimensions to {@link 
LinearTransformBuilder} target dimensions.
+     * @param projToGrid         maps {@code projection} dimensions to {@link 
LinearTransformBuilder} target dimensions.
      * @param expectedDimension  number of {@link LinearTransformBuilder} 
target dimensions.
      */
-    ProjectedTransformTry(final String name, final MathTransform projection, 
final int[] dimensions, int expectedDimension) {
+    ProjectedTransformTry(final String name, final MathTransform projection, 
final int[] projToGrid, int expectedDimension) {
         ArgumentChecks.ensureNonNull("name", name);
         ArgumentChecks.ensureNonNull("projection", projection);
         this.name       = name;
         this.projection = projection;
-        this.dimensions = dimensions;
+        this.projToGrid = projToGrid;
         int side = 0;                           // 0 = problem with source 
dimensions, 1 = problem with target dimensions.
         int actual = projection.getSourceDimensions();
         if (actual <= expectedDimension) {
-            expectedDimension = dimensions.length;
+            expectedDimension = projToGrid.length;
             if (actual == expectedDimension) {
                 actual = projection.getTargetDimensions();
                 if (actual == expectedDimension) {
@@ -158,19 +158,19 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
     }
 
     /**
-     * Returns the projection, taking in account axis swapping if {@link 
#dimensions} is not an arithmetic progression.
+     * Returns the projection, taking in account axis swapping if {@link 
#projToGrid} is not an arithmetic progression.
      */
     final MathTransform projection() {
-        MathTransform mt = 
MathTransforms.linear(Matrices.createDimensionSelect(dimensions.length, 
dimensions));
+        MathTransform mt = 
MathTransforms.linear(Matrices.createDimensionSelect(projToGrid.length, 
projToGrid));
         return MathTransforms.concatenate(mt, projection);
     }
 
     /**
      * Transforms target coordinates of a localization grid. The {@code 
coordinates} argument is the value
      * of {@link LinearTransformBuilder#targets}, without clone (this method 
will only read those arrays).
-     * Only arrays at indices given by {@link #dimensions} will be read; the 
other arrays will be ignored.
+     * Only arrays at indices given by {@link #projToGrid} will be read; the 
other arrays will be ignored.
      * The coordinate operation result will be stored in arrays of size {@code 
[numDimensions][numPoints]}
-     * where {@code numDimensions} is the length of the {@link #dimensions} 
array. Indices are as below,
+     * where {@code numDimensions} is the length of the {@link #projToGrid} 
array. Indices are as below,
      * with 0 ≦ <var>d</var> ≦ {@code numDimensions}:
      *
      * <ol>
@@ -187,7 +187,7 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
      * @return results of coordinate operations (see method javadoc), or 
{@code null} if an error occurred.
      */
     final double[][] transform(final double[][] coordinates, final int 
numPoints, final Queue<double[]> pool) {
-        final int numDimensions = dimensions.length;
+        final int numDimensions = projToGrid.length;
         final double[][] results = new double[numDimensions][];
         for (int i=0; i<numDimensions; i++) {
             if ((results[i] = pool.poll()) == null) {
@@ -201,7 +201,7 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
          */
         try {
             if (numDimensions == 1) {
-                projection.transform(coordinates[dimensions[0]], 0, 
results[0], 0, numPoints);
+                projection.transform(coordinates[projToGrid[0]], 0, 
results[0], 0, numPoints);
             } else {
                 final int bufferCapacity = Math.min(numPoints, 
BUFFER_CAPACITY);                 // In number of points.
                 final double[] buffer = new double[bufferCapacity * 
numDimensions];
@@ -214,7 +214,7 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
                      * Coordinates start at index 0 and the number of valid 
points is stop - start.
                      */
                     for (int d=0; d<numDimensions; d++) {
-                        final double[] data = coordinates[dimensions[d]];
+                        final double[] data = coordinates[projToGrid[d]];
                         dataOffset = start;
                         int dst = d;
                         do {
@@ -223,7 +223,8 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
                         } while (++dataOffset < stop);
                     }
                     /*
-                     * Transform coordinates and save the result.
+                     * Transform coordinates and save the result. If any 
coordinate result is NaN,
+                     * we can not use that projection (LinearTransformBuilder 
requires all points).
                      */
                     projection.transform(buffer, 0, buffer, 0, stop - start);
                     for (int d=0; d<numDimensions; d++) {
@@ -232,7 +233,10 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
                         dataOffset = start;
                         int dst = d;
                         do {
-                            data[dataOffset] = buffer[dst];
+                            if (Double.isNaN(data[dataOffset] = buffer[dst])) {
+                                recycle(results, pool);         // Make arrays 
available for other transforms.
+                                return null;
+                            }
                             dst += numDimensions;
                         } while (++dataOffset < stop);
                     }
@@ -264,12 +268,12 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
      * @return a copy of the given {@code correlation} array with new values 
overwriting the old values.
      */
     final double[] replace(double[] correlations, final double[] newValues) {
-        if (newValues.length == correlations.length && ArraysExt.isRange(0, 
dimensions)) {
+        if (newValues.length == correlations.length && ArraysExt.isRange(0, 
projToGrid)) {
             return newValues;
         }
         correlations = correlations.clone();
-        for (int j=0; j<dimensions.length; j++) {
-            correlations[dimensions[j]] = newValues[j];
+        for (int j=0; j<projToGrid.length; j++) {
+            correlations[projToGrid[j]] = newValues[j];
         }
         return correlations;
     }
@@ -289,12 +293,12 @@ final class ProjectedTransformTry implements 
Comparable<ProjectedTransformTry> {
          * have a different number of rows since the number of target 
dimensions may differ.
          */
         assert newValues.getNumCol() == transform.getNumCol();
-        if (newValues.getNumRow() == transform.getNumRow() && 
ArraysExt.isRange(0, dimensions)) {
+        if (newValues.getNumRow() == transform.getNumRow() && 
ArraysExt.isRange(0, projToGrid)) {
             return newValues;
         }
         transform = transform.clone();
-        for (int j=0; j<dimensions.length; j++) {
-            final int d = dimensions[j];
+        for (int j=0; j<projToGrid.length; j++) {
+            final int d = projToGrid[j];
             for (int i=transform.getNumRow(); --i >= 0;) {
                 transform.setNumber(d, i, newValues.getNumber(j, i));
             }
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 094f194..f034fa4 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
@@ -634,6 +634,11 @@ main:   switch (getDimension()) {
      * This method is invoked as a fallback when {@link 
#trySetTransform(Matrix, int, int, List)}
      * could not set coefficients in the matrix of an affine transform.
      *
+     * <p>The <em>source</em> dimensions (pixel indices) are insensitive to 
variables order: invoking {@code A.f(B)}
+     * or {@code B.f(A)} are equivalent. However the <em>target</em> 
dimensions ("real world" coordinates) depend on
+     * the order: values of this variable will be stored in the first target 
dimension of the localization grid, and
+     * values of the other variable will be in the second target dimension.</p>
+     *
      * @param  other  the other axis to use for creating a localization grid.
      * @return the localization grid, or {@code null} if none can be built.
      * @throws IOException if an error occurred while reading the data.
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 fa0c7ee..5c50d31 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
@@ -40,6 +40,7 @@ import org.apache.sis.coverage.grid.GridGeometry;
 import org.apache.sis.coverage.grid.IllegalGridGeometryException;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.NullArgumentException;
+import org.apache.sis.util.ArraysExt;
 
 
 /**
@@ -374,7 +375,7 @@ public abstract class Grid extends NamedElement {
             for (int i=0; i<sourceDimensions.length; i++) {
                 final int tgtDim = deferred[i];
                 final Axis axis = axes[tgtDim];
-findFree:       for (int srcDim : axis.sourceDimensions) {
+findFree:       for (int srcDim : axis.sourceDimensions) {                     
 // In preference order (will take only one).
                     srcDim = lastSrcDim - srcDim;                              
 // Convert netCDF order to "natural" order.
                     for (int j=affine.getNumRow(); --j>=0;) {
                         if (affine.getElement(j, srcDim) != 0) {
@@ -394,23 +395,26 @@ findFree:       for (int srcDim : axis.sourceDimensions) {
             final MathTransformFactory factory = 
decoder.getMathTransformFactory();
             for (int i=0; i<nonLinears.size(); i++) {         // Length of 
'nonLinears' may change in this loop.
                 if (nonLinears.get(i) == null) {
-                    final Axis axis = axes[deferred[i]];
                     for (int j=i; ++j < nonLinears.size();) {
                         if (nonLinears.get(j) == null) {
-                            final Axis other   = axes[deferred[j]];
+                            final Axis[] gridAxes = new Axis[] {
+                                axes[deferred[i]],
+                                axes[deferred[j]]
+                            };
                             final int srcDim   = sourceDimensions[i];
                             final int otherDim = sourceDimensions[j];
-                            final LocalizationGridBuilder grid;
                             switch (srcDim - otherDim) {
-                                case -1: grid = 
axis.createLocalizationGrid(other); break;
-                                case +1: grid = 
other.createLocalizationGrid(axis); break;
+                                case -1: break;
+                                case +1: ArraysExt.swap(gridAxes, 0, 1); break;
                                 default: continue;            // Needs axes at 
consecutive source dimensions.
                             }
+                            final LocalizationGridBuilder grid = 
gridAxes[0].createLocalizationGrid(gridAxes[1]);
                             if (grid != null) {
                                 /*
                                  * 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
new file mode 100644
index 0000000..dcaf27e
--- /dev/null
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Linearizer.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.netcdf;
+
+import java.util.Map;
+import java.util.HashMap;
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.apache.sis.referencing.operation.builder.LocalizationGridBuilder;
+import org.apache.sis.internal.metadata.ReferencingServices;
+import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.util.Constants;
+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.
+ *
+ * <p>Current implementation provides a hard-coded list of linearized, but 
future version may allow
+ * customization depending on the netCDF file being decoded.</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ *
+ * @see 
org.apache.sis.referencing.operation.builder.LocalizationGridBuilder#addLinearizers(Map,
 int...)
+ *
+ * @since 1.0
+ * @module
+ */
+final class 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.
+     */
+    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);
+                
pg.parameter(Constants.SEMI_MAJOR).setValue(ReferencingServices.AUTHALIC_RADIUS);
+                
pg.parameter(Constants.SEMI_MINOR).setValue(ReferencingServices.AUTHALIC_RADIUS);
+                PROJECTIONS.put(operation, 
factory.createParameterizedTransform(pg));
+            } catch (FactoryException e) {
+                /*
+                 * Should never happen. But if it happens anyway, do not cause 
the whole netCDF reader
+                 * to fail for all files because of this error. Declare this 
error as originating from
+                 * Variable.getGridGeometry() because it is the caller 
(indirectly) for this class.
+                 */
+                Logging.unexpectedException(Logging.getLogger(Modules.NETCDF), 
Variable.class, "getGridGeometry", e);
+            }
+        }
+    }
+
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private Linearizer() {
+    }
+
+    /**
+     * 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.
+     */
+    static void applyTo(final LocalizationGridBuilder grid, final Axis[] axes) 
{
+        int xdim = -1, ydim = -1;
+        for (int i=axes.length; --i >= 0;) {
+            switch (axes[i].abbreviation) {
+                case 'λ': xdim = i; break;
+                case 'φ': ydim = i; break;
+            }
+        }
+        if (xdim >= 0 && ydim >= 0) {
+            grid.addLinearizers(PROJECTIONS, xdim, ydim);
+        }
+    }
+}

Reply via email to