Search code examples
canvasgeometrypaperjs

Correct algorithm to resize a rectangle on mouse drag


I am using paper.js to make a level editor. I am currently bugging on how to resize a rectangle properly

Currently, I am doing something like :

 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;
  };

So I just check the adjacent points and move them accordingly to the mouse event. It works fine for AABB's

enter image description here

But as soon as the rectangle is rotated, everything breaks enter image description here

Can anyone explain or just link me what's the correct algorithm to resize a rectangle and keep it rectangle ? I think this question has already been adressed but I can't find anything useful.

Thanks :)


Solution

  • OK, my good friend of the compote zrugvanoudu35 speedrunned this problem:

         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;
          }
    

    He's a man of wise.

    2D rectangle resizing algorithm

    Obviously this needs some refactoring but it's easier to post the comprehensive answer this way.