变换矩阵旋转不保留局部轴缩放?

Transformation matrix rotation not preserving local axis scaling?

我有一个简单的变换 class 以任意顺序在 div 上应用平移、缩放和旋转:

class TransformDiv{

  constructor(div)
  {
    this.div = div;
    this.translateX = 0;
    this.translateY = 0;
    this.scaleX = 1;
    this.scaleY = 1;
    this.shearX = 0;
    this.shearY = 0;
  }
  
  translate(x, y)
  {
    this.translateX += x;
    this.translateY += y;
    this.setTransform();
  }
  
  scale(x, y, anchorX = 0, anchorY = 0)
  {
    this.scaleX *= x;
    this.shearX *= x;
    this.scaleY *= y;
    this.shearY *= y;
    this.translateX -= (this.translateX - anchorX) * (1 - x);
    this.translateY -= (this.translateY - anchorY) * (1 - y);
    this.setTransform();
  }
  
  rotate(rad, anchorX = 0, anchorY = 0)
  {
    let cos = Math.cos(rad);
    let sin = Math.sin(rad);
    
    // the composition of two successive rotations are additive
    let newScaleX = this.scaleX * cos + this.shearX * sin;
    let newShearX = this.scaleX * (-sin) + this.shearX * cos;
    let newShearY = this.shearY * cos + this.scaleY * sin;
    let newScaleY = this.shearY * (-sin) + this.scaleY * cos;
    this.scaleX = newScaleX;
    this.shearX = newShearX;
    this.shearY = newShearY;
    this.scaleY = newScaleY;
    //rotation about an arbitrary point
    let originX = (this.translateX - anchorX);
    let originY = (this.translateY - anchorY);
    this.translateX -= (originY * sin - originX * (cos - 1));
    this.translateY -= (-originY * (cos - 1) - originX * sin);
    
    this.setTransform();
  }
  
  setTransform()
  {
    this.div.style.transform = `matrix(${this.scaleX}, ${this.shearY}, ${this.shearX}, ${this.scaleY}, ${this.translateX}, ${this.translateY})`;
  }
}

当我想在一个不均匀的缩放后旋转时出现问题。

编辑 - 较新的交互示例:https://codepen.io/manstie/pen/RwGGOmB

这是我做的例子: https://jsfiddle.net/ft61q230/1/

在此处的示例中:

div2.translate(100, 100);
div2.scale(2, 1, 100, 100);
div2.rotate(Math.PI / 2, 100, 100);

预期的结果是Test 1 TextTest 2 Text的长度相同,就好像你从div的左上角顺时针旋转90度;但如您所见,结果是我正在执行的旋转逻辑保留了 world-space 轴上的比例,所以现在 Test 2 Text 是两倍高而不是两倍长。

当前结果:

期望的结果:

当前的旋转逻辑是基于将组成旋转的现有变换矩阵乘以另一个包含旋转角度的变换矩阵,但我意识到它并不那么简单,我缺少一些东西来保留局部-轴向刻度。

感谢您的帮助。

编辑:

被推荐 DOMMatrix,它为我做了所有这些数学运算,但它有同样的问题,虽然有一些我认为不准确的偏差:

https://jsfiddle.net/heqo7vrt/1/

倾斜是由缩放函数缩放其局部 X 轴而旋转,然后在不保持局部 X 轴缩放后旋转引起的。此外,DOMMatrix translate 函数将翻译应用于其局部轴,这在我的情况下是不希望的,但如果它的 rotate 函数按预期工作,我将能够使用它。

我在这里成功修复了它:

常规:https://jsfiddle.net/sbca61k5/

let newScaleX = cos * this.scaleX + sin * this.shearY;
let newShearX = cos * this.shearX + sin * this.scaleY;
let newShearY = -sin * this.scaleX + cos * this.shearY;
let newScaleY = -sin * this.shearX + cos * this.scaleY;

DOMMatrix 版本:https://jsfiddle.net/b36kqrsg/

this.matrix = new DOMMatrix([cos, sin, -sin, cos, 0, 0]).multiply(this.matrix);
// or
this.matrix = new DOMMatrix().rotate(deg).multiply(this.matrix);

不同之处在于将旋转矩阵乘以矩阵的其余部分以“添加”它,而不是反过来:

[a c e]   [cos -sin 0]   [scx shy tx]
[b d f] = [sin  cos 0] . [shx scy ty]
[0 0 1]   [0    0   1]   [0   0   1 ]

我不确定锚点数学的细节,但 DOMMatrix 版本的锚点是相对于它自己的左上角,而另一个是相对于文档的左上角。

在我的交互式示例中,锚点数学不起作用,因为经过多次旋转后,对象离锚点原点越来越远。 https://codepen.io/manstie/pen/PoGXMed