Author: desruisseaux
Date: Thu Feb 12 21:21:36 2015
New Revision: 1659405
URL: http://svn.apache.org/r1659405
Log:
Continue the port of DefaultMathTransformFactory.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/HardCoded.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/HardCoded.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/HardCoded.java?rev=1659405&r1=1659404&r2=1659405&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/HardCoded.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/HardCoded.java
[UTF-8] Thu Feb 12 21:21:36 2015
@@ -25,7 +25,7 @@ import org.apache.sis.internal.util.Cita
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.5
- * @version 0.5
+ * @version 0.6
* @module
*/
public final class HardCoded extends Static {
@@ -35,6 +35,11 @@ public final class HardCoded extends Sta
public static final String EPSG = Citations.EPSG;
/**
+ * Name of the {@value} projection parameter, which is handled specially
during WKT formatting.
+ */
+ public static final String SEMI_MAJOR = "semi_major", SEMI_MINOR =
"semi_minor";
+
+ /**
* The {@value} code space.
*/
public static final String CRS = "CRS";
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=1659405&r1=1659404&r2=1659405&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] Thu Feb 12 21:21:36 2015
@@ -27,24 +27,35 @@ import java.util.logging.Level;
import javax.measure.quantity.Length;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
+import javax.measure.converter.ConversionException;
+
import org.opengis.metadata.Identifier;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.datum.Ellipsoid;
+import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.OperationMethod;
import org.opengis.referencing.operation.SingleOperation;
import org.opengis.util.FactoryException;
import org.opengis.util.NoSuchIdentifierException;
+
import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.internal.referencing.HardCoded;
import org.apache.sis.internal.referencing.ReferencingUtilities;
+import org.apache.sis.internal.referencing.j2d.ParameterizedAffine;
+import org.apache.sis.parameter.Parameters;
import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.cs.CoordinateSystems;
import org.apache.sis.referencing.operation.DefaultOperationMethod;
+import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.Classes;
import org.apache.sis.util.Deprecable;
import org.apache.sis.util.collection.WeakHashSet;
import org.apache.sis.util.iso.AbstractFactory;
@@ -81,7 +92,7 @@ import org.apache.sis.util.resources.Mes
* @version 0.6
* @module
*/
-public abstract class DefaultMathTransformFactory extends AbstractFactory
implements MathTransformFactory {
+public class DefaultMathTransformFactory extends AbstractFactory implements
MathTransformFactory {
/**
* The separator character between an identifier and its namespace in the
argument given to
* {@link #getOperationMethod(String)}. For example this is the separator
in {@code "EPSG:9807"}.
@@ -206,7 +217,8 @@ public abstract class DefaultMathTransfo
* if it does not support filtering by the given type.
*
* @param type <code>{@linkplain SingleOperation}.class</code> for
fetching all operation methods,
- * <code>{@linkplain Projection}.class</code> for fetching only
map projection methods, <i>etc</i>.
+ * <code>{@linkplain
org.opengis.referencing.operation.Projection}.class</code> for fetching
+ * only map projection methods, <i>etc</i>.
* @return Methods available in this factory for coordinate operations of
the given type.
*
* @see #getDefaultParameters(String)
@@ -276,7 +288,7 @@ public abstract class DefaultMathTransfo
}
}
if (method == null) {
- throw new
NoSuchIdentifierException(Errors.format(Errors.Keys.NoSuchOperationMethod_1,
method), identifier);
+ throw new
NoSuchIdentifierException(Errors.format(Errors.Keys.NoSuchOperationMethod_1,
identifier), identifier);
}
/*
* Remember the method we just found, for faster check next time.
@@ -325,8 +337,7 @@ public abstract class DefaultMathTransfo
* "<a
href="http://www.remotesensing.org/geotiff/proj_list/transverse_mercator.html">Transverse
Mercator</a>").
*
* <p>This method creates new parameter instances at every call. The
returned object is intended to be modified
- * by the user before to be passed to <code>{@linkplain
#createParameterizedTransform(ParameterValueGroup)
- * createParameterizedTransform}(parameters)</code>.</p>
+ * by the user before to be passed to {@link
#createParameterizedTransform(ParameterValueGroup)}.</p>
*
* @param method The name or identifier of the operation method to search.
* @return A new group of parameter values for the {@code OperationMethod}
identified by the given name.
@@ -380,23 +391,27 @@ public abstract class DefaultMathTransfo
}
/**
- * Creates a {@linkplain
#createParameterizedTransform(ParameterValueGroup) parameterized transform}
- * from a base CRS to a derived CS. This convenience method {@linkplain
#createConcatenatedTransform
- * concatenates} the parameterized transform with any other transform
required for performing units
- * changes and ordinates swapping.
- *
- * In addition, this method infers the {@code "semi_major"} and {@code
"semi_minor"} parameters values
- * from the {@linkplain org.apache.sis.referencing.datum.DefaultEllipsoid
ellipsoid} associated to the
- * {@code baseCRS}, if those parameters are not explicitly given and if
they are applicable (typically
- * for cartographic projections).
+ * Creates a transform from a base CRS to a derived CS using the given
parameters.
+ * This convenience method:
+ *
+ * <ol>
+ * <li>Infers the {@code "semi_major"} and {@code "semi_minor"}
parameters values from the
+ * {@linkplain org.apache.sis.referencing.datum.DefaultEllipsoid
ellipsoid} associated
+ * to the {@code baseCRS}, if those parameters are not explicitly
given and if they are
+ * applicable (typically for cartographic projections).</li>
+ * <li>{@linkplain #createConcatenatedTransform Concatenates} the
+ * {@linkplain #createParameterizedTransform(ParameterValueGroup)
parameterized transform}
+ * with any other transform required for performing units changes
and ordinates swapping.</li>
+ * </ol>
*
- * <p>The {@code OperationMethod} instance used by this method can be
obtained by a call to
- * {@link #getLastMethodUsed()}.</p>
+ * The {@code OperationMethod} instance used by this method can be
obtained by a call to
+ * {@link #getLastMethodUsed()}.
*
* @param baseCRS The source coordinate reference system.
* @param parameters The parameter values for the transform.
* @param derivedCS The target coordinate system.
- * @return The parameterized transform.
+ * @return The parameterized transform from {@code baseCRS} to {@code
derivedCS},
+ * including unit conversions and axis swapping.
* @throws NoSuchIdentifierException if there is no transform registered
for the method.
* @throws FactoryException if the object creation failed. This exception
is thrown
* if some required parameter has not been supplied, or has
illegal value.
@@ -417,8 +432,8 @@ public abstract class DefaultMathTransfo
ParameterValue<?> mismatchedParam = null;
double mismatchedValue = 0;
try {
- final ParameterValue<?> semiMajor =
parameters.parameter("semi_major");
- final ParameterValue<?> semiMinor =
parameters.parameter("semi_minor");
+ final ParameterValue<?> semiMajor =
parameters.parameter(HardCoded.SEMI_MAJOR);
+ final ParameterValue<?> semiMinor =
parameters.parameter(HardCoded.SEMI_MINOR);
final Unit<Length> axisUnit = ellipsoid.getAxisUnit();
/*
* The two calls to getOptional(…) shall succeed before we
write anything, in order to have a
@@ -463,7 +478,7 @@ public abstract class DefaultMathTransfo
try {
baseToDerived = createParameterizedTransform(parameters);
final OperationMethod method = lastMethod.get();
- baseToDerived = createBaseToDerived(baseCRS, baseToDerived,
derivedCS);
+ baseToDerived = createBaseToDerived(baseCRS.getCoordinateSystem(),
baseToDerived, derivedCS);
lastMethod.set(method);
} catch (FactoryException e) {
if (failure != null) {
@@ -475,22 +490,181 @@ public abstract class DefaultMathTransfo
}
/**
- * Creates a transform from a base CRS to a derived CS. This method
expects a "raw" transform without
- * unit conversion or axis swapping. Such "raw" transforms are typically
map projections working on
- * (<cite>longitude</cite>, <cite>latitude</cite>) axes in degrees and
(<cite>x</cite>, <cite>y</cite>)
- * axes in metres. This method inspects the coordinate systems and prepend
or append the unit conversions
- * and axis swapping automatically.
+ * Creates a transform from a base to a derived CS using an existing
parameterized transform.
+ * This convenience method {@linkplain #createConcatenatedTransform
concatenates} the given parameterized
+ * transform with any other transform required for performing units
changes and ordinates swapping.
+ *
+ * <p>The given {@code parameterized} transform shall expect
+ * {@linkplain org.apache.sis.referencing.cs.AxesConvention#NORMALIZED
normalized} input coordinates and
+ * produce normalized output coordinates. See {@link
org.apache.sis.referencing.cs.AxesConvention} for more
+ * information about what Apache SIS means by "normalized".</p>
*
- * @param baseCRS The source coordinate reference system.
- * @param projection The "raw" <cite>base to derived</cite> transform.
- * @param derivedCS the target coordinate system.
+ * <div class="note"><b>Example:</b>
+ * The most typical examples of transforms with normalized inputs/outputs
are normalized
+ * map projections expecting (<cite>longitude</cite>,
<cite>latitude</cite>) inputs in degrees
+ * and calculating (<cite>x</cite>, <cite>y</cite>) coordinates in metres,
+ * both of them with ({@linkplain
org.opengis.referencing.cs.AxisDirection#EAST East},
+ * {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}) axis
orientations.</div>
+ *
+ * @param baseCS The source coordinate system.
+ * @param parameterized A <cite>base to derived</cite> transform for
normalized input and output coordinates.
+ * @param derivedCS The target coordinate system.
+ * @return The transform from {@code baseCS} to {@code derivedCS},
including unit conversions and axis swapping.
+ * @throws FactoryException if the object creation failed. This exception
is thrown
+ * if some required parameter has not been supplied, or has
illegal value.
+ *
+ * @see org.apache.sis.referencing.cs.AxesConvention#NORMALIZED
+ */
+ public MathTransform createBaseToDerived(final CoordinateSystem baseCS,
+ final MathTransform parameterized, final CoordinateSystem
derivedCS)
+ throws FactoryException
+ {
+ /*
+ * 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 = CoordinateSystems.swapAndScaleAxes(baseCS,
CoordinateSystems.normalize(baseCS));
+ swap3 =
CoordinateSystems.swapAndScaleAxes(CoordinateSystems.normalize(derivedCS),
derivedCS);
+ } catch (IllegalArgumentException | ConversionException cause) {
+ throw new FactoryException(cause);
+ }
+ /*
+ * 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.
+ * For example the projection (step2) is usually two-dimensional while
the source
+ * coordinate system (step1) may be three-dimensional if it has a
height.
+ */
+ MathTransform step1 = createAffineTransform(swap1);
+ MathTransform step3 = createAffineTransform(swap3);
+ MathTransform step2 = parameterized;
+ /*
+ * If the target coordinate system has a height, instructs the
projection to pass
+ * the height unchanged from the base CRS to the target CRS. After
this block, the
+ * dimensions of 'step2' and 'step3' should match.
+ */
+ final int numTrailingOrdinates = step3.getSourceDimensions() -
step2.getTargetDimensions();
+ if (numTrailingOrdinates > 0) {
+ step2 = createPassThroughTransform(0, step2, numTrailingOrdinates);
+ }
+ /*
+ * If the source CS has a height but the target CS doesn't, drops the
extra coordinates.
+ * After this block, the dimensions of 'step1' and 'step2' should
match.
+ */
+ final int sourceDim = step1.getTargetDimensions();
+ final int targetDim = step2.getSourceDimensions();
+ if (sourceDim > targetDim) {
+ final Matrix drop = Matrices.createDiagonal(targetDim+1,
sourceDim+1);
+ drop.setElement(targetDim, sourceDim, 1); // Element in the
lower-right corner.
+ step1 = createConcatenatedTransform(createAffineTransform(drop),
step1);
+ }
+ MathTransform mt =
createConcatenatedTransform(createConcatenatedTransform(step1, step2), step3);
+ /*
+ * At this point we finished to create the transform. But before to
return it, verify if the
+ * parameterized transform given in argument had some custom
parameters. This happen with the
+ * Equirectangular projection, which can be simplified as an
AffineTransform while we want to
+ * continue to describe it with the "semi_major", "semi_minor", etc.
parameters instead than
+ * "elt_0_0", "elt_0_1", etc. The following code just forwards those
parameters to the newly
+ * created transform; it does not change the operation.
+ */
+ if (parameterized instanceof ParameterizedAffine) {
+ mt = ((ParameterizedAffine) parameterized).newTransform(mt);
+ }
+ return mt;
+ }
+
+ /**
+ * Creates a transform from a group of parameters. The {@code
OperationMethod} name is inferred
+ * from the {@linkplain ParameterDescriptorGroup#getName() parameter group
name}.
+ * Example:
+ *
+ * {@preformat java
+ * ParameterValueGroup p =
factory.getDefaultParameters("Transverse_Mercator");
+ * p.parameter("semi_major").setValue(6378137.000);
+ * p.parameter("semi_minor").setValue(6356752.314);
+ * MathTransform mt = factory.createParameterizedTransform(p);
+ * }
+ *
+ * @param parameters The parameter values.
* @return The parameterized transform.
+ * @throws NoSuchIdentifierException if there is no transform registered
for the method.
* @throws FactoryException if the object creation failed. This exception
is thrown
* if some required parameter has not been supplied, or has
illegal value.
+ *
+ * @see #getDefaultParameters(String)
+ * @see #getAvailableMethods(Class)
+ * @see #getLastMethodUsed()
*/
- public abstract MathTransform createBaseToDerived(final
CoordinateReferenceSystem baseCRS,
- final MathTransform projection, final CoordinateSystem derivedCS)
- throws FactoryException;
+ @Override
+ public MathTransform createParameterizedTransform(ParameterValueGroup
parameters)
+ throws NoSuchIdentifierException, FactoryException
+ {
+ final String methodName =
parameters.getDescriptor().getName().getCode();
+ OperationMethod method = null;
+ try {
+ method = getOperationMethod(methodName);
+ } finally {
+ lastMethod.set(method); // May be null in case of failure, which
is intended.
+ }
+ if (!(method instanceof MathTransformProvider)) {
+ throw new NoSuchIdentifierException(Errors.format( // For now,
handle like an unknown operation.
+ Errors.Keys.UnsupportedImplementation_1,
Classes.getClass(method)), methodName);
+ }
+ /*
+ * If the "official" parameter descriptor was used, that descriptor
should have already
+ * enforced argument validity. Consequently, there is no need to
performs the check and
+ * we will avoid it as a performance enhancement.
+ */
+ final ParameterDescriptorGroup expected = method.getParameters();
+ final boolean isConform = expected.equals(parameters.getDescriptor());
+ MathTransform transform;
+ try {
+ if (!isConform) {
+ /*
+ * Copies all values from the user-supplied group to the
provider-supplied group.
+ * The later should perform all needed checks. It is
supplier's responsibility to
+ * know about alias (e.g. OGC, EPSG, ESRI), since the caller
probably used names
+ * from only one authority.
+ */
+ final ParameterValueGroup copy = expected.createValue();
+ Parameters.copy(parameters, copy);
+ parameters = copy;
+ }
+ transform = ((MathTransformProvider)
method).createMathTransform(parameters);
+ } catch (IllegalArgumentException | IllegalStateException exception) {
+ /*
+ * Catch only exceptions which may be the result of improper
parameter
+ * usage (e.g. a value out of range). Do not catch exception
caused by
+ * programming errors (e.g. null pointer exception).
+ */
+ throw new FactoryException(exception);
+ }
+ transform = pool.unique(transform);
+ return transform;
+ }
+
+ /**
+ * Creates an affine transform from a matrix. If the transform input
dimension is {@code M},
+ * and output dimension is {@code N}, then the matrix will have size
{@code [N+1][M+1]}. The
+ * +1 in the matrix dimensions allows the matrix to do a shift, as well as
a rotation. The
+ * {@code [M][j]} element of the matrix will be the j'th ordinate of the
moved origin. The
+ * {@code [i][N]} element of the matrix will be 0 for <var>i</var> less
than {@code M}, and 1
+ * for <var>i</var> equals {@code M}.
+ *
+ * @param matrix The matrix used to define the affine transform.
+ * @return The affine transform.
+ * @throws FactoryException if the object creation failed.
+ *
+ * @see MathTransforms#linear(Matrix)
+ */
+ @Override
+ public MathTransform createAffineTransform(final Matrix matrix) throws
FactoryException {
+ lastMethod.remove(); // To be strict, we should set the
ProjectiveTransform provider
+ return pool.unique(MathTransforms.linear(matrix));
+ }
/**
* Creates a transform by concatenating two existing transforms.
@@ -503,12 +677,15 @@ public abstract class DefaultMathTransfo
* @param transform2 The second transform to apply to points.
* @return The concatenated transform.
* @throws FactoryException if the object creation failed.
+ *
+ * @see MathTransforms#concatenate(MathTransform, MathTransform)
*/
@Override
public MathTransform createConcatenatedTransform(final MathTransform
transform1,
final MathTransform
transform2)
throws FactoryException
{
+ lastMethod.remove();
MathTransform tr;
try {
tr = MathTransforms.concatenate(transform1, transform2);
@@ -536,7 +713,7 @@ public abstract class DefaultMathTransfo
* }
*
* @param firstAffectedOrdinate The lowest index of the affected
ordinates.
- * @param subTransform Transform to use for affected ordinates.
+ * @param subTransform Transform to use for affected ordinates.
* @param numTrailingOrdinates Number of trailing ordinates to pass
through. Affected ordinates will range
* from {@code firstAffectedOrdinate} inclusive to {@code
dimTarget-numTrailingOrdinates} exclusive.
* @return A pass through transform.
@@ -548,6 +725,7 @@ public abstract class DefaultMathTransfo
final int
numTrailingOrdinates)
throws FactoryException
{
+ lastMethod.remove();
MathTransform tr;
try {
tr = PassThroughTransform.create(firstAffectedOrdinate,
subTransform, numTrailingOrdinates);
@@ -559,10 +737,40 @@ public abstract class DefaultMathTransfo
}
/**
- * Returns the operation method used for the latest call to
- * {@link #createParameterizedTransform(ParameterValueGroup)} in the
currently running thread.
+ * Creates a math transform object from a XML string. The default
implementation
+ * always throws an exception, since this method is not yet implemented.
+ *
+ * @param xml Math transform encoded in XML format.
+ * @throws FactoryException if the object creation failed.
+ */
+ @Override
+ public MathTransform createFromXML(String xml) throws FactoryException {
+ lastMethod.remove();
+ throw new FactoryException("Not yet implemented.");
+ }
+
+ /**
+ * Creates a math transform object from a
+ * <a
href="http://www.geoapi.org/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
+ * Known Text</cite> (WKT)</a>.
+ *
+ * @param text Math transform encoded in Well-Known Text format.
+ * @return The math transform (never {@code null}).
+ * @throws FactoryException if the Well-Known Text can't be parsed,
+ * or if the math transform creation failed from some other reason.
+ */
+ @Override
+ public MathTransform createFromWKT(final String text) throws
FactoryException {
+ lastMethod.remove();
+ throw new FactoryException("Not yet implemented.");
+ }
+
+ /**
+ * Returns the operation method used by the latest call to a {@code
create} method in the currently running thread.
* Returns {@code null} if not applicable.
*
+ * @return The last method used, or {@code null} if unknown of unsupported.
+ *
* @see #createParameterizedTransform(ParameterValueGroup)
*/
@Override
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java?rev=1659405&r1=1659404&r2=1659405&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
[UTF-8] Thu Feb 12 21:21:36 2015
@@ -109,7 +109,7 @@ public final class MathTransforms extend
* @return The linear (usually affine) transform.
*
* @see #getMatrix(MathTransform)
- * @see
org.opengis.referencing.operation.MathTransformFactory#createAffineTransform(Matrix)
+ * @see DefaultMathTransformFactory#createAffineTransform(Matrix)
*/
public static LinearTransform linear(final Matrix matrix) {
ensureNonNull("matrix", matrix);
@@ -157,7 +157,7 @@ public final class MathTransforms extend
* @throws MismatchedDimensionException if the output dimension of the
first transform
* does not match the input dimension of the second transform.
*
- * @see MathTransformFactory#createConcatenatedTransform(MathTransform,
MathTransform)
+ * @see
DefaultMathTransformFactory#createConcatenatedTransform(MathTransform,
MathTransform)
*/
public static MathTransform concatenate(final MathTransform tr1, final
MathTransform tr2)
throws MismatchedDimensionException