Author: desruisseaux
Date: Wed Mar 18 10:53:24 2015
New Revision: 1667491
URL: http://svn.apache.org/r1667491
Log:
Referencing: port the code to be used for hiding the (linear / non-linear)
separation at WKT formatting time.
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/NonLinearParameters.java
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/NonLinearParameters.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/NonLinearParameters.java?rev=1667491&r1=1667490&r2=1667491&view=diff
==============================================================================
---
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/NonLinearParameters.java
[UTF-8] (original)
+++
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/NonLinearParameters.java
[UTF-8] Wed Mar 18 10:53:24 2015
@@ -16,6 +16,7 @@
*/
package org.apache.sis.referencing.operation.transform;
+import java.util.List;
import java.util.Objects;
import java.io.Serializable;
import org.opengis.util.FactoryException;
@@ -23,13 +24,16 @@ import org.opengis.referencing.operation
import org.opengis.referencing.operation.OperationMethod;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.operation.Matrix;
import org.opengis.referencing.operation.MathTransformFactory;
import org.apache.sis.internal.referencing.WKTUtilities;
import org.apache.sis.parameter.Parameterized;
import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import
org.apache.sis.referencing.operation.matrix.NoninvertibleMatrixException;
import org.apache.sis.io.wkt.FormattableObject;
import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.resources.Errors;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -203,7 +207,7 @@ public abstract class NonLinearParameter
* Formats the <cite>Well Known Text</cite> for the inverse of the
transform that would be built
* from the enclosing {@code NonLinearParameters}.
*/
- final class InverseWKT extends FormattableObject implements Parameterized {
+ private final class InverseWKT extends FormattableObject implements
Parameterized {
/**
* Creates a new object to be formatted instead than the enclosing
transform.
*/
@@ -238,4 +242,135 @@ public abstract class NonLinearParameter
return "Inverse_MT";
}
}
+
+ /**
+ * Given a transformation chain, replaces the elements around {@code
transforms.get(index)} transform by
+ * alternative objects to use when formatting WKT. The replacement is
performed in-place in the given list.
+ *
+ * <p>This method shall replace only the previous element and the few next
elements that need
+ * to be changed as a result of the previous change. This method is not
expected to continue
+ * the iteration after the changes that are of direct concern to this
object.</p>
+ *
+ * @param transforms The full chain of concatenated transforms.
+ * @param index The index of this transform in the {@code
transforms} chain.
+ * @param inverse Always {@code false}, except if we are formatting
the inverse transform.
+ * @return Index of the last transform processed. Iteration should
continue at that index + 1.
+ */
+ final int beforeFormat(final List<Object> transforms, int index, final
boolean inverse) {
+ /*
+ * We expect affine transforms before and after the unitary
projection. Extracts those
+ * affine transforms now. If one or both are missing, we will treat
null as an identity
+ * transform. We will not replace the elements in the list before new
values for those
+ * affine transforms have been fully calculated.
+ */
+ Matrix before = null;
+ Matrix after = null;
+ if (index != 0) {
+ final Object candidate = transforms.get(index - 1);
+ if (candidate instanceof MathTransform) {
+ before = MathTransforms.getMatrix((MathTransform) candidate);
+ }
+ }
+ if (index+1 < transforms.size()) {
+ final Object candidate = transforms.get(index + 1);
+ if (candidate instanceof MathTransform) {
+ after = MathTransforms.getMatrix((MathTransform) candidate);
+ }
+ }
+ final boolean hasBefore = (before != null);
+ final boolean hasAfter = (after != null);
+ /*
+ * We assume that the "before" affine contains the normalize operation
to be applied
+ * before the projection. However it may contains more than just this
normalization,
+ * because it may have been concatenated with any user-defined
transform (for example
+ * in order to apply a change of axis order). We need to separate the
"user-defined"
+ * part from the "normalize" part.
+ */
+ MatrixSIS userDefined = normalize(!inverse);
+ if (!inverse) try {
+ userDefined = userDefined.inverse();
+ } catch (NoninvertibleMatrixException e) {
+ // Should never happen. But if it does, we abandon the attempt to
change
+ // the list elements and will format the objects in their "raw"
format.
+ unexpectedException(e);
+ return index;
+ }
+ if (hasBefore) {
+ userDefined = userDefined.multiply(before);
+ }
+ /*
+ * At this point "userDefined" is the affine transform to show to user
instead of the
+ * "before" affine transform. Replaces "before" by "userDefined"
locally (but not yet
+ * in the list), or set it to null (meaning that it will be removed
from the list) if
+ * it is identity, which happen quite often. Note that in the former
(non-null) case,
+ * the coefficients are often either 0 or 1 since the transform is
often for changing
+ * axis order, so it is worth to attempt rounding coefficents.
+ */
+ before = userDefined.isIdentity() ? null : userDefined;
+ /*
+ * Compute the "after" affine transform in a way similar than the
"before" affine.
+ * Note that if this operation fails, we will cancel everything we
would have done
+ * in this method (i.e. we do not touch the transforms list at all).
+ */
+ userDefined = normalize(inverse);
+ if (!inverse) try {
+ userDefined = userDefined.inverse();
+ } catch (NoninvertibleMatrixException e) {
+ unexpectedException(e);
+ return index;
+ }
+ if (hasAfter) {
+ userDefined = MatrixSIS.castOrCopy(after).multiply(userDefined);
+ }
+ after = userDefined.isIdentity() ? null : userDefined;
+ /*
+ * At this point we have computed all the affine transforms to show to
the user.
+ * We can replace the elements in the list. The transform referenced
by transforms.get(index)
+ * is usually a UnitaryProjection, to be replaced by a
NonLinearParameters instance in order
+ * to format real parameter values (semi-major axis, scale factor,
etc.)
+ * instead than a semi-major axis length of 1.
+ */
+ if (before == null) {
+ if (hasBefore) {
+ final Object old = transforms.remove(--index);
+ assert (old instanceof LinearTransform);
+ }
+ } else {
+ if (hasBefore) {
+ final Object old = transforms.set(index-1, before);
+ assert (old instanceof LinearTransform);
+ } else {
+ transforms.add(index++, before);
+ }
+ }
+ transforms.set(index, inverse ? new InverseWKT() : this);
+ if (after == null) {
+ if (hasAfter) {
+ final Object old = transforms.remove(index + 1);
+ assert (old instanceof LinearTransform);
+ }
+ } else {
+ index++;
+ if (hasAfter) {
+ final Object old = transforms.set(index, after);
+ assert (old instanceof LinearTransform);
+ } else {
+ transforms.add(index, after);
+ }
+ }
+ return index;
+ }
+
+ /**
+ * Logs a warning about a non-invertible transform. This method may be
invoked during WKT
+ * formatting. This error should never occur, but it still possible to
recover from this
+ * error and let WKT formatting to continue, which can be useful for
debugging.
+ *
+ * <p>We pretend that the error come from {@link
ConcatenatedTransform#formatTo(Formatter)}
+ * because this error should occurs only in the context of WKT formatting
of a concatenated
+ * transform.</p>
+ */
+ private static void unexpectedException(final NoninvertibleMatrixException
e) {
+ Logging.unexpectedException(ConcatenatedTransform.class, "formatTo",
e);
+ }
}