20
$\begingroup$

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?

3 Answers 3

29

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)$

  • 0
    calculated the rotation using the formula float rAngle = Math.round(Math.atan2(v[Matrix.MSKEW_X], v[Matrix.MSCALE_X]) * (180 / Math.PI)); need to multiply with a _1 to get the correct rotaion, why is tha happing?2016-11-15
3

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);         }      }  } 
  • 1
    Hats off to you sir, You saved my week.2016-11-17
1

The term for this is matrix decomposition. Here is a solution that includes skew as described by Frédéric Wang.

It operates on a 2d matrix defined as such:

$\left[\begin{array}{ccc} \mathrm{a} & \mathrm{c} & \mathrm{tx}\\ \mathrm{b} & \mathrm{d} & \mathrm{ty}\end{array}\right]$

function decompose_2d_matrix(mat) {   var a = mat[0];   var b = mat[1];   var c = mat[2];   var d = mat[3];   var e = mat[4];   var f = mat[5];    var delta = a * d - b * c;    let result = {     translation: [e, f],     rotation: 0,     scale: [0, 0],     skew: [0, 0],   };    // Apply the QR-like decomposition.   if (a != 0 || b != 0) {     var r = Math.sqrt(a * a + b * b);     result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r);     result.scale = [r, delta / r];     result.skew = [Math.atan((a * c + b * d) / (r * r)), 0];   } else if (c != 0 || d != 0) {     var s = Math.sqrt(c * c + d * d);     result.rotation =       Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s));     result.scale = [delta / s, s];     result.skew = [0, Math.atan((a * c + b * d) / (s * s))];   } else {     // a = b = c = d = 0   }    return result; }