Return-Path: X-Original-To: apmail-sis-commits-archive@www.apache.org Delivered-To: apmail-sis-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6952311007 for ; Wed, 4 Jun 2014 23:35:03 +0000 (UTC) Received: (qmail 63244 invoked by uid 500); 4 Jun 2014 23:35:03 -0000 Delivered-To: apmail-sis-commits-archive@sis.apache.org Received: (qmail 63212 invoked by uid 500); 4 Jun 2014 23:35:03 -0000 Mailing-List: contact commits-help@sis.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: sis-dev@sis.apache.org Delivered-To: mailing list commits@sis.apache.org Received: (qmail 63205 invoked by uid 99); 4 Jun 2014 23:35:03 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 04 Jun 2014 23:35:03 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 04 Jun 2014 23:34:59 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id D047B23889BB; Wed, 4 Jun 2014 23:34:39 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 -0000 To: commits@sis.apache.org From: desruisseaux@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140604233439.D047B23889BB@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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. + * + *

Special cases:

+ *
    + *
  • If {@code dimension} == 1, then the returned transform implements {@link MathTransform1D}.
  • + *
  • If {@code dimension} == 2, then the returned transform implements {@link MathTransform2D}.
  • + *
+ * + * @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 x will be converted into output values y using the following equation: + * + *
y  =  x × {@code scale} + {@code offset}
+ * + * @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 j'th ordinate of the moved origin. + * + *

The matrix is usually square and affine, but this is not mandatory. + * Non-affine transforms are allowed.

+ * + * @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. + * + *

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 Java Advanced Imaging): + * + * + *
+ * {@preformat text + * x' = u/t + * y' = v/t + * y' = w/t + * } + *
where {@code (u,v,w)} are obtained by:
+ * {@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 │ + * └ ┘ └ ┘ └ ┘ + * } + *
+ * + * 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 Affine transformation on MathWorld + */ +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{@link Matrix#getNumCol}-1. 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 + * [x0, y0, z0, + * x1, y1, z1..., + * xn, yn, zn]. + * + * @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{@link Matrix#getNumCol()} - 1. 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 + * [x0, y0, z0, + * x1, y1, z1..., + * xn, yn, zn]. + * + * @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= 0) { + int mix = 0; + for (int j=0; j= 0) { + int mix = 0; + for (int j=0; j