You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/06/08 19:04:10 UTC
svn commit: r1684222 [1/2] - in /sis/branches/JDK6: ./
core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/
core/sis-metadata/src/main/java/org/apache/sis/io/wkt/
core/sis-metadata/src/test/java/org/apache/sis/io/wkt/
core/sis-metadata/src...
Author: desruisseaux
Date: Mon Jun 8 17:04:09 2015
New Revision: 1684222
URL: http://svn.apache.org/r1684222
Log:
Merge WKT tests and bug fixes from the JDK7 branch.
Added:
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisNames.java
- copied unchanged from r1684221, sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisNames.java
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/WKTFormatTest.txt
- copied unchanged from r1684221, sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/WKTFormatTest.txt
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTFormatTest.java
- copied unchanged from r1684221, sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTFormatTest.java
Removed:
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.txt
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/WKTFormatTest.java
Modified:
sis/branches/JDK6/ (props changed)
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/CharEncodingTest.java
sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticObjectVerifier.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedCS.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultConversionTest.java
sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
sis/branches/JDK6/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
sis/branches/JDK6/core/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
Propchange: sis/branches/JDK6/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Jun 8 17:04:09 2015
@@ -1,4 +1,4 @@
/sis/branches/Android:1430670-1480699
-/sis/branches/JDK7:1394913-1683807
-/sis/branches/JDK8:1584960-1683803
+/sis/branches/JDK7:1394913-1684221
+/sis/branches/JDK8:1584960-1684220
/sis/trunk:1394364-1508466,1519089-1519674
Modified: sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -25,6 +25,7 @@ import org.opengis.parameter.ParameterDe
import org.opengis.referencing.IdentifiedObject;
import org.opengis.referencing.crs.SingleCRS;
import org.opengis.referencing.crs.DerivedCRS;
+import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
@@ -378,6 +379,22 @@ public class ReferencingServices extends
throw moduleNotFound();
}
+ /**
+ * Suggests an abbreviation for the given axis direction. The unit of measurement may be used
+ * for resolving some ambiguities like whether {@link AxisDirection#EAST} is for "x" (Easting)
+ * or "λ" (Longitude).
+ *
+ * @param name The axis name for which to suggest an abbreviation.
+ * @param direction The axis direction for which to suggest an abbreviation.
+ * @param unit The axis unit of measurement, for disambiguation.
+ * @return A suggested abbreviation.
+ *
+ * @since 0.6
+ */
+ public String suggestAbbreviation(final String name, final AxisDirection direction, final Unit<?> unit) {
+ throw moduleNotFound();
+ }
+
/**
* Creates the {@code TOWGS84} element during parsing of a WKT version 1. This is an optional operation:
* this method is allowed to return {@code null} if the "sis-referencing" module is not in the classpath.
Modified: sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -50,11 +50,13 @@ import org.opengis.referencing.operation
import org.apache.sis.measure.Units;
import org.apache.sis.metadata.iso.ImmutableIdentifier;
import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.internal.metadata.AxisNames;
import org.apache.sis.internal.metadata.WKTKeywords;
import org.apache.sis.internal.metadata.VerticalDatumTypes;
import org.apache.sis.internal.metadata.ReferencingServices;
import org.apache.sis.internal.util.LocalizedParseException;
import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.iso.Types;
@@ -261,7 +263,7 @@ final class GeodeticObjectParser extends
if (child instanceof Element) {
keyword = ((Element) child).keyword;
if (keyword != null) {
- if (keyword.equalsIgnoreCase(WKTKeywords.Axis)) return parseAxis (element, SI.METRE, true);
+ if (keyword.equalsIgnoreCase(WKTKeywords.Axis)) return parseAxis (element, false, SI.METRE, true);
if (keyword.equalsIgnoreCase(WKTKeywords.PrimeM)) return parsePrimem (element, NonSI.DEGREE_ANGLE);
if (keyword.equalsIgnoreCase(WKTKeywords.ToWGS84)) return parseToWGS84 (element);
if (keyword.equalsIgnoreCase(WKTKeywords.Spheroid)) return parseSpheroid (element);
@@ -386,15 +388,16 @@ final class GeodeticObjectParser extends
* to make the parser more tolerant to non-100% compliant WKT. Note that AXIS is really the only element without
* such AUTHORITY clause and the EPSG database provides authority code for all axis.</div>
*
- * @param parent The parent element.
- * @param unit The contextual unit, usually {@code SI.METRE} or {@code SI.RADIAN}.
- * @param mandatory {@code true} if the axis is mandatory, or {@code false} if it is optional.
+ * @param parent The parent element.
+ * @param isGeographic {@code true} if the parent element is a geodetic CRS having an ellipsoidal coordinate system.
+ * @param unit The contextual unit, usually {@code SI.METRE} or {@code SI.RADIAN}.
+ * @param mandatory {@code true} if the axis is mandatory, or {@code false} if it is optional.
* @return The {@code "AXIS"} element as a {@link CoordinateSystemAxis} object, or {@code null}
* if the axis was not required and there is no axis object.
* @throws ParseException if the {@code "AXIS"} element can not be parsed.
*/
- private CoordinateSystemAxis parseAxis(final Element parent, final Unit<?> unit, final boolean mandatory)
- throws ParseException
+ private CoordinateSystemAxis parseAxis(final Element parent, final boolean isGeographic,
+ final Unit<?> unit, final boolean mandatory) throws ParseException
{
final Element element;
if (mandatory) {
@@ -405,11 +408,40 @@ final class GeodeticObjectParser extends
return null;
}
}
- final String name = element.pullString("name");
+ String name = CharSequences.trimWhitespaces(element.pullString("name"));
+ if (isGeographic) {
+ /*
+ * The longitude and latitude axis names are explicitly fixed by ISO 19111 to "Geodetic longitude"
+ * and "Geodetic latitude". But ISO 19162 §7.5.3(ii) said that the "Geodetic" part in those names
+ * shall be omitted at WKT formatting time. SIS's DefaultCoordinateSystemAxis.formatTo(Formatter)
+ * method performs this removal, so we apply the reverse operation here.
+ */
+ if (name.equalsIgnoreCase(AxisNames.LATITUDE) || name.equalsIgnoreCase("lat")) {
+ name = AxisNames.GEODETIC_LATITUDE;
+ } else if (name.equalsIgnoreCase(AxisNames.LONGITUDE) || name.equalsIgnoreCase("long") || name.equalsIgnoreCase("lon")) {
+ name = AxisNames.GEODETIC_LONGITUDE;
+ }
+ }
final Element orientation = element.pullVoidElement("orientation");
final AxisDirection direction = Types.forCodeName(AxisDirection.class, orientation.keyword, mandatory);
+ /*
+ * According ISO 19162, the abbreviation should be inserted between parenthesis in the name.
+ * Example: "Easting (E)", "Longitude (L)". If we do not find an abbreviation, then we will
+ * have to guess one since abbreviation is a mandatory part of axis.
+ */
+ final String abbreviation;
+ final int start, end = name.length() - 1;
+ if (end > 1 && name.charAt(end) == ')' && (start = name.lastIndexOf('(', end-1)) >= 0) {
+ abbreviation = CharSequences.trimWhitespaces(name.substring(start + 1, end));
+ name = CharSequences.trimWhitespaces(name.substring(0, start));
+ if (name.isEmpty()) {
+ name = abbreviation;
+ }
+ } else {
+ abbreviation = referencing.suggestAbbreviation(name, direction, unit);
+ }
try {
- return csFactory.createCoordinateSystemAxis(parseAuthorityAndClose(element, name), name, direction, unit);
+ return csFactory.createCoordinateSystemAxis(parseAuthorityAndClose(element, name), abbreviation, direction, unit);
} catch (FactoryException exception) {
throw element.parseFailed(exception);
}
@@ -418,10 +450,10 @@ final class GeodeticObjectParser extends
/**
* Creates an axis with the same name than the abbreviation.
*/
- private CoordinateSystemAxis createAxis(final String abbreviation,
+ private CoordinateSystemAxis createAxis(final String name, final String abbreviation,
final AxisDirection direction, final Unit<?> unit) throws FactoryException
{
- return csFactory.createCoordinateSystemAxis(singletonMap(IdentifiedObject.NAME_KEY, abbreviation),
+ return csFactory.createCoordinateSystemAxis(singletonMap(IdentifiedObject.NAME_KEY, name),
abbreviation, direction, unit);
}
@@ -662,11 +694,11 @@ final class GeodeticObjectParser extends
final String name = element.pullString("name");
final EngineeringDatum datum = parseLocalDatum(element);
final Unit<Length> linearUnit = parseUnit(element, SI.METRE);
- CoordinateSystemAxis axis = parseAxis(element, linearUnit, true);
+ CoordinateSystemAxis axis = parseAxis(element, false, linearUnit, true);
final List<CoordinateSystemAxis> list = new ArrayList<CoordinateSystemAxis>();
do {
list.add(axis);
- axis = parseAxis(element, linearUnit, false);
+ axis = parseAxis(element, false, linearUnit, false);
} while (axis != null);
final CoordinateSystem cs = referencing.createAbstractCS(list.toArray(new CoordinateSystemAxis[list.size()]));
try {
@@ -697,11 +729,11 @@ final class GeodeticObjectParser extends
final Unit<Length> linearUnit = parseUnit (element, SI.METRE);
CartesianCS cs;
CoordinateSystemAxis axis0, axis1 = null, axis2 = null;
- axis0 = parseAxis(element, linearUnit, false);
+ axis0 = parseAxis(element, false, linearUnit, false);
try {
if (axis0 != null) {
- axis1 = parseAxis(element, linearUnit, true);
- axis2 = parseAxis(element, linearUnit, true);
+ axis1 = parseAxis(element, false, linearUnit, true);
+ axis2 = parseAxis(element, false, linearUnit, true);
}
final Map<String,?> properties = parseAuthorityAndClose(element, name);
if (axis0 != null && !isAxisIgnored) {
@@ -733,10 +765,23 @@ final class GeodeticObjectParser extends
final String name = element.pullString("name");
final VerticalDatum datum = parseVertDatum(element);
final Unit<Length> linearUnit = parseUnit(element, SI.METRE);
- CoordinateSystemAxis axis = parseAxis(element, linearUnit, false);
+ CoordinateSystemAxis axis = parseAxis(element, false, linearUnit, false);
try {
if (axis == null || isAxisIgnored) {
- axis = createAxis("h", AxisDirection.UP, linearUnit);
+ String sn = "Height", abbreviation = "h";
+ AxisDirection direction = AxisDirection.UP;
+ final VerticalDatumType type = datum.getVerticalDatumType();
+ if (VerticalDatumType.GEOIDAL.equals(type)) {
+ sn = AxisNames.GRAVITY_RELATED_HEIGHT;
+ abbreviation = "H";
+ } else if (VerticalDatumType.DEPTH.equals(type)) {
+ sn = AxisNames.DEPTH;
+ abbreviation = "D";
+ direction = AxisDirection.DOWN;
+ } else if (VerticalDatumTypes.ELLIPSOIDAL.equals(type)) {
+ sn = AxisNames.ELLIPSOIDAL_HEIGHT;
+ }
+ axis = createAxis(sn, abbreviation, direction, linearUnit);
}
return crsFactory.createVerticalCRS(parseAuthorityAndClose(element, name), datum,
csFactory.createVerticalCS(singletonMap("name", name), axis));
@@ -757,10 +802,10 @@ final class GeodeticObjectParser extends
final String name = element.pullString("name");
final TemporalDatum datum = parseTimeDatum(element);
final Unit<Duration> timeUnit = parseUnit(element, SI.SECOND);
- CoordinateSystemAxis axis = parseAxis(element, timeUnit, false);
+ CoordinateSystemAxis axis = parseAxis(element, false, timeUnit, false);
try {
if (axis == null || isAxisIgnored) {
- axis = createAxis("t", AxisDirection.UP, timeUnit);
+ axis = createAxis("Time", "t", AxisDirection.FUTURE, timeUnit);
}
return crsFactory.createTemporalCRS(parseAuthorityAndClose(element, name), datum,
csFactory.createTimeCS(singletonMap("name", name), axis));
@@ -794,15 +839,15 @@ final class GeodeticObjectParser extends
*/
name = datum.getName();
}
- CoordinateSystemAxis axis0 = parseAxis(element, angularUnit, false);
+ CoordinateSystemAxis axis0 = parseAxis(element, true, angularUnit, false);
CoordinateSystemAxis axis1 = null;
try {
if (axis0 != null) {
- axis1 = parseAxis(element, angularUnit, true);
+ axis1 = parseAxis(element, true, angularUnit, true);
}
if (axis0 == null || isAxisIgnored) {
- axis0 = createAxis("λ", AxisDirection.EAST, angularUnit);
- axis1 = createAxis("φ", AxisDirection.NORTH, angularUnit);
+ axis0 = createAxis(AxisNames.GEODETIC_LONGITUDE, "λ", AxisDirection.EAST, angularUnit);
+ axis1 = createAxis(AxisNames.GEODETIC_LATITUDE, "φ", AxisDirection.NORTH, angularUnit);
}
final Map<String,?> properties = parseAuthorityAndClose(element, name);
return crsFactory.createGeographicCRS(properties, datum,
@@ -833,15 +878,15 @@ final class GeodeticObjectParser extends
final Conversion conversion = parseProjection(element, linearUnit,
(convention == Convention.WKT1_COMMON_UNITS) ? NonSI.DEGREE_ANGLE :
geoCRS.getCoordinateSystem().getAxis(0).getUnit().asType(Angle.class));
- CoordinateSystemAxis axis0 = parseAxis(element, linearUnit, false);
+ CoordinateSystemAxis axis0 = parseAxis(element, false, linearUnit, false);
CoordinateSystemAxis axis1 = null;
try {
if (axis0 != null) {
- axis1 = parseAxis(element, linearUnit, true);
+ axis1 = parseAxis(element, false, linearUnit, true);
}
if (axis0 == null || isAxisIgnored) {
- axis0 = createAxis("x", AxisDirection.EAST, linearUnit);
- axis1 = createAxis("y", AxisDirection.NORTH, linearUnit);
+ axis0 = createAxis(AxisNames.EASTING, "E", AxisDirection.EAST, linearUnit);
+ axis1 = createAxis(AxisNames.NORTHING, "N", AxisDirection.NORTH, linearUnit);
}
final Map<String,?> properties = parseAuthorityAndClose(element, name);
return crsFactory.createProjectedCRS(properties, geoCRS, conversion,
Modified: sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/CharEncodingTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/CharEncodingTest.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/CharEncodingTest.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/CharEncodingTest.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -20,6 +20,7 @@ import org.opengis.referencing.cs.Spheri
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.apache.sis.internal.metadata.AxisNames;
import org.apache.sis.test.mock.CoordinateSystemAxisMock;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -41,10 +42,10 @@ public final strictfp class CharEncoding
*/
@Test
public void testGetAbbreviation() {
- assertAbbreviationEquals("B", new Geographic("Geodetic latitude", "φ"));
- assertAbbreviationEquals("U", new Geocentric("Geocentric latitude", "φ′"));
- assertAbbreviationEquals("L", new Geographic("Geodetic longitude", "λ"));
- assertAbbreviationEquals("V", new Geocentric("Geocentric longitude", "θ"));
+ assertAbbreviationEquals("B", new Geographic(AxisNames.GEODETIC_LATITUDE, "φ"));
+ assertAbbreviationEquals("U", new Geocentric(AxisNames.SPHERICAL_LATITUDE, "φ′"));
+ assertAbbreviationEquals("L", new Geographic(AxisNames.GEODETIC_LONGITUDE, "λ"));
+ assertAbbreviationEquals("V", new Geocentric(AxisNames.SPHERICAL_LONGITUDE, "θ"));
}
/**
Modified: sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -98,8 +98,7 @@ import org.junit.BeforeClass;
org.apache.sis.io.wkt.CharEncodingTest.class,
org.apache.sis.io.wkt.ColorsTest.class,
org.apache.sis.io.wkt.FormatterTest.class,
- org.apache.sis.io.wkt.ElementTest.class,
- org.apache.sis.io.wkt.WKTFormatTest.class
+ org.apache.sis.io.wkt.ElementTest.class
})
public final strictfp class MetadataTestSuite extends TestSuite {
/**
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -16,6 +16,7 @@
*/
package org.apache.sis.internal.referencing;
+import javax.measure.unit.Unit;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
@@ -23,6 +24,7 @@ import org.apache.sis.internal.util.Util
import org.apache.sis.util.Characters;
import org.apache.sis.util.Static;
import org.apache.sis.util.iso.Types;
+import org.apache.sis.measure.Units;
import static org.opengis.referencing.cs.AxisDirection.*;
import static org.apache.sis.util.CharSequences.*;
@@ -516,6 +518,77 @@ public final class AxisDirections extend
}
/**
+ * Returns {@code true} if the given name starts with the given keyword, ignoring case.
+ */
+ private static boolean startsWith(final String name, final String keyword) {
+ return name.regionMatches(true, 0, keyword, 0, keyword.length());
+ }
+
+ /**
+ * Suggests an abbreviation for the given axis direction. The unit of measurement may be used
+ * for resolving some ambiguities like whether {@link AxisDirection#EAST} is for "x" (Easting)
+ * or "λ" (Longitude).
+ *
+ * @param name The axis name for which to suggest an abbreviation.
+ * @param direction The axis direction for which to suggest an abbreviation.
+ * @param unit The axis unit of measurement, for disambiguation.
+ * @return A suggested abbreviation.
+ *
+ * @since 0.6
+ */
+ public static String suggestAbbreviation(final String name, final AxisDirection direction, final Unit<?> unit) {
+ if (name.length() == 1) {
+ return name; // Most common cases are "x", "y", "z", "t", "i" and "j".
+ }
+ if (isCompass(direction)) {
+ /*
+ * NORTH, EAST, SOUTH, WEST and all intercardinal directions (SOUTH_SOUTH_WEST, etc.):
+ * we will use the acronym (e.g. "SE" for SOUTH_EAST), unless the axis is likely to be
+ * a longitude or latitude axis. We detect those later cases by the unit of measurement.
+ */
+ if (!isIntercardinal(direction) && Units.isAngular(unit)) {
+ if (startsWith(name, "Spherical")) {
+ return NORTH.equals(absolute(direction)) ? "φ′" : "θ";
+ } else {
+ return NORTH.equals(absolute(direction)) ? "φ" : "λ";
+ }
+ }
+ } else {
+ /*
+ * All cases other than NORTH, SOUTH, etc. The most common direction is UP, in which case the
+ * abbreviation shall be "H" for Gravity-related height and "h" for ellipsoidal height. Those
+ * two names are specified by ISO 19111, but we will use "Gravity" as a criterion because we
+ * use "h" as the fallback for unknown vertical axis.
+ */
+ if (UP.equals(direction)) {
+ return startsWith(name, "Gravity") ? "H" : startsWith(name, "Geocentric") ? "r": "h";
+ } else if (DOWN.equals(direction)) {
+ return "D"; // "Depth"
+ } else if (isGeocentric(direction)) {
+ // For GEOCENTRIC_X, GEOCENTRIC_Y or GEOCENTRIC_Z, just take the last letter.
+ final String dir = direction.name();
+ return dir.substring(dir.length() - 1).trim();
+ }
+ final AxisDirection a = absolute(direction);
+ if (FUTURE.equals(a)) {
+ return "t";
+ } else if (COLUMN_POSITIVE.equals(a)) {
+ return "i";
+ } else if (ROW_POSITIVE.equals(a)) {
+ return "j";
+ } else if (DISPLAY_RIGHT.equals(a)) {
+ return "x";
+ } else if (DISPLAY_UP.equals(a)) {
+ return "y";
+ } else if (OTHER.equals(a)) {
+ return "z"; // Arbitrary abbreviation, may change in any future SIS version.
+ }
+ }
+ final String id = direction.identifier(); // UML identifier, or null if none.
+ return camelCaseToAcronym(id != null ? id : direction.name()).toString().intern();
+ }
+
+ /**
* Builds a coordinate system name from the given array of axes.
* This method expects a {@code StringBuilder} pre-filled with the coordinate system name.
* The axis directions and abbreviations will be appended after the CS name.
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -34,6 +34,7 @@ import org.opengis.referencing.crs.Tempo
import org.opengis.referencing.crs.VerticalCRS;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
@@ -545,6 +546,23 @@ public final class ServicesForMetadata e
}
/**
+ * Suggests an abbreviation for the given axis direction. The unit of measurement may be used
+ * for resolving some ambiguities like whether {@link AxisDirection#EAST} is for "x" (Easting)
+ * or "λ" (Longitude).
+ *
+ * @param name The axis name for which to suggest an abbreviation.
+ * @param direction The axis direction for which to suggest an abbreviation.
+ * @param unit The axis unit of measurement, for disambiguation.
+ * @return A suggested abbreviation.
+ *
+ * @since 0.6
+ */
+ @Override
+ public String suggestAbbreviation(final String name, final AxisDirection direction, final Unit<?> unit) {
+ return AxisDirections.suggestAbbreviation(name, direction, unit);
+ }
+
+ /**
* Creates the {@code TOWGS84} element during parsing of a WKT version 1.
*
* @param values The 7 Bursa-Wolf parameter values.
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -34,6 +34,7 @@ import org.opengis.referencing.cs.Coordi
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.VerticalCRS;
+import org.apache.sis.internal.metadata.AxisNames;
import org.apache.sis.metadata.iso.extent.Extents;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.referencing.datum.DefaultEllipsoid;
@@ -277,7 +278,7 @@ final class StandardDefinitions {
final AxisDirection dir;
switch (code) {
case 108: // Used in Ellipsoidal 3D.
- case 106: name = "Geodetic latitude";
+ case 106: name = AxisNames.GEODETIC_LATITUDE;
abrv = "φ";
unit = NonSI.DEGREE_ANGLE;
dir = AxisDirection.NORTH;
@@ -286,7 +287,7 @@ final class StandardDefinitions {
rm = RangeMeaning.EXACT;
break;
case 109: // Used in Ellipsoidal 3D.
- case 107: name = "Geodetic longitude";
+ case 107: name = AxisNames.GEODETIC_LONGITUDE;
abrv = "λ";
unit = NonSI.DEGREE_ANGLE;
dir = AxisDirection.EAST;
@@ -294,27 +295,27 @@ final class StandardDefinitions {
max = Longitude.MAX_VALUE;
rm = RangeMeaning.WRAPAROUND;
break;
- case 110: name = "Ellipsoidal height";
+ case 110: name = AxisNames.ELLIPSOIDAL_HEIGHT;
abrv = "h";
dir = AxisDirection.UP;
break;
- case 114: name = "Gravity-related height";
+ case 114: name = AxisNames.GRAVITY_RELATED_HEIGHT;
abrv = "H";
dir = AxisDirection.UP;
break;
- case 113: name = "Depth";
+ case 113: name = AxisNames.DEPTH;
abrv = "D";
dir = AxisDirection.DOWN;
break;
- case 115: name = "Geocentric X";
+ case 115: name = AxisNames.GEOCENTRIC_X;
abrv = "X";
dir = AxisDirection.GEOCENTRIC_X;
break;
- case 116: name = "Geocentric Y";
+ case 116: name = AxisNames.GEOCENTRIC_Y;
abrv = "Y";
dir = AxisDirection.GEOCENTRIC_Y;
break;
- case 117: name = "Geocentric Z";
+ case 117: name = AxisNames.GEOCENTRIC_Z;
abrv = "Z";
dir = AxisDirection.GEOCENTRIC_Z;
break;
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -38,6 +38,7 @@ import org.opengis.referencing.cs.Spheri
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.internal.metadata.AxisNames;
import org.apache.sis.internal.metadata.WKTKeywords;
import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.internal.referencing.ReferencingUtilities;
@@ -143,6 +144,9 @@ public class DefaultCoordinateSystemAxis
* <p>Keys in this map are names <strong>in lower cases</strong>.
* Values are any object that allow us to differentiate latitude from longitude.</p>
*
+ * <p>Similar strings appear in {@link #formatTo(Formatter)} and
+ * {@code org.apache.sis.io.wkt.GeodeticObjectParser.parseAxis(…)}.</p>
+ *
* @see #isHeuristicMatchForName(String)
*/
private static final Map<String,Object> ALIASES = new HashMap<String,Object>(12);
@@ -174,8 +178,8 @@ public class DefaultCoordinateSystemAxis
* @see #isHeuristicMatchForNameXY(String, String)
*/
private static final String[] ALIASES_XY = {
- "Easting", "Northing",
- "Westing", "Southing"
+ AxisNames.EASTING, AxisNames.NORTHING,
+ AxisNames.WESTING, AxisNames.SOUTHING
};
/**
@@ -526,7 +530,9 @@ public class DefaultCoordinateSystemAxis
/**
* Returns the meaning of axis value range specified by the {@linkplain #getMinimumValue() minimum}
- * and {@linkplain #getMaximumValue() maximum} values.
+ * and {@linkplain #getMaximumValue() maximum} values. If there is no minimum and maximum values
+ * (i.e. if those values are {@linkplain Double#NEGATIVE_INFINITY negative infinity} and
+ * {@linkplain Double#POSITIVE_INFINITY positive infinity} respectively), then this method returns {@code null}.
*
* @return The meaning of axis value range, or {@code null} if unspecified.
*/
@@ -795,11 +801,13 @@ public class DefaultCoordinateSystemAxis
name = IdentifiedObjects.getName(this, null);
}
if (name != null && !isInternal) {
- if (name.equalsIgnoreCase("Geodetic latitude")) {
- name = "Latitude"; // ISO 19162 §7.5.3(ii)
- } else if (name.equalsIgnoreCase("Geodetic longitude")) {
- name = "Longitude";
+ if (name.equalsIgnoreCase(AxisNames.GEODETIC_LATITUDE)) {
+ name = AxisNames.LATITUDE; // ISO 19162 §7.5.3(ii)
+ } else if (name.equalsIgnoreCase(AxisNames.GEODETIC_LONGITUDE)) {
+ name = AxisNames.LONGITUDE;
}
+ // Note: the converse of this operation is done in
+ // org.apache.sis.io.wkt.GeodeticObjectParser.parseAxis(…).
}
}
/*
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -140,15 +140,23 @@ class AbstractSingleOperation extends Ab
*
* <p>This constructor is for {@link DefaultConversion} usage only,
* in order to create a "real" conversion from a defining conversion.</p>
+ *
+ * @param definition The defining conversion.
+ * @param sourceCRS The source CRS.
+ * @param targetCRS The target CRS.
+ * @param transform The math transform, optionally with the parameters used for creating it.
+ * Bundled in a {@code Map.Entry} as an ugly workaround for RFE #4093999 in Java bug database
+ * ("Relax constraint on placement of this()/super() call in constructors").
*/
AbstractSingleOperation(final SingleOperation definition,
final CoordinateReferenceSystem sourceCRS,
final CoordinateReferenceSystem targetCRS,
- final MathTransform transform)
+ final Map.Entry<ParameterValueGroup,MathTransform> transform)
{
- super(definition, sourceCRS, targetCRS, transform);
+ super(definition, sourceCRS, targetCRS, transform.getValue());
method = definition.getMethod();
- parameters = getParameterValues(definition);
+ final ParameterValueGroup p = transform.getKey();
+ parameters = (p != null) ? p : getParameterValues(definition);
}
/**
@@ -337,8 +345,9 @@ class AbstractSingleOperation extends Ab
* {@code null} (in conformance with {@link #parameters} contract).
*/
private static ParameterValueGroup getParameterValues(final SingleOperation operation) {
- return (operation instanceof AbstractSingleOperation) ?
- ((AbstractSingleOperation) operation).parameters : operation.getParameterValues();
+ return (operation instanceof AbstractSingleOperation)
+ ? ((AbstractSingleOperation) operation).parameters // Null if inferred from MathTransform
+ : operation.getParameterValues();
}
/**
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -17,6 +17,7 @@
package org.apache.sis.referencing.operation;
import java.util.Map;
+import java.util.AbstractMap;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.measure.converter.ConversionException;
@@ -386,11 +387,19 @@ public class DefaultConversion extends A
/**
* Creates the math transform to be given to the sub-class constructor.
- * This method is a workaround for RFE #4093999 in Sun's bug database
+ * This method is a workaround for RFE #4093999 in Java bug database
* ("Relax constraint on placement of this()/super() call in constructors").
+ *
+ * <p>This method may also return the parameters used for creating the math transform because those parameters
+ * may have been augmented with the semi-major and semi-minor axis lengths. Since those parameter values have
+ * been set on a clone of {@code definition.getParameterValues()}, those values are lost (ignoring MathTransform
+ * internal) if we do not return them here.</p>
+ *
+ * @return The math transform, optionally with the parameters used for creating it.
+ * Bundled in a {@code Map.Entry} as an ugly workaround for RFE #4093999.
*/
@Workaround(library="JDK", version="1.7")
- private static MathTransform createMathTransform(
+ private static Map.Entry<ParameterValueGroup,MathTransform> createMathTransform(
final Conversion definition,
final CoordinateReferenceSystem sourceCRS,
final CoordinateReferenceSystem targetCRS,
@@ -398,6 +407,7 @@ public class DefaultConversion extends A
{
final int interpDim = ReferencingUtilities.getDimension(getInterpolationCRS(definition));
MathTransform mt = definition.getMathTransform();
+ final Map.Entry<ParameterValueGroup,MathTransform> pair;
if (mt == null) {
/*
* If the user did not specified explicitely a MathTransform, we will need to create it
@@ -412,7 +422,9 @@ public class DefaultConversion extends A
throw new IllegalArgumentException(Errors.format(Errors.Keys.UnspecifiedParameterValues));
}
mt = factory.createBaseToDerived(sourceCRS, parameters, targetCRS.getCoordinateSystem());
+ pair = new AbstractMap.SimpleEntry<ParameterValueGroup,MathTransform>(parameters, mt);
} else {
+ pair = new AbstractMap.SimpleEntry<ParameterValueGroup,MathTransform>(null, mt);
/*
* If the user specified explicitely a MathTransform, we may still need to swap or scale axes.
* If this conversion is a defining conversion (which is usually the case when creating a new
@@ -434,13 +446,15 @@ public class DefaultConversion extends A
*/
mt = swapAndScaleAxes(mt, sourceCRS, mtSource, interpDim, true, factory);
mt = swapAndScaleAxes(mt, mtTarget, targetCRS, interpDim, false, factory);
- return mt; // Skip createPassThroughTransform(…) since it was handled by swapAndScaleAxes(…).
+ pair.setValue(mt);
+ return pair; // Skip createPassThroughTransform(…) since it was handled by swapAndScaleAxes(…).
}
}
if (interpDim != 0) {
mt = factory.createPassThroughTransform(interpDim, mt, 0);
}
- return mt;
+ pair.setValue(mt);
+ return pair;
}
/**
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -469,6 +469,12 @@ public class DefaultMathTransformFactory
* The {@code OperationMethod} instance used by this constructor can be obtained by a call to
* {@link #getLastMethodUsed()}.
*
+ * <div class="section">Modification of given parameters</div>
+ * If this method needs to set the values of {@code "semi_major"} and {@code "semi_minor"} parameters,
+ * then it sets those values directly on the given {@code parameters} instance – not on a clone – for
+ * allowing the caller to get back the complete parameter values.
+ * However this method only fills missing values, it never modify existing values.
+ *
* @param baseCRS The source coordinate reference system.
* @param parameters The parameter values for the transform.
* @param derivedCS The target coordinate system.
Modified: sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -18,6 +18,7 @@ package org.apache.sis.geometry;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.DirectPosition;
+import org.apache.sis.internal.metadata.AxisNames;
import org.apache.sis.math.MathFunctions;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
@@ -446,7 +447,7 @@ public strictfp class GeneralEnvelopeTes
} catch (IllegalArgumentException ex) {
// This is the expected exception.
final String message = ex.getMessage();
- assertTrue(message, message.contains("Geodetic latitude"));
+ assertTrue(message, message.contains(AxisNames.GEODETIC_LATITUDE));
}
// Verify that the envelope still have the old values.
assertEnvelopeEquals(e, 3, -5, -8, 2);
@@ -467,7 +468,7 @@ public strictfp class GeneralEnvelopeTes
} catch (IllegalArgumentException ex) {
// This is the expected exception.
final String message = ex.getMessage();
- assertTrue(message, message.contains("Geodetic latitude"));
+ assertTrue(message, message.contains(AxisNames.GEODETIC_LATITUDE));
}
// Verify that the envelope still have the old values.
assertEnvelopeEquals(e, 2, -5, 3, 2);
@@ -494,7 +495,7 @@ public strictfp class GeneralEnvelopeTes
} catch (IllegalStateException ex) {
// This is the expected exception.
final String message = ex.getMessage();
- assertTrue(message, message.contains("Geodetic latitude"));
+ assertTrue(message, message.contains(AxisNames.GEODETIC_LATITUDE));
}
/*
* Verify that the envelope values are unchanged.
Modified: sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/AxisDirectionsTest.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -16,6 +16,10 @@
*/
package org.apache.sis.internal.referencing;
+import java.lang.reflect.Field;
+import javax.measure.unit.SI;
+import javax.measure.unit.NonSI;
+import javax.measure.unit.Unit;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
@@ -361,6 +365,65 @@ public final strictfp class AxisDirectio
}
/**
+ * Tests {@link AxisDirections#suggestAbbreviation(String, AxisDirection, Unit)}.
+ *
+ * @since 0.6
+ */
+ @Test
+ public void testSuggestAbbreviation() {
+ assertEquals("x", AxisDirections.suggestAbbreviation("x", EAST, SI.METRE));
+ assertEquals("λ", AxisDirections.suggestAbbreviation("Geodetic longitude", EAST, NonSI.DEGREE_ANGLE));
+ assertEquals("φ", AxisDirections.suggestAbbreviation("Geodetic latitude", NORTH, NonSI.DEGREE_ANGLE));
+ assertEquals("θ", AxisDirections.suggestAbbreviation("Spherical longitude", EAST, NonSI.DEGREE_ANGLE));
+ assertEquals("φ′", AxisDirections.suggestAbbreviation("Spherical latitude", NORTH, NonSI.DEGREE_ANGLE));
+ assertEquals("h", AxisDirections.suggestAbbreviation("Ellipsoidal height", UP, SI.METRE));
+ assertEquals("H", AxisDirections.suggestAbbreviation("Gravity-related height", UP, SI.METRE));
+ assertEquals("r", AxisDirections.suggestAbbreviation("Geocentric radius", UP, SI.METRE));
+ assertEquals("X", AxisDirections.suggestAbbreviation("not needed", GEOCENTRIC_X, SI.METRE));
+ assertEquals("Y", AxisDirections.suggestAbbreviation("not needed", GEOCENTRIC_Y, SI.METRE));
+ assertEquals("Z", AxisDirections.suggestAbbreviation("not needed", GEOCENTRIC_Z, SI.METRE));
+ assertEquals("D", AxisDirections.suggestAbbreviation("not needed", DOWN, SI.METRE));
+ assertEquals("t", AxisDirections.suggestAbbreviation("not needed", FUTURE, NonSI.DAY));
+ assertEquals("i", AxisDirections.suggestAbbreviation("not needed", COLUMN_NEGATIVE, Unit.ONE));
+ assertEquals("j", AxisDirections.suggestAbbreviation("not needed", ROW_NEGATIVE, Unit.ONE));
+ assertEquals("x", AxisDirections.suggestAbbreviation("not needed", DISPLAY_RIGHT, Unit.ONE));
+ assertEquals("y", AxisDirections.suggestAbbreviation("not needed", DISPLAY_DOWN, Unit.ONE));
+ assertEquals("N", AxisDirections.suggestAbbreviation("not needed", NORTH, SI.METRE));
+ assertEquals("S", AxisDirections.suggestAbbreviation("not needed", SOUTH, SI.METRE));
+ assertEquals("E", AxisDirections.suggestAbbreviation("not needed", EAST, SI.METRE));
+ assertEquals("W", AxisDirections.suggestAbbreviation("not needed", WEST, SI.METRE));
+ assertEquals("NE", AxisDirections.suggestAbbreviation("not needed", NORTH_EAST, SI.METRE));
+ assertEquals("NW", AxisDirections.suggestAbbreviation("not needed", NORTH_WEST, SI.METRE));
+ assertEquals("SE", AxisDirections.suggestAbbreviation("not needed", SOUTH_EAST, SI.METRE));
+ assertEquals("SW", AxisDirections.suggestAbbreviation("not needed", SOUTH_WEST, SI.METRE));
+ assertEquals("SSE", AxisDirections.suggestAbbreviation("not needed", SOUTH_SOUTH_EAST, SI.METRE));
+ assertEquals("NNW", AxisDirections.suggestAbbreviation("not needed", NORTH_NORTH_WEST, SI.METRE));
+ assertEquals("ENE", AxisDirections.suggestAbbreviation("not needed", EAST_NORTH_EAST, SI.METRE));
+ }
+
+ /**
+ * Verifies that the abbreviations used in {@link HardCodedAxes} constants are consistent with the abbreviations
+ * suggested by {@link AxisDirections#suggestAbbreviation(String, AxisDirection, Unit)}. Note that a failure in
+ * this verification does not necessarily means that the {@code suggestAbbreviation(…)}. It could also be the
+ * hard-coded constant which need a revision, or we may decide that the different abbreviations are intended and
+ * should not be compared.
+ *
+ * @throws IllegalAccessException should never happen since we inspect only for public fields.
+ *
+ * @since 0.6
+ */
+ @Test
+ public void verifyAbbreviationConsistency() throws IllegalAccessException {
+ for (final Field field : HardCodedAxes.class.getFields()) {
+ if (CoordinateSystemAxis.class.isAssignableFrom(field.getType())) {
+ final CoordinateSystemAxis axis = (CoordinateSystemAxis) field.get(null);
+ assertEquals(field.getName(), axis.getAbbreviation(), AxisDirections.suggestAbbreviation(
+ axis.getName().getCode(), axis.getDirection(), axis.getUnit()));
+ }
+ }
+ }
+
+ /**
* Tests {@link AxisDirections#appendTo(StringBuilder, CoordinateSystemAxis[])}.
*
* @since 0.6
Modified: sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java?rev=1684222&r1=1684221&r2=1684222&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java [UTF-8] Mon Jun 8 17:04:09 2015
@@ -20,15 +20,22 @@ import java.util.Date;
import java.util.Iterator;
import java.text.ParsePosition;
import java.text.ParseException;
+import javax.measure.unit.SI;
+import javax.measure.unit.NonSI;
+import javax.measure.unit.Unit;
import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.cs.*;
import org.opengis.referencing.crs.*;
import org.opengis.referencing.datum.*;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterValueGroup;
+import org.apache.sis.internal.metadata.AxisNames;
import org.apache.sis.test.DependsOnMethod;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
import org.junit.Test;
-import static org.junit.Assert.*;
+import static org.apache.sis.test.ReferencingAssert.*;
/**
@@ -39,7 +46,16 @@ import static org.junit.Assert.*;
* @version 0.6
* @module
*/
-@DependsOn(MathTransformParserTest.class)
+@DependsOn({
+ MathTransformParserTest.class,
+ org.apache.sis.referencing.crs.DefaultGeocentricCRSTest.class,
+ org.apache.sis.referencing.crs.DefaultGeographicCRSTest.class,
+ org.apache.sis.referencing.crs.DefaultProjectedCRSTest.class,
+ org.apache.sis.referencing.crs.DefaultVerticalCRSTest.class,
+ org.apache.sis.referencing.crs.DefaultTemporalCRSTest.class,
+ org.apache.sis.referencing.crs.DefaultCompoundCRSTest.class,
+ org.apache.sis.internal.referencing.AxisDirectionsTest.class
+})
public final strictfp class GeodeticObjectParserTest extends TestCase {
/**
* The parser to use for the test.
@@ -51,7 +67,7 @@ public final strictfp class GeodeticObje
*
* @throws ParseException if an error occurred during the parsing.
*/
- private Object parse(final String text) throws ParseException {
+ private <T> T parse(final Class<T> type, final String text) throws ParseException {
if (parser == null) {
parser = new GeodeticObjectParser();
}
@@ -59,15 +75,369 @@ public final strictfp class GeodeticObje
final Object obj = parser.parseObject(text, position);
assertEquals("errorIndex", -1, position.getErrorIndex());
assertEquals("index", text.length(), position.getIndex());
- return obj;
+ assertInstanceOf("GeodeticObjectParser.parseObject", type, obj);
+ return type.cast(obj);
}
/**
- * Asserts that the name of the given object is equals to the given string.
+ * Uses a new parser for the given convention.
*/
- private static void assertNameEquals(final String expected, final IdentifiedObject object) {
+ private void setConvention(final Convention convention, final boolean isAxisIgnored) {
+ final GeodeticObjectParser p = parser;
+ parser = new GeodeticObjectParser(p.symbols, convention, isAxisIgnored, p.errorLocale, null);
+ }
+
+ /**
+ * Asserts that the name and (optionally) the EPSG identifier of the given object
+ * are equal to the given strings.
+ *
+ * @param name The expected name.
+ * @param epsg The expected EPSG identifier, or {@code 0} if the object shall have no identifier.
+ */
+ static void assertNameAndIdentifierEqual(final String name, final int epsg, final IdentifiedObject object) {
final String message = object.getClass().getSimpleName();
- assertEquals(message, expected, object.getName().getCode());
+ assertEquals(message, name, object.getName().getCode());
+ assertEpsgIdentifierEquals(epsg, object.getIdentifiers());
+ }
+
+ /**
+ * Asserts that the given axis is a longitude axis. This method expects the name to be
+ * <cite>"Geodetic longitude"</cite> even if the WKT string contained a different name,
+ * because {@link GeodeticObjectParser} should have done the replacement.
+ */
+ private static void assertLongitudeAxisEquals(final CoordinateSystemAxis axis) {
+ assertAxisEquals(AxisNames.GEODETIC_LONGITUDE, "λ", AxisDirection.EAST, -180, +180, NonSI.DEGREE_ANGLE, RangeMeaning.WRAPAROUND, axis);
+ }
+
+ /**
+ * Asserts that the given axis is a latitude axis. This method expects the name to be
+ * <cite>"Geodetic latitude"</cite> even if the WKT string contained a different name,
+ * because {@link GeodeticObjectParser} should have done the replacement.
+ */
+ private static void assertLatitudeAxisEquals(final CoordinateSystemAxis axis) {
+ assertAxisEquals(AxisNames.GEODETIC_LATITUDE, "φ", AxisDirection.NORTH, -90, +90, NonSI.DEGREE_ANGLE, RangeMeaning.EXACT, axis);
+ }
+
+ /**
+ * Asserts the given axis is an axis of the given name without minimum and maximum values.
+ */
+ private static void assertUnboundedAxisEquals(final String name, final String abbreviation,
+ final AxisDirection direction, final Unit<?> unit, final CoordinateSystemAxis axis)
+ {
+ assertAxisEquals(name, abbreviation, direction, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, unit, null, axis);
+ }
+
+ /**
+ * Verifies that the axes of the coordinate system are those of a projected CRS, in metres.
+ */
+ private static void verifyProjectedCS(final CartesianCS cs) {
+ assertEquals("dimension", 2, cs.getDimension());
+ assertUnboundedAxisEquals("Easting", "E", AxisDirection.EAST, SI.METRE, cs.getAxis(0));
+ assertUnboundedAxisEquals("Northing", "N", AxisDirection.NORTH, SI.METRE, cs.getAxis(1));
+ }
+
+ /**
+ * Tests the parsing of a geocentric CRS from a WKT 1 string. The parser
+ * shall replace the OGC 01-009 axis directions (OTHER, EAST, NORTH) by
+ * ISO 19111 axis directions (Geocentric X, Geocentric Y, Geocentric Z).
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ public void testGeocentricCRS() throws ParseException {
+ final GeocentricCRS crs = parse(GeocentricCRS.class,
+ "GEOCCS[“Geocentric”,\n" +
+ " DATUM[“World Geodetic System 1984”,\n" +
+ " SPHEROID[“WGS84”, 6378137.0, 298.257223563, AUTHORITY[“EPSG”, “7030”]],\n" +
+ " AUTHORITY[“EPSG”, “6326”]],\n" +
+ " PRIMEM[“Greenwich”, 0.0, AUTHORITY[“EPSG”, “8901”]],\n" +
+ " UNIT[“metre”, 1.0],\n" +
+ " AXIS[“X”, OTHER],\n" +
+ " AXIS[“Y”, EAST],\n" +
+ " AXIS[“Z”, NORTH]]");
+
+ assertNameAndIdentifierEqual("Geocentric", 0, crs);
+
+ final GeodeticDatum datum = crs.getDatum();
+ assertNameAndIdentifierEqual("World Geodetic System 1984", 6326, datum);
+ assertNameAndIdentifierEqual("Greenwich", 8901, datum.getPrimeMeridian());
+
+ final Ellipsoid ellipsoid = datum.getEllipsoid();
+ assertNameAndIdentifierEqual("WGS84", 7030, ellipsoid);
+ assertEquals("semiMajor", 6378137, ellipsoid.getSemiMajorAxis(), STRICT);
+ assertEquals("inverseFlattening", 298.257223563, ellipsoid.getInverseFlattening(), STRICT);
+
+ // Verify that the OGC 01-009 axes have been relaced by ISO 19111 axes.
+ final CartesianCS cs = (CartesianCS) crs.getCoordinateSystem();
+ assertEquals("dimension", 3, cs.getDimension());
+ assertUnboundedAxisEquals(AxisNames.GEOCENTRIC_X, "X", AxisDirection.GEOCENTRIC_X, SI.METRE, cs.getAxis(0));
+ assertUnboundedAxisEquals(AxisNames.GEOCENTRIC_Y, "Y", AxisDirection.GEOCENTRIC_Y, SI.METRE, cs.getAxis(1));
+ assertUnboundedAxisEquals(AxisNames.GEOCENTRIC_Z, "Z", AxisDirection.GEOCENTRIC_Z, SI.METRE, cs.getAxis(2));
+ }
+
+ /**
+ * Tests the parsing of a geographic CRS from a WKT 1 string using (longitude, latitude) axis order.
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ public void testGeographicCRS() throws ParseException {
+ verifyGeographicCRS(0, parse(GeographicCRS.class,
+ " GEOGCS[“WGS 84”,\n" +
+ " DATUM[“World Geodetic System 1984”,\n" +
+ " SPHEROID[“WGS84”, 6378137.0, 298.257223563]],\n" +
+ " PRIMEM[“Greenwich”, 0.0],\n" +
+ " UNIT[“degree”, 0.017453292519943295],\n" +
+ " AXIS[“Longitude”, EAST],\n" +
+ " AXIS[“Latitude”, NORTH]]"));
+ }
+
+ /**
+ * Tests the parsing of a geographic CRS from a WKT 1 string using (latitude, longitude) axis order.
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ @DependsOnMethod("testGeographicCRS")
+ public void testAxisSwapping() throws ParseException {
+ verifyGeographicCRS(1, parse(GeographicCRS.class,
+ " GEOGCS[“WGS 84”,\n" +
+ " DATUM[“World Geodetic System 1984”,\n" +
+ " SPHEROID[“WGS84”, 6378137.0, 298.257223563]],\n" +
+ " PRIMEM[“Greenwich”, 0.0],\n" +
+ " UNIT[“degree”, 0.017453292519943295],\n" +
+ " AXIS[“Latitude”, NORTH],\n" +
+ " AXIS[“Longitude”, EAST]]"));
+ }
+
+ /**
+ * Tests the parsing of a geographic CRS from a WKT 1 string that does not declare explicitly the axes.
+ *
+ * @throws ParseException if the parsing failed.
+ *
+ * @see #testImplicitAxesInSeconds()
+ */
+ @Test
+ @DependsOnMethod("testGeographicCRS")
+ public void testImplicitAxes() throws ParseException {
+ verifyGeographicCRS(0, parse(GeographicCRS.class,
+ " GEOGCS[“WGS 84”,\n" +
+ " DATUM[“World Geodetic System 1984”,\n" +
+ " SPHEROID[“WGS84”, 6378137.0, 298.257223563]],\n" +
+ " PRIMEM[“Greenwich”, 0.0],\n" +
+ " UNIT[“degree”, 0.017453292519943295]]"));
+ }
+
+ /**
+ * Implementation of {@link #testGeographicCRS()} and {@link #testAxisSwapping()}.
+ * This test expects no {@code AUTHORITY} element on any component.
+ *
+ * @param swap 1 if axes are expected to be swapped, or 0 otherwise.
+ */
+ private void verifyGeographicCRS(final int swap, final GeographicCRS crs) throws ParseException {
+ assertNameAndIdentifierEqual("WGS 84", 0, crs);
+
+ final GeodeticDatum datum = crs.getDatum();
+ assertNameAndIdentifierEqual("World Geodetic System 1984", 0, datum);
+ assertNameAndIdentifierEqual("Greenwich", 0, datum.getPrimeMeridian());
+
+ final Ellipsoid ellipsoid = datum.getEllipsoid();
+ assertNameAndIdentifierEqual("WGS84", 0, ellipsoid);
+ assertEquals("semiMajor", 6378137, ellipsoid.getSemiMajorAxis(), STRICT);
+ assertEquals("inverseFlattening", 298.257223563, ellipsoid.getInverseFlattening(), STRICT);
+
+ final EllipsoidalCS cs = crs.getCoordinateSystem();
+ assertEquals("dimension", 2, cs.getDimension());
+ assertLongitudeAxisEquals(cs.getAxis(0 ^ swap));
+ assertLatitudeAxisEquals (cs.getAxis(1 ^ swap));
+ }
+
+ /**
+ * Tests the parsing of a projected CRS from a WKT 1 string.
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ @DependsOnMethod("testGeographicCRS")
+ public void testProjectedCRS() throws ParseException {
+ final ProjectedCRS crs = parse(ProjectedCRS.class,
+ "PROJCS[“Mercator test”,\n" +
+ " GEOGCS[“WGS 84”,\n" +
+ " DATUM[“World Geodetic System 1984”,\n" +
+ " SPHEROID[“WGS84”, 6378137.0, 298.257223563]],\n" +
+ " PRIMEM[“Greenwich”, 0.0],\n" +
+ " UNIT[“degree”, 0.017453292519943295],\n" +
+ " AXIS[“Longitude”, EAST],\n" +
+ " AXIS[“Latitude”, NORTH]],\n" +
+ " PROJECTION[“Mercator_1SP”],\n" +
+ " PARAMETER[“central_meridian”, -20.0],\n" +
+ " PARAMETER[“scale_factor”, 1.0],\n" +
+ " PARAMETER[“false_easting”, 500000.0],\n" +
+ " PARAMETER[“false_northing”, 0.0],\n" +
+ " UNIT[“metre”, 1.0],\n" +
+ " AXIS[“Easting”, EAST],\n" +
+ " AXIS[“Northing”, NORTH]]");
+
+ assertNameAndIdentifierEqual("Mercator test", 0, crs);
+ verifyProjectedCS(crs.getCoordinateSystem());
+ verifyGeographicCRS(0, crs.getBaseCRS());
+
+ final GeodeticDatum datum = crs.getDatum();
+ assertNameAndIdentifierEqual("World Geodetic System 1984", 0, datum);
+ assertNameAndIdentifierEqual("Greenwich", 0, datum.getPrimeMeridian());
+
+ final Ellipsoid ellipsoid = datum.getEllipsoid();
+ assertNameAndIdentifierEqual("WGS84", 0, ellipsoid);
+ assertEquals("semiMajor", 6378137, ellipsoid.getSemiMajorAxis(), STRICT);
+ assertEquals("inverseFlattening", 298.257223563, ellipsoid.getInverseFlattening(), STRICT);
+
+ assertEquals("Mercator (variant A)", crs.getConversionFromBase().getMethod().getName().getCode());
+ final ParameterValueGroup param = crs.getConversionFromBase().getParameterValues();
+ assertEquals("semi_major", 6378137.0, param.parameter("semi_major" ).doubleValue(), STRICT);
+ assertEquals("semi_minor", 6356752.3, param.parameter("semi_minor" ).doubleValue(), 0.1);
+ assertEquals("central_meridian", -20.0, param.parameter("central_meridian").doubleValue(), STRICT);
+ assertEquals("scale_factor", 1.0, param.parameter("scale_factor" ).doubleValue(), STRICT);
+ assertEquals("false_easting", 500000.0, param.parameter("false_easting" ).doubleValue(), STRICT);
+ assertEquals("false_northing", 0.0, param.parameter("false_northing" ).doubleValue(), STRICT);
+ }
+
+ /**
+ * Tests parsing of a CRS using a prime meridian other than Greenwich. The result depends on whether
+ * the parsing is standard compliant or if the parsing use {@link Convention#WKT1_COMMON_UNITS}.
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ @DependsOnMethod("testGeographicCRS")
+ public void testNonGreenwichMeridian() throws ParseException {
+ String wkt = "GEOGCS[“NTF (Paris)”,\n" +
+ " DATUM[“Nouvelle Triangulation Française (Paris)”,\n" +
+ " SPHEROID[“Clarke 1880 (IGN)”, 6378249.2, 293.4660212936269]],\n" +
+ " PRIMEM[“Paris”, 2.5969213, AUTHORITY[“EPSG”, “8903”]],\n" +
+ " UNIT[“grade”, 0.015707963267948967],\n" +
+ " AXIS[“Latitude”, NORTH],\n" +
+ " AXIS[“Longitude”, EAST]]";
+
+ GeographicCRS crs = parse(GeographicCRS.class, wkt);
+ assertNameAndIdentifierEqual("NTF (Paris)", 0, crs);
+ PrimeMeridian pm = verifyNTF(crs.getDatum());
+ assertEquals("angularUnit", NonSI.GRADE, pm.getAngularUnit());
+ assertEquals("greenwichLongitude", 2.5969213, pm.getGreenwichLongitude(), STRICT);
+ EllipsoidalCS cs = crs.getCoordinateSystem();
+ assertEquals("dimension", 2, cs.getDimension());
+ assertAxisEquals(AxisNames.GEODETIC_LATITUDE, "φ", AxisDirection.NORTH, -100, +100, NonSI.GRADE, RangeMeaning.EXACT, cs.getAxis(0));
+ assertAxisEquals(AxisNames.GEODETIC_LONGITUDE, "λ", AxisDirection.EAST, -200, +200, NonSI.GRADE, RangeMeaning.WRAPAROUND, cs.getAxis(1));
+ /*
+ * Parse again using Convention.WKT1_COMMON_UNITS and ignoring AXIS[…] elements (but not the UNIT[…] element,
+ * which still apply to the axes). When using this convention, the parser does not apply the angular units to
+ * the Greenwich longitude value in PRIMEM[…] elements. Instead, the longitude is unconditionally interpreted
+ * as a value in degrees, which is why we convert "2.5969213" grade to "2.33722917" degrees in the WKT before
+ * to run the test (but we do NOT change the UNIT[…] element since the purpose of this test is to verify that
+ * those units are ignored).
+ *
+ * This is a violation of both OGC 01-009 and ISO 19162 standards, but this is what GDAL does.
+ * So we allow this interpretation in Convention.WKT1_COMMON_UNITS for compatibility reasons.
+ */
+ wkt = wkt.replace("2.5969213", "2.33722917"); // Convert unit in prime meridian.
+ setConvention(Convention.WKT1_COMMON_UNITS, true);
+ crs = parse(GeographicCRS.class, wkt);
+ assertNameAndIdentifierEqual("NTF (Paris)", 0, crs);
+ pm = verifyNTF(crs.getDatum());
+ assertEquals("angularUnit", NonSI.DEGREE_ANGLE, pm.getAngularUnit());
+ assertEquals("greenwichLongitude", 2.33722917, pm.getGreenwichLongitude(), STRICT);
+ cs = crs.getCoordinateSystem();
+ assertEquals("dimension", 2, cs.getDimension());
+ assertAxisEquals(AxisNames.GEODETIC_LONGITUDE, "λ", AxisDirection.EAST, -200, +200, NonSI.GRADE, RangeMeaning.WRAPAROUND, cs.getAxis(0));
+ assertAxisEquals(AxisNames.GEODETIC_LATITUDE, "φ", AxisDirection.NORTH, -100, +100, NonSI.GRADE, RangeMeaning.EXACT, cs.getAxis(1));
+ }
+
+ /**
+ * Tests the parsing of a projected CRS using parameters in grades instead than degrees.
+ * The grad units are also used for the prime meridian.
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ @DependsOnMethod({"testNonGreenwichMeridian", "testProjectedCRS"})
+ public void testGradUnitInParameters() throws ParseException {
+ String wkt = "PROJCS[“NTF (Paris) / Lambert zone II”," +
+ " GEOGCS[“NTF (Paris)”," +
+ " DATUM[“Nouvelle Triangulation Française (Paris)”," +
+ " SPHEROID[“Clarke 1880 (IGN)”, 6378249.2, 293.4660212936269]," +
+ " TOWGS84[-168,-60,320,0,0,0,0]]," +
+ " PRIMEM[“Paris”, 2.5969213, AUTHORITY[“EPSG”, “8903”]]," + // In grads.
+ " UNIT[“grad”, 0.01570796326794897]]," +
+ " PROJECTION[“Lambert Conformal Conic (1SP)”]," + // Intentional swapping of "Conformal" and "Conic".
+ " PARAMETER[“latitude_of_origin”, 52.0]," + // In grads.
+ " PARAMETER[“scale_factor”, 0.99987742]," +
+ " PARAMETER[“false_easting”, 600000]," +
+ " PARAMETER[“false_northing”, 2200000]," +
+ " UNIT[“metre”,1]]";
+
+ ProjectedCRS crs = parse(ProjectedCRS.class, wkt);
+ assertNameAndIdentifierEqual("NTF (Paris) / Lambert zone II", 0, crs);
+ verifyProjectedCS(crs.getCoordinateSystem());
+ PrimeMeridian pm = verifyNTF(crs.getDatum());
+ assertEquals("angularUnit", NonSI.GRADE, pm.getAngularUnit());
+ assertEquals("greenwichLongitude", 2.5969213, pm.getGreenwichLongitude(), STRICT);
+ ParameterValue<?> param = verifyNTF(crs.getConversionFromBase().getParameterValues());
+ assertEquals("angularUnit", NonSI.GRADE, param.getUnit());
+ assertEquals("latitude_of_origin", 52.0, param.doubleValue(), STRICT);
+ /*
+ * Parse again using Convention.WKT1_COMMON_UNITS and ignoring AXIS[…] elements.
+ * See the comment in testNonGreenwichMeridian for a discussion. The new aspect
+ * tested by this method is that the unit should be ignored for the parameters
+ * in addition to the prime meridian.
+ */
+ wkt = wkt.replace("2.5969213", "2.33722917"); // Convert unit in prime meridian.
+ wkt = wkt.replace("52.0", "46.8"); // Convert unit in “latitude_of_origin” parameter.
+ setConvention(Convention.WKT1_COMMON_UNITS, true);
+ crs = parse(ProjectedCRS.class, wkt);
+ assertNameAndIdentifierEqual("NTF (Paris) / Lambert zone II", 0, crs);
+ verifyProjectedCS(crs.getCoordinateSystem());
+ pm = verifyNTF(crs.getDatum());
+ assertEquals("angularUnit", NonSI.DEGREE_ANGLE, pm.getAngularUnit());
+ assertEquals("greenwichLongitude", 2.33722917, pm.getGreenwichLongitude(), STRICT);
+ param = verifyNTF(crs.getConversionFromBase().getParameterValues());
+ assertEquals("angularUnit", NonSI.DEGREE_ANGLE, param.getUnit());
+ assertEquals("latitude_of_origin", 46.8, param.doubleValue(), STRICT);
+ }
+
+ /**
+ * Verifies the properties of a datum which is expected to be “Nouvelle Triangulation Française (Paris)”.
+ * This is used by the methods in this class which test a CRS using less frequently used units and prime
+ * meridian.
+ *
+ * @return The prime meridian, to be verified by the caller because the unit of measurement depends on the test.
+ */
+ private static PrimeMeridian verifyNTF(final GeodeticDatum datum) {
+ assertNameAndIdentifierEqual("Nouvelle Triangulation Française (Paris)", 0, datum);
+
+ final Ellipsoid ellipsoid = datum.getEllipsoid();
+ assertNameAndIdentifierEqual("Clarke 1880 (IGN)", 0, ellipsoid);
+ assertEquals("semiMajor", 6378249.2, ellipsoid.getSemiMajorAxis(), STRICT);
+ assertEquals("inverseFlattening", 293.4660212936269, ellipsoid.getInverseFlattening(), STRICT);
+
+ final PrimeMeridian pm = datum.getPrimeMeridian();
+ assertNameAndIdentifierEqual("Paris", 8903, pm);
+ return pm;
+ }
+
+ /**
+ * Verifies the parameter values for a projected CRS which is expected to be “NTF (Paris) / Lambert zone II”.
+ * This is used by the methods in this class which test a CRS using less frequently used units and prime meridian.
+ *
+ * @return The latitude of origin, to be verified by the caller because the unit of measurement depends on the test.
+ */
+ private static ParameterValue<?> verifyNTF(final ParameterValueGroup param) {
+ assertEquals("Lambert Conic Conformal (1SP)", param.getDescriptor().getName().getCode());
+ assertEquals("semi_major", 6378249.2, param.parameter("semi_major" ).doubleValue(), STRICT);
+ assertEquals("semi_minor", 6356515.0, param.parameter("semi_minor" ).doubleValue(), 1E-12);
+ assertEquals("central_meridian", 0.0, param.parameter("central_meridian").doubleValue(), STRICT);
+ assertEquals("scale_factor", 0.99987742, param.parameter("scale_factor" ).doubleValue(), STRICT);
+ assertEquals("false_easting", 600000.0, param.parameter("false_easting" ).doubleValue(), STRICT);
+ assertEquals("false_northing", 2200000.0, param.parameter("false_northing" ).doubleValue(), STRICT);
+ return param.parameter("latitude_of_origin");
}
/**
@@ -76,8 +446,9 @@ public final strictfp class GeodeticObje
* @throws ParseException if the parsing failed.
*/
@Test
+ @DependsOnMethod("testGeographicCRS")
public void testCompoundCRS() throws ParseException {
- final CompoundCRS crs = (CompoundCRS) parse(
+ final CompoundCRS crs = parse(CompoundCRS.class,
"COMPD_CS[“WGS 84 + height + time”,\n" +
" GEOGCS[“WGS 84”,\n" +
" DATUM[“World Geodetic System 1984”,\n" +
@@ -96,55 +467,141 @@ public final strictfp class GeodeticObje
" Axis[“Time”, FUTURE]]]");
// CompoundCRS parent
- assertNameEquals("WGS 84 + height + time", crs);
+ assertNameAndIdentifierEqual("WGS 84 + height + time", 0, crs);
final Iterator<CoordinateReferenceSystem> components = crs.getComponents().iterator();
// GeographicCRS child
- final GeographicCRS geoCRS = (GeographicCRS) components.next();
- final GeodeticDatum geoDatum = geoCRS.getDatum();
- final Ellipsoid ellipsoid = geoDatum.getEllipsoid();
- assertNameEquals("WGS 84", geoCRS);
- assertNameEquals("World Geodetic System 1984", geoDatum);
- assertNameEquals("WGS84", ellipsoid);
- assertNameEquals("Greenwich", geoDatum.getPrimeMeridian());
- assertEquals("semiMajor", 6378137, ellipsoid.getSemiMajorAxis(), STRICT);
- assertEquals("inverseFlattening", 298.257223563, ellipsoid.getInverseFlattening(), STRICT);
+ verifyGeographicCRS(0, (GeographicCRS) components.next());
// VerticalCRS child
final VerticalCRS vertCRS = (VerticalCRS) components.next();
- assertNameEquals("Gravity-related height", vertCRS);
- assertNameEquals("Mean Sea Level", vertCRS.getDatum());
+ assertNameAndIdentifierEqual("Gravity-related height", 0, vertCRS);
+ assertNameAndIdentifierEqual("Mean Sea Level", 0, vertCRS.getDatum());
// TemporalCRS child
final TemporalCRS timeCRS = (TemporalCRS) components.next();
final TemporalDatum timeDatum = timeCRS.getDatum();
- assertNameEquals("Time", timeCRS);
- assertNameEquals("Modified Julian", timeDatum);
+ assertNameAndIdentifierEqual("Time", 0, timeCRS);
+ assertNameAndIdentifierEqual("Modified Julian", 0, timeDatum);
assertEquals("epoch", new Date(-40587 * (24*60*60*1000L)), timeDatum.getOrigin());
// No more CRS.
assertFalse(components.hasNext());
+
+ // Axes: we verify only the CompoundCRS ones, which should include all others.
+ final CoordinateSystem cs = crs.getCoordinateSystem();
+ assertEquals("dimension", 4, cs.getDimension());
+ assertLongitudeAxisEquals(cs.getAxis(0));
+ assertLatitudeAxisEquals (cs.getAxis(1));
+ assertUnboundedAxisEquals("Gravity-related height", "H", AxisDirection.UP, SI.METRE, cs.getAxis(2));
+ assertUnboundedAxisEquals("Time", "t", AxisDirection.FUTURE, NonSI.DAY, cs.getAxis(3));
}
/**
- * Tests integration in {@link WKTFormat#parse(CharSequence, ParsePosition)}.
- * This method tests only a simple WKT because it is not the purpose of this
- * method to test the parser itself. We only want to tests its integration in
- * the {@link WKTFormat} class.
+ * Tests parsing geographic CRS with implicit axes in seconds instead of degrees.
*
* @throws ParseException if the parsing failed.
+ *
+ * @see #testImplicitAxes()
*/
@Test
- @DependsOnMethod("testCompoundCRS")
- public void testWKTFormat() throws ParseException {
- final WKTFormat format = new WKTFormat(null, null);
- final VerticalCRS crs = (VerticalCRS) format.parseObject(
- "VERT_CS[“Gravity-related height”,\n" +
- " VERT_DATUM[“Mean Sea Level”, 2005],\n" +
- " UNIT[“metre”, 1],\n" +
- " AXIS[“Gravity-related height”, UP]]");
+ @DependsOnMethod("testImplicitAxes")
+ public void testImplicitAxesInSeconds() throws ParseException {
+ final GeographicCRS crs = parse(GeographicCRS.class,
+ "GEOGCS[“NAD83 / NFIS Seconds”," +
+ "DATUM[“North_American_Datum_1983”,\n" +
+ "SPHEROID[“GRS 1980”, 6378137, 298.257222101]],\n" +
+ "PRIMEM[“Greenwich”, 0],\n" +
+ "UNIT[“Decimal_Second”, 4.84813681109536e-06],\n" +
+ "AUTHORITY[“EPSG”, “100001”]]");
+
+ assertNameAndIdentifierEqual("NAD83 / NFIS Seconds", 100001, crs);
+
+ final GeodeticDatum datum = crs.getDatum();
+ assertNameAndIdentifierEqual("North_American_Datum_1983", 0, datum);
+ assertNameAndIdentifierEqual("Greenwich", 0, datum.getPrimeMeridian());
+
+ final Ellipsoid ellipsoid = datum.getEllipsoid();
+ assertNameAndIdentifierEqual("GRS 1980", 0, ellipsoid);
+ assertEquals("semiMajor", 6378137, ellipsoid.getSemiMajorAxis(), STRICT);
+ assertEquals("inverseFlattening", 298.257222101, ellipsoid.getInverseFlattening(), STRICT);
- assertNameEquals("Gravity-related height", crs);
- assertNameEquals("Mean Sea Level", crs.getDatum());
+ final EllipsoidalCS cs = crs.getCoordinateSystem();
+ final double secondsIn90 = 90*60*60;
+ CoordinateSystemAxis axis = cs.getAxis(0);
+ assertEquals("name", AxisNames.GEODETIC_LONGITUDE, axis.getName().getCode());
+ assertEquals("abbreviation", "λ", axis.getAbbreviation());
+ assertEquals("direction", AxisDirection.EAST, axis.getDirection());
+ assertEquals("minimumValue", -secondsIn90*2, axis.getMinimumValue(), 1E-9);
+ assertEquals("maximumValue", +secondsIn90*2, axis.getMaximumValue(), 1E-9);
+
+ axis = cs.getAxis(1);
+ assertEquals("name", AxisNames.GEODETIC_LATITUDE, axis.getName().getCode());
+ assertEquals("abbreviation", "φ", axis.getAbbreviation());
+ assertEquals("direction", AxisDirection.NORTH, axis.getDirection());
+ assertEquals("minimumValue", -secondsIn90, axis.getMinimumValue(), 1E-9);
+ assertEquals("maximumValue", +secondsIn90, axis.getMaximumValue(), 1E-9);
+ }
+
+ /**
+ * Tests parsing a WKT with a missing Geographic CRS name.
+ * This should be considered invalid, but happen in practice.
+ *
+ * <p>The WKT tested in this method contains also some other oddities compared to the usual WKT:</p>
+ * <ul>
+ * <li>The prime meridian is declared in the {@code "central_meridian"} projection parameter instead
+ * than in the {@code PRIMEM[…]} element.</li>
+ * <li>Some elements are not in the usual order.</li>
+ * </ul>
+ *
+ * @throws ParseException if the parsing failed.
+ */
+ @Test
+ @DependsOnMethod("testProjectedCRS")
+ public void testWithMissingName() throws ParseException {
+ final ProjectedCRS crs = parse(ProjectedCRS.class,
+ "PROJCS[“FRANCE/NTF/Lambert III”," +
+ "GEOGCS[“”," + // Missing name (the purpose of this test).
+ "DATUM[“NTF=GR3DF97A”,TOWGS84[-168, -60, 320, 0, 0, 0, 0] ," + // Intentionally misplaced coma.
+ "SPHEROID[“Clarke 1880 (IGN)”,6378249.2,293.4660212936269]]," +
+ "PRIMEM[“Greenwich”,0],UNIT[“Degrees”,0.0174532925199433]," +
+ "AXIS[“Long”,East],AXIS[“Lat”,North]]," +
+ "PROJECTION[“Lambert_Conformal_Conic_1SP”]," +
+ "PARAMETER[“latitude_of_origin”,44.1]," +
+ "PARAMETER[“central_meridian”,2.33722917]," + // Paris prime meridian.
+ "PARAMETER[“scale_factor”,0.999877499]," +
+ "PARAMETER[“false_easting”,600000]," +
+ "PARAMETER[“false_northing”,200000]," +
+ "UNIT[“Meter”,1]," +
+ "AXIS[“Easting”,East],AXIS[“Northing”,North]]");
+
+ assertNameAndIdentifierEqual("FRANCE/NTF/Lambert III", 0, crs);
+ verifyProjectedCS(crs.getCoordinateSystem());
+ final GeographicCRS geoCRS = crs.getBaseCRS();
+ assertNameAndIdentifierEqual("NTF=GR3DF97A", 0, geoCRS); // Inherited the datum name.
+
+ final GeodeticDatum datum = geoCRS.getDatum();
+ assertNameAndIdentifierEqual("NTF=GR3DF97A", 0, datum);
+ assertNameAndIdentifierEqual("Greenwich", 0, datum.getPrimeMeridian());
+
+ final Ellipsoid ellipsoid = datum.getEllipsoid();
+ assertNameAndIdentifierEqual("Clarke 1880 (IGN)", 0, ellipsoid);
+ assertEquals("semiMajor", 6378249.2, ellipsoid.getSemiMajorAxis(), STRICT);
+ assertEquals("inverseFlattening", 293.4660212936269, ellipsoid.getInverseFlattening(), STRICT);
+
+ final EllipsoidalCS cs = geoCRS.getCoordinateSystem();
+ assertEquals("dimension", 2, cs.getDimension());
+ assertLongitudeAxisEquals(cs.getAxis(0));
+ assertLatitudeAxisEquals (cs.getAxis(1));
+
+ final ParameterValueGroup param = crs.getConversionFromBase().getParameterValues();
+ assertEquals("Lambert Conic Conformal (1SP)", param.getDescriptor().getName().getCode());
+ assertEquals("semi_major", 6378249.2, param.parameter("semi_major" ).doubleValue(), STRICT);
+ assertEquals("semi_minor", 6356515.0, param.parameter("semi_minor" ).doubleValue(), 1E-12);
+ assertEquals("latitude_of_origin", 44.1, param.parameter("latitude_of_origin").doubleValue(), STRICT);
+ assertEquals("central_meridian", 2.33722917, param.parameter("central_meridian" ).doubleValue(), STRICT);
+ assertEquals("scale_factor", 0.999877499, param.parameter("scale_factor" ).doubleValue(), STRICT);
+ assertEquals("false_easting", 600000.0, param.parameter("false_easting" ).doubleValue(), STRICT);
+ assertEquals("false_northing", 200000.0, param.parameter("false_northing" ).doubleValue(), STRICT);
}
}