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