旋转内矩形锚定在左上角,考虑大小

Rotate inner rectangles anchoring on top-left considering size

提问人:Victor Lundgren 提问时间:10/29/2023 最后编辑:Victor Lundgren 更新时间:10/29/2023 访问量:35

问:

所以我有一个矩形 R,锚定在它的左上角。在矩形内部,我有内部矩形,每个矩形都有宽度和高度。我有一个算法可以将 R 旋转 alpha 度,并且需要计算每个内部矩形的新左上角位置,但这些矩形没有旋转。

我有这个函数,可以计算内部矩形的新左上角坐标,但它不适用于不同大小的内部矩形。

static rotatePoint(x0, y0, xi, yi, degrees) {
        // Calculate the coordinates of the point relative to the top-left corner of the box
        let x = xi - x0;
        let y = yi - y0;
        
        const rad = degrees * (Math.PI/180);
        const cos_rad = Math.cos(rad);
        const sin_rad = Math.sin(rad);
    
        // Calculate the transformed coordinates after rotation
        let qx = x0 + cos_rad * x + sin_rad * y
        let qy = y0 + -sin_rad * x + cos_rad * y

        return { x: qx, y: qy };
    }

例如,下图显示了一个 0º 的阵型,有 5 个内部矩形,一个是宽度和高度 ~2,四个是宽度和高度 ~1。红点代表原点,它是恒定的。

enter image description here

将编队旋转 90º,我得到以下结果:

enter image description here

请注意,如果 2x2 矩形的大小为 1x1,则该矩形的左上角坐标位于应有的位置。考虑到每个内部矩形的大小,我如何调整该函数以正确计算每个内部矩形的位置?

编辑: 这不是普通的 Javascript,它是针对 foundry vtt 的,但由于问题与 foundrt vtt 本身无关,我觉得这样标记它会使它变得不必要的利基。

内部矩形实际上从原点矩形中心开始,但它也不会改变计算。我正在更改一些铸造厂特定的属性,但这里有一个片段,它给出了与 froundy 相同的输出:

编辑2:我已将该片段替换为视觉片段。

class Rect {
    static rotateUnit(origin, inner, direction) {
        const angle = origin.rotation + ((direction > 0) ? 45 : -45);
        const delta_angle = origin.rotation - angle;
        origin.rotation = angle
        const box_x = origin.x + (origin.width / 2);
        const box_y = origin.y + (origin.height / 2);
        
        for (var i of inner) {
            var new_pos = Rect.rotatePoint(box_x, box_y, 
                                            i.x,
                                            i.y,
                                            delta_angle);
            
            i.x = new_pos.x;
            i.y = new_pos.y;
        }
    }
    
  static rotatePoint(x0, y0, xi, yi, degrees) {
        // Calculate the coordinates of the point relative to the top-left corner of the box
        let x = xi - x0;
        let y = yi - y0;
        
        const rad = degrees * (Math.PI/180);
        const cos_rad = Math.cos(rad);
        const sin_rad = Math.sin(rad);
    
        // Calculate the transformed coordinates after rotation
        let qx = x0 + cos_rad * x + sin_rad * y
        let qy = y0 + -sin_rad * x + cos_rad * y

        return { x: qx, y: qy };
    }
    
    static printCoordinates(origin, inner, offset) {
        const ratio = 5
        var canvas = document.getElementById("canvas");
      if (canvas.getContext) {
          var ctx = canvas.getContext("2d");
          ctx.fillStyle = "rgb(0,0,0)";
          ctx.fillRect(origin.x/ratio+offset/ratio, origin.y/ratio+offset/ratio, 70*origin.width/ratio, 70*origin.height/ratio);
          ctx.fillStyle = "rgb(200,0,0)";
          for (var i of inner) {
            ctx.fillRect(i.x/ratio+offset/ratio, i.y/ratio+offset/ratio, 70*i.width/ratio, 70*i.height/ratio);
          }
     }
    }
}

/* 
* SIZE (WIDTH AND HEIGHT) CORRELATES TO 
* PIXELS BY A CONSTANT OF 1:70
*/
const rect_origin = {
    rotation: 0,
  x: 2302.492125,
  y: 1700.492125,
  width: 0.9842500000000001,
  height: 0.9842500000000001
}
const inner = [
    {
    x: 2336,
    y: 1734,
    width: 1.9685000000000001,
    height: 1.9685000000000001
  },
  {
    x: 2336,
    y: 1872,
    width: 0.9842500000000001,
    height: 0.9842500000000001
  },
  {
    x: 2405,
    y: 1872,
    width: 0.9842500000000001,
    height: 0.9842500000000001
  },
  {
    x: 2336,
    y: 1941,
    width: 0.9842500000000001,
    height: 0.9842500000000001
  },
  {
    x: 2405,
    y: 1941,
    width: 0.9842500000000001,
    height: 0.9842500000000001
  }
]

Rect.printCoordinates(rect_origin, inner, -1500);
Rect.rotateUnit(rect_origin, inner, 1);
Rect.printCoordinates(rect_origin, inner, -1100);
Rect.rotateUnit(rect_origin, inner, 1);
Rect.printCoordinates(rect_origin, inner, -700);
Rect.rotateUnit(rect_origin, inner, 1);
Rect.printCoordinates(rect_origin, inner, -300);
Rect.rotateUnit(rect_origin, inner, 1);
Rect.printCoordinates(rect_origin, inner, 100);
Rect.rotateUnit(rect_origin, inner, 1);
Rect.printCoordinates(rect_origin, inner, 500);
Rect.rotateUnit(rect_origin, inner, 1);
Rect.printCoordinates(rect_origin, inner, 900);
Rect.rotateUnit(rect_origin, inner, 1);
Rect.printCoordinates(rect_origin, inner, 1300);
<canvas id="canvas" width="1000" height="1000"></canvas>

JavaScript 数学 几何

评论

0赞 trincot 10/29/2023
我使用了您的函数,将相关坐标传递给它,并且输出是正确的。请提供我们可以重现该问题的最小代码。
0赞 Mike 'Pomax' Kamermans 10/29/2023
还要注意的是,由于这是一个普通的 JS 问题,您应该能够将其作为可运行的片段展示在您的帖子中,只需少量的画布代码
0赞 Victor Lundgren 10/29/2023
我添加了更多信息和最小的片段来显示我使用真实数据获得的结果。
0赞 Victor Lundgren 10/29/2023
请注意,第一个(大)内部矩形的位置是 ~2269,但它应该是 ~2199 以保持块形成。
0赞 kikon 10/29/2023
和是什么意思,矩形不应该绕着它的左上角旋转吗?如果它绕中心旋转,如果 和 的单位与 和 的单位不同,则公式不行box_xbox_yxywidthheight

答: 暂无答案