Search in sources :

Example 11 with MathTransform1D

use of org.opengis.referencing.operation.MathTransform1D in project sis by apache.

the class DefaultVerticalExtent method intersect.

/**
 * Sets this vertical extent to the intersection of this extent with the specified one.
 * The {@linkplain org.apache.sis.referencing.crs.DefaultVerticalCRS#getDatum() vertical datum}
 * must be the same (ignoring metadata) for both extents; this method does not perform datum shift.
 * However this method can perform unit conversions.
 *
 * <p>If there is no intersection between the two extents, then this method sets both minimum and
 * maximum values to {@linkplain Double#NaN}. If either this extent or the specified extent has NaN
 * bounds, then the corresponding bounds of the intersection result will also be NaN.</p>
 *
 * @param  other  the vertical extent to intersect with this extent.
 * @throws IllegalArgumentException if the two extents do not use the same datum, ignoring metadata.
 *
 * @see Extents#intersection(VerticalExtent, VerticalExtent)
 * @see org.apache.sis.geometry.GeneralEnvelope#intersect(Envelope)
 *
 * @since 0.8
 */
public void intersect(final VerticalExtent other) throws IllegalArgumentException {
    checkWritePermission();
    ArgumentChecks.ensureNonNull("other", other);
    Double min = other.getMinimumValue();
    Double max = other.getMaximumValue();
    try {
        final MathTransform1D cv = getConversionFrom(other.getVerticalCRS());
        if (isReversing(cv, min, max)) {
            Double tmp = min;
            min = max;
            max = tmp;
        }
        /*
             * If minimumValue is NaN, keep it unchanged (because x > minimumValue is false)
             * in order to preserve the NilReason. Conversely if min is NaN, then we want to
             * take it without conversion for preserving its NilReason.
             */
        if (min != null) {
            if (minimumValue == null || min.isNaN() || (min = convert(cv, min)) > minimumValue) {
                minimumValue = min;
            }
        }
        if (max != null) {
            if (maximumValue == null || max.isNaN() || (max = convert(cv, max)) < maximumValue) {
                maximumValue = max;
            }
        }
    } catch (UnsupportedOperationException | FactoryException | ClassCastException | TransformException e) {
        throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatiblePropertyValue_1, "verticalCRS"), e);
    }
    if (minimumValue != null && maximumValue != null && minimumValue > maximumValue) {
        minimumValue = maximumValue = NilReason.MISSING.createNilObject(Double.class);
    }
}
Also used : FactoryException(org.opengis.util.FactoryException) TransformException(org.opengis.referencing.operation.TransformException) MathTransform1D(org.opengis.referencing.operation.MathTransform1D)

Example 12 with MathTransform1D

use of org.opengis.referencing.operation.MathTransform1D in project sis by apache.

the class ConcatenatedTransform method create.

/**
 * Concatenates the two given transforms.
 * If the concatenation result works with two-dimensional input and output points,
 * then the returned transform will implement {@link MathTransform2D}.
 * Likewise if the concatenation result works with one-dimensional input and output points,
 * then the returned transform will implement {@link MathTransform1D}.
 *
 * <div class="note"><b>Implementation note:</b>
 * {@code ConcatenatedTransform} implementations are available in two versions: direct and non-direct.
 * The "non-direct" versions use an intermediate buffer when performing transformations; they are slower
 * and consume more memory. They are used only as a fallback when a "direct" version can not be created.</div>
 *
 * @param  tr1      the first math transform.
 * @param  tr2      the second math transform.
 * @param  factory  the factory which is (indirectly) invoking this method, or {@code null} if none.
 * @return the concatenated transform.
 *
 * @see MathTransforms#concatenate(MathTransform, MathTransform)
 */
public static MathTransform create(MathTransform tr1, MathTransform tr2, final MathTransformFactory factory) throws FactoryException, MismatchedDimensionException {
    final int dim1 = tr1.getTargetDimensions();
    final int dim2 = tr2.getSourceDimensions();
    if (dim1 != dim2) {
        throw new MismatchedDimensionException(Resources.format(Resources.Keys.CanNotConcatenateTransforms_2, getName(tr1), getName(tr2)) + ' ' + Errors.format(Errors.Keys.MismatchedDimension_2, dim1, dim2));
    }
    MathTransform mt = createOptimized(tr1, tr2, factory);
    if (mt != null) {
        return mt;
    }
    /*
         * If at least one math transform is an instance of ConcatenatedTransform and assuming
         * that MathTransforms are associatives, tries the following arrangements and select
         * the one with the fewest amount of steps:
         *
         *   Assuming :  tr1 = (A * B)
         *               tr2 = (C * D)
         *
         *   Current  :  (A * B) * (C * D)     Will be the selected one if nothing better.
         *   Try k=0  :  A * (B * (C * D))     Implies A * ((B * C) * D) through recursivity.
         *   Try k=1  :  ((A * B) * C) * D     Implies (A * (B * C)) * D through recursivity.
         *   Try k=2  :                        Tried only if try k=1 changed something.
         *
         * TODO: The same combination may be computed more than once (e.g. (B * C) above).
         *       Should not be a big deal if there is not two many steps. In the even where
         *       it would appears a performance issue, we could maintain a Map of combinations
         *       already computed. The map would be local to a "create" method execution.
         */
    int stepCount = getStepCount(tr1) + getStepCount(tr2);
    // Really 'true' because we want at least 2 iterations.
    boolean tryAgain = true;
    for (int k = 0; ; k++) {
        MathTransform c1 = tr1;
        MathTransform c2 = tr2;
        final boolean first = (k & 1) == 0;
        MathTransform candidate = first ? c1 : c2;
        while (candidate instanceof ConcatenatedTransform) {
            final ConcatenatedTransform ctr = (ConcatenatedTransform) candidate;
            if (first) {
                c1 = candidate = ctr.transform1;
                c2 = create(ctr.transform2, c2, factory);
            } else {
                c1 = create(c1, ctr.transform1, factory);
                c2 = candidate = ctr.transform2;
            }
            final int c = getStepCount(c1) + getStepCount(c2);
            if (c < stepCount) {
                tr1 = c1;
                tr2 = c2;
                stepCount = c;
                tryAgain = true;
            }
        }
        if (!tryAgain)
            break;
        tryAgain = false;
    }
    /*
         * Tries again the check for optimized cases (identity, etc.), because a
         * transform may have been simplified to identity as a result of the above.
         */
    mt = createOptimized(tr1, tr2, factory);
    if (mt != null) {
        return mt;
    }
    /*
         * Can not avoid the creation of a ConcatenatedTransform object.
         * Check for the type to create (1D, 2D, general case...)
         */
    final int dimSource = tr1.getSourceDimensions();
    final int dimTarget = tr2.getTargetDimensions();
    if (dimSource == 1 && dimTarget == 1) {
        /*
             * Result needs to be a MathTransform1D.
             */
        if (tr1 instanceof MathTransform1D && tr2 instanceof MathTransform1D) {
            return new ConcatenatedTransformDirect1D((MathTransform1D) tr1, (MathTransform1D) tr2);
        } else {
            return new ConcatenatedTransform1D(tr1, tr2);
        }
    } else if (dimSource == 2 && dimTarget == 2) {
        /*
             * Result needs to be a MathTransform2D.
             */
        if (tr1 instanceof MathTransform2D && tr2 instanceof MathTransform2D) {
            return new ConcatenatedTransformDirect2D((MathTransform2D) tr1, (MathTransform2D) tr2);
        } else {
            return new ConcatenatedTransform2D(tr1, tr2);
        }
    } else if (// dim1 = tr1.getTargetDimensions() and
    dimSource == tr1.getTargetDimensions() && // dim2 = tr2.getSourceDimensions() may not be true anymore.
    dimTarget == tr2.getSourceDimensions()) {
        return new ConcatenatedTransformDirect(tr1, tr2);
    } else {
        return new ConcatenatedTransform(tr1, tr2);
    }
}
Also used : MathTransform(org.opengis.referencing.operation.MathTransform) MathTransform1D(org.opengis.referencing.operation.MathTransform1D) MathTransform2D(org.opengis.referencing.operation.MathTransform2D) MismatchedDimensionException(org.opengis.geometry.MismatchedDimensionException)

Example 13 with MathTransform1D

use of org.opengis.referencing.operation.MathTransform1D in project sis by apache.

the class LinearInterpolator1D method create.

/**
 * Creates a <i>y=f(x)</i> transform for the given preimage (<var>x</var>) and values (<var>y</var>).
 * See {@link MathTransforms#interpolate(double[], double[])} javadoc for more information.
 */
static MathTransform1D create(final double[] preimage, final double[] values) {
    final int length;
    if (preimage == null) {
        if (values == null) {
            return IdentityTransform1D.INSTANCE;
        }
        length = values.length;
    } else {
        length = preimage.length;
        if (values != null && values.length != length) {
            throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedArrayLengths));
        }
    }
    switch(length) {
        case 0:
            throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, (preimage != null) ? "preimage" : "values"));
        case 1:
            return LinearTransform1D.constant((preimage != null) ? preimage[0] : Double.NaN, (values != null) ? values[0] : Double.NaN);
    }
    /*
         * A common usage of this 'create' method is for creating a "gridToCRS" transform from grid coordinates
         * to something else, in which case the preimage array is null. In the less frequent case where preimage
         * is non-null, we first convert from preimage to indices, then from indices to y values.
         */
    MathTransform1D tr = null;
    if (values != null) {
        tr = create(values.clone());
    }
    if (preimage != null) {
        final MathTransform1D indexToValues = tr;
        try {
            // preimageToIndex transform.
            tr = create(preimage.clone()).inverse();
        } catch (NoninvertibleTransformException e) {
            throw new IllegalArgumentException(Resources.format(Resources.Keys.NonMonotonicSequence_1, "preimage"), e);
        }
        if (indexToValues != null) {
            tr = MathTransforms.concatenate(tr, indexToValues);
        }
    }
    return tr;
}
Also used : NoninvertibleTransformException(org.opengis.referencing.operation.NoninvertibleTransformException) MathTransform1D(org.opengis.referencing.operation.MathTransform1D)

Aggregations

MathTransform1D (org.opengis.referencing.operation.MathTransform1D)13 Test (org.junit.Test)5 DependsOnMethod (org.apache.sis.test.DependsOnMethod)3 MathTransform2D (org.opengis.referencing.operation.MathTransform2D)2 NoninvertibleTransformException (org.opengis.referencing.operation.NoninvertibleTransformException)2 Random (java.util.Random)1 Matrix2 (org.apache.sis.referencing.operation.matrix.Matrix2)1 After (org.junit.After)1 MismatchedDimensionException (org.opengis.geometry.MismatchedDimensionException)1 MathTransform (org.opengis.referencing.operation.MathTransform)1 Matrix (org.opengis.referencing.operation.Matrix)1 TransformException (org.opengis.referencing.operation.TransformException)1 FactoryException (org.opengis.util.FactoryException)1