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;
}
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;
}
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;
}
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;
}
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;
}
Aggregations