1 package org.djunits.vecmat.def;
2
3 import java.lang.reflect.Array;
4
5 import org.djunits.quantity.def.AbsQuantity;
6 import org.djunits.quantity.def.Quantity;
7 import org.djunits.quantity.def.Reference;
8
9 /**
10 * AbsTable contains a number of standard operations on 2-dimensional tables that contain absolute quantities.
11 * <p>
12 * Copyright (c) 2025-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 * @param <A> the absolute quantity type
17 * @param <Q> the quantity type
18 * @param <MA> the absolute table type
19 * @param <MQ> the relative table type
20 * @param <MAT> the type of the transposed version of the absolute table
21 */
22 public abstract class AbsTable<A extends AbsQuantity<A, Q, ?>, Q extends Quantity<Q>, MA extends AbsTable<A, Q, MA, MQ, MAT>,
23 MQ extends Table<Q, MQ, ?, ?, ?>, MAT extends AbsTable<A, Q, MAT, ?, MA>> extends AbsVectorMatrix<A, Q, MA, MQ, MAT>
24 {
25 /** */
26 private static final long serialVersionUID = 600L;
27
28 /**
29 * Create a new matrix of absolute values with a reference point.
30 * @param matrix the underlying relative matrix with SI values relative to the reference point
31 * @param reference the reference point for the absolute values
32 */
33 public AbsTable(final MQ matrix, final Reference<?, A, Q> reference)
34 {
35 super(matrix, reference);
36 }
37
38 /**
39 * Return the si-value at position (row, col), where both row and col are 0-based values.
40 * @param row the row (0-based)
41 * @param col the column (0-based)
42 * @return the si-value at position (row, col)
43 * @throws IndexOutOfBoundsException when row or col < 0 or larger than number of rows/columns - 1.
44 */
45 public double si(final int row, final int col) throws IndexOutOfBoundsException
46 {
47 return getRelativeVecMat().si(row, col);
48 }
49
50 /**
51 * Return the si-value at position (row, col), where both row and col are 1-based values.
52 * @param mRow the row (1-based)
53 * @param mCol the column (1-based)
54 * @return the si-value at position (row, col)
55 * @throws IndexOutOfBoundsException when row or col < 1 or larger than number of rows/columns.
56 */
57 public double msi(final int mRow, final int mCol) throws IndexOutOfBoundsException
58 {
59 return si(mRow - 1, mCol - 1);
60 }
61
62 /**
63 * Return the quantity at position (row, col), where both row and col are 0-based values.
64 * @param row the row (0-based)
65 * @param col the column (0-based)
66 * @return the quantity at position (row, col)
67 * @throws IndexOutOfBoundsException when row or col < 0 or larger than number of rows/columns - 1.
68 */
69 public A get(final int row, final int col) throws IndexOutOfBoundsException
70 {
71 return getReference().instantiate(getDisplayUnit().ofSi(si(row, col))).setDisplayUnit(getDisplayUnit());
72 }
73
74 /**
75 * Return the quantity at position (row, col), where both row and col are 1-based values.
76 * @param mRow the row (1-based)
77 * @param mCol the column (1-based)
78 * @return the quantity at position (row, col)
79 * @throws IndexOutOfBoundsException when row or col < 1 or larger than number of rows/columns.
80 */
81 public A mget(final int mRow, final int mCol) throws IndexOutOfBoundsException
82 {
83 return getReference().instantiate(getDisplayUnit().ofSi(msi(mRow, mCol))).setDisplayUnit(getDisplayUnit());
84 }
85
86 /**
87 * Return the vector or matrix as a 2D array of scalars.
88 * @return a new A[rows()][cols()] array; entry [i][j] contains get(i, j).
89 */
90 @SuppressWarnings("unchecked") // cast from Array.newInstance(...) to Q[][]
91 public A[][] getScalarGrid()
92 {
93 // Determine the runtime type of Q using the first cell; constructors guarantee rows, cols >= 0.
94 final A first = get(0, 0);
95 final Class<?> qClass = first.getClass();
96
97 // Allocate a Q[rows()][cols()] array and fill it.
98 final A[][] out = (A[][]) Array.newInstance(qClass, rows(), cols());
99 for (int i = 0; i < rows(); i++)
100 {
101 for (int j = 0; j < cols(); j++)
102 {
103 out[i][j] = get(i, j);
104 }
105 }
106 return out;
107 }
108
109 /**
110 * Return the vector or matrix as a 2D array of double SI values.
111 * @return a new double[rows()][cols()] array; entry [i][j] contains si(i, j).
112 */
113 public double[][] getSiGrid()
114 {
115 // Allocate a double[rows()][cols()] array and fill it.
116 final double[][] out = (double[][]) Array.newInstance(double.class, rows(), cols());
117 for (int r = 0; r < rows(); r++)
118 {
119 for (int c = 0; c < cols(); c++)
120 {
121 out[r][c] = si(r, c);
122 }
123 }
124 return out;
125 }
126
127 /**
128 * Return the vector or matrix as a row-major array of scalars.
129 * @return a new A[rows() * cols()] array.
130 */
131 @SuppressWarnings("unchecked") // cast from Array.newInstance(...) to A[][]
132 public A[] getScalarArray()
133 {
134 // Determine the runtime type of Q using the first cell; constructors guarantee rows, cols >= 0.
135 final A first = get(0, 0);
136 final Class<?> qClass = first.getClass();
137 int cols = cols();
138
139 // Allocate a Q[rows() * cols()] array and fill it.
140 final A[] out = (A[]) Array.newInstance(qClass, rows() * cols());
141 for (int r = 0; r < rows(); r++)
142 {
143 for (int c = 0; c < cols; c++)
144 {
145 out[r * cols + c] = get(r, c);
146 }
147 }
148 return out;
149 }
150
151 /**
152 * Return the vector or matrix as a row-major array of double SI values.
153 * @return a new double[rows() * cols()] array.
154 */
155 public double[] getSiArray()
156 {
157 // Allocate a double[rows()][cols()] array and fill it.
158 final double[] out = new double[rows() * cols()];
159 int cols = cols();
160 for (int r = 0; r < rows(); r++)
161 {
162 for (int c = 0; c < cols; c++)
163 {
164 out[r * cols + c] = si(r, c);
165 }
166 }
167 return out;
168 }
169
170 /**
171 * Return a quantity row (0-based) from the vector or matrix. Note that the specific vector to return can be tightened by
172 * the implementing class.
173 * @param row the row number to retrieve (0-based)
174 * @return a row vector with the data at the given row
175 */
176 public abstract AbsVector<A, Q, ?, ?, ?> getRowVector(int row);
177
178 /**
179 * Return a quantity row (1-based) from the vector or matrix. Note that the specific vector to return can be tightened by
180 * the implementing class.
181 * @param mRow the row number to retrieve (1-based)
182 * @return a row vector with the data at the given row
183 */
184 public abstract AbsVector<A, Q, ?, ?, ?> mgetRowVector(int mRow);
185
186 /**
187 * Return a quantity column (0-based) from the vector or matrix. Note that the specific vector to return can be tightened by
188 * the implementing class.
189 * @param col the column number to retrieve (0-based)
190 * @return a column vector with the data at the given column
191 */
192 public abstract AbsVector<A, Q, ?, ?, ?> getColumnVector(int col);
193
194 /**
195 * Return a quantity column (1-based) from the vector or matrix. Note that the specific vector to return can be tightened by
196 * the implementing class.
197 * @param mCol the column number to retrieve (1-based)
198 * @return a column vector with the data at the given column
199 */
200 public abstract AbsVector<A, Q, ?, ?, ?> mgetColumnVector(int mCol);
201
202 /**
203 * Return an array with SI-values for the given row (0-based) from the vector or matrix.
204 * @param row the row number to retrieve (0-based)
205 * @return an array with SI-values with the data at the given row
206 */
207 public double[] getRowSi(final int row)
208 {
209 return getRelativeVecMat().getRowSi(row);
210 }
211
212 /**
213 * Return an array with SI-values for the given row (1-based) from the vector or matrix.
214 * @param mRow the row number to retrieve (1-based)
215 * @return an array with SI-values with the data at the given row
216 */
217 public double[] mgetRowSi(final int mRow)
218 {
219 return getRelativeVecMat().mgetRowSi(mRow);
220 }
221
222 /**
223 * Return an array with SI-values for the given column (0-based) from the vector or matrix.
224 * @param col the column number to retrieve (0-based)
225 * @return an array with SI-values with the data at the given column
226 */
227 public double[] getColumnSi(final int col)
228 {
229 return getRelativeVecMat().getColumnSi(col);
230 }
231
232 /**
233 * Return an array with SI-values for the given column (1-based) from the vector or matrix.
234 * @param mCol the column number to retrieve (1-based)
235 * @return an array with SI-values with the data at the given column
236 */
237 public double[] mgetColumnSi(final int mCol)
238 {
239 return getRelativeVecMat().mgetColumnSi(mCol);
240 }
241
242 /**
243 * Retrieve a row (0-based) from the matrix as an array of scalars.
244 * @param row row of the values to retrieve (0-based)
245 * @return the row as a Scalar array
246 * @throws IndexOutOfBoundsException in case row is out of bounds
247 */
248 @SuppressWarnings("unchecked")
249 public A[] getRowScalars(final int row) throws IndexOutOfBoundsException
250 {
251 checkRow(row);
252
253 // Build a Q[] of length cols() using the runtime class of the first element
254 A first = get(row, 0);
255 A[] out = (A[]) Array.newInstance(first.getClass(), cols());
256 for (int c = 0; c < cols(); c++)
257 {
258 out[c] = get(row, c);
259 }
260 return out;
261 }
262
263 /**
264 * Retrieve a row (1-based) from the matrix as an array of scalars.
265 * @param mRow row of the values to retrieve (1-based)
266 * @return the row as a Scalar array
267 * @throws IndexOutOfBoundsException in case row is out of bounds
268 */
269 public A[] mgetRowScalars(final int mRow) throws IndexOutOfBoundsException
270 {
271 mcheckRow(mRow);
272 return getRowScalars(mRow - 1);
273 }
274
275 /**
276 * Retrieve a column (0-based) from the matrix as an array of scalars.
277 * @param col column of the values to retrieve (0-based)
278 * @return the column as a Scalar array
279 * @throws IndexOutOfBoundsException in case column is out of bounds
280 */
281 @SuppressWarnings("unchecked")
282 public A[] getColumnScalars(final int col) throws IndexOutOfBoundsException
283 {
284 checkCol(col);
285
286 A first = get(0, col);
287 A[] out = (A[]) Array.newInstance(first.getClass(), rows());
288 for (int r = 0; r < rows(); r++)
289 {
290 out[r] = get(r, col);
291 }
292 return out;
293 }
294
295 /**
296 * Retrieve a column (1-based) from the matrix as an array of scalars.
297 * @param mCol column of the values to retrieve (1-based)
298 * @return the column as a Scalar array
299 * @throws IndexOutOfBoundsException in case column is out of bounds
300 */
301 public A[] mgetColumnScalars(final int mCol) throws IndexOutOfBoundsException
302 {
303 mcheckCol(mCol);
304 return getColumnScalars(mCol - 1);
305 }
306
307 }