1 package org.djunits.value.vdouble.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.vdouble.scalar.SIScalar;
13
14 /**
15 * Static methods to create and operate on DoubleScalars.
16 * <p>
17 * Copyright (c) 2015-2022 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 DoubleScalar
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 DoubleScalarInterface<?, ?>>> CACHE = new HashMap<>();
31
32 /** Do not instantiate. */
33 private DoubleScalar()
34 {
35 // Utility class.
36 }
37
38 /**
39 * Instantiate the DoubleScalar based on its unit. Rigid check on types by the compiler.
40 * @param value double; the value
41 * @param unit U; the unit in which the value is expressed
42 * @return S; an instantiated DoubleScalar 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 DoubleScalarInterface<U, S>> S instantiate(final double value, final U unit)
47 {
48 return instantiateAnonymous(value, unit);
49 }
50
51 /**
52 * Instantiate the DoubleScalar with an SI value and add the displayUnit later. Rigid check on types by the compiler.
53 * @param valueSI double; the SIvalue
54 * @param displayUnit U; the unit in which the value will be displayed
55 * @return S; an instantiated DoubleScalar 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 DoubleScalarInterface<U, S>> S instantiateSI(final double 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 DoubleScalar 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 double; the value
72 * @param unit Unit<?>; the unit in which the value is expressed
73 * @return S; an instantiated DoubleScalar with the value expressed in the unit
74 * @param <S> the return type
75 */
76 @SuppressWarnings("unchecked")
77 public static <S extends DoubleScalarInterface<?, S>> S instantiateAnonymous(final double value, final Unit<?> unit)
78 {
79 try
80 {
81 Constructor<? extends DoubleScalarInterface<?, ?>> 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 DoubleScalarInterface<?, ?>> scalarClass;
90 if (unit instanceof SIUnit)
91 {
92 scalarClass = SIScalar.class;
93 }
94 else
95 {
96 scalarClass = (Class<DoubleScalarInterface<?, ?>>) Class
97 .forName("org.djunits.value.vdouble.scalar." + unit.getClass().getSimpleName().replace("Unit", ""));
98 }
99 scalarConstructor = scalarClass.getDeclaredConstructor(double.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 DoubleScalarInterface 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 DoubleScalar; the left argument
116 * @param right R, a relative typed DoubleScalar; 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 DoubleScalar; 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 DoubleScalarInterface.RelWithAbs<AU, A, RU, R>,
125 A extends DoubleScalarInterface.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 DoubleScalar; the left argument
134 * @param right R, a relative typed DoubleScalar; 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 DoubleScalar; 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 DoubleScalarInterface.RelWithAbs<AU, A, RU, R>,
143 A extends DoubleScalarInterface.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 DoubleScalar; the left argument
152 * @param right R, a relative typed DoubleScalar; 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 DoubleScalar; the sum of the values as a Relative value
156 */
157 public static <U extends Unit<U>, R extends DoubleScalarInterface.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 DoubleScalar; the left value
166 * @param right R, a relative typed DoubleScalar; 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 DoubleScalar; the resulting value as an absolute value
172 */
173 public static <AU extends AbsoluteLinearUnit<AU, RU>, RU extends Unit<RU>,
174 R extends DoubleScalarInterface.RelWithAbs<AU, A, RU, R>,
175 A extends DoubleScalarInterface.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 DoubleScalar; the left value
184 * @param right R, a relative typed DoubleScalar; 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 DoubleScalar; the resulting value as a relative value
188 */
189 public static <U extends Unit<U>, R extends DoubleScalarInterface.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 DoubleScalar; value 1
198 * @param right A, an absolute typed DoubleScalar; 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 DoubleScalar; 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 DoubleScalarInterface.RelWithAbs<AU, A, RU, R>,
207 A extends DoubleScalarInterface.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 DoubleScalarInterface.Rel<?, ?>; the left operand
215 * @param right DoubleScalarInterface.Rel<?, ?>; the right operand
216 * @return DoubleScalar.Rel<SIUnit>; the product of the two values
217 */
218 public static SIScalar multiply(final DoubleScalarInterface.Rel<?, ?> left, final DoubleScalarInterface.Rel<?, ?> right)
219 {
220 SIUnit targetUnit = Unit.lookupOrCreateUnitWithSIDimensions(left.getDisplayUnit().getQuantity().getSiDimensions()
221 .plus(right.getDisplayUnit().getQuantity().getSiDimensions()));
222 return new SIScalar(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 DoubleScalarInterface.Rel<?, ?>; the left operand
228 * @param right DoubleScalarInterface.Rel<?, ?>; the right operand
229 * @return DoubleScalar.Rel<SIUnit>; the ratio of the two values
230 */
231 public static SIScalar divide(final DoubleScalarInterface.Rel<?, ?> left, final DoubleScalarInterface.Rel<?, ?> right)
232 {
233 SIUnit targetUnit = Unit.lookupOrCreateUnitWithSIDimensions(left.getDisplayUnit().getQuantity().getSiDimensions()
234 .minus(right.getDisplayUnit().getQuantity().getSiDimensions()));
235 return new SIScalar(left.getSI() / right.getSI(), targetUnit);
236 }
237
238 /**
239 * Interpolate between two values. Made to be able to call e.g., Area a = DoubleScalar.interpolate(a1, a2, 0.4);
240 * @param zero R; the low value
241 * @param one R; the high value
242 * @param ratio double; 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 DoubleScalarInterface.Rel<U, R>> R interpolate(final R zero, final R one,
248 final double 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 = DoubleScalar.interpolate(t1, t2, 0.4);
256 * @param zero A; the low value
257 * @param one A; the high value
258 * @param ratio double; 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 DoubleScalarInterface.RelWithAbs<AU, A, RU, R>,
267 A extends DoubleScalarInterface.Abs<AU, A, RU, R>> A interpolate(final A zero, final A one, final double 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 DoubleScalarInterface<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 DoubleScalarInterface<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 DoubleScalarInterface<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 DoubleScalarInterface<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 }