1 package org.djunits.formatter;
2
3 import org.djunits.quantity.LinearObjectDensity;
4 import org.djunits.quantity.Mass;
5 import org.djunits.unit.si.SIPrefixes;
6 import org.djutils.exceptions.Throw;
7
8 /**
9 * QuantityFormat stores the settings that influence both the value part and the unit part of an output string when formatting a
10 * quantity.
11 * <p>
12 * Copyright (c) 2026-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
13 * for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
14 * distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
15 * @author Alexander Verbraeck
16 */
17 public class QuantityFormat extends Format<QuantityFormat, QuantityFormatContext>
18 {
19 /** The defaults (which can be changed). */
20 @SuppressWarnings("checkstyle:staticvariablename")
21 private static QuantityFormatContext DEFAULT = new QuantityFormatContext();
22
23 /**
24 * Construct a QuantityFormat object with a given context. Note that the context can be an existing context that is being
25 * modified or a default context.
26 * @param ctx the quantity format context to use
27 */
28 protected QuantityFormat(final QuantityFormatContext ctx)
29 {
30 super(ctx);
31 }
32
33 /**
34 * Return an instance of QuantityFormat, initialized with the default values.
35 * @return an instance of QuantityFormat, initialized with the default values
36 */
37 public static QuantityFormat instance()
38 {
39 return new QuantityFormat(DEFAULT.clone());
40 }
41
42 /**
43 * Return an instance of QuantityFormat with the DEFAULT values, which can be changed for all subsequent calls.
44 * @return an instance of QuantityFormat with the DEFAULT values
45 */
46 public static QuantityFormat changeDefaults()
47 {
48 return new QuantityFormat(DEFAULT);
49 }
50
51 /**
52 * Reset the default values of QuantityFormat to their original values.
53 */
54 public static void resetDefaults()
55 {
56 DEFAULT = new QuantityFormatContext();
57 }
58
59 /**
60 * Turn on the automatic allocation of the unit to its closest SI prefix. E.g., turn 20400 m into "20.4 km".
61 * @return QuantityFormat object for fluent design
62 */
63 public QuantityFormat setAutoSiPrefix()
64 {
65 this.ctx.autoSiPrefix = true;
66 return this;
67 }
68
69 /**
70 * Turn on the automatic allocation of the unit to its closest SI prefix, in case the exponent of the 10-power in scientific
71 * notation is between minExponent and maxExponent, inclusive. E.g., format 20400 m as "20.4 km" after calling
72 * setAutoSiPrefix(-9,9) but format it as 20400 m after calling setAutoSiPrefix(-9,0). Note that the kg for {@link Mass} is
73 * associated with an exponent of 3, and the g with an exponent of 0. For the {@link LinearObjectDensity} that is expressed
74 * in /m, /km is associated with an exponent of 3 and /mm with an exponent of -3. Note that the minimum and maximum
75 * exponents are clamped between -30 and 30.
76 * @param minExponent minimum exponent for the 10-power in scientific notation to use SI prefixes for (inclusive)
77 * @param maxExponent maximum exponent for the 10-power in scientific notation to use SI prefixes for (inclusive)
78 * @return QuantityFormat object for fluent design
79 * @throws IllegalArgumentException when minExponent > maxExponent
80 */
81 public QuantityFormat setAutoSiPrefix(final int minExponent, final int maxExponent)
82 {
83 Throw.when(minExponent > maxExponent, IllegalArgumentException.class, "minExponent %d > maxExponent %d", minExponent,
84 maxExponent);
85 this.ctx.autoSiPrefix = true;
86 this.ctx.autoSiMinExponent = Math.min(30, Math.max(-30, minExponent));
87 this.ctx.autoSiMaxExponent = Math.min(30, Math.max(-30, maxExponent));
88 return this;
89 }
90
91 /**
92 * Turn on the automatic allocation of the unit to its closest SI prefix, in case the exponent of the 10-power in scientific
93 * notation is between minExponent and maxExponent, inclusive. E.g., format 20400 m as "20.4 km" after calling
94 * setAutoSiPrefix("mu", "M") but format it as 20400 m after calling setAutoSiPrefix("mu", ""). Note that the kg for
95 * {@link Mass} is associated with the SI prefix "k", and the g with an SI prefix "". For the {@link LinearObjectDensity}
96 * that is expressed in /m, /km is associated with an SI prefix "k" and /mm with an SI prefix "m". Note that the minimum and
97 * maximum exponents are clamped between q (-30) and Q (30).
98 * @param minSiPrefix minimum SI prefix to use (inclusive)
99 * @param maxSiPrefix maximum SI prefix to use (inclusive)
100 * @return QuantityFormat object for fluent design
101 * @throws IllegalArgumentException when minSiPrefix > maxSiPrefix
102 * @throws IllegalArgumentException when the <code>minSiPrefix</code> or <code>maxSiPrefix</code> does not exist
103 */
104 public QuantityFormat setAutoSiPrefix(final String minSiPrefix, final String maxSiPrefix)
105 {
106 int minExponent = SIPrefixes.getSiPrefix(minSiPrefix).getExponent();
107 int maxExponent = SIPrefixes.getSiPrefix(maxSiPrefix).getExponent();
108 Throw.when(minExponent > maxExponent, IllegalArgumentException.class, "minExponent %d > maxExponent %d", minExponent,
109 maxExponent);
110 this.ctx.autoSiPrefix = true;
111 this.ctx.autoSiMinExponent = Math.min(30, Math.max(-30, minExponent));
112 this.ctx.autoSiMaxExponent = Math.min(30, Math.max(-30, maxExponent));
113 return this;
114 }
115
116 /**
117 * Set whether it is allowed to use prefixes c, d, da, h in the autoSiPrefix.
118 * @param allowed to indicate whether it is allowed or not to use prefixes c, d, da, h in the autoSiPrefix
119 * @return QuantityFormat object for fluent design
120 */
121 public QuantityFormat setAllowExponents12(final boolean allowed)
122 {
123 this.ctx.allowExponents12 = allowed;
124 return this;
125 }
126
127 /**
128 * Set that it is allowed to use prefixes c, d, da, h in the autoSiPrefix.
129 * @return QuantityFormat object for fluent design
130 */
131 public QuantityFormat setAllowExponents12()
132 {
133 return setAllowExponents12(true);
134 }
135
136 }