【问题标题】:How to calculate a bounding box for a rectangle rotated around its corner?如何计算围绕其角旋转的矩形的边界框?
【发布时间】:2021-11-11 03:51:36
【问题描述】:

几天前我问过this question,当一个矩形围绕其中心旋转时,答案非常适用。

但是,我现在正试图让它在矩形围绕其左上角旋转的情况下工作。

链接答案中的这些行仍然正确,可用于计算边界框的宽度和高度:

H = w * Abs(Sin(Fi)) + h * Abs(Cos(Fi))
W = w * Abs(Cos(Fi)) + h * Abs(Sin(Fi))

但是,xy 值不再适用于这种左上角的情况。起初我以为它可能只是一样,只是这样:

x0  = rXCenter - W/2
y0  = rYCenter - H/2

但它似乎不起作用。我认为答案涉及某种sincos 函数,但我不知道哪种组合可以提供正确的输出。同样,我在下面包含了该问题的完整再现:

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 的所有值这样做。

我认为需要在 sn-p 中更改以使其工作的唯一两行是以下两行:

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

但我不太清楚我必须将它们更改为什么才能解决问题。

【问题讨论】:

    标签: javascript math geometry bounding-box


    【解决方案1】:

    围绕角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>

    【讨论】:

    • 啊,这完全有道理。我没想过只是..寻找再次找到中心的方法。再次感谢!
    猜你喜欢
    • 2021-11-07
    • 1970-01-01
    • 2010-10-11
    • 2018-06-08
    • 2016-12-12
    • 2019-01-05
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    相关资源
    最近更新 更多