在鼠标拖动时调整矩形大小的正确算法

Correct algorithm to resize a rectangle on mouse drag

我正在使用 paper.js 制作关卡编辑器。我目前正在纠结如何正确调整矩形大小

目前,我正在做类似的事情:

 rect.onMouseDrag = event => {
    let selectedNode = rect.selectedNode;
      selectedNode.point.x += event.delta.x;
      selectedNode.point.y += event.delta.y;
      switch (rect.selectedNode.index) {
        case 0:
          rect.segments[1].point.x += event.delta.x;
          rect.segments[3].point.y += event.delta.y;
          break;
        case 1:
          rect.segments[0].point.x += event.delta.x;
          rect.segments[2].point.y += event.delta.y;
          break;
        case 2:
          rect.segments[3].point.x += event.delta.x;
          rect.segments[1].point.y += event.delta.y;
          break;
        case 3:
          rect.segments[selectedNode.index - 1].point.x += event.delta.x;
          rect.segments[selectedNode.index - 3].point.y += event.delta.y;
          break;
  };

所以我只是检查相邻的点并相应地移动它们到鼠标事件。 它适用于 AABB

但是一旦矩形旋转,一切都崩溃了

任何人都可以解释或只是 link 我调整矩形大小并保持矩形的正确算法是什么?我认为这个问题已经得到解决,但我找不到任何有用的东西。

谢谢:)

将鼠标移动矢量投影到矩形边矢量上(它们取决于旋转角度)并对矩形边长应用相应的更改。

矩形的一个边具有单位方向矢量 (cos(fi), sin(fi)),另一个(相邻)边 - (-sin(fi), cos(fi)) 并且鼠标移动 (mx, my) 应用于这些边之间的顶点:

delta_width = mx * cos(fi) + my * sin(fi)
delta_height = -mx * sin(fi) + my * cos(fi)

注意符号取决于移动的顶点

好的,我的蜜饯zrugvanoudu35 speedrund 的好朋友解决了这个问题:

     switch (rect.selectedNode.index) {
        case 0:
          rect.segments[1].point.x +=
            event.delta.x * Math.cos(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.sin(rad);
          rect.segments[1].point.y +=
            event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.sin(rad) * Math.sin(rad);
          rect.segments[3].point.x +=
            event.delta.x * Math.sin(rad) * Math.sin(rad) +
            -event.delta.y * Math.sin(rad) * Math.cos(rad);
          rect.segments[3].point.y +=
            -event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.cos(rad);
          break;
        case 1:
          rect.segments[0].point.x +=
            event.delta.x * Math.cos(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.sin(rad);
          rect.segments[0].point.y +=
            event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.sin(rad) * Math.sin(rad);
          rect.segments[2].point.x +=
            event.delta.x * Math.sin(rad) * Math.sin(rad) +
            -event.delta.y * Math.sin(rad) * Math.cos(rad);
          rect.segments[2].point.y +=
            -event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.cos(rad);
          break;
        case 2:
          rect.segments[3].point.x +=
            event.delta.x * Math.cos(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.sin(rad);
          rect.segments[3].point.y +=
            event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.sin(rad) * Math.sin(rad);
          rect.segments[1].point.x +=
            event.delta.x * Math.sin(rad) * Math.sin(rad) +
            -event.delta.y * Math.sin(rad) * Math.cos(rad);
          rect.segments[1].point.y +=
            -event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.cos(rad);
          break;
        case 3:
          rect.segments[2].point.x +=
            event.delta.x * Math.cos(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.sin(rad);
          rect.segments[2].point.y +=
            event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.sin(rad) * Math.sin(rad);
          rect.segments[0].point.x +=
            event.delta.x * Math.sin(rad) * Math.sin(rad) +
            -event.delta.y * Math.sin(rad) * Math.cos(rad);
          rect.segments[0].point.y +=
            -event.delta.x * Math.sin(rad) * Math.cos(rad) +
            event.delta.y * Math.cos(rad) * Math.cos(rad);
          break;
      }

他是个有智慧的人。

显然这需要一些重构,但这样更容易 post 综合答案。