Author: desruisseaux
Date: Mon Mar 21 21:59:03 2016
New Revision: 1736104
URL: http://svn.apache.org/viewvc?rev=1736104&view=rev
Log:
Modify DefaultMathTransformFactory.Context API for making clearer that the
factory does not deal with datum.
In particular, change of prime meridian is caller's responsibility. Added a
Context.getMatrix(MatrixRole)
method for making easier to handle prime meridian outside
DefaultMathTransformFactory.
Those changes are needed for continuing CoordinateOperationInference
implementation.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1736104&r1=1736103&r2=1736104&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
[UTF-8] Mon Mar 21 21:59:03 2016
@@ -37,6 +37,7 @@ import org.apache.sis.referencing.Identi
import org.apache.sis.referencing.datum.DefaultPrimeMeridian;
import org.apache.sis.referencing.crs.DefaultGeographicCRS;
import org.apache.sis.referencing.cs.AxesConvention;
+import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory.Context;
import static java.util.Collections.singletonMap;
@@ -321,4 +322,36 @@ public final class ReferencingUtilities
}
return null;
}
+
+ /**
+ * Sets the source and target ellipsoids and coordinate systems to values
inferred from the given CRS.
+ * The ellipsoids will be non-null only if the given CRS is geographic
(not geocentric).
+ *
+ * @param sourceCRS The CRS from which to get the source coordinate system
and ellipsoid.
+ * @param targetCRS The CRS from which to get the target coordinate system
and ellipsoid.
+ * @param context A pre-allocated context, or {@code null} for creating
a new one.
+ * @return The given context if it was non-null, or a new context
otherwise.
+ *
+ * @since 0.7
+ */
+ public static Context createTransformContext(final
CoordinateReferenceSystem sourceCRS,
+ final CoordinateReferenceSystem targetCRS, Context context)
+ {
+ if (context == null) {
+ context = new Context();
+ }
+ final CoordinateSystem sourceCS = (sourceCRS != null) ?
sourceCRS.getCoordinateSystem() : null;
+ final CoordinateSystem targetCS = (targetCRS != null) ?
targetCRS.getCoordinateSystem() : null;
+ if (sourceCRS instanceof GeodeticCRS && sourceCS instanceof
EllipsoidalCS) {
+ context.setSource((EllipsoidalCS) sourceCS, ((GeodeticCRS)
sourceCRS).getDatum().getEllipsoid());
+ } else {
+ context.setSource(sourceCS);
+ }
+ if (targetCRS instanceof GeodeticCRS && targetCS instanceof
EllipsoidalCS) {
+ context.setTarget((EllipsoidalCS) targetCS, ((GeodeticCRS)
targetCRS).getDatum().getEllipsoid());
+ } else {
+ context.setTarget(targetCS);
+ }
+ return context;
+ }
}
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java?rev=1736104&r1=1736103&r2=1736104&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
[UTF-8] Mon Mar 21 21:59:03 2016
@@ -70,6 +70,7 @@ import org.apache.sis.internal.metadata.
import org.apache.sis.internal.metadata.sql.SQLUtilities;
import org.apache.sis.internal.referencing.DeprecatedCode;
import org.apache.sis.internal.referencing.EPSGParameterDomain;
+import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.referencing.Formulas;
import org.apache.sis.internal.system.Loggers;
import org.apache.sis.internal.system.Semaphores;
@@ -2845,10 +2846,8 @@ next: while (r.next()) {
final MathTransform mt;
final MathTransformFactory mtFactory = owner.mtFactory;
if (mtFactory instanceof DefaultMathTransformFactory) {
- DefaultMathTransformFactory.Context context = new
DefaultMathTransformFactory.Context();
- context.setSource(sourceCRS);
- context.setTarget(targetCRS);
- mt = ((DefaultMathTransformFactory)
mtFactory).createParameterizedTransform(parameters, context);
+ mt = ((DefaultMathTransformFactory)
mtFactory).createParameterizedTransform(parameters,
+
ReferencingUtilities.createTransformContext(sourceCRS, targetCRS, null));
} else {
// Fallback for non-SIS implementations. Work for
map projections but not for Molodensky.
mt = mtFactory.createBaseToDerived(sourceCRS,
parameters, targetCRS.getCoordinateSystem());
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java?rev=1736104&r1=1736103&r2=1736104&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
[UTF-8] Mon Mar 21 21:59:03 2016
@@ -254,12 +254,12 @@ public class DefaultConversion extends A
* CoordinateReferenceSystem because the targetCRS is
typically under construction when this
* method in invoked, and attempts to use it can cause
NullPointerException.
*/
- final DefaultMathTransformFactory.Context context = new
DefaultMathTransformFactory.Context();
- context.setSource(source);
+ final DefaultMathTransformFactory.Context context;
if (target instanceof GeneralDerivedCRS) {
+ context =
ReferencingUtilities.createTransformContext(source, null, null);
context.setTarget(target.getCoordinateSystem()); //
Using 'target' would be unsafe here.
} else {
- context.setTarget(target);
+ context =
ReferencingUtilities.createTransformContext(source, target, null);
}
transform = ((DefaultMathTransformFactory)
factory).createParameterizedTransform(parameters, context);
parameters =
Parameters.unmodifiable(context.getCompletedParameters());
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1736104&r1=1736103&r2=1736104&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
[UTF-8] Mon Mar 21 21:59:03 2016
@@ -68,7 +68,7 @@ import java.util.Objects;
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4
- * @version 0.6
+ * @version 0.7
* @module
*
* @see org.apache.sis.parameter.TensorParameters
@@ -776,7 +776,6 @@ public final class Matrices extends Stat
* @return {@code true} if the matrix represents an affine transform.
*
* @see MatrixSIS#isAffine()
- * @see AffineTransforms2D#castOrCopy(Matrix)
*/
public static boolean isAffine(final Matrix matrix) {
if (matrix instanceof MatrixSIS) {
@@ -787,6 +786,32 @@ public final class Matrices extends Stat
}
/**
+ * Returns {@code true} if the given matrix represents a translation.
+ * This method returns {@code true} if the given matrix {@linkplain
#isAffine(Matrix) is affine}
+ * and differs from the identity matrix only in the last column.
+ *
+ * @param matrix The matrix to test.
+ * @return {@code true} if the matrix represents a translation.
+ *
+ * @since 0.7
+ */
+ public static boolean isTranslation(final Matrix matrix) {
+ if (!isAffine(matrix)) {
+ return false;
+ }
+ final int numRow = matrix.getNumRow() - 1; // Excluding
translation column.
+ final int numCol = matrix.getNumCol() - 1; // Excluding last row
in affine transform.
+ for (int j=0; j<numRow; j++) {
+ for (int i=0; i<numCol; i++) {
+ if (matrix.getElement(j,i) != ((i == j) ? 1 : 0)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
* Returns {@code true} if the given matrix is close to an identity
matrix, given a tolerance threshold.
* This method is equivalent to computing the difference between the given
matrix and an identity matrix
* of identical size, and returning {@code true} if and only if all
differences are smaller than or equal
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1736104&r1=1736103&r2=1736104&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
[UTF-8] Mon Mar 21 21:59:03 2016
@@ -71,6 +71,7 @@ import org.apache.sis.referencing.cs.Coo
import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
import org.apache.sis.referencing.operation.DefaultOperationMethod;
import org.apache.sis.referencing.operation.matrix.Matrices;
+import
org.apache.sis.referencing.operation.matrix.NoninvertibleMatrixException;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.Classes;
@@ -450,13 +451,18 @@ public class DefaultMathTransformFactory
* {@link DefaultMathTransformFactory} uses this information for:
*
* <ul>
- * <li>Complete some parameters if they were not provided. In
particular, the {@linkplain #getSourceEllipsoid()
+ * <li>Completing some parameters if they were not provided. In
particular, the {@linkplain #getSourceEllipsoid()
* source ellipsoid} can be used for providing values for the {@code
"semi_major"} and {@code "semi_minor"}
* parameters in map projections.</li>
- * <li>{@linkplain CoordinateSystems#swapAndScaleAxes Swap and scale
axes} if the source or the target
+ * <li>{@linkplain CoordinateSystems#swapAndScaleAxes Swapping and
scaling axes} if the source or the target
* coordinate systems are not {@linkplain AxesConvention#NORMALIZED
normalized}.</li>
* </ul>
*
+ * By default this class does <strong>not</strong> handle change of
+ * {@linkplain
org.apache.sis.referencing.datum.DefaultGeodeticDatum#getPrimeMeridian() prime
meridian}
+ * or anything else related to datum. Datum changes have dedicated {@link
OperationMethod},
+ * for example <cite>"Longitude rotation"</cite> (EPSG:9601) for changing
the prime meridian.
+ *
* @author Martin Desruisseaux (Geomatys)
* @version 0.7
* @since 0.7
@@ -502,17 +508,6 @@ public class DefaultMathTransformFactory
}
/**
- * Sets the source ellipsoid to the given value.
- * The source coordinate system is unconditionally set to {@code null}.
- *
- * @param ellipsoid The ellipsoid to set as the source (can be {@code
null}).
- */
- public void setSource(final Ellipsoid ellipsoid) {
- sourceEllipsoid = ellipsoid;
- sourceCS = null;
- }
-
- /**
* Sets the source coordinate system to the given value.
* The source ellipsoid is unconditionally set to {@code null}.
*
@@ -524,26 +519,23 @@ public class DefaultMathTransformFactory
}
/**
- * Sets the source ellipsoid and coordinate system to values inferred
from the given CRS.
- * The source ellipsoid will be non-null only if the given CRS is
geographic (not geocentric).
+ * Sets the source coordinate system and its associated ellipsoid to
the given value.
*
- * @param crs The source coordinate reference system (can be {@code
null}).
- */
- public void setSource(final CoordinateReferenceSystem crs) {
- sourceCS = (crs != null) ? crs.getCoordinateSystem() : null;
- sourceEllipsoid =
ReferencingUtilities.getEllipsoidOfGeographicCRS(crs);
- // Ellipsoid is intentionally null for GeocentricCRS.
- }
-
- /**
- * Sets the target ellipsoid to the given value.
- * The target coordinate system is unconditionally set to {@code null}.
+ * <div class="note"><b>Design note:</b>
+ * ellipsoidal coordinate systems and ellipsoids are associated
indirectly, through a geodetic CRS.
+ * However this method expects those two components to be given
explicitely instead than inferring
+ * them from a {@code CoordinateReferenceSystem} for making clear that
{@code MathTransformFactory}
+ * does not perform any {@linkplain
org.apache.sis.referencing.datum.DefaultGeodeticDatum geodetic
+ * datum} analysis. For coordinate operations that take datum changes
in account (including change
+ * of prime meridian), see {@link
org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory}.
+ * This policy helps to enforce a separation of concerns.</div>
*
- * @param ellipsoid The ellipsoid to set as the target (can be {@code
null}).
+ * @param cs The coordinate system to set as the source, or {@code
null}.
+ * @param ellipsoid The ellipsoid associated to the given coordinate
system, or {@code null}.
*/
- public void setTarget(final Ellipsoid ellipsoid) {
- targetEllipsoid = ellipsoid;
- targetCS = null;
+ public void setSource(final EllipsoidalCS cs, final Ellipsoid
ellipsoid) {
+ sourceCS = cs;
+ sourceEllipsoid = ellipsoid;
}
/**
@@ -558,15 +550,17 @@ public class DefaultMathTransformFactory
}
/**
- * Sets the target ellipsoid and coordinate system to values inferred
from the given CRS.
- * The target ellipsoid will be non-null only if the given CRS is
geographic (not geocentric).
+ * Sets the target coordinate system and its associated ellipsoid to
the given value.
+ *
+ * <div class="note"><b>Design note:</b>
+ * see {@link #setSource(EllipsoidalCS, Ellipsoid)}.</div>
*
- * @param crs The target coordinate reference system (can be {@code
null}).
+ * @param cs The coordinate system to set as the source, or {@code
null}.
+ * @param ellipsoid The ellipsoid associated to the given coordinate
system, or {@code null}.
*/
- public void setTarget(final CoordinateReferenceSystem crs) {
- targetCS = (crs != null) ? crs.getCoordinateSystem() : null;
- targetEllipsoid =
ReferencingUtilities.getEllipsoidOfGeographicCRS(crs);
- // Ellipsoid is intentionally null for GeocentricCRS.
+ public void setTarget(final EllipsoidalCS cs, final Ellipsoid
ellipsoid) {
+ targetCS = cs;
+ targetEllipsoid = ellipsoid;
}
/**
@@ -608,6 +602,70 @@ public class DefaultMathTransformFactory
}
/**
+ * Returns the matrix that represent the affine transform to
concatenate before or after
+ * the parameterized transform. The {@code role} argument specifies
which matrix is desired:
+ *
+ * <ul class="verbose">
+ * <li>{@link
org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#NORMALIZATION
+ * NORMALIZATION} for the conversion from the {@linkplain
#getSourceCS() source coordinate system} to
+ * a {@linkplain AxesConvention#NORMALIZED normalized}
coordinate system, usually with
+ * (<var>longitude</var>, <var>latitude</var>) axis order in
degrees or
+ * (<var>easting</var>, <var>northing</var>) in metres.
+ * This normalization needs to be applied <em>before</em> the
parameterized transform.</li>
+ *
+ * <li>{@link
org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#DENORMALIZATION
+ * DENORMALIZATION} for the conversion from a normalized
coordinate system to the
+ * {@linkplain #getTargetCS() target coordinate system}, for
example with
+ * (<var>latitude</var>, <var>longitude</var>) axis order.
+ * This denormalization needs to be applied <em>after</em> the
parameterized transform.</li>
+ *
+ * <li>{@link
org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#INVERSE_NORMALIZATION
INVERSE_NORMALIZATION} and
+ * {@link
org.apache.sis.referencing.operation.transform.ContextualParameters.MatrixRole#INVERSE_DENORMALIZATION
INVERSE_DENORMALIZATION}
+ * are also supported but rarely used.</li>
+ * </ul>
+ *
+ * This method is invoked by {@link
DefaultMathTransformFactory#swapAndScaleAxes(MathTransform, Context)}.
+ * Users an override this method if they need to customize the
normalization process.
+ *
+ * @param role Whether the normalization or denormalization matrix is
desired.
+ * @return The requested matrix, or {@code null} if this {@code
Context} has no information about the coordinate system.
+ * @throws FactoryException if an error occurred while computing the
matrix.
+ *
+ * @see DefaultMathTransformFactory#createAffineTransform(Matrix)
+ * @see
DefaultMathTransformFactory#createParameterizedTransform(ParameterValueGroup,
Context)
+ */
+ @SuppressWarnings("fallthrough")
+ public Matrix getMatrix(final ContextualParameters.MatrixRole role)
throws FactoryException {
+ final CoordinateSystem source, target;
+ boolean inverse = false;
+ switch (role) {
+ case INVERSE_NORMALIZATION: inverse = true; // Fall
through
+ case NORMALIZATION: {
+ source = getSourceCS(); if (source == null) return null;
+ target = CoordinateSystems.replaceAxes(source,
AxesConvention.NORMALIZED);
+ break;
+ }
+ case INVERSE_DENORMALIZATION: inverse = true; // Fall
through
+ case DENORMALIZATION: {
+ target = getTargetCS(); if (target == null) return null;
+ source = CoordinateSystems.replaceAxes(target,
AxesConvention.NORMALIZED);
+ break;
+ }
+ default: throw new
IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2,
"role", role));
+ }
+ Matrix matrix;
+ try {
+ matrix = CoordinateSystems.swapAndScaleAxes(source, target);
+ if (inverse) {
+ matrix = Matrices.inverse(matrix);
+ }
+ } catch (IllegalArgumentException | ConversionException |
NoninvertibleMatrixException cause) {
+ throw new
InvalidGeodeticParameterException(cause.getLocalizedMessage(), cause);
+ }
+ return matrix;
+ }
+
+ /**
* Returns the parameter values used for the math transform creation,
including the parameters completed
* by the factory.
*
@@ -965,7 +1023,7 @@ public class DefaultMathTransformFactory
/**
* Given a transform between normalized spaces,
- * creates a transform taking in account axis directions and units of
measurement.
+ * creates a transform taking in account axis directions, units of
measurement and longitude rotation.
* This method {@linkplain #createConcatenatedTransform concatenates} the
given parameterized transform
* with any other transform required for performing units changes and
ordinates swapping.
*
@@ -981,6 +1039,10 @@ public class DefaultMathTransformFactory
* both of them with ({@linkplain
org.opengis.referencing.cs.AxisDirection#EAST East},
* {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}) axis
orientations.</div>
*
+ * <div class="section">Controlling the normalization process</div>
+ * Users who need a different normalized space than the default one way
find more convenient to
+ * override the {@link Context#getMatrix
Context.getMatrix(ContextualParameters.MatrixRole)} method.
+ *
* @param parameterized A transform for normalized input and output
coordinates.
* @param context Source and target coordinate systems in which the
transform is going to be used.
* @return A transform taking in account unit conversions and axis
swapping.
@@ -988,25 +1050,20 @@ public class DefaultMathTransformFactory
*
* @see org.apache.sis.referencing.cs.AxesConvention#NORMALIZED
* @see
org.apache.sis.referencing.operation.DefaultConversion#DefaultConversion(Map,
OperationMethod, MathTransform, ParameterValueGroup)
+ *
+ * @since 0.7
*/
public MathTransform swapAndScaleAxes(final MathTransform parameterized,
final Context context) throws FactoryException {
ArgumentChecks.ensureNonNull("parameterized", parameterized);
ArgumentChecks.ensureNonNull("context", context);
- final CoordinateSystem sourceCS = context.getSourceCS();
- final CoordinateSystem targetCS = context.getTargetCS();
/*
* Computes matrix for swapping axis and performing units conversion.
* There is one matrix to apply before projection on
(longitude,latitude)
* coordinates, and one matrix to apply after projection on
(easting,northing)
* coordinates.
*/
- final Matrix swap1, swap3;
- try {
- swap1 = (sourceCS != null) ?
CoordinateSystems.swapAndScaleAxes(sourceCS,
CoordinateSystems.replaceAxes(sourceCS, AxesConvention.NORMALIZED)) : null;
- swap3 = (targetCS != null) ?
CoordinateSystems.swapAndScaleAxes(CoordinateSystems.replaceAxes(targetCS,
AxesConvention.NORMALIZED), targetCS) : null;
- } catch (IllegalArgumentException | ConversionException cause) {
- throw new
InvalidGeodeticParameterException(cause.getLocalizedMessage(), cause);
- }
+ final Matrix swap1 =
context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
+ final Matrix swap3 =
context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
/*
* Prepares the concatenation of the matrices computed above and the
projection.
* Note that at this stage, the dimensions between each step may not
be compatible.
@@ -1086,8 +1143,7 @@ public class DefaultMathTransformFactory
ArgumentChecks.ensureNonNull("baseCRS", baseCRS);
ArgumentChecks.ensureNonNull("parameters", parameters);
ArgumentChecks.ensureNonNull("derivedCS", derivedCS);
- final Context context = new Context();
- context.setSource(baseCRS);
+ final Context context =
ReferencingUtilities.createTransformContext(baseCRS, null, null);
context.setTarget(derivedCS);
return createParameterizedTransform(parameters, context);
}