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 038be25 Allow `Linearizer` to use "Polar Stereographic" projection instead of "Universal Transverse Mercator" if the raster is too close to a pole. 038be25 is described below commit 038be2598e312f20858a1baa925f79b6178c4920 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Sun Jan 9 01:08:55 2022 +0100 Allow `Linearizer` to use "Polar Stereographic" projection instead of "Universal Transverse Mercator" if the raster is too close to a pole. --- .../sis/internal/referencing/AxisDirections.java | 18 ++- .../apache/sis/internal/referencing/Resources.java | 5 + .../sis/internal/referencing/Resources.properties | 1 + .../internal/referencing/Resources_fr.properties | 1 + .../operation/builder/LinearTransformBuilder.java | 5 +- .../operation/builder/ProjectedTransformTry.java | 2 +- ide-project/NetBeans/nbproject/genfiles.properties | 4 +- ide-project/NetBeans/nbproject/project.xml | 1 + .../apache/sis/internal/earth/netcdf/GCOM_C.java | 2 +- .../apache/sis/internal/earth/netcdf/GCOM_W.java | 2 +- .../java/org/apache/sis/internal/netcdf/Grid.java | 6 +- .../apache/sis/internal/netcdf/GridCacheValue.java | 22 +++- .../org/apache/sis/internal/netcdf/Linearizer.java | 126 +++++++++++++++++---- 13 files changed, 155 insertions(+), 40 deletions(-) diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java index a1f1ab2..2dd092b 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java @@ -44,7 +44,7 @@ import static org.apache.sis.util.CharSequences.*; * Utilities methods related to {@link AxisDirection}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * @since 0.4 * @module */ @@ -265,6 +265,22 @@ public final class AxisDirections extends Static { } /** + * Returns {@code true} if the given axis is such as "South along 90°E". + * + * <p><b>This is a temporary method to be removed!</b> + * Latest ISO 19111 revision uses another mechanism for declaring such axis direction. + * This method will be removed after we upgraded the API accordingly. + * + * @param dir the axis to test, or {@code null}. + * @return {@code true} if the given axis is such as "South along 90°E". + * + * @since 1.2 + */ + public static boolean isAlongMeridian(final AxisDirection dir) { + return (dir != null) && !isCompass(dir); + } + + /** * Returns {@code true} if the given direction is {@code UP} or {@code DOWN}. * * @param dir the direction to test, or {@code null}. diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java index 5992138..5d523d6 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java @@ -117,6 +117,11 @@ public final class Resources extends IndexedResourceBundle { public static final short CanNotInstantiateGeodeticObject_1 = 5; /** + * Can not linearize the localization grid. + */ + public static final short CanNotLinearizeLocalizationGrid = 100; + + /** * Can not map an axis from the specified coordinate system to the “{0}” direction. */ public static final short CanNotMapAxisToDirection_1 = 6; diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties index 0f2a5dd..ad2e8c7 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties @@ -54,6 +54,7 @@ CanNotCreateObjectAsInstanceOf_2 = Can not create an object of type \u201c{1}\u CanNotFindCommonCRS = Can not find a coordinate reference system common to all given envelopes. CanNotInferGridSizeFromValues_1 = Can not infer a grid size from the given values in {0} range. CanNotInstantiateGeodeticObject_1 = Can not instantiate geodetic object for \u201c{0}\u201d. +CanNotLinearizeLocalizationGrid = Can not linearize the localization grid. CanNotMapAxisToDirection_1 = Can not map an axis from the specified coordinate system to the \u201c{0}\u201d direction. CanNotParseCombinedReference_2 = Can not parse component {1} in the combined {0,choice,0#URN|1#URL}. CanNotSeparateCRS_1 = Can not separate the \u201c{0}\u201d coordinate reference system into sub-components. diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties index 17d1c77..b647712 100644 --- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties +++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties @@ -59,6 +59,7 @@ CanNotCreateObjectAsInstanceOf_2 = Ne peut pas cr\u00e9er un objet du type \u00 CanNotFindCommonCRS = Ne peut pas trouver un syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es commun pour toutes les enveloppes donn\u00e9es. CanNotInferGridSizeFromValues_1 = Ne peut pas inf\u00e9rer une taille de grille \u00e0 partir des valeurs donn\u00e9es dans la plage {0}. CanNotInstantiateGeodeticObject_1 = Ne peut pas cr\u00e9er l\u2019objet g\u00e9od\u00e9tique pour \u00ab\u202f{0}\u202f\u00bb. +CanNotLinearizeLocalizationGrid = Ne peut pas lin\u00e9ariser la grille de localisation. CanNotMapAxisToDirection_1 = Aucun axe du syst\u00e8me de coordonn\u00e9es sp\u00e9cifi\u00e9 n\u2019a pu \u00eatre associ\u00e9 \u00e0 la direction \u00ab\u202f{0}\u202f\u00bb. CanNotSeparateCRS_1 = Ne peut pas s\u00e9parer le syst\u00e8me de r\u00e9f\u00e9rence \u00ab\u202f{0}\u202f\u00bb en sous-composantes. CanNotSeparateTransform_3 = Ne peut pas s\u00e9parer la transformation parce-que le r\u00e9sultat aurait {2} dimension{2,choice,1#|2#s} en {0,choice,0#entr\u00e9|1#sortie} au lieu de {1}. 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 2df12fe..0f5838f 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 @@ -89,7 +89,7 @@ import org.apache.sis.util.Classes; * That selected projection is given by {@link #linearizer()}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * * @see LocalizationGridBuilder * @see LinearTransform @@ -1469,7 +1469,8 @@ search: for (int j=domain(); --j >= 0;) { * Finished to try all transforms. If all of them failed, wrap the `TransformException`. */ if (bestTransform == null) { - throw new FactoryException(ProjectedTransformTry.getError(linearizers)); + throw new FactoryException(Resources.format(Resources.Keys.CanNotLinearizeLocalizationGrid), + ProjectedTransformTry.getError(linearizers)); } if (needTargetReplace) { transformedArrays = appliedLinearizer.replaceTransformed(targets, transformedArrays); 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 64e6931..547fb73 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 @@ -369,7 +369,7 @@ final class ProjectedTransformTry implements Comparable<ProjectedTransformTry>, /** * Returns the first error in the given list of linearizers. Errors after the first one are added - * as suppressed exception. If no error are found, this method returns {@code null}. + * as suppressed exceptions. If no error are found, this method returns {@code null}. */ static TransformException getError(final List<ProjectedTransformTry> linearizers) { TransformException error = null; diff --git a/ide-project/NetBeans/nbproject/genfiles.properties b/ide-project/NetBeans/nbproject/genfiles.properties index c909012..26927a9 100644 --- a/ide-project/NetBeans/nbproject/genfiles.properties +++ b/ide-project/NetBeans/nbproject/genfiles.properties @@ -3,6 +3,6 @@ build.xml.data.CRC32=58e6b21c build.xml.script.CRC32=462eaba0 build.xml.stylesheet.CRC32=28e38971@1.53.1.46 -nbproject/build-impl.xml.data.CRC32=7361a050 +nbproject/build-impl.xml.data.CRC32=d3e84221 nbproject/build-impl.xml.script.CRC32=6b1e829a -nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.100.0.48 +nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.101.0.48 diff --git a/ide-project/NetBeans/nbproject/project.xml b/ide-project/NetBeans/nbproject/project.xml index 1fa69a1..00659e4 100644 --- a/ide-project/NetBeans/nbproject/project.xml +++ b/ide-project/NetBeans/nbproject/project.xml @@ -99,6 +99,7 @@ <word>initially</word> <word>javadoc</word> <word>kilometre</word> + <word>linearization</word> <word>linearizer</word> <word>linearizers</word> <word>loggings</word> diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java index 3e23d77..e81c9ef 100644 --- a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java +++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_C.java @@ -315,7 +315,7 @@ public final class GCOM_C extends Convention { */ @Override public Set<Linearizer> linearizers(final Decoder decoder) { - return Collections.singleton(new Linearizer(CommonCRS.WGS84, Linearizer.Type.UTM)); + return Collections.singleton(new Linearizer(CommonCRS.WGS84, Linearizer.Type.UNIVERSAL)); } /** diff --git a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java index b129195..343984e 100644 --- a/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java +++ b/profiles/sis-japan-profile/src/main/java/org/apache/sis/internal/earth/netcdf/GCOM_W.java @@ -198,7 +198,7 @@ public final class GCOM_W extends Convention { */ @Override public Set<Linearizer> linearizers(final Decoder decoder) { - return Collections.singleton(new Linearizer(CommonCRS.WGS84, Linearizer.Type.UTM)); + return Collections.singleton(new Linearizer(CommonCRS.WGS84, Linearizer.Type.UNIVERSAL)); } /** 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 9f67fa8..d19b8ce 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 @@ -215,7 +215,7 @@ public abstract class Grid extends NamedElement { /* * If an axis has a "wraparound" range (for example a longitude axis where the next value after +180° * may be -180°), we will examine it last. The reason is that if a wraparound occurs in the middle of - * the localization grid, it will confuse the computation based on 'coordinateForAxis(…)' calls below. + * the localization grid, it will confuse the computation based on `coordinateForAxis(…)` calls below. * We are better to resolve the latitude axis first, and then resolve the longitude axis with the code * path checking for dimension collisions, without using coordinateForAxis(…) on longitude axis. */ @@ -449,7 +449,7 @@ findFree: for (int srcDim : axis.gridDimensionIndices) { * axes come in pairs. */ final List<GridCacheValue> linearizations = new ArrayList<>(); - for (int i=0; i<nonLinears.size(); i++) { // Length of 'nonLinears' may change in this loop. + for (int i=0; i<nonLinears.size(); i++) { // Length of `nonLinears` may change in this loop. if (nonLinears.get(i) == null) { for (int j=i; ++j < nonLinears.size();) { if (nonLinears.get(j) == null) { @@ -487,7 +487,7 @@ findFree: for (int srcDim : axis.gridDimensionIndices) { if (grid.linearizationTarget != null) { linearizations.add(grid); } - break; // Continue the 'i' loop. + break; // Continue the `i` loop. } } } diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridCacheValue.java b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridCacheValue.java index 3f08c59..75c41af 100644 --- a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridCacheValue.java +++ b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/GridCacheValue.java @@ -20,9 +20,9 @@ import java.util.Map; import java.util.Set; import java.util.Optional; import org.opengis.util.FactoryException; +import org.opengis.referencing.crs.SingleCRS; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.MathTransformFactory; -import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.referencing.operation.builder.LocalizationGridBuilder; @@ -32,26 +32,34 @@ import org.apache.sis.referencing.operation.builder.LocalizationGridBuilder; * {@code GridCacheValue}s are associated to {@link GridCacheKey}s in a hash map. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * @since 1.1 * @module */ final class GridCacheValue { + /** * The transform from grid coordinates to geographic or projected coordinates. */ final MathTransform gridToCRS; /** + * If a linearization has been applied, the linearization type. Otherwise {@code null}. + * This field together with {@link #linearizationTarget} and {@link #axisSwap} fields are copies of + * {@link Linearizer} fields, copied for making sure that this {@code GridCacheValue} is immutable. + */ + final Linearizer.Type linearizationType; + + /** * The target CRS of {@link #gridToCRS} if different than the CRS inferred by {@link CRSBuilder}. * This field is non-null if the target CRS has been changed by application of a linearizer. */ - final CoordinateReferenceSystem linearizationTarget; + final SingleCRS linearizationTarget; /** * Whether axes need to be swapped in order to have the same direction before and after linearization. - * For example if input coordinates stored in the localization grid have (east, north) directions, then - * {@link #linearizationTarget} coordinates shall have (east, north) directions as well. + * For example if input coordinates stored in the localization grid have (east, north) directions, + * then {@link #linearizationTarget} coordinates shall have (east, north) directions as well. * This flag specifies whether input coordinates must be swapped for making above condition true. * * <p>This flag assumes that {@link #linearizationTarget} has two dimensions.</p> @@ -70,12 +78,14 @@ final class GridCacheValue { final String name = e.get().getKey(); for (final Linearizer linearizer : linearizers) { if (name.equals(linearizer.name())) { + linearizationType = linearizer.type; linearizationTarget = linearizer.getTargetCRS(); - axisSwap = linearizer.axisSwap(); + axisSwap = linearizer.axisSwap(); return; } } } + linearizationType = null; linearizationTarget = null; axisSwap = false; } 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 dc5bc4f..48ff2d6 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 @@ -23,7 +23,7 @@ import java.util.List; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.SingleCRS; import org.opengis.referencing.crs.ProjectedCRS; -import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.operation.Matrix; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; @@ -49,8 +49,10 @@ import org.apache.sis.util.ArraysExt; * order determined by {@link #targetCRS}. In other words, netCDF dimension order shall be ignored if a * linearization is applied.</p> * + * <p>A new instance of this class shall be created for each netCDF file is read.</p> + * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * * @see org.apache.sis.referencing.operation.builder.LocalizationGridBuilder#addLinearizers(Map, boolean, int...) * @@ -59,6 +61,13 @@ import org.apache.sis.util.ArraysExt; */ public final class Linearizer { /** + * Number of dimensions of the grid. + * + * @see org.apache.sis.referencing.operation.builder.ResidualGrid#SOURCE_DIMENSION + */ + private static final int SOURCE_DIMENSION = 2; + + /** * The datum to use as one of the predefined constants. The ellipsoid size do not matter * because a linear regression will be applied anyway. However the eccentricity matter. * @@ -74,14 +83,62 @@ public final class Linearizer { /** * The type of projection to create. - * Current implementation supports only Universal Transverse Mercator (UTM) projection, + * Current implementation supports only Universal Transverse Mercator (UTM) and stereographic projections, * but we nevertheless define this enumeration as a place-holder for more types in the future. */ public enum Type { /** - * Universal Transverse Mercator projection. + * Universal Transverse Mercator (UTM) or Polar Stereographic projection, depending on whether the image + * is close to a pole or not. The CRS is selected by a call to {@link CommonCRS#universal(double, double)}. + * The point given is the {@code universal(…)} is determined as below: + * + * <ul> + * <li>If the image is far enough from equator (at a latitude of {@value #POLAR_THRESHOLD} or further), + * then the point will be in the center of the border closest to the pole.</li> + * <li>Otherwise the point is in the middle of the image.</li> + * </ul> + * + * <div class="note"><b>Rational:</b> + * the intend is to increase the chances to get the Polar Stereographic projection for images close to pole. + * This is necessary because longitude values may become far from central meridian at latitudes such as 88°, + * causing the Transverse Mercator projection to produce NaN numbers.</div> */ - UTM + UNIVERSAL; + + /** + * Minimal latitude (in degrees) for forcing the {@link #UNIVERSAL} mode to consider a point + * on the border closest to pole for deciding whether to use UTM or stereographic projection. + * 60° is the limit of the domain of validity of Polar Stereographic methods. + */ + static final int POLAR_THRESHOLD = 60; + + /** + * Returns a coordinate system containing the axes to search and replace in order to build + * a "CRS after linearization" from a "CRS before linearization". The caller will use only + * the axis directions (not the names) of the returned coordinate system. + * + * <h4>Rational</h4> + * Usually, the source CRS is geographic and the target CRS is projected. + * We can generally associate a source axis to a target axis by looking at their directions. + * For example the "Longitude" source axis is approximately colinear with the "Easting" target axis. + * {@link org.opengis.referencing.cs.AxisDirection#EAST} can be used as a criterion for mapping them. + * Note however that axis names can not be used, because they differ in geographic and projected CRS. + * + * <p>However there is an exception where target axis directions will not work neither. + * If the projection is a polar projection with axis directions such as "South along 90°E", + * then {@link AxisDirections#indicesOfColinear(CoordinateSystem, CoordinateSystem)} will + * not find a match. We can workaround by using arbitrary (East, North) directions instead.</p> + * + * @param targetCS coordinate system of {@link Linearizer#targetCRS}. + */ + final CoordinateSystem getAxisReplacement(final CoordinateSystem targetCS) { + for (int i = targetCS.getDimension(); --i >= 0;) { + if (AxisDirections.isAlongMeridian(targetCS.getAxis(i).getDirection())) { + return CommonCRS.defaultGeographic().getCoordinateSystem(); + } + } + return targetCS; + } } /** @@ -93,7 +150,7 @@ public final class Linearizer { * The target coordinate reference system after application of the non-linear transform. * May depend on the netCDF file being read (for example for choosing a UTM zone). */ - private CoordinateReferenceSystem targetCRS; + private SingleCRS targetCRS; /** * Whether axes need to be swapped in order to have the same direction before and after the transform. @@ -124,7 +181,7 @@ public final class Linearizer { /** * Returns the target CRS computed by {@link #gridToTargetCRS gridToTargetCRS(…)}. */ - final CoordinateReferenceSystem getTargetCRS() { + final SingleCRS getTargetCRS() { return targetCRS; } @@ -168,16 +225,36 @@ public final class Linearizer { throw new AssertionError(type); } /* - * Create a Universal Transverse Mercator (UTM) projection for the zone containing a point in - * the middle of the grid. We apply `Math.signum(…)` on the latitude for avoiding stereographic - * projections near poles and for avoiding Norway and Svalbard special cases. + * Create a Universal Transverse Mercator (UTM) projection for the zone containing a point in the grid. + * First, we compute an estimation of the bounding box in geographic coordinates (using grid corners). + * Then if the box is far enough from equator, we use the point on the side closest to the pole. */ - case UTM: { + case UNIVERSAL: { final Envelope bounds = grid.getSourceEnvelope(false); - final double[] median = grid.getControlPoint( - (int) Math.round(bounds.getMedian(0)), - (int) Math.round(bounds.getMedian(1))); - final ProjectedCRS crs = datum.universal(Math.signum(median[ydim]), median[xdim]); + double x, y, ymin, ymax; + { // For keeping `median` variable local. + final double[] median = grid.getControlPoint( + (int) Math.round(bounds.getMedian(0)), + (int) Math.round(bounds.getMedian(1))); + x = median[xdim]; + y = median[ydim]; + ymin = ymax = y; + } + final int[] gc = new int[SOURCE_DIMENSION]; + for (int i=0; i<4; i++) { + for (int d=0; d<SOURCE_DIMENSION; d++) { + gc[d] = (int) Math.round(((i & (1 << d)) == 0) ? bounds.getMinimum(d) : bounds.getMaximum(d)); + } + final double yp = grid.getControlPoint(gc[0], gc[1])[ydim]; + if (yp < ymin) ymin = yp; + if (yp > ymax) ymax = yp; + } + /* + * If the image is far from equator, replace the middle point by a point close to pole. + */ + if (ymin >= +Type.POLAR_THRESHOLD) y = ymax; + else if (ymax <= -Type.POLAR_THRESHOLD) y = ymin; + final ProjectedCRS crs = datum.universal(y, x); assert ReferencingUtilities.startsWithNorthEast(crs.getBaseCRS().getCoordinateSystem()); transform = crs.getConversionFromBase().getMathTransform(); targetCRS = crs; @@ -245,7 +322,7 @@ public final class Linearizer { * <p>This static method is defined here for keeping in a single class all codes related to linearization.</p> * * @param components the components of the compound CRS that {@link CRSBuilder} inferred. - * @param replacements the {@link #targetCRS} of linearizations. + * @param replacements the {@link #targetCRS} of linearizations. Usually a list of size 1. * @param reorderGridToCRS an affine transform doing a final step in a "grid to CRS" transform for ordering axes. * Not used by this method, but modified for taking in account axis order changes caused by replacements. */ @@ -253,14 +330,16 @@ public final class Linearizer { final Matrix reorderGridToCRS) throws DataStoreReferencingException { Matrix original = null; -search: for (final GridCacheValue cache : replacements) { - final CoordinateReferenceSystem targetCRS = cache.linearizationTarget; +search: for (final GridCacheValue replacement : replacements) { + final SingleCRS targetCRS = replacement.linearizationTarget; + final CoordinateSystem targetCS = replacement.linearizationType.getAxisReplacement(targetCRS.getCoordinateSystem()); int firstDimension = 0; for (int i=0; i < components.length; i++) { final SingleCRS sourceCRS = components[i]; - final int[] r = AxisDirections.indicesOfColinear(sourceCRS.getCoordinateSystem(), targetCRS.getCoordinateSystem()); + final int[] r = AxisDirections.indicesOfColinear(sourceCRS.getCoordinateSystem(), targetCS); if (r != null) { - if (cache.axisSwap) { + components[i] = targetCRS; + if (replacement.axisSwap) { ArraysExt.swap(r, 0, 1); } for (int j=0; j<r.length; j++) { @@ -275,13 +354,14 @@ search: for (final GridCacheValue cache : replacements) { } } } - components[i] = (ProjectedCRS) targetCRS; continue search; } firstDimension += sourceCRS.getCoordinateSystem().getDimension(); } - // If a replacement can not be applied, fail CRS construction. - // May be relaxed in a future version if we have a use case. + /* + * If a replacement can not be applied, fail CRS construction. + * May be relaxed in a future version if we have a use case. + */ throw new DataStoreReferencingException(Resources.format( Resources.Keys.CanNotInjectComponent_1, IdentifiedObjects.getName(targetCRS, null))); }