简体   繁体   English

如何在 Javascript 中计算 2D 中的旋转

[英]How to calculate rotation in 2D in Javascript

I am not so familiar trigonometry, but I have only two points to rotate in 2D:我不太熟悉三角学,但我只有两个点可以在 2D 中旋转:

                    *nx, ny
               .     -
          .           -
     .  angle          -
*cx,cy.................*x,y

cx, cy = rotation center cx, cy = 旋转中心
x,y = current x,y x,y = 当前 x,y
nx, ny = new coordinates nx, ny = 新坐标

How to calculate new points in a certain angle?如何计算某个角度的新点?

function rotate(cx, cy, x, y, angle) {
    var radians = (Math.PI / 180) * angle,
        cos = Math.cos(radians),
        sin = Math.sin(radians),
        nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
        ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
    return [nx, ny];
}

The first two parameters are the X and Y coordinates of the central point (the origin around which the second point will be rotated).前两个参数是中心点(第二个点将围绕其旋转的原点)的 X 和 Y 坐标。 The next two parameters are the coordinates of the point that we'll be rotating.接下来的两个参数是我们将要旋转的点的坐标。 The last parameter is the angle, in degrees.最后一个参数是角度,以度为单位。

As an example, we'll take the point (2, 1) and rotate it around the point (1, 1) by 90 degrees clockwise.例如,我们将取点 (2, 1) 并将其绕点 (1, 1) 顺时针旋转 90 度。

rotate(1, 1, 2, 1, 90);
// > [1, 0]

Three notes about this function:关于这个函数的三个注意事项:

  1. For clockwise rotation, the last parameter angle should be positive.对于顺时针旋转,最后一个参数angle应为正。 For counterclockwise rotation (like in the diagram you provided), it should be negative.对于逆时针旋转(如您提供的图表),它应该是负的。

  2. Note that even if you provide arguments that should yield a point whose coordinates are whole numbers -- ie rotating the point (5, 0) by 90 degrees about the origin (0, 0), which should yield (0, -5) -- JavaScript's rounding behavior means that either coordinate could still be a value that's frustratingly close to the expected whole number, but is still a float.请注意,即使您提供的参数应该产生坐标为整数的点 - 即将点 (5, 0) 围绕原点 (0, 0) 旋转 90 度,这应该产生 (0, -5) - - JavaScript 的舍入行为意味着任一坐标仍然可能是一个非常接近预期整数的值,但仍然是一个浮点数。 For example:例如:

     rotate(0, 0, 5, 0, 90); // > [3.061616997868383e-16, -5]

    For this reason, both elements of the resulting array should be expected as a float.因此,结果数组的两个元素都应该是浮点数。 You can convert them to integers using Math.round() , Math.ceil() , or Math.floor() as needed.您可以根据需要使用Math.round()Math.ceil()Math.floor()将它们转换为整数。

  3. Finally, note that this function assumes a Cartesian coordinate system , meaning that values on the Y axis become higher as you go "up" in the coordinate plane.最后,请注意,此函数采用笛卡尔坐标系,这意味着 Y 轴上的值随着您在坐标平面中“向上”而变高。 In HTML / CSS, the Y axis is inverted -- values on the Y axis become higher as you move down the page .在 HTML/CSS 中,Y 轴是倒置的——当您向下移动页面时,Y 轴上的值会变高。

  1. First, translate the rotation center to the origin首先,将旋转中心平移到原点
  2. Calculate the new coordinates (nx, ny)计算新坐标 (nx, ny)
  3. Translate back to the original rotation center平移回原来的旋转中心

Step 1第 1 步

Your new points are你的新积分是

  1. center: (0,0)中心:(0,0)
  2. point: (x-cx, y-cy)点:(x-cx,y-cy)

Step 2第2步

  1. nx = (x-cx)*cos(theta) - (y-cy)*sin(theta) nx = (x-cx)*cos(theta) - (y-cy)*sin(theta)
  2. ny = (y-cy)*cos(theta) + (x-cx)*sin(theta) ny = (y-cy)*cos(theta) + (x-cx)*sin(theta)

Step 3第 3 步

Translate back to original rotation center:转换回原始旋转中心:

  1. nx = (x-cx)*cos(theta) - (y-cy)*sin(theta) + cx nx = (x-cx)*cos(theta) - (y-cy)*sin(theta) + cx
  2. ny = (y-cy)*cos(theta) + (x-cx)*sin(theta) + cy ny = (y-cy)*cos(theta) + (x-cx)*sin(theta) + cy

For deeper explanation, with some fancy diagrams, I recommend looking at this .为了更深入的解释,有一些花哨的图表,我建议看这个

above accepted answer not work for me correctly, rotation are reversed , here is working function以上接受的答案对我来说不正确,旋转是反向的,这是工作功能

/*
 CX @ Origin X  
 CY @ Origin Y
 X  @ Point X to be rotated
 Y  @ Point Y to be rotated  
 anticlock_wise @ to rotate point in clockwise direction or anticlockwise , default clockwise 
 return @ {x,y}  
*/
function rotate(cx, cy, x, y, angle,anticlock_wise = false) {
    if(angle == 0){
        return {x:parseFloat(x), y:parseFloat(y)};
    }if(anticlock_wise){
        var radians = (Math.PI / 180) * angle;
    }else{
        var radians = (Math.PI / -180) * angle;
    }
    var cos = Math.cos(radians);
    var sin = Math.sin(radians);
    var nx = (cos * (x - cx)) + (sin * (y - cy)) + cx;
    var ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
    return {x:nx, y:ny};
 }

According to Polar coordinate system artycle on Wikipedia :根据Wikipedia 上的极坐标系 artycle

x = r * cos(deg)
y = r * sin(deg)
  • r ( radius ) is equal to distance between Rotation Centre and Rotated Point r半径)等于Rotation CentreRotated Point之间的距离
  • deg ( degrees ) is angle measured in degrees deg)是以为单位的角度

I think it is better to use matrices for such operations.我认为最好使用矩阵进行此类操作。

Here is the example with gl-matrix (but you can use something like THREEJS as well).这是 gl-matrix 的示例(但您也可以使用 THREEJS 之类的东西)。

import * as glm from 'gl-matrix';
const rotateVector = (() => {
  
  const q = glm.quat.create();  
  // const m = glm.mat4.create(); // 2nd way

  return (v: glm.vec3, point: glm.vec3, axis: glm.vec3, angle: number) => {

      glm.quat.setAxisAngle(q, axis, angle);
      // glm.mat4.fromRotation(m, angle, axis); // 2nd way
      glm.vec3.sub(v, v, point);
      glm.vec3.transformQuat(v, v, q);
      // glm.vec3.transformMat4(v, v, m); // 2nd way
      glm.vec3.add(v, v, point);
      return v;
  }
})();

In 2D case you need to rotate around z-axis:在 2D 情况下,您需要绕 z 轴旋转:

rotateVector([x, y, 0], [cX, cY, 0], [0, 0, 1], angleInRadians);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM