001/** 002 * Matrix3D -- A 3x3 matrix of Parameter objects. 003 * 004 * Copyright (C) 2008-2025, by Joseph A. Huwaldt. All rights reserved. 005 * 006 * This library is free software; you can redistribute it and/or modify it under the terms 007 * of the GNU Lesser General Public License as published by the Free Software Foundation; 008 * either version 2 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 012 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License along with 015 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - 016 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html 017 */ 018package jahuwaldt.js.param; 019 020import java.text.MessageFormat; 021import java.util.List; 022import java.util.ResourceBundle; 023import javax.measure.converter.UnitConverter; 024import javax.measure.quantity.Length; 025import javax.measure.quantity.Quantity; 026import javax.measure.unit.NonSI; 027import javax.measure.unit.SI; 028import javax.measure.unit.Unit; 029import javolution.context.ObjectFactory; 030import javolution.context.StackContext; 031import javolution.lang.MathLib; 032import javolution.lang.Realtime; 033import javolution.lang.ValueType; 034import javolution.util.FastTable; 035import javolution.xml.XMLSerializable; 036import org.jscience.mathematics.number.Float64; 037import org.jscience.mathematics.vector.*; 038 039/** 040 * <p> 041 * This class represents a 3x3 {@link Matrix matrix} implementation for 042 * {@link Parameter parameter} elements.</p> 043 * 044 * <p> 045 * Instances of this class can be created from {@link Vector3D}, either as rows or columns 046 * if the matrix is transposed. For example: 047 * <pre> 048 * {@code 049 * Vector3D<Length> column0 = Vector3D.valueOf(...); 050 * Vector3D<Length> column1 = Vector3D.valueOf(...); 051 * Vector3D<Length> column2 = Vector3D.valueOf(...); 052 * Matrix3D<Length> M = Matrix3D.valueOf(column0, column1, column2).transpose(); 053 * } 054 * </pre> 055 * 056 * <p> Modified by: Joseph A. Huwaldt </p> 057 * 058 * @author Joseph A. Huwaldt, Date: November 26, 2008 059 * @version February 22, 2025 060 */ 061public final class Matrix3D<Q extends Quantity> extends Matrix<Parameter<Q>> implements Realtime, ValueType, XMLSerializable { 062 063 private static final long serialVersionUID = -3295634256026052059L; 064 065 /** 066 * The resource bundle for this package. 067 */ 068 protected static final ResourceBundle RESOURCES = Parameter.RESOURCES; 069 070 /** 071 * The elements stored in this matrix. Serialization is handled by this class since 072 * Float64Matrix is not Serializable. 073 */ 074 private transient Float64Matrix _data; 075 076 /** 077 * Holds the units of the matrix elements. 078 */ 079 private Unit<Q> _unit; 080 081 /** 082 * Returns 3D matrix from a sequence of 9 <code>double</code> values. 083 * <p> 084 * Values are ordered as follows: 085 * <pre> 086 * | a b c | 087 * | d e f | 088 * | g h i | 089 * </pre> 090 * 091 * @param a matrix element 0,0 092 * @param b matrix element 0,1 093 * @param c matrix element 0,2 094 * @param d matrix element 1,0 095 * @param e matrix element 1,1 096 * @param f matrix element 1,2 097 * @param g matrix element 2,0 098 * @param h matrix element 2,1 099 * @param i matrix element 2,2 100 * @param unit the unit in which the elements are stated. 101 * @param <Q> The quantity or unit type of the matrix. 102 * @return the 3D matrix having the specified elements stated in the specified units. 103 */ 104 public static <Q extends Quantity> Matrix3D<Q> valueOf(double a, double b, double c, double d, double e, double f, 105 double g, double h, double i, Unit<Q> unit) { 106 Float64Vector row0 = Float64Vector.valueOf(a, b, c); 107 Float64Vector row1 = Float64Vector.valueOf(d, e, f); 108 Float64Vector row2 = Float64Vector.valueOf(g, h, i); 109 110 Float64Matrix data = Float64Matrix.valueOf(row0, row1, row2); 111 112 Matrix3D<Q> M = Matrix3D.newInstance(unit); 113 M._data = data; 114 115 return M; 116 } 117 118 /** 119 * Returns a 3D matrix holding the specified row vectors in the stated units (column 120 * vectors if {@link #transpose transposed}). 121 * 122 * @param row0 the 1st row vector. 123 * @param row1 the 2nd row vector. 124 * @param row2 the 3rd row vector. 125 * @param unit the unit in which the elements are stated. 126 * @param <Q> The quantity or unit type of the matrix. 127 * @return the 3D matrix having the specified elements stated in the specified units. 128 */ 129 public static <Q extends Quantity> Matrix3D<Q> valueOf(Float64Vector row0, Float64Vector row1, Float64Vector row2, Unit<Q> unit) { 130 131 Float64Matrix data = Float64Matrix.valueOf(row0, row1, row2); 132 133 Matrix3D<Q> M = Matrix3D.newInstance(unit); 134 M._data = data; 135 136 return M; 137 } 138 139 /** 140 * Returns a 3D matrix holding the specified row vectors (column vectors if 141 * {@link #transpose transposed}). All the values are converted to the same units as 142 * the 1st row (row0). 143 * 144 * @param row0 the 1st row vector. 145 * @param row1 the 2nd row vector. 146 * @param row2 the 3rd row vector. 147 * @param <Q> The quantity or unit type of the matrix. 148 * @return the 3D matrix having the specified rows. 149 */ 150 public static <Q extends Quantity> Matrix3D<Q> valueOf(Vector3D<Q> row0, Vector3D<Q> row1, Vector3D<Q> row2) { 151 Unit<Q> unit = row0.getUnit(); 152 153 Float64Matrix data = Float64Matrix.valueOf(row0.toFloat64Vector(), 154 row1.to(unit).toFloat64Vector(), row2.to(unit).toFloat64Vector()); 155 156 Matrix3D<Q> M = Matrix3D.newInstance(unit); 157 M._data = data; 158 159 return M; 160 } 161 162 /** 163 * Returns a 3D matrix holding the row {@link Vector3D vectors} from the specified 164 * collection (column vectors if {@link #transpose transposed}). All the values are 165 * converted to the same units as the 1st row (row0). 166 * 167 * @param rows The list of row vectors. If there are more than 3 elements, an 168 * exception is thrown. 169 * @param <Q> The quantity or unit type of the matrix. 170 * @return the 3D matrix having the specified rows. 171 * @throws DimensionException if the rows do not have a dimension of 3. 172 */ 173 public static <Q extends Quantity> Matrix3D<Q> valueOf(List<Vector3D<Q>> rows) { 174 if (rows.size() != 3) 175 throw new DimensionException( 176 MessageFormat.format(RESOURCES.getString("3vectorsExpectedErr"), rows.size())); 177 178 return Matrix3D.valueOf((Vector3D<Q>)rows.get(0), (Vector3D<Q>)rows.get(1), (Vector3D<Q>)rows.get(2)); 179 } 180 181 /** 182 * Returns a {@link Matrix3D} instance containing the specified matrix of Float64 183 * values stated in the specified units. The input matrix must have dimensions of 3x3. 184 * 185 * @param matrix the matrix of Float64 values stated in the specified unit (must have 186 * dimension of 3x3). 187 * @param unit the unit in which the elements are stated. 188 * @param <Q> The quantity or unit type of the matrix. 189 * @return the matrix having the specified values. 190 */ 191 public static <Q extends Quantity> Matrix3D<Q> valueOf(Matrix<Float64> matrix, Unit<Q> unit) { 192 if (matrix.getNumberOfColumns() != 3 || matrix.getNumberOfRows() != 3) 193 throw new DimensionException(MessageFormat.format(RESOURCES.getString("3x3MatrixExpectedErr"), 194 matrix.getNumberOfRows(), matrix.getNumberOfColumns())); 195 196 Matrix3D<Q> M = Matrix3D.newInstance(unit); 197 M._data = Float64Matrix.valueOf(matrix); 198 199 return M; 200 } 201 202 /** 203 * Returns a {@link Matrix3D} instance containing the specified matrix of double 204 * values stated in the specified units. The input matrix must have dimensions of 3x3. 205 * 206 * @param matrix the matrix of double values stated in the specified unit (must have 207 * dimension of 3x3). 208 * @param unit the unit in which the elements are stated. 209 * @param <Q> The quantity or unit type of the matrix. 210 * @return the matrix having the specified values. 211 */ 212 public static <Q extends Quantity> Matrix3D<Q> valueOf(double[][] matrix, Unit<Q> unit) { 213 if (matrix.length != 3 || matrix[0].length != 3) 214 throw new DimensionException(MessageFormat.format(RESOURCES.getString("3x3MatrixExpectedErr"), 215 matrix.length, matrix[0].length)); 216 217 Matrix3D<Q> M = Matrix3D.newInstance(unit); 218 M._data = Float64Matrix.valueOf(matrix); 219 220 return M; 221 } 222 223 /** 224 * Returns a 3D matrix equivalent to the specified matrix. All the values are 225 * converted to the same units as the 1st element (row=0,column=0). 226 * 227 * @param that the matrix to convert. 228 * @param <Q> The quantity or unit type of the matrix. 229 * @return <code>that</code> or a 3D matrix holding the same elements as the specified 230 * matrix. 231 */ 232 public static <Q extends Quantity> Matrix3D<Q> valueOf(Matrix<Parameter<Q>> that) { 233 if (that instanceof Matrix3D) 234 return (Matrix3D<Q>)that; 235 236 if (that.getNumberOfColumns() != 3 || that.getNumberOfRows() != 3) 237 throw new DimensionException(MessageFormat.format(RESOURCES.getString("3x3MatrixExpectedErr"), 238 that.getNumberOfRows(), that.getNumberOfColumns())); 239 240 Vector3D<Q> row0 = Vector3D.valueOf(that.getRow(0)); 241 Vector3D<Q> row1 = Vector3D.valueOf(that.getRow(1)); 242 Vector3D<Q> row2 = Vector3D.valueOf(that.getRow(2)); 243 244 return Matrix3D.valueOf(row0, row1, row2); 245 } 246 247 /** 248 * Returns the number of rows m for this matrix. This implementation always returns 3. 249 */ 250 @Override 251 public int getNumberOfRows() { 252 return 3; 253 } 254 255 /** 256 * Returns the number of columns n for this matrix. This implementation always returns 257 * 3. 258 */ 259 @Override 260 public int getNumberOfColumns() { 261 return 3; 262 } 263 264 /** 265 * Returns the unit in which the {@link #get values} in this matrix are stated. 266 * 267 * @return The unit in which the values in this matrix are stated. 268 */ 269 public Unit<Q> getUnit() { 270 return _unit; 271 } 272 273 /** 274 * Returns the equivalent to this matrix but stated in the specified unit. 275 * 276 * @param unit the unit of the matrix to be returned. 277 * @param <R> The quantity or unit type of the new units. 278 * @return a matrix equivalent to this vector but stated in the specified unit. 279 * @throws ConversionException if the current model does not allows for conversion to 280 * the specified unit. 281 */ 282 public <R extends Quantity> Matrix3D<R> to(Unit<R> unit) { 283 if ((_unit == unit) || this._unit.equals(unit)) 284 return (Matrix3D<R>)this; 285 286 UnitConverter cvtr = Parameter.converterOf(_unit, unit); 287 if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary. 288 Matrix3D<R> result = (Matrix3D<R>)Matrix3D.copyOf(this); 289 result._unit = unit; 290 return result; 291 } 292 293 double a = cvtr.convert(_data.get(0, 0).doubleValue()); 294 double b = cvtr.convert(_data.get(0, 1).doubleValue()); 295 double c = cvtr.convert(_data.get(0, 2).doubleValue()); 296 double d = cvtr.convert(_data.get(1, 0).doubleValue()); 297 double e = cvtr.convert(_data.get(1, 1).doubleValue()); 298 double f = cvtr.convert(_data.get(1, 2).doubleValue()); 299 double g = cvtr.convert(_data.get(2, 0).doubleValue()); 300 double h = cvtr.convert(_data.get(2, 1).doubleValue()); 301 double i = cvtr.convert(_data.get(2, 2).doubleValue()); 302 303 Matrix3D<R> M = Matrix3D.valueOf(a, b, c, d, e, f, g, h, i, unit); 304 return M; 305 } 306 307 /** 308 * Casts this Matrix3D to a parameterized unit of specified nature or throw a 309 * <code>ClassCastException</code> if the specified quantity and this matrix unit 310 * dimension do not match. 311 * 312 * @param type the quantity class identifying the nature of the unit. 313 * @return this matrix parameterized with the specified type. 314 * @param <T> The new quantity or unit type. 315 * @throws ClassCastException if the dimension of this parameter's unit is different 316 * from the specified quantity dimension. 317 * @throws UnsupportedOperationException if the specified quantity class does not have 318 * a public static field named "UNIT" holding the standard unit for the quantity. 319 */ 320 public <T extends Quantity> Matrix3D<T> asType(Class<T> type) throws ClassCastException { 321 Unit<T> u = _unit.asType(type); // If no exception is thrown, the cast is valid. 322 return (Matrix3D<T>)this; 323 } 324 325 /** 326 * Returns a single element from this matrix. 327 * 328 * @param i the row index (range [0..3[). 329 * @param j the column index (range [0..3[). 330 * @return the element read at [i,j]. 331 */ 332 @Override 333 public Parameter<Q> get(int i, int j) { 334 return Parameter.valueOf(_data.get(i, j).doubleValue(), _unit); 335 } 336 337 /** 338 * Returns a single element from this matrix as a <code>double</code>. 339 * 340 * @param i the row index (range [0..3[). 341 * @param j the column index (range [0..3[). 342 * @return the element read at [i,j]. 343 */ 344 public double getValue(int i, int j) { 345 return _data.get(i, j).doubleValue(); 346 } 347 348 /** 349 * Returns the row identified by the specified index in this matrix. 350 * 351 * @param i the row index (range [0..3[). 352 */ 353 @Override 354 public Vector3D<Q> getRow(int i) { 355 return Vector3D.valueOf(_data.getRow(i), _unit); 356 } 357 358 /** 359 * Returns the column identified by the specified index in this matrix. 360 * 361 * @param j the column index (range [0..3[). 362 */ 363 @Override 364 public Vector3D<Q> getColumn(int j) { 365 return Vector3D.valueOf(_data.getColumn(j), _unit); 366 } 367 368 /** 369 * Returns the diagonal vector. 370 * 371 * @return the vector holding the diagonal elements. 372 */ 373 @Override 374 public Vector3D<Q> getDiagonal() { 375 return Vector3D.valueOf(_data.getDiagonal(), _unit); 376 } 377 378 /** 379 * Returns the negation of this matrix. 380 * 381 * @return <code>-this</code> 382 */ 383 @Override 384 public Matrix3D<Q> opposite() { 385 Matrix3D<Q> M = Matrix3D.newInstance(_unit); 386 M._data = _data.opposite(); 387 return M; 388 } 389 390 /** 391 * Returns the sum of this matrix with the one specified. 392 * 393 * @param that the matrix to be added. 394 * @return <code>this + that</code> 395 * @throws DimensionException if the matrix dimensions are different. 396 */ 397 @Override 398 public Matrix3D<Q> plus(Matrix<Parameter<Q>> that) { 399 400 // Convert input matrix to a Float64Matrix (with unit conversion if necessary). 401 Float64Matrix thatData = toFloat64Matrix(that, this._unit); 402 403 Matrix3D<Q> M = Matrix3D.newInstance(_unit); 404 M._data = this._data.plus(thatData); 405 406 return M; 407 } 408 409 /** 410 * Returns the difference between this matrix and the one specified. 411 * 412 * @param that the matrix to be subtracted from this one. 413 * @return <code>this - that</code> 414 * @throws DimensionException if the matrix dimensions are different. 415 */ 416 @Override 417 public Matrix3D<Q> minus(Matrix<Parameter<Q>> that) { 418 419 // Convert input matrix to a Float64Matrix (with unit conversion if necessary). 420 Float64Matrix thatData = toFloat64Matrix(that, this._unit); 421 422 Matrix3D<Q> M = Matrix3D.newInstance(_unit); 423 M._data = this._data.minus(thatData); 424 425 return M; 426 } 427 428 /** 429 * Returns the product of this matrix by the specified factor. 430 * 431 * @param k the coefficient multiplier 432 * @return <code>this · k</code> 433 */ 434 @Override 435 public Matrix3D times(Parameter k) { 436 Matrix3D<?> M = FACTORY.object(); 437 438 // Find the combined units. 439 M._unit = (Unit)Parameter.productOf(this.getUnit(), k.getUnit()); 440 M._data = this._data.times(Float64.valueOf(k.getValue())); 441 442 return M; 443 } 444 445 /** 446 * Returns the product of this matrix by the specified factor. 447 * 448 * @param k the coefficient multiplier 449 * @return <code>this · k</code> 450 */ 451 public Matrix3D<Q> times(double k) { 452 Matrix3D<Q> M = FACTORY.object(); 453 454 M._unit = this._unit; 455 M._data = this._data.times(Float64.valueOf(k)); 456 457 return M; 458 } 459 460 /** 461 * Returns the product of this matrix by the specified vector. 462 * 463 * @param v the vector. 464 * @return <code>this · v</code> 465 * @throws DimensionException - if v.getDimension() != this.getNumberOfColumns() 466 */ 467 @Override 468 public Vector3D times(Vector v) { 469 470 // Make sure the input vector is a Vector3D instance. 471 Vector3D T = Vector3D.valueOf(v); 472 473 // Find the combined units. 474 Unit unit = Parameter.productOf(this.getUnit(), ((Parameter)v.get(0)).getUnit()); 475 476 // Multiply the vector and the matrix. 477 Float64Vector V = _data.times(T.toFloat64Vector()); 478 479 return Vector3D.valueOf(V, unit); 480 } 481 482 /** 483 * Returns the product of this matrix with the one specified. 484 * 485 * @param that the matrix multiplier. 486 * @return <code>this · that</code> 487 * @throws DimensionException - if this.getNumberOfColumns() != 488 * that.getNumberOfRows(). 489 */ 490 @Override 491 public Matrix3D times(Matrix that) { 492 493 // Convert input matrix to a Float64Matrix. 494 Float64Matrix thatData = toFloat64Matrix(that, null); 495 496 // Find the combined units. 497 Unit unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(0, 0)).getUnit()); 498 499 Matrix3D M = Matrix3D.newInstance(unit); 500 M._data = this._data.times(thatData); 501 502 return M; 503 } 504 505 /** 506 * Returns the inverse of this matrix. If the matrix is singular, the 507 * {@link #determinant()} will be zero (or nearly zero). 508 * 509 * @return <code>1 / this</code> 510 */ 511 @Override 512 public Matrix3D inverse() { 513 Unit unit = _unit.inverse(); 514 515 Matrix3D M = Matrix3D.newInstance(unit); 516 M._data = _data.inverse(); 517 518 return M; 519 } 520 521 /** 522 * Returns the determinant of this matrix. 523 * 524 * @return this matrix determinant. 525 */ 526 @Override 527 public Parameter determinant() { 528 Unit unit = _unit.pow(3); 529 530 Parameter P = Parameter.valueOf(_data.determinant().doubleValue(), unit); 531 532 return P; 533 } 534 535 /** 536 * Returns the transpose of this matrix. 537 * 538 * @return <code>A'</code> 539 */ 540 @Override 541 public Matrix3D<Q> transpose() { 542 543 Matrix3D<Q> M = Matrix3D.newInstance(_unit); 544 M._data = _data.transpose(); 545 546 return M; 547 } 548 549 /** 550 * Returns the cofactor of an element in this matrix. It is the value obtained by 551 * evaluating the determinant formed by the elements not in that particular row or 552 * column. 553 * 554 * @param i the row index. 555 * @param j the column index. 556 * @return the cofactor of THIS[i,j]. 557 */ 558 @Override 559 public Parameter cofactor(int i, int j) { 560 Unit unit = _unit.pow(2); 561 562 Parameter P = Parameter.valueOf(_data.cofactor(i, j).doubleValue(), unit); 563 564 return P; 565 } 566 567 /** 568 * Returns the adjoint of this matrix. It is obtained by replacing each element in 569 * this matrix with its cofactor and applying a + or - sign according to (-1)**(i+j), 570 * and then finding the transpose of the resulting matrix. 571 * 572 * @return the adjoint of this matrix. 573 */ 574 @Override 575 public Matrix3D adjoint() { 576 Unit unit = _unit.pow(2); 577 578 Matrix3D M = Matrix3D.newInstance(unit); 579 M._data = _data.adjoint(); 580 581 return M; 582 } 583 584 /** 585 * Returns the linear algebraic matrix tensor product of this matrix and another 586 * (Kronecker product). 587 * 588 * @param that the second matrix 589 * @return <code>this times that</code> 590 * @see <a href="http://en.wikipedia.org/wiki/Kronecker_product"> 591 * Wikipedia: Kronecker Product</a> 592 */ 593 @Override 594 public Matrix tensor(Matrix that) { 595 StackContext.enter(); 596 try { 597 Float64Matrix thatData; 598 599 // Convert "that" into a matrix of Float64 values. 600 if (that instanceof Matrix3D) { 601 Matrix3D T = (Matrix3D)that; 602 thatData = T._data; 603 604 } else { 605 FastTable<Float64Vector> rows = FastTable.newInstance(); 606 FastTable<Float64> rowi = FastTable.newInstance(); 607 int numCols = that.getNumberOfColumns(); 608 int numRows = that.getNumberOfRows(); 609 for (int i = 0; i < numRows; ++i) { 610 for (int j = 0; j < numCols; ++j) { 611 Parameter p = (Parameter)that.get(i, j); 612 rowi.add(Float64.valueOf(p.getValue())); 613 } 614 rows.add(Float64Vector.valueOf(rowi)); 615 rowi.clear(); 616 } 617 618 thatData = Float64Matrix.valueOf(rows); 619 } 620 621 Unit unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(0, 0)).getUnit()); 622 623 Float64Matrix matrix = _data.tensor(thatData); 624 625 FastTable rows = FastTable.newInstance(); 626 FastTable<Parameter> rowi = FastTable.newInstance(); 627 int numRows = matrix.getNumberOfRows(); 628 int numCols = matrix.getNumberOfColumns(); 629 for (int i = 0; i < numRows; ++i) { 630 for (int j = 0; j < numCols; ++j) { 631 Parameter p = Parameter.valueOf(matrix.get(i, j).doubleValue(), unit); 632 rowi.add(p); 633 } 634 rows.add(DenseVector.valueOf(rowi)); 635 rowi.clear(); 636 } 637 638 DenseMatrix M = DenseMatrix.valueOf(rows); 639 640 return StackContext.outerCopy(M); 641 642 } finally { 643 StackContext.exit(); 644 } 645 } 646 647 /** 648 * Compares this Matrix3D for approximate equality to zero (all the values are within 649 * the numerical roundoff error of zero). 650 * 651 * @return <code>true</code> if this Matrix3D is approximately equal to zero; 652 * <code>false</code> otherwise. 653 */ 654 public boolean isApproxZero() { 655 656 for (int i = 0; i < 3; ++i) { 657 for (int j = 0; j < 3; ++j) { 658 double value = this.getValue(i, j); 659 if (MathLib.abs(value) > Parameter.EPS) 660 return false; 661 } 662 } 663 664 return true; 665 } 666 667 /** 668 * Returns the vectorization of this matrix. The vectorization of a matrix is the 669 * column vector obtained by stacking the columns of the matrix on top of one another. 670 * The default implementation returns a <code>DenseVector<Parameter<?>></code>. 671 * 672 * @return the vectorization of this matrix. 673 */ 674 @Override 675 public Vector<Parameter<Q>> vectorization() { 676 Float64Vector V = _data.vectorization(); 677 FastTable<Parameter<Q>> list = FastTable.newInstance(); 678 679 int num = V.getDimension(); 680 for (int i = 0; i < num; ++i) { 681 double value = V.getValue(i); 682 Parameter<Q> p = Parameter.valueOf(value, _unit); 683 list.add(p); 684 } 685 return DenseVector.valueOf(list); 686 } 687 688 /** 689 * Returns a copy of this matrix allocated by the calling thread (possibly on the 690 * stack). 691 * 692 * @return an identical and independent copy of this matrix. 693 */ 694 @Override 695 public Matrix3D<Q> copy() { 696 return Matrix3D.copyOf(this); 697 } 698 699 /** 700 * Returns a Float64Matrix containing the data in this matrix in the current units of 701 * this matrix. 702 * 703 * @return A Float64Matrix containing the data in this matrix in the current units of 704 * this matrix. 705 */ 706 public Float64Matrix toFloat64Matrix() { 707 return _data; 708 } 709 710 /** 711 * Convert a matrix of parameter objects to a Float64Matrix stated in the specified 712 * units. 713 */ 714 private static <Q extends Quantity> Float64Matrix toFloat64Matrix(Matrix<Parameter<Q>> that, Unit<Q> unit) { 715 716 // Make sure input is a Matrix3D instance. 717 Matrix3D<Q> T = Matrix3D.valueOf(that); 718 719 // Convert that vector's units to the specified units if necessary. 720 Float64Matrix thatData = T._data; 721 if ((unit != null) && (unit != T._unit) && !unit.equals(T._unit)) { 722 UnitConverter cvtr = Parameter.converterOf(T._unit, unit); 723 if (cvtr != UnitConverter.IDENTITY) { 724 double a = cvtr.convert(thatData.get(0, 0).doubleValue()); 725 double b = cvtr.convert(thatData.get(0, 1).doubleValue()); 726 double c = cvtr.convert(thatData.get(0, 2).doubleValue()); 727 double d = cvtr.convert(thatData.get(1, 0).doubleValue()); 728 double e = cvtr.convert(thatData.get(1, 1).doubleValue()); 729 double f = cvtr.convert(thatData.get(1, 2).doubleValue()); 730 double g = cvtr.convert(thatData.get(2, 0).doubleValue()); 731 double h = cvtr.convert(thatData.get(2, 1).doubleValue()); 732 double i = cvtr.convert(thatData.get(2, 2).doubleValue()); 733 Float64Vector row0 = Float64Vector.valueOf(a, b, c); 734 Float64Vector row1 = Float64Vector.valueOf(d, e, f); 735 Float64Vector row2 = Float64Vector.valueOf(g, h, i); 736 thatData = Float64Matrix.valueOf(row0, row1, row2); 737 } 738 } 739 740 return thatData; 741 } 742 743 /** 744 * During serialization, this will write out the Float64Matrix as a simple series of 745 * <code>double</code> values. This method is ONLY called by the Java Serialization 746 * mechanism and should not otherwise be used. 747 * 748 * @param out The output stream to serialized this object to. 749 * @throws java.io.IOException if the output stream could not be written to. 750 */ 751 private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { 752 753 // Call the default write object method. 754 out.defaultWriteObject(); 755 756 // Write out the three coordinate values. 757 for (int i = 0; i < 3; ++i) 758 for (int j = 0; j < 3; ++j) 759 out.writeDouble(_data.get(i, j).doubleValue()); 760 761 } 762 763 /** 764 * During de-serialization, this will handle the reconstruction of the Float64Matrix. 765 * This method is ONLY called by the Java Serialization mechanism and should not 766 * otherwise be used. 767 * 768 * @param in The input stream to be de-serialized 769 * @throws java.io.IOException if there is a problem reading from the input stream. 770 * @throws ClassNotFoundException if the class could not be constructed. 771 */ 772 private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { 773 774 // Call the default read object method. 775 in.defaultReadObject(); 776 777 // Read in the three coordinate values. 778 FastTable<Float64Vector> rows = FastTable.newInstance(); 779 for (int i = 0; i < 3; ++i) { 780 double v1 = in.readDouble(); 781 double v2 = in.readDouble(); 782 double v3 = in.readDouble(); 783 Float64Vector row = Float64Vector.valueOf(v1, v2, v3); 784 rows.add(row); 785 } 786 787 _data = Float64Matrix.valueOf(rows); 788 FastTable.recycle(rows); 789 790 } 791 792 /////////////////////// 793 // Factory creation. // 794 /////////////////////// 795 private Matrix3D() { } 796 797 private static final ObjectFactory<Matrix3D> FACTORY = new ObjectFactory<Matrix3D>() { 798 @Override 799 protected Matrix3D create() { 800 return new Matrix3D(); 801 } 802 }; 803 804 private static <Q extends Quantity> Matrix3D<Q> newInstance(Unit<Q> unit) { 805 Matrix3D<Q> measure = FACTORY.object(); 806 measure._unit = unit; 807 return measure; 808 } 809 810 private static <Q extends Quantity> Matrix3D<Q> copyOf(Matrix3D<Q> original) { 811 Matrix3D<Q> measure = Matrix3D.newInstance(original._unit); 812 measure._data = original._data.copy(); 813 return measure; 814 } 815 816 /** 817 * Tests the methods in this class. 818 * 819 * @param args the command-line arguments 820 */ 821 public static void main(String args[]) { 822 System.out.println("Testing Matrix3D:"); 823 824 Matrix3D<Length> m1 = Matrix3D.valueOf(1, 2, 3, 4, 5, 6, 7, 8, 9, SI.METER); 825 System.out.println("m1 = \n" + m1); 826 System.out.println(" converted to feet = \n" + m1.to(NonSI.FOOT)); 827 System.out.println(" m1.getRow(1) = " + m1.getRow(1)); 828 System.out.println(" m1.getColumn(2) = " + m1.getColumn(2)); 829 System.out.println(" m1.getDiagonal() = " + m1.getDiagonal()); 830 System.out.println(" m1.opposite() = \n" + m1.opposite()); 831 System.out.println(" m1.transpose() = \n" + m1.transpose()); 832 System.out.println(" m1.vectorization() = \n" + m1.vectorization()); 833 System.out.println(" m1.determinant() = " + m1.determinant() + "; matrix is singular and can not be inverted"); 834 835 Parameter<Length> p1 = Parameter.valueOf(2, SI.METER); 836 System.out.println("\np1 = " + p1); 837 System.out.println(" m1.times(p1) = \n" + m1.times(p1)); 838 839 Matrix3D<Length> m2 = Matrix3D.valueOf(1, 0, 1, 0, 1, 0, -1, 0, 1, SI.METER); 840 System.out.println("\nm2 = \n" + m2); 841 System.out.println(" m2.determinant() = " + m2.determinant()); 842 System.out.println(" m2.inverse() = \n" + m2.inverse()); 843 System.out.println(" m2.cofactor(0,2) = " + m2.cofactor(0, 2)); 844 System.out.println(" m2.adjoint() = \n" + m2.adjoint()); 845 System.out.println(" m1.times(m2) = \n" + m1.times(m2)); 846 System.out.println(" m1.tensor(m2) = \n" + m1.tensor(m2)); 847 848 Vector3D<Length> v1 = Vector3D.valueOf(1, 2, 3, SI.METER); 849 System.out.println("\nv1 = " + v1); 850 System.out.println(" m1.times(v1) = " + m1.times(v1)); 851 852 // Write out XML data. 853 try { 854 System.out.println(); 855 856 // Creates some useful aliases for class names. 857 javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding(); 858 binding.setAlias(jahuwaldt.js.param.Parameter.class, "Parameter"); 859 860 javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out); 861 writer.setIndentation(" "); 862 writer.setBinding(binding); 863 writer.write(m2, "Matrix3D", Matrix3D.class); 864 writer.flush(); 865 866 System.out.println(); 867 } catch (Exception e) { 868 e.printStackTrace(); 869 } 870 } 871 872}