如何获得旋转三角形的右下角 X 和 Y

How do I get the bottom-right X & Y of a rotated triangle

我正在尝试使用 JavaScript 创建一个可以在 0° - 360° 之间旋转的三角形,然后将其绘制到 canvas。

三角形的原点是 1/2 高和 1/2 宽(所以在中心)。三角形会相对于原点旋转。

我已经使用以下代码从原点(三角形的中心)计算出点 A(三角形的顶部)的位置

    let aX = Math.cos(radians) * origin.x - Math.sin(radians) * origin.y;
    let aY = Math.sin(radians) * origin.x + Math.cos(radians) * origin.y;

现在,我需要找到 B 点(三角形右下角)的 x 和 y 位置。

我必须处理的信息是:

如何在考虑旋转角度的情况下找到 B 点的 x 和 y 位置?

我试过了

let bX = Math.cos(radians) * Width/2 + Math.sin(radians) * Height/2;
let bY = Math.sin(radians) * Width/2 - Math.cos(radians) * Height/2; 

但这又回来了

*注意忽略倒角

B有初始坐标(Width/2, -Height/2),所以旋转后

let bX = Math.cos(radians) * Width/2 + Math.sin(radians) * Height/2;
let bY = Math.sin(radians) * Width/2 - Math.cos(radians) * Height/2; 

C 更改第一项的符号( - Width/2

围绕点c旋转任意点p的公式是

qₓ = cos(θ) * (pₓ - cₓ) - sin(θ) * (pᵧ - cᵧ) + cₓ
qᵧ = sin(θ) * (pₓ - cₓ) + cos(θ) * (pᵧ - cᵧ) + cᵧ ,

其中 q 是结果点。您可以按如下方式推导此公式。

众所周知(参见 [Wikipedia Rotation Matrix]),围绕原点旋转一个点 a,得到一个点 b,其中

bₓ = cos(θ) * aₓ - sin(θ) * aᵧ
bᵧ = sin(θ) * aₓ + cos(θ) * aᵧ .

你得到想要的公式,首先移动整个图形,使旋转中心移动到原点,即

aₓ = pₓ - cₓ
aᵧ = pᵧ - cᵧ .

然后,应用旋转,然后将所有内容移回原位,即

qₓ = bₓ - cₓ
qᵧ = bᵧ - cᵧ .

假设BxBy包含旋转前B的坐标,origin.xorigin.y包含原点的坐标,你使用以下代码获取 B 旋转后的坐标。

Bx_new = Math.cos(theta) * (Bx - origin.x) - Math.sin(theta) * (By - origin.y) + origin.x
By_new = Math.sin(theta) * (Bx - origin.x) + Math.cos(theta) * (By - origin.y) + origin.y

如果我正确理解你的草图,你会:

let origin = {'x': 0, 'y': 0}
let Bx = width/2.0
let By = -height/2.0

我设法使用以下代码解决了这个问题:

let bX = origin.x + Math.cos(radians) * -height / 2 - Math.sin(radians) * -width / 2
let bY = origin.y + Math.sin(radians) * -height / 2 + Math.cos(radians) * -width / 2

我最喜欢的计算二维旋转的方法是使用复数,使用简单的规则

Q = P e^(iΘ)

这描述了围绕原点的旋转,角度 Θ,适用于 PQ。现在,由你找到点 AB 的坐标,扮演 P.

的角色

附录:

如果你的旋转中心是C而不是原点,我们有

Q - C = (P - C) e^(iΘ)

Q = (P - C) e^(iΘ) + C.

[请不要告诉我你不能t/don不想使用复数。重写只有实数的公式很简单。]

如果您要使用 canvas,我建议您使用 getTransform(),其中 returns 可用于更新顶点的变换矩阵。这是一个片段,显示了三角形旋转时更新的顶点。

正如您将在此代码段中看到的,我首先使用传入的值计算质心。然后我可以从每个顶点中减去该数量,以便将变换原点变为三角形的中心。

要移动三角形,请使用 this.translate()。您也可以将这些值作为参数传递。使用 setTransform() 我们可以传入旋转值并平移数量并将 getTransform() 分配给一个变量允许我们将其传递给将计算新顶点位置的函数。

let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;

class Triangle {
  constructor(ptA, ptB, ptC) {
    this.ptA = ptA;
    this.ptB = ptB;
    this.ptC = ptC;
    this.translate = {x: 155, y: 100 };
    this.centroid = {
      ox: (this.ptA.x + this.ptB.x + this.ptC.x) / 3,
      oy: (this.ptA.y + this.ptB.y + this.ptC.y) / 3
    };
    this.c = "red";
    this.a = 0;
    this.rotation = this.a * (Math.PI / 180);
    this.pts = [];
  }
  draw() {
    let t;
    this.a -= 0.5;
    this.rotation = this.a * (Math.PI / 180);
    const cos = Math.cos(this.rotation)
    const sin = Math.sin(this.rotation)
    
    ctx.save();
    ctx.beginPath();
    ctx.fillStyle = this.c;
    ctx.setTransform(cos, sin, -sin, cos, this.translate.x, this.translate.y);
    t = ctx.getTransform();
    ctx.moveTo(this.ptA.x - this.centroid.ox, this.ptA.y - this.centroid.oy);
    ctx.lineTo(this.ptB.x - this.centroid.ox, this.ptB.y - this.centroid.oy)
    ctx.lineTo(this.ptC.x - this.centroid.ox, this.ptC.y - this.centroid.oy);
    ctx.lineTo(this.ptA.x - this.centroid.ox, this.ptA.y - this.centroid.oy);
    ctx.fill();
    ctx.closePath();
    ctx.restore();
    this.updateVertices(t);
  }
  drawVertices() {
    for (let i=0; i < this.pts.length; i++) {
      ctx.beginPath();
      ctx.fillStyle = "blue";
      ctx.arc(this.pts[i].x, this.pts[i].y, 3, 0, Math.PI * 2);
      ctx.fill();
      ctx.closePath();
    }
  }
  updateVertices(t) {
    //Explanation:
    //t is a variable for getTransform() passed in from draw() method.
    //The 7th and 8th arguments are the original point of where the vertex is drawn for that point. The 9th and 10th arguments are how mush the shap has been translated by.
    this.pts[0] = calcVertices(t.a, t.b, t.c, t.d, t.e, t.f, this.ptA.x - this.centroid.ox, this.ptA.y - this.centroid.oy, this.translate.x, this.translate.y)
    this.pts[1] = calcVertices(t.a, t.b, t.c, t.d, t.e, t.f, this.ptB.x - this.centroid.ox, this.ptB.y - this.centroid.oy, this.translate.x, this.translate.y) 
    this.pts[2] = calcVertices(t.a, t.b, t.c, t.d, t.e, t.f, this.ptC.x - this.centroid.ox, this.ptC.y - this.centroid.oy, this.translate.x, this.translate.y)
  }
}
let triangle = new Triangle({ x: 0, y: 0 }, { x: 50, y: 60 }, { x: 0, y: 100 })

function calcVertices(a, b, c, d, e, f, pX, pY, cx, cy) {
  //pX and pY are the original vertex points
  let x, y;
  x = (e + pX - cx) * a + (f + pY - cy) * c + (e);
  y = (e + pX - cx) * b + (f + pY - cy) * d + (f);
  
  return {x: x, y: y}
}

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  triangle.draw();
  triangle.drawVertices();
  requestAnimationFrame(animate);
}
animate();
<canvas id="canvas"></canvas>