Java Code Examples for org.opengis.referencing.operation.Matrix#getNumCol()

The following examples show how to use org.opengis.referencing.operation.Matrix#getNumCol() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: NormalizedProjection.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * If a sequence of 3 transforms are (inverse projection) → (affine) → (projection) where
 * the (projection) and (inverse projection) steps are the inverse of each other, returns
 * the matrix of the affine transform step. Otherwise returns {@code null}. This method
 * accepts also (projection) → (affine) → (inverse projection) sequence, but such sequences
 * should be much more unusual.
 *
 * @param  projection       either {@link NormalizedProjection} or {@link Inverse}.
 * @param  other            the arbitrary transforms to be concatenated with the given projection.
 * @param  applyOtherFirst  whether {@code other} is concatenated before {@code projection} or the converse.
 * @return the 3×3 matrix of the affine transform step, or {@code null} if none.
 */
private static Matrix getMiddleMatrix(final AbstractMathTransform projection, final MathTransform other,
        final boolean applyOtherFirst)
{
    final List<MathTransform> steps = MathTransforms.getSteps(other);
    if (steps.size() == 2) try {
        final int oi = applyOtherFirst ? 0 : 1;
        if (projection.equals(steps.get(oi).inverse(), ComparisonMode.IGNORE_METADATA)) {
            final Matrix m = MathTransforms.getMatrix(steps.get(oi ^ 1));
            if (Matrices.isAffine(m) && m.getNumRow() == DIMENSION+1 && m.getNumCol() == DIMENSION+1) {
                return m;
            }
        }
    } catch (NoninvertibleTransformException e) {
        Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
                (projection instanceof NormalizedProjection) ? NormalizedProjection.class : projection.getClass(),
                "tryConcatenate", e);
    }
    return null;
}
 
Example 2
Source File: Matrices.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * 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;
}
 
Example 3
Source File: Matrices.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Creates a new matrix which is a copy of the given matrix.
 *
 * <div class="note"><b>Implementation note:</b>
 * For square matrix with a size between {@value org.apache.sis.referencing.operation.matrix.Matrix1#SIZE}
 * and {@value org.apache.sis.referencing.operation.matrix.Matrix4#SIZE} inclusive, the returned matrix is
 * usually an instance of one of {@link Matrix1} … {@link Matrix4} subtypes.</div>
 *
 * @param  matrix  the matrix to copy, or {@code null}.
 * @return a copy of the given matrix, or {@code null} if the given matrix was null.
 *
 * @see MatrixSIS#clone()
 * @see MatrixSIS#castOrCopy(Matrix)
 */
public static MatrixSIS copy(final Matrix matrix) {
    if (matrix == null) {
        return null;
    }
    final int size = matrix.getNumRow();
    if (size != matrix.getNumCol()) {
        return new NonSquareMatrix(matrix);
    }
    if (!isExtendedPrecision(matrix)) {
        switch (size) {
            case 1: return new Matrix1(matrix);
            case 2: return new Matrix2(matrix);
            case 3: return new Matrix3(matrix);
            case 4: return new Matrix4(matrix);
        }
    }
    return new GeneralMatrix(matrix);
}
 
Example 4
Source File: Solver.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Solves {@code X} × <var>U</var> = {@code Y}.
 * This method is an adaptation of the {@code LUDecomposition} class of the JAMA matrix package.
 *
 * @param  X  the matrix to invert.
 * @param  Y  the desired result of {@code X} × <var>U</var>.
 * @throws NoninvertibleMatrixException if the {@code X} matrix is not square or singular.
 */
static MatrixSIS solve(final Matrix X, final Matrix Y) throws NoninvertibleMatrixException {
    final int size   = X.getNumRow();
    final int numCol = X.getNumCol();
    if (numCol != size) {
        throw new NoninvertibleMatrixException(Resources.format(Resources.Keys.NonInvertibleMatrix_2, size, numCol));
    }
    final int innerSize = Y.getNumCol();
    GeneralMatrix.ensureNumRowMatch(size, Y.getNumRow(), innerSize);
    double[] eltY = null;
    if (Y instanceof GeneralMatrix) {
        eltY = ((GeneralMatrix) Y).elements;
        if (eltY.length == size * innerSize) {
            eltY = null;                            // Matrix does not contains error terms.
        }
    }
    return solve(X, Y, eltY, size, innerSize, true);
}
 
Example 5
Source File: MatrixSIS.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Fallback for matrix of unknown implementation.
 */
static boolean isAffine(final Matrix matrix) {
    int j = matrix.getNumRow();
    int i = matrix.getNumCol();
    if (i != j--) {
        return false; // Matrix is not square.
    }
    double e = 1;
    while (--i >= 0) {
        if (matrix.getElement(j, i) != e) {
            return false;
        }
        e = 0;
    }
    return true;
}
 
Example 6
Source File: ProjectiveTransformTest.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Creates a new test suite.
 */
public ProjectiveTransformTest() {
    this(new MathTransformFactoryBase() {
        @Override
        public MathTransform createAffineTransform(final Matrix matrix) {
            final ProjectiveTransform pt;
            if (matrix.getNumRow() == 3 && matrix.getNumCol() == 3) {
                pt = new ProjectiveTransform2D(matrix);
            } else {
                pt = new ProjectiveTransform(matrix);
            }
            MathTransform tr = pt.optimize();
            if (tr != pt) {
                /*
                 * Opportunistically tests ScaledTransform together with ProjectiveTransform.
                 * We takes ScaledTransform as a reference implementation since it is simpler.
                 */
                tr = new TransformResultComparator(tr, pt, 0);
            }
            return tr;
        }
    });
}
 
Example 7
Source File: DatumShiftTransform.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Computes the conversion factors needed for calls to {@link DatumShiftGrid#interpolateInCell(double, double, double[])}.
 * This method takes only the {@value DatumShiftGrid#INTERPOLATED_DIMENSIONS} first dimensions. If a conversion factor can
 * not be computed, then it is set to NaN.
 */
@SuppressWarnings("fallthrough")
private void computeConversionFactors() {
    scaleX = Double.NaN;
    scaleY = Double.NaN;
    x0     = Double.NaN;
    y0     = Double.NaN;
    if (grid != null) {
        final LinearTransform coordinateToGrid = grid.getCoordinateToGrid();
        final double toStandardUnit = Units.toStandardUnit(grid.getCoordinateUnit());
        if (!Double.isNaN(toStandardUnit)) {
            final Matrix m = coordinateToGrid.getMatrix();
            if (Matrices.isAffine(m)) {
                final int n = m.getNumCol() - 1;
                switch (m.getNumRow()) {
                    default: y0 = m.getElement(1,n); scaleY = diagonal(m, 1, n) / toStandardUnit;   // Fall through
                    case 1:  x0 = m.getElement(0,n); scaleX = diagonal(m, 0, n) / toStandardUnit;
                    case 0:  break;
                }
            }
        }
    }
}
 
Example 8
Source File: ReferencingAssert.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Asserts that the given matrix is diagonal, and that all elements on the diagonal are equal
 * to the given values. The matrix doesn't need to be square. The last row is handled especially
 * if the {@code affine} argument is {@code true}.
 *
 * @param expected   the values which are expected on the diagonal. If the length of this array
 *                   is less than the matrix size, then the last element in the array is repeated
 *                   for all remaining diagonal elements.
 * @param affine     if {@code true}, then the last row is expected to contains the value 1
 *                   in the last column, and all other columns set to 0.
 * @param matrix     the matrix to test.
 * @param tolerance  the tolerance threshold while comparing floating point values.
 */
public static void assertDiagonalEquals(final double[] expected, final boolean affine,
        final Matrix matrix, final double tolerance)
{
    final int numRows = matrix.getNumRow();
    final int numCols = matrix.getNumCol();
    final StringBuilder buffer = new StringBuilder("matrix(");
    final int bufferBase = buffer.length();
    for (int j=0; j<numRows; j++) {
        for (int i=0; i<numCols; i++) {
            final double e;
            if (affine && j == numRows-1) {
                e = (i == numCols-1) ? 1 : 0;
            } else if (i == j) {
                e = expected[min(expected.length-1, i)];
            } else {
                e = 0;
            }
            buffer.setLength(bufferBase);
            assertEquals(buffer.append(j).append(',').append(i).append(')').toString(),
                    e, matrix.getElement(j, i), tolerance);
        }
    }
}
 
Example 9
Source File: TransferFunction.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Sets the {@link #scale} and {@link #offset} terms from the given function.
 *
 * @param  function  the transform to set.
 * @throws IllegalArgumentException if this method does not recognize the given transform.
 */
private void setLinearTerms(final LinearTransform function) throws IllegalArgumentException {
    final Matrix m = function.getMatrix();
    final int numRow = m.getNumRow();
    final int numCol = m.getNumCol();
    if (numRow != 2 || numCol != 2) {
        final Integer two = 2;
        throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedMatrixSize_4, two, two, numRow, numCol));
    }
    scale  = m.getElement(0, 0);
    offset = m.getElement(0, 1);
}
 
Example 10
Source File: MathTransforms.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Creates an arbitrary linear transform from the specified matrix. Usually the matrix
 * {@linkplain org.apache.sis.referencing.operation.matrix.MatrixSIS#isAffine() is affine},
 * but this is not mandatory. Non-affine matrix will define a projective transform.
 *
 * <p>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 coordinate of the moved origin.</p>
 *
 * @param  matrix  the matrix used to define the linear transform.
 * @return the linear (usually affine) transform.
 *
 * @see #getMatrix(MathTransform)
 * @see DefaultMathTransformFactory#createAffineTransform(Matrix)
 */
public static LinearTransform linear(final Matrix matrix) {
    ArgumentChecks.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));
                }
                case 2: {
                    if (matrix instanceof ExtendedPrecisionMatrix) {
                        return new AffineTransform2D(((ExtendedPrecisionMatrix) matrix).getExtendedElements());
                    } else {
                        return new AffineTransform2D(
                                matrix.getElement(0,0), matrix.getElement(1,0),
                                matrix.getElement(0,1), matrix.getElement(1,1),
                                matrix.getElement(0,2), matrix.getElement(1,2));
                    }
                }
            }
        } else if (sourceDimension == 2) {
            return new ProjectiveTransform2D(matrix);
        }
    }
    final LinearTransform candidate = CopyTransform.create(matrix);
    if (candidate != null) {
        return candidate;
    }
    return new ProjectiveTransform(matrix).optimize();
}
 
Example 11
Source File: DefaultTransformationTest.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Asserts that at least some of the properties of the given {@code op} instance have the expected values
 * for an instance created by {@link #createGeocentricTranslation()}.
 */
@SuppressWarnings("SuspiciousToArrayCall")
private static void verifyProperties(final DefaultTransformation op) {
    assertEquals("name",       "Tokyo to JGD2000 (GSI)",  op.getName().getCode());
    assertEquals("sourceCRS",  "Tokyo 1918",              op.getSourceCRS().getName().getCode());
    assertEquals("targetCRS",  "JGD2000",                 op.getTargetCRS().getName().getCode());
    assertEquals("method",     "Geocentric translations", op.getMethod().getName().getCode());
    assertEquals("parameters", "Geocentric translations", op.getParameterDescriptors().getName().getCode());

    final ParameterValueGroup parameters = op.getParameterValues();
    final ParameterValue<?>[] values = parameters.values().toArray(new ParameterValue<?>[3]);
    assertEquals("parameters",    "Geocentric translations", parameters.getDescriptor().getName().getCode());
    assertEquals("parameters[0]", "X-axis translation",      values[0] .getDescriptor().getName().getCode());
    assertEquals("parameters[1]", "Y-axis translation",      values[1] .getDescriptor().getName().getCode());
    assertEquals("parameters[2]", "Z-axis translation",      values[2] .getDescriptor().getName().getCode());
    assertEquals("parameters[0]", -146.414, values[0].doubleValue(), STRICT);
    assertEquals("parameters[1]",  507.337, values[1].doubleValue(), STRICT);
    assertEquals("parameters[2]",  680.507, values[2].doubleValue(), STRICT);
    assertEquals(3, values.length);

    final Matrix m = MathTransforms.getMatrix(op.getMathTransform());
    assertNotNull("transform", m);
    for (int j=m.getNumRow(); --j >= 0;) {
        for (int i=m.getNumCol(); --i >= 0;) {
            double expected = (i == j) ? 1 : 0;
            if (i == 2) switch (j) {
                case 0: expected = -146.414; break;
                case 1: expected =  507.337; break;
                case 2: expected =  680.507; break;
            }
            assertEquals(expected, m.getElement(j,i), STRICT);
        }
    }
}
 
Example 12
Source File: MatrixSIS.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Ensures that the given matrix has the given dimension.
 * This is a convenience method for subclasses.
 */
static void ensureSizeMatch(final int numRow, final int numCol, final Matrix matrix)
        throws MismatchedMatrixSizeException
{
    final int othRow = matrix.getNumRow();
    final int othCol = matrix.getNumCol();
    if (numRow != othRow || numCol != othCol) {
        throw new MismatchedMatrixSizeException(Errors.format(
                Errors.Keys.MismatchedMatrixSize_4, numRow, numCol, othRow, othCol));
    }
}
 
Example 13
Source File: Solver.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Computes the inverse of the given matrix. This method shall be invoked only for square matrices.
 *
 * @param  X         the matrix to invert, which must be square.
 * @param  noChange  if {@code true}, do not allow modifications to the {@code X} matrix.
 * @throws NoninvertibleMatrixException if the {@code X} matrix is not square or singular.
 */
static MatrixSIS inverse(final Matrix X, final boolean noChange) throws NoninvertibleMatrixException {
    final int size = X.getNumRow();
    final int numCol = X.getNumCol();
    if (numCol != size) {
        throw new NoninvertibleMatrixException(Resources.format(Resources.Keys.NonInvertibleMatrix_2, size, numCol));
    }
    return solve(X, IDENTITY, null, size, size, noChange);
}
 
Example 14
Source File: CopyTransform.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * If a transform can be created from the given matrix, returns it.
 * Otherwise returns {@code null}.
 */
static CopyTransform create(final Matrix matrix) {
    final int srcDim = matrix.getNumCol() - 1;
    final int dstDim = matrix.getNumRow() - 1;
    for (int i=0; i <= srcDim; i++) {
        if (matrix.getElement(dstDim, i) != (i == srcDim ? 1 : 0)) {
            // Not an affine transform (ignoring if square or not).
            return null;
        }
    }
    final int[] indices = new int[dstDim];
    for (int j=0; j<dstDim; j++) {
        if (matrix.getElement(j, srcDim) != 0) {
            // The matrix has translation terms.
            return null;
        }
        boolean found = false;
        for (int i=0; i<srcDim; i++) {
            final double elt = matrix.getElement(j, i);
            if (elt != 0) {
                if (elt != 1 || found) {
                    // Not a simple copy operation.
                    return null;
                }
                indices[j] = i;
                found = true;
            }
        }
        if (!found) {
            // Target coordinate unconditionally set to 0 (not a copy).
            return null;
        }
    }
    return new CopyTransform(srcDim, indices);
}
 
Example 15
Source File: Matrices.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Returns the inverse of the given matrix.
 *
 * @param  matrix  the matrix to inverse, or {@code null}.
 * @return the inverse of this matrix, or {@code null} if the given matrix was null.
 * @throws NoninvertibleMatrixException if the given matrix is not invertible.
 *
 * @see MatrixSIS#inverse()
 *
 * @since 0.6
 */
public static MatrixSIS inverse(final Matrix matrix) throws NoninvertibleMatrixException {
    if (matrix == null) {
        return null;
    } else if (matrix instanceof MatrixSIS) {
        return ((MatrixSIS) matrix).inverse();  // Maybe the subclass override that method.
    } else if (matrix.getNumRow() != matrix.getNumCol()) {
        return new NonSquareMatrix(matrix).inverse();
    } else {
        return Solver.inverse(matrix, true);
    }
}
 
Example 16
Source File: TensorValues.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Sets all parameter values to the element value in the specified matrix.
 * After this method call, {@link #values} will returns only the elements
 * different from the default value.
 *
 * @param  matrix  the matrix to copy in this group of parameters.
 */
final void setMatrix(final Matrix matrix) {
    final int numRow = matrix.getNumRow();
    final int numCol = matrix.getNumCol();
    dimensions[0].setValue(numRow);
    dimensions[1].setValue(numCol);
    values = null;
    final int[] indices = new int[2];
    for (int j=0; j<numRow; j++) {
        indices[0] = j;
        ParameterValue<?>[] row = null;
        for (int i=0; i<numCol; i++) {
            indices[1] = i;
            ParameterDescriptor<E> descriptor = descriptors.getElementDescriptor(indices);
            final E def = descriptor.getDefaultValue();
            final double element = matrix.getElement(j,i);
            if (!(def instanceof Number) || !Numerics.equalsIgnoreZeroSign(element, ((Number) def).doubleValue())) {
                final ParameterValue<?> value = descriptor.createValue();
                value.setValue(element);
                if (row == null) {
                    row = new ParameterValue<?>[numCol];
                    if (values == null) {
                        values = new ParameterValue<?>[numRow][];
                    }
                    values[j] = row;
                }
                row[i] = value;
            }
        }
    }
}
 
Example 17
Source File: Matrices.java    From sis with Apache License 2.0 4 votes vote down vote up
/**
 * Returns a matrix with the same content than the given matrix but a different size, assuming an affine transform.
 * This method can be invoked for adding or removing the <strong>last</strong> dimensions of an affine transform.
 * More specifically:
 *
 * <ul class="verbose">
 *   <li>If the given {@code numCol} is <var>n</var> less than the number of columns in the given matrix,
 *       then the <var>n</var> columns <em>before the last column</em> are removed.
 *       The last column is left unchanged because it is assumed to contain the translation terms.</li>
 *   <li>If the given {@code numCol} is <var>n</var> more than the number of columns in the given matrix,
 *       then <var>n</var> columns are inserted <em>before the last column</em>.
 *       All values in the new columns will be zero.</li>
 *   <li>If the given {@code numRow} is <var>n</var> less than the number of rows in the given matrix,
 *       then the <var>n</var> rows <em>before the last row</em> are removed.
 *       The last row is left unchanged because it is assumed to contain the usual [0 0 0 … 1] terms.</li>
 *   <li>If the given {@code numRow} is <var>n</var> more than the number of rows in the given matrix,
 *       then <var>n</var> rows are inserted <em>before the last row</em>.
 *       The corresponding offset and scale factors will be 0 and 1 respectively.
 *       In other words, new dimensions are propagated unchanged.</li>
 * </ul>
 *
 * @param  matrix  the matrix to resize. This matrix will never be changed.
 * @param  numRow  the new number of rows. This is equal to the desired number of target dimensions plus 1.
 * @param  numCol  the new number of columns. This is equal to the desired number of source dimensions plus 1.
 * @return a new matrix of the given size, or the given {@code matrix} if no resizing was needed.
 */
public static Matrix resizeAffine(final Matrix matrix, int numRow, int numCol) {
    ArgumentChecks.ensureNonNull         ("matrix", matrix);
    ArgumentChecks.ensureStrictlyPositive("numRow", numRow);
    ArgumentChecks.ensureStrictlyPositive("numCol", numCol);
    int srcRow = matrix.getNumRow();
    int srcCol = matrix.getNumCol();
    if (numRow == srcRow && numCol == srcCol) {
        return matrix;
    }
    final int      stride  = srcCol;
    final int      length  = srcCol * srcRow;
    final double[] sources = getExtendedElements(matrix);
    final DoubleDouble transfer = (sources.length > length) ? new DoubleDouble() : null;
    final MatrixSIS resized = createZero(numRow, numCol, transfer != null);
    final int copyRow = Math.min(--numRow, --srcRow);
    final int copyCol = Math.min(--numCol, --srcCol);
    for (int j=copyRow; j<numRow; j++) {
        resized.setElement(j, j, 1);
    }
    resized.setElements(sources, length, stride, transfer, 0,      0,       0,      0,       copyRow, copyCol);    // Shear and scale terms.
    resized.setElements(sources, length, stride, transfer, 0,      srcCol,  0,      numCol,  copyRow, 1);          // Translation column.
    resized.setElements(sources, length, stride, transfer, srcRow, 0,       numRow, 0,       1,       copyCol);    // Last row.
    resized.setElements(sources, length, stride, transfer, srcRow, srcCol,  numRow, numCol,  1,       1);          // Last row.
    return resized;
}
 
Example 18
Source File: BursaWolfParameters.java    From sis with Apache License 2.0 4 votes vote down vote up
/**
 * Sets all Bursa-Wolf parameters from the given <cite>Position Vector transformation</cite> matrix.
 * The matrix shall comply to the following constraints:
 *
 * <ul>
 *   <li>The matrix shall be {@linkplain org.apache.sis.referencing.operation.matrix.MatrixSIS#isAffine() affine}.</li>
 *   <li>The sub-matrix defined by {@code matrix} without the last row and last column shall be
 *       <a href="http://en.wikipedia.org/wiki/Skew-symmetric_matrix">skew-symmetric</a> (a.k.a. antisymmetric).</li>
 * </ul>
 *
 * @param  matrix     the matrix from which to get Bursa-Wolf parameters.
 * @param  tolerance  the tolerance error for the skew-symmetric matrix test, in units of PPM or arc-seconds (e.g. 1E-8).
 * @throws IllegalArgumentException if the specified matrix does not met the conditions.
 *
 * @see #getPositionVectorTransformation(Date)
 */
public void setPositionVectorTransformation(final Matrix matrix, final double tolerance) throws IllegalArgumentException {
    final int numRow = matrix.getNumRow();
    final int numCol = matrix.getNumCol();
    if (numRow != SIZE || numCol != SIZE) {
        final Integer n = SIZE;
        throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedMatrixSize_4, n, n, numRow, numCol));
    }
    if (!Matrices.isAffine(matrix)) {
        throw new IllegalArgumentException(Resources.format(Resources.Keys.NotAnAffineTransform));
    }
    /*
     * Translation terms, taken "as-is".
     * If the matrix contains only translation terms (which is often the case), we are done.
     */
    tX = matrix.getElement(0,3);
    tY = matrix.getElement(1,3);
    tZ = matrix.getElement(2,3);
    if (Matrices.isTranslation(matrix)) {                   // Optimization for a common case.
        return;
    }
    /*
     * Scale factor: take the average of elements on the diagonal. All those
     * elements should have the same value, but we tolerate slight deviation
     * (this will be verified later).
     */
    final DoubleDouble S = DoubleDouble.castOrCopy(getNumber(matrix, 0,0));
    S.addGuessError(getNumber(matrix, 1,1));
    S.addGuessError(getNumber(matrix, 2,2));
    S.divide(3);
    /*
     * Computes: RS = S * toRadians(1″)
     *           dS = (S-1) * PPM
     */
    final DoubleDouble RS = DoubleDouble.createSecondsToRadians();
    RS.multiply(S);
    S.add(-1);
    S.multiply(PPM);
    dS = S.doubleValue();
    /*
     * Rotation terms. Each rotation terms appear twice, with one value being the negative of the other value.
     * We verify this skew symmetric aspect in the loop. We also opportunistically verify that the scale terms
     * are uniform.
     */
    for (int j=0; j < SIZE-1; j++) {
        if (!(abs((matrix.getElement(j,j) - 1)*PPM - dS) <= tolerance)) {
            throw new IllegalArgumentException(Resources.format(Resources.Keys.NonUniformScale));
        }
        for (int i = j+1; i < SIZE-1; i++) {
            S.setFrom(RS);
            S.inverseDivideGuessError(getNumber(matrix, j,i));          // Negative rotation term.
            double value = S.value;
            double error = S.error;
            S.setFrom(RS);
            S.inverseDivideGuessError(getNumber(matrix, i,j));          // Positive rotation term.
            if (!(abs(value + S.value) <= tolerance)) {                 // We expect r1 ≈ -r2
                throw new IllegalArgumentException(Resources.format(Resources.Keys.NotASkewSymmetricMatrix));
            }
            S.subtract(value, error);
            S.multiply(0.5);
            value = S.doubleValue();                                    // Average of the two rotation terms.
            switch (j*SIZE + i) {
                case 1: rZ =  value; break;
                case 2: rY = -value; break;
                case 6: rX =  value; break;
            }
        }
    }
}
 
Example 19
Source File: MatrixSIS.java    From sis with Apache License 2.0 3 votes vote down vote up
/**
 * Returns a new matrix which is the result of multiplying this matrix with the specified one.
 * In other words, returns {@code this} × {@code matrix}.
 *
 * <h4>Relationship with coordinate operations</h4>
 * In the context of coordinate operations, {@code Matrix.multiply(other)} is equivalent to
 * <code>{@linkplain AffineTransform#concatenate AffineTransform.concatenate}(other)</code>:
 * first transforms by the supplied transform and then transform the result by the original transform.
 *
 * @param  matrix  the matrix to multiply to this matrix.
 * @return the result of {@code this} × {@code matrix}.
 * @throws MismatchedMatrixSizeException if the number of rows in the given matrix is not equals to the
 *         number of columns in this matrix.
 */
public MatrixSIS multiply(final Matrix matrix) throws MismatchedMatrixSizeException {
    final int nc = matrix.getNumCol();
    ensureNumRowMatch(getNumCol(), matrix.getNumRow(), nc);
    final GeneralMatrix result = GeneralMatrix.createExtendedPrecision(getNumRow(), nc, false);
    result.setToProduct(this, matrix);
    return result;
}
 
Example 20
Source File: Matrices.java    From sis with Apache License 2.0 3 votes vote down vote up
/**
 * Returns a new matrix which is the result of multiplying the first matrix with the second one.
 * In other words, returns {@code m1} × {@code m2}.
 *
 * @param  m1  the first matrix to multiply.
 * @param  m2  the second matrix to multiply.
 * @return the result of {@code m1} × {@code m2}.
 * @throws MismatchedMatrixSizeException if the number of columns in {@code m1} is not equals to the
 *         number of rows in {@code m2}.
 *
 * @see MatrixSIS#multiply(Matrix)
 *
 * @since 0.6
 */
public static MatrixSIS multiply(final Matrix m1, final Matrix m2) throws MismatchedMatrixSizeException {
    if (m1 instanceof MatrixSIS) {
        return ((MatrixSIS) m1).multiply(m2);           // Maybe the subclass overrides that method.
    }
    final int nc = m2.getNumCol();
    MatrixSIS.ensureNumRowMatch(m1.getNumCol(), m2.getNumRow(), nc);
    final GeneralMatrix result = GeneralMatrix.createExtendedPrecision(m1.getNumRow(), nc, false);
    result.setToProduct(m1, m2);
    return result;
}