从Javascript画布获取点的未翻译,未旋转(x,y)坐标

时间:2023-02-09 10:35:45

In Javascript we often render graphics by rotating and translating the coordinate plane before sending things

在Javascript中,我们经常通过在发送内容之前旋转和平移坐标平面来渲染图形

ctx.save();
ctx.translate(someX, someY);
ctx.rotate(someAngle * Math.PI / 180);

ctx.beginPath();
ctx.moveTo(x1, y1);    // What's the actual (x1,y1)?
ctx.lineTo(x2, y2);    // What's the actual (x2,y2)?
ctx.stroke();

ctx.restore();

So having done this, how do I figure out the actual values of the endpoints of that line segment I've drawn? Because after that translating and rotating, (x1,y1) and (x2,y2) are somewhere far away from where they'd be without the translating and rotating. Is there an easy way to find out what their actual values are?

所以这样做了,我如何计算出我所画线段的端点的实际值?因为在翻译和旋转之后,(x1,y1)和(x2,y2)远离它们没有平移和旋转的地方。有没有一种简单的方法可以找出他们的实际价值是多少?

2 个解决方案

#1


There's no way right now to get the current transformation matrix, so you would need to keep track of any rotations/translations/scaling yourself.

现在没办法获得当前的变换矩阵,因此您需要自己跟踪任何旋转/平移/缩放。

To actually perform the transformation, you need to multiply the transformation matrix by the point (as a column vector).

要实际执行变换,需要将变换矩阵乘以点(作为列向量)。

You could override the methods that affect the transformation to store your own copy of the matrix. I haven't tested this code, but something like this should work:

您可以覆盖影响转换的方法,以存储您自己的矩阵副本。我没有测试过这段代码,但是这样的代码应该可行:

var contextPrototype = CanvasRenderingContext2D.prototype;

contextPrototype.xform = Matrix.I(3);

contextPrototype.realSave = contextPrototype.save;
contextPrototype.save = function() {
    if (!this.xformStack) {
        this.xformStack = [];
    }
    this.xformStack.push(this.xform.dup());
    this.realSave();
}

contextPrototype.realRestore = contextPrototype.restore;
contextPrototype.restore = function() {
    if (this.xformStack && this.xformStack.length > 0) {
        this.xform = this.xformStack.pop();
    }
    this.realRestore();
}

contextPrototype.realScale = contextPrototype.scale;
contextPrototype.scale = function(x, y) {
    this.xform = this.xform.multiply($M([
        [x, 0, 0],
        [0, y, 0],
        [0, 0, 1]
    ]));
    this.realScale(x, y);
}

contextPrototype.realRotate = contextPrototype.rotate;
contextPrototype.rotate = function(angle) {
    var sin = Math.sin(angle);
    var cos = Math.cos(angle);
    this.xform = this.xform.multiply($M([
        [cos, -sin, 0],
        [sin,  cos, 0],
        [   0,   0, 1]
    ]));
    this.realRotate(angle);
}

contextPrototype.realTranslate = contextPrototype.translate;
contextPrototype.translate = function(x, y) {
    this.xform = this.xform.multiply($M([
        [1, 0, x],
        [0, 1, y],
        [0, 0, 1]
    ]));
    this.realTranslate(x, y);
}

contextPrototype.realTransform = contextPrototype.transform;
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
    this.xform = this.xform.multiply($M([
        [m11, m21, dx],
        [m12, m22, dy],
        [  0,   0,  1]
    ]));
    this.realTransform(m11, m12, m21, m22, dx, dy);
}

contextPrototype.realSetTransform = contextPrototype.setTransform;
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
    this.xform = $M([
        [m11, m21, dx],
        [m12, m22, dy],
        [  0,   0,  1]
    ]);
    this.realSetTransform(m11, m12, m21, m22, dx, dy);
}

I used the Sylvester matrix library for convenience, but you could do your own multiplication.

为方便起见,我使用了Sylvester矩阵库,但您可以自己进行乘法运算。

To get the transformed point, just multiply the transformation matrix by the point:

要获得变换点,只需将变换矩阵乘以点:

// Get the transformed point as [x, y]
contextPrototype.getTransformedPoint = function(x, y) {
    var point = this.xform.multiply($V([x, y, 1]));
    return [point.e(1), point.e(2)];
}

#2


I think the only way to find that would be to apply the same transformations as you did on the rendering context to the points you want to know the actual coordinates. A few libraries provide matrix operations, like : http://sylvester.jcoglan.com/ You can try to perform rotation operations to the cartesian coordinates

我认为找到这种方法的唯一方法是将与渲染上下文相同的变换应用于想要了解实际坐标的点。一些库提供矩阵运算,例如:http://sylvester.jcoglan.com/您可以尝试对笛卡尔坐标执行旋转运算

#1


There's no way right now to get the current transformation matrix, so you would need to keep track of any rotations/translations/scaling yourself.

现在没办法获得当前的变换矩阵,因此您需要自己跟踪任何旋转/平移/缩放。

To actually perform the transformation, you need to multiply the transformation matrix by the point (as a column vector).

要实际执行变换,需要将变换矩阵乘以点(作为列向量)。

You could override the methods that affect the transformation to store your own copy of the matrix. I haven't tested this code, but something like this should work:

您可以覆盖影响转换的方法,以存储您自己的矩阵副本。我没有测试过这段代码,但是这样的代码应该可行:

var contextPrototype = CanvasRenderingContext2D.prototype;

contextPrototype.xform = Matrix.I(3);

contextPrototype.realSave = contextPrototype.save;
contextPrototype.save = function() {
    if (!this.xformStack) {
        this.xformStack = [];
    }
    this.xformStack.push(this.xform.dup());
    this.realSave();
}

contextPrototype.realRestore = contextPrototype.restore;
contextPrototype.restore = function() {
    if (this.xformStack && this.xformStack.length > 0) {
        this.xform = this.xformStack.pop();
    }
    this.realRestore();
}

contextPrototype.realScale = contextPrototype.scale;
contextPrototype.scale = function(x, y) {
    this.xform = this.xform.multiply($M([
        [x, 0, 0],
        [0, y, 0],
        [0, 0, 1]
    ]));
    this.realScale(x, y);
}

contextPrototype.realRotate = contextPrototype.rotate;
contextPrototype.rotate = function(angle) {
    var sin = Math.sin(angle);
    var cos = Math.cos(angle);
    this.xform = this.xform.multiply($M([
        [cos, -sin, 0],
        [sin,  cos, 0],
        [   0,   0, 1]
    ]));
    this.realRotate(angle);
}

contextPrototype.realTranslate = contextPrototype.translate;
contextPrototype.translate = function(x, y) {
    this.xform = this.xform.multiply($M([
        [1, 0, x],
        [0, 1, y],
        [0, 0, 1]
    ]));
    this.realTranslate(x, y);
}

contextPrototype.realTransform = contextPrototype.transform;
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
    this.xform = this.xform.multiply($M([
        [m11, m21, dx],
        [m12, m22, dy],
        [  0,   0,  1]
    ]));
    this.realTransform(m11, m12, m21, m22, dx, dy);
}

contextPrototype.realSetTransform = contextPrototype.setTransform;
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
    this.xform = $M([
        [m11, m21, dx],
        [m12, m22, dy],
        [  0,   0,  1]
    ]);
    this.realSetTransform(m11, m12, m21, m22, dx, dy);
}

I used the Sylvester matrix library for convenience, but you could do your own multiplication.

为方便起见,我使用了Sylvester矩阵库,但您可以自己进行乘法运算。

To get the transformed point, just multiply the transformation matrix by the point:

要获得变换点,只需将变换矩阵乘以点:

// Get the transformed point as [x, y]
contextPrototype.getTransformedPoint = function(x, y) {
    var point = this.xform.multiply($V([x, y, 1]));
    return [point.e(1), point.e(2)];
}

#2


I think the only way to find that would be to apply the same transformations as you did on the rendering context to the points you want to know the actual coordinates. A few libraries provide matrix operations, like : http://sylvester.jcoglan.com/ You can try to perform rotation operations to the cartesian coordinates

我认为找到这种方法的唯一方法是将与渲染上下文相同的变换应用于想要了解实际坐标的点。一些库提供矩阵运算,例如:http://sylvester.jcoglan.com/您可以尝试对笛卡尔坐标执行旋转运算