【问题标题】:How to extract position, rotation and scale from matrix SVG如何从矩阵 SVG 中提取位置、旋转和缩放
【发布时间】:2013-05-03 12:44:10
【问题描述】:

我有一个简单的问题:我想提取平移 (tx, ty)、旋转 (r) 和缩放 (sx, sy) 值,形成一个应用于我的 svg 元素的变换矩阵。

让我们用这个例子:

<g
  id="myElement"
  transform="matrix(0.93893241,0.34410162,-0.34410162,0.93893241,363.88475,-76.125919)"
  >... </g>

如果我在 javascript 中这样做

document.getElementById("myElement").getCTM()

我可以访问 a、b、c、d、e、f 值。我怎样才能从那里得到 tx、ty、sx、sy 和 r? 谢谢

【问题讨论】:

    标签: javascript matrix svg


    【解决方案1】:

    受此 ActionScript 版本的启发:https://gist.github.com/fwextensions/2052247,我编写了一个 JavaScript 端口:

        function deltaTransformPoint(matrix, point)  {
    
            var dx = point.x * matrix.a + point.y * matrix.c + 0;
            var dy = point.x * matrix.b + point.y * matrix.d + 0;
            return { x: dx, y: dy };
        }
    
    
        function decomposeMatrix(matrix) {
    
            // @see https://gist.github.com/2052247
    
            // calculate delta transform point
            var px = deltaTransformPoint(matrix, { x: 0, y: 1 });
            var py = deltaTransformPoint(matrix, { x: 1, y: 0 });
    
            // calculate skew
            var skewX = ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);
            var skewY = ((180 / Math.PI) * Math.atan2(py.y, py.x));
    
            return {
    
                translateX: matrix.e,
                translateY: matrix.f,
                scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
                scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
                skewX: skewX,
                skewY: skewY,
                rotation: skewX // rotation is the same as skew x
            };        
        }
    

    用法:decomposeMatrix(document.getElementById('myElement').getCTM())

    【讨论】:

    • 非常感谢您的回答!我会尽快将我的电脑拿回来尝试并提供反馈。
    • 没有得到准确的 e,f 值?为什么?
    • 旋转计算可以更直接,见:stackoverflow.com/a/4361442
    • 为什么deltaTransformPoint()中的dx和dy要加0?
    【解决方案2】:

    要分别分解旋转和倾斜,您可以查看这些示例:

    反应原生:

    https://github.com/facebook/react-native/blob/master/Libraries/Utilities/MatrixMath.js

    三个.js: https://github.com/mrdoob/three.js/blob/302f1d155835888a77aad31241e0d74a2ee2f926/src/math/Matrix4.js

    https://github.com/ismailman/decompose-dommatrix/blob/master/decomposeDommatrix.mjs

    http://math.stackexchange.com/questions/861674/decompose-a-2d-arbitrary-transform-into-only-scaling-and-rotation

    https://gist.github.com/Breton/9d217e0375de055d563b9a0b758d4ae6

    function decomposeMatrix(m) {
      var E = (m.a + m.d) / 2
      var F = (m.a - m.d) / 2
      var G = (m.c + m.b) / 2
      var H = (m.c - m.b) / 2
    
      var Q = Math.sqrt(E * E + H * H);
      var R = Math.sqrt(F * F + G * G);
      var a1 = Math.atan2(G, F);
      var a2 = Math.atan2(H, E);
      var theta = (a2 - a1) / 2;
      var phi = (a2 + a1) / 2;
    
      // The requested parameters are then theta, 
      // sx, sy, phi,
      return {
        translateX: m.e,
        translateY: m.f,
        rotate: -phi * 180 / Math.PI,
        scaleX: Q + R,
        scaleY: Q - R,
        skew: -theta * 180 / Math.PI
      };
    }
    

    https://www.w3.org/TR/css-transforms-1/#decomposing-a-2d-matrix

      function decomposeMatrix2DW3(m) {
    
          var row0x = m.a;
          var row0y = m.b;
          var row1x = m.c;
          var row1y = m.d;
    
          var scaleX = Math.sqrt(row0x * row0x + row0y * row0y)
          var scaleY = Math.sqrt(row1x * row1x + row1y * row1y)
    
          // If determinant is negative, one axis was flipped.
          var determinant = row0x * row1y - row0y * row1x
          if (determinant < 0)
            // Flip axis with minimum unit vector dot product.
            if (row0x < row1y)
              scaleX = -scaleX
            else
              scaleY = -scaleY
    
          // Renormalize matrix to remove scale.
          if (scaleX) {
            row0x *= 1 / scaleX
            row0y *= 1 / scaleX
          }
    
          if (scaleY) {
            row1x *= 1 / scaleY
            row1y *= 1 / scaleY
          }
    
          // Compute rotation and renormalize matrix.
          var angle = Math.atan2(row0y, row0x);
    
          if (angle) {
            // Rotate(-angle) = [cos(angle), sin(angle), -sin(angle), cos(angle)]
            //                = [row0x, -row0y, row0y, row0x]
            // Thanks to the normalization above.
            var sn = -row0y
            var cs = row0x
            var m11 = row0x
            var m12 = row0y
            var m21 = row1x
            var m22 = row1y
            row0x = cs * m11 + sn * m21
            row0y = cs * m12 + sn * m22
            row1x = -sn * m11 + cs * m21
            row1y = -sn * m12 + cs * m22
          }
    
          m11 = row0x
          m12 = row0y
          m21 = row1x
          m22 = row1y
    
          // Convert into degrees because our rotation functions expect it.
          angle = angle * (180 / Math.PI);
          // The requested parameters are then theta, 
          // sx, sy, phi,
          return {
            translateX: m.e,
            translateY: m.f,
            rotateZ: angle,
            scaleX: scaleX,
            scaleY: scaleY,
            matrix: [m11, m12, m21, m22, 0, 0]
          };
        }
    

    你也可以看看:

    https://github.com/d3/d3-interpolate/blob/master/src/transform/decompose.js#L12-L25

    【讨论】:

    • 有没有办法将 2x2 矩阵转换为倾斜值?
    猜你喜欢
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 2013-02-14
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多