Reputation: 257
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
But as soon as the rectangle is rotated, everything breaks
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 :)
Upvotes: 2
Views: 676
Reputation: 257
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.
Obviously this needs some refactoring but it's easier to post the comprehensive answer this way.
Upvotes: 1
Reputation: 80187
Make projection of mouse move vector onto rectangle side vectors (they depends on rotation angle) and apply corresponding changes to rectangle side lengths.
One rectangle side has unit direction vector (cos(fi), sin(fi))
, another (neighbor) side - (-sin(fi), cos(fi))
and for mouse shift (mx, my)
applied to vertex between these sides:
delta_width = mx * cos(fi) + my * sin(fi)
delta_height = -mx * sin(fi) + my * cos(fi)
Note that signs depend on which vertex is moved
Upvotes: 0