I asked this question several days ago and the answer works perfectly for when a rectangle is rotated around its center.
However, I'm now trying to get it working in the case that the rectangle is rotated around its top left corner and I still haven't figured it out after several hours of trying.
These lines from the linked answer are still correct and working for calculating the width and height of the bounding box:
H = w * Abs(Sin(Fi)) h * Abs(Cos(Fi))
W = w * Abs(Cos(Fi)) h * Abs(Sin(Fi))
However, the x
and y
values are no longer working for this top-left case. At first I thought it may just be the same and just this:
x0 = rXCenter - W/2
y0 = rYCenter - H/2
But it doesn't seem to work. I think the answer involves some sort of sin
and cos
functions, but I can't figure out which combination provides the correct output. Again, I've included a full reproduction of the issue below:
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, rOX, rOY) {
rotateCanvas(rAngle, rOX, rOY);
drawRectangle(rX, rY, rW, rH);
rotateCanvas(-rAngle, rOX, rOY);
}
function computeBB(x, y, w, h, a) {
let sinA = Math.abs(Math.sin(a));
let cosA = Math.abs(Math.cos(a));
let bbH = w * sinA h * cosA;
let bbW = w * cosA h * sinA;
let bbX = x - bbW / 2;
let bbY = y - bbH / 2;
return { x: bbX, y: bbY, w: bbW, h: bbH };
}
let rX = 100;
let rY = 100;
let rW = 100;
let rH = 50;
let rA = degreesToRadians(45);
let rOX = rX;
let rOY = rY;
drawRotatedRectangle(rX, rY, rW, rH, rA, rOX, rOY);
let bb = computeBB(rX, rY, rW, rH, rA);
ctx.strokeStyle = "#ff0000";
drawRectangle(bb.x, bb.y, bb.w, bb.h);
body { margin: 0; overflow: hidden; }
<canvas width="600" height="600"></canvas>
As you can see, when trying to use the same code, the bounding box (red rectangle) does not properly enclose the black rectangle, and I am trying to get it to do so for all values of rA
.
The only two lines that I believe need to be changed in the snippet to get it to work are these two:
let bbX = x - bbW / 2;
let bbY = y - bbH / 2;
But I can't quite figure out what I have to change them to in order to fix the problem.
CodePudding user response:
After rotation about corner x0, y0
by angle Fi
rectangle center has coordinates
cx = x0 w/2*Cos(Fi) - h/2*Sin(Fi)
cy = y0 w/2*Sin(Fi) h/2*Cos(Fi)
Same coordinates are for bounding box center. So bounding box base corner is
bbx = cx - bbW/2
bby = cy - bbH/2
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, rOX, rOY) {
rotateCanvas(rAngle, rOX, rOY);
drawRectangle(rX, rY, rW, rH);
rotateCanvas(-rAngle, rOX, rOY);
}
function computeBB(x, y, w, h, a) {
let sinA = Math.abs(Math.sin(a));
let cosA = Math.abs(Math.cos(a));
let bbH = w * sinA h * cosA;
let bbW = w * cosA h * sinA;
let cx = x w/2*Math.cos(a) - h/2*Math.sin(a)
let cy = y w/2*Math.sin(a) h/2*Math.cos(a)
let bbX = cx - bbW / 2;
let bbY = cy - bbH / 2;
return { x: bbX, y: bbY, w: bbW, h: bbH };
}
let rX = 100;
let rY = 100;
let rW = 100;
let rH = 50;
let rA = degreesToRadians(45);
let rOX = rX;
let rOY = rY;
drawRotatedRectangle(rX, rY, rW, rH, rA, rOX, rOY);
let bb = computeBB(rX, rY, rW, rH, rA);
ctx.strokeStyle = "#ff0000";
drawRectangle(bb.x, bb.y, bb.w, bb.h);
<canvas width="600" height="600"></canvas>