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 2016/01/14 00:59:41 UTC
svn commit: r1724531 [2/13] - in /sis/trunk: ./
application/sis-console/src/main/artifact/bin/
application/sis-console/src/main/artifact/log/
application/sis-console/src/main/java/org/apache/sis/console/
core/sis-build-helper/src/main/java/org/apache/s...
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicOffsets.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,24 +16,26 @@
*/
package org.apache.sis.internal.referencing.provider;
-import javax.xml.bind.annotation.XmlTransient;
+import javax.measure.unit.SI;
import javax.measure.unit.NonSI;
+import javax.xml.bind.annotation.XmlTransient;
+import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
-import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.Transformation;
-import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
import org.apache.sis.parameter.ParameterBuilder;
import org.apache.sis.parameter.Parameters;
+import org.apache.sis.referencing.operation.matrix.Matrix4;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
/**
- * The provider for <cite>"Geographic2D offsets"</cite> (EPSG:9619).
- * The default implementation handles the 2D case.
- * The {@link GeographicOffsets3D} subclass adds a third dimension.
+ * Base class for all transformations that perform a translation in the geographic domain.
+ * This base class defines a provider for <cite>"Geographic3D offsets"</cite> (EPSG:9660),
+ * but subclasses will provide different operations.
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.7
@@ -58,28 +60,34 @@ public class GeographicOffsets extends A
static final ParameterDescriptor<Double> TY;
/**
+ * The operation parameter descriptor for the <cite>"Vertical Offset"</cite> parameter value.
+ */
+ static final ParameterDescriptor<Double> TZ;
+
+ /**
* The group of all parameters expected by this coordinate operation.
*/
private static final ParameterDescriptorGroup PARAMETERS;
static {
final ParameterBuilder builder = builder();
- TY = builder.addIdentifier("8601").addName("Latitude offset").create(0, NonSI.DEGREE_ANGLE);
+ TY = builder.addIdentifier("8601").addName("Latitude offset") .create(0, NonSI.DEGREE_ANGLE);
TX = builder.addIdentifier("8602").addName("Longitude offset").create(0, NonSI.DEGREE_ANGLE);
- PARAMETERS = builder.addIdentifier("9619").addName("Geographic2D offsets").createGroup(TY, TX);
+ TZ = builder.addIdentifier("8603").addName("Vertical Offset") .create(0, SI.METRE);
+ PARAMETERS = builder.addIdentifier("9660").addName("Geographic3D offsets").createGroup(TY, TX, TZ);
}
/**
* Constructs a provider with default parameters.
*/
public GeographicOffsets() {
- super(2, 2, PARAMETERS);
+ super(3, 3, PARAMETERS);
}
/**
- * For subclass constructor only.
+ * For subclasses constructor only.
*/
- GeographicOffsets(ParameterDescriptorGroup parameters) {
- super(3, 3, parameters);
+ GeographicOffsets(int dim, ParameterDescriptorGroup parameters) {
+ super(dim, dim, parameters);
}
/**
@@ -94,7 +102,7 @@ public class GeographicOffsets extends A
/**
* Creates a transform from the specified group of parameter values.
- * The parameter values are unconditionally converted to degrees.
+ * The parameter values are unconditionally converted to degrees and metres.
*
* @param factory Ignored (can be null).
* @param values The group of parameter values.
@@ -106,6 +114,10 @@ public class GeographicOffsets extends A
throws ParameterNotFoundException
{
final Parameters pv = Parameters.castOrWrap(values);
- return new AffineTransform2D(1, 0, 0, 1, pv.doubleValue(TX), pv.doubleValue(TY));
+ final Matrix4 t = new Matrix4();
+ t.m03 = pv.doubleValue(TX);
+ t.m13 = pv.doubleValue(TY);
+ t.m23 = pv.doubleValue(TZ);
+ return MathTransforms.linear(t);
}
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -84,6 +84,17 @@ public final class GeographicToGeocentri
}
/**
+ * Notifies {@code DefaultMathTransformFactory} that Geographic/geocentric conversions
+ * require values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
+ *
+ * @return 1, meaning that the operation requires a source ellipsoid.
+ */
+ @Override
+ public int getEllipsoidsMask() {
+ return 1;
+ }
+
+ /**
* Creates a transform from the specified group of parameter values.
*
* @param factory The factory to use for creating the transform.
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LongitudeRotation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LongitudeRotation.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LongitudeRotation.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/LongitudeRotation.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlTran
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
-import org.opengis.referencing.operation.Transformation;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
@@ -45,11 +44,11 @@ import org.apache.sis.parameter.Paramete
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.6
- * @version 0.6
+ * @version 0.7
* @module
*/
@XmlTransient
-public final class LongitudeRotation extends AbstractProvider {
+public final class LongitudeRotation extends GeographicOffsets {
/**
* Serial number for inter-operability with different versions.
*/
@@ -60,24 +59,14 @@ public final class LongitudeRotation ext
*/
private static final ParameterDescriptorGroup PARAMETERS;
static {
- PARAMETERS = builder().addIdentifier("9601").addName("Longitude rotation").createGroup(GeographicOffsets.TX);
+ PARAMETERS = builder().addIdentifier("9601").addName("Longitude rotation").createGroup(TX);
}
/**
* Constructs a provider with default parameters.
*/
public LongitudeRotation() {
- super(2, 2, PARAMETERS);
- }
-
- /**
- * Returns the operation type.
- *
- * @return Interface implemented by all coordinate operations that use this method.
- */
- @Override
- public Class<Transformation> getOperationType() {
- return Transformation.class;
+ super(2, PARAMETERS);
}
/**
@@ -100,7 +89,7 @@ public final class LongitudeRotation ext
public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
throws ParameterNotFoundException
{
- final double offset = Parameters.castOrWrap(values).doubleValue(GeographicOffsets.TX);
- return new AffineTransform2D(1, 0, 0, 1, offset, 0);
+ final Parameters pv = Parameters.castOrWrap(values);
+ return new AffineTransform2D(1, 0, 0, 1, pv.doubleValue(TX), 0);
}
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -204,6 +204,17 @@ public abstract class MapProjection exte
*/
protected abstract NormalizedProjection createProjection(final Parameters parameters) throws ParameterNotFoundException;
+ /**
+ * Notifies {@code DefaultMathTransformFactory} that map projections require
+ * values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
+ *
+ * @return 1, meaning that the operation requires a source ellipsoid.
+ */
+ @Override
+ public final int getEllipsoidsMask() {
+ return 1;
+ }
+
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -96,27 +96,24 @@ public final class Molodensky extends Ge
final ParameterBuilder builder = builder();
AXIS_LENGTH_DIFFERENCE = builder.addName("Semi-major axis length difference").create(Double.NaN, SI.METRE);
FLATTENING_DIFFERENCE = builder.addName("Flattening difference").createBounded(-1, +1, Double.NaN, Unit.ONE);
- builder.setRequired(false);
- ParameterDescriptor<Double> a = builder.addName(TGT_SEMI_MAJOR.getName()).createStrictlyPositive(Double.NaN, SI.METRE);
- ParameterDescriptor<Double> b = builder.addName(TGT_SEMI_MINOR.getName()).createStrictlyPositive(Double.NaN, SI.METRE);
PARAMETERS = builder.setRequired(true)
.addIdentifier("9604")
.addName("Molodensky")
.addName(Citations.OGC, "Molodenski")
.createGroup(DIMENSION, // OGC only
+ SRC_SEMI_MAJOR, SRC_SEMI_MINOR, // OGC only
+ TGT_SEMI_MAJOR, TGT_SEMI_MINOR, // OGC only - redundant with differences
TX, // OGC and EPSG
TY, // OGC and EPSG
TZ, // OGC and EPSG
AXIS_LENGTH_DIFFERENCE, // EPSG only
- FLATTENING_DIFFERENCE, // EPSG only
- SRC_SEMI_MAJOR, SRC_SEMI_MINOR, // OGC only
- a, b); // OGC only
+ FLATTENING_DIFFERENCE); // EPSG only
}
/**
* Creates a descriptor for the internal parameters of {@link MolodenskyTransform}.
- * This is identical to the standard parameters except that the last 3 OGC parameters
- * are replaced by the eccentricity.
+ * This is similar to the standard parameters except that the redundant target axes
+ * lengths are omitted.
*
* @return Internal parameter descriptor.
*/
@@ -126,19 +123,19 @@ public final class Molodensky extends Ge
ParameterDescriptor<Boolean> abridged = builder.addName("abridged").create(Boolean.class, null);
return builder.addName("Molodensky")
.createGroup(DIMENSION,
+ SRC_SEMI_MAJOR,
+ SRC_SEMI_MINOR,
+ AXIS_LENGTH_DIFFERENCE,
+ FLATTENING_DIFFERENCE,
TX,
TY,
TZ,
- AXIS_LENGTH_DIFFERENCE,
- FLATTENING_DIFFERENCE,
- SRC_SEMI_MAJOR,
- MapProjection.ECCENTRICITY,
abridged);
}
/**
* The providers for all combinations between 2D and 3D cases.
- * Array length is 4. Index is build with following rule:
+ * Array length is 4. Index is built with following rule:
* <ul>
* <li>Bit 1: dimension of source coordinates (0 for 2D, 1 for 3D).</li>
* <li>Bit 0: dimension of target coordinates (0 for 2D, 1 for 3D).</li>
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercator.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercator.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercator.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/TransverseMercator.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,13 +16,20 @@
*/
package org.apache.sis.internal.referencing.provider;
+import javax.measure.unit.Unit;
+import javax.measure.unit.SI;
+import javax.measure.unit.NonSI;
import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.parameter.ParameterValueGroup;
+import org.apache.sis.measure.Longitude;
+import org.apache.sis.parameter.Parameters;
import org.apache.sis.parameter.ParameterBuilder;
import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.parameter.Parameters;
import org.apache.sis.referencing.operation.projection.NormalizedProjection;
+import org.apache.sis.internal.util.Constants;
+import org.apache.sis.math.MathFunctions;
/**
@@ -31,7 +38,7 @@ import org.apache.sis.referencing.operat
* @author Martin Desruisseaux (MPO, IRD, Geomatys)
* @author Rueben Schulz (UBC)
* @since 0.6
- * @version 0.6
+ * @version 0.7
* @module
*
* @see <a href="http://www.remotesensing.org/geotiff/proj_list/transverse_mercator.html">Transverse Mercator on RemoteSensing.org</a>
@@ -44,6 +51,19 @@ public final class TransverseMercator ex
private static final long serialVersionUID = -3386587506686432398L;
/**
+ * Width of a Universal Transverse Mercator (UTM) zone, in degrees.
+ *
+ * @see #zone(double)
+ * @see #centralMeridian(int)
+ */
+ private static final double ZONE_WIDTH = 6;
+
+ /**
+ * The {@value} string, which is also the EPSG name for this projection.
+ */
+ public static final String NAME = "Transverse Mercator";
+
+ /**
* The operation parameter descriptor for the <cite>Latitude of natural origin</cite> (φ₀) parameter value.
* Valid values range is [-90 … 90]° and default value is 0°.
*/
@@ -64,7 +84,7 @@ public final class TransverseMercator ex
/**
* The group of all parameters expected by this coordinate operation.
*/
- private static final ParameterDescriptorGroup PARAMETERS;
+ static final ParameterDescriptorGroup PARAMETERS;
static {
final ParameterBuilder builder = builder();
LATITUDE_OF_ORIGIN = createLatitude(builder
@@ -80,7 +100,7 @@ public final class TransverseMercator ex
PARAMETERS = builder
.addIdentifier( "9807")
- .addName( "Transverse Mercator")
+ .addName( NAME)
.addName( "Gauss-Kruger")
.addName( "Gauss-Boaga")
.addName( "TM")
@@ -119,4 +139,81 @@ public final class TransverseMercator ex
protected NormalizedProjection createProjection(final Parameters parameters) {
return new org.apache.sis.referencing.operation.projection.TransverseMercator(this, parameters);
}
+
+ /**
+ * Sets the parameter values for a Transverse Mercator projection and returns a suggested conversion name.
+ *
+ * <blockquote><table class="sis">
+ * <caption>Transverse Mercator parameters</caption>
+ * <tr><th>Parameter name</th> <th>Value</th></tr>
+ * <tr><td>Latitude of natural origin</td> <td>Given latitude, or 0° if UTM projection</td></tr>
+ * <tr><td>Longitude of natural origin</td> <td>Given longitude, optionally snapped to a UTM central meridian</td></tr>
+ * <tr><td>Scale factor at natural origin</td> <td>0.9996</td></tr>
+ * <tr><td>False easting</td> <td>500000 metres</td></tr>
+ * <tr><td>False northing</td> <td>0 (North hemisphere) or 10000000 (South hemisphere) metres</td></tr>
+ * </table></blockquote>
+ *
+ * @param group The parameters for which to set the values.
+ * @param isUTM {@code true} for Universal Transverse Mercator (UTM) projection.
+ * @param latitude The latitude in the center of the desired projection.
+ * @param longitude The longitude in the center of the desired projection.
+ * @return A name like <cite>"Transverse Mercator"</cite> or <cite>"UTM zone 10N"</cite>,
+ * depending on the arguments given to this method.
+ *
+ * @since 0.7
+ */
+ public static String setParameters(final ParameterValueGroup group,
+ final boolean isUTM, double latitude, double longitude)
+ {
+ final boolean isSouth = MathFunctions.isNegative(latitude);
+ int zone = zone(longitude);
+ if (isUTM) {
+ latitude = 0;
+ longitude = centralMeridian(zone);
+ } else if (longitude != centralMeridian(zone)) {
+ zone = 0;
+ }
+ String name = NAME;
+ if (zone != 0) {
+ name = "UTM zone " + zone + (isSouth ? 'S' : 'N');
+ }
+ group.parameter(Constants.LATITUDE_OF_ORIGIN).setValue(latitude, NonSI.DEGREE_ANGLE);
+ group.parameter(Constants.CENTRAL_MERIDIAN) .setValue(longitude, NonSI.DEGREE_ANGLE);
+ group.parameter(Constants.SCALE_FACTOR) .setValue(0.9996, Unit.ONE);
+ group.parameter(Constants.FALSE_EASTING) .setValue(500000, SI.METRE);
+ group.parameter(Constants.FALSE_NORTHING) .setValue(isSouth ? 10000000 : 0, SI.METRE);
+ return name;
+ }
+
+ /**
+ * Computes the UTM zone from a meridian in the zone.
+ *
+ * @param longitude A meridian inside the desired zone, in degrees relative to Greenwich.
+ * Positive longitudes are toward east, and negative longitudes toward west.
+ * @return The UTM zone number numbered from 1 to 60 inclusive, or 0 if the given central meridian was NaN.
+ *
+ * @since 0.7
+ */
+ public static int zone(double longitude) {
+ /*
+ * Casts to int are equivalent to Math.floor(double) for positive values, which is guaranteed
+ * to be the case here since we normalize the central meridian to the [MIN_VALUE … MAX_VALUE] range.
+ */
+ double z = (longitude - Longitude.MIN_VALUE) / ZONE_WIDTH; // Zone number with fractional part.
+ z -= Math.floor(z / ((Longitude.MAX_VALUE - Longitude.MIN_VALUE) / ZONE_WIDTH)) // Roll in the [0 … 60) range.
+ * ((Longitude.MAX_VALUE - Longitude.MIN_VALUE) / ZONE_WIDTH);
+ return (int) (z + 1); // Cast only after addition in order to handle NaN as documented.
+ }
+
+ /**
+ * Computes the central meridian of a given UTM zone.
+ *
+ * @param zone The UTM zone as a number in the [1 … 60] range.
+ * @return The central meridian of the given UTM zone.
+ *
+ * @since 0.7
+ */
+ public static double centralMeridian(final int zone) {
+ return (zone - 0.5) * ZONE_WIDTH + Longitude.MIN_VALUE;
+ }
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -44,11 +44,14 @@ import org.apache.sis.internal.referenci
import org.apache.sis.internal.metadata.WKTKeywords;
import org.apache.sis.internal.util.PatchedUnitFormat;
import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.internal.system.Loggers;
import org.apache.sis.util.Numbers;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.LenientComparable;
import org.apache.sis.util.ObjectConverters;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.UnconvertibleObjectException;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
import static org.apache.sis.util.Utilities.deepEquals;
@@ -504,6 +507,19 @@ public class DefaultParameterValue<T> ex
}
/**
+ * Same as {@link #isFile(Object)}, but accepts also a {@link String} if the type specified
+ * in the parameter descriptor is one of the types documented in {@link #valueFile()}.
+ */
+ private boolean isOrNeedFile(final Object value) {
+ if (value instanceof String) {
+ final Class<?> type = descriptor.getValueClass();
+ return (type == URI.class) || (type == URL.class)
+ || File.class.isAssignableFrom(type);
+ }
+ return isFile(value);
+ }
+
+ /**
* Returns the exception to throw when an incompatible method is invoked for the value type.
*/
private IllegalStateException missingOrIncompatibleValue(final Object value) {
@@ -539,9 +555,25 @@ public class DefaultParameterValue<T> ex
* @see #getValue()
*/
@Override
- public void setValue(final Object value) throws InvalidParameterValueException {
- // Use 'unit' instead than 'getUnit()' despite class Javadoc claims because units are not expected
- // to be involved in this method. We just want the current unit setting to be unchanged.
+ public void setValue(Object value) throws InvalidParameterValueException {
+ /*
+ * Try to convert the value only for a limited amount of types. In particular we want to allow conversions
+ * between java.io.File and java.nio.file.Path for easier transition between JDK6 and JDK7. We do not want
+ * to allow too many conversions for reducing the risk of unexpected behavior. If we fail to convert, try
+ * to set the value anyway since the user may have redefined the setValue(Object, Unit) method.
+ */
+ if (isOrNeedFile(value)) try {
+ value = ObjectConverters.convert(value, descriptor.getValueClass());
+ } catch (UnconvertibleObjectException e) {
+ // Level.FINE (not WARNING) because this log duplicates the exception
+ // that 'setValue(Object, Unit)' may throw (with a better message).
+ Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
+ DefaultParameterValue.class, "setValue", e);
+ }
+ /*
+ * Use 'unit' instead than 'getUnit()' despite class Javadoc claims because units are not expected
+ * to be involved in this method. We just want the current unit setting to be unchanged.
+ */
setValue(value, unit);
}
@@ -829,6 +861,8 @@ public class DefaultParameterValue<T> ex
* @return An unmodifiable implementation of the given parameter, or {@code null} if the given parameter was null.
*
* @since 0.6
+ *
+ * @see DefaultParameterValueGroup#unmodifiable(ParameterValueGroup)
*/
public static <T> DefaultParameterValue<T> unmodifiable(final ParameterValue<T> parameter) {
return UnmodifiableParameterValue.create(parameter);
@@ -895,9 +929,9 @@ public class DefaultParameterValue<T> ex
WKTUtilities.appendName(descriptor, formatter, ElementKind.PARAMETER);
final Convention convention = formatter.getConvention();
final boolean isWKT1 = convention.majorVersion() == 1;
- Unit<?> unit = getUnit(); // Gives to users a chance to override this property.
+ Unit<?> unit = getUnit(); // Gives to users a chance to override this property.
if (unit == null) {
- final T value = getValue(); // Gives to users a chance to override this property.
+ final T value = getValue(); // Gives to users a chance to override this property.
if (!isWKT1 && isFile(value)) {
formatter.append(value.toString(), null);
return WKTKeywords.ParameterFile;
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -18,8 +18,10 @@ package org.apache.sis.parameter;
import java.util.List;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.Map;
import java.util.IdentityHashMap;
+import java.util.Iterator;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlElement;
@@ -38,9 +40,7 @@ import org.apache.sis.util.LenientCompar
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
-
-import static org.apache.sis.util.Utilities.deepEquals;
-import static org.apache.sis.referencing.IdentifiedObjects.isHeuristicMatchForName;
+import org.apache.sis.util.Utilities;
// Branch-dependent imports
import org.apache.sis.internal.jdk7.Objects;
@@ -103,7 +103,7 @@ import org.apache.sis.internal.jdk7.Obje
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.7
* @module
*
* @see DefaultParameterDescriptorGroup
@@ -206,7 +206,7 @@ public class DefaultParameterValueGroup
@Override
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public List<GeneralParameterValue> values() {
- return values; // Intentionally modifiable.
+ return values; // Intentionally modifiable.
}
/**
@@ -305,7 +305,7 @@ public class DefaultParameterValueGroup
for (int i=0; i<size; i++) {
final GeneralParameterDescriptor descriptor = values.descriptor(i);
if (descriptor instanceof ParameterDescriptor<?>) {
- if (isHeuristicMatchForName(descriptor, name)) {
+ if (IdentifiedObjects.isHeuristicMatchForName(descriptor, name)) {
if (fallback < 0) {
fallback = i;
} else {
@@ -334,7 +334,7 @@ public class DefaultParameterValueGroup
*
* @param name The name of the parameter to search for.
* @return The set of all parameter group for the given name.
- * @throws ParameterNotFoundException If no descriptor was found for the given name.
+ * @throws ParameterNotFoundException if no descriptor was found for the given name.
*/
@Override
public List<ParameterValueGroup> groups(final String name) throws ParameterNotFoundException {
@@ -345,7 +345,7 @@ public class DefaultParameterValueGroup
for (int i=0; i<size; i++) {
final GeneralParameterDescriptor descriptor = values.descriptor(i);
if (descriptor instanceof ParameterDescriptorGroup) {
- if (isHeuristicMatchForName(descriptor, name)) {
+ if (IdentifiedObjects.isHeuristicMatchForName(descriptor, name)) {
groups.add((ParameterValueGroup) values.get(i));
}
}
@@ -358,8 +358,8 @@ public class DefaultParameterValueGroup
if (groups.isEmpty()) {
final ParameterDescriptorGroup descriptor = values.descriptor;
if (!(descriptor.descriptor(name) instanceof ParameterDescriptorGroup)) {
- throw new ParameterNotFoundException(Errors.format(
- Errors.Keys.ParameterNotFound_2, descriptor.getName(), name), name);
+ throw new ParameterNotFoundException(Errors.format(Errors.Keys.ParameterNotFound_2,
+ Verifier.getDisplayName(descriptor), name), name);
}
}
return groups;
@@ -377,8 +377,8 @@ public class DefaultParameterValueGroup
*
* @param name The name of the parameter group to create.
* @return A newly created parameter group for the given name.
- * @throws ParameterNotFoundException If no descriptor was found for the given name.
- * @throws InvalidParameterCardinalityException If this parameter group already contains the
+ * @throws ParameterNotFoundException if no descriptor was found for the given name.
+ * @throws InvalidParameterCardinalityException if this parameter group already contains the
* {@linkplain ParameterDescriptorGroup#getMaximumOccurs() maximum number of occurrences}
* of subgroups of the given name.
*/
@@ -400,7 +400,14 @@ public class DefaultParameterValueGroup
/**
* Compares the specified object with this parameter for equality.
- * The strictness level is controlled by the second argument.
+ * The strictness level is controlled by the second argument:
+ *
+ * <ul>
+ * <li>{@link ComparisonMode#STRICT} and {@link ComparisonMode#BY_CONTRACT BY_CONTRACT}
+ * take in account the parameter order.</li>
+ * <li>{@link ComparisonMode#IGNORE_METADATA} and {@link ComparisonMode#APPROXIMATIVE APPROXIMATIVE}
+ * ignore the order of parameter values (but not necessarily the order of parameter descriptors).</li>
+ * </ul>
*
* @param object The object to compare to {@code this}.
* @param mode The strictness level of the comparison.
@@ -420,15 +427,37 @@ public class DefaultParameterValueGroup
Objects.equals(values, that.values);
}
} else if (object instanceof ParameterValueGroup) {
- final ParameterValueGroup that = (ParameterValueGroup) object;
- return deepEquals(getDescriptor(), that.getDescriptor(), mode) &&
- deepEquals(values(), that.values(), mode);
+ return equals(this, (ParameterValueGroup) object, mode);
}
}
return false;
}
/**
+ * Compares the given objects for equality, ignoring parameter order in "ignore metadata" mode.
+ */
+ static boolean equals(final Parameters expected, final ParameterValueGroup actual, final ComparisonMode mode) {
+ if (!Utilities.deepEquals(expected.getDescriptor(), actual.getDescriptor(), mode)) {
+ return false;
+ }
+ if (!mode.isIgnoringMetadata()) {
+ return Utilities.deepEquals(expected.values(), actual.values(), mode);
+ }
+ final List<GeneralParameterValue> values = new LinkedList<GeneralParameterValue>(expected.values());
+scan: for (final GeneralParameterValue param : actual.values()) {
+ final Iterator<GeneralParameterValue> it = values.iterator();
+ while (it.hasNext()) {
+ if (Utilities.deepEquals(it.next(), param, mode)) {
+ it.remove();
+ continue scan;
+ }
+ }
+ return false; // A parameter from 'actual' has not been found in 'expected'.
+ }
+ return values.isEmpty();
+ }
+
+ /**
* Compares the specified object with this parameter for equality.
* This method is implemented as below:
*
@@ -449,7 +478,7 @@ public class DefaultParameterValueGroup
/**
* Returns a hash value for this parameter.
*
- * @return The hash code value. This value doesn't need to be the same
+ * @return The hash code value. This value does not need to be the same
* in past or future versions of this class.
*/
@Override
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -20,9 +20,6 @@ import javax.measure.unit.Unit;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.GeneralParameterDescriptor;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.referencing.cs.CoordinateSystem; // For javadoc
-import org.opengis.referencing.crs.CoordinateReferenceSystem; // For javadoc
import org.apache.sis.measure.MeasurementRange;
import org.apache.sis.measure.NumberRange;
import org.apache.sis.measure.Range;
@@ -428,8 +425,6 @@ public class ParameterBuilder extends Bu
* for the group to create.
* @return The parameter descriptor group for a map projection.
*
- * @see org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#createBaseToDerived(CoordinateReferenceSystem, ParameterValueGroup, CoordinateSystem)
- *
* @since 0.6
*/
public ParameterDescriptorGroup createGroupForMapProjection(final ParameterDescriptor<?>... parameters) {
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -124,6 +124,24 @@ public abstract class Parameters impleme
}
/**
+ * Returns the given parameter value group as an unmodifiable {@code Parameters} instance.
+ * If the given parameters is already an unmodifiable instance of {@code Parameters},
+ * then it is returned as-is. Otherwise this method copies all parameter values in a new,
+ * unmodifiable, parameter group instance.
+ *
+ * @param parameters The parameters to make unmodifiable, or {@code null}.
+ * @return An unmodifiable group with the same parameters than the given group,
+ * or {@code null} if the given argument was null.
+ *
+ * @since 0.7
+ *
+ * @see DefaultParameterValue#unmodifiable(ParameterValue)
+ */
+ public static Parameters unmodifiable(final ParameterValueGroup parameters) {
+ return UnmodifiableParameterValueGroup.create(parameters);
+ }
+
+ /**
* Returns the given parameter value group as a {@code Parameters} instance.
* If the given parameters is already an instance of {@code Parameters}, then it is returned as-is.
* Otherwise this method returns a wrapper which delegate all method invocations to the given instance.
@@ -352,15 +370,32 @@ public abstract class Parameters impleme
* The {@link DefaultParameterValueGroup} subclass will override this method with a more efficient
* implementation which avoid creating some deferred parameters.
*/
+ @SuppressWarnings("null")
ParameterValue<?> parameterIfExist(final String name) throws ParameterNotFoundException {
+ ParameterValue<?> fallback = null;
+ ParameterValue<?> ambiguity = null;
for (final GeneralParameterValue value : values()) {
if (value instanceof ParameterValue<?>) {
- if (isHeuristicMatchForName(value.getDescriptor(), name)) {
- return (ParameterValue<?>) value;
+ final ParameterValue<?> param = (ParameterValue<?>) value;
+ final ParameterDescriptor<?> descriptor = param.getDescriptor();
+ if (name.equals(descriptor.getName().toString())) {
+ return param;
+ }
+ if (isHeuristicMatchForName(descriptor, name)) {
+ if (fallback == null) {
+ fallback = param;
+ } else {
+ ambiguity = param;
+ }
}
}
}
- return null;
+ if (ambiguity != null) {
+ throw new ParameterNotFoundException(Errors.format(Errors.Keys.AmbiguousName_3,
+ IdentifiedObjects.toString(fallback .getDescriptor().getName()),
+ IdentifiedObjects.toString(ambiguity.getDescriptor().getName()), name), name);
+ }
+ return fallback;
}
/**
@@ -408,7 +443,7 @@ public abstract class Parameters impleme
}
/**
- * Returns the value of the parameter identified by the given descriptor.
+ * Returns the value of the parameter identified by the given descriptor, or {@code null} if none.
* This method uses the following information from the given {@code parameter} descriptor:
*
* <ul>
@@ -465,6 +500,30 @@ public abstract class Parameters impleme
}
/**
+ * Returns the value of the parameter identified by the given descriptor, or throws an exception if none.
+ * The default implementation invokes {@link #getValue(ParameterDescriptor)} and verifies that the returned
+ * value is non-null.
+ *
+ * @param <T> The type of the parameter value.
+ * @param parameter The name or alias of the parameter to look for, together with the desired type and unit of value.
+ * @return The requested parameter value if it exists, or the {@linkplain DefaultParameterDescriptor#getDefaultValue()
+ * default value} otherwise provided that it is not {@code null}.
+ * @throws ParameterNotFoundException if the given {@code parameter} name or alias is not legal for this group.
+ * @throws IllegalStateException if the value is not defined and there is no default value.
+ *
+ * @since 0.7
+ */
+ public <T> T getMandatoryValue(final ParameterDescriptor<T> parameter) throws ParameterNotFoundException {
+ final T value = getValue(parameter);
+ if (value != null) {
+ return value;
+ } else {
+ throw new IllegalStateException(Errors.format(Errors.Keys.MissingValueForParameter_1,
+ Verifier.getDisplayName(parameter)));
+ }
+ }
+
+ /**
* Returns the default value of the given descriptor, or throws an exception if the
* descriptor does not define a default value. This check should be kept consistent
* with the {@link DefaultParameterValue#incompatibleValue(Object)} check.
@@ -721,7 +780,7 @@ public abstract class Parameters impleme
target.setValue(((Number) v).doubleValue(), unit);
} else if (v instanceof double[]) {
target.setValue((double[]) v, unit);
- } else {
+ } else if (v != target.getValue()) { // Accept null value if the target value is already null.
throw new InvalidParameterValueException(Errors.format(
Errors.Keys.IllegalArgumentValue_2, name, v), name, v);
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -17,6 +17,7 @@
package org.apache.sis.parameter;
import javax.measure.unit.Unit;
+import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterValue;
import org.apache.sis.internal.util.Cloner;
import org.apache.sis.util.collection.WeakHashSet;
@@ -54,6 +55,7 @@ import org.apache.sis.util.resources.Err
* @version 0.6
* @module
*/
+@XmlTransient
final class UnmodifiableParameterValue<T> extends DefaultParameterValue<T> {
/**
* For cross-version compatibility.
@@ -117,6 +119,7 @@ final class UnmodifiableParameterValue<T
* Returns a modifiable copy of this parameter.
*/
@Override
+ @SuppressWarnings("CloneDoesntCallSuperClone")
public DefaultParameterValue<T> clone() {
return new DefaultParameterValue<T>(this);
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -174,7 +174,7 @@ public class AbstractIdentifiedObject ex
* The name for this object or code. Shall never be {@code null}.
*
* <p><b>Consider this field as final!</b>
- * This field is modified only at unmarshalling time by {@link #addName(ReferenceIdentifier)}.</p>
+ * This field is modified only at unmarshalling time by {@link Names#add(Identifier)}.</p>
*
* @see #getName()
* @see #getNames()
@@ -187,7 +187,7 @@ public class AbstractIdentifiedObject ex
* we may get both on unmarshalling.
*
* <p><b>Consider this field as final!</b>
- * This field is modified only at unmarshalling time by {@link #addName(ReferenceIdentifier)}.</p>
+ * This field is modified only at unmarshalling time by {@link Names#add(Identifier)}.</p>
*/
private Collection<GenericName> alias;
@@ -654,6 +654,8 @@ public class AbstractIdentifiedObject ex
* <cite>When object name matter</cite> below.</td></tr>
* <tr><td>{@link ComparisonMode#APPROXIMATIVE APPROXIMATIVE}:</td>
* <td>Same as {@code IGNORE_METADATA}, with some tolerance threshold on numerical values.</td></tr>
+ * <tr><td>{@link ComparisonMode#ALLOW_VARIANT ALLOW_VARIANT}:</td>
+ * <td>Same as {@code APPROXIMATIVE}, but ignores coordinate system axes.</td></tr>
* <tr><td>{@link ComparisonMode#DEBUG DEBUG}:</td>
* <td>Special mode for figuring out why two objects expected to be equal are not.</td></tr>
* </table>
@@ -728,6 +730,7 @@ public class AbstractIdentifiedObject ex
}
case IGNORE_METADATA:
case APPROXIMATIVE:
+ case ALLOW_VARIANT:
case DEBUG: {
return implementsSameInterface(object);
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -33,6 +33,8 @@ import org.opengis.referencing.Identifie
import org.apache.sis.metadata.iso.ImmutableIdentifier;
import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.internal.util.Citations;
+import org.apache.sis.internal.referencing.DeprecatedCode;
+import org.apache.sis.internal.referencing.DeprecatedName;
import org.apache.sis.util.iso.Types;
import org.apache.sis.util.Deprecable;
import org.apache.sis.util.resources.Errors;
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -122,7 +122,7 @@ public final class CRS extends Static {
* <tr><td>EPSG:4979</td> <td>{@link CommonCRS#WGS84 WGS84}</td> <td>Geographic 3D</td> <td>World Geodetic System 1984</td></tr>
* <tr><td>EPSG:4984</td> <td>{@link CommonCRS#WGS72 WGS72}</td> <td>Geocentric</td> <td>World Geodetic System 1972</td></tr>
* <tr><td>EPSG:4985</td> <td>{@link CommonCRS#WGS72 WGS72}</td> <td>Geographic 3D</td> <td>World Geodetic System 1972</td></tr>
- * <tr><td>EPSG:5715</td> <td>{@link CommonCRS.Vertical#DEPTH DEPTH}</td> <td>Vertical</td> <td>Mean Sea Level depth</td></tr>
+ * <tr><td>EPSG:5715</td> <td>{@link CommonCRS.Vertical#DEPTH DEPTH}</td> <td>Vertical</td> <td>Mean Sea Level depth</td></tr>
* <tr><td>EPSG:5714</td> <td>{@link CommonCRS.Vertical#MEAN_SEA_LEVEL MEAN_SEA_LEVEL}</td> <td>Vertical</td> <td>Mean Sea Level height</td></tr>
* </table></blockquote>
*
@@ -138,6 +138,8 @@ public final class CRS extends Static {
* @throws NoSuchAuthorityCodeException If there is no known CRS associated to the given code.
* @throws FactoryException if the CRS creation failed for an other reason.
*
+ * @see org.apache.sis.referencing.factory.GeodeticAuthorityFactory
+ *
* @category factory
*/
public static CoordinateReferenceSystem forCode(final String code)
@@ -260,7 +262,7 @@ public final class CRS extends Static {
* CRS as horizontal if it is two-dimensional and comply with one of the following conditions:
*
* <ul>
- * <li>is an instance of {@link GeographicCRS}, or</li>
+ * <li>is an instance of {@link GeographicCRS} (or an equivalent {@link GeodeticCRS}), or</li>
* <li>is an instance of {@link ProjectedCRS}, or</li>
* <li>is an instance of {@link EngineeringCRS} (following
* <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#111">ISO 19162 §16.1</a>
@@ -282,8 +284,17 @@ public final class CRS extends Static {
* @category information
*/
public static boolean isHorizontalCRS(final CoordinateReferenceSystem crs) {
- if (crs instanceof GeographicCRS || crs instanceof ProjectedCRS || crs instanceof EngineeringCRS) {
- return crs.getCoordinateSystem().getDimension() == 2;
+ /*
+ * In order to determine if the CRS is geographic, checking the CoordinateSystem type is more reliable
+ * then checking if the CRS implements the GeographicCRS interface. This is because the GeographicCRS
+ * interface is GeoAPI-specific, so a CRS may be OGC-compliant without implementing that interface.
+ */
+ final boolean isGeodetic = (crs instanceof GeodeticCRS);
+ if (isGeodetic || crs instanceof ProjectedCRS || crs instanceof EngineeringCRS) {
+ final CoordinateSystem cs = crs.getCoordinateSystem();
+ if (cs.getDimension() == 2) {
+ return !isGeodetic || (cs instanceof EllipsoidalCS);
+ }
}
return false;
}
@@ -307,21 +318,24 @@ public final class CRS extends Static {
if (isHorizontalCRS(crs)) {
return (SingleCRS) crs;
}
- if (crs instanceof GeographicCRS) {
- EllipsoidalCS cs = ((GeographicCRS) crs).getCoordinateSystem();
- final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
- if (i >= 0) {
- final CoordinateSystemAxis xAxis = cs.getAxis(i > 0 ? 0 : 1);
- final CoordinateSystemAxis yAxis = cs.getAxis(i > 1 ? 1 : 2);
- cs = CommonCRS.DEFAULT.geographic().getCoordinateSystem();
- if (!Utilities.equalsIgnoreMetadata(cs.getAxis(0), xAxis) ||
- !Utilities.equalsIgnoreMetadata(cs.getAxis(1), yAxis))
- {
- // We can not reuse the name of the existing CS, because it typically
- // contains text about axes including the axis that we just dropped.
- cs = new DefaultEllipsoidalCS(singletonMap(EllipsoidalCS.NAME_KEY, "Ellipsoidal 2D"), xAxis, yAxis);
+ if (crs instanceof GeodeticCRS) {
+ CoordinateSystem cs = crs.getCoordinateSystem();
+ if (cs instanceof EllipsoidalCS) { // See comment in isHorizontalCRS(…) method.
+ final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
+ if (i >= 0) {
+ final CoordinateSystemAxis xAxis = cs.getAxis(i > 0 ? 0 : 1);
+ final CoordinateSystemAxis yAxis = cs.getAxis(i > 1 ? 1 : 2);
+ cs = CommonCRS.DEFAULT.geographic().getCoordinateSystem();
+ if (!Utilities.equalsIgnoreMetadata(cs.getAxis(0), xAxis) ||
+ !Utilities.equalsIgnoreMetadata(cs.getAxis(1), yAxis))
+ {
+ // We can not reuse the name of the existing CS, because it typically
+ // contains text about axes including the axis that we just dropped.
+ cs = new DefaultEllipsoidalCS(singletonMap(EllipsoidalCS.NAME_KEY, "Ellipsoidal 2D"), xAxis, yAxis);
+ }
+ return new DefaultGeographicCRS(IdentifiedObjects.getProperties(crs),
+ ((GeodeticCRS) crs).getDatum(), (EllipsoidalCS) cs);
}
- return new DefaultGeographicCRS(IdentifiedObjects.getProperties(crs), ((GeographicCRS) crs).getDatum(), cs);
}
}
if (crs instanceof CompoundCRS) {
@@ -384,17 +398,19 @@ public final class CRS extends Static {
}
} while ((a = !a) == allowCreateEllipsoidal);
}
- if (allowCreateEllipsoidal && crs instanceof GeographicCRS) {
+ if (allowCreateEllipsoidal && crs instanceof GeodeticCRS) {
final CoordinateSystem cs = crs.getCoordinateSystem();
- final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
- if (i >= 0) {
- final CoordinateSystemAxis axis = cs.getAxis(i);
- VerticalCRS c = CommonCRS.Vertical.ELLIPSOIDAL.crs();
- if (!c.getCoordinateSystem().getAxis(0).equals(axis)) {
- final Map<String,?> properties = IdentifiedObjects.getProperties(c);
- c = new DefaultVerticalCRS(properties, c.getDatum(), new DefaultVerticalCS(properties, axis));
+ if (cs instanceof EllipsoidalCS) { // See comment in isHorizontalCRS(…) method.
+ final int i = AxisDirections.indexOfColinear(cs, AxisDirection.UP);
+ if (i >= 0) {
+ final CoordinateSystemAxis axis = cs.getAxis(i);
+ VerticalCRS c = CommonCRS.Vertical.ELLIPSOIDAL.crs();
+ if (!c.getCoordinateSystem().getAxis(0).equals(axis)) {
+ final Map<String,?> properties = IdentifiedObjects.getProperties(c);
+ c = new DefaultVerticalCRS(properties, c.getDatum(), new DefaultVerticalCS(properties, axis));
+ }
+ return c;
}
- return c;
}
}
return null;
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -18,6 +18,8 @@ package org.apache.sis.referencing;
import java.util.Map;
import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
import javax.measure.unit.SI;
import javax.measure.unit.NonSI;
import javax.measure.unit.Unit;
@@ -32,7 +34,9 @@ import org.opengis.referencing.crs.Verti
import org.opengis.referencing.crs.TemporalCRS;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.GeocentricCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.cs.TimeCS;
import org.opengis.referencing.cs.VerticalCS;
import org.opengis.referencing.cs.CartesianCS;
@@ -45,7 +49,6 @@ import org.opengis.referencing.datum.Ver
import org.opengis.referencing.datum.VerticalDatumType;
import org.opengis.referencing.datum.TemporalDatum;
import org.opengis.referencing.datum.DatumAuthorityFactory;
-import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.apache.sis.referencing.datum.DefaultVerticalDatum;
import org.apache.sis.referencing.datum.DefaultTemporalDatum;
import org.apache.sis.referencing.cs.AxesConvention;
@@ -56,12 +59,17 @@ import org.apache.sis.referencing.crs.De
import org.apache.sis.referencing.crs.DefaultVerticalCRS;
import org.apache.sis.referencing.crs.DefaultGeographicCRS;
import org.apache.sis.referencing.crs.DefaultGeocentricCRS;
+import org.apache.sis.internal.referencing.provider.TransverseMercator;
+import org.apache.sis.internal.referencing.Formulas;
import org.apache.sis.internal.system.SystemListener;
import org.apache.sis.internal.system.Modules;
import org.apache.sis.internal.system.Loggers;
import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.math.MathFunctions;
+import org.apache.sis.measure.Latitude;
import org.apache.sis.measure.Units;
import static java.util.Collections.singletonMap;
@@ -72,6 +80,9 @@ import static org.apache.sis.internal.ut
import static org.apache.sis.internal.util.Constants.CRS83;
import static org.apache.sis.internal.util.Constants.CRS84;
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.JDK8;
+
/**
* Frequently-used geodetic CRS and datum that are guaranteed to be available in SIS.
@@ -115,9 +126,12 @@ import static org.apache.sis.internal.ut
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.5
+ * @version 0.7
* @module
+ *
+ * @see org.apache.sis.referencing.factory.CommonAuthorityFactory
*/
+@SuppressWarnings("DoubleCheckedLocking")
public enum CommonCRS {
/**
* World Geodetic System 1984.
@@ -133,9 +147,11 @@ public enum CommonCRS {
* <tr><th>Semi-minor axis length:</th> <td>6356752 <i>(approximative)</i></td></tr>
* <tr><th>Inverse flattening:</th> <td>298.257223563 <i>(definitive)</i></td></tr>
* <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
+ * <tr><th>UTM zones:</th> <td>1 to 60 in North and South hemispheres</td></tr>
* </table></blockquote>
*/
- WGS84((short) 4326, (short) 4979, (short) 4978, (short) 6326, (short) 7030),
+ WGS84((short) 4326, (short) 4979, (short) 4978, (short) 6326, (short) 7030, // Geodetic info
+ (short) 32600, (short) 32700, (byte) 1, (byte) 60), // UTM info
/**
* World Geodetic System 1972.
@@ -149,32 +165,11 @@ public enum CommonCRS {
* <tr><th>Semi-minor axis length:</th> <td>6356751 <i>(approximative)</i></td></tr>
* <tr><th>Inverse flattening:</th> <td>298.26 <i>(definitive)</i></td></tr>
* <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
+ * <tr><th>UTM zones:</th> <td>1 to 60 in North and South hemispheres</td></tr>
* </table></blockquote>
*/
- WGS72((short) 4322, (short) 4985, (short) 4984, (short) 6322, (short) 7043),
-
- /**
- * European Terrestrial Reference System 1989.
- * The ellipsoid is <cite>"GRS 1980"</cite>, also known as <cite>"International 1979"</cite>.
- * This ellipsoid is very close, but not identical, to the {@linkplain #WGS84} one.
- *
- * <blockquote><table class="compact" summary="ETRS89 properties.">
- * <tr><th>EPSG identifiers:</th> <td>4258 (<i>datum:</i> 6258, <i>ellipsoid:</i> 7019)</td></tr>
- * <tr><th>Primary names:</th> <td>"ETRS89" (<i>datum:</i> "European Terrestrial Reference System 1989", <i>ellipsoid:</i> "GRS 1980")</td></tr>
- * <tr><th>Abbreviations or aliases:</th><td>"ETRF89", "EUREF89", "ETRS89-GRS80" (<i>ellipsoid:</i> "International 1979")</td></tr>
- * <tr><th>Prime meridian:</th> <td>Greenwich</td></tr>
- * <tr><th>Semi-major axis length:</th> <td>6378137</td></tr>
- * <tr><th>Semi-minor axis length:</th> <td>6356752 <i>(approximative)</i></td></tr>
- * <tr><th>Inverse flattening:</th> <td>298.257222101 <i>(definitive)</i></td></tr>
- * <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
- * </table></blockquote>
- *
- * <div class="note"><b>Note:</b>
- * {@link #NAD83} uses the same ellipsoid for a different datum.
- * The <cite>Web Map Server</cite> {@code "CRS:83"} authority code uses the NAD83 datum,
- * while the {@code "IGNF:MILLER"} authority code uses the GRS80 datum.</div>
- */
- ETRS89((short) 4258, (short) 4937, (short) 4936, (short) 6258, (short) 7019),
+ WGS72((short) 4322, (short) 4985, (short) 4984, (short) 6322, (short) 7043, // Geodetic info
+ (short) 32200, (short) 32300, (byte) 1, (byte) 60), // UTM info
/**
* North American Datum 1983.
@@ -191,6 +186,7 @@ public enum CommonCRS {
* <tr><th>Semi-minor axis length:</th> <td>6356752 <i>(approximative)</i></td></tr>
* <tr><th>Inverse flattening:</th> <td>298.257222101 <i>(definitive)</i></td></tr>
* <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
+ * <tr><th>UTM zones:</th> <td>1 to 23 in the North hemisphere</td></tr>
* </table></blockquote>
*
* <div class="note"><b>Note:</b>
@@ -198,7 +194,8 @@ public enum CommonCRS {
* The <cite>Web Map Server</cite> {@code "CRS:83"} authority code uses the NAD83 datum,
* while the {@code "IGNF:MILLER"} authority code uses the GRS80 datum.</div>
*/
- NAD83((short) 4269, (short) 0, (short) 0, (short) 6269, (short) 7019),
+ NAD83((short) 4269, (short) 0, (short) 0, (short) 6269, (short) 7019, // Geodetic info
+ (short) 26900, (short) 0, (byte) 1, (byte) 23), // UTM info
/**
* North American Datum 1927.
@@ -212,9 +209,36 @@ public enum CommonCRS {
* <tr><th>Semi-major axis length:</th> <td>6378206.4</td></tr>
* <tr><th>Semi-minor axis length:</th> <td>6356583.8 <i>(definitive)</i></td></tr>
* <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
+ * <tr><th>UTM zones:</th> <td>1 to 22 in the North hemisphere</td></tr>
* </table></blockquote>
*/
- NAD27((short) 4267, (short) 0, (short) 0, (short) 6267, (short) 7008),
+ NAD27((short) 4267, (short) 0, (short) 0, (short) 6267, (short) 7008, // Geodetic info
+ (short) 26700, (short) 0, (byte) 1, (byte) 22), // UTM info
+
+ /**
+ * European Terrestrial Reference System 1989.
+ * The ellipsoid is <cite>"GRS 1980"</cite>, also known as <cite>"International 1979"</cite>.
+ * This ellipsoid is very close, but not identical, to the {@linkplain #WGS84} one.
+ *
+ * <blockquote><table class="compact" summary="ETRS89 properties.">
+ * <tr><th>EPSG identifiers:</th> <td>4258 (<i>datum:</i> 6258, <i>ellipsoid:</i> 7019)</td></tr>
+ * <tr><th>Primary names:</th> <td>"ETRS89" (<i>datum:</i> "European Terrestrial Reference System 1989", <i>ellipsoid:</i> "GRS 1980")</td></tr>
+ * <tr><th>Abbreviations or aliases:</th><td>"ETRF89", "EUREF89", "ETRS89-GRS80" (<i>ellipsoid:</i> "International 1979")</td></tr>
+ * <tr><th>Prime meridian:</th> <td>Greenwich</td></tr>
+ * <tr><th>Semi-major axis length:</th> <td>6378137</td></tr>
+ * <tr><th>Semi-minor axis length:</th> <td>6356752 <i>(approximative)</i></td></tr>
+ * <tr><th>Inverse flattening:</th> <td>298.257222101 <i>(definitive)</i></td></tr>
+ * <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
+ * <tr><th>UTM zones:</th> <td>28 to 38 in the North hemisphere</td></tr>
+ * </table></blockquote>
+ *
+ * <div class="note"><b>Note:</b>
+ * {@link #NAD83} uses the same ellipsoid for a different datum.
+ * The <cite>Web Map Server</cite> {@code "CRS:83"} authority code uses the NAD83 datum,
+ * while the {@code "IGNF:MILLER"} authority code uses the GRS80 datum.</div>
+ */
+ ETRS89((short) 4258, (short) 4937, (short) 4936, (short) 6258, (short) 7019, // Geodetic info
+ (short) 25800, (short) 0, (byte) 28, (byte) 38), // UTM info
/**
* European Datum 1950.
@@ -228,9 +252,11 @@ public enum CommonCRS {
* <tr><th>Semi-minor axis length:</th> <td>6356912 <i>(approximative)</i></td></tr>
* <tr><th>Inverse flattening:</th> <td>297 <i>(definitive)</i></td></tr>
* <tr><th>Ellipsoid axes unit:</th> <td>{@link SI#METRE}</td></tr>
+ * <tr><th>UTM zones:</th> <td>28 to 38 in the North hemisphere</td></tr>
* </table></blockquote>
*/
- ED50((short) 4230, (short) 0, (short) 0, (short) 6230, (short) 7022),
+ ED50((short) 4230, (short) 0, (short) 0, (short) 6230, (short) 7022, // Geodetic info
+ (short) 23000, (short) 0, (byte) 28, (byte) 38), // UTM info
/**
* Unspecified datum based upon the GRS 1980 Authalic Sphere. Spheres use a simpler algorithm for
@@ -248,7 +274,8 @@ public enum CommonCRS {
*
* @see org.apache.sis.referencing.datum.DefaultEllipsoid#getAuthalicRadius()
*/
- SPHERE((short) 4047, (short) 0, (short) 0, (short) 6047, (short) 7048);
+ SPHERE((short) 4047, (short) 0, (short) 0, (short) 6047, (short) 7048, // Geodetic info
+ (short) 0, (short) 0, (byte) 0, (byte) 0); // UTM info
/**
* The enum for the default CRS.
@@ -285,6 +312,16 @@ public enum CommonCRS {
final short ellipsoid;
/**
+ * EPSG codes of pseudo "UTM zone zero" (North case and South case), or 0 if none.
+ */
+ final short northUTM, southUTM;
+
+ /**
+ * Zone number of the first UTM and last UTM zone defined in the EPSG database, inclusive.
+ */
+ final byte firstZone, lastZone;
+
+ /**
* The cached object. This is initially {@code null}, then set to various kind of objects depending
* on which method has been invoked. The kind of object stored in this field may change during the
* application execution.
@@ -313,6 +350,14 @@ public enum CommonCRS {
private transient volatile GeocentricCRS cachedGeocentric;
/**
+ * The Universal Transverse Mercator projections, created when first needed.
+ * All accesses to this map shall be synchronized on {@code cachedUTM}.
+ *
+ * @see #UTM(double, double)
+ */
+ private final Map<Integer,ProjectedCRS> cachedUTM;
+
+ /**
* Creates a new constant for the given EPSG or SIS codes.
*
* @param geographic The EPSG code for the two-dimensional geographic CRS.
@@ -321,14 +366,19 @@ public enum CommonCRS {
* @param datum The EPSG code for the datum.
* @param ellipsoid The EPSG code for the ellipsoid.
*/
- private CommonCRS(final short geographic, final short geo3D, final short geocentric,
- final short datum, final short ellipsoid)
+ private CommonCRS(final short geographic, final short geo3D, final short geocentric, final short datum, final short ellipsoid,
+ final short northUTM, final short southUTM, final byte firstZone, final byte lastZone)
{
this.geographic = geographic;
this.geocentric = geocentric;
this.geo3D = geo3D;
this.datum = datum;
this.ellipsoid = ellipsoid;
+ this.northUTM = northUTM;
+ this.southUTM = southUTM;
+ this.firstZone = firstZone;
+ this.lastZone = lastZone;
+ cachedUTM = new HashMap<Integer,ProjectedCRS>();
}
/**
@@ -348,11 +398,15 @@ public enum CommonCRS {
/**
* Invoked by when the cache needs to be cleared after a classpath change.
*/
+ @SuppressWarnings("NestedSynchronizedStatement") // Safe because cachedUTM never call any method of 'this'.
synchronized void clear() {
cached = null;
cachedGeo3D = null;
cachedNormalized = null;
cachedGeocentric = null;
+ synchronized (cachedUTM) {
+ cachedUTM.clear();
+ }
}
/**
@@ -460,7 +514,7 @@ public enum CommonCRS {
failure(this, "geographic", e);
}
/*
- * All constants defined in this enumeration use the same coordinate system, EPSG:6422.
+ * All constants defined in this enumeration use the same coordinate system, EPSG::6422.
* We will arbitrarily create this CS only for the most frequently created CRS,
* and share that CS instance for all other constants.
*/
@@ -517,7 +571,7 @@ public enum CommonCRS {
}
}
/*
- * All constants defined in this enumeration use the same coordinate system, EPSG:6423.
+ * All constants defined in this enumeration use the same coordinate system, EPSG::6423.
* We will arbitrarily create this CS only for the most frequently created CRS,
* and share that CS instance for all other constants.
*/
@@ -575,7 +629,7 @@ public enum CommonCRS {
}
}
/*
- * All constants defined in this enumeration use the same coordinate system, EPSG:6500.
+ * All constants defined in this enumeration use the same coordinate system, EPSG::6500.
* We will arbitrarily create this CS only for the most frequently created CRS,
* and share that CS instance for all other constants.
*/
@@ -664,7 +718,7 @@ public enum CommonCRS {
object = ellipsoid(cached);
if (object == null) {
if (this == NAD83) {
- object = ETRS89.ellipsoid(); // Share the same instance for NAD83 and ETRS89.
+ object = ETRS89.ellipsoid(); // Share the same instance for NAD83 and ETRS89.
} else {
final DatumAuthorityFactory factory = datumFactory();
if (factory != null) try {
@@ -704,7 +758,7 @@ public enum CommonCRS {
object = primeMeridian(cached);
if (object == null) {
if (this != DEFAULT) {
- object = DEFAULT.primeMeridian(); // Share the same instance for all constants.
+ object = DEFAULT.primeMeridian(); // Share the same instance for all constants.
} else {
final DatumAuthorityFactory factory = datumFactory();
if (factory != null) try {
@@ -764,6 +818,130 @@ public enum CommonCRS {
return (datum != null) ? datum.getPrimeMeridian() : null;
}
+ /*
+ * NOTE ABOUT MAP PROJECTION CONVENIENCE METHODS:
+ * There is no convenience method for projections other than UTM because this enumeration is not a
+ * factory for arbitrary CRS (the UTM projection has the advantage of being constrained to zones).
+ * World-wide projections like "WGS 84 / World Mercator" are not handled neither because they make
+ * sense only for some datum like WGS84 or WGS72. Application to more regional datum like NAD27 or
+ * ED50 would be more questionable.
+ */
+
+ /**
+ * Returns a Universal Transverse Mercator (UTM) projection for the zone containing the given point.
+ * There is a total of 120 UTM zones, with 60 zones in the North hemisphere and 60 zones in the South hemisphere.
+ * The projection zone is determined from the arguments as below:
+ *
+ * <ul>
+ * <li>The sign of the <var>latitude</var> argument determines the hemisphere:
+ * North for positive latitudes (including positive zero) or
+ * South for negative latitudes (including negative zero).
+ * The latitude magnitude is ignored, except for ensuring that the latitude is inside the [-90 … 90]° range.</li>
+ * <li>The value of the <var>longitude</var> argument determines the 6°-width zone,
+ * numbered from 1 for the zone starting at 180°W up to 60 for the zone finishing at 180°E.
+ * Longitudes outside the [-180 … 180]° range will be rolled as needed before to compute the zone.</li>
+ * </ul>
+ *
+ * <div class="note"><b>Warning:</b>
+ * be aware of parameter order! For this method, latitude is first.
+ * This order is for consistency with the non-normalized {@linkplain #geographic() geographic} CRS
+ * of all items in this {@code CommonCRS} enumeration.</div>
+ *
+ * The map projection uses the following parameters:
+ *
+ * <blockquote><table class="sis">
+ * <caption>Universal Transverse Mercator (UTM) parameters</caption>
+ * <tr><th>Parameter name</th> <th>Value</th></tr>
+ * <tr><td>Latitude of natural origin</td> <td>0°</td></tr>
+ * <tr><td>Longitude of natural origin</td> <td>Central meridian of the UTM zone containing the given longitude</td></tr>
+ * <tr><td>Scale factor at natural origin</td> <td>0.9996</td></tr>
+ * <tr><td>False easting</td> <td>500000 metres</td></tr>
+ * <tr><td>False northing</td> <td>0 (North hemisphere) or 10000000 (South hemisphere) metres</td></tr>
+ * </table></blockquote>
+ *
+ * The coordinate system axes are (Easting, Northing) in metres.
+ *
+ * @param latitude A latitude in the desired UTM projection zone.
+ * @param longitude A longitude in the desired UTM projection zone.
+ * @return A Universal Transverse Mercator projection for the zone containing the given point.
+ *
+ * @since 0.7
+ */
+ public ProjectedCRS UTM(final double latitude, final double longitude) {
+ ArgumentChecks.ensureBetween("latitude", Latitude.MIN_VALUE, Latitude.MAX_VALUE, latitude);
+ ArgumentChecks.ensureBetween("longitude", -Formulas.LONGITUDE_MAX, Formulas.LONGITUDE_MAX, longitude);
+ final boolean isSouth = MathFunctions.isNegative(latitude);
+ final int zone = TransverseMercator.zone(longitude);
+ final Integer key = isSouth ? -zone : zone;
+ ProjectedCRS crs;
+ synchronized (cachedUTM) {
+ crs = cachedUTM.get(key);
+ }
+ if (crs == null) {
+ int code = 0;
+ if (zone >= firstZone && zone <= lastZone) {
+ code = JDK8.toUnsignedInt(isSouth ? southUTM : northUTM);
+ if (code != 0) {
+ code += zone;
+ final CRSAuthorityFactory factory = crsFactory();
+ if (factory != null) try {
+ return factory.createProjectedCRS(String.valueOf(code));
+ } catch (FactoryException e) {
+ failure(this, "UTM", e);
+ }
+ }
+ }
+ /*
+ * All constants defined in this enumeration use the same coordinate system, EPSG::4400.
+ * We will arbitrarily create this CS only for a frequently created CRS, and share that
+ * CS instance for all other constants.
+ */
+ CartesianCS cs = null;
+ synchronized (DEFAULT.cachedUTM) {
+ final Iterator<ProjectedCRS> it = DEFAULT.cachedUTM.values().iterator();
+ if (it.hasNext()) {
+ cs = it.next().getCoordinateSystem();
+ }
+ }
+ if (cs == null) {
+ if (this != DEFAULT) {
+ cs = DEFAULT.UTM(latitude, longitude).getCoordinateSystem();
+ } else {
+ cs = (CartesianCS) StandardDefinitions.createCoordinateSystem((short) 4400);
+ }
+ }
+ crs = StandardDefinitions.createUTM(code, geographic(), latitude, longitude, cs);
+ final ProjectedCRS other;
+ synchronized (cachedUTM) {
+ other = JDK8.putIfAbsent(cachedUTM, key, crs);
+ }
+ if (other != null) {
+ return other;
+ }
+ }
+ return crs;
+ }
+
+ /**
+ * Returns the CRS for the given EPSG code, or {@code null} if none.
+ * This is a helper method for {@link #forCode(String, String, FactoryException)} only.
+ */
+ private CoordinateReferenceSystem forCode(final int code) {
+ if (code == geographic) return geographic();
+ if (code == geocentric) return geocentric();
+ if (code == geo3D) return geographic3D();
+ final double latitude;
+ int zone;
+ if (northUTM != 0 && (zone = code - northUTM) >= firstZone && zone <= lastZone) {
+ latitude = +1;
+ } else if (southUTM != 0 && (zone = code - southUTM) >= firstZone && zone <= lastZone) {
+ latitude = -1;
+ } else {
+ return null;
+ }
+ return UTM(latitude, TransverseMercator.centralMeridian(zone));
+ }
+
@@ -788,13 +966,15 @@ public enum CommonCRS {
*
* <blockquote><table class="sis">
* <caption>Geodetic objects accessible by enumeration constants</caption>
- * <tr><th>Name or alias</th> <th>Object type</th> <th>Enumeration value</th></tr>
- * <tr><td>Barometric altitude</td> <td>CRS, Datum</td> <td>{@link #BAROMETRIC}</td></tr>
- * <!-- <s>Ellipsoidal height</s> intentionally omitted <td><s>{@link #ELLIPSOIDAL}</s></td> -->
- * <tr><td>Mean Sea Level</td> <td>Datum</td> <td>{@link #MEAN_SEA_LEVEL}</td></tr>
- * <tr><td>Mean Sea Level depth</td> <td>CRS</td> <td>{@link #DEPTH}</td></tr>
- * <tr><td>Mean Sea Level height</td> <td>CRS</td> <td>{@link #MEAN_SEA_LEVEL}</td></tr>
- * <tr><td>Other surface</td> <td>CRS, Datum</td> <td>{@link #OTHER_SURFACE}</td></tr>
+ * <tr><th>Name or alias</th> <th>Object type</th> <th>Enumeration value</th></tr>
+ * <tr><td>Barometric altitude</td> <td>CRS, Datum</td> <td>{@link #BAROMETRIC}</td></tr>
+ * <!-- <s>Ellipsoidal height</s> intentionally omitted <td><s>{@link #ELLIPSOIDAL}</s></td> -->
+ * <tr><td>Mean Sea Level</td> <td>Datum</td> <td>{@link #MEAN_SEA_LEVEL}</td></tr>
+ * <tr><td>Mean Sea Level depth</td> <td>CRS</td> <td>{@link #DEPTH}</td></tr>
+ * <tr><td>Mean Sea Level height</td> <td>CRS</td> <td>{@link #MEAN_SEA_LEVEL}</td></tr>
+ * <tr><td>NAVD88 height</td> <td>CRS</td> <td>{@link #NAVD88}</td></tr>
+ * <tr><td>North American Vertical Datum 1988</td> <td>Datum</td> <td>{@link #NAVD88}</td></tr>
+ * <tr><td>Other surface</td> <td>CRS, Datum</td> <td>{@link #OTHER_SURFACE}</td></tr>
* </table></blockquote>
*
* <div class="note"><b>Note:</b>
@@ -804,8 +984,10 @@ public enum CommonCRS {
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.4
+ * @version 0.7
* @module
+ *
+ * @see org.apache.sis.referencing.factory.CommonAuthorityFactory
*/
public static enum Vertical {
/**
@@ -849,6 +1031,24 @@ public enum CommonCRS {
DEPTH(true, (short) 5715, (short) 5100),
/**
+ * North American Vertical Datum 1988 height.
+ *
+ * <blockquote><table class="compact" summary="Mean Sea Level properties.">
+ * <tr><th>WMS identifier:</th> <td>CRS:88</td></tr>
+ * <tr><th>EPSG identifiers:</th> <td>5703 (<i>datum:</i> 5103)</td></tr>
+ * <tr><th>Primary names:</th> <td>"NAVD88 height" (<i>datum:</i> "North American Vertical Datum 1988")</td></tr>
+ * <tr><th>Abbreviations or aliases:</th> <td>" North American Vertical Datum of 1988 height (m)" (<i>datum:</i> "NAVD88")</td></tr>
+ * <tr><th>Direction:</th> <td>{@link AxisDirection#UP}</td></tr>
+ * <tr><th>Unit:</th> <td>{@link SI#METRE}</td></tr>
+ * </table></blockquote>
+ *
+ * @see CommonCRS#NAD83
+ *
+ * @since 0.7
+ */
+ NAVD88(true, (short) 5703, (short) 5103),
+
+ /**
* Height measured along the normal to the ellipsoid used in the definition of horizontal datum.
* The unit of measurement is metres.
*
@@ -1377,9 +1577,10 @@ public enum CommonCRS {
final int n = Integer.parseInt(code);
if (n != 0) { // CommonCRS uses 0 as a sentinel value for "no EPSG code".
for (final CommonCRS candidate : CommonCRS.values()) {
- if (candidate.geographic == n) return candidate.geographic();
- if (candidate.geocentric == n) return candidate.geocentric();
- if (candidate.geo3D == n) return candidate.geographic3D();
+ final CoordinateReferenceSystem crs = candidate.forCode(n);
+ if (crs != null) {
+ return crs;
+ }
}
for (final CommonCRS.Vertical candidate : CommonCRS.Vertical.values()) {
if (candidate.isEPSG && candidate.crs == n) {
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -89,7 +89,7 @@ import org.apache.sis.internal.jdk7.Obje
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.7
* @module
*/
public class NamedIdentifier extends ImmutableIdentifier implements GenericName {
@@ -143,7 +143,59 @@ public class NamedIdentifier extends Imm
/**
* Constructs an identifier from the given properties. The content of the properties map is used as
- * described in the {@linkplain ImmutableIdentifier#ImmutableIdentifier(Map) super-class constructor}.
+ * described in the {@linkplain ImmutableIdentifier#ImmutableIdentifier(Map) super-class constructor},
+ * with the addition of an optional {@code "name"} property.
+ *
+ * <table class="sis">
+ * <caption>Recognized properties</caption>
+ * <tr>
+ * <th>Property name</th>
+ * <th>Value type</th>
+ * <th>Returned by</th>
+ * </tr>
+ * <tr>
+ * <td>{@code "name"}</td>
+ * <td>{@link GenericName}</td>
+ * <td>(none)</td>
+ * </tr>
+ * <tr>
+ * <th colspan="3" class="hsep">Defined in parent class (reminder)</th>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.metadata.Identifier#CODE_KEY}</td>
+ * <td>{@link String}</td>
+ * <td>{@link #getCode()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.metadata.Identifier#CODESPACE_KEY}</td>
+ * <td>{@link String}</td>
+ * <td>{@link #getCodeSpace()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.metadata.Identifier#AUTHORITY_KEY}</td>
+ * <td>{@link String} or {@link Citation}</td>
+ * <td>{@link #getAuthority()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.metadata.Identifier#VERSION_KEY}</td>
+ * <td>{@link String}</td>
+ * <td>{@link #getVersion()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.opengis.metadata.Identifier#DESCRIPTION_KEY}</td>
+ * <td>{@link String} or {@link InternationalString}</td>
+ * <td>{@link #getDescription()}</td>
+ * </tr>
+ * <tr>
+ * <td>{@value org.apache.sis.referencing.AbstractIdentifiedObject#LOCALE_KEY}</td>
+ * <td>{@link Locale}</td>
+ * <td>(none)</td>
+ * </tr>
+ * </table>
+ *
+ * The {@value org.opengis.metadata.Identifier#CODE_KEY} property is mandatory and all other properties
+ * are optional. If a {@code "name"} property is provided, then calls to name-related methods like
+ * {@link #tip()}, {@link #head()} and {@link #scope()} will delegate to the given name.
*
* @param properties The properties to be given to this identifier.
* @throws InvalidParameterValueException if a property has an invalid value.
@@ -151,6 +203,8 @@ public class NamedIdentifier extends Imm
*/
public NamedIdentifier(final Map<String,?> properties) throws IllegalArgumentException {
super(properties);
+ name = (GenericName) properties.get("name");
+ isNameSupplied = (name != null);
}
/**
@@ -172,7 +226,7 @@ public class NamedIdentifier extends Imm
super(authority, Citations.getCodeSpace(authority), toString(code));
if (code instanceof InternationalString) {
name = createName(authority, super.getCodeSpace(), code);
- isNameSupplied = true; // Because 'code' is an international string.
+ isNameSupplied = true; // Because 'code' is an international string.
}
}
@@ -205,7 +259,7 @@ public class NamedIdentifier extends Imm
super(authority, codeSpace, toString(code), version, description);
if (code instanceof InternationalString) {
name = createName(authority, codeSpace, code);
- isNameSupplied = true; // Because 'code' is an international string.
+ isNameSupplied = true; // Because 'code' is an international string.
}
}
@@ -233,7 +287,7 @@ public class NamedIdentifier extends Imm
/**
* Returns the generic name of this identifier.
* The name will be constructed automatically the first time it will be needed.
- * The name's scope is inferred from the shortest alternative title (if any).
+ * The name's head is inferred from the shortest alternative title (if any).
* This heuristic rule is compatible to the ISO 19115 remark saying that the
* {@linkplain Citation#getAlternateTitles() alternate titles} often contains abbreviation
* (for example "DCW" as an alternative title for "Digital Chart of the World").
@@ -261,7 +315,7 @@ public class NamedIdentifier extends Imm
*/
private static GenericName createName(final Citation authority, String codeSpace, final CharSequence code) {
if (codeSpace == null) {
- codeSpace = Citations.getCodeSpace(authority); // Whitespaces trimed by Citations.
+ codeSpace = Citations.getCodeSpace(authority); // Whitespaces trimed by Citations.
}
final NameFactory factory = DefaultFactories.forBuildin(NameFactory.class);
if (codeSpace != null) {
@@ -411,7 +465,7 @@ public class NamedIdentifier extends Imm
}
if (super.equals(object)) {
if (!isNameSupplied) {
- return true; // No need to compare names if they are computed from the same values.
+ return true; // No need to compare names if they are computed from the same values.
}
final NamedIdentifier that = (NamedIdentifier) object;
return Objects.equals(this.getName(), that.getName());