2

我有一个用于仿射变换的 javascript Matrix 类,以及一个将旋转设置为围绕给定中心的绝对弧度数的函数:

this.setRotation = function (radians, center) {
    var cos = Math.cos(radians);
    var sin = Math.sin(radians);
    this.a = cos;
    this.b = sin;
    this.c = -sin;
    this.d = cos;
    this.tx += center.x - center.x * cos + center.y * sin;
    this.ty += center.y - center.x * sin - center.y * cos;
}

我试图围绕对象本身的中心旋转,所以我传入对象宽度一半和高度一半的中心点,因此对于 100 x 100 对象,我传入 50、50。

如果我的对象从零旋转开始,则可以正常工作:

前 后

...但是如果我再次旋转形状,或者以非零的旋转开始,则 tx 和 ty 值最终会出错:

位置移动

我上面的公式有什么问题?设置旋转似乎是准确的,但不是 tx 和 ty。

我已经看到了关于这个主题的其他一些问题,特别是这个问题,但没有任何帮助。

更新要为此添加一些数字:

如果我从一个 100x100 的矩形开始,位于 100,100,那么我的初始矩阵是:{Matrix: [a:1, b:0, c:0, d:1, tx:100, ty:100]}

要将其顺时针旋转 45 度,我输入上述函数 0.7853981633974483(弧度为 45 度)和中心:{Point: [x:50, y: 50]}

这会产生以下矩阵: {Matrix: [a:0.7071067812, b:0.7071067812, c:-0.7071067812, d:0.7071067812, tx:150, ty:79.28932188]}完全正确。

{Point: [x:70.71067812000001, y: 70.71067812000001]}但是,如果我然后从该矩阵开始,并尝试通过提供函数参数 0 和(新的旋转形状的中心)将其返回为零,那么输出是{Matrix: [a:1, b:0, c:0, d:1, tx:150, ty:79.28932188]},这是正确的旋转但不是正确的翻译。我期待得到{Matrix: [a:1, b:0, c:0, d:1, tx:100, ty:100]}

我已经尝试了该函数的其他几种变体,包括使用父坐标空间 150,150 中的矩形中心而不是 50,50 的局部中心,并按照下面的建议将 += 替换为 =,但似乎没有任何帮助。如果我注释掉 tx 计算,那么我的形状会围绕它的原点完美旋转,所以问题必须与 tx/ty 计算有关,或者与我传入的中心点有关。

有没有人有任何进一步的想法?

4

2 回答 2

1

除了可能是一个不正确的符号(尽管这取决于坐标轴的方向)之外,我认为问题只是您正在使用+=而不是=在填充仿射矩阵的txty部分时。

于 2012-09-26T12:00:26.247 回答
0

我的问题是让对象回到原点 - 在旋转之前移除左上角的坐标以及高度和宽度的一半,然后再次添加它们。

我发现使用旋转函数比使用 setRotate 函数更容易,最终得到以下代码:

// Matrix class functions:
this.rotate = function (radians) {
    var cos = parseFloat(Math.cos(radians).toFixed(10));
    var sin = parseFloat(Math.sin(radians).toFixed(10));
    a = this.a,
    b = this.b,
    c = this.c,
    d = this.d,
    tx = this.tx,
    ty = this.ty;
    this.a = a * cos - b * sin;
    this.b = a * sin + b * cos;
    this.c = c * cos - d * sin;
    this.d = c * sin + d * cos;
    this.tx = tx * cos - ty * sin;
    this.ty = tx * sin + ty * cos;
}

this.setRotation = function (radians) {
    var rotation = this.rotation();
    this.rotate(radians - rotation);
}

this.translate = function (tx, ty) {
    this.tx += tx;
    this.ty += ty;
}

// Called from outside the class
var transformedBounds = pe.Model.ReadTransformedBounds(selection[0]);
var itemTransform = pe.Model.ReadItemTransform(selection[0]);

// Cache the coordinates before translating them away:
var ox = transformedBounds.Left + (transformedBounds.Width / 2); 
var oy = transformedBounds.Top + (transformedBounds.Height / 2);
itemTransform.translate(-ox, -oy);

// Rotate:
itemTransform.setRotation(radians);

// Restore the translation:
itemTransform.translate(ox, oy);

如果你真的能做总和,所有这些可能都很明显,但我把它贴在这里,以防有人和我一样昏暗的一天......

于 2012-09-26T17:50:13.437 回答