1 package org.djunits.vecmat.table;
2
3 import java.util.Objects;
4
5 import org.djunits.quantity.SIQuantity;
6 import org.djunits.quantity.def.Quantity;
7 import org.djunits.unit.UnitInterface;
8 import org.djunits.unit.si.SIUnit;
9 import org.djunits.vecmat.d1.Matrix1x1;
10 import org.djunits.vecmat.d1.Vector1;
11 import org.djunits.vecmat.d2.Matrix2x2;
12 import org.djunits.vecmat.d2.Vector2;
13 import org.djunits.vecmat.d3.Matrix3x3;
14 import org.djunits.vecmat.d3.Vector3;
15 import org.djunits.vecmat.def.VectorMatrix;
16 import org.djunits.vecmat.dn.MatrixNxN;
17 import org.djunits.vecmat.dn.VectorN;
18 import org.djunits.vecmat.storage.DataGridSi;
19 import org.djunits.vecmat.storage.DenseDoubleDataSi;
20 import org.djutils.exceptions.Throw;
21
22
23
24
25
26
27
28
29
30
31
32
33 public class QuantityTable<Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>>
34 extends VectorMatrix<Q, U, QuantityTable<Q, U>, QuantityTable<SIQuantity, SIUnit>, QuantityTable<?, ?>>
35 {
36
37 private static final long serialVersionUID = 600L;
38
39
40 private final DataGridSi<?> dataSi;
41
42
43
44
45
46
47
48 public QuantityTable(final DataGridSi<?> dataSi, final U displayUnit)
49 {
50 super(displayUnit);
51 Throw.whenNull(dataSi, "dataSi");
52 this.dataSi = dataSi;
53 }
54
55
56
57
58
59
60
61
62
63
64
65
66
67 @SuppressWarnings("checkstyle:needbraces")
68 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> QuantityTable<Q, U> of(
69 final double[] valueArrayInUnit, final int rows, final int cols, final U displayUnit)
70 {
71 Throw.whenNull(valueArrayInUnit, "valueArrayInUnit");
72 Throw.whenNull(displayUnit, "displayUnit");
73 Throw.when(rows <= 0, IllegalArgumentException.class, "rows <= 0");
74 Throw.when(cols <= 0, IllegalArgumentException.class, "cols <= 0");
75 Throw.when(rows * cols != valueArrayInUnit.length, IllegalArgumentException.class,
76 "valueArrayInUnit does not contain the correct number of entries (%d x %d != %d)", rows, cols,
77 valueArrayInUnit.length);
78 double[] aSi = new double[rows * cols];
79 for (int i = 0; i < valueArrayInUnit.length; i++)
80 aSi[i] = displayUnit.toBaseValue(valueArrayInUnit[i]);
81 return new QuantityTable<Q, U>(new DenseDoubleDataSi(aSi, rows, cols), displayUnit);
82 }
83
84
85
86
87
88
89
90
91
92
93
94 @SuppressWarnings("checkstyle:needbraces")
95 public static <Q extends Quantity<Q, U>,
96 U extends UnitInterface<U, Q>> QuantityTable<Q, U> of(final double[][] valueGridInUnit, final U displayUnit)
97 {
98 Throw.whenNull(valueGridInUnit, "valueGridInUnit");
99 Throw.whenNull(displayUnit, "displayUnit");
100 int rows = valueGridInUnit.length;
101 Throw.when(rows == 0, IllegalArgumentException.class, "valueGridInUnit has 0 rows");
102 int cols = valueGridInUnit[0].length;
103 Throw.when(cols == 0, IllegalArgumentException.class, "row 0 in valueGridInUnit has 0 columns");
104 double[] aSi = new double[rows * cols];
105 for (int r = 0; r < rows; r++)
106 {
107 Throw.when(valueGridInUnit[r].length != cols, IllegalArgumentException.class,
108 "valueGridInUnit is not a NxM array; row %d has a length of %d, not %d", r, valueGridInUnit[r].length,
109 cols);
110 for (int c = 0; c < cols; c++)
111 aSi[cols * r + c] = displayUnit.toBaseValue(valueGridInUnit[r][c]);
112 }
113 return new QuantityTable<Q, U>(new DenseDoubleDataSi(aSi, rows, cols), displayUnit);
114 }
115
116
117
118
119
120
121
122
123
124
125
126 @SuppressWarnings("checkstyle:needbraces")
127 public static <Q extends Quantity<Q, U>, U extends UnitInterface<U, Q>> QuantityTable<Q, U> of(final Q[][] quantityGrid,
128 final U displayUnit)
129 {
130 return new QuantityTable<Q, U>(new DenseDoubleDataSi(quantityGrid), displayUnit);
131 }
132
133 @Override
134 public QuantityTable<Q, U> instantiateSi(final double[] siNew)
135 {
136 return new QuantityTable<Q, U>(this.dataSi.instantiateNew(siNew), getDisplayUnit().getBaseUnit())
137 .setDisplayUnit(getDisplayUnit());
138 }
139
140 @Override
141 public QuantityTable<SIQuantity, SIUnit> instantiateSi(final double[] siNew, final SIUnit siUnit)
142 {
143 return new QuantityTable<SIQuantity, SIUnit>(this.dataSi.instantiateNew(siNew), siUnit);
144 }
145
146
147
148
149
150 public DataGridSi<?> getDataGrid()
151 {
152 return this.dataSi;
153 }
154
155 @Override
156 public double[] si()
157 {
158 return this.dataSi.getDataArray();
159 }
160
161 @Override
162 public double si(final int row, final int col) throws IndexOutOfBoundsException
163 {
164 checkRow(row);
165 checkCol(col);
166 return this.dataSi.get(row, col);
167 }
168
169 @Override
170 public VectorN.Row<Q, U> getRowVector(final int row)
171 {
172 return VectorN.Row.ofSi(getRowSi(row), getDisplayUnit());
173 }
174
175 @Override
176 public VectorN.Row<Q, U> mgetRowVector(final int mRow)
177 {
178 return VectorN.Row.ofSi(mgetRowSi(mRow), getDisplayUnit());
179 }
180
181 @Override
182 public VectorN.Col<Q, U> getColumnVector(final int col)
183 {
184 return VectorN.Col.ofSi(getColumnSi(col), getDisplayUnit());
185 }
186
187 @Override
188 public VectorN.Col<Q, U> mgetColumnVector(final int mCol)
189 {
190 return VectorN.Col.ofSi(mgetColumnSi(mCol), getDisplayUnit());
191 }
192
193 @Override
194 public double[] getRowSi(final int row)
195 {
196 checkRow(row);
197 return this.dataSi.getRowArray(row);
198 }
199
200 @Override
201 public double[] getColumnSi(final int col)
202 {
203 checkCol(col);
204 return this.dataSi.getColArray(col);
205 }
206
207 @Override
208 public int rows()
209 {
210 return this.dataSi.rows();
211 }
212
213 @Override
214 public int cols()
215 {
216 return this.dataSi.cols();
217 }
218
219
220
221
222 @Override
223 public int hashCode()
224 {
225 return Objects.hash(this.dataSi);
226 }
227
228 @SuppressWarnings("checkstyle:needbraces")
229 @Override
230 public boolean equals(final Object obj)
231 {
232 if (this == obj)
233 return true;
234 if (obj == null)
235 return false;
236 if (getClass() != obj.getClass())
237 return false;
238 QuantityTable<?, ?> other = (QuantityTable<?, ?>) obj;
239 return Objects.equals(this.dataSi, other.dataSi);
240 }
241
242
243
244
245
246
247
248
249
250
251 public <TQ extends Quantity<TQ, TU>, TU extends UnitInterface<TU, TQ>> QuantityTable<TQ, TU> as(final TU targetUnit)
252 throws IllegalArgumentException
253 {
254 Throw.when(!getDisplayUnit().siUnit().equals(targetUnit.siUnit()), IllegalArgumentException.class,
255 "QuantityTable.as(%s) called, but units do not match: %s <> %s", targetUnit,
256 getDisplayUnit().siUnit().getDisplayAbbreviation(), targetUnit.siUnit().getDisplayAbbreviation());
257 return new QuantityTable<TQ, TU>(this.dataSi.instantiateNew(si()), targetUnit.getBaseUnit()).setDisplayUnit(targetUnit);
258 }
259
260
261
262
263
264
265 public Matrix1x1<Q, U> asMatrix1x1()
266 {
267 Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class,
268 "asMatrix1x1() called, but matrix is no 1x1 but %dx%d", rows(), cols());
269 return Matrix1x1.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
270 }
271
272
273
274
275
276
277 public Matrix2x2<Q, U> asMatrix2x2()
278 {
279 Throw.when(rows() != 2 || cols() != 2, IllegalStateException.class,
280 "asMatrix2x2() called, but matrix is no 2x2 but %dx%d", rows(), cols());
281 return Matrix2x2.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
282 }
283
284
285
286
287
288
289 public Matrix3x3<Q, U> asMatrix3x3()
290 {
291 Throw.when(rows() != 3 || cols() != 3, IllegalStateException.class,
292 "asMatrix3x3() called, but matrix is no 3x3 but %dx%d", rows(), cols());
293 return Matrix3x3.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
294 }
295
296
297
298
299
300
301 public MatrixNxN<Q, U> asMatrixNxN()
302 {
303 Throw.when(rows() != cols(), IllegalStateException.class, "asMatrixNxN() called, but matrix is no square but %dx%d",
304 rows(), cols());
305 return new MatrixNxN<Q, U>(new DenseDoubleDataSi(si(), rows(), cols()), getDisplayUnit().getBaseUnit())
306 .setDisplayUnit(getDisplayUnit());
307 }
308
309
310
311
312
313
314 public Vector1<Q, U> asVector1()
315 {
316 Throw.when(rows() != 1 || cols() != 1, IllegalStateException.class, "Matrix is not 1x1");
317 final double[] data = si();
318 return new Vector1<Q, U>(data[0], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
319 }
320
321
322
323
324
325
326 public Vector2.Col<Q, U> asVector2Col()
327 {
328 Throw.when(rows() != 2 || cols() != 1, IllegalStateException.class, "Matrix is not 2x1");
329 final double[] data = si();
330 return new Vector2.Col<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
331 }
332
333
334
335
336
337
338 public Vector3.Col<Q, U> asVector3Col()
339 {
340 Throw.when(rows() != 3 || cols() != 1, IllegalStateException.class, "Matrix is not 3x1");
341 final double[] data = si();
342 return new Vector3.Col<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
343 .setDisplayUnit(getDisplayUnit());
344 }
345
346
347
348
349
350
351 public VectorN.Col<Q, U> asVectorNCol()
352 {
353 Throw.when(cols() != 1, IllegalStateException.class, "Matrix is not Nx1");
354 return VectorN.Col.ofSi(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
355 }
356
357
358
359
360
361
362 public Vector2.Row<Q, U> asVector2Row()
363 {
364 Throw.when(rows() != 1 || cols() != 2, IllegalStateException.class, "Matrix is not 1x2");
365 final double[] data = si();
366 return new Vector2.Row<Q, U>(data[0], data[1], getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
367 }
368
369
370
371
372
373
374 public Vector3.Row<Q, U> asVector3Row()
375 {
376 Throw.when(rows() != 1 || cols() != 3, IllegalStateException.class, "Matrix is not 1x3");
377 final double[] data = si();
378 return new Vector3.Row<Q, U>(data[0], data[1], data[2], getDisplayUnit().getBaseUnit())
379 .setDisplayUnit(getDisplayUnit());
380 }
381
382
383
384
385
386
387 public VectorN.Row<Q, U> asVectorNRow()
388 {
389 Throw.when(rows() != 1, IllegalStateException.class, "Matrix is not 1xN");
390 return VectorN.Row.of(si(), getDisplayUnit().getBaseUnit()).setDisplayUnit(getDisplayUnit());
391 }
392
393 }