diff options
author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2019-04-14 17:46:43 -0400 |
---|---|---|
committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2019-04-14 17:46:43 -0400 |
commit | 910b2f1b448ec56e6a66f4aa4f72e71c39de40a1 (patch) | |
tree | 231fcb8f72a467a77efc1e6050de12bd70f7b152 /src/org/unitConverter/unit | |
parent | 70273e127b061c69ce4b3d9d6c3881c6b0c2b829 (diff) | |
parent | 2ce65fa76908d77a5e3b045a8eb40c798939b8be (diff) |
Release v0.2.0v0.2.0
Diffstat (limited to 'src/org/unitConverter/unit')
-rw-r--r-- | src/org/unitConverter/unit/AbstractUnit.java | 117 | ||||
-rwxr-xr-x | src/org/unitConverter/unit/BaseUnit.java | 168 | ||||
-rwxr-xr-x | src/org/unitConverter/unit/DefaultUnitPrefix.java | 68 | ||||
-rw-r--r-- | src/org/unitConverter/unit/LinearUnit.java | 294 | ||||
-rwxr-xr-x | src/org/unitConverter/unit/NonlinearUnits.java | 57 | ||||
-rw-r--r-- | src/org/unitConverter/unit/SI.java | 74 | ||||
-rwxr-xr-x | src/org/unitConverter/unit/SIPrefix.java | 54 | ||||
-rwxr-xr-x | src/org/unitConverter/unit/Unit.java | 110 | ||||
-rwxr-xr-x | src/org/unitConverter/unit/UnitPrefix.java | 72 | ||||
-rwxr-xr-x | src/org/unitConverter/unit/UnitSystem.java | 53 | ||||
-rw-r--r-- | src/org/unitConverter/unit/package-info.java | 24 |
11 files changed, 1091 insertions, 0 deletions
diff --git a/src/org/unitConverter/unit/AbstractUnit.java b/src/org/unitConverter/unit/AbstractUnit.java new file mode 100644 index 0000000..05a6c17 --- /dev/null +++ b/src/org/unitConverter/unit/AbstractUnit.java @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2019 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +import java.util.Objects; + +import org.unitConverter.dimension.UnitDimension; + +/** + * The default abstract implementation of the {@code Unit} interface. + * + * @author Adrien Hopkins + * @since 2018-12-22 + * @since v0.1.0 + */ +public abstract class AbstractUnit implements Unit { + /** + * The dimension, or what the unit measures. + * + * @since 2018-12-22 + * @since v0.1.0 + */ + private final UnitDimension dimension; + + /** + * The unit's base unit. Values converted by {@code convertFromBase} and {@code convertToBase} are expressed in this + * unit. + * + * @since 2018-12-22 + * @since v0.1.0 + */ + private final BaseUnit base; + + /** + * The system that this unit is a part of. + * + * @since 2018-12-23 + * @since v0.1.0 + */ + private final UnitSystem system; + + /** + * Creates the {@code AbstractUnit}. + * + * @param base + * unit's base + * @throws NullPointerException + * if name, symbol or base is null + * @since 2018-12-22 + * @since v0.1.0 + */ + public AbstractUnit(final BaseUnit base) { + this.base = Objects.requireNonNull(base, "base must not be null."); + this.dimension = this.base.getDimension(); + this.system = this.base.getSystem(); + } + + /** + * Creates the {@code AbstractUnit} using a unique dimension. This constructor is for making base units and should + * only be used by {@code BaseUnit}. + * + * @param dimension + * dimension measured by unit + * @param system + * system that unit is a part of + * @throws AssertionError + * if this constructor is not run by {@code BaseUnit} or a subclass + * @throws NullPointerException + * if name, symbol or dimension is null + * @since 2018-12-23 + * @since v0.1.0 + */ + AbstractUnit(final UnitDimension dimension, final UnitSystem system) { + // try to set this as a base unit + if (this instanceof BaseUnit) { + this.base = (BaseUnit) this; + } else + throw new AssertionError(); + + this.dimension = Objects.requireNonNull(dimension, "dimension must not be null."); + this.system = Objects.requireNonNull(system, "system must not be null."); + } + + @Override + public final BaseUnit getBase() { + return this.base; + } + + @Override + public final UnitDimension getDimension() { + return this.dimension; + } + + @Override + public final UnitSystem getSystem() { + return this.system; + } + + @Override + public String toString() { + return String.format("%s-derived unit of dimension %s", this.getSystem(), this.getDimension()); + } +} diff --git a/src/org/unitConverter/unit/BaseUnit.java b/src/org/unitConverter/unit/BaseUnit.java new file mode 100755 index 0000000..67309cf --- /dev/null +++ b/src/org/unitConverter/unit/BaseUnit.java @@ -0,0 +1,168 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +import java.util.Objects; + +import org.unitConverter.dimension.StandardDimensions; +import org.unitConverter.dimension.UnitDimension; + +/** + * A unit that is the base for its dimension. It does not have to be for a base dimension, so units like the Newton and + * Joule are still base units. + * <p> + * {@code BaseUnit} does not have any public constructors or static factories. There are two ways to obtain + * {@code BaseUnit} instances. + * <ol> + * <li>The class {@link SI} in this package has constants for all of the SI base units. You can use these constants and + * multiply or divide them to get other units. For example: + * + * <pre> + * BaseUnit JOULE = SI.KILOGRAM.times(SI.METRE.toExponent(2)).dividedBy(SI.SECOND.toExponent(2)); + * </pre> + * + * </li> + * <li>You can also query a unit system for a base unit using a unit dimension. The previously mentioned {@link SI} + * class can do this for SI and SI-derived units (including imperial and USC), but if you want to use another system, + * this is the way to do it. {@link StandardDimensions} contains common unit dimensions that you can use for this. Here + * is an example: + * + * <pre> + * BaseUnit JOULE = SI.SI.getBaseUnit(StandardDimensions.ENERGY); + * </pre> + * + * </li> + * </ol> + * + * @author Adrien Hopkins + * @since 2018-12-23 + * @since v0.1.0 + */ +public final class BaseUnit extends LinearUnit { + /** + * Is this unit a full base (i.e. m, s, ... but not N, J, ...) + * + * @since 2019-01-15 + * @since v0.1.0 + */ + private final boolean isFullBase; + + /** + * Creates the {@code BaseUnit}. + * + * @param dimension + * dimension measured by unit + * @param system + * system that unit is a part of + * @param name + * name of unit + * @param symbol + * symbol of unit + * @since 2018-12-23 + * @since v0.1.0 + */ + BaseUnit(final UnitDimension dimension, final UnitSystem system) { + super(dimension, system, 1); + this.isFullBase = dimension.isBase(); + } + + /** + * Returns the quotient of this unit and another. + * <p> + * Two units can be divided if they are part of the same unit system. If {@code divisor} does not meet this + * condition, an {@code IllegalArgumentException} should be thrown. + * </p> + * + * @param divisor + * unit to divide by + * @return quotient of two units + * @throws IllegalArgumentException + * if {@code divisor} is not compatible for division as described above + * @throws NullPointerException + * if {@code divisor} is null + * @since 2018-12-22 + * @since v0.1.0 + */ + public BaseUnit dividedBy(final BaseUnit divisor) { + Objects.requireNonNull(divisor, "other must not be null."); + + // check that these units can be multiplied + if (!this.getSystem().equals(divisor.getSystem())) + throw new IllegalArgumentException( + String.format("Incompatible units for division \"%s\" and \"%s\".", this, divisor)); + + return new BaseUnit(this.getDimension().dividedBy(divisor.getDimension()), this.getSystem()); + } + + /** + * @return true if the unit is a "full base" unit like the metre or second. + * @since 2019-04-10 + * @since v0.2.0 + */ + public final boolean isFullBase() { + return this.isFullBase; + } + + /** + * Returns the product of this unit and another. + * <p> + * Two units can be multiplied if they are part of the same unit system. If {@code multiplier} does not meet this + * condition, an {@code IllegalArgumentException} should be thrown. + * </p> + * + * @param multiplier + * unit to multiply by + * @return product of two units + * @throws IllegalArgumentException + * if {@code multiplier} is not compatible for multiplication as described above + * @throws NullPointerException + * if {@code multiplier} is null + * @since 2018-12-22 + * @since v0.1.0 + */ + public BaseUnit times(final BaseUnit multiplier) { + Objects.requireNonNull(multiplier, "other must not be null"); + + // check that these units can be multiplied + if (!this.getSystem().equals(multiplier.getSystem())) + throw new IllegalArgumentException( + String.format("Incompatible units for multiplication \"%s\" and \"%s\".", this, multiplier)); + + // multiply the units + return new BaseUnit(this.getDimension().times(multiplier.getDimension()), this.getSystem()); + } + + /** + * Returns this unit, but to an exponent. + * + * @param exponent + * exponent + * @return result of exponentiation + * @since 2019-01-15 + * @since v0.1.0 + */ + @Override + public BaseUnit toExponent(final int exponent) { + return this.getSystem().getBaseUnit(this.getDimension().toExponent(exponent)); + } + + @Override + public String toString() { + return String.format("%s base unit of%s dimension %s", this.getSystem(), this.isFullBase ? " base" : "", + this.getDimension()); + } +} diff --git a/src/org/unitConverter/unit/DefaultUnitPrefix.java b/src/org/unitConverter/unit/DefaultUnitPrefix.java new file mode 100755 index 0000000..4a9e487 --- /dev/null +++ b/src/org/unitConverter/unit/DefaultUnitPrefix.java @@ -0,0 +1,68 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +import java.util.Objects; + +/** + * The default implementation of {@code UnitPrefix}, which contains a multiplier and nothing else. + * + * @author Adrien Hopkins + * @since 2019-01-14 + * @since v0.1.0 + */ +public final class DefaultUnitPrefix implements UnitPrefix { + private final double multiplier; + + /** + * Creates the {@code DefaultUnitPrefix}. + * + * @param multiplier + * @since 2019-01-14 + * @since v0.2.0 + */ + public DefaultUnitPrefix(final double multiplier) { + this.multiplier = multiplier; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof DefaultUnitPrefix)) + return false; + final DefaultUnitPrefix other = (DefaultUnitPrefix) obj; + return Double.doubleToLongBits(this.multiplier) == Double.doubleToLongBits(other.multiplier); + } + + @Override + public double getMultiplier() { + return this.multiplier; + } + + @Override + public int hashCode() { + return Objects.hash(this.multiplier); + } + + @Override + public String toString() { + return String.format("Unit prefix equal to %s", this.multiplier); + } +} diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java new file mode 100644 index 0000000..1b1ac97 --- /dev/null +++ b/src/org/unitConverter/unit/LinearUnit.java @@ -0,0 +1,294 @@ +/** + * Copyright (C) 2019 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +import java.util.Objects; + +import org.unitConverter.dimension.UnitDimension; +import org.unitConverter.math.DecimalComparison; + +/** + * A unit that is equal to a certain number multiplied by its base. + * <p> + * {@code LinearUnit} does not have any public constructors or static factories. In order to obtain a {@code LinearUnit} + * instance, multiply its base by the conversion factor. Example: + * + * <pre> + * LinearUnit foot = METRE.times(0.3048); + * </pre> + * + * (where {@code METRE} is a {@code BaseUnit} instance) + * </p> + * + * @author Adrien Hopkins + * @since 2018-12-22 + * @since v0.1.0 + */ +public class LinearUnit extends AbstractUnit { + /** + * The value of one of this unit in this unit's base unit + * + * @since 2018-12-22 + * @since v0.1.0 + */ + private final double conversionFactor; + + /** + * + * Creates the {@code LinearUnit}. + * + * @param base + * unit's base + * @param conversionFactor + * value of one of this unit in its base + * @since 2018-12-23 + * @since v0.1.0 + */ + LinearUnit(final BaseUnit base, final double conversionFactor) { + super(base); + this.conversionFactor = conversionFactor; + } + + /** + * Creates the {@code LinearUnit} as a base unit. + * + * @param dimension + * dimension measured by unit + * @param system + * system unit is part of + * @since 2019-01-25 + * @since v0.1.0 + */ + LinearUnit(final UnitDimension dimension, final UnitSystem system, final double conversionFactor) { + super(dimension, system); + this.conversionFactor = conversionFactor; + } + + @Override + public double convertFromBase(final double value) { + return value / this.getConversionFactor(); + } + + @Override + public double convertToBase(final double value) { + return value * this.getConversionFactor(); + } + + /** + * Divides this unit by a scalar. + * + * @param divisor + * scalar to divide by + * @return quotient + * @since 2018-12-23 + * @since v0.1.0 + */ + public LinearUnit dividedBy(final double divisor) { + return new LinearUnit(this.getBase(), this.getConversionFactor() / divisor); + } + + /** + * Returns the quotient of this unit and another. + * <p> + * Two units can be divided if they are part of the same unit system. If {@code divisor} does not meet this + * condition, an {@code IllegalArgumentException} should be thrown. + * </p> + * + * @param divisor + * unit to divide by + * @return quotient of two units + * @throws IllegalArgumentException + * if {@code divisor} is not compatible for division as described above + * @throws NullPointerException + * if {@code divisor} is null + * @since 2018-12-22 + * @since v0.1.0 + */ + public LinearUnit dividedBy(final LinearUnit divisor) { + Objects.requireNonNull(divisor, "other must not be null"); + + // check that these units can be multiplied + if (!this.getSystem().equals(divisor.getSystem())) + throw new IllegalArgumentException( + String.format("Incompatible units for division \"%s\" and \"%s\".", this, divisor)); + + // divide the units + final BaseUnit base = this.getBase().dividedBy(divisor.getBase()); + return new LinearUnit(base, this.getConversionFactor() / divisor.getConversionFactor()); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof LinearUnit)) + return false; + final LinearUnit other = (LinearUnit) obj; + return Objects.equals(this.getSystem(), other.getSystem()) + && Objects.equals(this.getDimension(), other.getDimension()) + && DecimalComparison.equals(this.getConversionFactor(), other.getConversionFactor()); + } + + /** + * @return conversion factor between this unit and its base + * @since 2018-12-22 + * @since v0.1.0 + */ + public final double getConversionFactor() { + return this.conversionFactor; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = result * prime + this.getSystem().hashCode(); + result = result * prime + this.getDimension().hashCode(); + result = result * prime + Double.hashCode(this.getConversionFactor()); + return result; + } + + /** + * Returns the difference of this unit and another. + * <p> + * Two units can be subtracted if they have the same base. If {@code subtrahend} does not meet this condition, an + * {@code IllegalArgumentException} will be thrown. + * </p> + * + * @param subtrahend + * unit to subtract + * @return difference of units + * @throws IllegalArgumentException + * if {@code subtrahend} is not compatible for subtraction as described above + * @throws NullPointerException + * if {@code subtrahend} is null + * @since 2019-03-17 + * @since v0.2.0 + */ + public LinearUnit minus(final LinearUnit subtrahendend) { + Objects.requireNonNull(subtrahendend, "addend must not be null."); + + // reject subtrahends that cannot be added to this unit + if (!this.getBase().equals(subtrahendend.getBase())) + throw new IllegalArgumentException( + String.format("Incompatible units for subtraction \"%s\" and \"%s\".", this, subtrahendend)); + + // add the units + return new LinearUnit(this.getBase(), this.getConversionFactor() - subtrahendend.getConversionFactor()); + } + + /** + * Returns the sum of this unit and another. + * <p> + * Two units can be added if they have the same base. If {@code addend} does not meet this condition, an + * {@code IllegalArgumentException} will be thrown. + * </p> + * + * @param addend + * unit to add + * @return sum of units + * @throws IllegalArgumentException + * if {@code addend} is not compatible for addition as described above + * @throws NullPointerException + * if {@code addend} is null + * @since 2019-03-17 + * @since v0.2.0 + */ + public LinearUnit plus(final LinearUnit addend) { + Objects.requireNonNull(addend, "addend must not be null."); + + // reject addends that cannot be added to this unit + if (!this.getBase().equals(addend.getBase())) + throw new IllegalArgumentException( + String.format("Incompatible units for addition \"%s\" and \"%s\".", this, addend)); + + // add the units + return new LinearUnit(this.getBase(), this.getConversionFactor() + addend.getConversionFactor()); + } + + /** + * Multiplies this unit by a scalar. + * + * @param multiplier + * scalar to multiply by + * @return product + * @since 2018-12-23 + * @since v0.1.0 + */ + public LinearUnit times(final double multiplier) { + return new LinearUnit(this.getBase(), this.getConversionFactor() * multiplier); + } + + /** + * Returns the product of this unit and another. + * <p> + * Two units can be multiplied if they are part of the same unit system. If {@code multiplier} does not meet this + * condition, an {@code IllegalArgumentException} should be thrown. + * </p> + * + * @param multiplier + * unit to multiply by + * @return product of two units + * @throws IllegalArgumentException + * if {@code multiplier} is not compatible for multiplication as described above + * @throws NullPointerException + * if {@code multiplier} is null + * @since 2018-12-22 + * @since v0.1.0 + */ + public LinearUnit times(final LinearUnit multiplier) { + Objects.requireNonNull(multiplier, "other must not be null"); + + // check that these units can be multiplied + if (!this.getSystem().equals(multiplier.getSystem())) + throw new IllegalArgumentException( + String.format("Incompatible units for multiplication \"%s\" and \"%s\".", this, multiplier)); + + // multiply the units + final BaseUnit base = this.getBase().times(multiplier.getBase()); + return new LinearUnit(base, this.getConversionFactor() * multiplier.getConversionFactor()); + } + + /** + * Returns this unit but to an exponent. + * + * @param exponent + * exponent to exponientate unit to + * @return exponientated unit + * @since 2019-01-15 + * @since v0.1.0 + */ + public LinearUnit toExponent(final int exponent) { + return new LinearUnit(this.getBase().toExponent(exponent), Math.pow(this.conversionFactor, exponent)); + } + + @Override + public String toString() { + return super.toString() + String.format(" (equal to %s * base)", this.getConversionFactor()); + } + + /** + * Returns the result of applying {@code prefix} to this unit. + * + * @param prefix + * prefix to apply + * @return unit with prefix + * @since 2019-03-18 + * @since v0.2.0 + */ + public LinearUnit withPrefix(final UnitPrefix prefix) { + return this.times(prefix.getMultiplier()); + } +} diff --git a/src/org/unitConverter/unit/NonlinearUnits.java b/src/org/unitConverter/unit/NonlinearUnits.java new file mode 100755 index 0000000..e47c28f --- /dev/null +++ b/src/org/unitConverter/unit/NonlinearUnits.java @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +/** + * Some major nonlinear units. + * + * @author Adrien Hopkins + * @since 2019-01-14 + * @since v0.1.0 + */ +public final class NonlinearUnits { + public static final Unit CELSIUS = new AbstractUnit(SI.KELVIN) { + + @Override + public double convertFromBase(final double value) { + return value - 273.15; + } + + @Override + public double convertToBase(final double value) { + return value + 273.15; + } + }; + + public static final Unit FAHRENHEIT = new AbstractUnit(SI.KELVIN) { + + @Override + public double convertFromBase(final double value) { + return 1.8 * value - 459.67; + } + + @Override + public double convertToBase(final double value) { + return (value + 459.67) / 1.8; + } + }; + + // You may NOT get a NonlinearUnits instance. + private NonlinearUnits() { + throw new AssertionError(); + } +} diff --git a/src/org/unitConverter/unit/SI.java b/src/org/unitConverter/unit/SI.java new file mode 100644 index 0000000..46e6ff1 --- /dev/null +++ b/src/org/unitConverter/unit/SI.java @@ -0,0 +1,74 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import org.unitConverter.dimension.StandardDimensions; +import org.unitConverter.dimension.UnitDimension; + +/** + * The SI, which holds all SI units + * + * @author Adrien Hopkins + * @since 2018-12-23 + * @since v0.1.0 + */ +public enum SI implements UnitSystem { + SI; + + /** + * This system's base units. + * + * @since 2019-01-25 + * @since v0.1.0 + */ + private static final Set<BaseUnit> baseUnits = new HashSet<>(); + + // base units + public static final BaseUnit METRE = SI.getBaseUnit(StandardDimensions.LENGTH); + public static final BaseUnit KILOGRAM = SI.getBaseUnit(StandardDimensions.MASS); + public static final BaseUnit SECOND = SI.getBaseUnit(StandardDimensions.TIME); + public static final BaseUnit AMPERE = SI.getBaseUnit(StandardDimensions.ELECTRIC_CURRENT); + public static final BaseUnit KELVIN = SI.getBaseUnit(StandardDimensions.TEMPERATURE); + public static final BaseUnit MOLE = SI.getBaseUnit(StandardDimensions.QUANTITY); + public static final BaseUnit CANDELA = SI.getBaseUnit(StandardDimensions.LUMINOUS_INTENSITY); + + @Override + public BaseUnit getBaseUnit(final UnitDimension dimension) { + // try to find an existing unit before creating a new one + + Objects.requireNonNull(dimension, "dimension must not be null."); + for (final BaseUnit unit : baseUnits) { + // it will be equal since the conditions for equality are dimension and system, + // and system is always SI. + if (unit.getDimension().equals(dimension)) + return unit; + } + // could not find an existing base unit + final BaseUnit unit = new BaseUnit(dimension, this); + baseUnits.add(unit); + return unit; + } + + @Override + public String getName() { + return "SI"; + } +} diff --git a/src/org/unitConverter/unit/SIPrefix.java b/src/org/unitConverter/unit/SIPrefix.java new file mode 100755 index 0000000..31d7ff2 --- /dev/null +++ b/src/org/unitConverter/unit/SIPrefix.java @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +/** + * The SI prefixes. + * + * @author Adrien Hopkins + * @since 2019-01-14 + * @since v0.1.0 + */ +public enum SIPrefix implements UnitPrefix { + DECA(10), HECTO(100), KILO(1e3), MEGA(1e6), GIGA(1e9), TERA(1e12), PETA(1e15), EXA(1e18), ZETTA(1e21), YOTTA( + 1e24), DECI(0.1), CENTI(0.01), MILLI( + 1e-3), MICRO(1e-6), NANO(1e-9), PICO(1e-12), FEMTO(1e-15), ATTO(1e-18), ZEPTO(1e-21), YOCTO(1e-24); + + private final double multiplier; + + /** + * Creates the {@code SIPrefix}. + * + * @param multiplier + * prefix's multiplier + * @since 2019-01-14 + * @since v0.1.0 + */ + private SIPrefix(final double multiplier) { + this.multiplier = multiplier; + } + + /** + * @return value + * @since 2019-01-14 + * @since v0.1.0 + */ + @Override + public final double getMultiplier() { + return this.multiplier; + } +} diff --git a/src/org/unitConverter/unit/Unit.java b/src/org/unitConverter/unit/Unit.java new file mode 100755 index 0000000..86fc5a2 --- /dev/null +++ b/src/org/unitConverter/unit/Unit.java @@ -0,0 +1,110 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +import java.util.Objects; + +import org.unitConverter.dimension.UnitDimension; + +/** + * A unit that has an associated base unit, and can convert a value expressed in it to and from that base. + * + * @author Adrien Hopkins + * @since 2018-12-22 + * @since v0.1.0 + */ +public interface Unit { + /** + * Checks if a value expressed in this unit can be converted to a value expressed in {@code other} + * + * @param other + * unit to test with + * @return true if the units are compatible + * @since 2019-01-13 + * @since v0.1.0 + */ + default boolean canConvertTo(final Unit other) { + return Objects.equals(this.getBase(), other.getBase()); + } + + /** + * Converts from a value expressed in this unit's base unit to a value expressed in this unit. + * <p> + * This must be the inverse of {@code convertToBase}, so {@code convertFromBase(convertToBase(value))} must be equal + * to {@code value} for any value, ignoring precision loss by roundoff error. + * </p> + * <p> + * If this unit <i>is</i> a base unit, this method should return {@code value}. + * </p> + * + * @param value + * value expressed in <b>base</b> unit + * @return value expressed in <b>this</b> unit + * @since 2018-12-22 + * @since v0.1.0 + */ + double convertFromBase(double value); + + /** + * Converts from a value expressed in this unit to a value expressed in this unit's base unit. + * <p> + * This must be the inverse of {@code convertFromBase}, so {@code convertToBase(convertFromBase(value))} must be + * equal to {@code value} for any value, ignoring precision loss by roundoff error. + * </p> + * <p> + * If this unit <i>is</i> a base unit, this method should return {@code value}. + * </p> + * + * @param value + * value expressed in <b>this</b> unit + * @return value expressed in <b>base</b> unit + * @since 2018-12-22 + * @since v0.1.0 + */ + double convertToBase(double value); + + /** + * <p> + * Returns the base unit associated with this unit. + * </p> + * <p> + * The dimension of this unit must be equal to the dimension of the returned unit. + * </p> + * <p> + * If this unit <i>is</i> a base unit, this method should return this unit.\ + * </p> + * + * @return base unit associated with this unit + * @since 2018-12-22 + * @since v0.1.0 + */ + BaseUnit getBase(); + + /** + * @return dimension measured by this unit + * @since 2018-12-22 + * @since v0.1.0 + */ + UnitDimension getDimension(); + + /** + * @return system that this unit is a part of + * @since 2018-12-23 + * @since v0.1.0 + */ + UnitSystem getSystem(); +} diff --git a/src/org/unitConverter/unit/UnitPrefix.java b/src/org/unitConverter/unit/UnitPrefix.java new file mode 100755 index 0000000..9f9645d --- /dev/null +++ b/src/org/unitConverter/unit/UnitPrefix.java @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +/** + * A prefix that can be attached onto the front of any unit, which multiplies it by a certain value + * + * @author Adrien Hopkins + * @since 2019-01-14 + * @since v0.1.0 + */ +public interface UnitPrefix { + /** + * Divides this prefix by {@code other}. + * + * @param other + * prefix to divide by + * @return quotient of prefixes + * @since 2019-04-13 + * @since v0.2.0 + */ + default UnitPrefix dividedBy(final UnitPrefix other) { + return new DefaultUnitPrefix(this.getMultiplier() / other.getMultiplier()); + } + + /** + * @return this prefix's multiplier + * @since 2019-01-14 + * @since v0.1.0 + */ + double getMultiplier(); + + /** + * Multiplies this prefix by {@code other}. + * + * @param other + * prefix to multiply by + * @return product of prefixes + * @since 2019-04-13 + * @since v0.2.0 + */ + default UnitPrefix times(final UnitPrefix other) { + return new DefaultUnitPrefix(this.getMultiplier() * other.getMultiplier()); + } + + /** + * Raises this prefix to an exponent. + * + * @param exponent + * exponent to raise to + * @return result of exponentiation. + * @since 2019-04-13 + * @since v0.2.0 + */ + default UnitPrefix toExponent(final double exponent) { + return new DefaultUnitPrefix(Math.pow(getMultiplier(), exponent)); + } +} diff --git a/src/org/unitConverter/unit/UnitSystem.java b/src/org/unitConverter/unit/UnitSystem.java new file mode 100755 index 0000000..550eff6 --- /dev/null +++ b/src/org/unitConverter/unit/UnitSystem.java @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2018 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.unitConverter.unit; + +import java.util.Objects; + +import org.unitConverter.dimension.UnitDimension; + +/** + * A system of units. Each unit should be aware of its system. + * + * @author Adrien Hopkins + * @since 2018-12-23 + * @since v0.1.0 + */ +public interface UnitSystem { + /** + * Gets a base unit for this system and the provided dimension. + * + * @param dimension + * dimension used by base unit + * @return base unit + * @throws NullPointerException + * if dimension is null + * @since 2019-01-25 + * @since v0.1.0 + */ + default BaseUnit getBaseUnit(final UnitDimension dimension) { + Objects.requireNonNull(dimension, "dimension must not be null."); + return new BaseUnit(dimension, this); + } + + /** + * @return name of system + * @since 2018-12-23 + * @since v0.1.0 + */ + String getName(); +} diff --git a/src/org/unitConverter/unit/package-info.java b/src/org/unitConverter/unit/package-info.java new file mode 100644 index 0000000..dd5a939 --- /dev/null +++ b/src/org/unitConverter/unit/package-info.java @@ -0,0 +1,24 @@ +/** + * Copyright (C) 2019 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +/** + * All of the classes that correspond to the units being converted. + * + * @author Adrien Hopkins + * @since 2019-01-25 + * @since v0.1.0 + */ +package org.unitConverter.unit;
\ No newline at end of file |