Rotación de coordenadas

facebook-svg gplus-svg twitter-svg

La vía fácil

Si conocemos las coordenadas del centro de rotación var c = {x:cx, y:cy}, el radio de la trayectoria circular, el angulo inicial del elemento que queremos girar, y el ángulo de rotacion lo tenemos muy fácil. Las nuevas coordenadas del elemento son:

var p1 = {
    x: c.x + radio * Math.cos(angulo + rotacion),
    y: c.y + radio * Math.sin(angulo + rotacion)
  }

En los siguientes ejemplos el punto rojo es la posición que toma el punto azul después de un giro de 30 grados.

See the Pen rotación 2D TEST simple* by Gabi (@enxaneta) on CodePen.

Un poco más complicado

Pero ¿que pasa si conocemos solo: las coordenadas del centro de rotación var c = {x:cx, y:cy}, las coordenadas del punto p que queremos girar y el ángulo de rotacion?

 En este caso tenemos que calcular el radio de la trayectoria circular:

  // la distancia en x entre el punto p y el centro c de la trayectoria
  var dx = p.x - c.x;
  // la distancia en y entre el punto p y el centro c de la trayectoria
  var dy = p.y - c.y;
  // el radio de la trayectoria
  var radio = Math.sqrt(dx * dx + dy * dy);

También tenemos que calcular el ángulo inicial del elemento que queremos girar.

var angulo = Math.atan2(dy, dx);

Finalmente podemos calcular las nuevas coordenadas del elemento utilizando las mismas fórmulas de antes:

var p1 = {
    x: c.x + radio * Math.cos(angulo + rotacion),
    y: c.y + radio * Math.sin(angulo + rotacion)
}

See the Pen rotación 2D TEST #0 by Gabi (@enxaneta) on CodePen.

Este método va muy bien si tenemos que girar un solo punto o muy pocos. Sin embargo es muy ineficiente si tenemos que calcular las trayectorias de un gran número de puntos.

Un método avanzado

Hay unas fórmulas que nos permiten calcular fácilmente el seno y el coseno de la suma de dos ángulos:

cos(a + b) = cos(a)*cos(b) - sin(a)*sin(b);
sin(a + b) = sin(a)*cos(b) + cos(a)*sin(b);

Por lo cual si queremos calcular las coordenadas de un punto después de la rotación podemos escribir ( traducido al javascript ):

x1 = r * (Math.cos(a)*Math.cos(rot)) – r*(Math.sin(a)*Math.sin(rot));
y1 = r * (Math.sin(a)*Math.cos(rot)) + r*(Math.cos(a)*Math.sin(rot));

Donde a es el ángulo inicial, rot es el ángulo de rotación y r es el radio de la trayectoria. Sabemos que podemos calcular el el radio de la trayectoria utilizando estas fórmulas:

  r = x / Math.cos(a) o
  r = y / Math.sin(a);

O sea:

x1 = (x / Math.cos(a)) * (Math.cos(a)*Math.cos(rot)) – 
     (y / Math.sin(a)) * (Math.sin(a)*Math.sin(rot));
     
y1 = (y / Math.sin(a)) * (Math.sin(a)*Math.cos(rot)) + 
     (x / Math.cos(a)) * (Math.cos(a)*Math.sin(rot));

Simplificando podemos escribir:

x1 = x  * Math.cos(rot) - y  * Math.sin(rot);
y1 = y  * Math.cos(rot) + x  * Math.sin(rot);

Y lo podemos poner en una fórmula:


var cos = Math.cos(rotacion);
var sin = Math.sin(rotacion);

function girarPunto(p){
  return {
  x : p.x * cos - p.y * sin,
  y : p.x * sin + p.y * cos
  }
}

OJO: Esta fórmula considera que el centro de rotación es origen del canvas, por lo cual, en el siguiente ejemplo, necesitamos trasladar el contexto en el centro del canvas ( ctx.translate(cx, cy); ):

See the Pen rotación 2D TEST #2 by Gabi (@enxaneta) on CodePen.

Teniendo en cuenta el centro de rotación

En este otro ejemplo el punto p gira alrededor del centro del canvas, así que hemos vuelto a escribir la función girarPunto() para que tenga en cuenta el centro de rotación.


var cos = Math.cos(rotacion);
var sin = Math.sin(rotacion);

function girarPunto(p,centro){
return {
  x: centro.x + (p.x - centro.x) * cos - (p.y - centro.y) * sin,
  y: centro.y + (p.x - centro.x) * sin + (p.y - centro.y) * cos
}
}

See the Pen rotación 2D TEST #3* by Gabi (@enxaneta) on CodePen.