Java Code Examples for javax.measure.UnitConverter#isLinear()

The following examples show how to use javax.measure.UnitConverter#isLinear() . 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: Units.java    From sis with Apache License 2.0 6 votes vote down vote up
/**
 * Returns the coefficients of the given converter expressed as a polynomial equation.
 * This method returns the first of the following choices that apply:
 *
 * <ul>
 *   <li>If the given converter {@linkplain UnitConverter#isIdentity() is identity}, returns an empty array.</li>
 *   <li>If the given converter shifts the values without scaling them (for example the conversion from Kelvin to
 *       Celsius degrees), returns an array of length 1 containing only the offset.</li>
 *   <li>If the given converter scales the values (optionally in addition to shifting them), returns an array of
 *       length 2 containing the offset and scale factor, in that order.</li>
 * </ul>
 *
 * This method returns {@code null} if it can not get the polynomial equation coefficients from the given converter.
 *
 * @param  converter  the converter from which to get the coefficients of the polynomial equation, or {@code null}.
 * @return the polynomial equation coefficients (may be any length, including zero), or {@code null} if the given
 *         converter is {@code null} or if this method can not get the coefficients.
 *
 * @since 0.8
 */
@SuppressWarnings("fallthrough")
public static Number[] coefficients(final UnitConverter converter) {
    if (converter != null) {
        if (converter instanceof AbstractConverter) {
            return ((AbstractConverter) converter).coefficients();
        }
        if (converter.isIdentity()) {
            return new Number[0];
        }
        if (converter.isLinear()) {
            final double offset = converter.convert(0);  // Should be zero as per JSR-363 specification, but we are paranoiac.
            final double scale  = converter.convert(1) - offset;
            final Number[] c = new Number[(scale != 1) ? 2 : (offset != 0) ? 1 : 0];
            switch (c.length) {
                case 2: c[1] = scale;       // Fall through
                case 1: c[0] = offset;
                case 0: break;
            }
            return c;
        }
    }
    return null;
}
 
Example 2
Source File: SystemUnit.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Implementation of {@link #multiply(Unit)} and {@link #divide(Unit)} methods.
 *
 * @param  inverse  wether to use the inverse of {@code other}.
 */
private <T extends Quantity<T>> Unit<?> product(final Unit<T> other, final boolean inverse) {
    final Unit<T> intermediate = other.getSystemUnit();
    final Dimension dim = intermediate.getDimension();
    final UnitDimension newDimension;
    final char operation;
    if (inverse) {
        operation = DIVIDE;
        newDimension = dimension.divide(dim);
    } else {
        operation = MULTIPLY;
        newDimension = dimension.multiply(dim);
    }
    final boolean transformed = (intermediate != other);
    Unit<?> result = create(newDimension, operation, transformed ? null : other);
    if (transformed) {
        UnitConverter c = other.getConverterTo(intermediate);
        if (!c.isLinear()) {
            throw new IllegalArgumentException(Errors.format(Errors.Keys.NonRatioUnit_1, other));
        }
        if (!c.isIdentity()) {
            if (inverse) c = c.inverse();
            result = result.transform(c);
            /*
             * If the system unit product is an Apache SIS implementation, try to infer a unit symbol
             * to be given to our customized 'transform' method. Otherwise fallback on standard API.
             */
            result = inferSymbol(result, operation, other);
        }
    }
    return result;
}
 
Example 3
Source File: AbstractConverter.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Delegates to {@link #derivative(double)} if the given converter is an Apache SIS implementation,
 * or use a fallback otherwise.
 */
static double derivative(final UnitConverter converter, final double value) {
    if (converter != null) {
        if (converter instanceof AbstractConverter) {
            return ((AbstractConverter) converter).derivative(value);
        } else if (converter.isLinear()) {
            return converter.convert(1) - converter.convert(0);
        }
    }
    return Double.NaN;
}
 
Example 4
Source File: AbstractConverter.java    From sis with Apache License 2.0 5 votes vote down vote up
/**
 * Returns the scale factor of the given converter if the conversion is linear, or NaN otherwise.
 */
static double scale(final UnitConverter converter) {
    if (converter != null && converter.isLinear() && converter.convert(0) == 0) {
        // Above check for converter(0) is a paranoiac check since
        // JSR-363 said that a "linear" converter has no offset.
        return converter.convert(1);
    }
    return Double.NaN;
}
 
Example 5
Source File: LinearConverter.java    From sis with Apache License 2.0 4 votes vote down vote up
/**
 * Concatenates this converter with another converter. The resulting converter is equivalent to first converting
 * by the specified converter (right converter), and then converting by this converter (left converter).  In the
 * following equations, the 1 subscript is for the specified converter and the 2 subscript is for this converter:
 *
 * {@preformat math
 *    t = (x⋅scale₁ + offset₁) ∕ divisor₁
 *    y = (t⋅scale₂ + offset₂) ∕ divisor₂
 * }
 *
 * We rewrite as:
 *
 * {@preformat math
 *    y = (x⋅scale₁⋅scale₂ + offset₁⋅scale₂ + divisor₁⋅offset₂) ∕ (divisor₁⋅divisor₂)
 * }
 */
@Override
public UnitConverter concatenate(final UnitConverter converter) {
    ArgumentChecks.ensureNonNull("converter", converter);
    if (converter.isIdentity()) {
        return this;
    }
    if (isIdentity()) {
        return converter;
    }
    double otherScale, otherOffset, otherDivisor;
    if (converter instanceof LinearConverter) {
        final LinearConverter lc = (LinearConverter) converter;
        otherScale   = lc.scale;
        otherOffset  = lc.offset;
        otherDivisor = lc.divisor;
    } else if (converter.isLinear()) {
        /*
         * Fallback for foreigner implementations. Note that 'otherOffset' should be restricted to zero
         * according JSR-363 definition of 'isLinear()', but let be safe; maybe we are not the only one
         * to have a different interpretation about the meaning of "linear".
         */
        otherOffset  = converter.convert(0.0);
        otherScale   = converter.convert(1.0) - otherOffset;
        otherDivisor = 1;
    } else {
        return new ConcatenatedConverter(converter, this);
    }
    otherScale   *= scale;
    otherOffset   = otherOffset * scale + otherDivisor * offset;
    otherDivisor *= divisor;
    /*
     * Following loop is a little bit similar to simplifying a fraction, but checking only for the
     * powers of 10 since unit conversions are often such values. Algorithm is not very efficient,
     * but the loop should not be executed often.
     */
    if (otherScale != 0 || otherOffset != 0 || otherDivisor != 0) {
        double cf, f = 1;
        do {
            cf = f;
            f *= 10;
        } while (otherScale % f == 0 && otherOffset % f == 0 && otherDivisor % f == 0);
        otherScale   /= cf;
        otherOffset  /= cf;
        otherDivisor /= cf;
    }
    if (otherOffset == 0 && otherScale == otherDivisor) {
        return IdentityConverter.INSTANCE;
    }
    return new LinearConverter(otherScale, otherOffset, otherDivisor);
}
 
Example 6
Source File: Units.java    From sis with Apache License 2.0 3 votes vote down vote up
/**
 * Invoked by {@code Units} static class initializer for registering SI conventional units.
 * This method shall be invoked in a single thread by the {@code Units} class initializer only.
 *
 * <p>The {@code target} argument should be an instance of {@link SystemUnit}.
 * The only exception is for creating the {@link #DECIBEL} unit base on the bel conventional unit.</p>
 *
 * <p>If the {@code target} unit holds a list of {@linkplain SystemUnit#related() related units}
 * (i.e. conventional units that can not be computed easily by appending a SI prefix), then the new
 * conventional unit is added to that list of related units. For example "foot" is related to "metre"
 * and "degree Celsius" is related to "Kelvin", but "kilometre" is not recorded as related to "metre"
 * because this relationship can be inferred automatically without the need of a {@code related} table.
 * The unrecorded units are all SI units related to {@code target} by a scale factor without offset.</p>
 */
private static <Q extends Quantity<Q>> ConventionalUnit<Q> add(AbstractUnit<Q> target, UnitConverter toTarget, String symbol, byte scope, short epsg) {
    final ConventionalUnit<Q> unit = UnitRegistry.init(new ConventionalUnit<>(target, toTarget, symbol, scope, epsg));
    final ConventionalUnit<Q>[] related = target.related();
    if (related != null && (unit.scope != UnitRegistry.SI || !toTarget.isLinear())) {
        // Search first empty slot. This algorithm is inefficient, but the length of those arrays is small (<= 7).
        int i = 0;
        while (related[i] != null) i++;
        related[i] = unit;
    }
    return unit;
}