Estoy buscando calcular el cuadro delimitador de un rectángulo girado alrededor de su centro. He leído esta pregunta y aunque la respuesta de MarkusQ funciona en general, no es lo suficientemente eficiente para mis necesidades. Estoy tratando de que la respuesta de Troubadour funcione, pero parece que solo funciona cuando el origen de la rotación está en una esquina, no en el centro.
¿Es posible adaptar su solución para trabajar con rectángulos que tienen su origen de rotación alrededor de su centro?
He desarrollado una recreación completa del problema a continuación:
let canvas = document.querySelector("canvas"); let ctx = canvas.getContext("2d"); function drawRectangle(rX, rY, rW, rH) { 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(rX, rY, rW, rH, rAngle) { let rXCenter = rX + rW / 2; let rYCenter = rY + rH / 2; rotateCanvas(rAngle, rXCenter, rYCenter); drawRectangle(rX, rY, rW, rH); rotateCanvas(-rAngle, rXCenter, rYCenter); } function computeAABBCenter(x, y, w, h, theta) { const ux = Math.cos(theta) * 0.5; // half unit vector along w const uy = Math.sin(theta) * 0.5; const wx = w * ux; const wy = w * uy; // vector along w const hx = h * -uy; const hy = h * ux; // vector along h // all point from top left CW const x1 = x - wx - hx; const y1 = y - wy - hy; const x2 = x + wx - hx; const y2 = y + wy - hy; const x3 = x + wx + hx; const y3 = y + wy + hy; const x4 = x - wx + hx; const y4 = y - wy + hy; return { x1: Math.min(x1, x2, x3, x4), y1: Math.min(y1, y2, y3, y4), x2: Math.max(x1, x2, x3, x4), y2: Math.max(y1, y2, y3, y4), }; } let rX = 100; let rY = 100; let rW = 100; let rH = 50; let rA = 0.707; drawRotatedRectangle(rX, rY, rW, rH, rA); let bb = computeAABBCenter(rX, rY, rW, rH, rA); drawRectangle(bb.x1, bb.y1, bb.x2 - bb.x1, bb.y2 - bb.y1); body { margin: 0; overflow: hidden; } <canvas width="800" height="800"></canvas>Como puede ver, el rectángulo del cuadro delimitador no es correcto. Así es como se ve actualmente y cómo debería verse:
Tamaño del cuadro delimitador ( descripción aquí )
H = w * Abs(Sin(Fi)) + h * Abs(Cos(Fi)) W = w * Abs(Cos(Fi)) + h * Abs(Sin(Fi)) Teniendo rXCenter, rYCenter , puede encontrar las coordenadas de los límites
x0 = rXCenter - W/2 y0 = rYCenter - H/2Se siente como si estuvieras pensando demasiado en esto. Aquí muestro cómo dibujar tres rectángulos girados alrededor de un punto central que hice azul.
const wrapper = document.getElementById('wrapper'); const canvas = document.getElementById('canvas'); const wCS = window.getComputedStyle(wrapper, null) const pl = parseFloat(wCS.getPropertyValue('padding-left')); const pt = parseFloat(wCS.getPropertyValue('padding-top')); const pr = parseFloat(wCS.getPropertyValue('padding-right')); const pb = parseFloat(wCS.getPropertyValue('padding-bottom')); canvas.width = wrapper.clientWidth - pl - pr; canvas.height = wrapper.clientHeight - pt - pb; const ctx = canvas.getContext('2d'); // setup a rectangle let cornerLeft = 70; let cornerTop = 70; let width = 180; let height = 60; let horizontalCenter = cornerTop + (width / 2); let verticalCenter = cornerTop + (height / 2); let centerPoint = { horz: horizontalCenter, vert: verticalCenter }; let colorBlue = '#0000FF'; let colorLime = '#40FF40'; let colorPurple = '#4040FF'; let colorOrange = '#FFA500'; ctx.fillStyle = colorBlue; ctx.fillRect(centerPoint.horz, centerPoint.vert, 8, 8); // fill in the pixels at center point ctx.strokeStyle = colorPurple; ctx.strokeRect(cornerTop, cornerLeft, width, height); // horizontal purple box ctx.strokeStyle = colorOrange; ctx.translate(centerPoint.horz, centerPoint.vert); // center point note positive ctx.rotate(Math.PI / 2); // vertical ctx.translate(-centerPoint.horz, -centerPoint.vert); // center point - note negative ctx.strokeRect(cornerTop, cornerLeft, width, height); // vertical orange box ctx.strokeStyle = colorLime; ctx.translate(-centerPoint.horz * (1.375), -centerPoint.vert * (0.5)); // center point - note negative ctx.rotate((Math.PI / 2) / -2); //back left by 45 deg left ctx.translate(centerPoint.horz * (.025), centerPoint.vert * (2.75)); // center point note positive ctx.strokeRect(cornerTop, cornerLeft, width, height); #wrapper { width: 400px; height: 400px; padding: 2rem; border: 1px solid blue; } #canvas { border: 1px solid orange; } <div id="wrapper"><canvas id="canvas"></canvas></div>