// // DerivedUnit.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.text.ChoiceFormat; import java.util.Arrays; import java.util.Vector; /** * A class that represents a unit consisting of zero or more base units. * * Instances are immutable. * * @author Steven R. Emmerson * * This is part of Steve Emmerson's Unit package that has been * incorporated into VisAD. */ public final class DerivedUnit extends Unit implements Serializable { private static final long serialVersionUID = 1L; /** * The array of individual base-unit factors that make up this unit. * * The following is effectively "final" in that it is only set in * constructors and never altered. Unfortunately, the JDK 1.1.2 javac(1) * compiler on our SunOS 5.5 systems doesn't recognize this fact; hence, the * "final" is commented-out. */ /* final */Factor[] factors; /** * Construct a dimensionless derived unit. The identifier of the unit will * be empty. */ public DerivedUnit() { this(new BaseUnit[] {}, new int[] {}, ""); } /** * Construct a dimensionless derived unit with an identifier. * * @param identifier * Name or abbreviation for the unit. May be <code>null</code> or * empty. */ public DerivedUnit(final String identifier) { this(new BaseUnit[] {}, new int[] {}, identifier); } /** * Construct a derived unit from a base unit. The identifier of the unit * will be that of the base unit. * * @param baseUnit * The base unit. */ public DerivedUnit(final BaseUnit baseUnit) { this(new BaseUnit[] { baseUnit }, new int[] { 1 }, baseUnit .getIdentifier()); } /** * Construct a derived unit from an array base units and powers. The * identifier of the unit with be that of the base unit if there's only one * base unit; otherwise, the identifier will be <code>null</code>. * * @param baseUnits * The array of base units (e.g. {m, s}). * @param powers * The array of powers (e.g. {1, -1} to create a m/s unit). */ public DerivedUnit(final BaseUnit[] baseUnits, final int[] powers) { this(newFactors(baseUnits, powers), baseUnits.length == 1 ? baseUnits[0].getIdentifier() : null); } /** * Construct a derived unit from an array base units, powers, and an * identifier. * * @param baseUnits * The array of base units (e.g. {m, s}). * @param powers * The array of powers (e.g. {1, -1} to create a m/s unit). * @param identifier * Name or abbreviation for the unit. May be <code>null</code> or * empty. */ public DerivedUnit(final BaseUnit[] baseUnits, final int[] powers, final String identifier) { this(newFactors(baseUnits, powers), identifier); } /** * Creates an array of Factor-s from arrays of base units and powers. * * @param baseUnits * The array of base units (e.g. {m, s}). * @param powers * The array of powers (e.g. {1, -1} to create a m/s unit). * @return An array of {@link Factor}s equivalent to the given base units * and powers. */ protected static Factor[] newFactors(final BaseUnit[] baseUnits, final int[] powers) { final Factor[] factors = new Factor[baseUnits.length]; for (int i = 0; i < baseUnits.length; ++i) { factors[i] = new Factor(baseUnits[i], powers[i]); } return factors; } /** * Construct a derived unit from a derived unit and an identifier. * * @param that * The derived unit. * @param identifier * Name or abbreviation for the unit. May be <code>null</code> or * empty. */ public DerivedUnit(final DerivedUnit that, final String identifier) { this(that.factors, identifier); } /** * Constructs from an array of factors. The identifier of the unit will be * <code>null</code>. * * @param facts * The factors for the DerivedUnit. Every factor with a power of * zero will be ignored. */ private DerivedUnit(final Factor[] facts) { this(facts, null); } /** * Constructs from an array of factors and an identifier. * * @param facts * The factors for the DerivedUnit. Every factor with a power of * zero will be ignored. * @param identifier * Name or abbreviation for the unit. May be <code>null</code> or * empty. */ private DerivedUnit(final Factor[] facts, final String identifier) { super(identifier); int n = 0; for (int i = 0; i < facts.length; ++i) { final Factor fact = facts[i]; if (fact != null && fact.power != 0) { n++; } } factors = new Factor[n]; n = 0; for (int i = 0; i < facts.length; ++i) { final Factor fact = facts[i]; if (fact != null && fact.power != 0) { factors[n++] = fact; } } } /** * <p> * 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". * </p> * * @return True if an only if this unit is dimensionless. */ @Override public boolean isDimensionless() { for (int i = 0; i < factors.length; i++) { if (factors[i].power != 0 && !factors[i].baseUnit.isDimensionless()) { return false; } } return true; } /** * Clones this unit, changing the identifier. * * @param identifier * The name or abbreviation for the cloned unit. May be * <code>null</code> or empty. * @return A unit equal to this unit but with the given identifier. */ @Override protected Unit protectedClone(final String identifier) { return new DerivedUnit(this, identifier); } /** * Scale this unit by an amount. * * @param amount * The amount by which to scale this unit. E.g. Unit yard = * meter.scale(0.9144); * @return A unit equal this this unit scaled by the given amount. * @exception UnitException * This unit cannot be scaled. */ @Override public Unit scale(final double amount) throws UnitException { return ScaledUnit.getInstance(amount, this); } /** * Shift this unit by an amount. * * @param offset * The amount by which to shift this unit. E.g. Unit celsius = * kelvin.shift(273.15); * @return A unit equal to this unit with the origin shifted to the given * point. * @exception UnitException * The unit subclass is unknown. */ @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); } /** * Raise a derived unit to a power. * * @param power * The power to raise this unit by. * @return The unit resulting from raising this unit to <code>power</code>. * @promise The unit has not been modified. */ @Override public Unit pow(final int power) { DerivedUnit result; if (power == 1) { result = this; } else { final Factor[] newFactors = new Factor[factors.length]; for (int i = 0; i < factors.length; ++i) { final Factor factor = factors[i]; newFactors[i] = new Factor(factor.baseUnit, factor.power * power); } result = new DerivedUnit(newFactors); } return result; } /** * 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 <code>root</code>-th root of this * unit. * @promise The unit has not been modified. * @throws IllegalArgumentException * <code>root</code> is zero or the result would have a * non-integral unit dimension. */ @Override public Unit root(final int root) throws IllegalArgumentException { if (root == 0) { throw new IllegalArgumentException(getClass().getName() + ".root(int): zero root"); } DerivedUnit result; if (root == 1) { result = this; } else { final Factor[] newFactors = new Factor[factors.length]; for (int i = 0; i < factors.length; ++i) { final Factor factor = factors[i]; if (factor.power % root != 0) { throw new IllegalArgumentException(getClass().getName() + ".root(int): " + "Non-integral resulting dimension"); } newFactors[i] = new Factor(factor.baseUnit, factor.power / root); } result = new DerivedUnit(newFactors); } return result; } /** * Raise a derived unit to a power. * * @param power * The power to raise this unit by. If this unit is not * dimensionless, then the value must be an integer or the * reciprocal of an integer. * @return The unit resulting from raising this unit to <code>power</code>. * @throws IllegalArgumentException * This unit is not dimensionless and <code>power * </code> * is neither an integer nor the reciprocal of an integer. * @promise The unit has not been modified. */ @Override public Unit pow(final double power) throws IllegalArgumentException { Unit result; if (factors.length == 0) { result = this; } else { if (Math.abs(power) > 1) { final double intVal = Math.rint(power); if (power < ChoiceFormat.previousDouble(intVal) || power > ChoiceFormat.nextDouble(intVal)) { throw new IllegalArgumentException(this.getClass() .getName() + ".pow(double): " + "Non-integral power"); } result = pow((int) intVal); } else { final double root = 1. / power; final double intVal = Math.rint(root); if (root < ChoiceFormat.previousDouble(intVal) || root > ChoiceFormat.nextDouble(intVal)) { throw new IllegalArgumentException(this.getClass() .getName() + ".pow(double): " + "Non-integral reciprocal power"); } result = root((int) intVal); } } return result; } /** * Return the definition of this unit. * * @return The definition of this unit (e.g. "m.s-1"). */ @Override public String getDefinition() { String definition; if (factors == null) { /* Probably exception thrown during construction */ definition = "<unconstructed DerivedUnit>"; } else { final StringBuffer buf = new StringBuffer(80); for (int i = 0; i < factors.length; ++i) { if (factors[i].power == 1) { buf.append(factors[i].baseUnit.toString() + "."); } else if (factors[i].power != 0) { buf.append(factors[i].baseUnit.toString() + factors[i].power + "."); } } if (buf.length() > 0) { buf.setLength(buf.length() - 1); } definition = buf.toString(); } return definition; } 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 = SI.meter; final BaseUnit second = SI.second; final DerivedUnit speed = new DerivedUnit(new BaseUnit[] { meter, second }, new int[] { 1, -1 }); final Unit speed2 = speed.pow(2); myAssert(!speed.equals(meter)); myAssert(!speed.equals(second)); myAssert(!speed.isConvertible(meter)); myAssert(!speed.isConvertible(second)); myAssert(speed, meter.divide(second)); myAssert(!speed.equals(speed2)); myAssert(!speed.isConvertible(speed2)); myAssert(speed, speed2.sqrt()); myAssert(speed, speed2.root(2)); myAssert(speed.pow(2.0 + Math.ulp(2.0)), speed2); myAssert(speed2.pow(1 / (2.0 + Math.ulp(2.0))), speed); myAssert(meter.divide(speed), second); myAssert(speed.divide(meter), second.pow(-1)); myAssert(speed.toThis(5, speed), 5); myAssert(speed.toThat(5, speed), 5); final double[] values = { 1, 2 }; myAssert(speed.toThis(values, speed), values); myAssert(speed.toThat(values, speed), values); final DerivedUnit joule = (DerivedUnit) speed.pow(2).multiply( SI.kilogram); myAssert(joule.equals(joule)); myAssert(joule.isConvertible(joule)); myAssert(!joule.equals(meter)); myAssert(!joule.isConvertible(meter)); System.out.println("Checking exceptions:"); try { speed.toThis(5, joule); throw new AssertionError(); } catch (final UnitException e) { System.out.println(e.getMessage()); } try { System.out.println("speed.pow(2+2*ULP)=\"" + speed.pow(ChoiceFormat.nextDouble(ChoiceFormat .nextDouble(2.0))) + "\""); throw new AssertionError(); } catch (final IllegalArgumentException e) { System.out.println(e.getMessage()); } try { System.out.println("speed2.pow(1/(2+2*ULP))=\"" + speed2.pow(1 / ChoiceFormat.nextDouble(ChoiceFormat .nextDouble(2.0))) + "\""); throw new AssertionError(); } catch (final IllegalArgumentException e) { System.out.println(e.getMessage()); } System.out.println("Done"); } /* * PROMISE: None of the returned factors will have a power of zero and input * dimensionless factors will be ignored and not appear in the output. */ private Vector[] common(final DerivedUnit that) { final Vector[] vector = new Vector[3]; final int max = factors.length + that.factors.length; vector[0] = new Vector(max); vector[1] = new Vector(max); vector[2] = new Vector(max); for (int i = 0; i < factors.length; ++i) { if (factors[i].power != 0 && !factors[i].baseUnit.isDimensionless()) { int j; for (j = 0; j < that.factors.length; ++j) { if (that.factors[j].power != 0 && factors[i].baseUnit .equals(that.factors[j].baseUnit)) { vector[2].addElement(new Factor[] { factors[i], that.factors[j] }); break; } } if (j == that.factors.length) { vector[0].addElement(factors[i]); } } } for (int j = 0; j < that.factors.length; ++j) { if (that.factors[j].power != 0 && !that.factors[j].baseUnit.isDimensionless()) { int i; for (i = 0; i < factors.length; ++i) { if (factors[i].power != 0 && factors[i].baseUnit .equals(that.factors[j].baseUnit)) { break; } } if (i == factors.length) { vector[1].addElement(that.factors[j]); } } } return vector; } static abstract class Op { public DerivedUnit multOp(final DerivedUnit d1, final DerivedUnit d2) { final Vector[] comm = d1.common(d2); final int n0 = comm[0].size(); final int n1 = comm[1].size(); final int n2 = comm[2].size(); final Factor[] factors = new Factor[n0 + n1 + n2]; int k = 0; for (int i = 0; i < n0; ++i) { factors[k++] = (Factor) comm[0].elementAt(i); } for (int i = 0; i < n1; ++i) { factors[k++] = op((Factor) comm[1].elementAt(i)); } for (int i = 0; i < n2; ++i) { final Factor[] facts = (Factor[]) comm[2].elementAt(i); factors[k++] = op(facts[0], facts[1]); } return new DerivedUnit(factors); } protected abstract Factor op(Factor factor); protected abstract Factor op(Factor f1, Factor f2); } private static final class AddPow extends Op { @Override protected Factor op(final Factor factor) { return factor; } @Override protected Factor op(final Factor f1, final Factor f2) { return new Factor(f1.baseUnit, f1.power + f2.power); } } private static final class SubPow extends Op { @Override protected Factor op(final Factor factor) { return new Factor(factor.baseUnit, -factor.power); } @Override protected Factor op(final Factor f1, final Factor f2) { return new Factor(f1.baseUnit, f1.power - f2.power); } } /** * Instantiations of the inner "helper" classes. */ private static AddPow addPow = new AddPow(); private static SubPow subPow = new SubPow(); /** * Multiply a derived 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 that instanceof DerivedUnit ? multiply((DerivedUnit) that) : that.multiply(this); } /** * Multiply a derived unit by a derived unit. * * @param that * The derived unit with which to multiply this unit. * @return The product of the two units. * @promise Neither unit has been modified. */ public Unit multiply(final DerivedUnit that) { return addPow.multOp(this, that); } /** * Divide a derived 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 that instanceof DerivedUnit ? divide((DerivedUnit) that) : that.divideInto(this); } /** * Divide a derived unit by a derived unit. * * @param that * The derived unit to divide into this unit. * @return The quotient of the two units. * @promise Neither unit has been modified. */ Unit divide(final DerivedUnit that) { return subPow.multOp(this, that); } /** * Divide a derived 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 that.divide(this); } /** * Indicate whether or not this unit has the same dimensionality as a * derived unit. * * @param that * The derived unit. * @return <code>true</code> if and only if both units have the same * dimensionality (e.g. Length/Time). */ boolean sameDimensionality(final DerivedUnit that) { final Vector[] comm = common(that); if (comm[0].size() != 0 || comm[1].size() != 0) { return false; } final int n2 = comm[2].size(); for (int i = 0; i < n2; ++i) { final Factor[] factors = (Factor[]) comm[2].elementAt(i); if (factors[0].power != factors[1].power) { return false; } } return true; } /** * Indicate whether or not this unit has the reciprocal dimensionality of a * derived unit. * * @param that * The derived unit. * @return <code>true</code> if and only if the unit dimensionalities are * reciprocals of each other (e.g. Length/Time and Time/Length). */ boolean reciprocalDimensionality(final DerivedUnit that) { final Vector[] comm = common(that); if (comm[0].size() != 0 || comm[1].size() != 0) { return false; } final int n2 = comm[2].size(); for (int i = 0; i < n2; ++i) { final Factor[] factors = (Factor[]) comm[2].elementAt(i); if (factors[0].power != -factors[1].power) { return false; } } return true; } /** * Convert values to this unit from another unit. * * @param values * The values to be converted. * @param that * The unit of <code>values</code>. * @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 <code>values</code>. * @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 <code>values</code>. * @param copy * if false and <code>that</code> equals this, return * <code>values</code>, 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 { if (that instanceof PromiscuousUnit) { final double[] newValues = (copy) ? (double[]) values.clone() : values; return newValues; } return that instanceof DerivedUnit ? toThis(values, (DerivedUnit) that, copy) : that.toThat(values, this); } /** * Convert values to this unit from another unit. * * @param values * The values to be converted. * @param that * The unit of <code>values</code>. * @param copy * if false and <code>that</code> equals this, return * <code>values</code>, 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 { if (that instanceof PromiscuousUnit) { final float[] newValues = (copy) ? (float[]) values.clone() : values; return newValues; } return that instanceof DerivedUnit ? toThis(values, (DerivedUnit) that, copy) : that.toThat(values, this); } /** * Convert values to this unit from a derived unit. * * @param values * The values to be converted. * @param that * The unit of <code>values</code>. * @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. */ double[] toThis(final double[] values, final DerivedUnit that) throws UnitException { return toThis(values, that, true); } /** * Convert values to this unit from a derived unit. * * @param values * The values to be converted. * @param that * The unit of <code>values</code>. * @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. */ float[] toThis(final float[] values, final DerivedUnit that) throws UnitException { return toThis(values, that, true); } /** * Convert values to this unit from a derived unit. * * @param values * The values to be converted. * @param that * The unit of <code>values</code>. * @param copy * if false and <code>that</code> equals this, return * <code>values</code>, 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. */ double[] toThis(final double[] values, final DerivedUnit that, final boolean copy) throws UnitException { double[] newValues; if (sameDimensionality(that)) { newValues = (copy) ? (double[]) values.clone() : values; } else if (reciprocalDimensionality(that)) { newValues = (copy) ? (double[]) values.clone() : values; for (int i = 0; i < values.length; ++i) { if (values[i] == values[i]) { newValues[i] = 1.0 / values[i]; } else { newValues[i] = Double.NaN; } } } else { throw new UnitException("Attempt to convert from unit \"" + that + "\" to unit \"" + this + "\""); } return newValues; } /** * Convert values to this unit from a derived unit. * * @param values * The values to be converted. * @param that * The unit of <code>values</code>. * @param copy * if false and <code>that</code> equals this, return * <code>values</code>, 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. */ float[] toThis(final float[] values, final DerivedUnit that, final boolean copy) throws UnitException { float[] newValues; if (sameDimensionality(that)) { newValues = (copy) ? (float[]) values.clone() : values; } else if (reciprocalDimensionality(that)) { newValues = (copy) ? (float[]) values.clone() : values; for (int i = 0; i < values.length; ++i) { newValues[i] = 1.0f / values[i]; if (values[i] == values[i]) { newValues[i] = 1.0f / values[i]; } else { newValues[i] = Float.NaN; } } } else { throw new UnitException("Attempt to convert from unit \"" + that + "\" to unit \"" + this + "\""); } 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 convertible. * @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 convertible. * @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 a derived 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 convertible. * @promise Neither unit has been modified. * @throws UnitException * The units are not convertible. */ double[] toThat(final double values[], final DerivedUnit that) throws UnitException { return that.toThis(values, this, true); } /** * Convert values from this unit to a derived 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 convertible. * @promise Neither unit has been modified. * @throws UnitException * The units are not convertible. */ float[] toThat(final float values[], final DerivedUnit that) throws UnitException { return that.toThis(values, this, 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 <code>that</code> equals this, return * <code>values</code>, 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 { if (that instanceof PromiscuousUnit) { final double[] newValues = (copy) ? (double[]) values.clone() : values; return newValues; } return that instanceof DerivedUnit ? toThat(values, (DerivedUnit) that, copy) : that.toThis(values, this, copy); } /** * 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 <code>that</code> equals this, return * <code>values</code>, 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 { if (that instanceof PromiscuousUnit) { final float[] newValues = (copy) ? (float[]) values.clone() : values; return newValues; } return that instanceof DerivedUnit ? toThat(values, (DerivedUnit) that, copy) : that.toThis(values, this, copy); } /** * Convert values from this unit to a derived 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 <code>that</code> equals this, return * <code>values</code>, 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. */ double[] toThat(final double values[], final DerivedUnit that, final boolean copy) throws UnitException { return that.toThis(values, this, copy); } /** * Convert values from this unit to a derived 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 <code>that</code> equals this, return * <code>values</code>, 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. */ float[] toThat(final float values[], final DerivedUnit that, final boolean copy) throws UnitException { return that.toThis(values, this, copy); } /** * Indicate whether this unit is convertible with another unit. If one unit * is convertible with another, then the <code>toThis(...)</code>/ and * <code>toThat(...)</code> 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) { boolean isConvertible; if (unit == null) { isConvertible = false; } else { if (unit instanceof DerivedUnit) { final DerivedUnit that = (DerivedUnit) unit; isConvertible = sameDimensionality(that) || reciprocalDimensionality(that); } else { isConvertible = unit.isConvertible(this); } } return isConvertible; } // added by WLH 11 Feb 98 /** * Indicates if this instance equals a unit. * * @param unit * The unit. * @return <code>true</code> if and only if this instance equals the unit. */ @Override public boolean equals(final Unit unit) { if (this == unit) { return true; } if (!(unit instanceof DerivedUnit)) { return unit == null ? false : unit.equals(this); } final int n = factors.length; if (n != ((DerivedUnit) unit).factors.length) { return false; } final boolean[] mark = new boolean[n]; for (int j = 0; j < n; j++) { mark[j] = false; } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (!mark[j]) { if (factors[i].equals(((DerivedUnit) unit).factors[j])) { mark[j] = true; break; } } } } for (int j = 0; j < n; j++) { if (!mark[j]) { return false; } } return true; } /** * 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) { for (int i = 0; i < factors.length; i++) { hashCode ^= factors[i].hashCode(); } } return hashCode; } @Override public DerivedUnit getDerivedUnit() { return this; } }