Search in sources :

Example 31 with DoubleDouble

use of org.apache.sis.internal.util.DoubleDouble in project sis by apache.

the class Initializer method radiusOfConformalSphere.

/**
 * Returns the radius of the conformal sphere (assuming a semi-major axis length of 1) at a given latitude.
 * The radius of conformal sphere is computed from ρ, which is the radius of curvature in the meridian at
 * latitude φ, and ν which is the radius of curvature in the prime vertical, as below:
 *
 * <blockquote>Rc = √(ρ⋅ν) = √(1 – ℯ²) / (1 – ℯ²sin²φ)</blockquote>
 *
 * This is a function of latitude and therefore not constant. When used for spherical projections
 * the use of φ₀ (or φ₁ as relevant to method) for φ is suggested, except if the projection is
 * equal area when the radius of authalic sphere should be used.
 *
 * @param  sinφ  the sine of the φ latitude.
 * @return radius of the conformal sphere at latitude φ.
 */
final double radiusOfConformalSphere(final double sinφ) {
    final DoubleDouble Rc = verbatim(1);
    // 1 - ℯ²
    Rc.subtract(eccentricitySquared);
    // √(1 - ℯ²)
    Rc.sqrt();
    // √(1 - ℯ²) / (1 - ℯ²sin²φ)
    Rc.divide(rν2(sinφ));
    return Rc.value;
}
Also used : DoubleDouble(org.apache.sis.internal.util.DoubleDouble)

Example 32 with DoubleDouble

use of org.apache.sis.internal.util.DoubleDouble in project sis by apache.

the class Initializer method scaleAtφ.

/**
 * Returns the scale factor at latitude φ. This is computed as:
 *
 * <blockquote>cosφ / sqrt(rν2(sinφ))</blockquote>
 *
 * The result is returned as a {@code double} because the limited precision of {@code sinφ} and {@code cosφ}
 * makes the error term meaningless. We use double-double arithmetic only for intermediate calculation.
 *
 * @param  sinφ  the sine of the φ latitude.
 * @param  cosφ  the cosine of the φ latitude.
 * @return scale factor at latitude φ.
 */
final double scaleAtφ(final double sinφ, final double cosφ) {
    final DoubleDouble s = rν2(sinφ);
    s.sqrt();
    s.inverseDivide(cosφ, 0);
    return s.value;
}
Also used : DoubleDouble(org.apache.sis.internal.util.DoubleDouble)

Example 33 with DoubleDouble

use of org.apache.sis.internal.util.DoubleDouble in project sis by apache.

the class Matrices method createPassThrough.

/**
 * Creates a matrix which converts a subset of ordinates using the transform given by another matrix.
 * For example giving (<var>latitude</var>, <var>longitude</var>, <var>height</var>) coordinates,
 * a pass through operation can convert the height values from feet to metres without affecting
 * the (<var>latitude</var>, <var>longitude</var>) values.
 *
 * <p>The given sub-matrix shall have the following properties:</p>
 * <ul>
 *   <li>The last row often (but not necessarily) contains 0 values everywhere except in the last column.</li>
 *   <li>Values in the last column are translation terms, except in the last row.</li>
 *   <li>All other values are scale or shear terms.</li>
 * </ul>
 *
 * A square matrix complying with the above conditions is often {@linkplain #isAffine(Matrix) affine},
 * but this is not mandatory
 * (for example a <cite>perspective transform</cite> may contain non-zero values in the last row).
 *
 * <p>This method builds a new matrix with the following content:</p>
 * <ul>
 *   <li>An amount of {@code firstAffectedOrdinate} rows and columns are inserted before the first
 *       row and columns of the sub-matrix. The elements for the new rows and columns are set to 1
 *       on the diagonal, and 0 elsewhere.</li>
 *   <li>The sub-matrix - except for its last row and column - is copied in the new matrix starting
 *       at index ({@code firstAffectedOrdinate}, {@code firstAffectedOrdinate}).</li>
 *   <li>An amount of {@code numTrailingOrdinates} rows and columns are appended after the above sub-matrix.
 *       Their elements are set to 1 on the pseudo-diagonal ending in the lower-right corner, and 0 elsewhere.</li>
 *   <li>The last sub-matrix row is copied in the last row of the new matrix, and the last sub-matrix column
 *       is copied in the last column of the sub-matrix.</li>
 * </ul>
 *
 * <div class="note"><b>Example:</b>
 * given the following sub-matrix which converts height values from feet to metres before to subtracts 25 metres:
 *
 * {@preformat math
 *   ┌    ┐   ┌             ┐   ┌   ┐
 *   │ z' │ = │ 0.3048  -25 │ × │ z │
 *   │ 1  │   │ 0         1 │   │ 1 │
 *   └    ┘   └             ┘   └   ┘
 * }
 *
 * Then a call to {@code Matrices.createPassThrough(2, subMatrix, 1)} will return the following matrix,
 * which can be used for converting the height (<var>z</var>) without affecting the other ordinate values
 * (<var>x</var>,<var>y</var>,<var>t</var>):
 *
 * {@preformat math
 *   ┌    ┐   ┌                      ┐   ┌   ┐
 *   │ x  │   │ 1  0  0       0    0 │   │ x │
 *   │ y  │   │ 0  1  0       0    0 │   │ y │
 *   │ z' │ = │ 0  0  0.3048  0  -25 │ × │ z │
 *   │ t  │   │ 0  0  0       1    0 │   │ t │
 *   │ 1  │   │ 0  0  0       0    1 │   │ 1 │
 *   └    ┘   └                      ┘   └   ┘
 * }
 * </div>
 *
 * @param  firstAffectedOrdinate  the lowest index of the affected ordinates.
 * @param  subMatrix              the matrix to use for affected ordinates.
 * @param  numTrailingOrdinates   number of trailing ordinates to pass through.
 * @return a matrix for the same transform than the given matrix,
 *         augmented with leading and trailing pass-through coordinates.
 *
 * @see org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#createPassThroughTransform(int, MathTransform, int)
 */
public static MatrixSIS createPassThrough(final int firstAffectedOrdinate, final Matrix subMatrix, final int numTrailingOrdinates) {
    ArgumentChecks.ensureNonNull("subMatrix", subMatrix);
    ArgumentChecks.ensurePositive("firstAffectedOrdinate", firstAffectedOrdinate);
    ArgumentChecks.ensurePositive("numTrailingOrdinates", numTrailingOrdinates);
    final int expansion = firstAffectedOrdinate + numTrailingOrdinates;
    // Will become the number of dimensions later.
    int sourceDimensions = subMatrix.getNumCol();
    int targetDimensions = subMatrix.getNumRow();
    /*
         * Get data from the source matrix, together with the error terms if present.
         * The 'stride' and 'length' values will be used for computing indices in that array.
         * The DoubleDouble temporary object is used only if the array contains error terms.
         */
    final int stride = sourceDimensions;
    final int length = sourceDimensions * targetDimensions;
    final double[] sources = getExtendedElements(subMatrix);
    final DoubleDouble transfer = (sources.length > length) ? new DoubleDouble() : null;
    final MatrixSIS matrix = createZero(targetDimensions-- + expansion, sourceDimensions-- + expansion, transfer != null);
    /*
         * Following code processes from upper row to lower row.
         * First, set the diagonal elements on leading new dimensions.
         */
    for (int j = 0; j < firstAffectedOrdinate; j++) {
        matrix.setElement(j, j, 1);
    }
    /*
         * Copy the sub-matrix, with special case for the translation terms
         * which are unconditionally stored in the last column.
         */
    final int lastColumn = sourceDimensions + expansion;
    matrix.setElements(sources, length, stride, transfer, // Source (row, colum)
    0, // Source (row, colum)
    0, // Target (row, column)
    firstAffectedOrdinate, // Target (row, column)
    firstAffectedOrdinate, targetDimensions, // Number of rows and columns to copy.
    sourceDimensions);
    matrix.setElements(sources, length, stride, transfer, // Source (row, colum):  last column
    0, // Source (row, colum):  last column
    sourceDimensions, // Target (row, column): part of last column
    firstAffectedOrdinate, // Target (row, column): part of last column
    lastColumn, targetDimensions, // Copy some rows of only 1 column.
    1);
    /*
         * Set the pseudo-diagonal elements on the trailing new dimensions.
         * 'diff' is zero for a square matrix and non-zero for rectangular matrix.
         */
    final int diff = targetDimensions - sourceDimensions;
    for (int i = lastColumn - numTrailingOrdinates; i < lastColumn; i++) {
        matrix.setElement(diff + i, i, 1);
    }
    /*
         * Copy the last row from the sub-matrix. In the usual affine transform,
         * this row contains only 0 element except for the last one, which is 1.
         */
    final int lastRow = targetDimensions + expansion;
    matrix.setElements(sources, length, stride, transfer, // Source (row, colum):  last row
    targetDimensions, // Source (row, colum):  last row
    0, // Target (row, column): part of last row
    lastRow, // Target (row, column): part of last row
    firstAffectedOrdinate, 1, // Copy some columns of only 1 row.
    sourceDimensions);
    matrix.setElements(sources, length, stride, transfer, targetDimensions, sourceDimensions, lastRow, lastColumn, 1, 1);
    return matrix;
}
Also used : DoubleDouble(org.apache.sis.internal.util.DoubleDouble)

Example 34 with DoubleDouble

use of org.apache.sis.internal.util.DoubleDouble in project sis by apache.

the class Matrices method resizeAffine.

/**
 * 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);
    }
    // Shear and scale terms.
    resized.setElements(sources, length, stride, transfer, 0, 0, 0, 0, copyRow, copyCol);
    // Translation column.
    resized.setElements(sources, length, stride, transfer, 0, srcCol, 0, numCol, copyRow, 1);
    // Last row.
    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);
    return resized;
}
Also used : DoubleDouble(org.apache.sis.internal.util.DoubleDouble)

Example 35 with DoubleDouble

use of org.apache.sis.internal.util.DoubleDouble in project sis by apache.

the class MatrixSIS method removeColumns.

/**
 * Returns a new matrix with the same elements than this matrix except for the specified columns.
 * This method is useful for removing a range of <em>source</em> dimensions in an affine transform.
 * Coordinates will be converted as if the values in the removed dimensions were zeros.
 *
 * @param  lower  index of the first column to remove (inclusive).
 * @param  upper  index after the last column to remove (exclusive).
 * @return a copy of this matrix with the specified columns removed.
 *
 * @since 0.7
 */
public MatrixSIS removeColumns(final int lower, final int upper) {
    final int numRow = getNumRow();
    final int numCol = getNumCol();
    ArgumentChecks.ensureValidIndexRange(numCol, lower, upper);
    final DoubleDouble dd = isExtendedPrecision() ? new DoubleDouble() : null;
    final MatrixSIS reduced = Matrices.createZero(numRow, numCol - (upper - lower), dd != null);
    int dest = 0;
    for (int i = 0; i < numCol; i++) {
        if (i == lower) {
            i = upper;
            if (i == numCol)
                break;
        }
        for (int j = 0; j < numRow; j++) {
            if (dd != null) {
                get(j, i, dd);
                reduced.set(j, dest, dd);
            } else {
                reduced.setElement(j, dest, getElement(j, i));
            }
        }
        dest++;
    }
    return reduced;
}
Also used : DoubleDouble(org.apache.sis.internal.util.DoubleDouble)

Aggregations

DoubleDouble (org.apache.sis.internal.util.DoubleDouble)39 MatrixSIS (org.apache.sis.referencing.operation.matrix.MatrixSIS)5 Test (org.junit.Test)3 ExtendedPrecisionMatrix (org.apache.sis.internal.referencing.ExtendedPrecisionMatrix)2 DirectPosition (org.opengis.geometry.DirectPosition)2 AxisDirection (org.opengis.referencing.cs.AxisDirection)2 AffineTransform (java.awt.geom.AffineTransform)1 BigDecimal (java.math.BigDecimal)1 IncommensurableException (javax.measure.IncommensurableException)1 ParameterizedAffine (org.apache.sis.internal.referencing.j2d.ParameterizedAffine)1 Parameters (org.apache.sis.parameter.Parameters)1 Matrix4 (org.apache.sis.referencing.operation.matrix.Matrix4)1 ContextualParameters (org.apache.sis.referencing.operation.transform.ContextualParameters)1 DependsOnMethod (org.apache.sis.test.DependsOnMethod)1 MismatchedDimensionException (org.opengis.geometry.MismatchedDimensionException)1 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)1 MathTransform (org.opengis.referencing.operation.MathTransform)1