How to calculate rotation in 2D in Javascript

37,188

Solution 1

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). 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.

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

Three notes about this function:

  1. For clockwise rotation, the last parameter angle should be positive. 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 -- i.e. 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. 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.

  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. In HTML / CSS, the Y axis is inverted -- values on the Y axis become higher as you move down the page.

Solution 2

  1. First, translate the rotation center to the origin
  2. Calculate the new coordinates (nx, ny)
  3. Translate back to the original rotation center

Step 1

Your new points are

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

Step 2

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

Step 3

Translate back to original rotation center:

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

For deeper explanation, with some fancy diagrams, I recommend looking at this.

Solution 3

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};
 }

Solution 4

According to Polar coordinate system artycle on Wikipedia:

x = r * cos(deg)
y = r * sin(deg)
  • r (radius) is equal to distance between Rotation Centre and Rotated Point
  • deg (degrees) is angle measured in degrees

Solution 5

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).

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:

rotateVector([x, y, 0], [cX, cY, 0], [0, 0, 1], angleInRadians);
Share:
37,188

Related videos on Youtube

Digerkam
Author by

Digerkam

Diğerkâm means alturist, selfless, sencil, ve özgeci

Updated on July 09, 2022

Comments

  • Digerkam
    Digerkam almost 2 years

    I am not so familiar trigonometry, but I have only two points to rotate in 2D:

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

    cx, cy = rotation center
    x,y = current x,y
    nx, ny = new coordinates

    How to calculate new points in a certain angle?

    • Samuel Reid
      Samuel Reid almost 11 years
      So you have a triangle, and you're trying to calculate the the position of nx,ny when given a new angle?
  • theftprevention
    theftprevention almost 11 years
    That was supposed to be "+". Thank you!
  • Michael
    Michael about 9 years
    It seems about 50% of answers across SO have a "-" in the x formula, and the other half have it in the y formula. In my case, it only seems to work in the y formula. What's going on here?
  • theftprevention
    theftprevention over 8 years
    @Michael I don't know if you're still looking for clarity on this 5 months later, but I've made some edits to the function so it's more generalized now.
  • Michael
    Michael over 8 years
    Thanks! I'll have to go revisit my work: I solved the problem somehow, and it seemed to work ok, but I don't recall what I did now...
  • skibulk
    skibulk over 7 years
    This function works with Screen Coordinate Systems, only the direction of rotation reverses.
  • Junaid Shirwani
    Junaid Shirwani over 7 years
    when i rotate with angle 0. It generates a new coordinate. I was assuming it would generate the same point when rotating 0 degree. Why is that so?
  • theftprevention
    theftprevention about 7 years
    @JunaidShirwani, I can't replicate the behavior you described. Whenever I set the 5th argument (angle) to 0, I always get an array containing the 3rd and 4th arguments ([x, y]) unmodified. Are you seeing something different?
  • prateekj_ahead
    prateekj_ahead almost 7 years
    With regards to the 3rd point made in the answer, if someone wants to use this function to get the coordinates with respect to how coordinate system works in DOM, a minor change will give the right output - just reverse the arithmetic sign in nx and ny formulas as follows: nx = (cos * (x - cx)) - (sin * (y - cy)) + cx, ny = (cos * (y - cy)) + (sin * (x - cx)) + cy;
  • I wrestled a bear once.
    I wrestled a bear once. almost 5 years
    casting the coords to integer if the angle is zero will cut off decimals. you should at the very least cast to a float instead. also your parameters are upper case and your function uses them in lower case.