How to get scaling from transformation matrix

29 views Asked by At

I have a transformation matrix with scaling (20, 20, 1) and rotation by 90 degrees:

 0, -20, 0, 80
20,   0, 0, 20
 0,   0, 1,  0
 0,   0, 0,  1

I want to get scaling. I have the next example in JavaScript with the glMatrix library that extracts scaling from the transformation matrix above:

<body>
    <!-- Since import maps are not yet supported by all browsers, its is
        necessary to add the polyfill es-module-shims.js -->
    <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js">
    </script>

    <script type="importmap">
        {
            "imports": {
                "gl-matrix": "https://cdn.jsdelivr.net/npm/[email protected]/+esm"
            }
        }
    </script>

    <script type="module">
        import { mat4, vec3 } from "gl-matrix";

        // Create a matrix
        const matrix = mat4.fromValues(
              0, 20, 0, 0,
            -20,  0, 0, 0,
              0,  0, 1, 0,
             80, 20, 0, 1);

        // Extract scaling
        const scaling = vec3.create();
        mat4.getScaling(scaling, matrix);
        console.log(scaling[0], scaling[1], scaling[2]);
    </script>

</body>

I want to rewrite it to Qt. I read a documentation and tried to google but I didn't find how to extract scaling from a transformation matrix.

#include <QtGui/QMatrix4x4>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>

class Widget : public QWidget
{
public:
    Widget()
    {
        QMatrix4x4 matrix(
             0, -20, 0, 80,
            20,   0, 0, 20,
             0,   0, 1,  0,
             0,   0, 0,  1);

        qDebug() << "hello";
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Widget w;
    w.show();
    return app.exec();
}
1

There are 1 answers

0
8Observer8 On BEST ANSWER

I opened a source code of getScaling and saw how scaling is calculated there: https://glmatrix.net/docs/mat4.js.html#line1197

export function getScaling(out, mat) {
  let m11 = mat[0];
  let m12 = mat[1];
  let m13 = mat[2];
  let m21 = mat[4];
  let m22 = mat[5];
  let m23 = mat[6];
  let m31 = mat[8];
  let m32 = mat[9];
  let m33 = mat[10];
  out[0] = Math.hypot(m11, m12, m13);
  out[1] = Math.hypot(m21, m22, m23);
  out[2] = Math.hypot(m31, m32, m33);
  return out;
}

I made the same with qHypot

#include <QtGui/QMatrix4x4>
#include <QtGui/QVector3D>
#include <QtMath>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>

class Widget : public QWidget
{
public:
    Widget()
    {
        QMatrix4x4 m(
             0, -20, 0, 80,
            20,   0, 0, 20,
             0,   0, 1,  0,
             0,   0, 0,  1);

        float sx = qHypot(m.row(0)[0], m.row(1)[0], m.row(2)[0]);
        float sy = qHypot(m.row(0)[1], m.row(1)[1], m.row(2)[1]);
        float sz = qHypot(m.row(0)[2], m.row(1)[2], m.row(2)[2]);
        QVector3D scaling(sx, sy, sz);
        qDebug() << scaling;
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Widget w;
    w.show();
    return app.exec();
}

P.S. The QMatrix4x4 constructor uses row-major order. The glMatrix fromValues method uses column-major order.