001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2021, Jean-Marie Dautelle, Werner Keil, Otavio Santana. 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, Indriya 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.units.indriya.unit; 031 032import java.util.Map; 033import java.util.Objects; 034 035import javax.measure.Dimension; 036import javax.measure.Quantity; 037import javax.measure.Unit; 038import javax.measure.UnitConverter; 039 040import tech.units.indriya.AbstractUnit; 041import tech.uom.lib.common.function.UnitConverterSupplier; 042 043/** 044 * <p> 045 * This class represents the units derived from other units using {@linkplain UnitConverter converters}. 046 * </p> 047 * 048 * <p> 049 * Examples of transformed units:<code> 050 * CELSIUS = KELVIN.shift(273.15); 051 * FOOT = METRE.multiply(3048).divide(10000); 052 * MILLISECOND = MILLI(SECOND); 053 * </code> 054 * </p> 055 * 056 * <p> 057 * Transformed units have no symbol. But like any other units, they may have labels attached to them (see 058 * {@link javax.measure.format.UnitFormat#label(Unit, String) UnitFormat.label} 059 * </p> 060 * 061 * <p> 062 * Instances of this class are created through the {@link AbstractUnit#transform} method. 063 * </p> 064 * 065 * @param <Q> 066 * The type of the quantity measured by this unit. 067 * 068 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 069 * @author <a href="mailto:werner@units.tech">Werner Keil</a> 070 * @version 2.0, March 1, 2020 071 * @since 1.0 072 */ 073public final class TransformedUnit<Q extends Quantity<Q>> extends AbstractUnit<Q> implements UnitConverterSupplier { 074 075 /** 076 * 077 */ 078 private static final long serialVersionUID = 1L; 079 080 /** 081 * Holds the parent unit. 082 */ 083 private final AbstractUnit<Q> parentUnit; 084 085 /** 086 * Holds the system unit. 087 */ 088 private final Unit<Q> systemUnit; 089 090 /** 091 * Holds the converter to the parent unit. 092 */ 093 private final UnitConverter converter; 094 095 /** 096 * Creates a transformed unit from the specified system unit. using the parent as symbol 097 * 098 * @param parentUnit 099 * the system unit from which this unit is derived. 100 * @param converter 101 * the converter to the parent units. 102 */ 103 public TransformedUnit(Unit<Q> parentUnit, UnitConverter unitConverter) { 104 this(null, parentUnit, unitConverter); 105 } 106 107 /** 108 * Creates a transformed unit from the specified parent unit. 109 * 110 * @param symbol 111 * the symbol to use with this transformed unit. 112 * @param name 113 * the name to use with this transformed unit. 114 * @param parentUnit 115 * the parent unit from which this unit is derived. 116 * @param unitConverter 117 * the converter to the parent units. 118 * @since 2.0 119 */ 120 public TransformedUnit(String symbol, String name, Unit<Q> parentUnit, UnitConverter unitConverter) { 121 this(symbol, name, parentUnit, parentUnit.getSystemUnit(), unitConverter); 122 } 123 124 /** 125 * Creates a transformed unit from the specified parent unit. 126 * 127 * @param symbol 128 * the symbol to use with this transformed unit. 129 * @param parentUnit 130 * the parent unit from which this unit is derived. 131 * @param unitConverter 132 * the converter to the parent units. 133 */ 134 public TransformedUnit(String symbol, Unit<Q> parentUnit, UnitConverter unitConverter) { 135 this(symbol, parentUnit, parentUnit.getSystemUnit(), unitConverter); 136 } 137 138 /** 139 * Creates a transformed unit from the specified parent and system unit. using a specific symbol and name. 140 * 141 * @param symbol 142 * the symbol for this unit. 143 * @param name 144 * the name for this unit. 145 * @param parentUnit 146 * the parent unit from which this unit is derived. 147 * @param sysUnit 148 * the system unit which this unit is based on. 149 * @param converter 150 * the converter to the parent units. 151 * @since 2.0 152 */ 153 public TransformedUnit(String symbol, String name, Unit<Q> parentUnit, Unit<Q> sysUnit, UnitConverter unitConverter) { 154 if (parentUnit instanceof AbstractUnit) { 155 final AbstractUnit<Q> abParent = (AbstractUnit<Q>) parentUnit; 156 157 this.systemUnit = sysUnit; 158 // if (!abParent.isSystemUnit()) { 159 // throw new IllegalArgumentException("The parent unit: " + abParent 160 // + " is not a system unit"); 161 // } 162 this.parentUnit = abParent; 163 this.converter = unitConverter; 164 setSymbol(symbol); 165 // see https://github.com/unitsofmeasurement/uom-se/issues/54 166 setName(name); 167 } else { 168 throw new IllegalArgumentException("The parent unit: " + parentUnit + " is not an abstract unit."); 169 } 170 } 171 172 /** 173 * Creates a transformed unit from the specified parent and system unit. using a specific symbol. 174 * 175 * @param symbol 176 * the symbol for this unit. 177 * @param parentUnit 178 * the parent unit from which this unit is derived. 179 * @param sysUnit 180 * the system unit which this unit is based on. 181 * @param converter 182 * the converter to the parent units. 183 */ 184 public TransformedUnit(String symbol, Unit<Q> parentUnit, Unit<Q> sysUnit, UnitConverter unitConverter) { 185 this(symbol, null, parentUnit, sysUnit, unitConverter); 186 } 187 188 @Override 189 public Dimension getDimension() { 190 return parentUnit.getDimension(); 191 } 192 193 @Override 194 public UnitConverter getSystemConverter() { 195 return parentUnit.getSystemConverter().concatenate(converter); 196 } 197 198 /** 199 * Returns the converter to the parent unit. 200 * 201 * @return the converter to the parent unit. 202 */ 203 @Override 204 public UnitConverter getConverter() { 205 return converter; 206 } 207 208 @Override 209 protected Unit<Q> toSystemUnit() { 210 return (systemUnit != null ? systemUnit : parentUnit.getSystemUnit()); 211 } 212 213 @Override 214 public Map<? extends Unit<?>, Integer> getBaseUnits() { 215 return parentUnit.getBaseUnits(); 216 } 217 218 @Override 219 public int hashCode() { 220 return Objects.hash(parentUnit, converter); 221 } 222 223 @Override 224 public boolean equals(Object obj) { 225 if (this == obj) { 226 return true; 227 } 228 if (obj instanceof TransformedUnit) { 229 TransformedUnit<?> other = (TransformedUnit<?>) obj; 230 return Objects.equals(parentUnit, other.parentUnit) 231 && Objects.equals(converter, other.converter); 232 } 233 return false; 234 } 235 236 /** 237 * Returns the parent unit for this unit. The parent unit is the untransformed unit from which this unit is derived. 238 * 239 * @return the untransformed unit from which this unit is derived. 240 */ 241 public Unit<Q> getParentUnit() { 242 return parentUnit; 243 } 244}