Rotate a Point by Another Point in 2D

Rotating a point about another point (2D)

First subtract the pivot point (cx,cy), then rotate it (counter clock-wise), then add the point again.

Untested:

POINT rotate_point(float cx,float cy,float angle,POINT p)
{
float s = sin(angle);
float c = cos(angle);

// translate point back to origin:
p.x -= cx;
p.y -= cy;

// rotate point
float xnew = p.x * c - p.y * s;
float ynew = p.x * s + p.y * c;

// translate point back:
p.x = xnew + cx;
p.y = ynew + cy;
return p;
}

Rotate a point by another point in 2D

If you rotate point (px, py) around point (ox, oy) by angle theta you'll get:


p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox
p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy

Rotating a set of 2D points about another point

To have airfoil = np.column_stack((qx, qy)) inside the loop is not a good idea since it modifies the airfoil array at every iteration. Actually, by doing numpy.column_stack you make airfoil have shape (1,2) after the first iteration overriding the original airfoil which has shape (18,2) (hence on the second iteration it gives you the shape error).

You would be better by storing the rotated points on another variable. And even better, perform the rotation all at once with a simple A v = w, where A is your rotation matrix, v your airfoil coordinates and w the rotated coordinates.

Here is what you could do using the rotation matrix A

theta = 1.5708  # 90 degree
ox, oy = 2000, 2000 # point to rotate about
A = np.matrix([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]])

w = np.zeros(airfoil.shape)
airfoil_shifted = airfoil-np.array([ox,oy])
for i,v in enumerate(airfoil_shifted):
w[i] = A @ v

where w will contain the rotated coordinates.

How to rotate point around another one?

Understanding rotation.

Start with 2D.

A 2D coordinate defines a position via 2 values, x and y. The x is the distance along the x axis and the y is the distance along the y axis. By convention computer graphics generally have the x axis defined from left to right and y from top to bottom.

Note code in this answer is pseudo code and does not represent any particular language.

Axis

We can represent an axis as a vector, for example the x axis is 1 unit in the x direction and 0 units down, and the y axis is 0 units along the x direction and 1 unit down.

For code we define a vector as (eg x axis xAxis.x = 1, xAxis.y = 0)

Axis have an important quality that they are always 1 unit long. See below Unit vector

So with the axis defined and a point we can find its position by moving first along the x axis then along the y axis.

xAxis = { x : 1, y : 0 }; // define the x axis
yAxis = { x : 0, y : 1 }; // define the y axis
point = { x : 10, y : 10 };

// position the point first move along the x axis by distance x
pos.x = point.x * xAxis.x;
pos.y = point.x * xAxis.y;

// then move along the y axis by distance y
pos.x = pos.x + point.y * yAxis.x;
pos.y = pos.y + point.y * yAxis.y;

Rotation

This seems like the long way to position a point. But when you rotate a coordinate systems you are in effect rotating the x and y axis. So to get the coordinates in a rotated coordinate system you need the 2 rotated axis. See below Unit vector from angle

The x axis is rotated by the amount of rotation, and the y axis is at 90 deg to the x axis.

rotation = PI / 4; // using radians rotate clockwise 45 deg
// get the x axis at 45 deg
xAxis.x = cos(rotation);
xAxis.y = sin(rotation);

// get the y axis at 90 deg (PI / 2) from the x axis
yAxis.x = cos(rotation + (PI / 2));
yAxis.y = sin(rotation + (PI / 2));

We can now move the point in the rotated coordinate system

point = { x : 10, y : 10 };

// position the point first move along the x axis by distance x
pos.x = point.x * xAxis.x;
pos.y = point.x * xAxis.y;

// then move along the y axis by distance y
pos.x = pos.x + point.y * yAxis.x;
pos.y = pos.y + point.y * yAxis.y;

There are some short cuts. The y axis is at 90 deg to the x axis (unless skewed) to rotate a vector 90deg we swap the components negating the y

// get the x axis at 45 deg
xAxis.x = cos(rotation);
xAxis.y = sin(rotation);

// get y at 90 deg from x
yAxis.x = -xAxis.y;
yAxis.y = xAxis.x;

Also moving along the axis, each component is independent of the other so the calculation can be done one line.

pos.x = point.x * xAxis.x + point.y * yAxis.x;
pos.y = point.x * xAxis.y + point.y * yAxis.y;

The origin.

Coordinate systems are defined by an origin as well as the unit vectors describing the axis. To rotate a point around a specific point we need to make the point of rotation the origin. We then move the coordinate to rotate relative to the new origin

point = { x : 10, y : 10 };
origin = { x : 5 , y : 4 };

// move point relative to the origin

pos.x = point.x - origin.x;
pos.y = point.y - origin.y;

Now we can apply the rotation

rotatedPos.x = pos.x * xAxis.x + pos.y * yAxis.x;
rotatedPos.y = pos.x * xAxis.y + pos.y * yAxis.y;

But the rotated point is still relative to the origin, we need to move it back relative to the origin.

rotatedPos.x = rotatedPos.x + origin.x;
rotatedPos.y = rotatedPos.y + origin.y;

In computer graphics we generally keep related coordinates relative to its own local origin. It has a coordinate system that we call the local coordinates, with [0,0] or in 3d [0,0,0] as the point of rotation. This means we can skip the part of the calculation that moves the point relative to the rotation point.

We can then do the rotation and positioning in one line for each axis

pos.x = point.x * xAxis.x + point.y * yAxis.x + origin.x;
pos.y = point.x * xAxis.y + point.y * yAxis.y + origin.y;

Scale

It is also very common that we want to scale a coordinate, this can be done by changing the length of the unit vector representing each axis. For example if we want to scale the coordinate 2 times along the x axis we make the x axis 2 times as long

point = {x : 5, y : 6}; // point in local coordinates.
xAxis = {x : 1, y : 0}; // normalised x axis
xAxis.x = xAxis.x * 2; // scale x axis
xAxis.y = xAxis.y * 2;

// apply transformation.
pos.x = point.x * xAxis.x + point.y * yAxis.x + origin.x;
pos.y = point.x * xAxis.y + point.y * yAxis.y + origin.y;

3D

For 3D everything is much the same but with one additional axis and component

xAxis = {x : 1, y : 0, z : 0}; // direction and scale of x axis
yAxis = {x : 0, y : 1, z : 0}; // direction and scale of y axis
zAxis = {x : 0, y : 0, z : 1}; // direction and scale of z axis
origin = {x : 0, y : 0, z : 0}; // position of origin.

So to move point into the 3D coordinates system described above

point = {x : 5, y : 6, z : 4}; // point in local coordinates.
// move point.x distances along x axis
pos.x = point.x * xAxis.x
pos.y = point.x * xAxis.y
pos.z = point.x * xAxis.z

// move point.y distances along y axis
pos.x += point.y * yAxis.x
pos.y += point.y * yAxis.y
pos.z += point.y * yAxis.z

// move point.y distances along y axis
pos.x += point.z * zAxis.x
pos.y += point.z * zAxis.y
pos.z += point.z * zAxis.z

// then relative to the origin
pos.x += origin.x
pos.y += origin.y
pos.z += origin.z

Or more compact

pos.x = point.x * xAxis.x + point.y * yAxis.x + point.z * zAxis.x + origin.x
pos.y = point.x * xAxis.y + point.y * yAxis.y + point.z * zAxis.y + origin.y
pos.z = point.x * xAxis.z + point.y * yAxis.z + point.z * zAxis.z + origin.z

###The matrix

The above starts to become a little unwieldy so to simplify it we can convert the above objects point, xAxis, yAxis, zAxis, origin into a set of arrays (called matrices)

point = [5,6,4]; // vector as array  [x,y,z]
origin = [0,0,0]; // origin as array [x,y,z]
rotation = [1,0,0,0,1,0,0,0,1]; // 3 axis [x.x,x.y,x.z, y.x,y.y,y.z, z.x,z.y,z.z]

// rotation /*
[x.x,x.y,x.z, // x axis
y.x,y.y,y.z, // y axis
z.x,z.y,z.z] // z axis
*/

The notation can be simplified and in many languages overloading will allow you to do the math directly in shorthand form.

 pos = point * rotation + origin;    

3D rotation

In 2D we generally only rotate around a single imaginary axis ( the z axis in and out of the screen) in 3D we rotate around one of 3 axis, the x, y or z axis.

The order we rotate in also affect the final rotated location. Rotate 5 degree around z then 10 deg around y is different than 10 deg around y then 5 around z.

As each axis is itself a vector that can be rotated, we can rotate each axis by a rotation matrix. The result is a matrix that has many rotations all combined.

So say we want to rotate about the z axis 10 deg we create the 3 rotated axis

ang = 10; // in deg
xAxisA = [cos(ang) ,sin(ang),0]; // 1 unit long
yAxisA = [-sin(ang),cos(ang),0]; // 1 unit long
zAxisA = [0 ,0 ,1]; // 1 unit long

Or as a rotation matrix

A = rotationZ = [cos(ang), sin(ang), 0, -sin(ang), cos(ang), 0, 0, 0, 1];

And we want to then rotate about the y

xAxisB = [cos(ang) ,0 , sin(ang)];  // 1 unit long
yAxisB = [0, 1 , 0 ]; // 1 unit long
zAxisB = [-sin(ang),0, cos(ang)]; // 1 unit long

Or as a rotation matrix

B = rotationY = [cos(ang), 0, sin(ang), 0, 1, 0, -sin(ang), 0, cos(ang)];

We can then rotate each axis in the z rotation by the y rotation.

// rotate each rotation axis by the second rotation axis.
xAxisAB.x = xAxisA.x * xAxisB.x + xAxisA.y * yAxisB.x + xAxisA.z * zAxisB.x;
xAxisAB.y = xAxisA.x * xAxisB.y + xAxisA.y * yAxisB.y + xAxisA.z * zAxisB.y;
xAxisAB.z = xAxisA.x * xAxisB.z + xAxisA.y * yAxisB.z + xAxisA.z * zAxisB.z;
yAxisAB.x = yAxisA.x * xAxisB.x + yAxisA.y * yAxisB.x + yAxisA.z * zAxisB.x;
yAxisAB.y = yAxisA.x * xAxisB.y + yAxisA.y * yAxisB.y + yAxisA.z * zAxisB.y;
yAxisAB.z = yAxisA.x * xAxisB.z + yAxisA.y * yAxisB.z + yAxisA.z * zAxisB.z;
zAxisAB.x = zAxisA.x * xAxisB.x + zAxisA.y * yAxisB.x + zAxisA.z * zAxisB.x;
zAxisAB.y = zAxisA.x * xAxisB.y + zAxisA.y * yAxisB.y + zAxisA.z * zAxisB.y;
zAxisAB.z = zAxisA.x * xAxisB.z + zAxisA.y * yAxisB.z + zAxisA.z * zAxisB.z;

Or short hand

rotationAB = rotationZ * rotationY;

or

AB = A * B;

The resulting matrix AB is the combined rotation of the z rotation and then the y rotation. You can keep going, rotate around the x

// rotate about the x Axis
xAxisC = [1, 0 , 0 ]; // 1 unit long
yAxisC = [0, cos(ang) , sin(ang)]; // 1 unit long
zAxisC = [0, -sin(ang), cos(ang)]; // 1 unit long

C = rotationX =[1, 0, 0, 0, cos(ang), sin(ang), 0, -sin(ang), cos(ang)];

The final rotation is

ABC = A * B * C

But remember that the order is important.

A * B * C != C * B * A; // order of multiplication is important.


Using matrix, vector libraries.

The above is a what would be covered in a first year uni computer science course over a few weeks, but it would assume you have a good understanding of vector maths. Writing the code can become very repetitive and due to the nature of the problem, very hard to read and spot mistakes in.

I always believe that the best way to learn is to write your own library, but in this case a library is a good starting points as there is a lot more depth to this subject than just rotation, scale and translation.

There are hundreds of matrix/vector maths libraries out there, a good starting point would be github



Maths notation

In mathematics the axis are called î (pronounced i hat) for the x axis and ĵ (j hat) for the y axis. Each axis is defined by a unit vector, î = [1,0] and ĵ = [0,1] (for 3D we use three 3D vectors î = [1,0,0], ĵ = [0,1,0] and k hat = [0,0,1] sorry I could not find k hat in the character set)



Vector basics.

A vector

A vector is a set of numbers that represent a direction and distance. In math a vector is a matrix. Eg v = [1,0] in code as a structure/object/class v = { x : 1, y : 0} A vector can also be described as a distance and direction, eg 10 kilometers South East. It is easy to convert from one type to the other (see below)

Unit vector.

A unit vector is a vector that is 1 unit long. (1,0) is a unit vector its length is 1 unit long. You can multiply the unit vector to find a point n units for the origin.

n = 5;
axis = { x : 1, y : 0 };
point.x = axis.x * n; // 5 * 1 = 5
point.y = axis.y * n; // 5 * 0 = 0

Vector length

You can use pythagoras to get the length of a vector. For example the vector {x : 3, y : 4} has a length equal to sqrt( 3 * 3 + 4 * 4 ) = sqrt( 9 + 16 ) = sqrt( 25 ) = 5 five units long and clearly not a unit vector

Normalised vector (Normalized US spelling)

The process of normalising a vector converts a vector to a unit vector. It is done by dividing the vector's components by the vector length.

vec = { x : 3, y : 4 };
length = sqrt( vec.x * vec.x + vec.y * vec.y ); // length = 5
// nVec is the normalised vector vec
nVec.x = vec.x / length; // 3/5 = 0.6;
nVec.y = vec.y / length; // 4/5 = 0.8;

Unit vector from angle

To create a unit vector at a specific direction we use a little trig

 angle = 90; // in deg (normally this is radians)
v90.x = cos(angle);
v90.y = sin(angle);

Rotate a point around another point

The problem is int center = radius which you are setting int radius = 576. This doesn't make sense as surely you are rotating about a point that should have an x and y location.

Given you are rotating around the origin the center x and y should both be 0 not 576.

So, given that, try this.

/// <summary>
/// Rotates one point around another
/// </summary>
/// <param name="pointToRotate">The point to rotate.</param>
/// <param name="centerPoint">The center point of rotation.</param>
/// <param name="angleInDegrees">The rotation angle in degrees.</param>
/// <returns>Rotated point</returns>
static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
return new Point
{
X =
(int)
(cosTheta * (pointToRotate.X - centerPoint.X) -
sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),
Y =
(int)
(sinTheta * (pointToRotate.X - centerPoint.X) +
cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)
};
}

Use like so.

Point center = new Point(0, 0); 
Point newPoint = RotatePoint(blueA, center, 45);

Obviously if the center point is always 0,0 then you can simplify the function accordingly, or else make the center point optional via a default parameter, or by overloading the method. You would also probably want to encapsulate some of the reusable math into other static methods too.

e.g.

/// <summary>
/// Converts an angle in decimal degress to radians.
/// </summary>
/// <param name="angleInDegrees">The angle in degrees to convert.</param>
/// <returns>Angle in radians</returns>
static double DegreesToRadians(double angleInDegrees)
{
return angleInDegrees * (Math.PI / 180);
}

/// <summary>
/// Rotates a point around the origin
/// </summary>
/// <param name="pointToRotate">The point to rotate.</param>
/// <param name="angleInDegrees">The rotation angle in degrees.</param>
/// <returns>Rotated point</returns>
static Point RotatePoint(Point pointToRotate, double angleInDegrees)
{
return RotatePoint(pointToRotate, new Point(0, 0), angleInDegrees);
}

Use like so.

Point newPoint = RotatePoint(blueA, 45);

Finally, if you are using the GDI you can also simply do a RotateTransform.
See: http://msdn.microsoft.com/en-us/library/a0z3f662.aspx

Graphics g = this.CreateGraphics();
g.TranslateTransform(blueA);
g.RotateTransform(45);

Rotate object a object in 2D space

You can add a Rotate to the list of transforms for the object you are rotating:

double x = /* x-coordinate for center of rotation */ ;
double y = /* y-coordinate for center of rotation */ ;
double angle = /* angle in degrees */ ;

Rotate rotate = new Rotate(angle, x, y);
nodeToRotate.getTransforms().add(rotate);

The coordinates for the center of the rotation must be in the same coordinate system as used by the node you are rotating.

How to calculate rotation in 2D in Javascript

function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * angle,
cos = Math.cos(radians),
sin = Math.sin(radians),
nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
return [nx, ny];
}

The first two parameters are the X and Y coordinates of the central point (the origin around which the second point will be rotated). The next two parameters are the coordinates of the point that we'll be rotating. The last parameter is the angle, in degrees.

As an example, we'll take the point (2, 1) and rotate it around the point (1, 1) by 90 degrees clockwise.

rotate(1, 1, 2, 1, 90);
// > [1, 0]

Three notes about this function:

  1. For clockwise rotation, the last parameter angle should be positive. For counterclockwise rotation (like in the diagram you provided), it should be negative.

  2. Note that even if you provide arguments that should yield a point whose coordinates are whole numbers -- i.e. rotating the point (5, 0) by 90 degrees about the origin (0, 0), which should yield (0, -5) -- JavaScript's rounding behavior means that either coordinate could still be a value that's frustratingly close to the expected whole number, but is still a float. For example:

    rotate(0, 0, 5, 0, 90);
    // > [3.061616997868383e-16, -5]

    For this reason, both elements of the resulting array should be expected as a float. You can convert them to integers using Math.round(), Math.ceil(), or Math.floor() as needed.

  3. Finally, note that this function assumes a Cartesian coordinate system, meaning that values on the Y axis become higher as you go "up" in the coordinate plane. In HTML / CSS, the Y axis is inverted -- values on the Y axis become higher as you move down the page.

Swift: make rotation of point in 2D

You are really describing two rotations with your example:

  1. The points are rotated by -90 degrees around the center of the 3x3 grid. When this happens, the topLeft point becomes bottomLeft, and topRight becomes topLeft.
  2. Then you rotate those points around the center of the square 90 degrees (ie. the other direction) to make them topLeft and topRight again.

Using this function from this answer:

func rotatePoint(target: CGPoint, aroundOrigin origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
let dx = target.x - origin.x
let dy = target.y - origin.y
let radius = sqrt(dx * dx + dy * dy)
let azimuth = atan2(dy, dx) // in radians
let newAzimuth = azimuth + byDegrees * .pi / 180 // convert it to radians
let x = origin.x + radius * cos(newAzimuth)
let y = origin.y + radius * sin(newAzimuth)
return CGPoint(x: x, y: y)
}

let topLeft = CGPoint(x: 2, y: 1)
let topRight = CGPoint(x: 3, y: 1)
let squareCenter = CGPoint(x: 2.5, y: 1.5)

// First rotate around the center of the 3 x 3 square
let centerOfRotation = CGPoint(x: 1.5, y: 1.5)

let tl1 = rotatePoint(target: topLeft, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1 y 1)
let tr1 = rotatePoint(target: topRight, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1 y 0)
let sc1 = rotatePoint(target: squareCenter, aroundOrigin: centerOfRotation, byDegrees: -90) // (x 1.5 y 0.5)

// Now rotate the 1x1 square the other way around new position of square center
let tl2 = rotatePoint(target: tl1, aroundOrigin: sc1, byDegrees: 90) // (x 1 y 0)
let tr2 = rotatePoint(target: tr1, aroundOrigin: sc1, byDegrees: 90) // (x 2 y 0)

Note: As @MBo noted in the comments, if your cell is always 1x1, it is sufficient to rotate the center of your cell and then just add and subtract the 0.5 offsets to find the four corners.



Related Topics



Leave a reply



Submit