簡體   English   中英

變換矩陣旋轉不保留局部軸縮放?

[英]Transformation matrix rotation not preserving local axis scaling?

我有一個簡單的轉換類,可以按任意順序在 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 度一樣; 但是正如您所看到的,結果是我正在執行的旋轉邏輯保留了世界空間軸上的比例,所以現在Test 2 Text高度是原來的兩倍,而不是長度的兩倍。

當前結果:

當前結果

期望的結果:

期望的結果

當前的旋轉邏輯基於將構成旋轉的現有變換矩陣乘以另一個包含旋轉角度的變換矩陣,但我意識到它並不那么簡單,而且我缺少一些東西來保留局部軸尺度。

謝謝您的幫助。

編輯:

推薦使用DOMMatrix它為我完成所有這些數學運算,但它有同樣的問題,盡管有一些我認為不准確的偏差:

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

傾斜是由縮放函數在旋轉時縮放其局部 X 軸,然后在不保持該局部 X 軸縮放后旋轉引起的。 此外, DOMMatrix translate 函數將平移應用於其局部軸,這在我的情況下是不需要的,但如果它的旋轉函數按預期工作,我將能夠使用它。

我設法在這里修復它:

常規: 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM