Imagine you have two points in 2d space and you need to rotate one of these points by X degrees with the other point acting as a center.
float distX = Math.abs( centerX -point2X );
float distY = Math.abs( centerY -point2Y );
float dist = FloatMath.sqrt( distX*distX + distY*distY );
So far I just got to finding the distance between the two points... any ideas where should I go from that?
The easiest approach is to compose three transformations:
- A translation that brings point 1 to the origin
- Rotation around the origin by the required angle
- A translation that brings point 1 back to its original position
When you work this all out, you end up with the following transformation:
newX = centerX + (point2x-centerX)*Math.cos(x) - (point2y-centerY)*Math.sin(x);
newY = centerY + (point2x-centerX)*Math.sin(x) + (point2y-centerY)*Math.cos(x);
Note that this makes the assumption that the angle x
is negative for clockwise rotation (the so-called standard or right-hand orientation for the coordinate system). If that's not the case, then you would need to reverse the sign on the terms involving sin(x)
.
You need a 2-d rotation matrix http://en.wikipedia.org/wiki/Rotation_matrix
Your new point will be
newX = centerX + ( cosX * (point2X-centerX) + sinX * (point2Y -centerY))
newY = centerY + ( -sinX * (point2X-centerX) + cosX * (point2Y -centerY))
because you are rotating clockwise rather than anticlockwise
Assuming you are usign the Java Graphics2D API, try this code -
Point2D result = new Point2D.Double();
AffineTransform rotation = new AffineTransform();
double angleInRadians = (angle * Math.PI / 180);
rotation.rotate(angleInRadians, pivot.getX(), pivot.getY());
rotation.transform(point, result);
return result;
where pivot is the point you are rotating around.
Here is a way to rotate any point about any other point in 2D. Note that in 3D this can be used as rotation about z axis, z-coordinate of a point being ingored since it doesn't change. Rotation about x-axis and y-axis in 3D can be also easily implemented.
The code is in JavaScript. The commented lines at the beginning are a test set for the function. They also serve as an example of usage.
//A = new Array(0,0)
//S = new Array(-1,0)
//fi = 90
//alert("rotujBod: " + rotatePoint(A, S, fi))
function rotatePoint(A, S, fi) {
/** IN points A - rotated point, S - centre, fi - angle of rotation (rad)
* points in format [Ax, Ay, Az], angle fi (float)
* OUT point B
*/
r = Math.sqrt((A[0] - S[0])*(A[0] - S[0]) + (A[1] - S[1])*(A[1] - S[1]))
originOfRotation = new Array(S[0] + r, S[1])
if (A[1] < S[1]) {
A2 = new Array(A[0], -1*A[1])
originalAngle = -1*sizeOfAngle(originOfRotation, S, A2)
} else {
originalAngle = sizeOfAngle(originOfRotation, S, A)
}
x = S[0] + r*Math.cos(fi + originalAngle)
y = S[1] + r*Math.sin(fi + originalAngle)
B = new Array(x, y)
return(B)
}
function sizeOfAngle(A, S, B) {
ux = A[0] - S[0]
uy = A[1] - S[1]
vx = B[0] - S[0]
vy = B[1] - S[1]
if((Math.sqrt(ux*ux + uy*uy)*Math.sqrt(vx*vx + vy*vy)) == 0) {return 0}
return Math.acos((ux*vx + uy*vy)/(Math.sqrt(ux*ux + uy*uy)*Math.sqrt(vx*vx + vy*vy)))
}
Here a version that cares the rotate direction. Right (clockwise) is negative and left (counter clockwise) is positive. You can send a point or a 2d vector and set its primitives in this method (last line) to avoid memory allocation for performance. You may need to replace vector2 and mathutils to libraries you use or to java's built-in point class and you can use math.toradians() instead of mathutils.
/**
* rotates the point around a center and returns the new point
* @param cx x coordinate of the center
* @param cy y coordinate of the center
* @param angle in degrees (sign determines the direction + is counter-clockwise - is clockwise)
* @param px x coordinate of point to rotate
* @param py y coordinate of point to rotate
* */
public static Vector2 rotate_point(float cx,float cy,float angle,float px,float py){
float absangl=Math.abs(angle);
float s = MathUtils.sin(absangl * MathUtils.degreesToRadians);
float c = MathUtils.cos(absangl * MathUtils.degreesToRadians);
// translate point back to origin:
px -= cx;
py -= cy;
// rotate point
float xnew;
float ynew;
if (angle > 0) {
xnew = px * c - py * s;
ynew = px * s + py * c;
}
else {
xnew = px * c + py * s;
ynew = -px * s + py * c;
}
// translate point back:
px = xnew + cx;
py = ynew + cy;
return new Vector2(px, py);
}
Note that this way has more performance than the way you tried in your post. Because you use sqrt that is very costly and in this way converting from degrees to radians managed with a lookup table, if you wonder. And so it has very high performance.