【问题标题】:How do I get the bottom-right X & Y of a rotated triangle如何获得旋转三角形的右下角 X 和 Y
【发布时间】:2021-08-06 08:24:27
【问题描述】:

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

三角形的原点是 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 位置(三角形的右下角)。

我必须处理的信息是:

  • θ = 任意角度(在本例中为 90°)
  • 原点 = [0,0]
  • A 点 = 计算如上。在这种情况下 [0,50]
  • 高度 = 100
  • 宽度 = 50

如何在考虑旋转角度的情况下找到 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; 

但这又回来了

*注意忽略倒角

【问题讨论】:

  • 您在各个地方使用 Origin 的符号令人困惑。我敢打赌这就是为什么你在处理点 A 时遇到问题的原因,尽管旋转方程对 B 也有效。

标签: javascript math geometry physics trigonometry


【解决方案1】:

如果您要使用画布,我建议您使用getTransform(),它会返回可用于更新顶点的变换矩阵。这是一个显示三角形旋转时更新顶点的 sn-p。

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

要移动三角形,请使用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();
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

【讨论】:

    【解决方案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

    【讨论】:

    • 谢谢,这让我接近了我所追求的,但它似乎画错了地方。 (见更新的帖子)。这是相对于原点还是 A 点?
    • 你可以在minlopalis.github.io/rotating-arrow查看实际的实现,如果你有兴趣,代码在github.com/minlopalis/rotating-arrow.git我正在构建另一个项目,所以代码有点乱,我打算稍后重构。
    • 我很怀疑,因为您在某种意义上使用了origin。这个答案指的是图片,其中坐标零在三角形的中心,三角形围绕它旋转。 H. Rittich 已经给出了关于任意点旋转的扩展公式。
    • 谢谢你的代码真的很好,我的解决方案基本上使用了你的代码,除了宽度和高度以及加减法被切换了。非常感谢您对此提供的帮助。
    • width and the height were switched - 也许你有一个奇怪的坐标系,OX 轴向上
    【解决方案3】:

    任意点p绕点c旋转的公式为

    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
    

    【讨论】:

    • 感谢您的回复,您使用p时是指B点的位置吗? c 是指原点吗?还是我偏离了轨道?由于我缺乏数学经验,我在将您的惊人回复翻译成我的代码时遇到了一些麻烦。
    • 另外,我可能是错的,但 qᵧ = sin(θ) * (pₓ - cₓ) + sin(θ) * (pᵧ - cᵧ) + cᵧ 实际上应该是 qᵧ = sin(θ) * (pₓ - cₓ) + cos(θ) * (pᵧ - cᵧ) + cᵧ 吗?
    • @minlopalis 确实如此。公式中有错误。是的,p 是您要变换的点的位置,c 是原点。
    • 谢谢,这真的帮助我找到了我的解决方案。感谢您为此付出的努力。
    【解决方案4】:

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

    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
    

    【讨论】:

      【解决方案5】:

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

      Q = P e^(iΘ)
      

      这描述了围绕原点的旋转角度Θ,它将P 应用于Q。现在,由你来寻找AB的坐标,扮演P的角色。


      附录:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-12
        • 1970-01-01
        • 2013-03-24
        • 2023-01-08
        • 1970-01-01
        • 2021-10-30
        • 1970-01-01
        • 2016-01-27
        相关资源
        最近更新 更多