001/* 002 * Units of Measurement Enum Implementation 003 * Copyright © 2005-2021, Werner Keil and others. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-385, Unit-API nor the names of their contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tech.uom.impl.enums; 031 032import tech.uom.lib.common.function.DoubleFactorSupplier; 033import tech.uom.lib.common.function.QuantityConverter; 034import tech.uom.impl.enums.format.UnitStyle; 035 036import java.util.Objects; 037 038import javax.measure.Quantity; 039import javax.measure.Unit; 040 041/** 042 * @author Werner Keil 043 * @version 2.1, $Date: 2020-12-06 $ 044 * @since 1.0 045 */ 046public abstract class AbstractQuantity<Q extends Quantity<Q>> implements 047 Quantity<Q>, QuantityConverter<Q>, Comparable<Quantity<Q>> { 048 049 protected abstract Number getScalar(); 050 051 protected abstract boolean eq(AbstractQuantity<Q> dq); 052 053 protected abstract boolean isZero(); 054 055 private final Scale scale; 056 057 /** 058 * Constructor. 059 * @param scale a scale of measurement 060 */ 061 protected AbstractQuantity(Scale scale) { 062 this.scale = scale; 063 } 064 065 /** 066 * Constructor. 067 */ 068 protected AbstractQuantity() { 069 this(Scale.ABSOLUTE); 070 } 071 072 @SuppressWarnings("unchecked") 073 @Override 074 public boolean equals(Object o) { 075 if (o instanceof AbstractQuantity) { 076 return eq((AbstractQuantity<Q>) o); 077 } 078 return false; 079 } 080 081 @Override 082 public boolean isEquivalentTo(Quantity<Q> that) { 083 return this.compareTo(that) == 0; 084 } 085 086 /** 087 * Returns the measurement level. 088 * 089 * @return the measurement level. 090 * @since 2.0 091 */ 092 @Override 093 public Scale getScale() { 094 return scale; 095 } 096 097 /** 098 * Returns the hash code for this measure. 099 * 100 * @return the hash code value. 101 */ 102 @Override 103 public int hashCode() { 104 return Objects.hash(getValue(), getUnit(), getScale()); 105 } 106 107 public abstract String toString(boolean withUnit, boolean withSpace, 108 int precision); 109 110 public String toString(boolean withUnit, boolean withSpace) { 111 return toString(withUnit, withSpace, 0); 112 } 113 114 /** 115 * Casts this quantity to a parameterized quantity of specified nature or throw a 116 * <code>ClassCastException</code> if the dimension of the specified 117 * quantity and its unit's dimension do not match. For 118 * example:<br><code> 119 * Quantity<Length> length = BaseQuantity.of("2 km").asType(Length.class); 120 * </code> 121 * 122 * @param type the quantity class identifying the nature of the measure. 123 * @return this measure parameterized with the specified type. 124 * @throws ClassCastException if the dimension of this unit is different 125 * from the specified quantity dimension. 126 * @throws UnsupportedOperationException 127 * if the specified quantity class does not have a public static 128 * field named "UNIT" holding the SI unit for the quantity. 129 * @see Unit#asType(Class) 130 */ 131 @SuppressWarnings("unchecked") 132 public final <T extends Quantity<T>> AbstractQuantity<T> asType(Class<T> type) 133 throws ClassCastException { 134 this.getUnit().asType(type); // Raises ClassCastException if dimension mismatches. 135 return (AbstractQuantity<T>) this; 136 } 137 138 protected String toString(boolean withSpace) { 139 return toString(true, withSpace); 140 } 141 142 protected String toString(int precision) { 143 return toString(true, false, precision); 144 } 145 146 @Override 147 public String toString() { 148 return toString(true); 149 } 150 151 protected abstract String showInUnit(Unit<?> u, int precision, 152 UnitStyle style); 153 154 protected String showInUnit(Unit<?> u, Number s, int precision, 155 UnitStyle style, boolean withSpace) { 156 if (u == null) { 157 throw new IllegalArgumentException("Null unit not allowed!"); //$NON-NLS-1$ 158 } 159 double result; 160 if (u instanceof DoubleFactorSupplier) { 161 result = s.doubleValue() / ((DoubleFactorSupplier)u).getFactor(); 162 } else { 163 result = s.doubleValue(); 164 } 165 166 final String str = getStr(Double.valueOf(result), precision); 167 StringBuilder sb; 168 switch (style) { 169 case NAME: 170 sb = new StringBuilder(str); 171 if (withSpace) sb.append(' '); 172 return sb.append(u.getName()).toString(); 173 //return str; 174 default: 175 sb = new StringBuilder(str); 176 if (withSpace) sb.append(' '); 177 return sb.append(u.getSymbol()).toString(); 178 } 179 } 180 181 protected String showInUnit(Unit<?> u, Double s, int precision, 182 UnitStyle style) { 183 return showInUnit(u, s, precision, style, true); 184 } 185 186 /** 187 * 188 * @param u 189 * @param precision number of decimal places 190 * @return 191 */ 192 protected String showInUnit(Unit<?> u, int precision) { 193 return showInUnit(u, precision, UnitStyle.SYMBOL); 194 } 195 196 protected String getStr(Number val, int precision) { 197// if (val instanceof BigDecimal) { //TODO for #JavaME disable that part 198// BigDecimal num = ((BigDecimal)val).setScale(precision, RoundingMode.HALF_UP); 199// String str = num.toString(); 200// return str; 201// } 202 return String.valueOf(val); 203 } 204}