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 d9b0d29  Replace GridGeometry.reduce(lower, upper) by 
reduce(dimensions) and add test.
d9b0d29 is described below

commit d9b0d2911f7ee70fc30789f4a7e4addbec8c65dc
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Jan 4 11:31:40 2019 +0100

    Replace GridGeometry.reduce(lower, upper) by reduce(dimensions) and add 
test.
---
 .../org/apache/sis/coverage/grid/GridExtent.java   | 74 ++++++++++++++++------
 .../org/apache/sis/coverage/grid/GridGeometry.java | 61 ++++++++++--------
 .../org/apache/sis/internal/raster/Resources.java  |  5 ++
 .../sis/internal/raster/Resources.properties       |  1 +
 .../sis/internal/raster/Resources_fr.properties    |  1 +
 .../apache/sis/coverage/grid/GridExtentTest.java   | 21 +++---
 .../apache/sis/coverage/grid/GridGeometryTest.java | 43 ++++++++++++-
 .../main/java/org/apache/sis/referencing/CRS.java  | 10 ++-
 8 files changed, 157 insertions(+), 59 deletions(-)

diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
index 5b278dd..89b89d1 100644
--- a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
+++ b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridExtent.java
@@ -47,6 +47,7 @@ import org.apache.sis.geometry.Envelopes;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.operation.transform.TransformSeparator;
 import org.apache.sis.io.TableAppender;
+import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.iso.Types;
 
 // Branch-dependent imports
@@ -753,35 +754,66 @@ public class GridExtent implements Serializable {
     }
 
     /**
+     * Verifies the validity of a given {@code dimensions} argument.
+     *
+     * @param  dimensions  the user-supplied argument to validate.
+     * @param  limit       maximal number of dimensions, exclusive.
+     * @return {@code true} if the caller can return {@code this}.
+     */
+    static boolean verifyDimensions(final int[] dimensions, final int limit) {
+        ArgumentChecks.ensureNonNull("dimensions", dimensions);
+        final int n = dimensions.length;
+        if (n == 0) {
+            throw new 
IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, 
"dimensions"));
+        }
+        if (!ArraysExt.isSorted(dimensions, true)) {
+            throw new 
IllegalArgumentException(Resources.format(Resources.Keys.NotStrictlyOrderedDimensions));
+        }
+        int d = dimensions[0];
+        if (d >= 0) {
+            d = dimensions[n - 1];
+            if (d < limit) {
+                return n == limit;
+            }
+        }
+        throw new 
IndexOutOfBoundsException(Errors.format(Errors.Keys.IndexOutOfBounds_1, d));
+    }
+
+    /**
      * Returns a grid envelope that encompass only some dimensions of this 
grid envelope.
-     * This method copies this grid envelope into a new grid envelope, 
beginning at dimension
-     * {@code lower} and extending to dimension {@code upper-1} inclusive. 
Thus the dimension
-     * of the sub grid envelope is {@code upper - lower}.
+     * This method copies the specified dimensions of this grid envelope into 
a new grid envelope.
+     * The given dimensions must be in strictly ascending order without 
duplicated values.
+     * The dimension of the sub grid envelope will be {@code 
dimensions.length}.
      *
      * <p>This method performs a <cite>dimensionality reduction</cite> and can 
be used as the
-     * converse of {@link #append(DimensionNameType, long, long, boolean)}.</p>
+     * converse of {@link #append(DimensionNameType, long, long, boolean)}.
+     * This method can not be used for changing dimension order.</p>
      *
-     * @param  lower  the first dimension to copy, inclusive.
-     * @param  upper  the last  dimension to copy, exclusive.
-     * @return the sub-envelope, or {@code this} if [{@code lower} … {@code 
upper}] is [0 … {@link #getDimension() dimension}].
+     * @param  dimensions  the dimensions to select, in strictly increasing 
order.
+     * @return the sub-envelope, or {@code this} if the given array contains 
all dimensions of this grid extent.
      * @throws IndexOutOfBoundsException if an index is out of bounds.
      *
-     * @see GridGeometry#reduce(int, int)
+     * @see GridGeometry#reduce(int...)
      */
-    public GridExtent reduce(final int lower, final int upper) {
-        final int dimension = getDimension();
-        ArgumentChecks.ensureValidIndexRange(dimension, lower, upper);
-        final int newDim = upper - lower;
-        if (newDim == dimension) {
+    public GridExtent reduce(final int... dimensions) {
+        final int sd = getDimension();
+        if (verifyDimensions(dimensions, sd)) {
             return this;
         }
-        DimensionNameType[] axisTypes = types;
-        if (axisTypes != null) {
-            axisTypes = Arrays.copyOfRange(axisTypes, lower, upper);
+        final int td = dimensions.length;
+        DimensionNameType[] tt = null;
+        if (types != null) {
+            tt = new DimensionNameType[td];
+            for (int i=0; i<td; i++) {
+                tt[i] = types[dimensions[i]];
+            }
+        }
+        final GridExtent sub = new GridExtent(td, tt);
+        for (int i=0; i<td; i++) {
+            final int j = dimensions[i];
+            sub.coordinates[i]    = coordinates[j];
+            sub.coordinates[i+td] = coordinates[j+sd];
         }
-        final GridExtent sub = new GridExtent(newDim, axisTypes);
-        System.arraycopy(coordinates, lower,           sub.coordinates, 0,     
 newDim);
-        System.arraycopy(coordinates, lower+dimension, sub.coordinates, 
newDim, newDim);
         return sub;
     }
 
@@ -799,7 +831,7 @@ public class GridExtent implements Serializable {
      * grid borders.</div>
      *
      * This method does not reduce the number of dimensions of the grid extent.
-     * For dimensionality reduction, see {@link #reduce(int, int)}.
+     * For dimensionality reduction, see {@link #reduce(int...)}.
      *
      * @param  strides  the strides. Length shall be equal to the number of 
dimension and all values shall be greater than zero.
      * @return the sub-sampled extent, or {@code this} is sub-sampling results 
in the same extent.
@@ -838,7 +870,7 @@ public class GridExtent implements Serializable {
      * the number of dimensions of the grid extent.
      *
      * <p>This method does not reduce the number of dimensions of the grid 
extent.
-     * For dimensionality reduction, see {@link #reduce(int, int)}.</p>
+     * For dimensionality reduction, see {@link #reduce(int...)}.</p>
      *
      * @param  slicePoint           where to take a slice. NaN values are 
handled as if their dimensions were absent.
      * @param  modifiedDimensions   mapping from {@code slicePoint} dimensions 
to this {@code GridExtent} dimensions,
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
index 4001abb..9a66bc0 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/coverage/grid/GridGeometry.java
@@ -482,35 +482,39 @@ public class GridGeometry implements Serializable {
     }
 
     /**
-     * Creates a new grid geometry over the specified range of dimensions of 
the given grid geometry.
+     * Creates a new grid geometry over the specified dimensions of the given 
grid geometry.
      *
-     * @param  other  the grid geometry to copy.
-     * @param  lower  the first dimension to copy, inclusive.
-     * @param  upper  the last  dimension to copy, exclusive.
+     * @param  other       the grid geometry to copy.
+     * @param  dimensions  the dimensions to select, in strictly increasing 
order (this may not be verified).
      * @throws FactoryException if an error occurred while separating the 
"grid to CRS" transform.
      *
-     * @see #reduce(int, int)
+     * @see #reduce(int...)
      */
-    private GridGeometry(final GridGeometry other, final int lower, final int 
upper) throws FactoryException {
-        extent = (other.extent != null) ? other.extent.reduce(lower, upper) : 
null;
-        final int n = upper - lower;
-        final int[] dimensions;
+    private GridGeometry(final GridGeometry other, int[] dimensions) throws 
FactoryException {
+        extent = (other.extent != null) ? other.extent.reduce(dimensions) : 
null;
+        final int n = dimensions.length;
         if (other.gridToCRS != null) {
+            final int[] sources = dimensions;
             TransformSeparator sep = new TransformSeparator(other.gridToCRS);
-            sep.addSourceDimensionRange(lower, upper);
+            sep.addSourceDimensions(sources);
             gridToCRS  = sep.separate();
             dimensions = sep.getTargetDimensions();
             assert dimensions.length == n : Arrays.toString(dimensions);
-
+            if (!ArraysExt.isSorted(dimensions, true)) {
+                throw new 
IllegalGridGeometryException(Resources.format(Resources.Keys.IllegalGridGeometryComponent_1,
 "dimensions"));
+            }
+            /*
+             * We redo a separation for 'cornerToCRS' instead than applying a 
translation of the 'gridToCRS'
+             * computed above because we don't know which of 'gridToCRS' and 
'cornerToCRS' has less NaN values.
+             */
             sep = new TransformSeparator(other.cornerToCRS);
-            sep.addSourceDimensionRange(lower, upper);
+            sep.addSourceDimensions(sources);
             sep.addTargetDimensions(dimensions);
             cornerToCRS = sep.separate();
             assert Arrays.equals(sep.getSourceDimensions(), dimensions) : 
Arrays.toString(dimensions);
         } else {
             gridToCRS   = null;
             cornerToCRS = null;
-            dimensions  = ArraysExt.sequence(lower, upper);
         }
         final ImmutableEnvelope env = other.envelope;
         if (env != null) {
@@ -653,7 +657,7 @@ public class GridGeometry implements Serializable {
      * In such case the envelope needs to contain all dimensions.</p>
      *
      * <p>This method does not reduce the number of dimensions of this grid 
geometry.
-     * For dimensionality reduction, see {@link #reduce(int, int)}.</p>
+     * For dimensionality reduction, see {@link #reduce(int...)}.</p>
      *
      * @param  areaOfInterest  the desired spatiotemporal region in any CRS 
(transformations will be applied as needed).
      * @return a grid extent of the same dimension than the grid geometry 
which intersects the given area of interest.
@@ -681,7 +685,7 @@ public class GridGeometry implements Serializable {
      * See {@link #slice(DirectPosition)} for examples.
      *
      * <p>This method does not reduce the number of dimensions of this grid 
geometry.
-     * For dimensionality reduction, see {@link #reduce(int, int)}.</p>
+     * For dimensionality reduction, see {@link #reduce(int...)}.</p>
      *
      * @param  slicePoint   the coordinates where to get a slice.
      * @return a slice of the grid extent at the given slice point.
@@ -1024,7 +1028,7 @@ public class GridGeometry implements Serializable {
      * then no sub-sampling will be applied on the missing dimensions.
      *
      * <p>This method does not reduce the number of dimensions of this grid 
geometry.
-     * For dimensionality reduction, see {@link #reduce(int, int)}.</p>
+     * For dimensionality reduction, see {@link #reduce(int...)}.</p>
      *
      * @param  areaOfInterest    the desired spatiotemporal region in any CRS 
(transformations will be applied as needed),
      *                           or {@code null} for not restricting the 
sub-grid to a sub-area.
@@ -1069,7 +1073,7 @@ public class GridGeometry implements Serializable {
      * </ul></div>
      *
      * This method does not reduce the number of dimensions of this grid 
geometry.
-     * For dimensionality reduction, see {@link #reduce(int, int)}.
+     * For dimensionality reduction, see {@link #reduce(int...)}.
      *
      * @param  slicePoint   the coordinates where to get a slice.
      * @return a slice of this grid geometry at the given slice point. May be 
{@code this}.
@@ -1094,24 +1098,25 @@ public class GridGeometry implements Serializable {
 
     /**
      * Returns a grid geometry that encompass only some dimensions of this 
grid geometry.
-     * This method copies this grid geometry into a new grid geometry, 
beginning at dimension
-     * {@code lower} and extending to dimension {@code upper-1} inclusive. 
Thus the dimension
-     * of the sub grid geometry is {@code upper - lower}.
+     * This method copies the specified dimensions of this grid geometry into 
a new grid geometry.
+     * The given dimensions must be in strictly ascending order without 
duplicated values.
+     * The dimension of the sub grid grid geometry will be {@code 
dimensions.length}.
      *
-     * <p>This method performs a <cite>dimensionality reduction</cite>.</p>
+     * <p>This method performs a <cite>dimensionality reduction</cite>.
+     * This method can not be used for changing dimension order.</p>
      *
-     * @param  lower  the first grid dimension to copy, inclusive.
-     * @param  upper  the last  grid dimension to copy, exclusive.
-     * @return the sub grid geometry, or {@code this} if [{@code lower} … 
{@code upper}] is [0 … {@link #getDimension() dimension}].
+     * @param  dimensions  the dimensions to select, in strictly increasing 
order.
+     * @return the sub grid geometry, or {@code this} if the given array 
contains all dimensions of this grid grid geometry.
      * @throws IndexOutOfBoundsException if an index is out of bounds.
      *
-     * @see GridExtent#reduce(int, int)
+     * @see GridExtent#reduce(int...)
+     * @see org.apache.sis.referencing.CRS#reduce(CoordinateReferenceSystem, 
int...)
      */
-    public GridGeometry reduce(final int lower, final int upper) {
-        if (lower == 0 && upper == getDimension()) {
+    public GridGeometry reduce(final int... dimensions) {
+        if (GridExtent.verifyDimensions(dimensions, getDimension())) {
             return this;
         } else try {
-            return new GridGeometry(this, lower, upper);
+            return new GridGeometry(this, dimensions);
         } catch (FactoryException e) {
             throw new IllegalGridGeometryException(e, "dimensions");
         }
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java 
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java
index 51ef8eb..865cd1d 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.java
@@ -145,6 +145,11 @@ public final class Resources extends IndexedResourceBundle 
{
         public static final short NonLinearInDimensions_1 = 20;
 
         /**
+         * The specified dimensions are not in strictly ascending order.
+         */
+        public static final short NotStrictlyOrderedDimensions = 24;
+
+        /**
          * The ({0}, {1}) pixel coordinate is outside iterator domain.
          */
         public static final short OutOfIteratorDomain_2 = 1;
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
 
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
index 0f5531c..fd2bd6f 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources.properties
@@ -36,6 +36,7 @@ MismatchedSampleModel             = The two images use 
different sample models.
 MismatchedTileGrid                = The two images have different tile grid.
 NoCategoryForValue_1              = No category for value {0}.
 NonLinearInDimensions_1           = non-linear in {0} 
dimension{0,choice,1#|2#s}:
+NotStrictlyOrderedDimensions      = The specified dimensions are not in 
strictly ascending order.
 OutOfIteratorDomain_2             = The ({0}, {1}) pixel coordinate is outside 
iterator domain.
 PointOutsideCoverageDomain_1      = Point ({0}) is outside the coverage domain.
 TooManyQualitatives               = Too many qualitative categories.
diff --git 
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
 
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
index 0dc3acb..4dcd1d7 100644
--- 
a/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
+++ 
b/core/sis-raster/src/main/java/org/apache/sis/internal/raster/Resources_fr.properties
@@ -41,6 +41,7 @@ MismatchedSampleModel             = Les deux images disposent 
les pixels diff\u0
 MismatchedTileGrid                = Les deux images utilisent des grilles de 
tuiles diff\u00e9rentes.
 NoCategoryForValue_1              = Aucune cat\u00e9gorie n\u2019est 
d\u00e9finie pour la valeur {0}.
 NonLinearInDimensions_1           = non-lin\u00e9aire dans {0} 
dimension{0,choice,1#|2#s}\u2008:
+NotStrictlyOrderedDimensions      = Les dimensions sp\u00e9cifi\u00e9es ne 
sont pas en ordre strictement croissant.
 OutOfIteratorDomain_2             = La coordonn\u00e9e pixel ({0}, {1}) est en 
dehors du domaine de l\u2019it\u00e9rateur.
 PointOutsideCoverageDomain_1      = Le point ({0}) est en dehors du domaine de 
la couverture de donn\u00e9es.
 TooManyQualitatives               = Trop de cat\u00e9gories qualitatives.
diff --git 
a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
 
b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
index 01bfeff..c6ca296 100644
--- 
a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
+++ 
b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridExtentTest.java
@@ -122,17 +122,22 @@ public final strictfp class GridExtentTest extends 
TestCase {
     }
 
     /**
-     * Tests {@link GridExtent#reduce(int, int)}.
+     * Tests {@link GridExtent#reduce(int...)}.
      */
     @Test
     public void testReduce() {
-        GridExtent extent = create3D();
-        extent = extent.reduce(0, 2);
-        assertEquals("dimension", 2, extent.getDimension());
-        assertExtentEquals(extent, 0, 100, 499);
-        assertExtentEquals(extent, 1, 200, 799);
-        assertEquals(DimensionNameType.COLUMN, extent.getAxisType(0).get());
-        assertEquals(DimensionNameType.ROW,    extent.getAxisType(1).get());
+        final GridExtent extent = create3D();
+        GridExtent reduced = extent.reduce(0, 1);
+        assertEquals("dimension", 2, reduced.getDimension());
+        assertExtentEquals(reduced, 0, 100, 499);
+        assertExtentEquals(reduced, 1, 200, 799);
+        assertEquals(DimensionNameType.COLUMN, reduced.getAxisType(0).get());
+        assertEquals(DimensionNameType.ROW,    reduced.getAxisType(1).get());
+
+        reduced = extent.reduce(2);
+        assertEquals("dimension", 1, reduced.getDimension());
+        assertExtentEquals(reduced, 0, 40, 49);
+        assertEquals(DimensionNameType.TIME, reduced.getAxisType(0).get());
     }
 
     /**
diff --git 
a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
 
b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
index b692e2f..0533f1b 100644
--- 
a/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
+++ 
b/core/sis-raster/src/test/java/org/apache/sis/coverage/grid/GridGeometryTest.java
@@ -20,6 +20,7 @@ import org.opengis.metadata.spatial.DimensionNameType;
 import org.opengis.referencing.datum.PixelInCell;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.referencing.operation.matrix.Matrix2;
 import org.apache.sis.referencing.operation.matrix.Matrix3;
 import org.apache.sis.referencing.operation.matrix.Matrix4;
 import org.apache.sis.referencing.operation.matrix.Matrices;
@@ -368,10 +369,13 @@ public final strictfp class GridGeometryTest extends 
TestCase {
                         0.5, 0,   0, -180,
                         0,   0,   2,    3,
                         0,   0,   0,    1)), HardCodedCRS.WGS84_3D);
+        /*
+         * There is two ways to ask for a slice. The first way is to set some 
coordinates to NaN.
+         */
         GridGeometry slice = grid.slice(new GeneralDirectPosition(Double.NaN, 
Double.NaN, 15));
         assertNotSame(grid, slice);
         assertSame("gridToCRS", grid.gridToCRS, slice.gridToCRS);
-        final long[] expectedLow  = {336, 20, 6};
+        final long[] expectedLow  = {336,  20, 6};
         final long[] expectedHigh = {401, 419, 6};
         assertExtentEquals(expectedLow, expectedHigh, slice.getExtent());
         /*
@@ -385,4 +389,41 @@ public final strictfp class GridGeometryTest extends 
TestCase {
         assertSame("gridToCRS", grid.gridToCRS, slice.gridToCRS);
         assertExtentEquals(expectedLow, expectedHigh, slice.getExtent());
     }
+
+    /**
+     * Tests {@link GridGeometry#reduce(int...)}.
+     */
+    @Test
+    public void testReduce() {
+        final GridGeometry grid = new GridGeometry(
+                new GridExtent(null, new long[] {336, 20, 4}, new long[] {401, 
419, 10}, true),
+                PixelInCell.CELL_CORNER, MathTransforms.linear(new Matrix4(
+                        0,   0.5, 0,  -90,
+                        0.5, 0,   0, -180,
+                        0,   0,   2,    3,
+                        0,   0,   0,    1)), HardCodedCRS.GEOID_3D);
+        /*
+         * Tests on the two first dimensions.
+         */
+        GridGeometry reduced = grid.reduce(0, 1);
+        assertNotSame(grid, reduced);
+        assertExtentEquals(new long[] {336, 20}, new long[] {401, 419}, 
reduced.getExtent());
+        assertSame("CRS", HardCodedCRS.WGS84, 
reduced.getCoordinateReferenceSystem());
+        assertArrayEquals("resolution", new double[] {0.5, 0.5}, 
reduced.getResolution(false), STRICT);
+        assertMatrixEquals("gridToCRS", new Matrix3(
+                  0, 0.5,  -90,
+                  0.5, 0, -180,
+                  0,   0,    1), 
MathTransforms.getMatrix(reduced.getGridToCRS(PixelInCell.CELL_CORNER)), 
STRICT);
+        /*
+         * Tests on the last dimension.
+         */
+        reduced = grid.reduce(2);
+        assertNotSame(grid, reduced);
+        assertExtentEquals(new long[] {4}, new long[] {10}, 
reduced.getExtent());
+        assertSame("CRS", HardCodedCRS.GRAVITY_RELATED_HEIGHT, 
reduced.getCoordinateReferenceSystem());
+        assertArrayEquals("resolution", new double[] {2}, 
reduced.getResolution(false), STRICT);
+        assertMatrixEquals("gridToCRS", new Matrix2(
+                  2, 3,
+                  0, 1), 
MathTransforms.getMatrix(reduced.getGridToCRS(PixelInCell.CELL_CORNER)), 
STRICT);
+    }
 }
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
index e91666d..f1e837d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
@@ -933,7 +933,15 @@ public final class CRS extends Static {
 
     /**
      * Gets or creates a coordinate reference system with a subset of the 
dimensions of the given CRS.
-     * This method can be used for dimensionality reduction.
+     * This method can be used for dimensionality reduction, but not for 
changing axis order.
+     * The specified dimensions are used as if they were in strictly 
increasing order without duplicated values.
+     *
+     * <div class="section">Ellipsoidal height</div>
+     * This method can transform a three-dimensional geographic CRS into a 
two-dimensional geographic CRS.
+     * In this aspect, this method is the converse of {@link 
#compound(CoordinateReferenceSystem...)}.
+     * This method can also extract the {@linkplain 
CommonCRS.Vertical#ELLIPSOIDAL ellipsoidal height}
+     * from a three-dimensional geographic CRS, but this is generally not 
recommended since ellipsoidal
+     * heights make little sense without their (<var>latitude</var>, 
<var>longitude</var>) locations.
      *
      * @param  crs         the CRS to reduce the dimensionality, or {@code 
null} if none.
      * @param  dimensions  the dimensions to retain. The dimensions will be 
taken in increasing order, ignoring duplicated values.

Reply via email to