View Javadoc
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&lt;?&gt; 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&lt;?&gt;; 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&lt;?, ?&gt;; the left operand
215      * @param right FloatScalarInterface.Rel&lt;?, ?&gt;; the right operand
216      * @return FloatScalar.Rel&lt;SIUnit&gt;; 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&lt;?, ?&gt;; the left operand
228      * @param right FloatScalarInterface.Rel&lt;?, ?&gt;; the right operand
229      * @return FloatScalar.Rel&lt;SIUnit&gt;; 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 }