View Javadoc
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 }