summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/org/unitConverter/unit/BaseUnit.java48
-rw-r--r--src/org/unitConverter/unit/LinearUnit.java57
-rw-r--r--src/org/unitConverter/unit/OperatableUnit.java169
3 files changed, 272 insertions, 2 deletions
diff --git a/src/org/unitConverter/unit/BaseUnit.java b/src/org/unitConverter/unit/BaseUnit.java
index 1f0c825..894d338 100755
--- a/src/org/unitConverter/unit/BaseUnit.java
+++ b/src/org/unitConverter/unit/BaseUnit.java
@@ -28,7 +28,7 @@ import org.unitConverter.dimension.UnitDimension;
* @since 2018-12-23
* @since v0.1.0
*/
-public final class BaseUnit extends AbstractUnit {
+public final class BaseUnit extends AbstractUnit implements OperatableUnit {
/**
* Is this unit a full base (i.e. m, s, ... but not N, J, ...)
*
@@ -126,6 +126,35 @@ public final class BaseUnit extends AbstractUnit {
return result;
}
+ @Override
+ public LinearUnit negated() {
+ return this.times(-1);
+ }
+
+ @Override
+ public OperatableUnit plus(final OperatableUnit addend) {
+ Objects.requireNonNull(addend, "addend must not be null.");
+
+ // reject addends that cannot be added to this unit
+ if (!this.getSystem().equals(addend.getSystem()))
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
+ if (!this.getDimension().equals(addend.getDimension()))
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
+
+ // add them together
+ if (addend instanceof BaseUnit)
+ return this.times(2);
+ else
+ return addend.plus(this);
+ }
+
+ @Override
+ public BaseUnit reciprocal() {
+ return this.toExponent(-1);
+ }
+
/**
* Multiplies this unit by another unit.
*
@@ -159,6 +188,22 @@ public final class BaseUnit extends AbstractUnit {
return new LinearUnit(this, multiplier);
}
+ @Override
+ public OperatableUnit times(final OperatableUnit multiplier) {
+ Objects.requireNonNull(multiplier, "multiplier must not be null.");
+
+ // reject multipliers that cannot be muliplied by this unit
+ if (!this.getSystem().equals(multiplier.getSystem()))
+ throw new IllegalArgumentException(String
+ .format("Incompatible units for multiplication or division \"%s\" and \"%s\".", this, multiplier));
+
+ // multiply the units
+ if (multiplier instanceof BaseUnit)
+ return new BaseUnit(this.getDimension().times(multiplier.getDimension()), this.getSystem());
+ else
+ return multiplier.times(this);
+ }
+
/**
* Returns this unit, but to an exponent.
*
@@ -168,6 +213,7 @@ public final class BaseUnit extends AbstractUnit {
* @since 2019-01-15
* @since v0.1.0
*/
+ @Override
public BaseUnit toExponent(final int exponent) {
return this.getSystem().getBaseUnit(this.getDimension().toExponent(exponent));
}
diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java
index ab46f1e..64eff1f 100644
--- a/src/org/unitConverter/unit/LinearUnit.java
+++ b/src/org/unitConverter/unit/LinearUnit.java
@@ -27,7 +27,7 @@ import org.unitConverter.dimension.UnitDimension;
* @since 2018-12-22
* @since v0.1.0
*/
-public final class LinearUnit extends AbstractUnit {
+public final class LinearUnit extends AbstractUnit implements OperatableUnit {
/**
* The value of one of this unit in this unit's base unit
*
@@ -134,6 +134,40 @@ public final class LinearUnit extends AbstractUnit {
return result;
}
+ @Override
+ public LinearUnit negated() {
+ return new LinearUnit(this.getBase(), -this.getConversionFactor());
+ }
+
+ @Override
+ public OperatableUnit plus(final OperatableUnit addend) {
+ Objects.requireNonNull(addend, "addend must not be null.");
+
+ // reject addends that cannot be added to this unit
+ if (!this.getSystem().equals(addend.getSystem()))
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
+ if (!this.getDimension().equals(addend.getDimension()))
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
+
+ // add the units
+ if (addend instanceof BaseUnit)
+ // since addend's dimension is equal to this unit's dimension, and there is only one base unit per
+ // system-dimension, addend must be this unit's base.
+ return new LinearUnit(this.getBase(), this.getConversionFactor() + 1);
+ else if (addend instanceof LinearUnit)
+ return new LinearUnit(this.getBase(),
+ this.getConversionFactor() + ((LinearUnit) addend).getConversionFactor());
+ else
+ return addend.times(this);
+ }
+
+ @Override
+ public LinearUnit reciprocal() {
+ return this.toExponent(-1);
+ }
+
/**
* Multiplies this unit by a scalar.
*
@@ -164,6 +198,26 @@ public final class LinearUnit extends AbstractUnit {
return new LinearUnit(base, this.getConversionFactor() * other.getConversionFactor());
}
+ @Override
+ public OperatableUnit times(final OperatableUnit multiplier) {
+ Objects.requireNonNull(multiplier, "multiplier must not be null.");
+
+ // reject multipliers that cannot be muliplied by this unit
+ if (!this.getSystem().equals(multiplier.getSystem()))
+ throw new IllegalArgumentException(String
+ .format("Incompatible units for multiplication or division \"%s\" and \"%s\".", this, multiplier));
+
+ // multiply the units
+ if (multiplier instanceof BaseUnit) {
+ final BaseUnit newBase = this.getBase().times((BaseUnit) multiplier);
+ return new LinearUnit(newBase, this.getConversionFactor());
+ } else if (multiplier instanceof LinearUnit) {
+ final BaseUnit base = this.getBase().times(multiplier.getBase());
+ return new LinearUnit(base, this.getConversionFactor() * ((LinearUnit) multiplier).getConversionFactor());
+ } else
+ return multiplier.times(this);
+ }
+
/**
* Returns this unit but to an exponent.
*
@@ -173,6 +227,7 @@ public final class LinearUnit extends AbstractUnit {
* @since 2019-01-15
* @since v0.1.0
*/
+ @Override
public LinearUnit toExponent(final int exponent) {
return new LinearUnit(this.getBase().toExponent(exponent), Math.pow(this.conversionFactor, exponent));
}
diff --git a/src/org/unitConverter/unit/OperatableUnit.java b/src/org/unitConverter/unit/OperatableUnit.java
new file mode 100644
index 0000000..ae11c41
--- /dev/null
+++ b/src/org/unitConverter/unit/OperatableUnit.java
@@ -0,0 +1,169 @@
+/**
+ * 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;
+
+/**
+ * A unit that can be added, subtracted, multiplied or divided by another operatable unit, and raised to an integer
+ * exponent.
+ * <p>
+ * In order to use two units in an operation, they must be part of the same unit system. In addition, in order for two
+ * units to add or subtract, they must measure the same dimension.
+ * </p>
+ * <p>
+ * It is okay for an operation to throw a {@code ClassCastException} if the operator's class cannot operate with another
+ * class. However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
+ * {@code LinearUnit}.
+ * </p>
+ *
+ * @author Adrien Hopkins
+ * @since 2019-03-17
+ */
+public interface OperatableUnit extends Unit {
+ /**
+ * 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>
+ * <p>
+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code divisor}'s class.
+ * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
+ * {@code LinearUnit}.
+ * </p>
+ *
+ * @param divisor
+ * unit to divide by
+ * @return quotient
+ * @throws IllegalArgumentException
+ * if {@code divisor} is not compatible for division as described above
+ * @throws NullPointerException
+ * if {@code divisor} is null
+ * @throws ClassCastException
+ * if {@code divisor}'s class is incompatible with this unit's class
+ * @since 2019-03-17
+ */
+ default OperatableUnit dividedBy(final OperatableUnit divisor) {
+ return this.times(divisor.reciprocal());
+ }
+
+ /**
+ * Returns the difference of this unit and another.
+ * <p>
+ * Two units can be subtracted if they meet the following conditions:
+ * <ul>
+ * <li>The two units are part of the same UnitSystem.</li>
+ * <li>The two units have the same {@code dimension}.</li>
+ * </ul>
+ * If {@code subtrahend} does not meet these conditions, an {@code IllegalArgumentException} should be thrown.
+ * </p>
+ * <p>
+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code subtrahend}'s class.
+ * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
+ * {@code LinearUnit}.
+ * </p>
+ *
+ * @param subtrahend
+ * unit to subtract
+ * @return difference
+ * @throws IllegalArgumentException
+ * if {@code subtrahend} is not compatible for subtraction as described above
+ * @throws NullPointerException
+ * if {@code subtrahend} is null
+ * @throws ClassCastException
+ * if {@code subtrahend}'s class is incompatible with this unit's class
+ * @since 2019-03-17
+ */
+ default OperatableUnit minus(final OperatableUnit subtrahend) {
+ return this.plus(subtrahend.negated());
+ }
+
+ /**
+ * @return this unit negated, i.e. -this
+ * @since 2019-03-17
+ */
+ OperatableUnit negated();
+
+ /**
+ * Returns the sum of this unit and another.
+ * <p>
+ * Two units can be added if they meet the following conditions:
+ * <ul>
+ * <li>The two units are part of the same UnitSystem.</li>
+ * <li>The two units have the same {@code dimension}.</li>
+ * </ul>
+ * If {@code addend} does not meet these conditions, an {@code IllegalArgumentException} should be thrown.
+ * </p>
+ * <p>
+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code addend}'s class.
+ * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
+ * {@code LinearUnit}.
+ * </p>
+ *
+ * @param addend
+ * unit to add
+ * @return sum
+ * @throws IllegalArgumentException
+ * if {@code addend} is not compatible for addition as described above
+ * @throws NullPointerException
+ * if {@code addend} is null
+ * @throws ClassCastException
+ * if {@code addend}'s class is incompatible with this unit's class
+ * @since 2019-03-17
+ */
+ OperatableUnit plus(OperatableUnit addend);
+
+ /**
+ * @return reciprocal of this unit
+ * @since 2019-03-17
+ */
+ OperatableUnit reciprocal();
+
+ /**
+ * 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>
+ * <p>
+ * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code multiplier}'s class.
+ * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
+ * {@code LinearUnit}.
+ * </p>
+ *
+ * @param multiplier
+ * unit to multiply by
+ * @return product
+ * @throws IllegalArgumentException
+ * if {@code multiplier} is not compatible for multiplication as described above
+ * @throws NullPointerException
+ * if {@code multiplier} is null
+ * @throws ClassCastException
+ * if {@code multiplier}'s class is incompatible with this unit's class
+ * @since 2019-03-17
+ */
+ OperatableUnit times(OperatableUnit multiplier);
+
+ /**
+ * Returns the result of raising this unit to the exponent {@code exponent}.
+ *
+ * @param exponent
+ * exponent to exponentiate by
+ * @return result of exponentiation
+ * @since 2019-03-17
+ */
+ OperatableUnit toExponent(int exponent);
+}