【问题标题】:How to calculate a bounding box for a rectangle rotated around its center?如何计算围绕其中心旋转的矩形的边界框?
【发布时间】:2021-11-07 20:47:05
【问题描述】:

我正在计算围绕其中心旋转的矩形的边界框。我已经阅读了this question,虽然 MarkusQ 的回答通常有效,但它的效率不足以满足我的需求。我试图让 Troubadour 的答案起作用,但它似乎只在旋转原点在拐角处而不是中心时才起作用。

是否可以调整他的解决方案以处理以中心为中心旋转的矩形?

我已经对以下问题进行了完整的重现:

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>

如您所见,边界框矩形不正确。以下是它目前的样子,以及它应该是什么样子:

【问题讨论】:

标签: javascript math geometry bounding-box


【解决方案1】:

边界框的大小 (description here)

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

rXCenter, rYCenter,你可以找到获取边界坐标

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

【讨论】:

    【解决方案2】:

    感觉你想多了。在这里,我展示了如何绘制三个围绕中心点旋转的矩形。

    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>

    【讨论】:

      猜你喜欢
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-21
      • 2013-08-23
      • 2010-10-11
      • 2015-03-29
      • 2018-08-24
      相关资源
      最近更新 更多