//
// ScaledUnit.java
//

/*
 VisAD system for interactive analysis and visualization of numerical
 data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
 Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
 Tommy Jasmin.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Library General Public
 License as published by the Free Software Foundation; either
 version 2 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Library General Public License for more details.

 You should have received a copy of the GNU Library General Public
 License along with this library; if not, write to the Free
 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 MA 02111-1307, USA
 */

package visad;

import java.io.Serializable;
import java.util.Arrays;

/**
 * A class that represents a certain amount of a derived unit.
 * 
 * Instances are immutable.
 * 
 * @author Steven R. Emmerson
 * 
 *         This is part of Steve Emerson's Unit package that has been
 *         incorporated into VisAD.
 */
public final class ScaledUnit extends Unit implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * The amount of the associated derived unit.
     */
    final double              amount;

    /**
     * The underlying unit that's scaled.
     */
    final Unit                underUnit;

    /**
     * Construct a dimensionless scaled unit. The identifier will be empty.
     * 
     * @param amount
     *            The given amount of this unit.
     */
    public ScaledUnit(final double amount) {
        this(amount, "");
    }

    /**
     * Construct a dimensionless scaled unit with an identifier.
     * 
     * @param amount
     *            The given amount of this unit.
     * @param identifier
     *            Name or abbreviation for the unit. May be null or
     *            empty.
     */
    public ScaledUnit(final double amount, final String identifier) {
        super(identifier);
        this.amount = amount;
        underUnit = new DerivedUnit();
    }

    /**
     * Constructs a scaled unit from another unit. The identifier will be that
     * of the other unit if the amount is 1; otherwise, the identifier will be
     * null.
     * 
     * @param amount
     *            The given amount of the other unit (e.g. 0.9144 to create a
     *            yard unit if unit represents a meter).
     * @param unit
     *            The other unit.
     */
    public ScaledUnit(final double amount, final Unit unit) {
        this(amount, unit, null);
    }

    /**
     * Constructs a scaled unit from another unit and an identifier.
     * 
     * @param amount
     *            The given amount of the base unit (e.g. 0.9144 to create a
     *            yard unit if unit represents a meter).
     * @param unit
     *            The other unit.
     * @param identifier
     *            Name or abbreviation for the unit. May be null or
     *            empty. If {@code null} and if {@code amount} is {@code 1},
     *            then the identifier of {@code unit} is used.
     */
    public ScaledUnit(final double amount, final Unit unit,
            final String identifier) {
        super(identifier != null
                ? identifier
                : amount == 1
                        ? unit.getIdentifier()
                        : null);
        if (unit instanceof ScaledUnit) {
            final ScaledUnit that = (ScaledUnit) unit;
            this.amount = amount * that.amount;
            this.underUnit = that.underUnit;
        }
        else {
            this.amount = amount;
            this.underUnit = unit;
        }
    }

    public ScaledUnit(final double amount, final BaseUnit unit) {
        this(amount, (Unit) unit);
    }

    public ScaledUnit(final double amount, final BaseUnit unit, final String id) {
        this(amount, (Unit) unit, id);
    }

    public ScaledUnit(final double amount, final DerivedUnit unit) {
        this(amount, (Unit) unit);
    }

    public ScaledUnit(final double amount, final DerivedUnit unit,
            final String id) {
        this(amount, (Unit) unit, id);
    }

    /**
     * Factory method for creating a scaled unit. The identifier will be that of
     * the input unit if the scaling amount is 1; otherwise, the identifier will
     * be null.
     * 
     * @param amount
     *            The given amount of the scaled unit (e.g. 3.0 to create a yard
     *            unit if unit represents a foot.
     * @param unit
     *            The given unit.
     * @return A corresponding scaled unit.
     * @throws UnitException
     *             Can't create Scaled Unit from unit.
     */
    public static ScaledUnit create(final double amount, final Unit unit)
            throws UnitException {
        return (amount == 1 && unit instanceof ScaledUnit)
                ? (ScaledUnit) unit
                : new ScaledUnit(amount, unit);
    }

    /**
     * Returns an instance based on a scale amount and an underlying unit.
     * 
     * @param amount
     *            The amount of {@code unit}
     * @param unit
     *            The underlying unit.
     * @return An instance corresponding to the input.
     * @throws UnitException
     *             If the instance can't be created.
     */
    static Unit getInstance(final double amount, final Unit unit)
            throws UnitException {
        if (amount == 0) {
            throw new IllegalArgumentException("Zero amount argument");
        }
        return (amount == 1)
                ? unit
                : new ScaledUnit(amount, unit);
    }

    /**
     * 

* Indicates if this instance is dimensionless. A unit is dimensionless if * it is a measure of a dimensionless quantity like angle or concentration. * Examples of dimensionless units include radian, degree, steradian, and * "g/kg". *

* * @return True if an only if this unit is dimensionless. */ @Override public boolean isDimensionless() { return underUnit.isDimensionless(); } /** * Clones this unit, changing the identifier. * * @param identifier * The name or abbreviation for the cloned unit. May be * null or empty. * @return A unit equal to this instance but with the given identifier. */ @Override protected Unit protectedClone(final String identifier) { return new ScaledUnit(amount, underUnit, identifier); } @Override public Unit scale(final double amount) throws UnitException { return ScaledUnit.getInstance(amount * this.amount, underUnit); } @Override public Unit shift(final double offset) throws UnitException { return OffsetUnit.getInstance(offset, this); } @Override public Unit log(final double base) { return LogarithmicUnit.getInstance(base, this); } /** * Raises this unit to a power. * * @param power * The power to raise this unit by. * @return The unit resulting from raising this unit to power. * @throws UnitException * if the underlying unit can't be raised to the given power. * promise: This unit has not been modified. */ @Override public Unit pow(final int power) throws UnitException { return new ScaledUnit(Math.pow(amount, power), underUnit.pow(power)); } /** * Raises this unit to a power. * * @param power * The power to raise this unit by. If this unit is not * dimensionless, then the value must be integral. * @return The unit resulting from raising this unit to power. * @throws IllegalArgumentException * This unit is not dimensionless and power has a * non-integral value. * @throws UnitException * if the underlying unit can't be raised to the given power. * promise: The unit has not been modified. */ @Override public Unit pow(final double power) throws IllegalArgumentException, UnitException { return new ScaledUnit(Math.pow(amount, power), underUnit.pow(power)); } /** * Returns the N-th root of this unit. * * @param root * The root to take (e.g. 2 means square root). May not be zero. * @return The unit corresponding to the root-th root of this * unit. * @throws IllegalArgumentException * The root value is zero or the resulting unit would have a * non-integral unit dimension. * @throws UnitException * if the underlying unit given can't have the given root taken. * promise: This unit has not been modified. */ @Override public Unit root(final int root) throws IllegalArgumentException, UnitException { return new ScaledUnit(Math.pow(amount, 1. / root), underUnit.root(root)); } /** * Returns the definition of this unit. * * @return The definition of this unit (e.g. "0.9144 m" for a yard). */ @Override public String getDefinition() { String definition; if (underUnit == null) { /* Probably exception thrown during construction */ definition = ""; } else { final String derivedString = underUnit.toString(); definition = amount == 1 ? derivedString : derivedString.length() == 0 ? Double.toString(amount) : Double.toString(amount) + " " + derivedString; } return definition; } /** * Get the scale amount * * @return The scale amount */ public double getAmount() { return amount; } /** * Get the underlying unit * * @return The underlying unit */ public Unit getUnit() { return underUnit; } /** * Multiplies this unit by another unit. * * @param that * The unit with which to multiply this unit. * @return The product of the two units. * promise: Neither unit has been modified. * @throws UnitException * Meaningless operation. */ @Override public Unit multiply(final Unit that) throws UnitException { return create(amount, underUnit.multiply(that)); } /** * Divides this unit by another unit. * * @param that * The unit to divide into this unit. * @return The quotient of the two units. * promise: Neither unit has been modified. * @throws UnitException * Meaningless operation. */ @Override public Unit divide(final Unit that) throws UnitException { return create(amount, underUnit.divide(that)); } /** * Divides this unit into another unit. * * @param that * The unit to be divided by this unit. * @return The quotient of the two units. * promise: Neither unit has been modified. * @throws UnitException * Meaningless operation. */ @Override protected Unit divideInto(final Unit that) throws UnitException { return create(1. / amount, underUnit.divideInto(that)); } /** * Convert values to this unit from another unit. * * @param values * The values to be converted. * @param that * The unit of values. * @return The converted values in units of this unit. * require: The units are convertible. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public double[] toThis(final double[] values, final Unit that) throws UnitException { return toThis(values, that, true); } /** * Convert values to this unit from another unit. * * @param values * The values to be converted. * @param that * The unit of values. * @return The converted values in units of this unit. * require: The units are convertible. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public float[] toThis(final float[] values, final Unit that) throws UnitException { return toThis(values, that, true); } /** * Convert values to this unit from another unit. * * @param values * The values to be converted. * @param that * The unit of values. * @param copy * if false and that equals this, return * values, else return a new array * @return The converted values in units of this unit. * require: The units are convertible. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public double[] toThis(final double[] values, final Unit that, final boolean copy) throws UnitException { double[] newValues; if (equals(that) || that instanceof PromiscuousUnit) { newValues = (copy) ? (double[]) values.clone() : values; } else { newValues = that.toThat(values, underUnit, copy); for (int i = 0; i < newValues.length; ++i) { if (newValues[i] == newValues[i]) { newValues[i] /= amount; } } } return newValues; } /** * Convert values to this unit from another unit. * * @param values * The values to be converted. * @param that * The unit of values. * @param copy * if false and that equals this, return * values, else return a new array * @return The converted values in units of this unit. * require: The units are convertible. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public float[] toThis(final float[] values, final Unit that, final boolean copy) throws UnitException { float[] newValues; if (equals(that) || that instanceof PromiscuousUnit) { newValues = (copy) ? (float[]) values.clone() : values; } else { newValues = that.toThat(values, underUnit, copy); for (int i = 0; i < newValues.length; ++i) { if (newValues[i] == newValues[i]) { newValues[i] /= amount; } } } return newValues; } /** * Convert values from this unit to another unit. * * @param values * The values to be converted in units of this unit. * @param that * The unit to which to convert the values. * @return The converted values. * require: The units are identical. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public double[] toThat(final double[] values, final Unit that) throws UnitException { return toThat(values, that, true); } /** * Convert values from this unit to another unit. * * @param values * The values to be converted in units of this unit. * @param that * The unit to which to convert the values. * @return The converted values. * require: The units are identical. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public float[] toThat(final float[] values, final Unit that) throws UnitException { return toThat(values, that, true); } /** * Convert values from this unit to another unit. * * @param values * The values to be converted in units of this unit. * @param that * The unit to which to convert the values. * @param copy * if false and that equals this, return * values, else return a new array * @return The converted values. * require: The units are convertible. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public double[] toThat(final double values[], final Unit that, final boolean copy) throws UnitException { double[] newValues = (copy) ? (double[]) values.clone() : values; if (!(equals(that) || that instanceof PromiscuousUnit)) { for (int i = 0; i < newValues.length; ++i) { newValues[i] *= amount; } newValues = that.toThis(newValues, underUnit); } return newValues; } /** * Convert values from this unit to another unit. * * @param values * The values to be converted in units of this unit. * @param that * The unit to which to convert the values. * @param copy * if false and that equals this, return * values, else return a new array * @return The converted values. * require: The units are convertible. * promise: Neither unit has been modified. * @throws UnitException * The units are not convertible. */ @Override public float[] toThat(final float values[], final Unit that, final boolean copy) throws UnitException { float[] newValues = (copy) ? (float[]) values.clone() : values; if (!(equals(that) || that instanceof PromiscuousUnit)) { for (int i = 0; i < newValues.length; ++i) { newValues[i] *= amount; } newValues = that.toThis(newValues, underUnit); } return newValues; } /** * Indicate whether this unit is convertible with another unit. If one unit * is convertible with another, then the toThis(...)/ and * toThat(...) methods will not throw a UnitException. Unit A * is convertible with unit B if and only if unit B is convertible with unit * A; hence, calling-order is irrelevant. * * @param unit * The other unit. * @return True if and only if this unit is convertible with the other unit. */ @Override public boolean isConvertible(final Unit unit) { return unit == null ? false : underUnit.isConvertible(unit); } private static void myAssert(final boolean assertion) { if (!assertion) { throw new AssertionError(); } } private static void myAssert(final Unit have, final Unit expect) { if (!have.equals(expect)) { throw new AssertionError(have.toString() + " != " + expect); } } private static void myAssert(final double have, final double expect) { if (have != expect) { throw new AssertionError("" + have + " != " + expect); } } private static void myAssert(final double[] have, final double[] expect) { if (!Arrays.equals(have, expect)) { throw new AssertionError("" + have + " != " + expect); } } /** * Test this class. * * @param args * Arguments (ignored). * @exception UnitException * A problem occurred. */ public static void main(final String[] args) throws UnitException { final BaseUnit meter = BaseUnit.addBaseUnit("Length", "meter"); final BaseUnit second = BaseUnit.addBaseUnit("Time", "second"); final DerivedUnit meterPerSec = new DerivedUnit(new BaseUnit[] { meter, second }, new int[] { 1, -1 }); final Unit milePerHour = new ScaledUnit(0.44704, meterPerSec); final Unit milePerHour2 = milePerHour.pow(2); myAssert(milePerHour, milePerHour); myAssert(!milePerHour.equals(meterPerSec)); myAssert(milePerHour.isConvertible(milePerHour)); myAssert(milePerHour.isConvertible(meterPerSec)); myAssert(!milePerHour.equals(milePerHour2)); myAssert(!milePerHour.isConvertible(milePerHour2)); myAssert(!milePerHour.equals(meter)); myAssert(!milePerHour.isConvertible(meter)); myAssert(milePerHour2, milePerHour2); myAssert(milePerHour2.isConvertible(milePerHour2)); myAssert(milePerHour2.sqrt(), milePerHour); final BaseUnit kg = BaseUnit.addBaseUnit("Mass", "kilogram"); final DerivedUnit kgPerSec = new DerivedUnit(new BaseUnit[] { kg, second }, new int[] { 1, -1 }); final Unit poundPerSec = new ScaledUnit(0.453592, kgPerSec); myAssert(milePerHour.multiply(poundPerSec), poundPerSec .multiply(milePerHour)); myAssert(milePerHour.divide(poundPerSec), poundPerSec.divide( milePerHour).pow(-1)); myAssert(milePerHour.toThis(1, meterPerSec) != 1); myAssert(milePerHour.toThat(1, meterPerSec) != 1); myAssert(milePerHour.toThis(1, meterPerSec), meterPerSec.toThat(1, milePerHour)); myAssert(meterPerSec.toThat(milePerHour.toThat(1, meterPerSec), milePerHour), 1); final double[] values = { 1, 2 }; myAssert(milePerHour.toThis(values, meterPerSec), meterPerSec.toThat( values, milePerHour)); myAssert(meterPerSec.toThat(milePerHour.toThat(values, meterPerSec), milePerHour), values); System.out.println("Checking exceptions:"); try { milePerHour.toThis(5, poundPerSec); throw new AssertionError(); } catch (final UnitException e) { System.out.println(e.getMessage()); } System.out.println("Done"); } /** * Indicates if this instance is equal to a unit. * * @param unit * The unit. * @return true if and only if this instance equals the unit. */ @Override public boolean equals(final Unit unit) { if (this == unit) { return true; } if (amount == 1) return underUnit.equals(unit); if (!(unit instanceof ScaledUnit)) { return false; } final ScaledUnit that = (ScaledUnit) unit; return amount == that.amount && underUnit.equals(that.underUnit); } /** * Returns the hash code of this instance. {@link Object#hashCode()} should * be overridden whenever {@link Object#equals(Object)} is. * * @return The hash code of this instance (includes the values). */ @Override public int hashCode() { if (hashCode == 0) { hashCode = amount == 1 ? underUnit.hashCode() : underUnit.hashCode() ^ Double.valueOf(amount).hashCode(); } return hashCode; } @Override public DerivedUnit getDerivedUnit() { return underUnit.getDerivedUnit(); } }

Ads help maintain this website.