Skip to main content
GameDev.net gamedev.net
🔒 Locked

2d rotation around an arbitrary point?

Started by sirSolarius Mar 19, 2006 at 6:57 PM 10 replies 24.5k views
Original Post
sirSolarius
sirSolarius
Ok, I'm working in a very limited graphic library and I want to rotate an object around an arbitrary pivot point (its bottom, center, etc.) Right now, the object has its top as its center point, and I have two commands available to me: rotate around this point by d degrees or move in 2d by . Using these two commands, how can I rotate this object around a new center cx, cy? Thanks!
CIJolly
CIJolly
First of all, translate the object so that the middle of the object is 0, 0. Eg, if at the moment the the co-ordinates of the object refer to the top left, then translate the object left half the object's width and up half the object's height.

Now that the object is centred, rotate it by however many degrees you want (using your rotate this point by d degrees function).

Next up is moving it. Take the position of the centre of the object, eg, (100, 10).
Take the arbitrary point you are rotating around (eg, (10, 10).
Subtract the arbitrary from the centre to get the distance from the arbitrary to the centre (in this case, (90, 0).

Rotate the distance vector (90, 0) by the angle you are rotating the object through, using a rotation matrix or trig or however you are doing rotations.

Set the objects position to (Aribtrary_point + Rotated_Distance_Vector).

And you're done.
sonyafterdark
sonyafterdark
http://www.freewebs.com/sonyafterdark/Rotation.html
sirSolarius
sirSolarius
Ok, I'm still confused. Just to clarify, my rotation code will rotate my object in place.

Here's my code. For reference, pivot is the x, y offset from the center of the object, and rotate flips the object IN PLACE, so it does the whole "translation to center, rotate and translate back" stuff for me. Offset thus turns the relative coordinate pivot into an absolute coordinate.

The object is drifting around on the screen.

body.rotate(degrees);				Point2 offset=new Point2(position.x+pivot.x, position.y+pivot.y);		double radians=Math.toRadians(degrees);		double nx=Math.cos(radians)*offset.x-Math.sin(radians)*offset.y;		double ny=Math.sin(radians)*offset.x+Math.cos(radians)*offset.y;						setPosition(new Point3(nx+pivot.x, ny+pivot.y, position.z));
Dave Hunt
Dave Hunt
Quote:
Original post by sirSolarius
Ok, I'm still confused. Just to clarify, my rotation code will rotate my object in place.

Here's my code. For reference, pivot is the x, y offset from the center of the object, and rotate flips the object IN PLACE, so it does the whole "translation to center, rotate and translate back" stuff for me. Offset thus turns the relative coordinate pivot into an absolute coordinate.

The object is drifting around on the screen.

body.rotate(degrees);				Point2 offset=new Point2(position.x+pivot.x, position.y+pivot.y);		double radians=Math.toRadians(degrees);		double nx=Math.cos(radians)*offset.x-Math.sin(radians)*offset.y;		double ny=Math.sin(radians)*offset.x+Math.cos(radians)*offset.y;						setPosition(new Point3(nx+pivot.x, ny+pivot.y, position.z));


Change:
Point2 offset=new Point2(position.x+pivot.x, position.y+pivot.y);

To:
Point2 offset=new Point2(position.x-pivot.x, position.y-pivot.y);

sirSolarius
sirSolarius
Ok, I had to wrestle with the graphics library a lot to remove flickering, and now I'm back to square one and things aren't working like I want them to =(.

I combined rotate and move into a single function called rotate and move, because the object was updating with the rotation and then the movement, causing the flickering.

New code (flies off the screen).

NOTE: body.rotateAndMove is really rotate and set location, it doesn't take an offset but rather a position.

public void rotateAndMove(double degrees, Point2 pivot, Point3 point){				// my distance vector		Point2 offset=new Point2(position.x-pivot.x, position.y-pivot.y);				double radians=Math.toRadians(degrees);				// nx & ny are my rotated distance vector		double nx=Math.cos(radians)*offset.x-Math.sin(radians)*offset.y;		double ny=Math.sin(radians)*offset.x+Math.cos(radians)*offset.y;				double scaleFactor=position.z/point.z;				// set the position to the absolute new "center" plus the distance vector		position.x=pivot.x+position.x+point.x+nx;		position.y=pivot.y+position.y+point.y+ny;		position.z+=point.z;				if(point.z != 0)			body.scale(scaleFactor);						body.rotateAndMove(degrees, position.x, position.y);	}


Aaaargh. Pivot is a relative coordinate, position is absolute. I still can't figure out what's wrong =(
Dave Hunt
Dave Hunt
Ok. You need to translate your position to the origin, then rotate, then translate it back. So, try this:
Point2 center = new Point(position.x + pivot.x,position.y + pivot.y);Point2 origin = new Point(position.x - center.x,position.y - center.y);double nx = origin.x * Math.cos(radians) - origin.y * Math.sin(radians);double ny = origin.x * Math.sin(radians) + origin.y * Math.cos(radians);position.x = nx + center.x;position.y = ny + center.y;

Forget the scaling for now. This should work.

(Sorry about the bumb steer in my previous post. I was distracted.)
sirSolarius
sirSolarius
Sorry to keep this going on and on, but this didn't work so maybe I might be able to clarify some stuff to help.

The user passes in pivot, which is the relative position of a point to rotate around. By default, the program will rotate the object by its current center, which in my object happens to be the top middle.

Because I'm using an external graphics library, I have a function called rotate that will rotate an object IN PLACE. So if the center is at (50, 50) and I call rotate(45), my object will still have its center at (50, 50) and will be rotated 50 degrees.

Using only that and a movement function, how can I translate by an arbitrary point? From the code suggested so far, I have the following non-working code:

double radians=Math.toRadians(degrees);		Point2 center = new Point2(position.x + pivot.x,position.y + pivot.y);		Point2 origin = new Point2(position.x - center.x,position.y - center.y);		double nx = origin.x * Math.cos(radians) - origin.y * Math.sin(radians);		double ny = origin.x * Math.sin(radians) + origin.y * Math.cos(radians);		position.x = nx + center.x;		position.y = ny + center.y;			body.rotateAndMoveTo(degrees, position.x, position.y);


Sorry this is so complicated, but I really want to get this figured out. Thanks for all the help so far!!
CIJolly
CIJolly
Here is the code I use to rotate an object around an aribtrary point, rewritten using your terminology.

Pivot is the arbitrary point you are rotating around.
Position is where the object will appear on the screen.
Vector_from_pivot_to_object is a vector pointing from the Pivot to position.

Point2 vector_from_pivot_to_object = new Point2(position.x - pivot.x, position.y - pivot.y);double nx = vector_from_pivot_to_object.x * Math.cos(radians);double ny = vector_from_pivot_to_object.y * Math.sin(radians);position.x = pivot.x + nx;position.y = pivot.y + ny;body.rotateAndMoveTo(degrees, position.x, position.y);


In the most recent code you posted, the point "centre" has no purpose. There is no point in adding the pivot and the position. Think about it this way: if your pivot is at 10 and the position is 10, then centre.x would be 20.
If pivot is 20 and centre is 20, then pivot would be 40.
In both of these cases the pivot point is the same as the position of the object, so it wouldn't move at all when rotated. Not only would your function move the position of the object, but it would move them different and nonsensical amounts depending on where they are on the screen.

You have to do all your calculations relative to the pivot, then set the objects position to pivot.x+nx and pivot.y+ny.
CIJolly
CIJolly
I just read over the thread again, and I think I see the problem:
Are you trying to rotate the object around a point relative to the object, not an absolute point in space?

In this case, you will perform the calculation, which will translate the object.
Lets say that it translates the object up 1 and left 5.
Because the pivot point is declared relative to the object, and not in absolute terms, then the position of the pivot point will move up one and left 5. This means that the next time the code is run, the angle between the pivot and the object will be exactly the same as they were the first time the function was called, so vector_from_pivot_to_object will be the same, so the function will translate the object up 1 and left 5 again.
The object will move in a straight line off the screen.

It's kind of like making yourself fly by lifting up the collar of your shirt.
sirSolarius
sirSolarius
Quote:
Original post by CIJolly
I just read over the thread again, and I think I see the problem:
Are you trying to rotate the object around a point relative to the object, not an absolute point in space?

In this case, you will perform the calculation, which will translate the object.
Lets say that it translates the object up 1 and left 5.
Because the pivot point is declared relative to the object, and not in absolute terms, then the position of the pivot point will move up one and left 5. This means that the next time the code is run, the angle between the pivot and the object will be exactly the same as they were the first time the function was called, so vector_from_pivot_to_object will be the same, so the function will translate the object up 1 and left 5 again.
The object will move in a straight line off the screen.

It's kind of like making yourself fly by lifting up the collar of your shirt.


AHA! This is exactly what is happening.

This is for user-controlled animation. My concern with absolute points was that a user would specify a rotation point (say, the bottom of the object) and then would later move this object around. The Animation class has no idea this is happening, so just calls rotate(degrees, pivot) on the object using absolute coordinates and now the rotation is really screwy.

Any ideas on how to fix this?

Edit: now that I'm in absolute coordinates, everything is working perfectly btw. You rock!! But I'm still troubled by how to let the user specify an absolute coordinate.
CIJolly
CIJolly
If I'm understanding what you're saying, then you should be able to solve it by moving the pivot point relative to the object.

So, you specify the pivot point relative to the object.
You then call your rotate and move function.
Whatever this does to the position of the object, have it do the opposite to the relative pivot point.
So, your object is at (10, 0) and your pivot point is at (0, 0) in absolute terms, and (-10, 0) relative to the object. Your pivot point has been defined in relative terms, not absolute terms, so wherever the object is on the screen the pivot will be 10 to the left of it.
You call your rotate and move function, and the object is moved (0, 1).
The object is now at (10, 1) and the pivtot point is at (0, 1) absolute and (-10, 0) relative.
Change the relative positiong of the pivot by the opposite that you just moved the object. The pivot point is now at (0, 0) absolute (which is what you want, to avoid the object moving in a straight line off the screen) and (-10, -1) relative to the object.

In other words, whenever you want to rotate the object around the pivot, change the pivots relative position so that it stays in the same place in absolute terms.
If you are just moving the object linearly around the screen, then don't change the relative position of the pivot.

I haven't tested this, but it seems like it should work.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.