【问题标题】:How to rotate a rectangle around an origin?如何围绕原点旋转矩形?
【发布时间】:2021-11-07 10:36:06
【问题描述】:

我正在尝试围绕同一点以相同的量旋转两个矩形。这个点是任意的,所以为简单起见,我使用左上角的(0, 0)

不幸的是,结果似乎有些偏差,我不确定是什么原因造成的。这是该问题的完整再现:

let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");

class Rectangle {
  constructor(x, y, w, h, theta) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.theta = theta;
  }
}

function drawRectangle(r) {
  ctx.beginPath();
  ctx.rect(r.x, r.y, r.w, r.h);
  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(r) {
  let rXCenter = r.x + (r.w / 2);
  let rYCenter = r.y + (r.h / 2);
  alert(rXCenter);

  rotateCanvas(r.theta, rXCenter, rYCenter);
  drawRectangle(r);
  rotateCanvas(-r.theta, rXCenter, rYCenter);
}

let r1 = new Rectangle(100, 52, 90, 30, degreesToRadians(-20));
let r2 = new Rectangle(140, 80, 25, 25, degreesToRadians(10));

function simpleRotate(r, theta) {
  let transX = Math.cos(theta) * r.x - Math.sin(theta) * r.y;
  let transY = Math.sin(theta) * r.x + Math.cos(theta) * r.y;

  return new Rectangle(transX, transY, r.w, r.h, r.theta + theta);
}

drawRotatedRectangle(r1);
drawRotatedRectangle(r2);

let r1AABB = simpleRotate(r1, -r1.theta);
let r2Rotate = simpleRotate(r2, -r1.theta);

ctx.strokeStyle = "#ff0000";
drawRotatedRectangle(r1AABB);
drawRotatedRectangle(r2Rotate);
body { margin: 0; overflow: hidden; }
<canvas width="600" height="600"></canvas>

黑色矩形是旋转前的两个矩形,红色矩形是旋转后的两个矩形。

如您所见,两个黑色矩形在旋转之前是接触(碰撞)的。然后,我围绕同一点 (0, 0) 将它们旋转相同的量。但是,之后它们不再接触(您可以看到红色矩形不再碰撞。

这是为什么?我跟着 this code 旋转了一个点,但我似乎得到了不准确的结果。

如果我截取黑色矩形的屏幕截图,打开图像编辑器,框选它们并旋转它们,然后它们会保持在一起(碰撞)。如何在上面发布的代码示例中模拟这一点?

【问题讨论】:

  • Emm... 什么是旋转矩形的 x(和 y)?
  • @MBo 我不确定你的意思?你指的是哪一行代码?
  • 您在矩形类中定义了一些基本点 x,y。对于轴对齐的矩形,它具有毫无疑问的意义,但旋转矩形的基点在哪里?也许矩形中心会更可靠(在任意矩形的比较几何中的常见情况 - 定义中心,以及方向的一些变体 - 或侧向量,或宽度/高度/角度)
  • 哦,我想我明白你的意思了。是的,旋转的矩形在绘制时会围绕它们的原点(它们的中心)旋转。
  • 看到let rXCenter = r.x + (r.w / 2); 我很怀疑如果矩形被旋转 - 这个公式计算的中心在哪里?

标签: javascript math graphics geometry


【解决方案1】:

这可能会让它按您的预期工作。

function simpleRotate(r, theta) {
    let transX = Math.cos(theta) * (r.x + r.w / 2) - Math.sin(theta) * (r.y + r.h / 2) - r.w / 2;
    let transY = Math.sin(theta) * (r.x + r.w / 2) + Math.cos(theta) * (r.y + r.h / 2) - r.h / 2;
    return new Rectangle(transX, transY, r.w, r.h, r.theta + theta);
}

其他,如果您想更改中心,请使用以下表格。

function simpleRotate(r, theta, centerX, centerY) {
    let transX = Math.cos(theta) * (r.x + r.w / 2 - centerX) - Math.sin(theta) * (r.y + r.h / 2 - centerY) - r.w / 2 + centerX;
    let transY = Math.sin(theta) * (r.x + r.w / 2 - centerX) + Math.cos(theta) * (r.y + r.h / 2 - centerY) - r.h / 2 + centerY;
    return new Rectangle(transX, transY, r.w, r.h, r.theta + theta);
}

然后

let r1AABB = simpleRotate(r1, -r1.theta, 145, 67);
let r2Rotate = simpleRotate(r2, -r1.theta, 145, 67);

这些是如何工作的

一般来说,2d rotational transform with offsettranslationrotation 组成。然后,在该设置中,rotation 随后将通过drawRotatedRectangle() 应用。因此,您所要做的就是撰写适当的translation。仔细检查simpleRotate() 函数,你会注意到实际做了什么,计算translationtransXtransY ... 虽然sin/cos 正在使用)。

那么,如你所知,由于drawRotatedRectangle()是围绕其中心旋转矩形,通过组合translation将中心移动到合适的位置,就可以得到你需要的rotational transform

初始状态 → 通过 simpleRotate() 平移每个项目 → 通过 drawRotatedRectangle() 旋转每个项目 → 最终状态。

【讨论】:

  • 我可能做错了什么,但这似乎也不能解决它。另外,我不想不旋转矩形的中心点(这似乎是这样做的)?我的直觉是我只需要获取矩形左上角的新 x 和 y 位置。
  • 对不起,我不明白你的目标是什么。据我了解,您的 rotateCanvas() 函数似乎仅支持每个矩形围绕其中心进行单独旋转。如果您想通过您的实现以某种同步方式旋转多个矩形,它不适合您的目的。不过,会有办法的。如果可能,请提供您期望的矩形排列的简要草图。
  • 当然,这是我刚刚在 MS Paint 中绘制的粗略草图:i.imgur.com/UqHOQPf.png 左边是我目前拥有的,但右边是我正在拍摄的。基本上让两个形状一起围绕左上角 (0, 0) 旋转。
  • 看到草图,我认为我的答案中的代码并没有那么错误。请先自己尝试。那么让我们考虑一下出了什么问题。
  • 嗯,我想我搞砸了。我会在这里继续试验你的代码。
猜你喜欢
  • 1970-01-01
  • 2019-08-30
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-24
  • 1970-01-01
相关资源
最近更新 更多