extraire la rotation, les valeurs d'échelle de la matrice de transformation 2d

Comment puis-je extraire les valeurs de rotation, d'échelle et de traduction de la matrice de transformation 2d? je veux dire une transformation 2d

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)

maintenant ma matrice a des valeurs [a, b, c, d, tx, ty]

oublions les processus ci-dessus et imaginons que nous n'avons que les valeurs a, b, c, D, tx, ty

Comment puis-je trouver la rotation totale et les valeurs d'échelle via a, b, c, d, tx, ty

désolé pour mon anglais

Merci de votre avance

MODIFIER

je pense que ça devrait être une réponse quelque part...

je viens d'essayer dans Flash Builder (AS3) comme ceci

   var m:Matrix = new Matrix;
   m.rotate(.25 * Math.PI);
   m.scale(4, 5);
   m.translate(100, 50);
   m.rotate(.33 * Math.PI);
   m.scale(-3, 2.5);

   var shape:Shape = new Shape;
   shape.transform.matrix = m;

   trace(shape.x, shape.y, shape.scaleX, shape.scaleY, shape.rotation);

et la sortie est:

x = -23.6 
y = 278.8 
scaleX = 11.627334873920528 
scaleY = -13.54222263865791 
rotation = 65.56274134518259 (in degrees)
21
demandé sur ja72 2010-12-06 00:16:47

4 réponses

toutes les valeurs de a,b,C,D,tx,ty ne donneront pas une séquence de rotation valide. Je suppose que les valeurs ci-dessus font partie d'une matrice de rotation homogène 3x3 en 2D

    | a  b  tx |
A = | c  d  ty |
    | 0  0  1  |

qui transforme les coordonnées [x, y, 1] en:

[x', y', 1] = A * |x|
                  |y|
                  |z|
  • ainsi placer la traslation dans [dx, dy]=[tx, ty]
  • l'échelle est sx = sqrt(a² + c²) et sy = sqrt(b² + d²)
  • l'angle de rotation est t = atan(c/d) ou t = atan(-b/a) comme ils devraient être les mêmes.

sinon vous n'avez pas de matrice de rotation valide.


La transformation ci-dessus est étendue à:

x' = tx + sx (x Cos θ - y Sin θ)
y' = ty + sy (x Sin θ + y Cos θ)

lorsque l'ordre est une rotation, suivie d'une échelle puis d'une traduction.

39
répondu ja72 2015-03-25 11:00:22

j'ai rencontré ce problème aujourd'hui et j'ai trouvé la solution la plus facile pour transformer un point en utilisant la matrice. De cette façon, vous pouvez extraire la traduction d'abord, puis la rotation et l'échelle.

cela ne fonctionne que si x et y ont toujours la même échelle (échelle uniforme).

étant donné votre matrice m qui a subi une série de transformations,

var translate:Point;
var rotate:Number;
var scale:Number;

// extract translation
var p:Point = new Point();
translate = m.transformPoint(p);
m.translate( -translate.x, -translate.y);

// extract (uniform) scale
p.x = 1.0;
p.y = 0.0;
p = m.transformPoint(p);
scale = p.length;

// and rotation
rotate = Math.atan2(p.y, p.x);

voilà!

5
répondu bugshake 2012-03-08 21:38:40

si dans scaling vous aviez scalé par la même quantité en x et en y, alors le déterminant de la matrice, c.-à - D. ad-bc, qui vous dit le multiplicateur de zone vous dirait le changement linéaire d'échelle aussi-il serait la racine carrée du déterminant. atan (b / A ) ou mieux atan2( b,a) vous indiquerait l'angle total que vous avez tourné à travers.

cependant, comme votre échelle n'est pas uniforme, il n'y aura généralement pas de moyen de condenser votre série de rotations et mise à l'échelle en une seule rotation suivie d'une mise à l'échelle non uniforme en x et Y.

4
répondu James Crook 2010-12-05 21:56:26

le terme pour cela est décomposition de matrice . Voici une solution qui inclut skew comme décrit par Frédéric Wang .

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;
}
1
répondu Simon Epskamp 2018-08-19 19:46:34