/** * Copyright (C) 2020 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 . */ package sevenUnits.unit; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import sevenUnits.math.ObjectProduct; /** * A combination of units, like "5 foot + 7 inch". All but the last units should * have a whole number value associated with them. * * @since 2020-10-02 */ public final class MultiUnit extends Unitlike> { /** * Creates a {@code MultiUnit} from its units. It will not have a name or * symbol. * * @since 2020-10-03 */ public static final MultiUnit of(LinearUnit... units) { return of(Arrays.asList(units)); } /** * Creates a {@code MultiUnit} from its units. It will not have a name or * symbol. * * @since 2020-10-03 */ public static final MultiUnit of(List units) { if (units.size() < 1) throw new IllegalArgumentException("Must have at least one unit"); final ObjectProduct unitBase = units.get(0).getBase(); for (final LinearUnit unit : units) { if (!unitBase.equals(unit.getBase())) throw new IllegalArgumentException( "All units must have the same base."); } return new MultiUnit(new ArrayList<>(units), unitBase, NameSymbol.EMPTY); } /** * The units that make up this value. */ private final List units; /** * Creates a {@code MultiUnit}. * * @since 2020-10-03 */ private MultiUnit(List units, ObjectProduct unitBase, NameSymbol ns) { super(unitBase, ns); this.units = units; } @Override protected List convertFromBase(double value) { final List values = new ArrayList<>(this.units.size()); double temp = value; for (final LinearUnit unit : this.units.subList(0, this.units.size() - 1)) { values.add(Math.floor(temp / unit.getConversionFactor())); temp %= unit.getConversionFactor(); } values.add(this.units.size() - 1, this.units.get(this.units.size() - 1).convertFromBase(temp)); return values; } /** * Converts a value expressed in this unitlike form to a value expressed in * {@code other}. * * @implSpec If conversion is possible, this implementation returns * {@code other.convertFromBase(this.convertToBase(value))}. * Therefore, overriding either of those methods will change the * output of this method. * * @param other unit to convert to * @param value value to convert * @return converted value * @since 2020-10-03 * @throws IllegalArgumentException if {@code other} is incompatible for * conversion with this unitlike form (as * tested by {@link Unit#canConvertTo}). * @throws NullPointerException if other is null */ public final , V> V convertTo(U other, double... values) { final List valueList = new ArrayList<>(values.length); for (final double d : values) { valueList.add(d); } return this.convertTo(other, valueList); } /** * Converts a value expressed in this unitlike form to a value expressed in * {@code other}. * * @implSpec If conversion is possible, this implementation returns * {@code other.convertFromBase(this.convertToBase(value))}. * Therefore, overriding either of those methods will change the * output of this method. * * @param other unit to convert to * @param value value to convert * @return converted value * @since 2020-10-03 * @throws IllegalArgumentException if {@code other} is incompatible for * conversion with this unitlike form (as * tested by {@link Unit#canConvertTo}). * @throws NullPointerException if other is null */ public final double convertTo(Unit other, double... values) { final List valueList = new ArrayList<>(values.length); for (final double d : values) { valueList.add(d); } return this.convertTo(other, valueList); } @Override protected double convertToBase(List value) { if (value.size() != this.units.size()) throw new IllegalArgumentException("Wrong number of values for " + this.units.size() + "-unit MultiUnit."); double baseValue = 0; for (int i = 0; i < this.units.size(); i++) { baseValue += value.get(i) * this.units.get(i).getConversionFactor(); } return baseValue; } }