/* * $Id$ * This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc * * Copyright (c) 2000-2012 Stephane GALLAND. * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports, * Universite de Technologie de Belfort-Montbeliard. * Copyright (c) 2013-2016 The original authors, and other authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.arakhne.afc.math.matrix; import static org.arakhne.afc.math.MathConstants.JACOBI_EPSILON; import static org.arakhne.afc.math.MathConstants.JACOBI_MAX_SWEEPS; import java.io.Serializable; import java.util.Arrays; import org.eclipse.xtext.xbase.lib.Pure; import org.arakhne.afc.math.MathUtil; import org.arakhne.afc.math.extensions.xtext.MatrixExtensions; import org.arakhne.afc.math.geometry.d2.Point2D; import org.arakhne.afc.math.geometry.d2.Tuple2D; import org.arakhne.afc.math.geometry.d2.Vector2D; import org.arakhne.afc.vmutil.ReflectionUtil; import org.arakhne.afc.vmutil.annotations.ScalaOperator; import org.arakhne.afc.vmutil.annotations.XtextOperator; import org.arakhne.afc.vmutil.asserts.AssertMessages; /** * Is represented internally as a 2x2 floating point matrix. The mathematical * representation is row major, as in traditional matrix mathematics. * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ @SuppressWarnings({"checkstyle:magicnumber", "checkstyle:methodcount"}) public class Matrix2d implements Serializable, Cloneable { private static final long serialVersionUID = -181335987517755500L; /** * The first matrix element in the first row. */ protected double m00; /** * The second matrix element in the first row. */ protected double m01; /** * The first matrix element in the second row. */ protected double m10; /** * The second matrix element in the second row. */ protected double m11; /** Indicates if the matrix is identity. * If <code>null</code> the identity flag must be determined. */ protected Boolean isIdentity; /** * Constructs and initializes a Matrix2f from the specified nine values. * * @param m00 * the [0][0] element * @param m01 * the [0][1] element * @param m10 * the [1][0] element * @param m11 * the [1][1] element */ public Matrix2d(double m00, double m01, double m10, double m11) { this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; } /** * Constructs and initializes a Matrix2f from the specified nine- element * array. * * @param matrix * the array of length 4 containing in order */ public Matrix2d(double[] matrix) { assert matrix != null : AssertMessages.notNullParameter(); assert matrix.length >= 4 : AssertMessages.tooSmallArrayParameter(matrix.length, 4); this.m00 = matrix[0]; this.m01 = matrix[1]; this.m10 = matrix[2]; this.m11 = matrix[3]; } /** * Constructs a new matrix with the same values as the Matrix2f parameter. * * @param matrix * the source matrix */ public Matrix2d(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); this.m00 = matrix.m00; this.m01 = matrix.m01; this.m10 = matrix.m10; this.m11 = matrix.m11; } /** * Constructs and initializes a Matrix2f to all zeros. */ public Matrix2d() { this.m00 = 0.; this.m01 = 0.; this.m10 = 0.; this.m11 = 0.; } /** * Returns a string that contains the values of this Matrix2f. * * @return the String representation */ @Pure @Override public String toString() { return ReflectionUtil.toString(this); } /** * Sets this Matrix2f to identity. */ public final void setIdentity() { this.m00 = 1.; this.m01 = 0.; this.m10 = 0.; this.m11 = 1.; this.isIdentity = Boolean.TRUE; } /** * Sets the specified element of this Matrix2f to the value provided. * * @param row * the row number to be modified (zero indexed) * @param column * the column number to be modified (zero indexed) * @param value * the new value */ public final void setElement(int row, int column, double value) { assert row >= 0 && row < 2 : AssertMessages.outsideRangeInclusiveParameter(0, row, 0, 1); assert column >= 0 && column < 2 : AssertMessages.outsideRangeInclusiveParameter(1, column, 0, 1); switch (row) { case 0: switch (column) { case 0: this.m00 = value; break; case 1: this.m01 = value; break; default: throw new ArrayIndexOutOfBoundsException(); } break; case 1: switch (column) { case 0: this.m10 = value; break; case 1: this.m11 = value; break; default: throw new ArrayIndexOutOfBoundsException(); } break; default: throw new ArrayIndexOutOfBoundsException(); } this.isIdentity = null; } /** * Retrieves the value at the specified row and column of the specified * matrix. * * @param row * the row number to be retrieved (zero indexed) * @param column * the column number to be retrieved (zero indexed) * @return the value at the indexed element. */ @Pure public final double getElement(int row, int column) { assert row >= 0 && row < 2 : AssertMessages.outsideRangeInclusiveParameter(0, row, 0, 1); assert column >= 0 && column < 2 : AssertMessages.outsideRangeInclusiveParameter(1, column, 0, 1); switch (row) { case 0: switch (column) { case 0: return this.m00; case 1: return this.m01; default: break; } break; case 1: switch (column) { case 0: return this.m10; case 1: return this.m11; default: break; } break; default: break; } throw new ArrayIndexOutOfBoundsException(); } /** * Copies the matrix values in the specified row into the vector parameter. * * @param row * the matrix row * @param vector * the vector into which the matrix row values will be copied */ public final void getRow(int row, Tuple2D<?> vector) { assert row >= 0 && row < 2 : AssertMessages.outsideRangeInclusiveParameter(0, row, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); if (row == 0) { vector.set(this.m00, this.m01); } else if (row == 1) { vector.set(this.m10, this.m11); } else { throw new ArrayIndexOutOfBoundsException(); } } /** * Copies the matrix values in the specified row into the array parameter. * * @param row * the matrix row * @param vector * the array into which the matrix row values will be copied */ public final void getRow(int row, double[] vector) { assert row >= 0 && row < 2 : AssertMessages.outsideRangeInclusiveParameter(0, row, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); assert vector.length >= 2 : AssertMessages.tooSmallArrayParameter(1, vector.length, 2); if (row == 0) { vector[0] = this.m00; vector[1] = this.m01; } else if (row == 1) { vector[0] = this.m10; vector[1] = this.m11; } else { throw new ArrayIndexOutOfBoundsException(); } } /** * Copies the matrix values in the specified column into the vector * parameter. * * @param column * the matrix column * @param vector * the vector into which the matrix row values will be copied */ public final void getColumn(int column, Tuple2D<?> vector) { assert column >= 0 && column < 2 : AssertMessages.outsideRangeInclusiveParameter(0, column, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); if (column == 0) { vector.set(this.m00, this.m10); } else if (column == 1) { vector.set(this.m01, this.m11); } else { throw new ArrayIndexOutOfBoundsException(); } } /** * Copies the matrix values in the specified column into the array * parameter. * * @param column * the matrix column * @param vector * the array into which the matrix row values will be copied */ public final void getColumn(int column, double[] vector) { assert column >= 0 && column < 2 : AssertMessages.outsideRangeInclusiveParameter(0, column, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); assert vector.length >= 2 : AssertMessages.tooSmallArrayParameter(1, vector.length, 2); if (column == 0) { vector[0] = this.m00; vector[1] = this.m10; } else if (column == 1) { vector[0] = this.m01; vector[1] = this.m11; } else { throw new ArrayIndexOutOfBoundsException(); } } /** * Sets the specified row of this Matrix2f to the 4 values provided. * * @param row * the row number to be modified (zero indexed) * @param x * the first column element * @param y * the second column element */ public final void setRow(int row, double x, double y) { assert row >= 0 && row < 2 : AssertMessages.outsideRangeInclusiveParameter(0, row, 0, 1); switch (row) { case 0: this.m00 = x; this.m01 = y; break; case 1: this.m10 = x; this.m11 = y; break; default: throw new ArrayIndexOutOfBoundsException(); } this.isIdentity = null; } /** * Sets the specified row of this Matrix2f to the Vector provided. * * @param row * the row number to be modified (zero indexed) * @param vector * the replacement row */ public final void setRow(int row, Tuple2D<?> vector) { assert row >= 0 && row < 2 : AssertMessages.outsideRangeInclusiveParameter(0, row, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); switch (row) { case 0: this.m00 = vector.getX(); this.m01 = vector.getY(); break; case 1: this.m10 = vector.getX(); this.m11 = vector.getY(); break; default: throw new ArrayIndexOutOfBoundsException(); } this.isIdentity = null; } /** * Sets the specified row of this Matrix2f to the two values provided. * * @param row * the row number to be modified (zero indexed) * @param vector * the replacement row */ public final void setRow(int row, double[] vector) { assert row >= 0 && row < 2 : AssertMessages.outsideRangeInclusiveParameter(0, row, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); assert vector.length >= 2 : AssertMessages.tooSmallArrayParameter(1, vector.length, 2); switch (row) { case 0: this.m00 = vector[0]; this.m01 = vector[1]; break; case 1: this.m10 = vector[0]; this.m11 = vector[1]; break; default: throw new ArrayIndexOutOfBoundsException(); } this.isIdentity = null; } /** * Sets the specified column of this Matrix2f to the two values provided. * * @param column * the column number to be modified (zero indexed) * @param x * the first row element * @param y * the second row element */ public final void setColumn(int column, double x, double y) { assert column >= 0 && column < 2 : AssertMessages.outsideRangeInclusiveParameter(0, column, 0, 1); switch (column) { case 0: this.m00 = x; this.m10 = y; break; case 1: this.m01 = x; this.m11 = y; break; default: throw new ArrayIndexOutOfBoundsException(); } this.isIdentity = null; } /** * Sets the specified column of this Matrix2f to the vector provided. * * @param column * the column number to be modified (zero indexed) * @param vector * the replacement column */ public final void setColumn(int column, Tuple2D<?> vector) { assert column >= 0 && column < 2 : AssertMessages.outsideRangeInclusiveParameter(0, column, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); switch (column) { case 0: this.m00 = vector.getX(); this.m10 = vector.getY(); break; case 1: this.m01 = vector.getX(); this.m11 = vector.getY(); break; default: throw new ArrayIndexOutOfBoundsException(); } this.isIdentity = null; } /** * Sets the specified column of this Matrix2f to the two values provided. * * @param column * the column number to be modified (zero indexed) * @param vector * the replacement column */ public final void setColumn(int column, double[] vector) { assert column >= 0 && column < 2 : AssertMessages.outsideRangeInclusiveParameter(0, column, 0, 1); assert vector != null : AssertMessages.notNullParameter(1); assert vector.length >= 2 : AssertMessages.tooSmallArrayParameter(1, vector.length, 2); switch (column) { case 0: this.m00 = vector[0]; this.m10 = vector[1]; break; case 1: this.m01 = vector[0]; this.m11 = vector[1]; break; default: throw new ArrayIndexOutOfBoundsException(); } this.isIdentity = null; } /** * Adds a scalar to each component of this matrix. * * @param scalar * the scalar adder */ public final void add(double scalar) { this.m00 += scalar; this.m01 += scalar; this.m10 += scalar; this.m11 += scalar; this.isIdentity = null; } /** * Adds a scalar to each component of the matrix m1 and places the result * into this. Matrix m1 is not modified. * * @param scalar * the scalar adder * @param matrix * the original matrix values */ public final void add(double scalar, Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(1); this.m00 = matrix.m00 + scalar; this.m01 = matrix.m01 + scalar; this.m10 = matrix.m10 + scalar; this.m11 = matrix.m11 + scalar; this.isIdentity = null; } /** * Sets the value of this matrix to the matrix sum of matrices m1 and m2. * * @param matrix1 * the first matrix * @param matrix2 * the second matrix */ public final void add(Matrix2d matrix1, Matrix2d matrix2) { assert matrix1 != null : AssertMessages.notNullParameter(0); assert matrix2 != null : AssertMessages.notNullParameter(1); this.m00 = matrix1.m00 + matrix2.m00; this.m01 = matrix1.m01 + matrix2.m01; this.m10 = matrix1.m10 + matrix2.m10; this.m11 = matrix1.m11 + matrix2.m11; this.isIdentity = null; } /** * Sets the value of this matrix to the sum of itself and matrix m1. * * @param matrix * the other matrix */ public final void add(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); this.m00 += matrix.m00; this.m01 += matrix.m01; this.m10 += matrix.m10; this.m11 += matrix.m11; this.isIdentity = null; } /** * Sets the value of this matrix to the matrix difference of matrices m1 and * m2. * * @param matrix1 * the first matrix * @param matrix2 * the second matrix */ public final void sub(Matrix2d matrix1, Matrix2d matrix2) { assert matrix1 != null : AssertMessages.notNullParameter(0); assert matrix2 != null : AssertMessages.notNullParameter(1); this.m00 = matrix1.m00 - matrix2.m00; this.m01 = matrix1.m01 - matrix2.m01; this.m10 = matrix1.m10 - matrix2.m10; this.m11 = matrix1.m11 - matrix2.m11; this.isIdentity = null; } /** * Sets the value of this matrix to the matrix difference of itself and * matrix m1 (this = this - m1). * * @param matrix * the other matrix */ public final void sub(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); this.m00 -= matrix.m00; this.m01 -= matrix.m01; this.m10 -= matrix.m10; this.m11 -= matrix.m11; this.isIdentity = null; } /** * Sets the value of this matrix to its transpose. */ public final void transpose() { final double temp = this.m10; this.m10 = this.m01; this.m01 = temp; } /** * Sets the value of this matrix to the transpose of the argument matrix. * * @param matrix * the matrix to be transposed */ public final void transpose(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); if (this != matrix) { this.m00 = matrix.m00; this.m01 = matrix.m10; this.m10 = matrix.m01; this.m11 = matrix.m11; this.isIdentity = matrix.isIdentity(); } else { transpose(); } } /** * Sets the value of this matrix to the value of the Matrix2f argument. * * @param matrix * the source Matrix2f */ public final void set(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); this.m00 = matrix.m00; this.m01 = matrix.m01; this.m10 = matrix.m10; this.m11 = matrix.m11; this.isIdentity = matrix.isIdentity(); } /** * Sets the values in this Matrix2f equal to the row-major array parameter * (ie, the first two elements of the array will be copied into the first * row of this matrix, etc.). * * @param matrix * the double precision array of length 4 */ public final void set(double[] matrix) { assert matrix != null : AssertMessages.notNullParameter(); assert matrix.length >= 2 : AssertMessages.tooSmallArrayParameter(matrix.length, 2); this.m00 = matrix[0]; this.m01 = matrix[1]; this.m10 = matrix[2]; this.m11 = matrix[4]; this.isIdentity = null; } /** * Set the components of the matrix. * * @param m00 * the [0][0] element * @param m01 * the [0][1] element * @param m10 * the [1][0] element * @param m11 * the [1][1] element */ public void set(double m00, double m01, double m10, double m11) { this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; this.isIdentity = null; } /** * Computes the determinant of this matrix. * * @return the determinant of the matrix */ @Pure public final double determinant() { return this.m00 * this.m11 - this.m01 * this.m10; } /** * Multiplies each element of this matrix by a scalar. * * @param scalar * The scalar multiplier. */ public final void mul(double scalar) { this.m00 *= scalar; this.m01 *= scalar; this.m10 *= scalar; this.m11 *= scalar; this.isIdentity = null; } /** * Multiplies each element of matrix m1 by a scalar and places the result * into this. Matrix m1 is not modified. * * @param scalar * the scalar multiplier * @param matrix * the original matrix */ public final void mul(double scalar, Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(1); this.m00 = scalar * matrix.m00; this.m01 = scalar * matrix.m01; this.m10 = scalar * matrix.m10; this.m11 = scalar * matrix.m11; this.isIdentity = null; } /** * Sets the value of this matrix to the result of multiplying itself with * matrix m1. * * @param matrix * the other matrix */ public final void mul(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); final double m00 = this.m00 * matrix.m00 + this.m01 * matrix.m10; final double m01 = this.m00 * matrix.m01 + this.m01 * matrix.m11; final double m10 = this.m10 * matrix.m00 + this.m11 * matrix.m10; final double m11 = this.m10 * matrix.m01 + this.m11 * matrix.m11; this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; this.isIdentity = null; } /** * Multiply this matrix by the given vector v and set the resulting vector. * * @param vector the input vector * @param result is set with (this * v). */ @Pure public final void mul(Tuple2D<?> vector, Tuple2D<?> result) { assert vector != null : AssertMessages.notNullParameter(0); assert result != null : AssertMessages.notNullParameter(1); result.set( this.m00 * vector.getX() + this.m01 * vector.getY(), this.m10 * vector.getX() + this.m11 * vector.getY()); } /** * Sets the value of this matrix to the result of multiplying the two * argument matrices together. * * @param matrix1 * the first matrix * @param matrix2 * the second matrix */ public final void mul(Matrix2d matrix1, Matrix2d matrix2) { assert matrix1 != null : AssertMessages.notNullParameter(0); assert matrix2 != null : AssertMessages.notNullParameter(1); if (this != matrix1 && this != matrix2) { this.m00 = matrix1.m00 * matrix2.m00 + matrix1.m01 * matrix2.m10; this.m01 = matrix1.m00 * matrix2.m01 + matrix1.m01 * matrix2.m11; this.m10 = matrix1.m10 * matrix2.m00 + matrix1.m11 * matrix2.m10; this.m11 = matrix1.m10 * matrix2.m01 + matrix1.m11 * matrix2.m11; } else { final double m00 = matrix1.m00 * matrix2.m00 + matrix1.m01 * matrix2.m10; final double m01 = matrix1.m00 * matrix2.m01 + matrix1.m01 * matrix2.m11; final double m10 = matrix1.m10 * matrix2.m00 + matrix1.m11 * matrix2.m10; final double m11 = matrix1.m10 * matrix2.m01 + matrix1.m11 * matrix2.m11; this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; } this.isIdentity = null; } /** * Multiplies the transpose of matrix m1 times the transpose of matrix m2, * and places the result into this. * * @param matrix1 * the matrix on the left hand side of the multiplication * @param matrix2 * the matrix on the right hand side of the multiplication */ public final void mulTransposeBoth(Matrix2d matrix1, Matrix2d matrix2) { assert matrix1 != null : AssertMessages.notNullParameter(0); assert matrix2 != null : AssertMessages.notNullParameter(1); if (this != matrix1 && this != matrix2) { this.m00 = matrix1.m00 * matrix2.m00 + matrix1.m10 * matrix2.m01; this.m01 = matrix1.m00 * matrix2.m10 + matrix1.m10 * matrix2.m11; this.m10 = matrix1.m01 * matrix2.m00 + matrix1.m11 * matrix2.m01; this.m11 = matrix1.m01 * matrix2.m10 + matrix1.m11 * matrix2.m11; } else { final double m00 = matrix1.m00 * matrix2.m00 + matrix1.m10 * matrix2.m01; final double m01 = matrix1.m00 * matrix2.m10 + matrix1.m10 * matrix2.m11; final double m10 = matrix1.m01 * matrix2.m00 + matrix1.m11 * matrix2.m01; final double m11 = matrix1.m01 * matrix2.m10 + matrix1.m11 * matrix2.m11; this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; } this.isIdentity = null; } /** * Multiplies matrix m1 times the transpose of matrix m2, and places the * result into this. * * @param matrix1 * the matrix on the left hand side of the multiplication * @param matrix2 * the matrix on the right hand side of the multiplication */ public final void mulTransposeRight(Matrix2d matrix1, Matrix2d matrix2) { assert matrix1 != null : AssertMessages.notNullParameter(0); assert matrix2 != null : AssertMessages.notNullParameter(1); if (this != matrix1 && this != matrix2) { this.m00 = matrix1.m00 * matrix2.m00 + matrix1.m01 * matrix2.m01; this.m01 = matrix1.m00 * matrix2.m10 + matrix1.m01 * matrix2.m11; this.m10 = matrix1.m10 * matrix2.m00 + matrix1.m11 * matrix2.m01; this.m11 = matrix1.m10 * matrix2.m10 + matrix1.m11 * matrix2.m11; } else { final double m00 = matrix1.m00 * matrix2.m00 + matrix1.m01 * matrix2.m01; final double m01 = matrix1.m00 * matrix2.m10 + matrix1.m01 * matrix2.m11; final double m10 = matrix1.m10 * matrix2.m00 + matrix1.m11 * matrix2.m01; final double m11 = matrix1.m10 * matrix2.m10 + matrix1.m11 * matrix2.m11; this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; } this.isIdentity = null; } /** * Multiplies the transpose of matrix m1 times matrix m2, and places the * result into this. * * @param matrix1 * the matrix on the left hand side of the multiplication * @param matrix2 * the matrix on the right hand side of the multiplication */ public final void mulTransposeLeft(Matrix2d matrix1, Matrix2d matrix2) { assert matrix1 != null : AssertMessages.notNullParameter(0); assert matrix2 != null : AssertMessages.notNullParameter(1); if (this != matrix1 && this != matrix2) { this.m00 = matrix1.m00 * matrix2.m00 + matrix1.m10 * matrix2.m10; this.m01 = matrix1.m00 * matrix2.m01 + matrix1.m10 * matrix2.m11; this.m10 = matrix1.m01 * matrix2.m00 + matrix1.m11 * matrix2.m10; this.m11 = matrix1.m01 * matrix2.m01 + matrix1.m11 * matrix2.m11; } else { final double m00 = matrix1.m00 * matrix2.m00 + matrix1.m10 * matrix2.m10; final double m01 = matrix1.m00 * matrix2.m01 + matrix1.m10 * matrix2.m11; final double m10 = matrix1.m01 * matrix2.m00 + matrix1.m11 * matrix2.m10; final double m11 = matrix1.m01 * matrix2.m01 + matrix1.m11 * matrix2.m11; this.m00 = m00; this.m01 = m01; this.m10 = m10; this.m11 = m11; } this.isIdentity = null; } /** * Perform cross product normalization of this matrix. */ public final void normalizeCP() { double mag = 1.0 / Math.sqrt(this.m00 * this.m00 + this.m10 * this.m10); this.m00 = this.m00 * mag; this.m10 = this.m10 * mag; mag = 1.0 / Math.sqrt(this.m01 * this.m01 + this.m11 * this.m11); this.m01 = this.m01 * mag; this.m11 = this.m11 * mag; this.isIdentity = null; } /** * Perform cross product normalization of matrix m1 and place the normalized * values into this. * * @param matrix * Provides the matrix values to be normalized */ public final void normalizeCP(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); double mag = 1.0 / Math.sqrt(matrix.m00 * matrix.m00 + matrix.m10 * matrix.m10); this.m00 = matrix.m00 * mag; this.m10 = matrix.m10 * mag; mag = 1.0 / Math.sqrt(matrix.m01 * matrix.m01 + matrix.m11 * matrix.m11); this.m01 = matrix.m01 * mag; this.m11 = matrix.m11 * mag; this.isIdentity = null; } /** * Returns true if all of the data members of Matrix2f m1 are equal to the * corresponding data members in this Matrix2f. * * @param matrix * the matrix with which the comparison is made * @return true or false */ @Pure public boolean equals(Matrix2d matrix) { try { return this.m00 == matrix.m00 && this.m01 == matrix.m01 && this.m10 == matrix.m10 && this.m11 == matrix.m11; } catch (NullPointerException e2) { return false; } } /** * Returns true if the Object t1 is of type Matrix2f and all of the data * members of t1 are equal to the corresponding data members in this * Matrix2f. * * @param object * the matrix with which the comparison is made * @return true or false */ @Pure @Override public boolean equals(Object object) { if (object == this) { return true; } if (getClass().isInstance(object)) { final Matrix2d m2 = (Matrix2d) object; return this.m00 == m2.m00 && this.m01 == m2.m01 && this.m10 == m2.m10 && this.m11 == m2.m11; } return false; } /** * Returns a hash code value based on the data values in this object. Two * different Matrix2f objects with identical data values (i.e., * Matrix2f.equals returns true) will return the same hash code value. Two * objects with different data members may return the same hash value, * although this is not likely. * * @return the integer hash code value */ @Pure @Override public int hashCode() { long bits = 1L; bits = 31L * bits + Double.hashCode(this.m00); bits = 31L * bits + Double.hashCode(this.m01); bits = 31L * bits + Double.hashCode(this.m10); bits = 31L * bits + Double.hashCode(this.m11); return (int) (bits ^ (bits >> 31)); } /** * Sets this matrix to all zeros. */ public final void setZero() { this.m00 = 0.; this.m01 = 0.; this.m10 = 0.; this.m11 = 0.; this.isIdentity = Boolean.FALSE; } /** * Sets this matrix as diagonal. * * @param m00 * the first element of the diagonal * @param m11 * the second element of the diagonal */ public final void setDiagonal(double m00, double m11) { this.m00 = m00; this.m01 = 0.; this.m10 = 0.; this.m11 = m11; this.isIdentity = null; } /** * Negates the value of this matrix: this = -this. */ public final void negate() { this.m00 = -this.m00; this.m01 = -this.m01; this.m10 = -this.m10; this.m11 = -this.m11; this.isIdentity = null; } /** * Sets the value of this matrix equal to the negation of of the Matrix2f * parameter. * * @param matrix * the source matrix */ public final void negate(Matrix2d matrix) { assert matrix != null : AssertMessages.notNullParameter(); this.m00 = -matrix.m00; this.m01 = -matrix.m01; this.m10 = -matrix.m10; this.m11 = -matrix.m11; this.isIdentity = null; } /** * Creates a new object of the same class as this object. * * @return a clone of this instance. * @exception OutOfMemoryError * if there is not enough memory. * @see java.lang.Cloneable */ @Pure @Override public Matrix2d clone() { Matrix2d m1 = null; try { m1 = (Matrix2d) super.clone(); } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } // Also need to create new tmp arrays (no need to actually clone them) return m1; } /** * Get the first matrix element in the first row. * * @return Returns the m00. */ @Pure public final double getM00() { return this.m00; } /** * Set the first matrix element in the first row. * * @param m00 * The m00 to set. */ public final void setM00(double m00) { this.m00 = m00; } /** * Get the second matrix element in the first row. * * @return Returns the m01. */ @Pure public final double getM01() { return this.m01; } /** * Set the second matrix element in the first row. * * @param m01 * The m01 to set. */ public final void setM01(double m01) { this.m01 = m01; } /** * Get first matrix element in the second row. * * @return Returns the m10. */ @Pure public final double getM10() { return this.m10; } /** * Set first matrix element in the second row. * * @param m10 * The m10 to set. */ public final void setM10(double m10) { this.m10 = m10; } /** * Get second matrix element in the second row. * * @return Returns the m11. */ @Pure public final double getM11() { return this.m11; } /** * Set the second matrix element in the second row. * * @param m11 * The m11 to set. */ public final void setM11(double m11) { this.m11 = m11; this.isIdentity = null; } /** Set this matrix with the covariance matrix's elements for the given * set of tuples. * * @param result the mean of the tuples. * @param tuples the input tuples. * @return <code>true</code> if the covariance matrix could be computed. */ public final boolean cov(Vector2D<?, ?> result, Vector2D<?, ?>... tuples) { assert result != null : AssertMessages.notNullParameter(0); assert tuples != null : AssertMessages.notNullParameter(1); return cov(result, Arrays.asList(tuples)); } /** Set this matrix with the covariance matrix's elements for the given * set of tuples. * * @param result the mean of the tuples. * @param tuples the input tuples. * @return <code>true</code> if the covariance matrix could be computed. */ public final boolean cov(Vector2D<?, ?> result, Point2D<?, ?>... tuples) { assert result != null : AssertMessages.notNullParameter(0); assert tuples != null : AssertMessages.notNullParameter(1); return cov(result, Arrays.asList(tuples)); } /** Set this matrix with the covariance matrix's elements for the given * set of tuples. * * @param result the mean of the tuples. * @param tuples the input tuples. * @return <code>true</code> if the covariance matrix could be computed. */ public boolean cov(Vector2D<?, ?> result, Iterable<? extends Tuple2D<?>> tuples) { assert result != null : AssertMessages.notNullParameter(0); assert tuples != null : AssertMessages.notNullParameter(1); setZero(); // Compute the mean m double mx = 0; double my = 0; int count = 0; for (final Tuple2D<?> p : tuples) { mx += p.getX(); my += p.getY(); ++count; } if (count == 0) { return false; } final double scale = 1. / count; mx *= scale; my *= scale; // Compute the covariance term [Gottshalk2000] // c_ij = sum(p'_i * p'_j) / n // c_ij = sum((p_i - m_i) * (p_j - m_j)) / n for (final Tuple2D<?> p : tuples) { this.m00 += (p.getX() - mx) * (p.getX() - mx); this.m01 += (p.getX() - mx) * (p.getY() - my); //cov.m10 += (p.getY() - my) * (p.getX() - mx); // same as m01 this.m11 += (p.getY() - my) * (p.getY() - my); } this.m00 /= count; this.m01 /= count; this.m10 = this.m01; this.m11 /= count; result.set(mx, my); this.isIdentity = null; return true; } /** Replies if the matrix is symmetric. * * @return <code>true</code> if the matrix is symmetric, otherwise * <code>false</code> */ @Pure public boolean isSymmetric() { return this.m01 == this.m10; } /** * Compute the eigenvectors of this matrix, assuming it is a symmetric matrix * according to the Jacobi Cyclic Method. * * @param eigenVectors are the matrix of vectors to fill. Eigen vectors are the * columns of the matrix. * @return the eigenvalues which are corresponding to the {@code eigenVectors} columns. * @see #eigenVectorsOfSymmetricMatrix(Matrix2d) */ public double[] eigenVectorsOfSymmetricMatrix(Matrix2d eigenVectors) { assert eigenVectors != null : AssertMessages.notNullParameter(); // Copy values up to the diagonal double m11 = getM00(); double m12 = getM01(); double m22 = getM11(); eigenVectors.setIdentity(); boolean sweepsConsumed = true; for (int a = 0; a < JACOBI_MAX_SWEEPS; ++a) { // Exit loop if off-diagonal entries are small enough if (Math.abs(m12) < JACOBI_EPSILON) { sweepsConsumed = false; break; } // Annihilate (1, 2) entry if (m12 != 0.) { final double u = (m22 - m11) * .5 / m12; final double u2 = u * u; final double u2p1 = u2 + 1.; final double t; if (u2p1 != u2) { t = Math.signum(u) * (Math.sqrt(u2p1) - Math.abs(u)); } else { t = .5 / u; } final double c = 1. / Math.sqrt(t * t + 1); final double s = c * t; m11 -= t * m12; m22 += t * m12; m12 = 0.; for (int i = 0; i < 2; ++i) { final double ri0 = eigenVectors.getElement(i, 0); final double ri1 = eigenVectors.getElement(i, 1); eigenVectors.setElement(i, 0, c * ri0 - s * ri1); eigenVectors.setElement(i, 1, s * ri0 + c * ri1); } } } assert !sweepsConsumed; // eigenvalues are on the diagonal return new double[] {m11, m22}; } /** Replies if the matrix is identity. * * <p>This function uses the equal-to-zero test with the error {@link Math#ulp(double)}. * * @return <code>true</code> if the matrix is identity; <code>false</code> otherwise. * @see MathUtil#isEpsilonZero(double) * @see MathUtil#isEpsilonEqual(double, double) */ @Pure public boolean isIdentity() { if (this.isIdentity == null) { this.isIdentity = MathUtil.isEpsilonEqual(this.m00, 1.) && MathUtil.isEpsilonZero(this.m01) && MathUtil.isEpsilonZero(this.m10) && MathUtil.isEpsilonEqual(this.m11, 1.); } return this.isIdentity.booleanValue(); } /** Add the given matrix to this matrix: {@code this += matrix}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param matrix the matrix. * @see #add(Matrix2d) */ @XtextOperator("+=") public void operator_add(Matrix2d matrix) { add(matrix); } /** Add the given scalar to this matrix: {@code this += scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param scalar the scalar. * @see #add(double) */ @XtextOperator("+=") public void operator_add(double scalar) { add(scalar); } /** Substract the given matrix to this matrix: {@code this -= matrix}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param matrix the matrix. * @see #sub(Matrix2d) */ @XtextOperator("-=") public void operator_remove(Matrix2d matrix) { sub(matrix); } /** Substract the given scalar to this matrix: {@code this -= scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param scalar the scalar. * @see #add(double) */ @XtextOperator("-=") public void operator_remove(double scalar) { add(-scalar); } /** Replies the addition of the given matrix to this matrix: {@code this + matrix}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param matrix the matrix. * @return the sum of the matrices. * @see #add(Matrix2d) */ @Pure @XtextOperator("+") public Matrix2d operator_plus(Matrix2d matrix) { final Matrix2d result = new Matrix2d(); result.add(this, matrix); return result; } /** Replies the addition of the given scalar to this matrix: {@code this + scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * <p>The operation {@code scalar + this} is supported by {@link MatrixExtensions#operator_plus(double, Matrix2d)}. * * @param scalar the scalar. * @return the sum of the matrix and the scalar. * @see #add(double) * @see MatrixExtensions#operator_plus(double, Matrix2d) */ @Pure @XtextOperator("+") public Matrix2d operator_plus(double scalar) { final Matrix2d result = new Matrix2d(); result.add(scalar, this); return result; } /** Replies the substraction of the given matrix to this matrix: {@code this + matrix}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param matrix the matrix. * @return the result of the substraction. * @see #sub(Matrix2d) */ @Pure @XtextOperator("-") public Matrix2d operator_minus(Matrix2d matrix) { final Matrix2d result = new Matrix2d(); result.sub(this, matrix); return result; } /** Replies the substraction of the given scalar to this matrix: {@code this - scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * <p>The operation {@code scalar - this} is supported by {@link MatrixExtensions#operator_minus(double, Matrix2d)}. * * @param scalar the scalar. * @return the result of the substraction. * @see #add(double) * @see MatrixExtensions#operator_minus(double, Matrix2d) */ @Pure @XtextOperator("-") public Matrix2d operator_minus(double scalar) { final Matrix2d result = new Matrix2d(); result.add(-scalar, this); return result; } /** Replies the negation of this matrix: {@code -this}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @return the negation of this matrix. * @see #negate() */ @Pure @XtextOperator("(-)") public Matrix2d operator_minus() { final Matrix2d result = new Matrix2d(); result.negate(this); return result; } /** Replies the multiplication of the given matrix and this matrix: {@code this * matrix}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @param matrix the matrix. * @return the multiplication of the matrices. * @see #mul(Matrix2d) */ @Pure @XtextOperator("*") public Matrix2d operator_multiply(Matrix2d matrix) { final Matrix2d result = new Matrix2d(); result.mul(this, matrix); return result; } /** Replies the multiplication of the given scalar and this matrix: {@code this * scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * <p>The operation {@code scalar * this} is supported by {@link MatrixExtensions#operator_multiply(double, Matrix2d)}. * * @param scalar the scalar. * @return the multiplication of the scalar and the matrix. * @see #mul(Matrix2d) * @see MatrixExtensions#operator_multiply(double, Matrix2d) */ @Pure @XtextOperator("*") public Matrix2d operator_multiply(double scalar) { final Matrix2d result = new Matrix2d(); result.mul(scalar, this); return result; } /** Replies the division of this matrix by the given scalar: {@code this / scalar}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * <p>The operation {@code this / scalar} is supported by {@link MatrixExtensions#operator_divide(double, Matrix2d)}. * * @param scalar the scalar. * @return the division of the matrix by the scalar. * @see #mul(double) * @see MatrixExtensions#operator_divide(double, Matrix2d) */ @Pure @XtextOperator("/") public Matrix2d operator_divide(double scalar) { final Matrix2d result = new Matrix2d(); result.mul(1. / scalar, this); return result; } /** Increment this matrix: {@code this++}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @see #add(double) */ @XtextOperator("++") public void operator_plusPlus() { add(1); } /** Increment this matrix: {@code this--}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @see #add(double) */ @XtextOperator("--") public void operator_moinsMoins() { add(-1); } /** Replies the transposition of this matrix: {@code !this}. * * <p>This function is an implementation of the operator for * the languages that defined or based on the * <a href="https://www.eclipse.org/Xtext/">Xtext framework</a>. * * @return the transpose * @see #add(double) */ @XtextOperator("!") public Matrix2d operator_not() { final Matrix2d result = new Matrix2d(); result.transpose(this); return result; } /** Replies the addition of the given matrix to this matrix: {@code this + matrix}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @param matrix the matrix. * @return the sum of the matrices. * @see #add(Matrix2d) */ @Pure @ScalaOperator("+") public Matrix2d $plus(Matrix2d matrix) { return operator_plus(matrix); } /** Replies the addition of the given scalar to this matrix: {@code this + scalar}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * <p>The operation {@code scalar + this} is supported by * {@link org.arakhne.afc.math.extensions.scala.MatrixExtensions#$plus(double, Matrix2d)}. * * @param scalar the scalar. * @return the sum of the matrix and the scalar. * @see #add(double) * @see org.arakhne.afc.math.extensions.scala.MatrixExtensions#$plus(double, Matrix2d) */ @Pure @ScalaOperator("+") public Matrix2d $plus(double scalar) { return operator_plus(scalar); } /** Replies the substraction of the given matrix to this matrix: {@code this + matrix}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @param matrix the matrix. * @return the result of the substraction. * @see #sub(Matrix2d) */ @Pure @ScalaOperator("-") public Matrix2d $minus(Matrix2d matrix) { return operator_minus(matrix); } /** Replies the substraction of the given scalar to this matrix: {@code this - scalar}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * <p>The operation {@code scalar - this} is supported by * {@link org.arakhne.afc.math.extensions.scala.MatrixExtensions#$minus(double, Matrix2d)}. * * @param scalar the scalar. * @return the result of the substraction. * @see #add(double) * @see org.arakhne.afc.math.extensions.scala.MatrixExtensions#$minus(double, Matrix2d) */ @Pure @ScalaOperator("-") public Matrix2d $minus(double scalar) { return operator_minus(scalar); } /** Replies the negation of this matrix: {@code -this}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @return the negation of this matrix. * @see #negate() */ @Pure @ScalaOperator("(-)") public Matrix2d $minus() { return operator_minus(); } /** Replies the multiplication of the given matrix and this matrix: {@code this * matrix}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @param matrix the matrix. * @return the multiplication of the matrices. * @see #mul(Matrix2d) */ @Pure @ScalaOperator("*") public Matrix2d $times(Matrix2d matrix) { return operator_multiply(matrix); } /** Replies the multiplication of the given scalar and this matrix: {@code this * scalar}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * <p>The operation {@code scalar * this} is supported by * {@link org.arakhne.afc.math.extensions.scala.MatrixExtensions#$times(double, Matrix2d)}. * * @param scalar the scalar. * @return the multiplication of the scalar and the matrix. * @see #mul(Matrix2d) * @see org.arakhne.afc.math.extensions.scala.MatrixExtensions#$times(double, Matrix2d) */ @Pure @ScalaOperator("*") public Matrix2d $times(double scalar) { return operator_multiply(scalar); } /** Replies the division of this matrix by the given scalar: {@code this / scalar}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * <p>The operation {@code this / scalar} is supported by * {@link org.arakhne.afc.math.extensions.scala.MatrixExtensions#$div(double, Matrix2d)}. * * @param scalar the scalar. * @return the division of the matrix by the scalar. * @see #mul(double) * @see org.arakhne.afc.math.extensions.scala.MatrixExtensions#$div(double, Matrix2d) */ @Pure @ScalaOperator("/") public Matrix2d $div(double scalar) { return operator_divide(scalar); } /** Replies the transposition of this matrix: {@code !this}. * * <p>This function is an implementation of the operator for * the <a href="http://scala-lang.org/">Scala Language</a>. * * @return the transpose * @see #add(double) */ @ScalaOperator("!") public Matrix2d $bang() { return operator_not(); } }