Unit.java
package de.turnertech.measures;
import java.util.Objects;
import java.util.function.DoubleUnaryOperator;
/**
* A Unit is a single instance of a Measurement, such as a Metre or a Degree Celsius.
*/
public class Unit {
/** K */
public static final Unit KELVIN = new Unit("K");
/** Cel */
public static final Unit DEGREES_CELSIUS = new Unit("°C", KELVIN, (celsius) -> celsius + 273.15, (kelvin) -> kelvin - 273.15);
/** degF */
public static final Unit DEGREES_FAHRENHEIT = new Unit("°F", KELVIN, (fahrenheit) -> (fahrenheit - 32) * 5.0/9.0 + 273.15, (kelvin) -> (kelvin - 273.15) * 9/5 + 32);
/** m */
public static final Unit METRE = new Unit("m");
/** cm */
public static final Unit CENTIMETRE = new Unit("cm", METRE, (centimetre) -> centimetre * 0.01, (metre) -> metre * 100.0);
/** in_i */
public static final Unit INCH = new Unit("in", METRE, (inch) -> inch * 0.0254, (metre) -> metre / 0.0254);
/** ft_i */
public static final Unit FOOT = new Unit("ft", METRE, (foot) -> foot * 0.3048, (metre) -> metre / 0.3048);
/** yd_i */
public static final Unit YARD = new Unit("yd", METRE, (yard) -> yard * 0.9144, (metre) -> metre / 0.9144);
/** mi_i */
public static final Unit MILE = new Unit("mi", METRE, (mile) -> mile * 1609.344, (metre) -> metre / 1609.344);
/** km */
public static final Unit KILOMETRE = new Unit("km", METRE, (kilometer) -> kilometer * 1000.0, (metre) -> metre * 0.001);
/** nmi_i */
public static final Unit NAUTICAL_MILE = new Unit("NM", METRE, (nmi_i) -> nmi_i * 1852.0, (metre) -> metre / 1852.0);
/** s */
public static final Unit SECOND = new Unit("s");
/** g */
public static final Unit GRAM = new Unit("g");
/** lb_av */
public static final Unit POUND = new Unit("lb", Unit.GRAM, (gram) -> gram * 453.59237, (pound) -> pound / 453.59237);
/** deg */
public static final Unit DEGREE = new Unit("°");
/** ' */
public static final Unit MINUTE_ANGLE = new Unit("'", Unit.DEGREE, (min) -> min / 60.0, (deg) -> deg * 60.0);
/** " */
public static final Unit SECOND_ANGLE = new Unit("\"", Unit.DEGREE, (sec) -> sec / 3600.0, (deg) -> deg / 3600.0);
/** rad */
public static final Unit RADIAN = new Unit("rad", Unit.DEGREE, (rad) -> rad * 180.0 / Math.PI, (deg) -> deg * Math.PI / 180.0);
private final Unit baseUnit;
private final String symbol;
private final DoubleUnaryOperator toBaseUnitFunction;
private final DoubleUnaryOperator fromBaseUnitFunction;
/**
* Constructs a "Base Unit", where its own base unit is iteself, and
* conversions to and from its base unit will alway return the same value
* as input ({@link DoubleUnaryOperator#identity()}).
*/
public Unit() {
this("");
}
/**
* Constructs a "Base Unit", where its own base unit is iteself, and
* conversions to and from its base unit will alway return the same value
* as input ({@link DoubleUnaryOperator#identity()}).
*
* @param symbol may not be null.
*/
public Unit(final String symbol) {
this(symbol, null, DoubleUnaryOperator.identity(), DoubleUnaryOperator.identity());
}
/**
* Constructs a Unit with the supplied base unit and conversion functions
* too and from said Unit.
*
* @param baseUnit the unit to which the conversion functions will convert.
* Supplying null will make the base unit the unit itself (this).
* @param symbol may not be null.
* @param toBaseUnitFunction may not be null.
* @param fromBaseUnitFunction may not be null.
*/
public Unit(final String symbol, final Unit baseUnit, final DoubleUnaryOperator toBaseUnitFunction, final DoubleUnaryOperator fromBaseUnitFunction) {
this.baseUnit = Objects.requireNonNullElse(baseUnit, this);
this.symbol = Objects.requireNonNull(symbol);
this.toBaseUnitFunction = Objects.requireNonNull(toBaseUnitFunction);
this.fromBaseUnitFunction = Objects.requireNonNull(fromBaseUnitFunction);
}
/**
* Helper function for creating measures with a Unit.
*
* @param quantity the quantity of this unit which should be in the Measure.
* @return a new Measure instance.
*/
public Measure createMeasure(final double quantity) {
return new Measure(quantity, this);
}
/**
* Gets the common base unit for the family of units to which this Unit belongs. For example,
* Metres are the base Unit for all distance Units. Even Feet, Inches and Nautical Miles will
* share the same base unit of a Metre.
*
* @return the base unit for this Unit.
*/
public Unit getBaseUnit() {
return baseUnit;
}
/**
* Converts a supplied quantity of this Unit to a quantity of its base unit.
* For example supplying a quantity of 1 to this function on an instance of
* {@link Unit#KILOMETRE} will return 1000 (metres).
*
* @param quantity of this Unit to convert to the base unit.
* @return the quantity of the Base Unit which the supplied quantity represents.
*/
public Measure convertToBaseUnit(final double quantity) {
final Measure resultingValue = new Measure(toBaseUnitFunction.applyAsDouble(quantity), this.baseUnit);
if(quantity != Double.POSITIVE_INFINITY && quantity != Double.POSITIVE_INFINITY && (resultingValue.getQuantity() == Double.NEGATIVE_INFINITY || resultingValue.getQuantity() == Double.POSITIVE_INFINITY)) {
throw new ArithmeticException("Conversion caused overflow.");
}
return resultingValue;
}
/**
* Converts a supplied quantity of this Units base unit to a quantity of
* itself.
*
* @param quantity of this Unit base unit to convert to this unit.
* @return a measure with this Unit.
*/
public Measure convertFromBaseUnit(final double quantity) {
final Measure resultingValue = new Measure(fromBaseUnitFunction.applyAsDouble(quantity), this);
if(quantity != Double.POSITIVE_INFINITY && quantity != Double.POSITIVE_INFINITY && (resultingValue.getQuantity() == Double.NEGATIVE_INFINITY || resultingValue.getQuantity() == Double.POSITIVE_INFINITY)) {
throw new ArithmeticException("Conversion caused overflow.");
}
return resultingValue;
}
@Override
public String toString() {
return this.symbol;
}
}