001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2020, Units of Measurement project. 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 1.2.1, October 12, 2018 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 parentUnit 113 * the parent unit from which this unit is derived. 114 * @param unitConverter 115 * the converter to the parent units. 116 */ 117 public TransformedUnit(String symbol, Unit<Q> parentUnit, UnitConverter unitConverter) { 118 this(symbol, parentUnit, parentUnit.getSystemUnit(), unitConverter); 119 } 120 121 /** 122 * Creates a transformed unit from the specified parent and system unit. using the parent as symbol 123 * 124 * @param parentUnit 125 * the parent unit from which this unit is derived. 126 * @param sysUnit 127 * the system unit which this unit is based on. 128 * @param converter 129 * the converter to the parent units. 130 */ 131 public TransformedUnit(String symbol, Unit<Q> parentUnit, Unit<Q> sysUnit, UnitConverter unitConverter) { 132 if (parentUnit instanceof AbstractUnit) { 133 final AbstractUnit<Q> abParent = (AbstractUnit<Q>) parentUnit; 134 135 this.systemUnit = sysUnit; 136 // if (!abParent.isSystemUnit()) { 137 // throw new IllegalArgumentException("The parent unit: " + abParent 138 // + " is not a system unit"); 139 // } 140 this.parentUnit = abParent; 141 this.converter = unitConverter; 142 setSymbol(symbol); 143 // see https://github.com/unitsofmeasurement/uom-se/issues/54 144 } else { 145 throw new IllegalArgumentException("The parent unit: " + parentUnit + " is not an abstract unit."); 146 } 147 } 148 149 @Override 150 public Dimension getDimension() { 151 return parentUnit.getDimension(); 152 } 153 154 @Override 155 public UnitConverter getSystemConverter() { 156 return parentUnit.getSystemConverter().concatenate(converter); 157 } 158 159 /** 160 * Returns the converter to the parent unit. 161 * 162 * @return the converter to the parent unit. 163 */ 164 @Override 165 public UnitConverter getConverter() { 166 return converter; 167 } 168 169 @Override 170 protected Unit<Q> toSystemUnit() { 171 return (systemUnit != null ? systemUnit : parentUnit.getSystemUnit()); 172 } 173 174 @Override 175 public Map<? extends Unit<?>, Integer> getBaseUnits() { 176 return parentUnit.getBaseUnits(); 177 } 178 179 @Override 180 public int hashCode() { 181 return Objects.hash(parentUnit, converter); 182 } 183 184 @Override 185 public boolean equals(Object obj) { 186 if (this == obj) { 187 return true; 188 } 189 if (obj instanceof TransformedUnit) { 190 TransformedUnit<?> other = (TransformedUnit<?>) obj; 191 return Objects.equals(parentUnit, other.parentUnit) 192 && Objects.equals(converter, other.converter); 193 } 194 return false; 195 } 196 197 /** 198 * Returns the parent unit for this unit. The parent unit is the untransformed unit from which this unit is derived. 199 * 200 * @return the untransformed unit from which this unit is derived. 201 */ 202 public Unit<Q> getParentUnit() { 203 return parentUnit; 204 } 205}