/*
* $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 org.arakhne.afc.math.continous.object2d.Point2f;
import org.arakhne.afc.math.continous.object2d.Vector2f;
import org.arakhne.afc.math.generic.Point2D;
import org.arakhne.afc.math.generic.Tuple2D;
/** A 2D transformation.
* Is represented internally as a 3x3 floating point matrix. The
* mathematical representation is row major, as in traditional
* matrix mathematics.
*
* <p>The transformation matrix is:
* <pre><code>
* | cos(theta) | -sin(theta) | Tx |
* | sin(theta) | cos(theta) | Ty |
* | 0 | 0 | 1 |
* </code></pre>
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @deprecated see {@link org.arakhne.afc.math.geometry.d2.Transform2D}
*/
@Deprecated
@SuppressWarnings("checkstyle:all")
public class Transform2D extends Matrix3d {
private static final long serialVersionUID = -3437760883865605968L;
/**
* Constructs a new Transform2D object and sets it to the identity transformation.
*/
public Transform2D() {
super(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f);
}
/**
* Constructs a new Transform2D object and initializes it from the
* specified transform.
*
* @param t
*/
public Transform2D(Transform2D t) {
super(t);
}
/**
* @param m
*/
public Transform2D(Matrix3d m) {
super(m);
}
/**
* Constructs and initializes a Matrix3f from the specified nine values.
*
* @param m00
* the [0][0] element
* @param m01
* the [0][1] element
* @param m02
* the [0][2] element
* @param m10
* the [1][0] element
* @param m11
* the [1][1] element
* @param m12
* the [1][2] element
*/
public Transform2D(float m00, float m01, float m02, float m10, float m11, float m12) {
super(m00, m01, m02, m10, m11, m12, 0f, 0f, 1f);
}
@Override
public Transform2D clone() {
return (Transform2D)super.clone();
}
/** Set the position.
* <p>
* This function changes only the elements of
* the matrix related to the translation (m02,
* m12). The scaling and the shearing are not changed.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ ? ? x ]
* [ ? ? y ]
* [ ? ? ? ]
* </pre>
*
* @param x
* @param y
* @see #makeTranslationMatrix(float, float)
*/
public void setTranslation(float x, float y) {
this.m02 = x;
this.m12 = y;
}
/** Set the position.
* <p>
* This function changes only the elements of
* the matrix related to the translation (m02,
* m12). The scaling and the shearing are not changed.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ ? ? t.x ]
* [ ? ? t.y ]
* [ ? ? ? ]
* </pre>
*
* @param t
* @see #makeTranslationMatrix(float, float)
*/
public void setTranslation(Tuple2D<?> t) {
this.m02 = t.getX();
this.m12 = t.getY();
}
/** Translate the position.
* <p>
* This function is equivalent to:
* <pre>
* this = this * [ 0 0 dx ]
* [ 0 0 dy ]
* [ 0 0 1 ]
* </pre>
*
* @param dx
* @param dy
*/
public void translate(float dx, float dy) {
this.m02 = this.m00 * dx + this.m01 * dy + this.m02;
this.m12 = this.m10 * dx + this.m11 * dy + this.m12;
}
/** Translate the position.
* <p>
* This function is equivalent to:
* <pre>
* this = this * [ 0 0 t.x ]
* [ 0 0 t.y ]
* [ 0 0 1 ]
* </pre>
*
* @param t
*/
public void translate(Vector2f t) {
translate(t.getX(), t.getY());
}
/** Replies the X translation.
*
* @return the amount
*/
public float getTranslationX() {
return (float) this.m02;
}
/** Replies the Y translation.
*
* @return the amount
*/
public float getTranslationY() {
return (float) this.m12;
}
/** Replies the translation.
*
* @return the amount
*/
public Vector2f getTranslationVector() {
return new Vector2f(this.m02, this.m12);
}
/**
* Replies the rotation for the object (theta).
*
* @return the amount
*/
public float getRotation() {
float cosAngle = (float)Math.acos(this.m00);
float sinAngle = (float)Math.asin(this.m10);
return (sinAngle<0f) ? -cosAngle : cosAngle;
}
/**
* Set the rotation for the object (theta).
* <p>
* This function changes only the elements of
* the matrix related to the rotation (m00,
* m01, m10, m11). The translation is not changed.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ cos(theta) -sin(theta) ? ]
* [ sin(theta) cos(theta) ? ]
* [ ? ? ? ]
* </pre>
*
* @param theta
* @see #makeRotationMatrix(float)
*/
public void setRotation(float theta) {
float cosTheta = (float)Math.cos(theta);
float sinTheta = (float)Math.sin(theta);
this.m00 = cosTheta;
this.m01 = -sinTheta;
this.m10 = sinTheta;
this.m11 = cosTheta;
}
/**
* Rotate the object (theta).
* <p>
* This function is equivalent to:
* <pre>
* this = this * [ cos(theta) -sin(theta) 0 ]
* [ sin(theta) cos(theta) 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param theta
*/
public void rotate(float theta) {
// Copied from AWT API
float sin = (float)Math.sin(theta);
if (sin == 1f) {
rotate90();
}
else if (sin == -1f) {
rotate270();
}
else {
float cos = (float)Math.cos(theta);
if (cos == -1f) {
rotate180();
}
else if (cos != 1f) {
float M0, M1;
M0 = (float)this.m00;
M1 = (float)this.m01;
this.m00 = cos * M0 + sin * M1;
this.m01 = -sin * M0 + cos * M1;
M0 = (float)this.m10;
M1 = (float)this.m11;
this.m10 = cos * M0 + sin * M1;
this.m11 = -sin * M0 + cos * M1;
}
}
}
private final void rotate90() {
// Copied from AWT API
float M0 = (float)this.m00;
this.m00 = this.m01;
this.m01 = -M0;
M0 = (float)this.m10;
this.m10 = this.m11;
this.m11 = -M0;
}
private final void rotate180() {
// Copied from AWT API
this.m00 = -this.m00;
this.m11 = -this.m11;
// If there was a shear, then this rotation has no
// effect on the state.
this.m01 = -this.m01;
this.m10 = -this.m10;
}
private final void rotate270() {
// Copied from AWT API
float M0 = (float)this.m00;
this.m00 = -this.m01;
this.m01 = M0;
M0 = (float)this.m10;
this.m10 = -this.m11;
this.m11 = M0;
}
/** Set the scale.
* <p>
* This function changes only the elements of
* the matrix related to the scaling (m00,
* m11). The shearing and the translation are not changed.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ sx ? ? ]
* [ ? sy ? ]
* [ ? ? ? ]
* </pre>
*
* @param sx
* @param sy
* @see #makeScaleMatrix(float, float)
*/
public void setScale(float sx, float sy) {
this.m00 = sx;
this.m11 = sy;
}
/** Set the scale.
* <p>
* This function changes only the elements of
* the matrix related to the scaling (m00,
* m11). The shearing and the translation are not changed.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ t.x ? ? ]
* [ ? t.y ? ]
* [ ? ? ? ]
* </pre>
*
* @param t
* @see #makeScaleMatrix(float, float)
*/
public void setScale(Tuple2D<?> t) {
this.m00 = t.getX();
this.m11 = t.getY();
}
/** Concatenates this transform with a scaling transformation.
* <p>
* This function is equivalent to:
* <pre>
* this = this * [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param sx
* @param sy
*/
public void scale(float sx, float sy) {
this.m00 *= sx;
this.m11 *= sy;
this.m01 *= sy;
this.m10 *= sx;
}
/** Concatenates this transform with a scaling transformation.
* <p>
* This function is equivalent to:
* <pre>
* this = this * [ t.x 0 0 ]
* [ 0 t.y 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param t
*/
public void scale(Tuple2D<?> t) {
scale(t.getX(), t.getY());
}
/** Replies the X scaling.
* <p>
* <pre>
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
* </pre>
*
* @return the amount
*/
public float getScaleX() {
return (float)this.m00;
}
/** Replies the Y scaling.
* <p>
* <pre>
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
* </pre>
*
* @return the amount
*/
public float getScaleY() {
return (float)this.m11;
}
/** Replies the scaling vector.
* <p>
* <pre>
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
* </pre>
*
* @return the amount
*/
public Vector2f getScaleVector() {
return new Vector2f(this.m00, this.m11);
}
/** Set the shearing elements.
* <p>
* This function changes only the elements of
* the matrix related to the shearing (m01,
* m10). The scaling and the translation are not changed.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ ? shx ? ]
* [ shy ? ? ]
* [ ? ? ? ]
* </pre>
*
* @param shx
* @param shy
* @see #makeShearMatrix(float, float)
*/
public void setShear(float shx, float shy) {
this.m01 = shx;
this.m10 = shy;
}
/** Set the shearing elements.
* <p>
* This function changes only the elements of
* the matrix related to the shearing (m01,
* m10). The scaling and the translation are not changed.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ ? t.x ? ]
* [ t.y ? ? ]
* [ ? ? ? ]
* </pre>
*
* @param t
* @see #makeShearMatrix(float, float)
*/
public void setShear(Tuple2D<?> t) {
this.m01 = t.getX();
this.m10 = t.getY();
}
/** Concatenates this transform with a shearing transformation.
* <p>
* This function is equivalent to:
* <pre>
* this = this * [ 1 shx 0 ]
* [ shy 1 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param shx
* @param shy
*/
public void shear(float shx, float shy) {
float M0, M1;
M0 = (float)this.m00;
M1 = (float)this.m01;
this.m00 = M0 + M1 * shy;
this.m01 = M0 * shx + M1;
M0 = (float)this.m10;
M1 = (float)this.m11;
this.m10 = M0 + M1 * shy;
this.m11 = M0 * shx + M1;
}
/** Concatenates this transform with a shearing transformation.
* <p>
* This function is equivalent to:
* <pre>
* this = this * [ 1 t.x 0 ]
* [ t.y 1 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param t
*/
public void shear(Tuple2D<?> t) {
shear(t.getX(), t.getY());
}
/** Replies the X shearing.
* <p>
* <pre>
* [ 0 shx 0 ]
* [ shy 0 0 ]
* [ 0 0 1 ]
* </pre>
*
* @return the amount
*/
public float getShearX() {
return (float)this.m01;
}
/** Replies the Y shearing.
* <p>
* <pre>
* [ 0 shx 0 ]
* [ shy 0 0 ]
* [ 0 0 1 ]
* </pre>
*
* @return the amount
*/
public float getShearY() {
return (float)this.m10;
}
/** Replies the shearing vector.
* <p>
* <pre>
* [ 0 shx 0 ]
* [ shy 0 0 ]
* [ 0 0 1 ]
* </pre>
*
* @return the amount
*/
public Vector2f getShearVector() {
return new Vector2f(this.m01, this.m10);
}
/**
* Sets the value of this matrix to a counter clockwise rotation about the x
* axis, and no translation
* <p>
* This function changes all the elements of
* the matrix, icluding the translation.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ cos(theta) -sin(theta) 0 ]
* [ sin(theta) cos(theta) 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param angle
* the angle to rotate about the X axis in radians
* @see #setRotation(float)
*/
public final void makeRotationMatrix(float angle) {
float sinAngle, cosAngle;
sinAngle = (float)Math.sin(angle);
cosAngle = (float)Math.cos(angle);
this.m00 = cosAngle;
this.m01 = -sinAngle;
this.m02 = 0f;
this.m10 = sinAngle;
this.m11 = cosAngle;
this.m12 = 0f;
this.m20 = 0f;
this.m21 = 0f;
this.m22 = 1f;
}
/**
* Sets the value of this matrix to the given translation, without rotation.
* <p>
* This function changes all the elements of
* the matrix including the scaling and the shearing.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ 1 0 x ]
* [ 0 1 y ]
* [ 0 0 1 ]
* </pre>
*
* @param dx is the translation along X.
* @param dy is the translation along Y.
* @see #setTranslation(float, float)
* @see #setTranslation(Tuple2D)
*/
public final void makeTranslationMatrix(float dx, float dy) {
this.m00 = 1f;
this.m01 = 0f;
this.m02 = dx;
this.m10 = 0f;
this.m11 = 1f;
this.m12 = dy;
this.m20 = 0f;
this.m21 = 0f;
this.m22 = 1f;
}
/**
* Sets the value of this matrix to the given scaling, without rotation.
* <p>
* This function changes all the elements of
* the matrix, including the shearing and the
* translation.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param sx is the scaling along X.
* @param sy is the scaling along Y.
* @see #setScale(float, float)
* @see #setScale(Tuple2D)
*/
public final void makeScaleMatrix(float sx, float sy) {
this.m00 = sx;
this.m01 = 0f;
this.m02 = 0f;
this.m10 = 0f;
this.m11 = sy;
this.m12 = 0f;
this.m20 = 0f;
this.m21 = 0f;
this.m22 = 1f;
}
/**
* Sets the value of this matrix to the given scaling, without rotation.
* <p>
* This function changes all the elements of
* the matrix incuding the scaling and the
* translation.
* <p>
* After a call to this function, the matrix will
* contains (? means any value):
* <pre>
* [ 1 shx 0 ]
* [ shy 1 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param shx is the shearing along X.
* @param shy is the shearing along Y.
* @see #setShear(float, float)
* @see #setShear(Tuple2D)
*/
public final void makeShearMatrix(float shx, float shy) {
this.m00 = 1f;
this.m01 = shx;
this.m02 = 0f;
this.m10 = shy;
this.m11 = 1f;
this.m12 = 0f;
this.m20 = 0f;
this.m21 = 0f;
this.m22 = 1f;
}
/**
* Multiply this matrix by the tuple t and place the result back into the
* tuple (t = this*t).
*
* @param t
* the tuple to be multiplied by this matrix and then replaced
*/
public void transform(Tuple2D<?> t) {
float x, y;
x = (float)(this.m00 * t.getX() + this.m01 * t.getY() + this.m02);
y = (float)(this.m10 * t.getX() + this.m11 * t.getY() + this.m12);
t.set(x, y);
}
/** Multiply this matrix by the tuple (x, y) and return the result.
* <p>
* This function is equivalent to:
* <pre>
* result = this * [ x ]
* [ y ]
* [ 1 ]
* </pre>
*
* @param x
* @param y
* @return the transformation result
*/
public Point2D transform(float x, float y) {
float rx, ry;
rx = (float)(this.m00 * x + this.m01 * y + this.m02);
ry = (float)(this.m10 * x + this.m11 * y + this.m12);
return new Point2f(rx, ry);
}
/**
* Multiply this matrix by the tuple t and and place the result into the
* tuple "result".
* <p>
* This function is equivalent to:
* <pre>
* result = this * [ t.x ]
* [ t.y ]
* [ 1 ]
* </pre>
*
* @param t
* the tuple to be multiplied by this matrix
* @param result
* the tuple into which the product is placed
*/
public void transform(Tuple2D<?> t, Tuple2D<?> result) {
result.set(
(float)(this.m00 * t.getX() + this.m01 * t.getY() + this.m02),
(float)(this.m10 * t.getX() + this.m11 * t.getY() + this.m12));
}
/**
* Returns an <code>Transform2D</code> object representing the
* inverse transformation.
* The inverse transform Tx' of this transform Tx
* maps coordinates transformed by Tx back
* to their original coordinates.
* In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
* <p>
* If this transform maps all coordinates onto a point or a line
* then it will not have an inverse, since coordinates that do
* not lie on the destination point or line will not have an inverse
* mapping.
* The <code>determinant</code> method can be used to determine if this
* transform has no inverse, in which case an exception will be
* thrown if the <code>createInverse</code> method is called.
* @return a new <code>Transform2D</code> object representing the
* inverse transformation.
* @see #determinant()
* @throws SingularMatrixException if the matrix cannot be inverted.
*/
public Transform2D createInverse() {
float det = (float)(this.m00 * this.m11 - this.m01 * this.m10);
if (Math.abs(det) <= Double.MIN_VALUE) {
throw new SingularMatrixException("Determinant is "+det); //$NON-NLS-1$
}
return new Transform2D(
(float)(this.m11 / det),
(float)(-this.m01 / det),
(float)((this.m01 * this.m12 - this.m11 * this.m02) / det),
(float)(-this.m10 / det),
(float)(this.m00 / det),
(float)((this.m10 * this.m02 - this.m00 * this.m12) / det));
}
/**
* Set the components of the transformation.
*
* @param m00
* the [0][0] element
* @param m01
* the [0][1] element
* @param m02
* the [0][2] element
* @param m10
* the [1][0] element
* @param m11
* the [1][1] element
* @param m12
* the [1][2] element
*/
public void set(float m00, float m01, float m02, float m10, float m11, float m12) {
set(m00, m01, m02, m10, m11, m12, 0f, 0f, 1f);
}
/**
* Invert this transformation.
* The inverse transform Tx' of this transform Tx
* maps coordinates transformed by Tx back
* to their original coordinates.
* In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
* <p>
* If this transform maps all coordinates onto a point or a line
* then it will not have an inverse, since coordinates that do
* not lie on the destination point or line will not have an inverse
* mapping.
* The <code>determinant</code> method can be used to determine if this
* transform has no inverse, in which case an exception will be
* thrown if the <code>createInverse</code> method is called.
* @see #determinant()
* @throws SingularMatrixException if the matrix cannot be inverted.
*/
@Override
public void invert() {
float det = (float)(this.m00 * this.m11 - this.m01 * this.m10);
if (Math.abs(det) <= Double.MIN_VALUE) {
throw new SingularMatrixException("Determinant is "+det); //$NON-NLS-1$
}
set(
(float)(this.m11 / det),
(float)(-this.m01 / det),
(float)((this.m01 * this.m12 - this.m11 * this.m02) / det),
(float)(-this.m10 / det),
(float)(this.m00 / det),
(float)((this.m10 * this.m02 - this.m00 * this.m12) / det));
}
/**
* Invert this transformation.
* The inverse transform Tx' of this transform Tx
* maps coordinates transformed by Tx back
* to their original coordinates.
* In other words, Tx'(Tx(p)) = p = Tx(Tx'(p)).
* <p>
* If this transform maps all coordinates onto a point or a line
* then it will not have an inverse, since coordinates that do
* not lie on the destination point or line will not have an inverse
* mapping.
* The <code>determinant</code> method can be used to determine if this
* transform has no inverse, in which case an exception will be
* thrown if the <code>createInverse</code> method is called.
* @param m is the matrix to invert
* @see #determinant()
* @throws SingularMatrixException if the matrix cannot be inverted.
*/
@Override
public void invert(Matrix3d m) {
float det = (float)(m.m00 * m.m11 - m.m01 * m.m10);
if (Math.abs(det) <= Double.MIN_VALUE) {
throw new SingularMatrixException("Determinant is "+det); //$NON-NLS-1$
}
set(
(float)(m.m11 / det),
(float)(-m.m01 / det),
(float)((m.m01 * m.m12 - m.m11 * m.m02) / det),
(float)(-m.m10 / det),
(float)(m.m00 / det),
(float)((m.m10 * m.m02 - m.m00 * m.m12) / det));
}
}