【问题标题】:extract rotation, scale values from 2d transformation matrix从二维变换矩阵中提取旋转、缩放值
【发布时间】:2011-05-20 15:52:22
【问题描述】:

如何从二维变换矩阵中提取旋转、缩放和平移值?我的意思是有一个二维变换

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 找到总旋转和缩放值

对不起我的英语

感谢您的提前

编辑

我认为它应该是某个地方的答案......

我刚刚在 Flash Builder (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)

【问题讨论】:

  • 这个问题最适合math.stackexchange.com - 你会得到更快的回复:-)
  • 我刚刚在这里:math.stackexchange.com/questions/13150/… 谢谢
  • 给我们一个例子 a,b,c,d,tx,ty 值,让我们看看是否有任何答案符合您的期望。
  • (a=4.810188218418486, b=10.58569820374103, c=13.4489075059838, d=-1.5870322791938274, tx=-23.601120674381982, ty=2728)

标签: math matrix flash-builder


【解决方案1】:

并非所有 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 θ)

当顺序是旋转,然后是缩放,然后是平移。

【讨论】:

  • 每个方向的缩放操作可能不同...缩放是一个向量...
  • 感谢您的旋转和平移。关于比例,我们得到了一个计算出的缩放单个值 (s=sqrt(b^2+d^2)) 是否可以找到 scaleX 和 scaleY 值?
  • 请记住 sign(a)=sign(sx)sign(b)=sign(sy),因为 cos() 函数的性质。
  • 约定改变了。就像使用左手系统或右手系统一样。或预乘与后乘转换。或表示行主要与列主要顺序中的元素。或者存储仿射变换的最后一行(3×3 平面)与不存储(2×3 平面)。而且肯定还会有更多。
  • @ja72 同意使用了不同的约定,但在答案中,您使用了大多数书籍中用于A 的列向量约定。但是,与行向量相乘意味着您正在乘以 3 x 3 * 1 x 3,这是无效的。我冒昧地通过将其设为列向量来修复它,我希望没问题。
【解决方案2】:

我今天遇到了这个问题,并找到了使用矩阵变换点的最简单解决方案。这样,您可以先提取平移,然后再提取旋转和缩放。

这仅适用于 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);

你去!

【讨论】:

    【解决方案3】:

    这方面的术语是矩阵分解。这是一个包含 skew 的解决方案,如 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;
    }
    

    【讨论】:

      【解决方案4】:

      如果在缩放中你在 x 和 y 中缩放了相同的量,那么矩阵的行列式,即 ad-bc,它告诉你面积乘数也会告诉你比例的线性变化 - 它会是行列式的平方根。 atan( b/a ) 或更好的 atan2( b,a ) 会告诉您旋转的总角度。

      但是,由于您的缩放比例不均匀,因此通常无法将您的一系列旋转和缩放比例压缩为单个旋转,然后在 x 和 y 中进行单个非均匀缩放。

      【讨论】:

        猜你喜欢
        • 2015-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-14
        • 1970-01-01
        • 2011-11-15
        • 2020-02-14
        • 1970-01-01
        相关资源
        最近更新 更多