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