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/03/30 14:35:11 UTC
svn commit: r1737107 [2/6] - in /sis/trunk: ./
application/sis-console/src/main/artifact/conf/
core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/
core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/
core/sis-metadata/src...
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -24,6 +24,10 @@ import org.opengis.util.FactoryException
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.Transformation;
@@ -67,6 +71,14 @@ public abstract class GeocentricAffine e
private static final long serialVersionUID = 8291967302538661639L;
/**
+ * The tolerance factor for comparing the {@link BursaWolfParameters} values.
+ * We use a tolerance of 1E-6 ({@value Formulas#LINEAR_TOLERANCE} / 10000) based on the knowledge
+ * that the translation terms are in metres and the rotation terms have the some order of magnitude.
+ * Actually we could use a value of zero, but we add a small tolerance for rounding errors.
+ */
+ private static final double BURSAWOLF_TOLERANCE = Formulas.LINEAR_TOLERANCE / 10000;
+
+ /**
* The operation parameter descriptor for the <cite>X-axis translation</cite>
* ({@linkplain BursaWolfParameters#tX tX}) parameter value. Valid values range
* from negative to positive infinity. Units are {@linkplain SI#METRE metres}.
@@ -165,6 +177,16 @@ public abstract class GeocentricAffine e
abstract int getType();
/**
+ * The inverse of this operation is the same operation with parameter signs inverted.
+ *
+ * @return {@code true} for all {@code GeocentricAffine}.
+ */
+ @Override
+ public final boolean isInvertible() {
+ return true;
+ }
+
+ /**
* Creates a math transform from the specified group of parameter values.
* The default implementation creates an affine transform, but some subclasses
* will wrap that affine operation into Geographic/Geocentric conversions.
@@ -200,6 +222,103 @@ public abstract class GeocentricAffine e
}
/**
+ * Creates parameter values for a Molodensky, Geocentric Translation or Position Vector transformation.
+ *
+ * @param descriptor The {@code PARAMETERS} constant of the subclass describing the operation to create.
+ * @param parameters Bursa-Wolf parameters from which to get the values.
+ * @param isTranslation {@code true} if the operation contains only translation terms.
+ * @return The operation parameters with their values initialized.
+ */
+ private static Parameters createParameters(final ParameterDescriptorGroup descriptor,
+ final BursaWolfParameters parameters, final boolean isTranslation)
+ {
+ final Parameters values = Parameters.castOrWrap(descriptor.createValue());
+ values.getOrCreate(TX).setValue(parameters.tX);
+ values.getOrCreate(TY).setValue(parameters.tY);
+ values.getOrCreate(TZ).setValue(parameters.tZ);
+ if (!isTranslation) {
+ values.getOrCreate(RX).setValue(parameters.rX);
+ values.getOrCreate(RY).setValue(parameters.rY);
+ values.getOrCreate(RZ).setValue(parameters.rZ);
+ values.getOrCreate(DS).setValue(parameters.dS);
+ }
+ return values;
+ }
+
+ /**
+ * Returns the parameters for creating a datum shift operation.
+ * The operation method will be one of the {@code GeocentricAffine} subclasses.
+ * If no single operation method can be used, then this method returns {@code null}.
+ *
+ * <p>This method does <strong>not</strong> change the coordinate system type.
+ * The source and target coordinate systems can be both {@code EllipsoidalCS} or both {@code CartesianCS}.
+ * Any other type or mix of types (e.g. a {@code EllipsoidalCS} source and {@code CartesianCS} target)
+ * will cause this method to return {@code null}. In such case, it is caller's responsibility to apply
+ * the datum shift itself in Cartesian geocentric coordinates.</p>
+ *
+ * @param sourceCS The source coordinate system. Only the type and number of dimensions is checked.
+ * @param targetCS The target coordinate system. Only the type and number of dimensions is checked.
+ * @param datumShift The datum shift as a matrix.
+ * @param useMolodensky {@code true} for allowing the use of Molodensky approximation, or {@code false}
+ * for using the transformation in geocentric space (which should be more accurate).
+ * @return The parameter values, or {@code null} if no single operation method can be found.
+ */
+ public static ParameterValueGroup createParameters(final CoordinateSystem sourceCS,
+ final CoordinateSystem targetCS, final Matrix datumShift, boolean useMolodensky)
+ {
+ final boolean isEllipsoidal = (sourceCS instanceof EllipsoidalCS);
+ if (!(isEllipsoidal ? targetCS instanceof EllipsoidalCS
+ : targetCS instanceof CartesianCS && sourceCS instanceof CartesianCS))
+ {
+ return null; // Coordinate systems are not two EllipsoidalCS or two CartesianCS.
+ }
+ @SuppressWarnings("null")
+ int dimension = sourceCS.getDimension();
+ if (dimension != targetCS.getDimension()) {
+ dimension = 0; // Sentinal value for mismatched dimensions.
+ }
+ /*
+ * Try to convert the matrix into (tX, tY, tZ, rX, rY, rZ, dS) parameters.
+ * The matrix may not be convertible, in which case we will let the callers
+ * uses the matrix directly in Cartesian geocentric coordinates.
+ */
+ final BursaWolfParameters parameters = new BursaWolfParameters(null, null);
+ try {
+ parameters.setPositionVectorTransformation(datumShift, BURSAWOLF_TOLERANCE);
+ } catch (IllegalArgumentException e) {
+ log(Loggers.COORDINATE_OPERATION, "createParameters", e);
+ return null;
+ }
+ final boolean isTranslation = parameters.isTranslation();
+ final ParameterDescriptorGroup descriptor;
+ /*
+ * Following "if" blocks are ordered from more accurate to less accurate datum shift method
+ * supported by GeocentricAffine subclasses.
+ */
+ if (!isEllipsoidal) {
+ useMolodensky = false;
+ descriptor = isTranslation ? GeocentricTranslation.PARAMETERS
+ : PositionVector7Param .PARAMETERS;
+ } else {
+ if (!isTranslation) {
+ useMolodensky = false;
+ descriptor = (dimension >= 3) ? PositionVector7Param3D.PARAMETERS
+ : PositionVector7Param2D.PARAMETERS;
+ } else if (!useMolodensky) {
+ descriptor = (dimension >= 3) ? GeocentricTranslation3D.PARAMETERS
+ : GeocentricTranslation2D.PARAMETERS;
+ } else {
+ descriptor = Molodensky.PARAMETERS;
+ }
+ }
+ final Parameters values = createParameters(descriptor, parameters, isTranslation);
+ if (useMolodensky && dimension != 0) {
+ values.getOrCreate(Molodensky.DIMENSION).setValue(dimension);
+ }
+ return values;
+ }
+
+ /**
* Given a transformation chain, conditionally replaces the affine transform elements by an alternative object
* showing the Bursa-Wolf parameters. The replacement is applied if and only if the affine transform is a scale,
* translation or rotation in the geocentric domain.
@@ -211,7 +330,7 @@ public abstract class GeocentricAffine e
*
* @param transforms The full chain of concatenated transforms.
*/
- public static void asDatumShift(final List<Object> transforms) throws IllegalArgumentException {
+ public static void asDatumShift(final List<Object> transforms) {
for (int i=transforms.size() - 2; --i >= 0;) {
if (isOperation(GeographicToGeocentric.NAME, transforms.get(i)) &&
isOperation(GeocentricToGeographic.NAME, transforms.get(i+2)))
@@ -220,31 +339,18 @@ public abstract class GeocentricAffine e
if (step instanceof LinearTransform) {
final BursaWolfParameters parameters = new BursaWolfParameters(null, null);
try {
- /*
- * We use a 0.01 metre tolerance (Formulas.LINEAR_TOLERANCE) based on the knowledge that the
- * translation terms are in metres and the rotation terms have the some order of magnitude.
- */
- parameters.setPositionVectorTransformation(((LinearTransform) step).getMatrix(), Formulas.LINEAR_TOLERANCE);
+ parameters.setPositionVectorTransformation(((LinearTransform) step).getMatrix(), BURSAWOLF_TOLERANCE);
} catch (IllegalArgumentException e) {
/*
* Should not occur, except sometime on inverse transform of relatively complex datum shifts
* (more than just translation terms). We can fallback on formatting the full matrix.
*/
- Logging.recoverableException(Logging.getLogger(Loggers.WKT), GeocentricAffine.class, "asDatumShift", e);
+ log(Loggers.WKT, "asDatumShift", e);
continue;
}
final boolean isTranslation = parameters.isTranslation();
- final Parameters values = Parameters.castOrWrap(
- (isTranslation ? GeocentricTranslation.PARAMETERS : PositionVector7Param.PARAMETERS).createValue());
- values.getOrCreate(TX).setValue(parameters.tX);
- values.getOrCreate(TY).setValue(parameters.tY);
- values.getOrCreate(TZ).setValue(parameters.tZ);
- if (!isTranslation) {
- values.getOrCreate(RX).setValue(parameters.rX);
- values.getOrCreate(RY).setValue(parameters.rY);
- values.getOrCreate(RZ).setValue(parameters.rZ);
- values.getOrCreate(DS).setValue(parameters.dS);
- }
+ final Parameters values = createParameters(isTranslation ? GeocentricTranslation.PARAMETERS
+ : PositionVector7Param.PARAMETERS, parameters, isTranslation);
transforms.set(i+1, new FormattableObject() {
@Override protected String formatTo(final Formatter formatter) {
WKTUtilities.appendParamMT(values, formatter);
@@ -263,4 +369,11 @@ public abstract class GeocentricAffine e
return (actual instanceof Parameterized) &&
IdentifiedObjects.isHeuristicMatchForName(((Parameterized) actual).getParameterDescriptors(), expected);
}
+
+ /**
+ * Logs a warning about a failure to compute the Bursa-Wolf parameters.
+ */
+ private static void log(final String logger, final String method, final Exception e) {
+ Logging.recoverableException(Logging.getLogger(logger), GeocentricAffine.class, method, e);
+ }
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -40,7 +40,7 @@ public final class GeocentricTranslation
/**
* The group of all parameters expected by this coordinate operation.
*/
- private static final ParameterDescriptorGroup PARAMETERS;
+ static final ParameterDescriptorGroup PARAMETERS;
static {
PARAMETERS = builder()
.addIdentifier("1035")
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=1737107&r1=1737106&r2=1737107&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 Mar 30 12:35:10 2016
@@ -101,6 +101,16 @@ public class GeographicOffsets extends A
}
/**
+ * The inverse of this operation is the same operation with parameter signs inverted.
+ *
+ * @return {@code true} for all {@code GeocentricAffine}.
+ */
+ @Override
+ public final boolean isInvertible() {
+ return true;
+ }
+
+ /**
* Creates a transform from the specified group of parameter values.
* The parameter values are unconditionally converted to degrees and metres.
*
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorParameters.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -678,7 +678,7 @@ public class TensorParameters<E> impleme
if (++indices[j] < actualSize[j]) {
break;
}
- indices[j] = 0; // We have done a full turn at that dimension. Will increment next dimension.
+ indices[j] = 0; // We have done a full turn at that dimension. Will increment next dimension.
}
}
return parameters;
@@ -736,6 +736,8 @@ public class TensorParameters<E> impleme
* @param properties The properties to be given to the identified object.
* @param matrix The matrix to copy in the new parameter group.
* @return A new parameter group initialized to the given matrix.
+ *
+ * @see #toMatrix(ParameterValueGroup)
*/
public ParameterValueGroup createValueGroup(final Map<String,?> properties, final Matrix matrix) {
if (rank() != 2) {
@@ -754,6 +756,8 @@ public class TensorParameters<E> impleme
* @param parameters The group of parameters.
* @return A matrix constructed from the specified group of parameters.
* @throws InvalidParameterNameException if a parameter name was not recognized.
+ *
+ * @see #createValueGroup(Map, Matrix)
*/
public Matrix toMatrix(final ParameterValueGroup parameters) throws InvalidParameterNameException {
if (rank() != 2) {
@@ -761,7 +765,7 @@ public class TensorParameters<E> impleme
}
ArgumentChecks.ensureNonNull("parameters", parameters);
if (parameters instanceof TensorValues) {
- return ((TensorValues) parameters).toMatrix(); // More efficient implementation
+ return ((TensorValues) parameters).toMatrix(); // More efficient implementation
}
// Fallback on the general case (others implementations)
final ParameterValue<?> numRow = parameters.parameter(dimensions[0].getName().getCode());
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -110,7 +110,7 @@ final class AuthorityFactories<T extends
if (factory == null) try {
factory = new EPSGFactory(null);
} catch (FactoryException e) {
- log(Level.CONFIG, e);
+ log(e, false);
factory = EPSGFactoryFallback.INSTANCE;
}
EPSG[0] = factory;
@@ -137,37 +137,42 @@ final class AuthorityFactories<T extends
EPSG[0] = factory;
}
}
- log(Level.WARNING, e);
+ log(e, true);
return factory;
}
/**
* Notifies that a factory is unavailable, but without giving a fallback and without logging.
* The caller is responsible for logging a warning and to provide its own fallback.
+ *
+ * @return {@code true} on success, or {@code false} if this method did nothing.
*/
- static void failure(final UnavailableFactoryException e) {
+ static boolean failure(final UnavailableFactoryException e) {
if (!(e.getCause() instanceof SQLTransientException)) {
final AuthorityFactory unavailable = e.getUnavailableFactory();
synchronized (EPSG) {
if (unavailable == EPSG[0]) {
ALL.reload();
EPSG[0] = EPSGFactoryFallback.INSTANCE;
+ return true;
}
}
}
+ return false;
}
/**
* Logs the given exception at the given level. This method pretends that the logging come from
* {@link CRS#getAuthorityFactory(String)}, which is the public facade for {@link #EPSG()}.
*/
- private static void log(final Level level, final Exception e) {
+ private static void log(final Exception e, final boolean isWarning) {
String message = e.getLocalizedMessage();
if (message == null) {
message = e.toString();
}
- final LogRecord record = new LogRecord(level, message);
+ final LogRecord record = new LogRecord(isWarning ? Level.WARNING : Level.CONFIG, message);
record.setLoggerName(Loggers.CRS_FACTORY);
+ if (isWarning) record.setThrown(e);
Logging.log(CRS.class, "getAuthorityFactory", record);
}
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=1737107&r1=1737106&r2=1737107&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 Mar 30 12:35:10 2016
@@ -42,6 +42,7 @@ import org.opengis.referencing.crs.Engin
import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.extent.Extent;
import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.opengis.referencing.operation.CoordinateOperation;
import org.apache.sis.internal.metadata.AxisDirections;
import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.system.DefaultFactories;
@@ -50,8 +51,12 @@ import org.apache.sis.referencing.cs.Def
import org.apache.sis.referencing.crs.DefaultGeographicCRS;
import org.apache.sis.referencing.crs.DefaultVerticalCRS;
import org.apache.sis.referencing.crs.DefaultCompoundCRS;
-import org.apache.sis.metadata.iso.extent.Extents;
+import org.apache.sis.referencing.operation.CoordinateOperationContext;
+import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
import org.apache.sis.referencing.factory.UnavailableFactoryException;
+import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
+import org.apache.sis.metadata.iso.extent.Extents;
+import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.Utilities;
import org.apache.sis.util.Static;
@@ -591,4 +596,43 @@ check: while (lower != 0 || upper != di
}
return AuthorityFactories.ALL.getAuthorityFactory(CRSAuthorityFactory.class, authority, null);
}
+
+ /**
+ * Finds a mathematical operation that transforms or converts coordinates from the given source to the
+ * given target coordinate reference system. If an estimation of the geographic area containing the points
+ * to transform is known, it can be specified for helping this method to find a better suited operation.
+ *
+ * <p>Note that the area of interest is just one aspect that may affect the coordinate operation.
+ * Other aspects are the time of interest (because some coordinate operations take in account the
+ * plate tectonics movement) or the desired accuracy. For more control on the coordinate operation
+ * to create, see {@link CoordinateOperationContext}.</p>
+ *
+ * @param sourceCRS the CRS of source coordinates.
+ * @param targetCRS the CRS of target coordinates.
+ * @param areaOfInterest the area of interest, or {@code null} if none.
+ * @return the mathematical operation from {@code sourceCRS} to {@code targetCRS}.
+ * @throws FactoryException if the operation can not be created.
+ *
+ * @see DefaultCoordinateOperationFactory#createOperation(CoordinateReferenceSystem, CoordinateReferenceSystem, CoordinateOperationContext)
+ *
+ * @since 0.7
+ */
+ public static CoordinateOperation findOperation(final CoordinateReferenceSystem sourceCRS,
+ final CoordinateReferenceSystem targetCRS,
+ final GeographicBoundingBox areaOfInterest)
+ throws FactoryException
+ {
+ ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
+ ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
+ CoordinateOperationContext context = null;
+ if (areaOfInterest != null) {
+ final DefaultGeographicBoundingBox bbox = DefaultGeographicBoundingBox.castOrCopy(areaOfInterest);
+ if (bbox.isEmpty()) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "areaOfInterest"));
+ }
+ context = new CoordinateOperationContext();
+ context.setGeographicBoundingBox(bbox);
+ }
+ return CoordinateOperations.factory.createOperation(sourceCRS, targetCRS, context);
+ }
}
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=1737107&r1=1737106&r2=1737107&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 Mar 30 12:35:10 2016
@@ -20,6 +20,8 @@ import java.util.Map;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
import javax.measure.unit.SI;
import javax.measure.unit.NonSI;
import javax.measure.unit.Unit;
@@ -38,8 +40,10 @@ import org.opengis.referencing.crs.CRSAu
import org.opengis.referencing.cs.TimeCS;
import org.opengis.referencing.cs.VerticalCS;
import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.SphericalCS;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CSAuthorityFactory;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.datum.PrimeMeridian;
@@ -65,8 +69,10 @@ import org.apache.sis.internal.system.Sy
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.util.Exceptions;
import org.apache.sis.math.MathFunctions;
import org.apache.sis.measure.Latitude;
import org.apache.sis.measure.Units;
@@ -279,6 +285,11 @@ public enum CommonCRS {
static final CommonCRS DEFAULT = WGS84;
/**
+ * Properties to exclude when using an other object as a template.
+ */
+ private static final String[] EXCLUDE = new String[] {IdentifiedObject.IDENTIFIERS_KEY};
+
+ /**
* The EPSG code of the two-dimensional geographic CRS.
*/
final short geographic;
@@ -337,13 +348,20 @@ public enum CommonCRS {
private transient volatile GeographicCRS cachedGeo3D;
/**
- * The geocentric CRS, created when first needed.
+ * The geocentric CRS using Cartesian coordinate system, created when first needed.
*
* @see #geocentric()
*/
private transient volatile GeocentricCRS cachedGeocentric;
/**
+ * The geocentric CRS using spherical coordinate system, created when first needed.
+ *
+ * @see #spherical()
+ */
+ private transient volatile GeocentricCRS cachedSpherical;
+
+ /**
* The Universal Transverse Mercator projections, created when first needed.
* All accesses to this map shall be synchronized on {@code cachedUTM}.
*
@@ -505,7 +523,7 @@ public enum CommonCRS {
cached = object = factory.createGeographicCRS(String.valueOf(geographic));
return object;
} catch (FactoryException e) {
- failure(this, "geographic", e);
+ failure(this, "geographic", e, geographic);
}
/*
* All constants defined in this enumeration use the same coordinate system, EPSG:6422.
@@ -561,7 +579,7 @@ public enum CommonCRS {
cachedGeo3D = object = factory.createGeographicCRS(String.valueOf(geo3D));
return object;
} catch (FactoryException e) {
- failure(this, "geographic3D", e);
+ failure(this, "geographic3D", e, geo3D);
}
}
/*
@@ -619,7 +637,7 @@ public enum CommonCRS {
cachedGeocentric = object = factory.createGeocentricCRS(String.valueOf(geocentric));
return object;
} catch (FactoryException e) {
- failure(this, "geocentric", e);
+ failure(this, "geocentric", e, geocentric);
}
}
/*
@@ -644,6 +662,56 @@ public enum CommonCRS {
}
/**
+ * Returns the geocentric CRS using a spherical coordinate system. Axes are:
+ *
+ * <ol>
+ * <li>Spherical latitude in degrees oriented toward {@linkplain AxisDirection#NORTH north}.</li>
+ * <li>Spherical longitude in degrees oriented toward {@linkplain AxisDirection#EAST east}.</li>
+ * <li>Geocentric radius in metres oriented toward {@linkplain AxisDirection#UP up}.</li>
+ * </ol>
+ *
+ * @return The geocentric CRS associated to this enum.
+ *
+ * @see DefaultGeocentricCRS
+ *
+ * @since 0.7
+ */
+ public GeocentricCRS spherical() {
+ GeocentricCRS object = cachedSpherical;
+ if (object == null) {
+ synchronized (this) {
+ object = cachedSpherical;
+ if (object == null) {
+ /*
+ * All constants defined in this enumeration use the same coordinate system, EPSG:6404.
+ * We will arbitrarily create this CS only for the most frequently created CRS,
+ * and share that CS instance for all other constants.
+ */
+ SphericalCS cs = null;
+ if (this == DEFAULT) {
+ final CSAuthorityFactory factory = csFactory();
+ if (factory != null) try {
+ cs = factory.createSphericalCS("6404");
+ } catch (FactoryException e) {
+ failure(this, "spherical", e, (short) 6404);
+ }
+ if (cs == null) {
+ cs = (SphericalCS) StandardDefinitions.createCoordinateSystem((short) 6404);
+ }
+ } else {
+ cs = (SphericalCS) DEFAULT.spherical().getCoordinateSystem();
+ }
+ // Use same name and datum than the geographic CRS.
+ final GeographicCRS base = geographic();
+ object = new DefaultGeocentricCRS(IdentifiedObjects.getProperties(base, EXCLUDE), base.getDatum(), cs);
+ cachedSpherical = object;
+ }
+ }
+ }
+ return object;
+ }
+
+ /**
* Returns the geodetic datum associated to this geodetic object.
* The following table summarizes the datums known to this class,
* together with an enumeration value that can be used for fetching that datum:
@@ -675,7 +743,7 @@ public enum CommonCRS {
cached = object = factory.createGeodeticDatum(String.valueOf(datum));
return object;
} catch (FactoryException e) {
- failure(this, "datum", e);
+ failure(this, "datum", e, datum);
}
object = StandardDefinitions.createGeodeticDatum(datum, ellipsoid(), primeMeridian());
cached = object;
@@ -719,7 +787,7 @@ public enum CommonCRS {
cached = object = factory.createEllipsoid(String.valueOf(ellipsoid));
return object;
} catch (FactoryException e) {
- failure(this, "ellipsoid", e);
+ failure(this, "ellipsoid", e, ellipsoid);
}
object = StandardDefinitions.createEllipsoid(ellipsoid);
}
@@ -759,7 +827,7 @@ public enum CommonCRS {
cached = object = factory.createPrimeMeridian(StandardDefinitions.GREENWICH);
return object;
} catch (FactoryException e) {
- failure(this, "primeMeridian", e);
+ failure(this, "primeMeridian", e, (short) 8901);
}
object = StandardDefinitions.primeMeridian();
}
@@ -881,7 +949,7 @@ public enum CommonCRS {
if (factory != null) try {
return factory.createProjectedCRS(String.valueOf(code));
} catch (FactoryException e) {
- failure(this, "UTM", e);
+ failure(this, "UTM", e, code);
}
}
}
@@ -1131,12 +1199,12 @@ public enum CommonCRS {
cached = object = factory.createVerticalCRS(String.valueOf(crs));
return object;
} catch (FactoryException e) {
- failure(this, "crs", e);
+ failure(this, "crs", e, crs);
}
object = StandardDefinitions.createVerticalCRS(crs, datum());
} else {
final VerticalCS cs = cs();
- object = new DefaultVerticalCRS(IdentifiedObjects.getProperties(cs), datum(), cs);
+ object = new DefaultVerticalCRS(IdentifiedObjects.getProperties(cs, EXCLUDE), datum(), cs);
}
cached = object;
}
@@ -1196,7 +1264,7 @@ public enum CommonCRS {
cached = object = factory.createVerticalDatum(String.valueOf(datum));
return object;
} catch (FactoryException e) {
- failure(this, "datum", e);
+ failure(this, "datum", e, datum);
}
object = StandardDefinitions.createVerticalDatum(datum);
} else {
@@ -1374,7 +1442,7 @@ public enum CommonCRS {
object = crs(cached);
if (object == null) {
final TemporalDatum datum = datum();
- object = new DefaultTemporalCRS(IdentifiedObjects.getProperties(datum), datum, cs());
+ object = new DefaultTemporalCRS(IdentifiedObjects.getProperties(datum, EXCLUDE), datum, cs());
cached = object;
}
}
@@ -1402,8 +1470,8 @@ public enum CommonCRS {
case UNIX: {
// Share the NamedIdentifier created for Java time.
final TimeCS share = JAVA.crs().getCoordinateSystem();
- cs = IdentifiedObjects.getProperties(share);
- axis = IdentifiedObjects.getProperties(share.getAxis(0));
+ cs = IdentifiedObjects.getProperties(share, EXCLUDE);
+ axis = IdentifiedObjects.getProperties(share.getAxis(0), EXCLUDE);
break;
}
case JAVA: {
@@ -1503,7 +1571,7 @@ public enum CommonCRS {
* Returns the same properties than the given object, except for the identifier which is set to the given code.
*/
private static Map<String,?> properties(final IdentifiedObject template, final short code) {
- final Map<String,Object> properties = new HashMap<String,Object>(IdentifiedObjects.getProperties(template));
+ final Map<String,Object> properties = new HashMap<String,Object>(IdentifiedObjects.getProperties(template, EXCLUDE));
properties.put(GeographicCRS.IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, String.valueOf(code)));
return properties;
}
@@ -1523,6 +1591,20 @@ public enum CommonCRS {
}
/**
+ * Returns the EPSG factory to use for creating coordinate systems, or {@code null} if none.
+ * If this method returns {@code null}, then the caller will silently fallback on hard-coded values.
+ */
+ static CSAuthorityFactory csFactory() {
+ if (!EPSGFactoryFallback.FORCE_HARDCODED) {
+ final AuthorityFactory factory = AuthorityFactories.EPSG();
+ if (!(factory instanceof EPSGFactoryFallback)) {
+ return (CSAuthorityFactory) factory;
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the EPSG factory to use for creating datum, ellipsoids and prime meridians, or {@code null} if none.
* If this method returns {@code null}, then the caller will silently fallback on hard-coded values.
*/
@@ -1540,10 +1622,15 @@ public enum CommonCRS {
* Invoked when a factory failed to create an object.
* After invoking this method, the caller will fallback on hard-coded values.
*/
- static void failure(final Object caller, final String method, final FactoryException e) {
- if (e instanceof UnavailableFactoryException) {
- AuthorityFactories.failure((UnavailableFactoryException) e);
+ static void failure(final Object caller, final String method, final FactoryException e, final int code) {
+ String message = Errors.format(Errors.Keys.CanNotInstantiate_1, "EPSG:" + code);
+ message = Exceptions.formatChainedMessages(null, message, e);
+ final LogRecord record = new LogRecord(Level.WARNING, message);
+ if (!(e instanceof UnavailableFactoryException) || !AuthorityFactories.failure((UnavailableFactoryException) e)) {
+ // Append the stack trace only if the exception is the the one we expect when the factory is not available.
+ record.setThrown(e);
}
- Logging.unexpectedException(Logging.getLogger(Loggers.CRS_FACTORY), caller.getClass(), method, e);
+ record.setLoggerName(Loggers.CRS_FACTORY);
+ Logging.log(caller.getClass(), method, record);
}
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -91,6 +91,10 @@ public final class IdentifiedObjects ext
* <td>{@link CoordinateOperation#getOperationVersion()}</td></tr>
* <tr><td>{@value org.opengis.referencing.operation.CoordinateOperation#COORDINATE_OPERATION_ACCURACY_KEY}</td>
* <td>{@link CoordinateOperation#getCoordinateOperationAccuracy()}</td></tr>
+ * <tr><td>{@value org.opengis.referencing.operation.OperationMethod#FORMULA_KEY}</td>
+ * <td>{@link org.opengis.referencing.operation.OperationMethod#getFormula()}</td></tr>
+ * <tr><td>{@value org.apache.sis.referencing.AbstractIdentifiedObject#DEPRECATED_KEY}</td>
+ * <td>{@link AbstractIdentifiedObject#isDeprecated()}</td></tr>
* </table>
*
* <div class="note"><b>Note:</b>
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -26,8 +26,10 @@ import org.opengis.referencing.Reference
import org.opengis.referencing.IdentifiedObject;
import org.opengis.referencing.ReferenceIdentifier;
import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.OperationMethod;
import org.opengis.metadata.quality.PositionalAccuracy;
import org.apache.sis.internal.util.AbstractMap;
+import org.apache.sis.util.Deprecable;
/**
@@ -40,7 +42,7 @@ import org.apache.sis.internal.util.Abst
*
* @author Martin Desruisseaux (IRD)
* @since 0.4
- * @version 0.4
+ * @version 0.7
* @module
*/
final class Properties extends AbstractMap<String,Object> implements Serializable {
@@ -55,14 +57,16 @@ final class Properties extends AbstractM
* of {@link #INDICES}.
*/
private static final String[] KEYS = {
- /*[0]*/ IdentifiedObject .NAME_KEY,
- /*[1]*/ IdentifiedObject .IDENTIFIERS_KEY,
- /*[2]*/ IdentifiedObject .ALIAS_KEY,
- /*[3]*/ IdentifiedObject .REMARKS_KEY,
- /*[4]*/ CoordinateOperation .SCOPE_KEY, // same in Datum and ReferenceSystem
- /*[5]*/ CoordinateOperation .DOMAIN_OF_VALIDITY_KEY, // same in Datum and ReferenceSystem
- /*[6]*/ CoordinateOperation .OPERATION_VERSION_KEY,
- /*[7]*/ CoordinateOperation .COORDINATE_OPERATION_ACCURACY_KEY
+ /*[0]*/ IdentifiedObject .NAME_KEY,
+ /*[1]*/ IdentifiedObject .IDENTIFIERS_KEY,
+ /*[2]*/ IdentifiedObject .ALIAS_KEY,
+ /*[3]*/ IdentifiedObject .REMARKS_KEY,
+ /*[4]*/ CoordinateOperation .SCOPE_KEY, // same in Datum and ReferenceSystem
+ /*[5]*/ CoordinateOperation .DOMAIN_OF_VALIDITY_KEY, // same in Datum and ReferenceSystem
+ /*[6]*/ CoordinateOperation .OPERATION_VERSION_KEY,
+ /*[7]*/ CoordinateOperation .COORDINATE_OPERATION_ACCURACY_KEY,
+ /*[8]*/ OperationMethod .FORMULA_KEY,
+ /*[9]*/ AbstractIdentifiedObject.DEPRECATED_KEY
/*
* The current implementation does not look for minimum and maximum values in ParameterDescriptor
@@ -182,6 +186,18 @@ final class Properties extends AbstractM
}
break;
}
+ case 8: { // FORMULA_KEY
+ if (object instanceof OperationMethod) {
+ return ((OperationMethod) object).getFormula();
+ }
+ break;
+ }
+ case 9: { // DEPRECATED_KEY
+ if (object instanceof Deprecable) {
+ return ((Deprecable) object).isDeprecated();
+ }
+ break;
+ }
default: throw new AssertionError(key);
}
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/StandardDefinitions.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -51,6 +51,7 @@ import org.apache.sis.referencing.datum.
import org.apache.sis.referencing.datum.DefaultVerticalDatum;
import org.apache.sis.referencing.cs.DefaultVerticalCS;
import org.apache.sis.referencing.cs.DefaultCartesianCS;
+import org.apache.sis.referencing.cs.DefaultSphericalCS;
import org.apache.sis.referencing.cs.DefaultEllipsoidalCS;
import org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis;
import org.apache.sis.referencing.crs.DefaultGeographicCRS;
@@ -311,12 +312,14 @@ final class StandardDefinitions {
@SuppressWarnings("fallthrough")
static CoordinateSystem createCoordinateSystem(final short code) {
final String name;
- final int dim; // Number of dimension.
- short axisCode; // Code of first axis + dim (or code after the last axis).
+ final int dim; // Number of dimension.
+ short axisCode; // Code of first axis + dim (or code after the last axis).
boolean isCartesian = false;
+ boolean isSpherical = false;
switch (code) {
case 6422: name = "Ellipsoidal 2D"; dim = 2; axisCode = 108; break;
case 6423: name = "Ellipsoidal 3D"; dim = 3; axisCode = 111; break;
+ case 6404: name = "Spherical"; dim = 3; axisCode = 63; isSpherical = true; break;
case 6500: name = "Earth centred"; dim = 3; axisCode = 118; isCartesian = true; break;
case 4400: name = "Cartesian 2D"; dim = 2; axisCode = 3; isCartesian = true; break;
default: throw new AssertionError(code);
@@ -336,6 +339,8 @@ final class StandardDefinitions {
} else {
return new DefaultCartesianCS(properties, xAxis, yAxis);
}
+ } else if (isSpherical) {
+ return new DefaultSphericalCS(properties, xAxis, yAxis, zAxis);
} else {
if (zAxis != null) {
return new DefaultEllipsoidalCS(properties, xAxis, yAxis, zAxis);
@@ -369,6 +374,29 @@ final class StandardDefinitions {
unit = SI.METRE;
dir = AxisDirection.NORTH;
break;
+ case 60: name = "Spherical latitude";
+ abrv = "φ′"; // See HardCodedAxes.SPHERICAL_LATITUDE in tests.
+ unit = NonSI.DEGREE_ANGLE;
+ dir = AxisDirection.NORTH;
+ min = Latitude.MIN_VALUE;
+ max = Latitude.MAX_VALUE;
+ rm = RangeMeaning.EXACT;
+ break;
+ case 61: name = "Spherical longitude";
+ abrv = "θ"; // See HardCodedAxes.SPHERICAL_LONGITUDE in tests.
+ unit = NonSI.DEGREE_ANGLE;
+ dir = AxisDirection.EAST;
+ min = Longitude.MIN_VALUE;
+ max = Longitude.MAX_VALUE;
+ rm = RangeMeaning.WRAPAROUND;
+ break;
+ case 62: name = "Geocentric radius";
+ abrv = "R"; // See HardCodedAxes.GEOCENTRIC_RADIUS in tests.
+ unit = SI.METRE;
+ dir = AxisDirection.UP;
+ rm = RangeMeaning.EXACT;
+ min = 0;
+ break;
case 108: // Used in Ellipsoidal 3D.
case 106: name = AxisNames.GEODETIC_LATITUDE;
abrv = "φ";
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -108,7 +108,7 @@ import org.apache.sis.measure.Units;
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.7
* @module
*
* @see AbstractCS#forConvention(AxesConvention)
@@ -153,7 +153,13 @@ public enum AxesConvention implements Ax
}
@Override
+ @Deprecated
public Unit<?> getUnitReplacement(Unit<?> unit) {
+ return getUnitReplacement(null, unit);
+ }
+
+ @Override
+ public Unit<?> getUnitReplacement(final CoordinateSystemAxis axis, Unit<?> unit) {
if (Units.isLinear(unit)) {
unit = SI.METRE;
} else if (Units.isAngular(unit)) {
@@ -164,18 +170,35 @@ public enum AxesConvention implements Ax
return unit;
}
- /*
- * Same policy than AxesConvention.CONVENTIONALLY_ORIENTATED.
- */
@Override
+ @Deprecated
public AxisDirection getDirectionReplacement(final AxisDirection direction) {
- return AxisDirections.isIntercardinal(direction) ? direction : AxisDirections.absolute(direction);
+ return getDirectionReplacement(null, direction);
+ }
+
+ @Override
+ public AxisDirection getDirectionReplacement(final CoordinateSystemAxis axis, final AxisDirection direction) {
+ /*
+ * For now we do not touch to inter-cardinal directions (e.g. "North-East")
+ * because it is not clear which normalization policy would match common usage.
+ */
+ if (!AxisDirections.isIntercardinal(direction)) {
+ /*
+ * Change the direction only if the axis allows negative values.
+ * If the axis accepts only positive values, then the direction
+ * is considered non-invertible.
+ */
+ if (axis == null || axis.getMinimumValue() < 0) {
+ return AxisDirections.absolute(direction);
+ }
+ }
+ return direction;
}
},
/**
* Axes are oriented toward conventional directions and ordered for a {@linkplain #RIGHT_HANDED right-handed}
- * coordinate system. Ranges of ordinate values and units of measurement are unchanged.
+ * coordinate system. Units of measurement are unchanged.
*
* <p>More specifically, directions opposites to the following ones are replaced by their "forward" counterpart
* (e.g. {@code SOUTH} → {@code NORTH}):</p>
@@ -227,17 +250,25 @@ public enum AxesConvention implements Ax
}
@Override
+ @Deprecated
public Unit<?> getUnitReplacement(final Unit<?> unit) {
return unit;
}
- /*
- * For now we do not touch to inter-cardinal directions (e.g. "North-East")
- * because it is not clear which normalization policy would match common usage.
- */
@Override
+ public Unit<?> getUnitReplacement(final CoordinateSystemAxis axis, final Unit<?> unit) {
+ return unit;
+ }
+
+ @Override
+ @Deprecated
public AxisDirection getDirectionReplacement(final AxisDirection direction) {
- return AxisDirections.isIntercardinal(direction) ? direction : AxisDirections.absolute(direction);
+ return getDirectionReplacement(null, direction);
+ }
+
+ @Override
+ public AxisDirection getDirectionReplacement(CoordinateSystemAxis axis, AxisDirection direction) {
+ return NORMALIZED.getDirectionReplacement(axis, direction);
}
},
@@ -275,14 +306,26 @@ public enum AxesConvention implements Ax
}
@Override
+ @Deprecated
public Unit<?> getUnitReplacement(final Unit<?> unit) {
return unit;
}
@Override
+ public Unit<?> getUnitReplacement(CoordinateSystemAxis axis, final Unit<?> unit) {
+ return unit;
+ }
+
+ @Override
+ @Deprecated
public AxisDirection getDirectionReplacement(final AxisDirection direction) {
return direction;
}
+
+ @Override
+ public AxisDirection getDirectionReplacement(CoordinateSystemAxis axis, final AxisDirection direction) {
+ return direction;
+ }
},
/**
@@ -315,13 +358,25 @@ public enum AxesConvention implements Ax
}
@Override
+ @Deprecated
public Unit<?> getUnitReplacement(final Unit<?> unit) {
return unit;
}
@Override
+ public Unit<?> getUnitReplacement(CoordinateSystemAxis axis, final Unit<?> unit) {
+ return unit;
+ }
+
+ @Override
+ @Deprecated
public AxisDirection getDirectionReplacement(final AxisDirection direction) {
return direction;
}
+
+ @Override
+ public AxisDirection getDirectionReplacement(CoordinateSystemAxis axis, final AxisDirection direction) {
+ return direction;
+ }
}
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxisFilter.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -42,7 +42,7 @@ import javax.measure.unit.Unit;
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.6
- * @version 0.6
+ * @version 0.7
* @module
*
* @see CoordinateSystems#replaceAxes(CoordinateSystem, AxisFilter)
@@ -65,7 +65,7 @@ public interface AxisFilter {
*
* {@preformat java
* @Override
- * public getDirectionReplacement(AxisDirection direction) {
+ * public getDirectionReplacement(CoordinateSystemAxis axis, AxisDirection direction) {
* if (direction == AxisDirection.DOWN) {
* direction = AxisDirection.UP;
* }
@@ -74,9 +74,21 @@ public interface AxisFilter {
* }
* </div>
*
+ * @param axis The axis for which to change axis direction, if desired.
+ * @param direction The original axis direction.
+ * @return The new axis direction, or {@code direction} if there is no change.
+ *
+ * @since 0.7
+ */
+ AxisDirection getDirectionReplacement(CoordinateSystemAxis axis, AxisDirection direction);
+
+ /**
+ * @deprecated Use {@link #getDirectionReplacement(CoordinateSystemAxis, AxisDirection)} instead.
+ *
* @param direction The original axis direction.
* @return The new axis direction, or {@code direction} if there is no change.
*/
+ @Deprecated
AxisDirection getDirectionReplacement(AxisDirection direction);
/**
@@ -88,7 +100,7 @@ public interface AxisFilter {
*
* {@preformat java
* @Override
- * public Unit<?> getUnitReplacement(Unit<?> unit) {
+ * public Unit<?> getUnitReplacement(CoordinateSystemAxis axis, Unit<?> unit) {
* if (Units.isAngular(unit)) {
* unit = NonSI.DEGREE_ANGLE;
* }
@@ -97,8 +109,20 @@ public interface AxisFilter {
* }
* </div>
*
+ * @param axis The axis for which to change unit, if desired.
+ * @param unit The original axis unit.
+ * @return The new axis unit, or {@code unit} if there is no change.
+ *
+ * @since 0.7
+ */
+ Unit<?> getUnitReplacement(CoordinateSystemAxis axis, Unit<?> unit);
+
+ /**
+ * @deprecated Use {@link #getUnitReplacement(CoordinateSystemAxis, Unit)} instead.
+ *
* @param unit The original axis unit.
* @return The new axis unit, or {@code unit} if there is no change.
*/
+ @Deprecated
Unit<?> getUnitReplacement(Unit<?> unit);
}
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -349,7 +349,7 @@ public final class CoordinateSystems ext
* CoordinateSystem cs = ...;
* cs = CoordinateSystems.replaceAxes(cs, new AxisFilter() {
* @Override
- * public Unit<?> getUnitReplacement(Unit<?> unit) {
+ * public Unit<?> getUnitReplacement(CoordinateSystemAxis axis, Unit<?> unit) {
* if (Units.isAngular(unit)) {
* unit = NonSI.DEGREE_ANGLE;
* }
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -323,7 +323,7 @@ public class DefaultCoordinateSystemAxis
} else if (dir.equals(AxisDirection.EAST)) {
min = fromDegrees.convert(Longitude.MIN_VALUE);
max = fromDegrees.convert(Longitude.MAX_VALUE);
- rm = RangeMeaning.WRAPAROUND; // 180°E wraps to 180°W
+ rm = RangeMeaning.WRAPAROUND; // 180°E wraps to 180°W
}
if (min > max) {
final double t = min;
@@ -697,10 +697,10 @@ public class DefaultCoordinateSystemAxis
*/
private static CoordinateSystem getEnclosingCS(final Formatter formatter) {
final FormattableObject e = formatter.getEnclosingElement(1);
- if (e instanceof CoordinateReferenceSystem) { // This is what we expect in standard WKT.
+ if (e instanceof CoordinateReferenceSystem) { // This is what we expect in standard WKT.
return ((CoordinateReferenceSystem) e).getCoordinateSystem();
}
- if (e instanceof CoordinateSystem) { // Not standard WKT, but conceptually the right thing.
+ if (e instanceof CoordinateSystem) { // Not standard WKT, but conceptually the right thing.
return (CoordinateSystem) e;
}
return null;
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCylindricalCS.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -165,7 +165,7 @@ public class DefaultCylindricalCS extend
if (!AxisDirections.isSpatialOrUserDefined(direction, false)) {
return INVALID_DIRECTION;
}
- if (!Units.isLinear(unit)) {
+ if (!Units.isAngular(unit) && !Units.isLinear(unit)) {
return INVALID_UNIT;
}
return VALID;
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultLinearCS.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -157,7 +157,7 @@ public class DefaultLinearCS extends Abs
if (!AxisDirections.isSpatialOrUserDefined(direction, false)) {
return INVALID_DIRECTION;
}
- if (!Units.isLinear(unit)) {
+ if (!Units.isLinear(unit) && !Unit.ONE.equals(unit)) {
return INVALID_UNIT;
}
return VALID;
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -26,11 +26,16 @@ import org.opengis.referencing.cs.RangeM
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.SphericalCS;
+import org.opengis.referencing.cs.CylindricalCS;
+import org.opengis.referencing.cs.PolarCS;
import org.apache.sis.internal.metadata.AxisDirections;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.ArraysExt;
+import org.apache.sis.measure.Units;
import static java.util.Collections.singletonMap;
import static org.opengis.referencing.IdentifiedObject.NAME_KEY;
@@ -50,12 +55,39 @@ import static org.apache.sis.internal.re
* The main usage for this class is to reorder the axes in some fixed order like
* (<var>x</var>, <var>y</var>, <var>z</var>) or (<var>longitude</var>, <var>latitude</var>).
*
+ * <p>The normalization performed by this class shall be compatible with axis order expected by various
+ * {@code MathTransform} implementations in the {@link org.apache.sis.referencing.operation.transform} package.
+ * In particular:</p>
+ *
+ * <ul>
+ * <li>{@code EllipsoidToCentricTransform} input:<ol>
+ * <li>Geodetic longitude (λ) in degrees</li>
+ * <li>Geodetic latitude (φ) in degrees</li>
+ * <li>Height in units of semi-axes</li>
+ * </ol></li>
+ * <li>{@code SphericalToCartesian} input:<ol>
+ * <li>Spherical longitude in degrees</li>
+ * <li>Spherical latitude in degrees</li>
+ * <li>Spherical radius (r) in any units</li>
+ * </ol></li>
+ * <li>{@code CartesianToSpherical} input:<ol>
+ * <li>X in units of the above radius</li>
+ * <li>Y in units of the above radius</li>
+ * <li>Z in units of the above radius</li>
+ * </ol></li>
+ * <li>{@code CylindricalToCartesian} input:<ol>
+ * <li>Radius (r) in any units</li>
+ * <li>Angle (θ) in degrees</li>
+ * <li>Height (z) in any units</li>
+ * </ol></li>
+ * </ul>
+ *
* <p>This class implements {@link Comparable} for opportunist reasons.
* This should be considered as an implementation details.</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4
- * @version 0.5
+ * @version 0.7
* @module
*/
final class Normalizer implements Comparable<Normalizer> {
@@ -67,6 +99,30 @@ final class Normalizer implements Compar
};
/**
+ * Number of bits by which to shift the {@link AxisDirection#ordinal()} value in order to make room for
+ * inserting intermediate values between them. A shift of 2 make room for {@literal 1 << 2} intermediate
+ * values. Those intermediate values are declared in the {@link #ORDER} map.
+ *
+ * @see #order(AxisDirection)
+ */
+ private static final int SHIFT = 2;
+
+ /**
+ * Custom code list values to handle as if the where defined between two GeoAPI values.
+ *
+ * @see #order(AxisDirection)
+ */
+ private static final Map<AxisDirection,Integer> ORDER = new HashMap<AxisDirection,Integer>();
+ static {
+ final Map<AxisDirection,Integer> m = ORDER;
+ // Get ordinal of last compass direction defined by GeoAPI. We will continue on the horizontal plane.
+ final int horizontal = (AxisDirection.NORTH.ordinal() + (AxisDirections.COMPASS_COUNT - 1)) << SHIFT;
+ m.put(AxisDirections.AWAY_FROM, horizontal + 1);
+ m.put(AxisDirections.COUNTER_CLOCKWISE, horizontal + 2);
+ m.put(AxisDirections.CLOCKWISE, horizontal + 3);
+ }
+
+ /**
* The axis to be compared by {@link #compareTo(Normalizer)}.
*/
private final CoordinateSystemAxis axis;
@@ -78,53 +134,78 @@ final class Normalizer implements Compar
private final DirectionAlongMeridian meridian;
/**
+ * Angular units order relative to other units.
+ * A value of -1 means that angular units should be first.
+ * A value of +1 means than angular units should be last.
+ * A value of 0 means to not use this criterion.
+ */
+ private final int unitOrder;
+
+ /**
* For internal usage by {@link #sort(CoordinateSystemAxis[])} only.
*/
- private Normalizer(final CoordinateSystemAxis axis) {
+ private Normalizer(final CoordinateSystemAxis axis, final int angularUnitOrder) {
this.axis = axis;
+ unitOrder = Units.isAngular(axis.getUnit()) ? angularUnitOrder : 0;
final AxisDirection dir = axis.getDirection();
meridian = AxisDirections.isUserDefined(dir) ? DirectionAlongMeridian.parse(dir) : null;
}
/**
+ * Returns the order of the given axis direction.
+ */
+ private static int order(final AxisDirection dir) {
+ final Integer p = ORDER.get(dir);
+ return (p != null) ? p : (dir.ordinal() << SHIFT);
+ }
+
+ /**
* Compares two axis for an order that try to favor right-handed coordinate systems.
* Compass directions like North and East are first. Vertical directions like Up or Down are next.
*/
@Override
public int compareTo(final Normalizer that) {
- final AxisDirection d1 = this.axis.getDirection();
- final AxisDirection d2 = that.axis.getDirection();
- final int compass = AxisDirections.angleForCompass(d2, d1);
- if (compass != Integer.MIN_VALUE) {
- return compass;
- }
- if (meridian != null) {
- if (that.meridian != null) {
- return meridian.compareTo(that.meridian);
+ int d = unitOrder - that.unitOrder;
+ if (d == 0) {
+ final AxisDirection d1 = this.axis.getDirection();
+ final AxisDirection d2 = that.axis.getDirection();
+ d = AxisDirections.angleForCompass(d2, d1);
+ if (d == Integer.MIN_VALUE) {
+ if (meridian != null) {
+ if (that.meridian != null) {
+ d = meridian.compareTo(that.meridian);
+ } else {
+ d = -1;
+ }
+ } else if (that.meridian != null) {
+ d = +1;
+ } else {
+ d = order(d1) - order(d2);
+ }
}
- return -1;
- } else if (that.meridian != null) {
- return +1;
}
- return d1.ordinal() - d2.ordinal();
+ return d;
}
/**
* Sorts the specified axis in an attempt to create a right-handed system.
* The sorting is performed in place. This method returns {@code true} if
* at least one axis moved as result of this method call.
+ *
+ * @param axes The axes to sort.
+ * @param angularUnitOrder -1 for sorting angular units first, +1 for sorting them last, or 0 if neutral.
*/
- static boolean sort(final CoordinateSystemAxis[] axis) {
- final Normalizer[] wrappers = new Normalizer[axis.length];
- for (int i=0; i<axis.length; i++) {
- wrappers[i] = new Normalizer(axis[i]);
+ static boolean sort(final CoordinateSystemAxis[] axes, final int angularUnitOrder) {
+ final Normalizer[] wrappers = new Normalizer[axes.length];
+ for (int i=0; i<axes.length; i++) {
+ wrappers[i] = new Normalizer(axes[i], angularUnitOrder);
}
Arrays.sort(wrappers);
boolean changed = false;
- for (int i=0; i<axis.length; i++) {
+ for (int i=0; i<axes.length; i++) {
final CoordinateSystemAxis a = wrappers[i].axis;
- changed |= (axis[i] != a);
- axis[i] = a;
+ changed |= (axes[i] != a);
+ axes[i] = a;
}
return changed;
}
@@ -140,8 +221,8 @@ final class Normalizer implements Compar
static CoordinateSystemAxis normalize(final CoordinateSystemAxis axis, final AxisFilter changes) {
final Unit<?> unit = axis.getUnit();
final AxisDirection direction = axis.getDirection();
- final Unit<?> newUnit = changes.getUnitReplacement(unit);
- final AxisDirection newDir = changes.getDirectionReplacement(direction);
+ final Unit<?> newUnit = changes.getUnitReplacement(axis, unit);
+ final AxisDirection newDir = changes.getDirectionReplacement(axis, direction);
/*
* Reuse some properties (name, remarks, etc.) from the existing axis. If the direction changed,
* then the axis name may need change too (e.g. "Westing" → "Easting"). The new axis name may be
@@ -153,22 +234,8 @@ final class Normalizer implements Compar
return axis;
}
final String abbreviation = axis.getAbbreviation();
- String newAbbr = abbreviation;
- if (!sameDirection) {
- if (AxisDirections.isCompass(direction)) {
- if (CharSequences.isAcronymForWords(abbreviation, direction.name())) {
- if (newDir.equals(AxisDirection.EAST)) {
- newAbbr = "E";
- } else if (newDir.equals(AxisDirection.NORTH)) {
- newAbbr = "N";
- }
- }
- } else if (newDir.equals(AxisDirection.UP)) {
- newAbbr = "z";
- } else if (newDir.equals(AxisDirection.FUTURE)) {
- newAbbr = "t";
- }
- }
+ final String newAbbr = sameDirection ? abbreviation :
+ AxisDirections.suggestAbbreviation(axis.getName().getCode(), newDir, newUnit);
final Map<String,Object> properties = new HashMap<String,Object>();
if (newAbbr.equals(abbreviation)) {
properties.putAll(IdentifiedObjects.getProperties(axis, EXCLUDES));
@@ -176,18 +243,30 @@ final class Normalizer implements Compar
properties.put(NAME_KEY, UNNAMED);
}
/*
- * Converts the axis range and build the new axis.
+ * Convert the axis range and build the new axis. The axis range will be converted only if
+ * the axis direction is the same or the opposite, otherwise we do not know what should be
+ * the new values. In the particular case of opposite axis direction, we need to reverse the
+ * sign of minimum and maximum values.
*/
- final UnitConverter c;
- try {
- c = unit.getConverterToAny(newUnit);
- } catch (ConversionException e) {
- // Use IllegalStateException because the public API is an AbstractCS member method.
- throw new IllegalStateException(Errors.format(Errors.Keys.IllegalUnitFor_2, "axis", unit), e);
- }
- properties.put(DefaultCoordinateSystemAxis.MINIMUM_VALUE_KEY, c.convert(axis.getMinimumValue()));
- properties.put(DefaultCoordinateSystemAxis.MAXIMUM_VALUE_KEY, c.convert(axis.getMaximumValue()));
- properties.put(DefaultCoordinateSystemAxis.RANGE_MEANING_KEY, axis.getRangeMeaning());
+ if (sameDirection || newDir.equals(AxisDirections.opposite(direction))) {
+ final UnitConverter c;
+ try {
+ c = unit.getConverterToAny(newUnit);
+ } catch (ConversionException e) {
+ // Use IllegalStateException because the public API is an AbstractCS member method.
+ throw new IllegalStateException(Errors.format(Errors.Keys.IllegalUnitFor_2, "axis", unit), e);
+ }
+ double minimum = c.convert(axis.getMinimumValue());
+ double maximum = c.convert(axis.getMaximumValue());
+ if (!sameDirection) {
+ final double tmp = minimum;
+ minimum = -maximum;
+ maximum = -tmp;
+ }
+ properties.put(DefaultCoordinateSystemAxis.MINIMUM_VALUE_KEY, minimum);
+ properties.put(DefaultCoordinateSystemAxis.MAXIMUM_VALUE_KEY, maximum);
+ properties.put(DefaultCoordinateSystemAxis.RANGE_MEANING_KEY, axis.getRangeMeaning());
+ }
return new DefaultCoordinateSystemAxis(properties, newAbbr, newDir, newUnit);
}
@@ -221,7 +300,26 @@ final class Normalizer implements Compar
* If nothing changed, return the given Coordinate System as-is.
*/
if (reorder) {
- changed |= sort(axes);
+ int angularUnitOrder = 0;
+ if (cs instanceof EllipsoidalCS || cs instanceof SphericalCS) angularUnitOrder = -1; // (λ,φ,h) order
+ else if (cs instanceof CylindricalCS || cs instanceof PolarCS) angularUnitOrder = +1; // (r,θ) order
+ changed |= sort(axes, angularUnitOrder);
+ if (angularUnitOrder == 1) { // Cylindrical or polar
+ /*
+ * Change (r,z,θ) to (r,θ,z) order in CylindricalCS. The check on unit of
+ * measurements should be always true, but we verify as a paranoiac check.
+ */
+ if (axes.length == 3 && isLengthAndAngle(axes, 1)) {
+ ArraysExt.swap(axes, 1, 2);
+ }
+ /*
+ * If we were not allowed to normalize the axis direction, we may have a
+ * left-handed coordinate system here. If so, make it right-handed.
+ */
+ if (AxisDirections.CLOCKWISE.equals(axes[1].getDirection()) && isLengthAndAngle(axes, 0)) {
+ ArraysExt.swap(axes, 0, 1);
+ }
+ }
}
if (!changed && n == dimension) {
return null;
@@ -236,6 +334,14 @@ final class Normalizer implements Compar
}
/**
+ * Returns {@code true} if the units of measurement at the given position is a linear unit,
+ * followed by an angular unit on the next axis.
+ */
+ private static boolean isLengthAndAngle(final CoordinateSystemAxis[] axes, final int p) {
+ return Units.isLinear(axes[p].getUnit()) && Units.isAngular(axes[p+1].getUnit());
+ }
+
+ /**
* Returns a coordinate system with the same axes than the given CS, except that the wrapround axes
* are shifted to a range of positive values. This method can be used in order to shift between the
* [-180 … +180]° and [0 … 360]° ranges of longitude values.
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -21,11 +21,13 @@ import java.util.Arrays;
import java.io.Serializable;
import org.opengis.metadata.extent.Extent;
import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.datum.PrimeMeridian;
import org.opengis.referencing.operation.Matrix;
import org.apache.sis.referencing.operation.matrix.Matrix4;
import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.io.wkt.FormattableObject;
import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.util.Utilities;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.internal.util.DoubleDouble;
import org.apache.sis.internal.metadata.WKTKeywords;
@@ -123,7 +125,7 @@ import org.apache.sis.internal.jdk7.Obje
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.7
* @module
*
* @see DefaultGeodeticDatum#getBursaWolfParameters()
@@ -226,15 +228,37 @@ public class BursaWolfParameters extends
/**
* Verifies parameters validity after initialization of {@link DefaultGeodeticDatum}.
- */
- void verify() {
+ * This method requires that the prime meridian of the target datum is either the same
+ * than the enclosing {@code GeodeticDatum}, or Greenwich. We put this restriction for
+ * avoiding ambiguity about whether the longitude rotation should be applied before or
+ * after the datum shift.
+ *
+ * <p>If the target prime meridian is Greenwich, then SIS will assume that the datum shift
+ * needs to be applied in a coordinate system having Greenwich as the prime meridian.</p>
+ *
+ * <p><b>Maintenance note:</b>
+ * if the above policy regarding prime meridians is modified, then some {@code createOperationStep(…)} method
+ * implementations in {@link org.apache.sis.referencing.operation.CoordinateOperationInference} may need to be
+ * revisited. See especially the methods creating a transformation between a pair of {@code GeocentricCRS} or
+ * between a pair of {@code GeographicCRS} (tip: search for {@code DefaultGeodeticDatum}).</p>
+ *
+ * @param pm The prime meridian of the enclosing {@code GeodeticDatum}.
+ */
+ void verify(final PrimeMeridian pm) throws IllegalArgumentException {
+ if (targetDatum != null) {
+ final PrimeMeridian actual = targetDatum.getPrimeMeridian();
+ if (actual.getGreenwichLongitude() != 0 && !Utilities.equalsIgnoreMetadata(pm, actual)) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedPrimeMeridian_2,
+ IdentifiedObjects.getName(pm, null), IdentifiedObjects.getName(actual, null)));
+ }
+ }
ensureFinite("tX", tX);
ensureFinite("tY", tY);
ensureFinite("tZ", tZ);
ensureFinite("rX", rX);
ensureFinite("rY", rY);
ensureFinite("rZ", rZ);
- ensureBetween("dS", -PPM, PPM, dS); // For preventing zero or negative value on the matrix diagonal.
+ ensureBetween("dS", -PPM, PPM, dS); // For preventing zero or negative value on the matrix diagonal.
}
/**
@@ -276,7 +300,7 @@ public class BursaWolfParameters extends
public double[] getValues() {
final double[] elements = new double[(dS != 0) ? 7 : (rZ != 0 || rY != 0 || rX != 0) ? 6 : 3];
switch (elements.length) {
- default: elements[6] = dS; // Fallthrough everywhere.
+ default: elements[6] = dS; // Fallthrough everywhere.
case 6: elements[5] = rZ;
elements[4] = rY;
elements[3] = rX;
@@ -307,7 +331,7 @@ public class BursaWolfParameters extends
@SuppressWarnings("fallthrough")
public void setValues(final double... elements) {
switch (elements.length) {
- default: dS = elements[6]; // Fallthrough everywhere.
+ default: dS = elements[6]; // Fallthrough everywhere.
case 6: rZ = elements[5];
case 5: rY = elements[4];
case 4: rX = elements[3];
@@ -510,10 +534,14 @@ public class BursaWolfParameters extends
}
/*
* Translation terms, taken "as-is".
+ * If the matrix contains only translation terms (which is often the case), we are done.
*/
tX = matrix.getElement(0,3);
tY = matrix.getElement(1,3);
tZ = matrix.getElement(2,3);
+ if (Matrices.isTranslation(matrix)) { // Optimization for a common case.
+ return;
+ }
/*
* Scale factor: take the average of elements on the diagonal. All those
* elements should have the same value, but we tolerate slight deviation
@@ -543,17 +571,17 @@ public class BursaWolfParameters extends
}
for (int i = j+1; i < SIZE-1; i++) {
S.setFrom(RS);
- S.inverseDivide(getNumber(matrix, j,i)); // Negative rotation term.
+ S.inverseDivide(getNumber(matrix, j,i)); // Negative rotation term.
double value = S.value;
double error = S.error;
S.setFrom(RS);
- S.inverseDivide(getNumber(matrix, i,j)); // Positive rotation term.
- if (!(abs(value + S.value) <= tolerance)) { // We expect r1 ≈ -r2
+ S.inverseDivide(getNumber(matrix, i,j)); // Positive rotation term.
+ if (!(abs(value + S.value) <= tolerance)) { // We expect r1 ≈ -r2
throw new IllegalArgumentException(Errors.format(Errors.Keys.NotASkewSymmetricMatrix));
}
S.subtract(value, error);
S.multiply(0.5, 0);
- value = S.value; // Average of the two rotation terms.
+ value = S.value; // Average of the two rotation terms.
switch (j*SIZE + i) {
case 1: rZ = value; break;
case 2: rY = -value; break;
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java?rev=1737107&r1=1737106&r2=1737107&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] Wed Mar 30 12:35:10 2016
@@ -243,6 +243,13 @@ public class DefaultGeodeticDatum extend
* </tr>
* </table>
*
+ * If Bursa-Wolf parameters are specified, then the prime meridian of their
+ * {@linkplain BursaWolfParameters#getTargetDatum() target datum} shall be either the same than the
+ * {@code primeMeridian} given to this constructor, or Greenwich. This restriction is for avoiding
+ * ambiguity about whether the longitude rotation shall be applied before or after the datum shift.
+ * If the target prime meridian is Greenwich, then the datum shift will be applied in a coordinate
+ * system having Greenwich as the prime meridian.
+ *
* @param properties The properties to be given to the identified object.
* @param ellipsoid The ellipsoid.
* @param primeMeridian The prime meridian.
@@ -265,7 +272,7 @@ public class DefaultGeodeticDatum extend
BursaWolfParameters param = bursaWolf[i];
ensureNonNullElement("bursaWolf", i, param);
param = param.clone();
- param.verify();
+ param.verify(primeMeridian);
bursaWolf[i] = param;
}
}
@@ -368,12 +375,21 @@ public class DefaultGeodeticDatum extend
* 1033 – <cite>Position Vector transformation (geocentric domain)</cite>, or
* 1053 – <cite>Time-dependent Position Vector transformation</cite>.
*
- * <p>If this datum and the given {@code targetDatum} do not use the same
- * {@linkplain #getPrimeMeridian() prime meridian}, then it is caller's responsibility
- * to apply longitude rotation before to use the matrix returned by this method.</p>
- *
- * <div class="section">Search order</div>
- * This method performs the search in the following order:
+ * <p>If this datum and the given {@code targetDatum} do not use the same {@linkplain #getPrimeMeridian() prime meridian},
+ * then it is caller's responsibility to to apply longitude rotation before to use the matrix returned by this method.
+ * The target prime meridian should be Greenwich (see {@linkplain #DefaultGeodeticDatum(Map, Ellipsoid, PrimeMeridian)
+ * constructor javadoc}), in which case the datum shift should be applied in a geocentric coordinate system having
+ * Greenwich as the prime meridian.</p>
+ *
+ * <div class="note"><b>Note:</b>
+ * in EPSG dataset version 8.9, all datum shifts that can be represented by this method use Greenwich as the
+ * prime meridian, both in source and target datum.</div>
+ *
+ * <div class="section">Search criterion</div>
+ * If the given {@code areaOfInterest} is non-null and contains at least one geographic bounding box, then this
+ * method ignores any Bursa-Wolf parameters having a {@linkplain BursaWolfParameters#getDomainOfValidity() domain
+ * of validity} that does not intersect the given geographic extent.
+ * This method performs the search among the remaining parameters in the following order:
* <ol>
* <li>If this {@code GeodeticDatum} contains {@code BursaWolfParameters} having the given
* {@linkplain BursaWolfParameters#getTargetDatum() target datum} (ignoring metadata),
@@ -449,7 +465,7 @@ public class DefaultGeodeticDatum extend
* not a subclass of BursaWolfParameters. This optimisation covers the vast majority of cases.
*/
return bursaWolf.getPositionVectorTransformation(bursaWolf.getClass() != BursaWolfParameters.class ?
- Extents.getDate(areaOfInterest, 0.5) : null); // 0.5 is for choosing midway instant.
+ Extents.getDate(areaOfInterest, 0.5) : null); // 0.5 is for choosing midway instant.
}
/**
@@ -530,7 +546,7 @@ public class DefaultGeodeticDatum extend
@Override
public boolean equals(final Object object, final ComparisonMode mode) {
if (object == this) {
- return true; // Slight optimization.
+ return true; // Slight optimization.
}
if (!super.equals(object, mode)) {
return false;
@@ -547,14 +563,10 @@ public class DefaultGeodeticDatum extend
return deepEquals(getEllipsoid(), that.getEllipsoid(), mode) &&
deepEquals(getPrimeMeridian(), that.getPrimeMeridian(), mode);
/*
- * HACK: We do not consider Bursa-Wolf parameters as a non-metadata field.
- * This is needed in order to get equalsIgnoreMetadata(...) to returns
- * 'true' when comparing the WGS84 constant in this class with a WKT
- * DATUM element with a TOWGS84[0,0,0,0,0,0,0] element. Furthermore,
- * the Bursa-Wolf parameters are not part of ISO 19111 specification.
- * We don't want two CRS to be considered as different because one has
- * more of those transformation informations (which is nice, but doesn't
- * change the CRS itself).
+ * Bursa-Wolf parameters are considered ignorable metadata. This is needed in order to get
+ * equalsIgnoreMetadata(…) to return true when comparing WGS84 datums with and without the
+ * WKT 1 "TOWGS84[0,0,0,0,0,0,0]" element. Furthermore those Bursa-Wolf parameters are not
+ * part of ISO 19111 specification.
*/
}
}