/** * 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 . */ package unitConverter.dimension; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; /** * An object that represents what a unit measures, like length, mass, area, energy, etc. * * @author Adrien Hopkins * @since 2018-12-11 * @since v0.1.0 */ public final class UnitDimension { /** * The unit dimension where every exponent is zero * * @since 2018-12-12 * @since v0.1.0 */ public static final UnitDimension EMPTY = new UnitDimension(new HashMap<>()); /** * Gets an UnitDimension that has 1 of a certain dimension and nothing else * * @param dimension * dimension to get * @return unit dimension * @since 2018-12-11 * @since v0.1.0 */ public static final UnitDimension getBase(final BaseDimension dimension) { final Map map = new HashMap<>(); map.put(dimension, 1); return new UnitDimension(map); } /** * The base dimensions that make up this dimension. * * @since 2018-12-11 * @since v0.1.0 */ final Map exponents; /** * Creates the {@code UnitDimension}. * * @param exponents * base dimensions that make up this dimension * @since 2018-12-11 * @since v0.1.0 */ private UnitDimension(final Map exponents) { this.exponents = new HashMap<>(exponents); } /** * Divides this dimension by another * * @param other * other dimension * @return quotient of two dimensions * @since 2018-12-11 * @since v0.1.0 */ public UnitDimension dividedBy(final UnitDimension other) { final Map map = new HashMap<>(this.exponents); for (final BaseDimension key : other.exponents.keySet()) { if (map.containsKey(key)) { // add the dimensions map.put(key, map.get(key) - other.exponents.get(key)); } else { map.put(key, -other.exponents.get(key)); } } return new UnitDimension(map); } @Override public boolean equals(final Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof UnitDimension)) return false; final UnitDimension other = (UnitDimension) obj; // anything with a value of 0 is equal to a nonexistent value for (final BaseDimension b : this.getBaseSet()) { if (this.exponents.get(b) != other.exponents.get(b)) if (!(this.exponents.get(b) == 0 && !other.exponents.containsKey(b))) return false; } for (final BaseDimension b : other.getBaseSet()) { if (this.exponents.get(b) != other.exponents.get(b)) if (!(other.exponents.get(b) == 0 && !this.exponents.containsKey(b))) return false; } return true; } /** * @return a set of all of the base dimensions with non-zero exponents that make up this dimension. * @since 2018-12-12 * @since v0.1.0 */ public final Set getBaseSet() { final Set dimensions = new HashSet<>(); // add all dimensions with a nonzero exponent - they shouldn't be there in the first place for (final BaseDimension dimension : this.exponents.keySet()) { if (!this.exponents.get(dimension).equals(0)) { dimensions.add(dimension); } } return dimensions; } /** * Gets the exponent for a specific dimension. * * @param dimension * dimension to check * @return exponent for that dimension * @since 2018-12-12 * @since v0.1.0 */ public int getExponent(final BaseDimension dimension) { return this.exponents.getOrDefault(dimension, 0); } @Override public int hashCode() { return Objects.hash(this.exponents); } /** * @return true if this dimension is a base, i.e. it has one exponent of one and no other nonzero exponents * @since 2019-01-15 * @since v0.1.0 */ public boolean isBase() { int oneCount = 0; boolean twoOrMore = false; // has exponents of 2 or more for (final BaseDimension b : this.getBaseSet()) { if (this.exponents.get(b) == 1) { oneCount++; } else if (this.exponents.get(b) != 0) { twoOrMore = true; } } return (oneCount == 0 || oneCount == 1) && !twoOrMore; } /** * Multiplies this dimension by another * * @param other * other dimension * @return product of two dimensions * @since 2018-12-11 * @since v0.1.0 */ public UnitDimension times(final UnitDimension other) { final Map map = new HashMap<>(this.exponents); for (final BaseDimension key : other.exponents.keySet()) { if (map.containsKey(key)) { // add the dimensions map.put(key, map.get(key) + other.exponents.get(key)); } else { map.put(key, other.exponents.get(key)); } } return new UnitDimension(map); } /** * Returns this dimension, but to an exponent * * @param exp * exponent * @return result of exponientation * @since 2019-01-15 * @since v0.1.0 */ public UnitDimension toExponent(final int exp) { final Map map = new HashMap<>(this.exponents); for (final BaseDimension key : this.exponents.keySet()) { map.put(key, this.getExponent(key) * exp); } return new UnitDimension(map); } @Override public String toString() { final List positiveStringComponents = new ArrayList<>(); final List negativeStringComponents = new ArrayList<>(); // for each base dimension that makes up this dimension, add it and its exponent for (final BaseDimension dimension : this.getBaseSet()) { final int exponent = this.exponents.get(dimension); if (exponent > 0) { positiveStringComponents.add(String.format("%s^%d", dimension.getSymbol(), exponent)); } else if (exponent < 0) { negativeStringComponents.add(String.format("%s^%d", dimension.getSymbol(), -exponent)); } } final String positiveString = positiveStringComponents.isEmpty() ? "1" : String.join(" ", positiveStringComponents); final String negativeString = negativeStringComponents.isEmpty() ? "" : " / " + String.join(" ", negativeStringComponents); return positiveString + negativeString; } }