4
votes

I need to retain coordinate information following a rotation and am struggling with the necessary math.

I have an image, with certain crop coordinates. These coordinates are given as the following object:

{
      h:  139.68333435058594,
      w:  139.68333435058594,
      x:  60.31666564941406,
      x2: 200,
      y:  80,
      y2: 219.68333435058594
}

I am then rotating this image (it is a canvas element) but I would like the new coordinates to accurately reflect the rotation, leaving the original crop intact.

e.g. if the top left quarter of a 400x400 image is selected the returned coordinates would be x:0, y:0, x2:200, y2:200. When rotated -90 degrees to the left, the new coordinates should be : x:0, y:200, x2:200, y:400.

How would I write a function to calculate these new coordinates?

Many thanks.

To help visualize this question properly I have included a quick image:

enter image description here

EDIT: The large square in the image above is the photo that I am rotating. It is being rotated around its midpoint and the crop coordinates are relative to the image itself. Upon rotation the actual coordinate plane is reset prior to recalculating the new coordinates meaning that the top left point of the image/container will always be 0,0.

3
Are you rotating the larger square from its center?Shmiddty
The large square (the photo in this case) is being rotated around its mid point. I just need to recalculate the crop area so that it gets rotated as well.gordyr
Or, more generally, what is the pivot point on which you are rotating?Shmiddty
The new coordinates of the "crop area" will be dependent on where the canvas is rotatedShmiddty
Not in this case as for this app you will need to imagine the canvas being destroyed and a new version recreated to match the rotation. To be a little more clear, all crop coordinates are relative to the container and upon rotation all container coordinates are reset, i.e. the top left corner will ALWAYS be 0,0. I hope that makes sensegordyr

3 Answers

3
votes

This function uses the Rotation Matrix algorithm

function rotate(x, y, xm, ym, a) {
    var cos = Math.cos, sin = Math.sin,
    a = a * Math.PI / 180, // Convert to radians 
    // Subtract midpoints, so that midpoint is translated to origin
    // and add it in the end again
    xr = (x - xm) * cos(a) - (y - ym) * sin(a)   + xm,
    yr = (x - xm) * sin(a) + (y - ym) * cos(a)   + ym;

    return [xr, yr];
}

alert(rotate(0, 0, 200, 200, -90));​ // 0,400

JSFiddle

2
votes

The matrix for a 90 degree counterclockwise rotation around the (0,0) point (in your coordinate system) is

  0 1
 -1 0

Which translates in code to:

new_x = y; new_y = -x;

But you want to rotate around (200,200), so you will need to move your points before rotating them, and move them back afterwards.

new_x = (y-200) + 200;
new_y = -(x-200) + 200;

Simplified, this is just

new_x = y; new_y = 400-x;

You should be able to transform all of the crop coordinates like that.

2
votes

Top left corner will be:

0, heightImg - heightCrop

Bottom Right will be:

widthCrop, widthImg

This is assuming the crop is snug with the top left corner before rotation.

I'll work out the general math in a bit.

The formulas to rotate a point (A) around a point (B) by angle (C) are as follows:

N.x = (A.x-B.x) * cos(c) - (A.y-B.y) * sin(c) + B.x
N.y = (A.y-B.y) * cos(c) + (A.x-B.x) * sin(c) + B.y

We can reduce these since we're rotating by 90 degrees. [cos(90) = 0, sin(90)=1]

N.x = 0 - (A.y-B.y) + B.x = B.x + B.y - A.y
N.y = 0 + (A.x-B.x) + B.y = B.y + A.x - B.x

So using this formula with the coordinates of the top-left point will give you the bottom-left point. (The x will be correct, but you'll have to subtract the crop area's height to get the correct y value for the new top-left point)