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