From 3c23fd15b88396868101457256173c0c2c29df5c Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 21 Oct 2019 21:27:59 -0400 Subject: Added unit names and the NameSymbol. --- src/org/unitConverter/unit/Unit.java | 329 +++++++++++++++++++++++++++++++++-- 1 file changed, 315 insertions(+), 14 deletions(-) (limited to 'src/org/unitConverter/unit/Unit.java') diff --git a/src/org/unitConverter/unit/Unit.java b/src/org/unitConverter/unit/Unit.java index 7971a41..d65e14f 100644 --- a/src/org/unitConverter/unit/Unit.java +++ b/src/org/unitConverter/unit/Unit.java @@ -16,9 +16,14 @@ */ package org.unitConverter.unit; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.DoubleUnaryOperator; import org.unitConverter.math.ObjectProduct; @@ -30,6 +35,222 @@ import org.unitConverter.math.ObjectProduct; * @since 2019-10-16 */ public abstract class Unit { + /** + * A class that can be used to specify names and a symbol for a unit. + * + * @author Adrien Hopkins + * @since 2019-10-21 + */ + public static final class NameSymbol { + public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(), Optional.empty(), new HashSet<>()); + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and no other names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if name or symbol is null + */ + public static final NameSymbol of(final String name, final String symbol) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), new HashSet<>()); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final Set otherNames) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), + new HashSet<>(Objects.requireNonNull(otherNames, "otherNames must not be null."))); + } + + /** + * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String... otherNames) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), + new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames, "otherNames must not be null.")))); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and an additional name. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2) { + final Set otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @param name3 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2, + final String name3) { + final Set otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @param name3 + * alternate name + * @param name4 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2, + final String name3, final String name4) { + final Set otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); + otherNames.add(Objects.requireNonNull(name4, "name4 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, no symbol, and no other names. + * + * @param name + * name to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if name is null + */ + public static final NameSymbol ofName(final String name) { + return new NameSymbol(Optional.of(name), Optional.empty(), new HashSet<>()); + } + + /** + * Gets a {@code NameSymbol} with a symbol and no names. + * + * @param symbol + * symbol to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if symbol is null + */ + public static final NameSymbol ofSymbol(final String symbol) { + return new NameSymbol(Optional.empty(), Optional.of(symbol), new HashSet<>()); + } + + private final Optional primaryName; + private final Optional symbol; + + private final Set otherNames; + + /** + * Creates the {@code NameSymbol}. + * + * @param primaryName + * primary name of unit + * @param symbol + * symbol used to represent unit + * @param otherNames + * other names and/or spellings + * @since 2019-10-21 + */ + private NameSymbol(final Optional primaryName, final Optional symbol, + final Set otherNames) { + this.primaryName = primaryName; + this.symbol = symbol; + this.otherNames = Collections.unmodifiableSet(otherNames); + } + + /** + * @return otherNames + * @since 2019-10-21 + */ + public final Set getOtherNames() { + return this.otherNames; + } + + /** + * @return primaryName + * @since 2019-10-21 + */ + public final Optional getPrimaryName() { + return this.primaryName; + } + + /** + * @return symbol + * @since 2019-10-21 + */ + public final Optional getSymbol() { + return this.symbol; + } + } + /** * Returns a unit from its base and the functions it uses to convert to and from its base. * @@ -54,7 +275,36 @@ public abstract class Unit { */ public static final Unit fromConversionFunctions(final ObjectProduct base, final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo) { - return FunctionalUnit.valueOf(base, converterFrom, converterTo); + return new FunctionalUnit(base, converterFrom, converterTo); + } + + /** + * Returns a unit from its base and the functions it uses to convert to and from its base. + * + *

+ * For example, to get a unit representing the degree Celsius, the following code can be used: + * + * {@code Unit.fromConversionFunctions(SI.KELVIN, tempK -> tempK - 273.15, tempC -> tempC + 273.15);} + *

+ * + * @param base + * unit's base + * @param converterFrom + * function that accepts a value expressed in the unit's base and returns that value expressed in this + * unit. + * @param converterTo + * function that accepts a value expressed in the unit and returns that value expressed in the unit's + * base. + * @param ns + * names and symbol of unit + * @return a unit that uses the provided functions to convert. + * @since 2019-05-22 + * @throws NullPointerException + * if any argument is null + */ + public static final Unit fromConversionFunctions(final ObjectProduct base, + final DoubleUnaryOperator converterFrom, final DoubleUnaryOperator converterTo, final NameSymbol ns) { + return new FunctionalUnit(base, converterFrom, converterTo, ns); } /** @@ -64,6 +314,21 @@ public abstract class Unit { */ private final ObjectProduct unitBase; + /** + * The primary name used by this unit. + */ + private final Optional primaryName; + + /** + * A short symbol used to represent this unit. + */ + private final Optional symbol; + + /** + * A set of any additional names and/or spellings that the unit uses. + */ + private final Set otherNames; + /** * Cache storing the result of getDimension() * @@ -72,27 +337,37 @@ public abstract class Unit { private transient ObjectProduct dimension = null; /** - * A constructor that constructs {@code BaseUnit} instances. + * Creates the {@code AbstractUnit}. * + * @param unitBase + * base of unit + * @param ns + * names and symbol of unit * @since 2019-10-16 + * @throws NullPointerException + * if unitBase or ns is null */ - Unit() { - if (this instanceof BaseUnit) { - this.unitBase = ObjectProduct.oneOf((BaseUnit) this); - } else - throw new AssertionError(); + protected Unit(final ObjectProduct unitBase, final NameSymbol ns) { + this.unitBase = Objects.requireNonNull(unitBase, "unitBase must not be null."); + this.primaryName = Objects.requireNonNull(ns, "ns must not be null.").getPrimaryName(); + this.symbol = ns.getSymbol(); + this.otherNames = ns.getOtherNames(); } /** - * Creates the {@code AbstractUnit}. + * A constructor that constructs {@code BaseUnit} instances. * - * @param unitBase * @since 2019-10-16 - * @throws NullPointerException - * if unitBase is null */ - protected Unit(final ObjectProduct unitBase) { - this.unitBase = Objects.requireNonNull(unitBase, "unitBase must not be null."); + Unit(final String primaryName, final String symbol, final Set otherNames) { + if (this instanceof BaseUnit) { + this.unitBase = ObjectProduct.oneOf((BaseUnit) this); + } else + throw new AssertionError(); + this.primaryName = Optional.of(primaryName); + this.symbol = Optional.of(symbol); + this.otherNames = Collections.unmodifiableSet( + new HashSet<>(Objects.requireNonNull(otherNames, "additionalNames must not be null."))); } /** @@ -208,8 +483,34 @@ public abstract class Unit { return this.dimension; } + /** + * @return additionalNames + * @since 2019-10-21 + */ + public final Set getOtherNames() { + return this.otherNames; + } + + /** + * @return primaryName + * @since 2019-10-21 + */ + public final Optional getPrimaryName() { + return this.primaryName; + } + + /** + * @return symbol + * @since 2019-10-21 + */ + public final Optional getSymbol() { + return this.symbol; + } + @Override public String toString() { - return "Unit derived from base " + this.getBase().toString(); + return this.getPrimaryName().orElse("Unnamed unit") + + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : "") + + ", derived from " + this.getBase().toString(); } } -- cgit v1.2.3 From 8ec94bea790cc010c29cd8de86e47117ff331979 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 21 Oct 2019 21:41:26 -0400 Subject: Added new ways to create named units. --- src/org/unitConverter/unit/BaseUnit.java | 11 ++++++ src/org/unitConverter/unit/LinearUnit.java | 56 ++++++++++++++++++++++++++++-- src/org/unitConverter/unit/Unit.java | 13 +++++++ 3 files changed, 77 insertions(+), 3 deletions(-) (limited to 'src/org/unitConverter/unit/Unit.java') diff --git a/src/org/unitConverter/unit/BaseUnit.java b/src/org/unitConverter/unit/BaseUnit.java index 8fd0664..e9ef3fa 100644 --- a/src/org/unitConverter/unit/BaseUnit.java +++ b/src/org/unitConverter/unit/BaseUnit.java @@ -118,4 +118,15 @@ public final class BaseUnit extends Unit { return this.getPrimaryName().orElse("Unnamed unit") + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : ""); } + + @Override + public BaseUnit withName(final NameSymbol ns) { + Objects.requireNonNull(ns, "ns must not be null."); + if (!ns.getPrimaryName().isPresent()) + throw new IllegalArgumentException("BaseUnits must have primary names."); + if (!ns.getSymbol().isPresent()) + throw new IllegalArgumentException("BaseUnits must have symbols."); + return BaseUnit.valueOf(this.getBaseDimension(), ns.getPrimaryName().get(), ns.getSymbol().get(), + ns.getOtherNames()); + } } diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java index 2a55dea..7b7338b 100644 --- a/src/org/unitConverter/unit/LinearUnit.java +++ b/src/org/unitConverter/unit/LinearUnit.java @@ -38,9 +38,32 @@ public final class LinearUnit extends Unit { * value to convert * @return value expressed as a {@code LinearUnit} * @since 2019-10-16 + * @throws NullPointerException + * if unit is null */ public static LinearUnit fromUnitValue(final Unit unit, final double value) { - return new LinearUnit(unit.getBase(), NameSymbol.EMPTY, unit.convertToBase(value)); + return new LinearUnit(Objects.requireNonNull(unit, "unit must not be null.").getBase(), + unit.convertToBase(value), NameSymbol.EMPTY); + } + + /** + * Gets a {@code LinearUnit} from a unit and a value. For example, converts '59 °F' to a linear unit with the value + * of '288.15 K' + * + * @param unit + * unit to convert + * @param value + * value to convert + * @param ns + * name(s) and symbol of unit + * @return value expressed as a {@code LinearUnit} + * @since 2019-10-21 + * @throws NullPointerException + * if unit or ns is null + */ + public static LinearUnit fromUnitValue(final Unit unit, final double value, final NameSymbol ns) { + return new LinearUnit(Objects.requireNonNull(unit, "unit must not be null.").getBase(), + unit.convertToBase(value), ns); } /** @@ -53,9 +76,31 @@ public final class LinearUnit extends Unit { * number to multiply base by * @return product of base and conversion factor * @since 2019-10-16 + * @throws NullPointerException + * if unitBase is null */ public static LinearUnit valueOf(final ObjectProduct unitBase, final double conversionFactor) { - return new LinearUnit(unitBase, NameSymbol.EMPTY, conversionFactor); + return new LinearUnit(unitBase, conversionFactor, NameSymbol.EMPTY); + } + + /** + * Gets a {@code LinearUnit} from a unit base and a conversion factor. In other words, gets the product of + * {@code unitBase} and {@code conversionFactor}, expressed as a {@code LinearUnit}. + * + * @param unitBase + * unit base to multiply by + * @param conversionFactor + * number to multiply base by + * @param ns + * name(s) and symbol of unit + * @return product of base and conversion factor + * @since 2019-10-21 + * @throws NullPointerException + * if unitBase is null + */ + public static LinearUnit valueOf(final ObjectProduct unitBase, final double conversionFactor, + final NameSymbol ns) { + return new LinearUnit(unitBase, conversionFactor, ns); } /** @@ -78,7 +123,7 @@ public final class LinearUnit extends Unit { * conversion factor between base and unit * @since 2019-10-16 */ - private LinearUnit(final ObjectProduct unitBase, final NameSymbol ns, final double conversionFactor) { + private LinearUnit(final ObjectProduct unitBase, final double conversionFactor, final NameSymbol ns) { super(unitBase, ns); this.conversionFactor = conversionFactor; } @@ -275,6 +320,11 @@ public final class LinearUnit extends Unit { + Double.toString(this.conversionFactor) + " * " + this.getBase().toString(u -> u.getSymbol().get()); } + @Override + public LinearUnit withName(final NameSymbol ns) { + return valueOf(this.getBase(), this.getConversionFactor(), ns); + } + /** * Returns the result of applying {@code prefix} to this unit. * diff --git a/src/org/unitConverter/unit/Unit.java b/src/org/unitConverter/unit/Unit.java index d65e14f..d848ea1 100644 --- a/src/org/unitConverter/unit/Unit.java +++ b/src/org/unitConverter/unit/Unit.java @@ -513,4 +513,17 @@ public abstract class Unit { + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : "") + ", derived from " + this.getBase().toString(); } + + /** + * @param ns + * name(s) and symbol to use + * @return a copy of this unit with provided name(s) and symbol + * @since 2019-10-21 + * @throws NullPointerException + * if ns is null + */ + public Unit withName(final NameSymbol ns) { + return fromConversionFunctions(this.getBase(), this::convertFromBase, this::convertToBase, + Objects.requireNonNull(ns, "ns must not be null.")); + } } -- cgit v1.2.3