web-dev-qa-db-ja.com

2次元変換行列から回転、スケール値を抽出します

2D変換行列から回転、スケール、平行移動の値を抽出するにはどうすればよいですか?つまり、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)

今私の行列は値[a、b、c、d、tx、ty]を持っています

上記のプロセスを忘れて、値a、b、c、d、tx、tyしかないことを想像してみましょう。

a、b、c、d、tx、tyを介して総回転値とスケール値を見つけるにはどうすればよいですか?

私の英語でごめんなさい

よろしくお願いします

[〜#〜]編集[〜#〜]

どこかで答えになると思います...

このようにFlashBuilder(AS3)で試しました

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

出力は次のとおりです。

x = -23.6 
y = 278.8 
scaleX = 11.627334873920528 
scaleY = -13.54222263865791 
rotation = 65.56274134518259 (in degrees)
23

A、b、c、d、tx、tyのすべての値が有効なローテーションシーケンスを生成するわけではありません。上記の値は、2Dの3x3均一回転行列の一部であると想定しています。

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

これは、座標_[x, y, 1]_を次のように変換します。

_[x', y', 1] = A * |x|
                  |y|
                  |z|
_
  • したがって、翻訳を_[dx, dy]=[tx, ty]_に設定します
  • スケールはsx = sqrt(a² + c²)およびsy = sqrt(b² + d²)です。
  • 回転角はt = atan(c/d)またはt = atan(-b/a)です。これらも同じである必要があります。

そうしないと、有効な回転行列がありません。


上記の変換は次のように拡張されます。

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

順序が回転、スケール、平行移動の順の場合。

43
ja72

今日この問題に遭遇し、行列を使用して点を変換する最も簡単な解決策を見つけました。このようにして、最初に平行移動を抽出し、次に回転とスケーリングを抽出できます。

これは、xとyが常に同じスケーリング(均一スケーリング)である場合にのみ機能します。

一連の変換を受けた行列mが与えられると、

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

どうぞ!

6
bugshake

スケーリングでxとyで同じ量だけスケーリングした場合、行列の行列式、つまり面積乗数を示すad-bcは、スケールの線形変化も示します。これは平方根になります。行列式のルート。 atan(b/a)以上のatan2(b、a)は、回転した合計角度を示します。

ただし、スケーリングが均一ではないため、通常、一連の回転とスケーリングを1つの回転に凝縮してから、xとyで1つの不均一なスケーリングを行う方法はありません。

4
James Crook

これの用語は行列分解です。 FrédéricWang で説明されているように、skewを含むソリューションを次に示します。

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;
}
2
Simon Epskamp