extracting rotation, scale values from 2d transformation matrix
How can I extract rotation and scale values from a 2D transformation matrix?
matrix = [1, 0, 0, 1, 0, 0]
matrix.rotate(45 / 180 * PI)
matrix.scale(3, 4)
matrix.translate(50, 100)
matrix.rotate(30 / 180 * PI)
matrix.scale(-2, 4)
Now my matrix have values [a, b, c, d, tx, ty]
. Lets forget about the processes above and imagine that we have only the values a, b, c, d, tx, and ty. How can I find final rotation and scale values?
Essentially you need to solve the following
$$\left[\begin{array}{ccc} \mathrm{a} & \mathrm{b} & \mathrm{tx}\\ \mathrm{c} & \mathrm{d} & \mathrm{ty}\end{array}\right]=\left[\begin{array}{ccc} s_{x}\cos\psi & -s_{x}\sin\psi & x_{c}\\ s_{y}\sin\psi & s_{y}\cos\psi & y_{c}\end{array}\right]$$
where $s_x$, $s_y$ are the scalings, $x_c$, $y_c$ is the translation and $\psi$ is the rotation angle. The results I get are:
$$x_{c}=\mathrm{tx}$$ $$y_{c}=\mathrm{ty}$$ $$s_{x}=\mathrm{sign(a)\,}\sqrt{\mathrm{a}^{2}+\mathrm{b}^{2}}$$ $$s_{y}=\mathrm{sign(d)\,}\sqrt{\mathrm{c}^{2}+\mathrm{d}^{2}}$$ $$\tan\psi=-\frac{\mathrm{b}}{\mathrm{a}}=\frac{\mathrm{c}}{\mathrm{d}}$$
So the angle is either $\psi = {\rm atan2}(-b,a)$ or $\psi = {\rm atan2}(c,d)$
Scale and Rotation Extraction for Action Script 3
package nid.utils
{
import flash.geom.Matrix;
import flash.geom.Point;
import nid.geom.DMatrix;
/**
* ...
* @author Nidin P Vinayakan
*/
public class MatrixConvertor
{
public static const degree:Number = 180 / Math.PI;
public static const radian:Number = Math.PI / 180;
public function MatrixConvertor()
{
}
public static function convert(mat:Matrix):DMatrix
{
var dmat:DMatrix = new DMatrix(mat.a, mat.b, mat.c, mat.d, mat.tx, mat.ty);
var rad:Number;
var deg:Number;
var sign:Number;
/**
* scaleX = √(a^2+c^2)
* scaleY = √(b^2+d^2)
* rotation = tan^-1(c/d) = tan^-1(-b/a) it will not work sometimes
* rotation = a / scaleX = d / scaleY
*/
with (dmat)
{
scaleX = Math.sqrt((a * a) + (c * c));
scaleY = Math.sqrt((b * b) + (d * d));
sign = Math.atan(-c / a);
rad = Math.acos(a / scaleX);
deg = rad * degree;
if (deg > 90 && sign > 0)
{
rotation = (360 - deg) * radian;
}
else if (deg < 90 && sign < 0)
{
rotation = (360 - deg) * radian;
}
else
{
rotation = rad;
}
rotationInDegree = rotation * degree;
}
return dmat;
}
}
}
/**
* DMatrix Class
*/
package nid.geom
{
import flash.geom.Matrix;
/**
* ...
* @author Nidin P Vinayakan
*/
public class DMatrix extends Matrix
{
public var rotation:Number=0;
public var rotationInDegree:Number=0;
public var scaleX:Number=1;
public var scaleY:Number=1;
public function DMatrix(a:Number=1, b:Number=0, c:Number=0, d:Number=1, tx:Number=0, ty:Number=0)
{
super(a, b, c, d, tx, ty);
}
}
}