sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1600540 [2/2] - in /sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis: internal/referencing/j2d/ referencing/operation/provider/ referencing/operation/transform/
Date Wed, 04 Jun 2014 23:34:39 GMT
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=1600540&r1=1600539&r2=1600540&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] Wed Jun  4 23:34:38 2014
@@ -26,6 +26,7 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.internal.referencing.DirectPositionView;
 import org.apache.sis.referencing.operation.matrix.AffineTransforms2D;
+import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.util.Static;
 
 import static org.apache.sis.util.ArgumentChecks.*;
@@ -61,6 +62,76 @@ public final class MathTransforms extend
     }
 
     /**
+     * Returns an identity transform of the specified dimension.
+     *
+     * <p>Special cases:</p>
+     * <ul>
+     *   <li>If {@code dimension} == 1, then the returned transform implements {@link
MathTransform1D}.</li>
+     *   <li>If {@code dimension} == 2, then the returned transform implements {@link
MathTransform2D}.</li>
+     * </ul>
+     *
+     * @param dimension The dimension of the transform to be returned.
+     * @return An identity transform of the specified dimension.
+     */
+    public static LinearTransform identity(final int dimension) {
+        ensureStrictlyPositive("dimension", dimension);
+        return IdentityTransform.create(dimension);
+    }
+
+    /**
+     * Creates a one-dimensional affine transform for the given coefficients.
+     * Input values <var>x</var> will be converted into output values <var>y</var>
using the following equation:
+     *
+     * <blockquote><var>y</var>  =  <var>x</var> × {@code
scale} + {@code offset}</blockquote>
+     *
+     * @param  scale  The {@code scale}  term in the linear equation.
+     * @param  offset The {@code offset} term in the linear equation.
+     * @return The linear transform for the given scale and offset.
+     */
+    public static LinearTransform linear(final double scale, final double offset) {
+        return LinearTransform1D.create(scale, offset);
+    }
+
+    /**
+     * Creates an arbitrary linear transform from the specified matrix.
+     * If the transform input dimension is {@code M}, and output dimension is {@code N},
then the
+     * given matrix shall 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 <var>j</var>'th ordinate of the moved origin.
+     *
+     * <p>The matrix is usually square and affine, but this is not mandatory.
+     * Non-affine transforms are allowed.</p>
+     *
+     * @param  matrix The matrix used to define the linear transform.
+     * @return The linear (usually affine) transform.
+     *
+     * @see org.opengis.referencing.operation.MathTransformFactory#createAffineTransform(Matrix)
+     */
+    public static LinearTransform linear(final Matrix matrix) {
+        ensureNonNull("matrix", matrix);
+        final int sourceDimension = matrix.getNumCol() - 1;
+        final int targetDimension = matrix.getNumRow() - 1;
+        if (sourceDimension == targetDimension) {
+            if (matrix.isIdentity()) {
+                return identity(sourceDimension);
+            }
+            if (Matrices.isAffine(matrix)) {
+                switch (sourceDimension) {
+                    case 1: return linear(matrix.getElement(0,0), matrix.getElement(0,1));
+//TODO              case 2: return linear(Matrices.toAffineTransform(matrix));
+                }
+            } else if (sourceDimension == 2) {
+//TODO          return new ProjectiveTransform2D(matrix);
+            }
+        }
+        final LinearTransform candidate = CopyTransform.create(matrix);
+        if (candidate != null) {
+            return candidate;
+        }
+        return new ProjectiveTransform(matrix);
+    }
+
+    /**
      * Concatenates the two given transforms. The returned transform will implement
      * {@link MathTransform1D} or {@link MathTransform2D} if the dimensions of the
      * concatenated transform are equal to 1 or 2 respectively.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ProjectiveTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ProjectiveTransform.java?rev=1600540&r1=1600539&r2=1600540&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ProjectiveTransform.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ProjectiveTransform.java
[UTF-8] Wed Jun  4 23:34:38 2014
@@ -16,14 +16,476 @@
  */
 package org.apache.sis.referencing.operation.transform;
 
+import java.util.Arrays;
+import java.io.Serializable;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
 
-class ProjectiveTransform {
-    public static LinearTransform create(final Matrix matrix) {
-        throw new UnsupportedOperationException();
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.parameter.TensorParameters;
+import org.apache.sis.referencing.operation.provider.Affine;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+
+
+/**
+ * A usually affine, or otherwise a projective transform. A projective transform is capable
of
+ * mapping an arbitrary quadrilateral into another arbitrary quadrilateral, while preserving
the
+ * straightness of lines. In the special case where the transform is affine, the parallelism
of
+ * lines in the source is preserved in the output.
+ *
+ * <p>Such a coordinate transformation can be represented by a square {@linkplain MatrixSIS
matrix}
+ * of arbitrary size. Point coordinates must have a dimension equal to the matrix size minus
one.
+ * For example a square matrix of size 4×4 is used for transforming three-dimensional coordinates.
+ * The transformed points {@code (x',y',z')} are computed as below (note that this computation
is
+ * similar to {@code PerspectiveTransform} in <cite>Java Advanced Imaging</cite>):
+ *
+ * <table class="compact" summary="Projective transform matrix">
+ * <tr><td nowrap>
+ * {@preformat text
+ *     x' = u/t
+ *     y' = v/t
+ *     y' = w/t
+ * }
+ * </td><td><blockquote>where {@code (u,v,w)} are obtained by:</blockquote></td><td
nowrap>
+ * {@preformat text
+ *     ┌   ┐     ┌                    ┐ ┌   ┐
+ *     │ u │     │ m00  m01  m02  m03 │ │ x │
+ *     │ v │  =  │ m10  m11  m12  m13 │ │ y │
+ *     │ w │     │ m20  m21  m22  m23 │ │ z │
+ *     │ t │     │ m30  m31  m32  m33 │ │ 1 │
+ *     └   ┘     └                    ┘ └   ┘
+ * }
+ * </td></tr></table>
+ *
+ * In the special case of an affine transform, the last row contains only zero values except
in the last column,
+ * which contains 1.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.5 (derived from geotk-1.2)
+ * @version 0.5
+ * @module
+ *
+ * @see java.awt.geom.AffineTransform
+ * @see <a href="http://mathworld.wolfram.com/AffineTransformation.html">Affine transformation
on MathWorld</a>
+ */
+public class ProjectiveTransform extends AbstractMathTransform implements LinearTransform,
Serializable {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -2104496465933824935L;
+
+    /**
+     * The number of rows.
+     */
+    private final int numRow;
+
+    /**
+     * The number of columns.
+     */
+    private final int numCol;
+
+    /**
+     * Elements of the matrix. Column indices vary fastest.
+     */
+    private final double[] elt;
+
+    /**
+     * The inverse transform. Will be created only when first needed. This field is part
of the serialization form
+     * in order to avoid rounding errors if a user asks for the inverse of the inverse (i.e.
the original transform)
+     * after deserialization.
+     */
+    AbstractMathTransform inverse;
+
+    /**
+     * Constructs a transform from the specified matrix.
+     * The matrix is usually square and affine, but this is not enforced.
+     *
+     * @param matrix The matrix.
+     */
+    protected ProjectiveTransform(final Matrix matrix) {
+        numRow = matrix.getNumRow();
+        numCol = matrix.getNumCol();
+        elt = new double[numRow * numCol];
+        int index = 0;
+        for (int j=0; j<numRow; j++) {
+            for (int i=0; i<numCol; i++) {
+                elt[index++] = matrix.getElement(j,i);
+            }
+        }
+    }
+
+    /**
+     * Gets the dimension of input points.
+     */
+    @Override
+    public int getSourceDimensions() {
+        return numCol - 1;
+    }
+
+    /**
+     * Gets the dimension of output points.
+     */
+    @Override
+    public int getTargetDimensions() {
+        return numRow - 1;
+    }
+
+    /**
+     * Tests whether this transform does not move any points.
+     */
+    @Override
+    public boolean isIdentity() {
+        if (numRow != numCol) {
+            return false;
+        }
+        int index = 0;
+        for (int j=0; j<numRow; j++) {
+            for (int i=0; i<numCol; i++) {
+                if (elt[index++] != (i == j ? 1 : 0)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns a copy of the matrix given to the constructor.
+     */
+    @Override
+    public Matrix getMatrix() {
+        return Matrices.create(numRow, numCol, elt);
+    }
+
+    /**
+     * Returns the parameter descriptors for this math transform.
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    public ParameterDescriptorGroup getParameterDescriptors() {
+        return Affine.PARAMETERS;
+    }
+
+    /**
+     * Returns the matrix elements as a group of parameters values. The number of parameters
depends on the
+     * matrix size. Only matrix elements different from their default value will be included
in this group.
+     *
+     * @param  matrix The matrix to returns as a group of parameters.
+     * @return A copy of the parameter values for this math transform.
+     */
+    static ParameterValueGroup getParameterValues(final Matrix matrix) {
+//      final MatrixParameters values;
+//      values = (MatrixParameters) Affine.PARAMETERS.createValue();
+//      values.setMatrix(matrix);
+//      return values;
+        return null; // TODO
+    }
+
+    /**
+     * Returns the matrix elements as a group of parameters values. The number of parameters
depends on the
+     * matrix size. Only matrix elements different from their default value will be included
in this group.
+     *
+     * @return A copy of the parameter values for this math transform.
+     */
+    @Override
+    public ParameterValueGroup getParameterValues() {
+        return getParameterValues(getMatrix());
+    }
+
+    /**
+     * Converts a single coordinate point in a list of ordinal values,
+     * and optionally computes the derivative at that location.
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    public Matrix transform(final double[] srcPts, final int srcOff,
+                            final double[] dstPts, final int dstOff,
+                            final boolean derivate)
+    {
+        transform(srcPts, srcOff, dstPts, dstOff, 1);
+        return derivate ? derivative((DirectPosition) null) : null;
+    }
+
+    /**
+     * Transforms an array of floating point coordinates by this matrix. Point coordinates
must have a dimension
+     * equal to <code>{@link Matrix#getNumCol}-1</code>. For example, for square
matrix of size 4×4, coordinate
+     * points are three-dimensional and stored in the arrays starting at the specified offset
({@code srcOff}) in
+     * the order
+     * <code>[x<sub>0</sub>, y<sub>0</sub>, z<sub>0</sub>,
+     *        x<sub>1</sub>, y<sub>1</sub>, z<sub>1</sub>...,
+     *        x<sub>n</sub>, y<sub>n</sub>, z<sub>n</sub>]</code>.
+     *
+     * @param srcPts The array containing the source point coordinates.
+     * @param srcOff The offset to the first point to be transformed in the source array.
+     * @param dstPts The array into which the transformed point coordinates are returned.
+     * @param dstOff The offset to the location of the first transformed point that is stored
in the
+     *               destination array. The source and destination array sections can overlap.
+     * @param numPts The number of points to be transformed.
+     */
+    @Override
+    public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)
{
+        final int srcDim, dstDim;
+        int srcInc = srcDim = numCol - 1; // The last ordinate will be assumed equal to 1.
+        int dstInc = dstDim = numRow - 1;
+        if (srcPts == dstPts) {
+            switch (IterationStrategy.suggest(srcOff, srcDim, dstOff, dstDim, numPts)) {
+                case ASCENDING: {
+                    break;
+                }
+                case DESCENDING: {
+                    srcOff += (numPts-1) * srcDim;
+                    dstOff += (numPts-1) * dstDim;
+                    srcInc = -srcInc;
+                    dstInc = -dstInc;
+                    break;
+                }
+                default: {
+                    srcPts = Arrays.copyOfRange(srcPts, srcOff, srcOff + numPts*srcDim);
+                    srcOff = 0;
+                    break;
+                }
+            }
+        }
+        final double[] buffer = new double[numRow];
+        while (--numPts >= 0) {
+            int mix = 0;
+            for (int j=0; j<numRow; j++) {
+                double sum = elt[mix + srcDim];
+                for (int i=0; i<srcDim; i++) {
+                    final double e = elt[mix++];
+                    if (e != 0) {
+                        /*
+                         * The purpose of the test for non-zero value is not performance
(it is actually more likely
+                         * to slow down the calculation), but to get a valid sum even if
some source ordinates are NaN.
+                         * This occurs when the ProjectiveTransform is used for excluding
some dimensions, for example
+                         * getting 2D points from 3D points. In such case, the fact that
the excluded dimensions had
+                         * NaN values should not force the retained dimensions to get NaN
values.
+                         */
+                        sum += srcPts[srcOff + i] * e;
+                    }
+                }
+                buffer[j] = sum;
+                mix++;
+            }
+            final double w = buffer[dstDim];
+            for (int j=0; j<dstDim; j++) {
+                // 'w' is equal to 1 if the transform is affine.
+                dstPts[dstOff + j] = buffer[j] / w;
+            }
+            srcOff += srcInc;
+            dstOff += dstInc;
+        }
+    }
+
+    /**
+     * Transforms an array of floating point coordinates by this matrix. Point coordinates
must have a dimension
+     * equal to <code>{@link Matrix#getNumCol()} - 1</code>. For example, for
square matrix of size 4×4, coordinate
+     * points are three-dimensional and stored in the arrays starting at the specified offset
({@code srcOff})
+     * in the order
+     * <code>[x<sub>0</sub>, y<sub>0</sub>, z<sub>0</sub>,
+     *        x<sub>1</sub>, y<sub>1</sub>, z<sub>1</sub>...,
+     *        x<sub>n</sub>, y<sub>n</sub>, z<sub>n</sub>]</code>.
+     *
+     * @param srcPts The array containing the source point coordinates.
+     * @param srcOff The offset to the first point to be transformed in the source array.
+     * @param dstPts The array into which the transformed point coordinates are returned.
+     * @param dstOff The offset to the location of the first transformed point that is stored
in the
+     *               destination array. The source and destination array sections can overlap.
+     * @param numPts The number of points to be transformed.
+     */
+    @Override
+    public void transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)
{
+        final int srcDim, dstDim;
+        int srcInc = srcDim = numCol-1;
+        int dstInc = dstDim = numRow-1;
+        if (srcPts == dstPts) {
+            switch (IterationStrategy.suggest(srcOff, srcDim, dstOff, dstDim, numPts)) {
+                case ASCENDING: {
+                    break;
+                }
+                case DESCENDING: {
+                    srcOff += (numPts-1) * srcDim;
+                    dstOff += (numPts-1) * dstDim;
+                    srcInc = -srcInc;
+                    dstInc = -dstInc;
+                    break;
+                }
+                default: {
+                    srcPts = Arrays.copyOfRange(srcPts, srcOff, srcOff + numPts*srcDim);
+                    srcOff = 0;
+                    break;
+                }
+            }
+        }
+        final double[] buffer = new double[numRow];
+        while (--numPts >= 0) {
+            int mix = 0;
+            for (int j=0; j<numRow; j++) {
+                double sum = elt[mix + srcDim];
+                for (int i=0; i<srcDim; i++) {
+                    final double e = elt[mix++];
+                    if (e != 0) { // See comment in transform(double[], ...)
+                        sum += srcPts[srcOff + i] * e;
+                    }
+                }
+                buffer[j] = sum;
+                mix++;
+            }
+            final double w = buffer[dstDim];
+            for (int j=0; j<dstDim; j++) {
+                dstPts[dstOff + j] = (float) (buffer[j] / w);
+            }
+            srcOff += srcInc;
+            dstOff += dstInc;
+        }
+    }
+
+    /**
+     * Transforms an array of floating point coordinates by this matrix.
+     *
+     * @param srcPts The array containing the source point coordinates.
+     * @param srcOff The offset to the first point to be transformed in the source array.
+     * @param dstPts The array into which the transformed point coordinates are returned.
+     * @param dstOff The offset to the location of the first transformed point that is stored
in the destination array.
+     * @param numPts The number of points to be transformed.
+     */
+    @Override
+    public void transform(double[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)
{
+        final int srcDim = numCol-1;
+        final int dstDim = numRow-1;
+        final double[] buffer = new double[numRow];
+        while (--numPts >= 0) {
+            int mix = 0;
+            for (int j=0; j<numRow; j++) {
+                double sum = elt[mix + srcDim];
+                for (int i=0; i<srcDim; i++) {
+                    final double e = elt[mix++];
+                    if (e != 0) { // See comment in transform(double[], ...)
+                        sum += srcPts[srcOff + i] * e;
+                    }
+                }
+                buffer[j] = sum;
+                mix++;
+            }
+            final double w = buffer[dstDim];
+            for (int j=0; j<dstDim; j++) {
+                dstPts[dstOff++] = (float) (buffer[j] / w);
+            }
+            srcOff += srcDim;
+        }
+    }
+
+    /**
+     * Transforms an array of floating point coordinates by this matrix.
+     *
+     * @param srcPts The array containing the source point coordinates.
+     * @param srcOff The offset to the first point to be transformed in the source array.
+     * @param dstPts The array into which the transformed point coordinates are returned.
+     * @param dstOff The offset to the location of the first transformed point that is stored
in the destination array.
+     * @param numPts The number of points to be transformed.
+     */
+    @Override
+    public void transform(float[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)
{
+        final int srcDim = numCol-1;
+        final int dstDim = numRow-1;
+        final double[] buffer = new double[numRow];
+        while (--numPts >= 0) {
+            int mix = 0;
+            for (int j=0; j<numRow; j++) {
+                double sum = elt[mix + srcDim];
+                for (int i=0; i<srcDim; i++) {
+                    final double e = elt[mix++];
+                    if (e != 0) { // See comment in transform(double[], ...)
+                        sum += srcPts[srcOff + i] * e;
+                    }
+                }
+                buffer[j] = sum;
+                mix++;
+            }
+            final double w = buffer[dstDim];
+            for (int j=0; j<dstDim; j++) {
+                dstPts[dstOff++] = buffer[j] / w;
+            }
+            srcOff += srcDim;
+        }
+    }
+
+    /**
+     * Gets the derivative of this transform at a point.
+     * For a matrix transform, the derivative is the same everywhere.
+     *
+     * @param point Ignored (can be {@code null}).
+     */
+    @Override
+    public Matrix derivative(final DirectPosition point) {
+        final MatrixSIS matrix = Matrices.create(numRow, numCol, elt);
+// TODO matrix.setSize(numRow-1, numCol-1);
+        return matrix;
+    }
+
+    /**
+     * Creates the inverse transform of this object.
+     */
+    @Override
+    public synchronized MathTransform inverse() throws NoninvertibleTransformException {
+        if (inverse == null) {
+            if (isIdentity()) {
+                inverse = this;
+            } else {
+                MatrixSIS matrix = Matrices.create(numRow, numCol, elt);
+                matrix = matrix.inverse();
+                ProjectiveTransform inv = createInverse(matrix);
+                inv.inverse = this;
+                inverse = inv;
+            }
+        }
+        return inverse;
+    }
+
+    /**
+     * Creates an inverse transform using the specified matrix.
+     * To be overridden by {@link GeocentricTranslation}.
+     */
+    ProjectiveTransform createInverse(final Matrix matrix) {
+        return new ProjectiveTransform(matrix);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    protected int computeHashCode() {
+        return Arrays.hashCode(elt) + 31 * super.computeHashCode();
     }
 
-    public static LinearTransform identity(final int dimension) {
-        throw new UnsupportedOperationException();
+    /**
+     * {@inheritDoc}
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    public boolean equals(final Object object, final ComparisonMode mode) {
+        if (object == this) { // Slight optimization
+            return true;
+        }
+        if (mode != ComparisonMode.STRICT) {
+            return equals(this, object, mode);
+        }
+        if (super.equals(object, mode)) {
+            final ProjectiveTransform that = (ProjectiveTransform) object;
+            return this.numRow == that.numRow &&
+                   this.numCol == that.numCol &&
+                   Arrays.equals(this.elt, that.elt);
+        }
+        return false;
     }
 }



Mime
View raw message