sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1811868 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/internal/referencing/ main/java/org/apache/sis/referencing/ test/java/org/apache/sis/internal/metadata/ test/java/org/apache/sis/internal/referencing/ test/...
Date Wed, 11 Oct 2017 18:51:59 GMT
Author: desruisseaux
Date: Wed Oct 11 18:51:58 2017
New Revision: 1811868

URL: http://svn.apache.org/viewvc?rev=1811868&view=rev
Log:
More support of three-dimensional projected CRS, by improving the decomposition in components.

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/EllipsoidalHeightCombinerTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1811868&r1=1811867&r2=1811868&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] Wed Oct 11 18:51:58 2017
@@ -297,15 +297,14 @@ public final class ReferencingUtilities
      * </ul></div>
      *
      * @param  object    the identified object to view as a properties map.
-     * @param  excludes  the keys of properties to exclude from the map.
      * @return a view of the identified object properties.
      *
      * @see IdentifiedObjects#getProperties(IdentifiedObject, String...)
      *
      * @since 0.7
      */
-    public static Map<String,?> getPropertiesForModifiedCRS(final IdentifiedObject
object, final String... excludes) {
-        final Map<String,?> properties = IdentifiedObjects.getProperties(object, excludes);
+    public static Map<String,?> getPropertiesForModifiedCRS(final IdentifiedObject
object) {
+        final Map<String,?> properties = IdentifiedObjects.getProperties(object, IdentifiedObject.IDENTIFIERS_KEY);
         final Identifier id = (Identifier) properties.get(IdentifiedObject.NAME_KEY);
         if (id != null) {
             String name = id.getCode();

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1811868&r1=1811867&r2=1811868&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
[UTF-8] Wed Oct 11 18:51:58 2017
@@ -25,6 +25,7 @@ import org.opengis.util.FactoryException
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CoordinateSystem;
@@ -42,6 +43,7 @@ import org.opengis.referencing.crs.Proje
 import org.opengis.referencing.crs.TemporalCRS;
 import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.crs.EngineeringCRS;
+import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.referencing.operation.OperationNotFoundException;
 import org.opengis.metadata.citation.Citation;
@@ -63,14 +65,18 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.referencing.cs.AxisFilter;
+import org.apache.sis.referencing.cs.CoordinateSystems;
 import org.apache.sis.referencing.cs.DefaultVerticalCS;
-import org.apache.sis.referencing.cs.DefaultEllipsoidalCS;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
+import org.apache.sis.referencing.crs.DefaultProjectedCRS;
 import org.apache.sis.referencing.crs.DefaultVerticalCRS;
 import org.apache.sis.referencing.crs.DefaultCompoundCRS;
+import org.apache.sis.referencing.crs.DefaultEngineeringCRS;
 import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
 import org.apache.sis.referencing.operation.CoordinateOperationContext;
 import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
+import org.apache.sis.referencing.operation.DefaultConversion;
 import org.apache.sis.referencing.factory.GeodeticObjectFactory;
 import org.apache.sis.referencing.factory.UnavailableFactoryException;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
@@ -82,8 +88,6 @@ import org.apache.sis.util.ArgumentCheck
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.Static;
 
-import static java.util.Collections.singletonMap;
-
 // Branch-dependent imports
 import org.opengis.geometry.Geometry;
 
@@ -890,20 +894,38 @@ public final class CRS extends Static {
      * @category information
      */
     public static boolean isHorizontalCRS(final CoordinateReferenceSystem crs) {
+        return horizontalCode(crs) == 2;
+    }
+
+    /**
+     * If the given CRS would quality as horizontal except for its number of dimensions,
returns that number.
+     * Otherwise returns 0. The number of dimensions can only be 2 or 3.
+     */
+    private static int horizontalCode(final CoordinateReferenceSystem crs) {
         /*
          * In order to determine if the CRS is geographic, checking the CoordinateSystem
type is more reliable
          * then checking if the CRS implements the GeographicCRS interface.  This is because
the GeographicCRS
-         * interface is GeoAPI-specific, so a CRS may be OGC-compliant without implementing
that interface.
+         * type did not existed in ISO 19111:2007, so a CRS could be standard-compliant without
implementing
+         * the GeographicCRS interface.
          */
+        boolean isEngineering = false;
         final boolean isGeodetic = (crs instanceof GeodeticCRS);
-        if (isGeodetic || crs instanceof ProjectedCRS || crs instanceof EngineeringCRS) {
-            @SuppressWarnings("null")
+        if (isGeodetic || crs instanceof ProjectedCRS || (isEngineering = (crs instanceof
EngineeringCRS))) {
             final CoordinateSystem cs = crs.getCoordinateSystem();
-            if (cs.getDimension() == 2) {
-                return !isGeodetic || (cs instanceof EllipsoidalCS);
+            final int dim = cs.getDimension();
+            if ((dim & ~1) == 2 && (!isGeodetic || (cs instanceof EllipsoidalCS)))
{
+                if (isEngineering) {
+                    int n = 0;
+                    for (int i=0; i<dim; i++) {
+                        if (AxisDirections.isCompass(cs.getAxis(i).getDirection())) n++;
+                    }
+                    // If we don't have exactly 2 east, north, etc. directions, consider
as non-horizontal.
+                    if (n != 2) return 0;
+                }
+                return dim;
             }
         }
-        return false;
+        return 0;
     }
 
     /**
@@ -913,8 +935,8 @@ public final class CRS extends Static {
      * first horizontal component in the order of the {@linkplain #getSingleComponents(CoordinateReferenceSystem)
      * single components list}.
      *
-     * <p>In the special case where a three-dimensional geographic CRS is found, this
method will create a
-     * two-dimensional geographic CRS without the vertical axis.</p>
+     * <p>In the special case where a three-dimensional geographic or projected CRS
is found, this method
+     * will create a two-dimensional geographic or projected CRS without the vertical axis.</p>
      *
      * @param  crs  the coordinate reference system, or {@code null}.
      * @return the first horizontal CRS, or {@code null} if none.
@@ -922,26 +944,53 @@ public final class CRS extends Static {
      * @category information
      */
     public static SingleCRS getHorizontalComponent(final CoordinateReferenceSystem crs) {
-        if (crs instanceof GeodeticCRS) {
-            CoordinateSystem cs = crs.getCoordinateSystem();
-            if (cs instanceof EllipsoidalCS) {                          // See comment in
isHorizontalCRS(…) method.
-                final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
-                if (i < 0) {
-                    return (SingleCRS) crs;
-                }
-                final CoordinateSystemAxis xAxis = cs.getAxis(i > 0 ? 0 : 1);
-                final CoordinateSystemAxis yAxis = cs.getAxis(i > 1 ? 1 : 2);
-                cs = CommonCRS.DEFAULT.geographic().getCoordinateSystem();
-                if (!Utilities.equalsIgnoreMetadata(cs.getAxis(0), xAxis) ||
-                    !Utilities.equalsIgnoreMetadata(cs.getAxis(1), yAxis))
-                {
-                    // We can not reuse the name of the existing CS, because it typically
-                    // contains text about axes including the axis that we just dropped.
-                    cs = new DefaultEllipsoidalCS(singletonMap(EllipsoidalCS.NAME_KEY, "Ellipsoidal
2D"), xAxis, yAxis);
-                }
-                return new DefaultGeographicCRS(
-                        ReferencingUtilities.getPropertiesForModifiedCRS(crs, CoordinateReferenceSystem.IDENTIFIERS_KEY),
-                        ((GeodeticCRS) crs).getDatum(), (EllipsoidalCS) cs);
+        switch (horizontalCode(crs)) {
+            /*
+             * If the CRS is already two-dimensional and horizontal, return as-is.
+             * We don't need to check if crs is an instance of SingleCRS since all
+             * CRS accepted by horizontalCode(…) are SingleCRS.
+             */
+            case 2: {
+                return (SingleCRS) crs;
+            }
+            case 3: {
+                /*
+                 * The CRS would be horizontal if we can remove the vertical axis. CoordinateSystems.replaceAxes(…)
+                 * will do this task for us. We can verify if the operation has been successful
by checking that
+                 * the number of dimensions has been reduced by 1 (from 3 to 2).
+                 */
+                final CoordinateSystem cs = CoordinateSystems.replaceAxes(crs.getCoordinateSystem(),
new AxisFilter() {
+                    @Override public boolean accept(final CoordinateSystemAxis axis) {
+                        return !AxisDirections.isVertical(axis.getDirection());
+                    }
+                });
+                if (cs.getDimension() != 2) break;
+                /*
+                 * Most of the time, the CRS to rebuild will be geodetic. In such case we
known that the
+                 * coordinate system is ellipsoidal because (i.e. the CRS is geographic)
because it was
+                 * a condition verified by horizontalCode(…). A ClassCastException would
be a bug.
+                 */
+                final Map<String, ?> properties = ReferencingUtilities.getPropertiesForModifiedCRS(crs);
+                if (crs instanceof GeodeticCRS) {
+                    return new DefaultGeographicCRS(properties, ((GeodeticCRS) crs).getDatum(),
(EllipsoidalCS) cs);
+                }
+                /*
+                 * In Apache SIS implementation, the Conversion contains the source and target
CRS together with
+                 * a MathTransform.   We need to recreate the same conversion, but without
CRS and MathTransform
+                 * for letting SIS create or associate new ones, which will be two-dimensional
now.
+                 */
+                if (crs instanceof ProjectedCRS) {
+                    final ProjectedCRS  proj = (ProjectedCRS) crs;
+                    final GeographicCRS base = (GeographicCRS) getHorizontalComponent(proj.getBaseCRS());
+                    Conversion fromBase = proj.getConversionFromBase();
+                    fromBase = new DefaultConversion(IdentifiedObjects.getProperties(fromBase),
+                            fromBase.getMethod(), null, fromBase.getParameterValues());
+                    return new DefaultProjectedCRS(properties, base, fromBase, (CartesianCS)
cs);
+                }
+                /*
+                 * If the CRS is neither geographic or projected, then it is engineering.
+                 */
+                return new DefaultEngineeringCRS(properties, ((EngineeringCRS) crs).getDatum(),
cs);
             }
         }
         if (crs instanceof CompoundCRS) {
@@ -953,7 +1002,7 @@ public final class CRS extends Static {
                 }
             }
         }
-        return isHorizontalCRS(crs) ? (SingleCRS) crs : null;
+        return null;
     }
 
     /**
@@ -1006,19 +1055,17 @@ public final class CRS extends Static {
                 }
             } while ((a = !a) == allowCreateEllipsoidal);
         }
-        if (allowCreateEllipsoidal && crs instanceof GeodeticCRS) {
+        if (allowCreateEllipsoidal && horizontalCode(crs) == 3) {
             final CoordinateSystem cs = crs.getCoordinateSystem();
-            if (cs instanceof EllipsoidalCS) {                          // See comment in
isHorizontalCRS(…) method.
-                final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
-                if (i >= 0) {
-                    final CoordinateSystemAxis axis = cs.getAxis(i);
-                    VerticalCRS c = CommonCRS.Vertical.ELLIPSOIDAL.crs();
-                    if (!c.getCoordinateSystem().getAxis(0).equals(axis)) {
-                        final Map<String,?> properties = IdentifiedObjects.getProperties(c);
-                        c = new DefaultVerticalCRS(properties, c.getDatum(), new DefaultVerticalCS(properties,
axis));
-                    }
-                    return c;
+            final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
+            if (i >= 0) {
+                final CoordinateSystemAxis axis = cs.getAxis(i);
+                VerticalCRS c = CommonCRS.Vertical.ELLIPSOIDAL.crs();
+                if (!c.getCoordinateSystem().getAxis(0).equals(axis)) {
+                    final Map<String,?> properties = IdentifiedObjects.getProperties(c);
+                    c = new DefaultVerticalCRS(properties, c.getDatum(), new DefaultVerticalCS(properties,
axis));
                 }
+                return c;
             }
         }
         return null;

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/EllipsoidalHeightCombinerTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/EllipsoidalHeightCombinerTest.java?rev=1811868&r1=1811867&r2=1811868&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/EllipsoidalHeightCombinerTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/metadata/EllipsoidalHeightCombinerTest.java
[UTF-8] Wed Oct 11 18:51:58 2017
@@ -82,11 +82,11 @@ public final strictfp class EllipsoidalH
     public void testGeographicCRS() throws FactoryException {
         final EllipsoidalHeightCombiner services = create();
         final Map<String,String> properties = Collections.singletonMap(CoordinateReferenceSystem.NAME_KEY,
"WGS 84 (4D)");
-        final GeographicCRS horizontal   = HardCodedCRS.WGS84;
-        final GeographicCRS horizontal3D = HardCodedCRS.WGS84_3D;
-        final VerticalCRS   vertical     = HardCodedCRS.ELLIPSOIDAL_HEIGHT;
-        final TemporalCRS   temporal     = HardCodedCRS.TIME;
-        final VerticalCRS   geoidal      = HardCodedCRS.GRAVITY_RELATED_HEIGHT;
+        final GeographicCRS horizontal = HardCodedCRS.WGS84;
+        final GeographicCRS volumetric = HardCodedCRS.WGS84_3D;
+        final VerticalCRS   vertical   = HardCodedCRS.ELLIPSOIDAL_HEIGHT;
+        final TemporalCRS   temporal   = HardCodedCRS.TIME;
+        final VerticalCRS   geoidal    = HardCodedCRS.GRAVITY_RELATED_HEIGHT;
         /*
          * createCompoundCRS(…) should not combine GeographicCRS with non-ellipsoidal height.
          */
@@ -96,12 +96,12 @@ public final strictfp class EllipsoidalH
          * createCompoundCRS(…) should combine GeographicCRS with ellipsoidal height.
          */
         compound = services.createCompoundCRS(properties, horizontal, vertical);
-        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {horizontal3D}, CRS.getSingleComponents(compound).toArray());
+        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {volumetric}, CRS.getSingleComponents(compound).toArray());
         /*
          * createCompoundCRS(…) should combine GeographicCRS with ellipsoidal height and
keep time.
          */
         compound = services.createCompoundCRS(properties, horizontal, vertical, temporal);
-        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {horizontal3D, temporal}, CRS.getSingleComponents(compound).toArray());
+        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {volumetric, temporal}, CRS.getSingleComponents(compound).toArray());
         /*
          * Non-standard feature: accept (VerticalCRS + GeodeticCRS) order.
          * The test below use the reverse order for all axes compared to the previous test.
@@ -128,11 +128,11 @@ public final strictfp class EllipsoidalH
         final EllipsoidalHeightCombiner services = create();
         final GeodeticObjectFactory factory = new GeodeticObjectFactory();
         final Map<String,String> properties = Collections.singletonMap(CoordinateReferenceSystem.NAME_KEY,
"World Mercator (4D)");
-        final ProjectedCRS horizontal   = factory.createProjectedCRS(properties, HardCodedCRS.WGS84,
   HardCodedConversions.MERCATOR, HardCodedCS.PROJECTED);
-        final ProjectedCRS horizontal3D = factory.createProjectedCRS(properties, HardCodedCRS.WGS84_3D,
HardCodedConversions.MERCATOR, HardCodedCS.PROJECTED_3D);
-        final VerticalCRS  vertical     = HardCodedCRS.ELLIPSOIDAL_HEIGHT;
-        final TemporalCRS  temporal     = HardCodedCRS.TIME;
-        final VerticalCRS  geoidal      = HardCodedCRS.GRAVITY_RELATED_HEIGHT;
+        final ProjectedCRS horizontal = factory.createProjectedCRS(properties, HardCodedCRS.WGS84,
   HardCodedConversions.MERCATOR, HardCodedCS.PROJECTED);
+        final ProjectedCRS volumetric = factory.createProjectedCRS(properties, HardCodedCRS.WGS84_3D,
HardCodedConversions.MERCATOR, HardCodedCS.PROJECTED_3D);
+        final VerticalCRS  vertical   = HardCodedCRS.ELLIPSOIDAL_HEIGHT;
+        final TemporalCRS  temporal   = HardCodedCRS.TIME;
+        final VerticalCRS  geoidal    = HardCodedCRS.GRAVITY_RELATED_HEIGHT;
         /*
          * createCompoundCRS(…) should not combine ProjectedCRS with non-ellipsoidal height.
          */
@@ -142,12 +142,12 @@ public final strictfp class EllipsoidalH
          * createCompoundCRS(…) should combine ProjectedCRS with ellipsoidal height.
          */
         compound = services.createCompoundCRS(properties, horizontal, vertical);
-        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {horizontal3D}, CRS.getSingleComponents(compound).toArray());
+        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {volumetric}, CRS.getSingleComponents(compound).toArray());
         /*
          * createCompoundCRS(…) should combine ProjectedCRS with ellipsoidal height and
keep time.
          */
         compound = services.createCompoundCRS(properties, horizontal, vertical, temporal);
-        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {horizontal3D, temporal}, CRS.getSingleComponents(compound).toArray());
+        assertArrayEqualsIgnoreMetadata(new SingleCRS[] {volumetric, temporal}, CRS.getSingleComponents(compound).toArray());
         /*
          * Non-standard feature: accept (VerticalCRS + ProjectedCRS) order.
          */

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java?rev=1811868&r1=1811867&r2=1811868&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
[UTF-8] Wed Oct 11 18:51:58 2017
@@ -93,7 +93,7 @@ public final strictfp class ReferencingU
     }
 
     /**
-     * Tests {@link ReferencingUtilities#getPropertiesForModifiedCRS(IdentifiedObject, String...)}.
+     * Tests {@link ReferencingUtilities#getPropertiesForModifiedCRS(IdentifiedObject)}.
      *
      * @since 0.7
      */

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java?rev=1811868&r1=1811867&r2=1811868&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
[UTF-8] Wed Oct 11 18:51:58 2017
@@ -19,6 +19,7 @@ package org.apache.sis.referencing;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Arrays;
+import java.util.Collections;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -38,6 +39,7 @@ import org.apache.sis.util.Utilities;
 // Test imports
 import org.apache.sis.referencing.operation.HardCodedConversions;
 import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -280,6 +282,26 @@ public final strictfp class CRSTest exte
     }
 
     /**
+     * Tests getting the horizontal and vertical components of a three-dimensional projected
CRS.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testComponentsOfProjectedCRS() {
+        final ProjectedCRS volumetric = new DefaultProjectedCRS(Collections.singletonMap(ProjectedCRS.NAME_KEY,
"3D"),
+                HardCodedCRS.WGS84_3D, HardCodedConversions.MERCATOR, HardCodedCS.PROJECTED_3D);
+
+        assertFalse("isHorizontalCRS", CRS.isHorizontalCRS(volumetric));
+        assertNull("getTemporalComponent", CRS.getTemporalComponent(volumetric));
+        assertNull("getVerticalComponent", CRS.getVerticalComponent(volumetric, false));
+        assertEqualsIgnoreMetadata(HardCodedCRS.ELLIPSOIDAL_HEIGHT, CRS.getVerticalComponent(volumetric,
true));
+        final SingleCRS horizontal = CRS.getHorizontalComponent(volumetric);
+        assertInstanceOf("getHorizontalComponent", ProjectedCRS.class, horizontal);
+        assertEquals("dimension", 2, horizontal.getCoordinateSystem().getDimension());
+        assertTrue("isHorizontalCRS", CRS.isHorizontalCRS(horizontal));
+    }
+
+    /**
      * Tests {@link CRS#getComponentAt(CoordinateReferenceSystem, int, int)}.
      *
      * @since 0.5



Mime
View raw message