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/04/22 01:03:17 UTC
svn commit: r1675207 - in /sis/branches/JDK8/core:
sis-referencing/src/main/java/org/apache/sis/internal/referencing/
sis-referencing/src/main/java/org/apache/sis/parameter/
sis-referencing/src/main/java/org/apache/sis/referencing/
sis-referencing/src/...
Author: desruisseaux
Date: Tue Apr 21 23:03:17 2015
New Revision: 1675207
URL: http://svn.apache.org/r1675207
Log:
Referencing: initial port of AbstractCoordinateOperation, together with an opportunist improvement of WKT2 formatting of axes.
Added:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java (with props)
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxisTest.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -17,11 +17,17 @@
package org.apache.sis.internal.referencing;
import java.util.Map;
+import java.util.Collection;
+import org.opengis.util.Record;
+import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+import javax.measure.quantity.Length;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
-import org.opengis.referencing.operation.Matrix;
-import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.metadata.quality.Result;
+import org.opengis.metadata.quality.PositionalAccuracy;
+import org.opengis.metadata.quality.QuantitativeResult;
+import org.opengis.referencing.operation.*;
import org.apache.sis.referencing.AbstractIdentifiedObject;
import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.operation.transform.PassThroughTransform;
@@ -30,6 +36,7 @@ import org.apache.sis.util.resources.Err
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.Characters;
import org.apache.sis.util.Static;
+import org.apache.sis.measure.Units;
/**
@@ -38,17 +45,60 @@ import org.apache.sis.util.Static;
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
public final class OperationMethods extends Static {
/**
+ * The key for specifying explicitely the value to be returned by
+ * {@link org.apache.sis.referencing.operation.DefaultSingleOperation#getParameterValues()}.
+ * It is usually not necessary to specify those parameters because they are inferred either from
+ * the {@link MathTransform}, or specified explicitely in a {@code DefiningConversion}. However
+ * there is a few cases, for example the Molodenski transform, where none of the above can apply,
+ * because SIS implements those operations as a concatenation of math transforms, and such
+ * concatenations do not have {@link org.opengis.parameter.ParameterValueGroup}.
+ */
+ public static final String PARAMETERS_KEY = "parameters";
+
+ /**
* Do not allow instantiation of this class.
*/
private OperationMethods() {
}
/**
+ * Returns the most specific {@link CoordinateOperation} interface implemented by the specified operation.
+ * Special cases:
+ *
+ * <ul>
+ * <li>If the operation implements the {@link Transformation} interface,
+ * then this method returns {@code Transformation.class}. Transformation
+ * has precedence over any other interface implemented by the operation.</li>
+ * <li>Otherwise if the operation implements the {@link Conversion} interface,
+ * then this method returns the most specific {@code Conversion} sub-interface.</li>
+ * <li>Otherwise if the operation implements the {@link SingleOperation} interface,
+ * then this method returns {@code SingleOperation.class}.</li>
+ * <li>Otherwise if the operation implements the {@link ConcatenatedOperation} interface,
+ * then this method returns {@code ConcatenatedOperation.class}.</li>
+ * <li>Otherwise this method returns {@code CoordinateOperation.class}.</li>
+ * </ul>
+ *
+ * @param operation A coordinate operation.
+ * @return The most specific GeoAPI interface implemented by the given operation.
+ */
+ public static Class<? extends CoordinateOperation> getType(final CoordinateOperation operation) {
+ if (operation instanceof Transformation) return Transformation.class;
+ if (operation instanceof ConicProjection) return ConicProjection.class;
+ if (operation instanceof CylindricalProjection) return CylindricalProjection.class;
+ if (operation instanceof PlanarProjection) return PlanarProjection.class;
+ if (operation instanceof Projection) return Projection.class;
+ if (operation instanceof Conversion) return Conversion.class;
+ if (operation instanceof SingleOperation) return SingleOperation.class;
+ if (operation instanceof ConcatenatedOperation) return ConcatenatedOperation.class;
+ return CoordinateOperation.class;
+ }
+
+ /**
* Determines whether a match or mismatch is found between the two given collections of identifiers.
* If any of the given collections is {@code null} or empty, this method returns {@code null}.
*
@@ -207,4 +257,100 @@ public final class OperationMethods exte
}
return false;
}
+
+ /**
+ * Convenience method returning the accuracy in meters for the specified operation.
+ * This method tries each of the following procedures and returns the first successful one:
+ *
+ * <ul>
+ * <li>If a {@link QuantitativeResult} is found with a linear unit, then this accuracy estimate
+ * is converted to {@linkplain SI#METRE metres} and returned.</li>
+ *
+ * <li>Otherwise, if the operation is a {@link Conversion}, then returns 0 since a conversion
+ * is by definition accurate up to rounding errors.</li>
+ *
+ * <li>Otherwise, if the operation is a {@link Transformation}, then checks if the datum shift
+ * were applied with the help of Bursa-Wolf parameters. This procedure looks for SIS-specific
+ * {@link PositionalAccuracyConstant#DATUM_SHIFT_APPLIED} and
+ * {@link PositionalAccuracyConstant#DATUM_SHIFT_OMITTED DATUM_SHIFT_OMITTED} constants.
+ * If a datum shift has been applied, returns 25 meters.
+ * If a datum shift should have been applied but has been omitted, returns 1000 meters.
+ * The 1000 meters value is higher than the highest value (999 meters) found in the EPSG
+ * database version 6.7. The 25 meters value is the next highest value found in the EPSG
+ * database for a significant number of transformations.
+ *
+ * <li>Otherwise, if the operation is a {@link ConcatenatedOperation}, returns the sum of the accuracy
+ * of all components. This is a conservative scenario where we assume that errors cumulate linearly.
+ * Note that this is not necessarily the "worst case" scenario since the accuracy could be worst
+ * if the math transforms are highly non-linear.</li>
+ * </ul>
+ *
+ * @param operation The operation to inspect for accuracy.
+ * @return The accuracy estimate (always in meters), or NaN if unknown.
+ */
+ public static double getLinearAccuracy(final CoordinateOperation operation) {
+ final Collection<PositionalAccuracy> accuracies = operation.getCoordinateOperationAccuracy();
+ for (final PositionalAccuracy accuracy : accuracies) {
+ for (final Result result : accuracy.getResults()) {
+ if (result instanceof QuantitativeResult) {
+ final QuantitativeResult quantity = (QuantitativeResult) result;
+ final Collection<? extends Record> records = quantity.getValues();
+ if (records != null) {
+ final Unit<?> unit = quantity.getValueUnit();
+ if (Units.isLinear(unit)) {
+ final Unit<Length> unitOfLength = unit.asType(Length.class);
+ for (final Record record : records) {
+ for (final Object value : record.getAttributes().values()) {
+ if (value instanceof Number) {
+ double v = ((Number) value).doubleValue();
+ v = unitOfLength.getConverterTo(SI.METRE).convert(v);
+ return v;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /*
+ * No quantitative (linear) accuracy were found. If the coordinate operation is actually
+ * a conversion, the accuracy is up to rounding error (i.e. conceptually 0) by definition.
+ */
+ if (operation instanceof Conversion) {
+ return 0;
+ }
+ /*
+ * If the coordinate operation is actually a transformation, checks if Bursa-Wolf parameters
+ * were available for the datum shift. This is SIS-specific. See method javadoc for a rational
+ * about the return values chosen.
+ */
+ if (operation instanceof Transformation) {
+ if (!accuracies.contains(PositionalAccuracyConstant.DATUM_SHIFT_OMITTED)) {
+ if (accuracies.contains(PositionalAccuracyConstant.DATUM_SHIFT_APPLIED)) {
+ return 25;
+ }
+ }
+ return 1000;
+ }
+ /*
+ * If the coordinate operation is a compound of other coordinate operations, returns the sum of their accuracy,
+ * skipping unknown ones. Making the sum is a conservative approach (not exactly the "worst case" scenario,
+ * since it could be worst if the transforms are highly non-linear).
+ */
+ double accuracy = Double.NaN;
+ if (operation instanceof ConcatenatedOperation) {
+ for (final SingleOperation op : ((ConcatenatedOperation) operation).getOperations()) {
+ final double candidate = Math.abs(getLinearAccuracy(op));
+ if (!Double.isNaN(candidate)) {
+ if (Double.isNaN(accuracy)) {
+ accuracy = candidate;
+ } else {
+ accuracy += candidate;
+ }
+ }
+ }
+ }
+ return accuracy;
+ }
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -848,6 +848,12 @@ public class DefaultParameterValue<T> ex
}
formatter.append(convertedValue);
} else {
+ if (!isWKT1 && (unit == null) && (value instanceof URI || value instanceof URL
+ || value instanceof File || value instanceof Path))
+ {
+ formatter.append(value.toString(), null);
+ return "ParameterFile";
+ }
formatter.appendAny(value);
}
/*
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -431,6 +431,7 @@ public class AbstractIdentifiedObject ex
* {@link org.opengis.referencing.datum.Datum},
* {@link org.opengis.referencing.datum.Ellipsoid},
* {@link org.opengis.referencing.datum.PrimeMeridian},
+ * {@link org.opengis.referencing.operation.OperationMethod},
* {@link org.opengis.parameter.ParameterDescriptor} or
* {@link org.opengis.parameter.ParameterDescriptorGroup},
* then this method delegates to the {@code castOrCopy(…)} method of the corresponding SIS subclass.
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -23,6 +23,7 @@ import org.opengis.referencing.crs.Coord
import org.opengis.referencing.datum.Datum;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.operation.OperationMethod;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.apache.sis.referencing.crs.AbstractCRS;
@@ -31,6 +32,7 @@ import org.apache.sis.referencing.cs.Def
import org.apache.sis.referencing.datum.AbstractDatum;
import org.apache.sis.referencing.datum.DefaultEllipsoid;
import org.apache.sis.referencing.datum.DefaultPrimeMeridian;
+import org.apache.sis.referencing.operation.DefaultOperationMethod;
import org.apache.sis.parameter.DefaultParameterDescriptor;
import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
@@ -47,7 +49,7 @@ import org.apache.sis.parameter.DefaultP
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.4
+ * @version 0.6
* @module
*/
final class SubTypes {
@@ -81,6 +83,9 @@ final class SubTypes {
if (object instanceof PrimeMeridian) {
return DefaultPrimeMeridian.castOrCopy((PrimeMeridian) object);
}
+ if (object instanceof OperationMethod) {
+ return DefaultOperationMethod.castOrCopy((OperationMethod) object);
+ }
if (object instanceof ParameterDescriptor<?>) {
return DefaultParameterDescriptor.castOrCopy((ParameterDescriptor<?>) object);
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -33,6 +33,8 @@ import org.opengis.metadata.Identifier;
import org.opengis.referencing.crs.GeodeticCRS;
import org.opengis.referencing.cs.RangeMeaning;
import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.PolarCS;
+import org.opengis.referencing.cs.SphericalCS;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.referencing.AbstractIdentifiedObject;
@@ -79,7 +81,7 @@ import java.util.Objects;
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4
- * @version 0.4
+ * @version 0.6
* @module
*
* @see AbstractCS
@@ -743,8 +745,13 @@ public class DefaultCoordinateSystemAxis
* The only actions (derived from ISO 19162 rules) taken by this method are:
*
* <ul>
- * <li>Replace “<cite>Geodetic latitude</cite>” and “<cite>Geodetic longitude</cite>” names (case insensitive)
- * by “<cite>Latitude</cite>” and “<cite>Longitude</cite>” respectively.</li>
+ * <li>Replace <cite>“Geodetic latitude”</cite> and <cite>“Geodetic longitude”</cite> names (case insensitive)
+ * by <cite>“latitude”</cite> and <cite>“longitude”</cite> respectively.</li>
+ * <li>For latitude and longitude axes, replace “φ” and “λ” abbreviations by <var>“B”</var> and <var>“L”</var>
+ * respectively (from German “Breite” and “Länge”, used in academic texts worldwide).
+ * Note that <var>“L”</var> is also the transliteration of Greek letter “lambda” (λ).</li>
+ * <li>In {@link SphericalCS}, replace “φ” and “θ” abbreviations by <var>“U”</var> and <var>“V”</var> respectively.</li>
+ * <li>In {@link PolarCS}, replace “θ” abbreviation by <var>“U”</var>.</li>
* </ul>
*
* @return {@code "Axis"}.
@@ -760,9 +767,9 @@ public class DefaultCoordinateSystemAxis
if (name == null) {
name = IdentifiedObjects.getName(this, null);
}
- if (!isInternal && name != null) {
+ if (name != null && !isInternal) {
if (name.equalsIgnoreCase("Geodetic latitude")) {
- name = "Latitude"; // ISO 19162 §7.5.3(ii)
+ name = "Latitude"; // ISO 19162 §7.5.3(ii)
} else if (name.equalsIgnoreCase("Geodetic longitude")) {
name = "Longitude";
}
@@ -770,13 +777,52 @@ public class DefaultCoordinateSystemAxis
}
/*
* ISO 19162 §7.5.3 suggests to put abbreviation in parentheses, e.g. "Easting (x)".
+ * The specification also suggests to write only the abbreviation (e.g. "(X)") in the
+ * special case of Geocentric axis, and disallows Greek letters.
*/
- if (!isWKT1 && (name == null || !name.equals(abbreviation))) {
+ String a = abbreviation;
+ if (!isWKT1 && (a != null) && !a.equals(name)) {
+ if (!isInternal && a.length() == 1) {
+ switch (a.charAt(0)) {
+ /*
+ * ISO 19162 §7.5.3 recommendations:
+ *
+ * a) For PolarCS using Greek letter θ for direction, the letter ‘U’ should be used in WKT.
+ * b) For SphericalCS using φ and θ, the letter ‘U’ and ‘V’ respectively should be used in WKT.
+ */
+ case 'θ': {
+ final Object e = formatter.getEnclosingElement(0);
+ if (e instanceof SphericalCS) a ="V";
+ else if (e instanceof PolarCS) a ="U";
+ break;
+ }
+ /*
+ * ISO 19162 §7.5.3 requirement (ii) and recommendation (b):
+ *
+ * ii) Greek letters φ and λ for geodetic latitude and longitude must be replaced by Latin char.
+ * b) For SphericalCS using φ and θ, the letter ‘U’ and ‘V’ respectively should be used in WKT.
+ */
+ case 'φ': {
+ if (formatter.getEnclosingElement(0) instanceof SphericalCS) {
+ a = "U";
+ } else if ("Latitude".equalsIgnoreCase(name)) {
+ a = "B"; // From German "Breite", used in academic texts worldwide.
+ }
+ break;
+ }
+ case 'λ': {
+ if ("Longitude".equalsIgnoreCase(name)) {
+ a = "L"; // From German "Länge", used in academic texts worldwide.
+ }
+ break;
+ }
+ }
+ }
final StringBuilder buffer = new StringBuilder();
if (name != null) {
buffer.append(name).append(' ');
}
- name = buffer.append('(').append(abbreviation).append(')').toString();
+ name = buffer.append('(').append(a).append(')').toString();
}
formatter.append(name, ElementKind.AXIS);
/*
Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java?rev=1675207&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -0,0 +1,551 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation;
+
+import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.metadata.quality.PositionalAccuracy;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.*; // We really use most of this package content.
+import org.opengis.metadata.Identifier;
+import org.apache.sis.parameter.Parameterized;
+import org.opengis.parameter.ParameterValueGroup;
+import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.util.iso.Types;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.collection.Containers;
+import org.apache.sis.util.UnsupportedImplementationException;
+import org.apache.sis.referencing.AbstractIdentifiedObject;
+import org.apache.sis.referencing.operation.transform.PassThroughTransform;
+import org.apache.sis.internal.referencing.OperationMethods;
+import org.apache.sis.internal.referencing.WKTUtilities;
+import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.system.Semaphores;
+
+import static org.apache.sis.util.Utilities.deepEquals;
+
+// Branch-dependent imports
+import java.util.Objects;
+
+
+/**
+ * Establishes an association between a source and a target {@linkplain CoordinateReferenceSystem CRS}, and provides a
+ * {@linkplain MathTransform transform} for transforming coordinates in the source CRS to coordinates in the target CRS.
+ *
+ * <div class="section">Instantiation</div>
+ * This class is conceptually <cite>abstract</cite>, even if it is technically possible to instantiate it.
+ * Typical applications should create instances of the most specific subclass prefixed by {@code Default} instead.
+ * An exception to this rule may occur when it is not possible to identify the exact CRS type.
+ *
+ * <div class="section">Immutability and thread safety</div>
+ * This base class is immutable and thus thread-safe if the property <em>values</em> (not necessarily the map itself)
+ * given to the constructor are also immutable. Most SIS subclasses and related classes are immutable under similar
+ * conditions. This means that unless otherwise noted in the javadoc, {@code CoordinateOperation} instances created
+ * using only SIS factories and static constants can be shared by many objects and passed between threads without
+ * synchronization.
+ *
+ * @author Martin Desruisseaux (IRD, Geomatys)
+ * @since 0.6
+ * @version 0.6
+ * @module
+ */
+public class AbstractCoordinateOperation extends AbstractIdentifiedObject implements CoordinateOperation {
+ /**
+ * Serial number for inter-operability with different versions.
+ */
+ private static final long serialVersionUID = 1237358357729193885L;
+
+ /**
+ * The source CRS, or {@code null} if not available.
+ *
+ * @see #getSourceCRS()
+ */
+ private final CoordinateReferenceSystem sourceCRS;
+
+ /**
+ * The target CRS, or {@code null} if not available.
+ *
+ * @see #getTargetCRS()
+ */
+ private final CoordinateReferenceSystem targetCRS;
+
+ /**
+ * Version of the coordinate transformation
+ * (i.e., instantiation due to the stochastic nature of the parameters).
+ */
+ private final String operationVersion;
+
+ /**
+ * Estimate(s) of the impact of this operation on point accuracy, or {@code null} if none.
+ */
+ private final Collection<PositionalAccuracy> coordinateOperationAccuracy;
+
+ /**
+ * Area in which this operation is valid, or {@code null} if not available.
+ */
+ private final Extent domainOfValidity;
+
+ /**
+ * Description of domain of usage, or limitations of usage, for which this operation is valid.
+ */
+ private final InternationalString scope;
+
+ /**
+ * Transform from positions in the {@linkplain #getSourceCRS source coordinate reference system}
+ * to positions in the {@linkplain #getTargetCRS target coordinate reference system}.
+ */
+ private final MathTransform transform;
+
+ /**
+ * Constructs a new coordinate operation with the same values than the specified
+ * defining conversion, together with the specified source and target CRS.
+ * This constructor is used by {@link DefaultConversion} only.
+ */
+ AbstractCoordinateOperation(final Conversion definition,
+ final CoordinateReferenceSystem sourceCRS,
+ final CoordinateReferenceSystem targetCRS,
+ final MathTransform transform)
+ {
+ super(definition);
+ this.sourceCRS = sourceCRS;
+ this.targetCRS = targetCRS;
+ this.operationVersion = definition.getOperationVersion();
+ this.coordinateOperationAccuracy = definition.getCoordinateOperationAccuracy();
+ this.domainOfValidity = definition.getDomainOfValidity();
+ this.scope = definition.getScope();
+ this.transform = transform;
+ }
+
+ /**
+ * Creates a coordinate operation from the given properties.
+ * The properties given in argument follow the same rules than for the
+ * {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}.
+ * Additionally, the following properties are understood by this constructor:
+ *
+ * <table class="sis">
+ * <caption>Recognized properties (non exhaustive list)</caption>
+ * <tr>
+ * <th>Property name</th>
+ * <th>Value type</th>
+ * <th>Returned by</th>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.operation.CoordinateOperation#OPERATION_VERSION_KEY}</td>
+ * <td>{@link String}</td>
+ * <td>{@link #getOperationVersion()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.operation.CoordinateOperation#COORDINATE_OPERATION_ACCURACY_KEY}</td>
+ * <td>{@link PositionalAccuracy} (optionally as array)</td>
+ * <td>{@link #getCoordinateOperationAccuracy()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.operation.CoordinateOperation#DOMAIN_OF_VALIDITY_KEY}</td>
+ * <td>{@link Extent}</td>
+ * <td>{@link #getDomainOfValidity()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.operation.CoordinateOperation#SCOPE_KEY}</td>
+ * <td>{@link InternationalString} or {@link String}</td>
+ * <td>{@link #getScope()}</td>
+ * </tr>
+ * <tr>
+ * <th colspan="3" class="hsep">Defined in parent class (reminder)</th>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
+ * <td>{@link Identifier} or {@link String}</td>
+ * <td>{@link #getName()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY}</td>
+ * <td>{@link GenericName} or {@link CharSequence} (optionally as array)</td>
+ * <td>{@link #getAlias()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
+ * <td>{@link Identifier} (optionally as array)</td>
+ * <td>{@link #getIdentifiers()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td>
+ * <td>{@link InternationalString} or {@link String}</td>
+ * <td>{@link #getRemarks()}</td>
+ * </tr>
+ * </table>
+ *
+ * @param properties The properties to be given to the identified object.
+ * @param sourceCRS The source CRS, or {@code null} if unspecified.
+ * @param targetCRS The target CRS, or {@code null} if unspecified.
+ * @param transform Transform from positions in the source CRS to positions in the target CRS,
+ * or {@code null} if unspecified.
+ */
+ public AbstractCoordinateOperation(final Map<String,?> properties,
+ final CoordinateReferenceSystem sourceCRS,
+ final CoordinateReferenceSystem targetCRS,
+ final MathTransform transform)
+ {
+ super(properties);
+ Object positionalAccuracy;
+ domainOfValidity = Containers.property(properties, DOMAIN_OF_VALIDITY_KEY, Extent.class);
+ scope = Types.toInternationalString(properties, SCOPE_KEY);
+ operationVersion = Containers.property(properties, OPERATION_VERSION_KEY, String.class);
+ positionalAccuracy = properties.get(COORDINATE_OPERATION_ACCURACY_KEY);
+ if (positionalAccuracy instanceof PositionalAccuracy[]) {
+ coordinateOperationAccuracy = CollectionsExt.nonEmptySet((PositionalAccuracy[]) positionalAccuracy);
+ } else {
+ coordinateOperationAccuracy = (positionalAccuracy == null) ? null :
+ Collections.singleton((PositionalAccuracy) positionalAccuracy);
+ }
+ this.sourceCRS = sourceCRS;
+ this.targetCRS = targetCRS;
+ this.transform = transform;
+ if (transform != null) {
+ ArgumentChecks.ensureDimensionMatches("sourceCRS", transform.getSourceDimensions(), sourceCRS);
+ ArgumentChecks.ensureDimensionMatches("targetCRS", transform.getTargetDimensions(), targetCRS);
+ }
+ }
+
+ /**
+ * Returns the GeoAPI interface implemented by this class.
+ * The default implementation returns {@code CoordinateOperation.class}.
+ * Subclasses implementing a more specific GeoAPI interface shall override this method.
+ *
+ * @return The coordinate operation interface implemented by this class.
+ */
+ @Override
+ public Class<? extends CoordinateOperation> getInterface() {
+ return CoordinateOperation.class;
+ }
+
+ /**
+ * Returns the source CRS, or {@code null} if unspecified.
+ * The source CRS is mandatory for {@linkplain DefaultTransformation transformations} only.
+ * This information is optional for {@linkplain DefaultConversion conversions} according
+ * the ISO 19111 standard, but Apache SIS tries to provide that CRS in most cases anyway.
+ *
+ * @return The source CRS, or {@code null} if not available.
+ */
+ @Override
+ public CoordinateReferenceSystem getSourceCRS() {
+ return sourceCRS;
+ }
+
+ /**
+ * Returns the target CRS, or {@code null} if unspecified.
+ * The target CRS is mandatory for {@linkplain DefaultTransformation transformations} only.
+ * This information is optional for {@linkplain DefaultConversion conversions} according
+ * the ISO 19111 standard, but Apache SIS tries to provide that CRS in most cases anyway.
+ *
+ * @return The target CRS, or {@code null} if not available.
+ */
+ @Override
+ public CoordinateReferenceSystem getTargetCRS() {
+ return targetCRS;
+ }
+
+ /**
+ * Returns the CRS which is neither the {@linkplain #getSourceCRS() source CRS} or
+ * {@linkplain #getTargetCRS() target CRS} but still required for performing the operation.
+ *
+ * <div class="note"><b>Example:</b>
+ * some transformations of vertical coordinates (<var>h</var>) require the horizontal coordinates (φ,λ)
+ * in order to interpolate in a grid. This method returns the CRS of the grid where such interpolations
+ * are performed.</div>
+ *
+ * @return The CRS (neither source or target CRS) required for interpolating the values, or {@code null} if none.
+ */
+ public CoordinateReferenceSystem getInterpolationCRS() {
+ return null;
+ }
+
+ /**
+ * Returns the version of the coordinate operation. Different versions of a coordinate
+ * {@linkplain DefaultTransformation transformation} may exist because of the stochastic
+ * nature of the parameters. In principle this property is irrelevant to coordinate
+ * {@linkplain DefaultConversion conversions}, but Apache SIS accepts it anyway.
+ *
+ * @return The coordinate operation version, or {@code null} in none.
+ */
+ @Override
+ public String getOperationVersion() {
+ return operationVersion;
+ }
+
+ /**
+ * Returns an estimation of the impact of this operation on point accuracy.
+ * The positional accuracy gives position error estimates for target coordinates
+ * of this coordinate operation, assuming no errors in source coordinates.
+ *
+ * @return The position error estimations, or an empty collection if not available.
+ *
+ * @see #getLinearAccuracy()
+ */
+ @Override
+ public Collection<PositionalAccuracy> getCoordinateOperationAccuracy() {
+ return (coordinateOperationAccuracy != null) ? coordinateOperationAccuracy : Collections.emptySet();
+ }
+
+ /**
+ * Returns an estimation of positional accuracy in metres, or {@code NaN} if unknown.
+ * The default implementation tries to infer a value from the metadata returned by
+ * {@link #getCoordinateOperationAccuracy()} using SIS-specific heuristics.
+ *
+ * @return The accuracy estimation (always in meters), or NaN if unknown.
+ */
+ public double getLinearAccuracy() {
+ return OperationMethods.getLinearAccuracy(this);
+ }
+
+ /**
+ * Returns the area or region or timeframe in which this coordinate operation is valid.
+ *
+ * @return The coordinate operation valid domain, or {@code null} if not available.
+ */
+ @Override
+ public Extent getDomainOfValidity() {
+ return domainOfValidity;
+ }
+
+ /**
+ * Returns a description of domain of usage, or limitations of usage, for which this operation is valid.
+ *
+ * @return A description of domain of usage, or {@code null} if none.
+ */
+ @Override
+ public InternationalString getScope() {
+ return scope;
+ }
+
+ /**
+ * Returns the object for transforming coordinates in the {@linkplain #getSourceCRS() source CRS}
+ * to coordinates in the {@linkplain #getTargetCRS() target CRS}.
+ *
+ * @return The transform from source to target CRS, or {@code null} if not applicable.
+ */
+ @Override
+ public MathTransform getMathTransform() {
+ return transform;
+ }
+
+ /**
+ * Returns the operation method. {@link DefaultConversion} and {@link DefaultTransformation} need to override
+ * this method as a final method because {@code equals(Object, ComparisonMode.STRICT)} assumes that the field
+ * value is returned directly.
+ */
+ OperationMethod getMethod() {
+ return null;
+ }
+
+ /**
+ * Returns the parameter values. The default implementation infers the parameter
+ * values from the {@linkplain #transform transform}, if possible.
+ *
+ * @throws UnsupportedOperationException if the parameter values can't be determined
+ * for the current math transform implementation.
+ *
+ * @see DefaultMathTransformFactory#createParameterizedTransform(ParameterValueGroup)
+ * @see Parameterized#getParameterValues()
+ */
+ ParameterValueGroup getParameterValues() throws UnsupportedOperationException {
+ MathTransform mt = transform;
+ while (mt != null) {
+ if (mt instanceof Parameterized) {
+ final ParameterValueGroup param;
+ if (Semaphores.queryAndSet(Semaphores.PROJCS)) {
+ throw new AssertionError(); // Should never happen.
+ }
+ try {
+ param = ((Parameterized) mt).getParameterValues();
+ } finally {
+ Semaphores.clear(Semaphores.PROJCS);
+ }
+ if (param != null) {
+ return param;
+ }
+ }
+ if (mt instanceof PassThroughTransform) {
+ mt = ((PassThroughTransform) mt).getSubTransform();
+ } else {
+ break;
+ }
+ }
+ throw new UnsupportedImplementationException(Classes.getClass(mt));
+ }
+
+
+ /**
+ * Compares this coordinate operation with the specified object for equality. If the {@code mode} argument
+ * is {@link ComparisonMode#STRICT} or {@link ComparisonMode#BY_CONTRACT BY_CONTRACT}, then all available
+ * properties are compared including the {@linkplain #getDomainOfValidity() domain of validity} and the
+ * {@linkplain #getScope() scope}.
+ *
+ * @param object The object to compare to {@code this}.
+ * @param mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or
+ * {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only properties
+ * relevant to transformations.
+ * @return {@code true} if both objects are equal.
+ */
+ @Override
+ public boolean equals(final Object object, final ComparisonMode mode) {
+ if (object == this) {
+ return true; // Slight optimization.
+ }
+ if (!super.equals(object, mode)) {
+ return false;
+ }
+ if (mode == ComparisonMode.STRICT) {
+ final AbstractCoordinateOperation that = (AbstractCoordinateOperation) object;
+ if (!Objects.equals(getMethod(), that.getMethod()) ||
+ !Objects.equals(sourceCRS, that.sourceCRS) ||
+ !Objects.equals(transform, that.transform) ||
+ !Objects.equals(scope, that.scope) ||
+ !Objects.equals(domainOfValidity, that.domainOfValidity) ||
+ !Objects.equals(coordinateOperationAccuracy, that.coordinateOperationAccuracy))
+ {
+ return false;
+ }
+ // See comment at the end of this method.
+ if (Semaphores.queryAndSet(Semaphores.COMPARING)) {
+ return true;
+ } else try {
+ return Objects.equals(targetCRS, that.targetCRS);
+ } finally {
+ Semaphores.clear(Semaphores.COMPARING);
+ }
+ }
+ final CoordinateOperation that = (CoordinateOperation) object;
+ if (mode == ComparisonMode.BY_CONTRACT) {
+ if (!deepEquals(getMethod(), (that instanceof SingleOperation) ? ((SingleOperation) that).getMethod() : null, mode) ||
+ !deepEquals(getScope(), that.getScope(), mode) ||
+ !deepEquals(getDomainOfValidity(), that.getDomainOfValidity(), mode) ||
+ !deepEquals(getCoordinateOperationAccuracy(), that.getCoordinateOperationAccuracy(), mode))
+ {
+ return false;
+ }
+ // SourceCRS, targetCRS and transform to be tested below.
+ }
+ /*
+ * We consider the operation method as metadata. One could argue that OperationMethod's 'sourceDimension' and
+ * 'targetDimension' are not metadata, but their values should be identical to the 'sourceCRS' and 'targetCRS'
+ * dimensions, already checked below. We could also argue that 'OperationMethod.parameters' are not metadata,
+ * but their values should have been taken in account for the MathTransform creation, compared below.
+ *
+ * Comparing the MathTransforms instead of parameters avoid the problem of implicit parameters. For example in
+ * a ProjectedCRS, the "semiMajor" and "semiMinor" axis lengths are sometime provided as explicit parameters,
+ * and sometime inferred from the geodetic datum. The two cases would be different set of parameters from the
+ * OperationMethod's point of view, but still result in the creation of identical MathTransforms.
+ *
+ * An other rational for treating OperationMethod as metadata is that SIS's MathTransform providers extend
+ * DefaultOperationMethod. Consequently there is a wide range of subclasses, which make the comparisons more
+ * difficult. For example Mercator1SP and Mercator2SP providers are two different ways to describe the same
+ * projection. The SQL-backed EPSG factory uses yet an other implementation.
+ *
+ * NOTE: A previous Geotk implementation made this final check:
+ *
+ * return nameMatches(this.method, that.method);
+ *
+ * but it was not strictly necessary since it was redundant with the comparisons of MathTransforms.
+ * Actually it was preventing to detect that two CRS were equivalent despite different method names
+ * (e.g. "Mercator (1SP)" and "Mercator (2SP)" when the parameters are properly chosen).
+ */
+ if (!deepEquals(getMathTransform(), that.getMathTransform(), mode)
+ || !deepEquals(getSourceCRS(), that.getSourceCRS(), mode))
+ {
+ return false;
+ }
+ /*
+ * Avoid never-ending recursivity: AbstractDerivedCRS has a 'conversionFromBase'
+ * field that is set to this AbstractCoordinateOperation.
+ */
+ if (Semaphores.queryAndSet(Semaphores.COMPARING)) {
+ return true;
+ } else try {
+ return deepEquals(getTargetCRS(), that.getTargetCRS(), mode);
+ } finally {
+ Semaphores.clear(Semaphores.COMPARING);
+ }
+ }
+
+ /**
+ * Invoked by {@code hashCode()} for computing the hash code when first needed.
+ * See {@link #computeHashCode()} for more information.
+ *
+ * @return The hash code value. This value may change in any future Apache SIS version.
+ */
+ @Override
+ protected long computeHashCode() {
+ /*
+ * Do NOT take 'getMethod()' in account in hash code calculation. See the comment
+ * inside the above 'equals(Object, ComparisonMode)' method for more information.
+ * Note that we use the 'transform' hash code, which should be sufficient.
+ */
+ return super.computeHashCode() + Objects.hash(sourceCRS, targetCRS, transform);
+ }
+
+ /**
+ * Formats this coordinate operation in Well Known Text (WKT) version 2 format.
+ *
+ * @param formatter The formatter to use.
+ * @return {@code "CoordinateOperation"}.
+ */
+ @Override
+ protected String formatTo(final Formatter formatter) {
+ super.formatTo(formatter);
+ append(formatter, getSourceCRS(), "SourceCRS");
+ append(formatter, getTargetCRS(), "TargetCRS");
+ formatter.append(DefaultOperationMethod.castOrCopy(getMethod()));
+ append(formatter, getInterpolationCRS(), "InterpolationCRS");
+ final double accuracy = getLinearAccuracy();
+ if (accuracy > 0) {
+ formatter.append(new FormattableObject() {
+ @Override protected String formatTo(final Formatter formatter) {
+ formatter.append(accuracy);
+ return "OperationAccuracy";
+ }
+ });
+ }
+ if (formatter.getConvention().majorVersion() == 1) {
+ formatter.setInvalidWKT(this, null);
+ }
+ return "CoordinateOperation";
+ }
+
+ /**
+ * Appends the given CRS (if non-null) wrapped in an element of the given name.
+ *
+ * @param formatter The formatter where to append the object name.
+ * @param crs The object to append, or {@code null} if none.
+ * @param type The keyword to write before the object.
+ */
+ private static void append(final Formatter formatter, final CoordinateReferenceSystem crs, final String type) {
+ if (crs != null) {
+ formatter.append(new FormattableObject() {
+ @Override protected String formatTo(final Formatter formatter) {
+ formatter.append(WKTUtilities.toFormattable(crs));
+ return type;
+ }
+ });
+ }
+ }
+}
Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -181,8 +181,8 @@ public final strictfp class DefaultCompo
" Ellipsoid[“WGS84”, 6378137.0, 298.257223563, LengthUnit[“metre”, 1]]],\n" +
" PrimeMeridian[“Greenwich”, 0.0, AngleUnit[“degree”, 0.017453292519943295]],\n" +
" CS[“ellipsoidal”, 2],\n" +
- " Axis[“Longitude (λ)”, east],\n" +
- " Axis[“Latitude (φ)”, north],\n" +
+ " Axis[“Longitude (L)”, east],\n" +
+ " Axis[“Latitude (B)”, north],\n" +
" AngleUnit[“degree”, 0.017453292519943295]],\n" +
" VerticalCRS[“Gravity-related height”,\n" +
" VerticalDatum[“Mean Sea Level”],\n" +
Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -162,8 +162,8 @@ public final strictfp class DefaultGeogr
" Ellipsoid[“WGS84”, 6378137.0, 298.257223563, LengthUnit[“metre”, 1]]],\n" +
" PrimeMeridian[“Greenwich”, 0.0, AngleUnit[“degree”, 0.017453292519943295]],\n" +
" CS[“ellipsoidal”, 2],\n" +
- " Axis[“Longitude (λ)”, east],\n" +
- " Axis[“Latitude (φ)”, north],\n" +
+ " Axis[“Longitude (L)”, east],\n" +
+ " Axis[“Latitude (B)”, north],\n" +
" AngleUnit[“degree”, 0.017453292519943295],\n" +
" Area[“World”],\n" +
" BBox[-90.00, -180.00, 90.00, 180.00]]",
@@ -175,8 +175,8 @@ public final strictfp class DefaultGeogr
" Ellipsoid[“WGS84”, 6378137.0, 298.257223563]],\n" +
" PrimeMeridian[“Greenwich”, 0.0],\n" +
" CS[“ellipsoidal”, 2],\n" +
- " Axis[“Longitude (λ)”, east],\n" +
- " Axis[“Latitude (φ)”, north],\n" +
+ " Axis[“Longitude (L)”, east],\n" +
+ " Axis[“Latitude (B)”, north],\n" +
" Unit[“degree”, 0.017453292519943295],\n" +
" Area[“World”],\n" +
" BBox[-90.00, -180.00, 90.00, 180.00]]",
Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxisTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxisTest.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxisTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxisTest.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -89,13 +89,13 @@ public final strictfp class DefaultCoord
assertWktEquals("Axis[“x”, east, LengthUnit[“metre”, 1]]", X);
assertWktEquals("Axis[“y”, north, LengthUnit[“metre”, 1]]", Y);
assertWktEquals("Axis[“z”, up, LengthUnit[“metre”, 1]]", Z);
- assertWktEquals("Axis[“Longitude (λ)”, east, AngleUnit[“grade”, 0.015707963267948967]]", LONGITUDE_gon);
- assertWktEquals("Axis[“Latitude (φ)”, north, AngleUnit[“grade”, 0.015707963267948967]]", LATITUDE_gon);
+ assertWktEquals("Axis[“Longitude (L)”, east, AngleUnit[“grade”, 0.015707963267948967]]", LONGITUDE_gon);
+ assertWktEquals("Axis[“Latitude (B)”, north, AngleUnit[“grade”, 0.015707963267948967]]", LATITUDE_gon);
assertWktEquals("Axis[“Altitude (h)”, up, LengthUnit[“metre”, 1]]", ALTITUDE);
assertWktEquals("Axis[“Time (t)”, future, TimeUnit[“day”, 86400]]", TIME);
- assertWktEquals("Axis[“Longitude (λ)”, east, AngleUnit[“degree”, 0.017453292519943295]]", GEODETIC_LONGITUDE);
+ assertWktEquals("Axis[“Longitude (L)”, east, AngleUnit[“degree”, 0.017453292519943295]]", GEODETIC_LONGITUDE);
assertWktEquals("Axis[“Spherical longitude (Ω)”, east, AngleUnit[“degree”, 0.017453292519943295]]", SPHERICAL_LONGITUDE);
- assertWktEquals("Axis[“Latitude (φ)”, north, AngleUnit[“degree”, 0.017453292519943295]]", GEODETIC_LATITUDE);
+ assertWktEquals("Axis[“Latitude (B)”, north, AngleUnit[“degree”, 0.017453292519943295]]", GEODETIC_LATITUDE);
assertWktEquals("Axis[“Spherical latitude (Θ)”, north, AngleUnit[“degree”, 0.017453292519943295]]", SPHERICAL_LATITUDE);
assertWktEquals(Convention.WKT1, "AXIS[“x”, EAST]", X);
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java?rev=1675207&r1=1675206&r2=1675207&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java [UTF-8] Tue Apr 21 23:03:17 2015
@@ -104,6 +104,22 @@ public final class CollectionsExt extend
}
/**
+ * Returns a copy of the given array as a non-empty immutable set.
+ * If the given array is empty, then this method returns {@code null}.
+ *
+ * @param <T> The type of elements.
+ * @param elements The elements to copy in a set.
+ * @return An unmodifiable set which contains all the given elements, or {@code null}.
+ *
+ * @since 0.6
+ */
+ @SafeVarargs
+ public static <T> Set<T> nonEmptySet(final T... elements) {
+ final Set<T> asSet = immutableSet(true, elements);
+ return (asSet != null && asSet.isEmpty()) ? null : asSet;
+ }
+
+ /**
* Returns the given array if non-empty, or {@code null} if the given array is null or empty.
* This method is generally not recommended, since public API should prefer empty array instead of null.
* However this method is occasionally useful for managing private fields.