1 package org.djunits.value.vfloat.scalar.base; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.InvocationTargetException; 5 import java.util.HashMap; 6 import java.util.Map; 7 8 import org.djunits.unit.AbsoluteLinearUnit; 9 import org.djunits.unit.SIUnit; 10 import org.djunits.unit.Unit; 11 import org.djunits.unit.util.UnitRuntimeException; 12 import org.djunits.value.vfloat.scalar.FloatSIScalar; 13 14 /** 15 * Static methods to create and operate on FloatScalars. 16 * <p> 17 * Copyright (c) 2015-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br> 18 * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>. 19 * <p> 20 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a> 21 * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a> 22 */ 23 public abstract class FloatScalar 24 { 25 /**********************************************************************************/ 26 /********************************* STATIC METHODS *********************************/ 27 /**********************************************************************************/ 28 29 /** The cache to make the lookup of the constructor for a Scalar belonging to a unit faster. */ 30 private static final Map<Unit<?>, Constructor<? extends FloatScalarInterface<?, ?>>> CACHE = new HashMap<>(); 31 32 /** Do not instantiate. */ 33 private FloatScalar() 34 { 35 // Utility class. 36 } 37 38 /** 39 * Instantiate the FloatScalar based on its unit. Rigid check on types by the compiler. 40 * @param value float; the value 41 * @param unit U; the unit in which the value is expressed 42 * @return S; an instantiated FloatScalar with the value expressed in the unit 43 * @param <U> the unit 44 * @param <S> the return type 45 */ 46 public static <U extends Unit<U>, S extends FloatScalarInterface<U, S>> S instantiate(final float value, final U unit) 47 { 48 return instantiateAnonymous(value, unit); 49 } 50 51 /** 52 * Instantiate the FloatScalar with an SI value and add the displayUnit later. Rigid check on types by the compiler. 53 * @param valueSI float; the SIvalue 54 * @param displayUnit U; the unit in which the value will be displayed 55 * @return S; an instantiated FloatScalar with the SI value and the display unit 56 * @param <U> the unit 57 * @param <S> the return type 58 */ 59 public static <U extends Unit<U>, S extends FloatScalarInterface<U, S>> S instantiateSI(final float valueSI, 60 final U displayUnit) 61 { 62 S result = instantiateAnonymous(valueSI, displayUnit.getStandardUnit()); 63 result.setDisplayUnit(displayUnit); 64 return result; 65 } 66 67 /** 68 * Instantiate the FloatScalar based on its unit. Loose check for types on the compiler. This allows the unit to be 69 * specified as a Unit<?> type.<br> 70 * <b>Note</b> that it is possible to make mistakes with anonymous units. 71 * @param value float; the value 72 * @param unit Unit<?>; the unit in which the value is expressed 73 * @return S; an instantiated FloatScalar with the value expressed in the unit 74 * @param <S> the return type 75 */ 76 @SuppressWarnings("unchecked") 77 public static <S extends FloatScalarInterface<?, S>> S instantiateAnonymous(final float value, final Unit<?> unit) 78 { 79 try 80 { 81 Constructor<? extends FloatScalarInterface<?, ?>> scalarConstructor = CACHE.get(unit); 82 if (scalarConstructor == null) 83 { 84 if (!unit.getClass().getSimpleName().endsWith("Unit")) 85 { 86 throw new ClassNotFoundException("Unit " + unit.getClass().getSimpleName() 87 + " name does noet end with 'Unit'. Cannot find corresponding scalar"); 88 } 89 Class<? extends FloatScalarInterface<?, ?>> scalarClass; 90 if (unit instanceof SIUnit) 91 { 92 scalarClass = FloatSIScalar.class; 93 } 94 else 95 { 96 scalarClass = (Class<FloatScalarInterface<?, ?>>) Class.forName( 97 "org.djunits.value.vfloat.scalar.Float" + unit.getClass().getSimpleName().replace("Unit", "")); 98 } 99 scalarConstructor = scalarClass.getDeclaredConstructor(float.class, unit.getClass()); 100 CACHE.put(unit, scalarConstructor); 101 } 102 return (S) scalarConstructor.newInstance(value, unit); 103 } 104 catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException 105 | IllegalAccessException | IllegalArgumentException | InvocationTargetException exception) 106 { 107 throw new UnitRuntimeException("Cannot instantiate FloatScalarInterface of unit " + unit.toString() + ". Reason: " 108 + exception.getMessage()); 109 } 110 } 111 112 /** 113 * Add a Relative value to an Absolute value. Return a new instance of the value. The unit of the return value will be the 114 * unit of the left argument. 115 * @param left A, an absolute typed FloatScalar; the left argument 116 * @param right R, a relative typed FloatScalar; the right argument 117 * @param <AU> Unit; the absolute unit of the parameters and the result 118 * @param <RU> Unit; the relative unit of the parameters and the result 119 * @param <R> the relative type 120 * @param <A> the corresponding absolute type 121 * @return A; an absolute typed FloatScalar; the sum of the values as an Absolute value 122 */ 123 public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>, 124 R extends FloatScalarInterface.RelWithAbs<AU, A, RU, R>, 125 A extends FloatScalarInterface.Abs<AU, A, RU, R>> A plus(final A left, final R right) 126 { 127 return left.plus(right); 128 } 129 130 /** 131 * Add an Absolute value to a Relative value. Return a new instance of the value. The unit of the return value will be the 132 * unit of the left argument. 133 * @param left A, an absolute typed FloatScalar; the left argument 134 * @param right R, a relative typed FloatScalar; the right argument 135 * @param <AU> Unit; the absolute unit of the parameters and the result 136 * @param <RU> Unit; the relative unit of the parameters and the result 137 * @param <R> the relative type 138 * @param <A> the corresponding absolute type 139 * @return A; an absolute typed FloatScalar; the sum of the values as an Absolute value 140 */ 141 public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>, 142 R extends FloatScalarInterface.RelWithAbs<AU, A, RU, R>, 143 A extends FloatScalarInterface.Abs<AU, A, RU, R>> A plus(final R left, final A right) 144 { 145 return right.plus(left); 146 } 147 148 /** 149 * Add a Relative value to a Relative value. Return a new instance of the value. The unit of the return value will be the 150 * unit of the left argument. 151 * @param left R, a relative typed FloatScalar; the left argument 152 * @param right R, a relative typed FloatScalar; the right argument 153 * @param <U> Unit; the unit of the parameters and the result 154 * @param <R> the relative type 155 * @return R; a relative typed FloatScalar; the sum of the values as a Relative value 156 */ 157 public static <U extends Unit<U>, R extends FloatScalarInterface.Rel<U, R>> R plus(final R left, final R right) 158 { 159 return left.plus(right); 160 } 161 162 /** 163 * Subtract a Relative value from an absolute value. Return a new instance of the value. The unit of the return value will 164 * be the unit of the left argument. 165 * @param left A, an absolute typed FloatScalar; the left value 166 * @param right R, a relative typed FloatScalar; the right value 167 * @param <AU> Unit; the absolute unit of the parameters and the result 168 * @param <RU> Unit; the relative unit of the parameters and the result 169 * @param <R> the relative type 170 * @param <A> the corresponding absolute type 171 * @return A; an absolute typed FloatScalar; the resulting value as an absolute value 172 */ 173 public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>, 174 R extends FloatScalarInterface.RelWithAbs<AU, A, RU, R>, 175 A extends FloatScalarInterface.Abs<AU, A, RU, R>> A minus(final A left, final R right) 176 { 177 return left.minus(right); 178 } 179 180 /** 181 * Subtract a relative value from a relative value. Return a new instance of the value. The unit of the value will be the 182 * unit of the first argument. 183 * @param left R, a relative typed FloatScalar; the left value 184 * @param right R, a relative typed FloatScalar; the right value 185 * @param <U> Unit; the unit of the parameters and the result 186 * @param <R> the relative type 187 * @return R; a relative typed FloatScalar; the resulting value as a relative value 188 */ 189 public static <U extends Unit<U>, R extends FloatScalarInterface.Rel<U, R>> R minus(final R left, final R right) 190 { 191 return left.minus(right); 192 } 193 194 /** 195 * Subtract two absolute values. Return a new instance of a relative value of the difference. The unit of the value will be 196 * the unit of the first argument. 197 * @param left A, an absolute typed FloatScalar; value 1 198 * @param right A, an absolute typed FloatScalar; value 2 199 * @param <AU> Unit; the absolute unit of the parameters and the result 200 * @param <RU> Unit; the relative unit of the parameters and the result 201 * @param <R> the relative type 202 * @param <A> the corresponding absolute type 203 * @return R; a relative typed FloatScalar; the difference of the two absolute values as a relative value 204 */ 205 public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>, 206 R extends FloatScalarInterface.RelWithAbs<AU, A, RU, R>, 207 A extends FloatScalarInterface.Abs<AU, A, RU, R>> R minus(final A left, final A right) 208 { 209 return left.minus(right); 210 } 211 212 /** 213 * Multiply two values; the result is a new instance with a different (existing or generated) SI unit. 214 * @param left FloatScalarInterface.Rel<?, ?>; the left operand 215 * @param right FloatScalarInterface.Rel<?, ?>; the right operand 216 * @return FloatScalar.Rel<SIUnit>; the product of the two values 217 */ 218 public static FloatSIScalar multiply(final FloatScalarInterface.Rel<?, ?> left, final FloatScalarInterface.Rel<?, ?> right) 219 { 220 SIUnit targetUnit = Unit.lookupOrCreateUnitWithSIDimensions(left.getDisplayUnit().getQuantity().getSiDimensions() 221 .plus(right.getDisplayUnit().getQuantity().getSiDimensions())); 222 return new FloatSIScalar(left.getSI() * right.getSI(), targetUnit); 223 } 224 225 /** 226 * Divide two values; the result is a new instance with a different (existing or generated) SI unit. 227 * @param left FloatScalarInterface.Rel<?, ?>; the left operand 228 * @param right FloatScalarInterface.Rel<?, ?>; the right operand 229 * @return FloatScalar.Rel<SIUnit>; the ratio of the two values 230 */ 231 public static FloatSIScalar divide(final FloatScalarInterface.Rel<?, ?> left, final FloatScalarInterface.Rel<?, ?> right) 232 { 233 SIUnit targetUnit = Unit.lookupOrCreateUnitWithSIDimensions(left.getDisplayUnit().getQuantity().getSiDimensions() 234 .minus(right.getDisplayUnit().getQuantity().getSiDimensions())); 235 return new FloatSIScalar(left.getSI() / right.getSI(), targetUnit); 236 } 237 238 /** 239 * Interpolate between two values. Made to be able to call e.g., Area a = FloatScalar.interpolate(a1, a2, 0.4); 240 * @param zero R; the low value 241 * @param one R; the high value 242 * @param ratio float; the ratio between 0 and 1, inclusive 243 * @param <U> Unit; the unit of the parameters and the result 244 * @param <R> the relative type 245 * @return R; an Absolute Scalar at the <code>ratio</code> between <code>zero</code> and <code>one</code> 246 */ 247 public static <U extends Unit<U>, R extends FloatScalarInterface.Rel<U, R>> R interpolate(final R zero, final R one, 248 final float ratio) 249 { 250 return zero.instantiateRel(zero.getInUnit() * (1 - ratio) + one.getInUnit(zero.getDisplayUnit()) * ratio, 251 zero.getDisplayUnit()); 252 } 253 254 /** 255 * Interpolate between two values. Made to be able to call e.g., Time t = FloatScalar.interpolate(t1, t2, 0.4); 256 * @param zero A; the low value 257 * @param one A; the high value 258 * @param ratio float; the ratio between 0 and 1, inclusive 259 * @param <AU> Unit; the absolute unit of the parameters and the result 260 * @param <RU> Unit; the relative unit of the parameters and the result 261 * @param <R> the relative type 262 * @param <A> the corresponding absolute type 263 * @return R; a Relative Scalar at the <code>ratio</code> between <code>zero</code> and <code>one</code> 264 */ 265 public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>, 266 R extends FloatScalarInterface.RelWithAbs<AU, A, RU, R>, 267 A extends FloatScalarInterface.Abs<AU, A, RU, R>> A interpolate(final A zero, final A one, final float ratio) 268 { 269 return zero.instantiateAbs(zero.getInUnit() * (1 - ratio) + one.getInUnit(zero.getDisplayUnit()) * ratio, 270 zero.getDisplayUnit()); 271 } 272 273 /** 274 * Return the maximum value of two relative scalars. 275 * @param r1 T; the first scalar 276 * @param r2 T; the second scalar 277 * @param <U> Unit; the unit of the parameters and the result 278 * @param <T> the argument and result type 279 * @return T; the maximum value of two relative scalars 280 */ 281 public static <U extends Unit<U>, T extends FloatScalarInterface<U, T>> T max(final T r1, final T r2) 282 { 283 return (r1.gt(r2)) ? r1 : r2; 284 } 285 286 /** 287 * Return the maximum value of more than two relative scalars. 288 * @param r1 T; the first scalar 289 * @param r2 T; the second scalar 290 * @param rn T...; the other scalars 291 * @param <U> Unit; the unit of the parameters and the result 292 * @param <T> the argument and result type 293 * @return T; the maximum value of more than two relative scalars 294 */ 295 @SafeVarargs 296 public static <U extends Unit<U>, T extends FloatScalarInterface<U, T>> T max(final T r1, final T r2, final T... rn) 297 { 298 T maxr = (r1.gt(r2)) ? r1 : r2; 299 for (T r : rn) 300 { 301 if (r.gt(maxr)) 302 { 303 maxr = r; 304 } 305 } 306 return maxr; 307 } 308 309 /** 310 * Return the minimum value of two relative scalars. 311 * @param r1 T; the first scalar 312 * @param r2 T; the second scalar 313 * @param <U> Unit; the unit of the parameters and the result 314 * @param <T> the argument and result type 315 * @return T; the minimum value of two relative scalars 316 */ 317 public static <U extends Unit<U>, T extends FloatScalarInterface<U, T>> T min(final T r1, final T r2) 318 { 319 return r1.lt(r2) ? r1 : r2; 320 } 321 322 /** 323 * Return the minimum value of more than two relative scalars. 324 * @param r1 T; the first scalar 325 * @param r2 T; the second scalar 326 * @param rn T...; the other scalars 327 * @param <U> Unit; the unit of the parameters and the result 328 * @param <T> the argument and result type 329 * @return T; the minimum value of more than two relative scalars 330 */ 331 @SafeVarargs 332 public static <U extends Unit<U>, T extends FloatScalarInterface<U, T>> T min(final T r1, final T r2, final T... rn) 333 { 334 T minr = r1.lt(r2) ? r1 : r2; 335 for (T r : rn) 336 { 337 if (r.lt(minr)) 338 { 339 minr = r; 340 } 341 } 342 return minr; 343 } 344 345 }