Estoy tratando de rotar dos rectángulos la misma cantidad alrededor del mismo punto. El punto es arbitrario, así que para simplificar, estoy usando la esquina superior izquierda (0, 0)
Desafortunadamente, el resultado parece ligeramente incorrecto y no estoy seguro de qué lo está causando. Aquí hay una reproducción completa del problema:
let canvas = document.querySelector("canvas"); let ctx = canvas.getContext("2d"); class Rectangle { constructor(x, y, w, h, theta) { this.x = x; this.y = y; this.w = w; this.h = h; this.theta = theta; } } function drawRectangle(r) { ctx.beginPath(); ctx.rect(rx, ry, rw, rh); ctx.stroke(); } function degreesToRadians(degrees) { return degrees * (Math.PI / 180); } function rotateCanvas(radians, centerX, centerY) { ctx.translate(centerX, centerY); ctx.rotate(radians); ctx.translate(-centerX, -centerY); } function drawRotatedRectangle(r) { let rXCenter = rx + (rw / 2); let rYCenter = ry + (rh / 2); alert(rXCenter); rotateCanvas(r.theta, rXCenter, rYCenter); drawRectangle(r); rotateCanvas(-r.theta, rXCenter, rYCenter); } let r1 = new Rectangle(100, 52, 90, 30, degreesToRadians(-20)); let r2 = new Rectangle(140, 80, 25, 25, degreesToRadians(10)); function simpleRotate(r, theta) { let transX = Math.cos(theta) * rx - Math.sin(theta) * ry; let transY = Math.sin(theta) * rx + Math.cos(theta) * ry; return new Rectangle(transX, transY, rw, rh, r.theta + theta); } drawRotatedRectangle(r1); drawRotatedRectangle(r2); let r1AABB = simpleRotate(r1, -r1.theta); let r2Rotate = simpleRotate(r2, -r1.theta); ctx.strokeStyle = "#ff0000"; drawRotatedRectangle(r1AABB); drawRotatedRectangle(r2Rotate); body { margin: 0; overflow: hidden; } <canvas width="600" height="600"></canvas>Los rectángulos negros son los dos rectángulos antes de rotar, y los rectángulos rojos son los dos rectángulos después de rotar.
Como puede ver, los dos rectángulos negros se tocan (colisionan) antes de girar. Luego, los giro a ambos en la misma cantidad alrededor del mismo punto (0, 0) . Sin embargo, luego ya no se tocan (como puede ver, los rectángulos rojos ya no chocan).
¿Por qué es esto? Seguí este código para rotar un punto, pero parece que estoy obteniendo resultados inexactos.
Si tomo una captura de pantalla de los rectángulos negros, abro un editor de imágenes, los selecciono y los giro, luego permanecen juntos (colisionando). ¿Cómo puedo emular esto en mi ejemplo de código publicado anteriormente?
Esto puede dejar que funcione como esperas.
function simpleRotate(r, theta) { let transX = Math.cos(theta) * (rx + rw / 2) - Math.sin(theta) * (ry + rh / 2) - rw / 2; let transY = Math.sin(theta) * (rx + rw / 2) + Math.cos(theta) * (ry + rh / 2) - rh / 2; return new Rectangle(transX, transY, rw, rh, r.theta + theta); }De lo contrario, si desea cambiar de centro, utilice el siguiente formulario.
function simpleRotate(r, theta, centerX, centerY) { let transX = Math.cos(theta) * (rx + rw / 2 - centerX) - Math.sin(theta) * (ry + rh / 2 - centerY) - rw / 2 + centerX; let transY = Math.sin(theta) * (rx + rw / 2 - centerX) + Math.cos(theta) * (ry + rh / 2 - centerY) - rh / 2 + centerY; return new Rectangle(transX, transY, rw, rh, r.theta + theta); }Después
let r1AABB = simpleRotate(r1, -r1.theta, 145, 67); let r2Rotate = simpleRotate(r2, -r1.theta, 145, 67); En general, 2d rotational transform with offset consta de translation y rotation . Luego, en esa configuración, la rotation se aplicará a través drawRotatedRectangle() después. Por lo tanto, todo lo que tiene que hacer es componer una translation adecuada. Al inspeccionar la función simpleRotate() cuidado, notará que lo que realmente se hace allí es el cálculo de la translation ( transX , transY ... aunque se usan sin / cos ).
Luego, como sabe, dado que drawRotatedRectangle() rota el rectángulo alrededor de su centro, al componer la translation para mover el centro a la posición adecuada, puede obtener rotational transform que necesita.
Estado inicial → Traduce cada elemento con simpleRotate() → Rota cada elemento con drawRotatedRectangle() → Estado final.