MAIN EN typewriter

older-tomato

Spinning square on plane

Linear algebra • Rotation matrix 06.01.2023

Let’s write an algorithm in JavaScript to rotate a square by an angle around its center, repeat the high school program. We will use the Math class for calculations, and Canvas for displaying the results.

Development of thought, volumetric model: Spinning cube in space.

Point rotation on plane #

We calculate the coordinates of the new point using the formulas of the rotation matrix for two-dimensional space. We rotate the point t relative to the point t0 — we get the point t'.

&x'=x_0+(x-x_0)cos\varphi-(y-y_0)sin\varphi,&\\&y'=y_0+(x-x_0)sin\varphi+(y-y_0)cos\varphi.&\\

Algorithm description #

The origin of the coordinates is in the upper left corner, the coordinate axes are directed to the right and down. The central point for rotations t0 is located in the center of the figure. A square is an array of four points-vertices. We bypass the array of points, rotate each of them by an angle, then link the points with lines and draw lines on the canvas. We renew the image at a frequency of 20 frames per second.

Implementation #

Canvas for displaying computations results

HTML #

<canvas id="canvas" width="300" height="300" style="border: 1px solid gray;">
  <p>Canvas for displaying computations results</p>
</canvas>

JavaScript #

'use strict';
let canvas = document.getElementById('canvas');
// original array of points-vertices of square
let square = [{x:50,y:50},{x:50,y:250},{x:250,y:250},{x:250,y:50}];
// figure center, we'll perform a rotation around it
let t0 = {x:150, y:150};
// rotation angle in degrees
let deg = 1;
// figure rotation and image refresh
function repaint() {
  // rotate the original array of points by an angle
  for (let i = 0; i < square.length; i++)
    square[i] = rotateOnDegree(t0, square[i], deg);
  // draw the current array of points
  drawFigure(canvas, square);
}
// rotate the point (t) by an angle (deg) relative to the point (t0)
function rotateOnDegree(t0, t, deg) {
  let t_new = {};
  // convert angle of rotation from degrees to radians
  let rad = (Math.PI / 180) * deg;
  // calculate the coordinates of the new point using the formula
  t_new.x = t0.x+(t.x-t0.x)*Math.cos(rad)-(t.y-t0.y)*Math.sin(rad);
  t_new.y = t0.y+(t.x-t0.x)*Math.sin(rad)+(t.y-t0.y)*Math.cos(rad);
  // return new point
  return t_new;
}
// draw a figure by points from an array
function drawFigure(canvas, arr) {
  let context = canvas.getContext('2d');
  // clear the entire canvas
  context.clearRect(0, 0, canvas.width, canvas.height);
  // bypass the array of points and link them with lines
  context.beginPath();
  for (let i = 0; i < arr.length; i++)
    if (i == 0)
      context.moveTo(arr[i].x, arr[i].y);
    else
      context.lineTo(arr[i].x, arr[i].y);
  context.closePath();
  // draw lines on the canvas
  context.lineWidth = 2.2;
  context.strokeStyle = '#222';
  context.stroke();
}
// after loading the page, set the image refresh rate at 20 Hz
document.addEventListener('DOMContentLoaded',()=>setInterval(repaint,50));

Spinning backwards #

Let’s add one more point, which we’ll rotate backwards. The point is distant from the center of the figure by a quarter of the length of the side of the square. let’s shift the center of the square to this point — shift the array of its vertices. We will rotate the square itself clockwise, and its central point — counterclockwise. This code works in conjunction with the previous one.

Canvas for displaying computations results

HTML #

<canvas id="canvas2" width="300" height="300" style="border: 1px solid gray;">
  <p>Canvas for displaying computations results</p>
</canvas>

JavaScript #

'use strict';
let canvas2 = document.getElementById('canvas2');
// current array of points
let square2 = [];
// spinning point
let t2 = {x:100, y:100};
// figure rotation and image refresh
function repaint2() {
  // rotate the point in the opposite direction
  t2 = rotateOnDegree(t0, t2, -deg);
  // bypass the points of the original array and shift
  for (let i = 0; i < square.length; i++) {
    // current point
    square2[i] = {};
    // shifting the point of the original array
    square2[i].x = square[i].x - t0.x + t2.x;
    square2[i].y = square[i].y - t0.y + t2.y;
  }
  // draw the current array of points
  drawFigure(canvas2, square2);
}
// after loading the page, set the image refresh rate at 20 Hz
document.addEventListener('DOMContentLoaded',()=>setInterval(repaint2,50));

© Golovin G.G., Code with comments, translation from Russian, 2023