You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算绕左上角旋转的矩形的边界框坐标?

问题描述

几天前我问过相关问题,得到的答案对于绕自身中心旋转的矩形完全适用。
但我现在需要计算绕自身左上角旋转的矩形的边界框。

此前答案中用于计算边界框宽高的代码仍然正确可用:

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>

运行代码可见,沿用原逻辑得到的红色边界框无法正确包裹黑色旋转矩形,我需要适配所有rA取值的正确计算方式。
我认为只需要修改代码中以下两行计算bbX、bbY的逻辑即可解决问题,但始终找不到正确的修改方式:

let bbX = x - bbW / 2;
let bbY = y - bbH / 2;

请问该如何修改这两行代码,才能正确计算绕左上角旋转的矩形的边界框坐标?


解决方案

直接修改computeBB函数的坐标计算逻辑即可,基于旋转矩阵计算矩形四个顶点旋转后的相对坐标,取偏移最小值作为边界框的左上角:

function computeBB(x, y, w, h, a) {
  let sinA = Math.sin(a);
  let cosA = Math.cos(a);
  let absSinA = Math.abs(sinA);
  let absCosA = Math.abs(cosA);

  // 原有宽高计算逻辑保持不变
  let bbH = w * absSinA + h * absCosA;
  let bbW = w * absCosA + h * absSinA;

  // 计算四个顶点相对于旋转原点的偏移,取最小值作为边界框左上角偏移
  let minX = Math.min(0, w * cosA, -h * sinA, w * cosA - h * sinA);
  let minY = Math.min(0, w * sinA, h * cosA, w * sinA + h * cosA);

  let bbX = x + minX;
  let bbY = y + minY;

  return { x: bbX, y: bbY, w: bbW, h: bbH };
}

该方案对任意正负角度都适配,不需要额外做象限判断。

内容的提问来源于stack exchange,提问作者Ryan Peschel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 21:18:02