1 package org.djunits.vecmat.table;
2
3 import org.djunits.formatter.TableFormat;
4 import org.djunits.formatter.TableFormatter;
5 import org.djunits.quantity.def.AbsQuantity;
6 import org.djunits.quantity.def.Quantity;
7 import org.djunits.quantity.def.Reference;
8 import org.djunits.unit.Unit;
9 import org.djunits.vecmat.def.AbsTable;
10 import org.djunits.vecmat.dn.AbsVectorN;
11 import org.djunits.vecmat.storage.DenseDoubleDataSi;
12 import org.djutils.exceptions.Throw;
13
14 /**
15 * AbsQuantityTable implements a table containing absolute quantities with a reference point. The table is immutable, except for
16 * the display unit, which can be changed.
17 * <p>
18 * Copyright (c) 2026-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
19 * for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
20 * distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
21 * @author Alexander Verbraeck
22 * @param <A> the absolute quantity type
23 * @param <Q> the corresponding relative quantity type
24 */
25 public class AbsQuantityTable<A extends AbsQuantity<A, Q, ?>, Q extends Quantity<Q>>
26 extends AbsTable<A, Q, AbsQuantityTable<A, Q>, QuantityTable<Q>, AbsQuantityTable<A, Q>>
27 {
28 /** */
29 private static final long serialVersionUID = 600L;
30
31 /**
32 * Create a new AbsQuantityTable with a display unit and a reference point.
33 * @param relativeTable the table values {a_ij} expressed in the displayUnit
34 * @param reference the reference point for the absolute values
35 */
36 public AbsQuantityTable(final QuantityTable<Q> relativeTable, final Reference<?, A, Q> reference)
37 {
38 super(relativeTable, reference);
39 }
40
41 @Override
42 public AbsQuantityTable<A, Q> instantiate(final QuantityTable<Q> relativeTable, final Reference<?, A, Q> reference)
43 {
44 return new AbsQuantityTable<>(relativeTable, reference);
45 }
46
47 @Override
48 public AbsVectorN.Row<A, Q> getRowVector(final int row)
49 {
50 return new AbsVectorN.Row<>(getRelativeVecMat().getRowVector(row), getReference());
51 }
52
53 @Override
54 public AbsVectorN.Row<A, Q> mgetRowVector(final int mRow)
55 {
56 return new AbsVectorN.Row<>(getRelativeVecMat().mgetRowVector(mRow), getReference());
57 }
58
59 @Override
60 public AbsVectorN.Col<A, Q> getColumnVector(final int col)
61 {
62 return new AbsVectorN.Col<>(getRelativeVecMat().getColumnVector(col), getReference());
63 }
64
65 @Override
66 public AbsVectorN.Col<A, Q> mgetColumnVector(final int mCol)
67 {
68 return new AbsVectorN.Col<>(getRelativeVecMat().mgetColumnVector(mCol), getReference());
69 }
70
71 @Override
72 public AbsQuantityTable<A, Q> transpose()
73 {
74 return instantiate(getRelativeVecMat().transpose(), getReference()).setDisplayUnit(getDisplayUnit());
75 }
76
77 // ------------------------------------------ OF METHODS ------------------------------------------
78
79 /**
80 * Create a new AbsQuantityTable with a unit, based on a row-major array with values in the given unit.
81 * @param dataInUnit the table values {a11, a12, ..., A1M, ..., aN1, aN2, ..., aNM} expressed in the unit
82 * @param rows the number of rows
83 * @param cols the number of columns
84 * @param unit the unit of the data, also used as the display unit
85 * @param reference the reference point for the absolute quantities
86 * @return a new AbsQuantityTable with a unit
87 * @param <A> the absolute quantity type
88 * @param <Q> the quantity type
89 * @param <R> the reference type
90 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols, or when the number of rows
91 * or columns is not positive
92 */
93 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
94 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> of(final double[] dataInUnit, final int rows, final int cols,
95 final Unit<?, Q> unit, final R reference)
96 {
97 return new AbsQuantityTable<A, Q>(QuantityTable.of(dataInUnit, rows, cols, unit), reference);
98 }
99
100 /**
101 * Create a AbsQuantityTable without needing generics, based on a row-major array with SI-values.
102 * @param dataSi the table values {a11, a12, ..., A1M, ..., aN1, aN2, ..., aNM} as an array using SI units
103 * @param rows the number of rows
104 * @param cols the number of columns
105 * @param displayUnit the display unit to use
106 * @param reference the reference point for the absolute quantities
107 * @return a new AbsQuantityTable with a unit
108 * @param <A> the absolute quantity type
109 * @param <Q> the quantity type
110 * @param <R> the reference type
111 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols, or when the number of rows
112 * or columns is not positive
113 */
114 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
115 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> ofSi(final double[] dataSi, final int rows, final int cols,
116 final Unit<?, Q> displayUnit, final R reference)
117 {
118 return new AbsQuantityTable<A, Q>(QuantityTable.ofSi(dataSi, rows, cols, displayUnit), reference);
119 }
120
121 /**
122 * Create a AbsQuantityTable without needing generics, based on a row-major array of quantities. The unit is taken from the
123 * first quantity in the array.
124 * @param data the table values {a11, a12, ..., A1M, ..., aN1, aN2, ..., aNM} expressed as an array of quantities
125 * @param rows the number of rows
126 * @param cols the number of columns
127 * @param reference the reference point for the absolute quantities
128 * @return a new AbsQuantityTable with a unit
129 * @param <A> the absolute quantity type
130 * @param <Q> the quantity type
131 * @param <R> the reference type
132 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols, or when the number of rows
133 * or columns is not positive
134 */
135 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
136 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> of(final Q[] data, final int rows, final int cols,
137 final R reference)
138 {
139 return new AbsQuantityTable<A, Q>(QuantityTable.of(data, rows, cols), reference);
140 }
141
142 /**
143 * Create a AbsQuantityTable without needing generics, based on a row-major array of absolute quantities. The unit is taken
144 * from the first quantity in the grid. The reference points have to be all the same.
145 * @param absData the table values {a11, a12, ..., A1M, ..., aN1, aN2, ..., aNM} expressed as an array of absolute
146 * quantities
147 * @param rows the number of rows
148 * @param cols the number of columns
149 * @return a new AbsQuantityTable with a display unit and reference point
150 * @param <A> the absolute quantity type
151 * @param <Q> the quantity type
152 * @param <R> the reference type
153 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols
154 */
155 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
156 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> of(final A[] absData, final int rows, final int cols)
157 {
158 Throw.whenNull(absData, "absData");
159 var ddd = DenseDoubleDataSi.of(absData, rows, cols); // guarantees that absGrid[0][0] exists
160 return new AbsQuantityTable<>(new QuantityTable<Q>(ddd, absData[0].getDisplayUnit()), absData[0].getReference());
161 }
162
163 /**
164 * Create a new AbsQuantityTable with a unit, based on a 2-dimensional grid with SI-values.
165 * @param gridSi the table values {{a11, a12, ..., A1M}, ..., {aN1, aN2, ..., aNM}} expressed in the SI or base unit
166 * @param displayUnit the unit of the data, which will also be used as the display unit
167 * @param reference the reference point for the absolute quantities
168 * @return a new AbsQuantityTable with a unit
169 * @param <A> the absolute quantity type
170 * @param <Q> the quantity type
171 * @param <R> the reference type
172 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols
173 */
174 @SuppressWarnings("checkstyle:needbraces")
175 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
176 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> ofSi(final double[][] gridSi, final Unit<?, Q> displayUnit,
177 final R reference)
178 {
179 Throw.whenNull(displayUnit, "displayUnit");
180 return new AbsQuantityTable<>(QuantityTable.ofSi(gridSi, displayUnit), reference);
181 }
182
183 /**
184 * Create a new AbsQuantityTable with a unit, based on a 2-dimensional grid with values in the given unit.
185 * @param gridInUnit the table values {{a11, a12, ..., A1M}, ..., {aN1, aN2, ..., aNM}} expressed in the unit
186 * @param unit the unit of the values, also used as the display unit
187 * @param reference the reference point for the absolute quantities
188 * @return a new AbsQuantityTable with a unit
189 * @param <A> the absolute quantity type
190 * @param <Q> the quantity type
191 * @param <R> the reference type
192 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols
193 */
194 @SuppressWarnings("checkstyle:needbraces")
195 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
196 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> of(final double[][] gridInUnit, final Unit<?, Q> unit,
197 final R reference)
198 {
199 return new AbsQuantityTable<>(QuantityTable.of(gridInUnit, unit), reference);
200 }
201
202 /**
203 * Create a AbsQuantityTable without needing generics, based on a 2-dimensional grid of quantities. The unit is taken from
204 * the first quantity in the grid.
205 * @param grid the table values {{a11, a12, ..., A1M}, ..., {aN1, aN2, ..., aNM}} expressed as a 2-dimensional array of
206 * quantities
207 * @param reference the reference point for the absolute quantities
208 * @return a new AbsQuantityTable with a unit
209 * @param <A> the absolute quantity type
210 * @param <Q> the quantity type
211 * @param <R> the reference type
212 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols
213 */
214 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
215 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> of(final Q[][] grid, final R reference)
216 {
217 return new AbsQuantityTable<>(QuantityTable.of(grid), reference);
218 }
219
220 /**
221 * Create a AbsQuantityTable without needing generics, based on a 2-dimensional grid of absolute quantities. The unit is
222 * taken from the first quantity in the grid. The reference points have to be all the same.
223 * @param absGrid the table values {{a11, a12, ..., A1M}, ..., {aN1, aN2, ..., aNM}} expressed as a 2-dimensional array of
224 * absolute quantities
225 * @return a new AbsQuantityTable with a display unit and reference point
226 * @param <A> the absolute quantity type
227 * @param <Q> the quantity type
228 * @param <R> the reference type
229 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols
230 */
231 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
232 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> of(final A[][] absGrid)
233 {
234 Throw.whenNull(absGrid, "absGrid");
235 var ddd = DenseDoubleDataSi.of(absGrid); // guarantees that absGrid[0][0] exists
236 return new AbsQuantityTable<>(new QuantityTable<Q>(ddd, absGrid[0][0].getDisplayUnit()), absGrid[0][0].getReference());
237 }
238
239 /**
240 * Create a AbsQuantityTable without needing generics, based on a relative table. The unit is taken from the first quantity
241 * in the grid.
242 * @param relativeTable the relative table with values relative to the reference point
243 * @param reference the reference point for the absolute quantities
244 * @return a new AbsQuantityTable with a unit
245 * @param <A> the absolute quantity type
246 * @param <Q> the quantity type
247 * @param <R> the reference type
248 * @throws IllegalArgumentException when the size of the data object is not equal to rows*cols
249 */
250 public static <A extends AbsQuantity<A, Q, R>, Q extends Quantity<Q>,
251 R extends Reference<R, A, Q>> AbsQuantityTable<A, Q> of(final QuantityTable<Q> relativeTable, final R reference)
252 {
253 return new AbsQuantityTable<>(relativeTable, reference);
254 }
255
256 // ----------------------------------------- STRING AND FORMATTING METHODS ----------------------------------------
257
258 /**
259 * Concise description of this quantity table.
260 * @return a String with the quantity table, with the unit and possibly the reference attached.
261 */
262 @Override
263 public String format()
264 {
265 return format(TableFormat.defaults());
266 }
267
268 /**
269 * String representation of this quantity table after applying the format.
270 * @param format the format to apply for the quantity table
271 * @return a String representation of this quantity table, formatted according to the given format
272 */
273 public String format(final TableFormat format)
274 {
275 return TableFormatter.format(this, format);
276 }
277
278 /**
279 * String representation of this quantity table, expressed in the specified unit.
280 * @param targetUnit the unit into which the values of the quantity table are converted for display
281 * @return printable string with the quantity table's values expressed in the specified unit
282 */
283 @Override
284 public String format(final Unit<?, Q> targetUnit)
285 {
286 return format(TableFormat.defaults().setDisplayUnit(targetUnit));
287 }
288
289 }