如何计算围绕其角旋转的矩形的边界框?
How to calculate a bounding box for a rectangle rotated around its corner?
我几天前问过 ,当矩形围绕其中心旋转时,答案非常适用。
但是,我现在正试图让它在矩形围绕其左上角旋转的情况下工作。
链接答案中的这些行仍然正确并且可用于计算边界框的宽度和高度:
H = w * Abs(Sin(Fi)) + h * Abs(Cos(Fi))
W = w * Abs(Cos(Fi)) + h * Abs(Sin(Fi))
但是,x
和 y
值不再适用于这种左上角的情况。起初我以为它可能只是一样的,只是这个:
x0 = rXCenter - W/2
y0 = rYCenter - H/2
但是好像不行。我 认为 答案涉及某种 sin
和 cos
函数,但我无法弄清楚哪种组合提供了正确的输出。同样,我在下面包含了问题的完整复制:
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>
如您所见,当尝试使用相同的代码时,边界框(红色矩形)没有正确包围黑色矩形,我试图让它对 [=20 的所有值都这样做=].
我认为代码片段中只有两行需要更改才能使其正常工作:
let bbX = x - bbW / 2;
let bbY = y - bbH / 2;
但我不太明白我必须将它们更改为什么才能解决问题。
围绕角 x0, y0
旋转角度 Fi
后矩形中心有坐标
cx = x0 + w/2*Cos(Fi) - h/2*Sin(Fi)
cy = y0 + w/2*Sin(Fi) + h/2*Cos(Fi)
边界框中心的坐标相同。所以边界框底角是
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>
我几天前问过
但是,我现在正试图让它在矩形围绕其左上角旋转的情况下工作。
链接答案中的这些行仍然正确并且可用于计算边界框的宽度和高度:
H = w * Abs(Sin(Fi)) + h * Abs(Cos(Fi))
W = w * Abs(Cos(Fi)) + h * Abs(Sin(Fi))
但是,x
和 y
值不再适用于这种左上角的情况。起初我以为它可能只是一样的,只是这个:
x0 = rXCenter - W/2
y0 = rYCenter - H/2
但是好像不行。我 认为 答案涉及某种 sin
和 cos
函数,但我无法弄清楚哪种组合提供了正确的输出。同样,我在下面包含了问题的完整复制:
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>
如您所见,当尝试使用相同的代码时,边界框(红色矩形)没有正确包围黑色矩形,我试图让它对 [=20 的所有值都这样做=].
我认为代码片段中只有两行需要更改才能使其正常工作:
let bbX = x - bbW / 2;
let bbY = y - bbH / 2;
但我不太明白我必须将它们更改为什么才能解决问题。
围绕角 x0, y0
旋转角度 Fi
后矩形中心有坐标
cx = x0 + w/2*Cos(Fi) - h/2*Sin(Fi)
cy = y0 + w/2*Sin(Fi) + h/2*Cos(Fi)
边界框中心的坐标相同。所以边界框底角是
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>