Libgdx + box2d - Rotating around a point

I am trying to create a circle which rotates around a specific point using box2d. I have managed to do it using RevoluteJointDef and WeldJointDef but it is not working as smoothly as i would want it to work. It uses motor functionality which does not have a fixed rotation speed ( motorTorque messed everything up - i asume ). Is this even possible with box2d?

So you are trying to create a point which an object rotates around, while rotating itself?
Like planet and the sun?

With box2d, are you able to define the rotation and position of your objects manually with efficiency?

I am able to define position of all objects but i am not able to make the outside object ( circle ) to rotate around the point which is in the middle of the big circle.

This image probably explains it better. It doesnt really matter if its a rectangle or a circle which is rotating.

This is an easy trig problem!

Here let me explain how this works.

Let’s let the variable aac (angle around circle) determine a 2d rotation (y axis… spinning the circle) around the middle of the circle. We should shape an equation that utilizes aac.

If you get out a piece of paper and draw your circle, then draw a right triangle like so…

We can let H be our distance from the center of our big circle. Let’s call this by proper terms, radius of the big circle.

We can let angle a be our rotation around the circle. We should set this to aac variable, because thats our angle around circle variable. Like always, a right triangle has a 90 point. Angle b will be of no use to us.

o stands for opposite. This is the opposite side of our triangle. side a stands for adjacent, please note that there are two a’s because angle a and b are alpha and beta. side a is adjacent side.

Since we have all that we need to find another component on this triangle, we can calculate.

Let’s say the raidus of this big circle, h, is 1. We will use the sine function here. You can check which one you need by soh cah toa. Sine deals with opposite and hypotenuse, cosine with adjacent and hypotenuse and tangent with opposite and adjacent.

sin(angle) = o / h
We know the angle is aac and hypotenuse so…
sin(aac) = o / 1
Do a little function rearranging - multiply h over…
sin(aac) * 1 = o
Then there you go, you have your y axis translation from the middle of your circle. Now we need the x axis, which is the adjacent side. To do this, we need cosine.

cos(angle) = a / h
We know the angle is aac and hypotenuse so…
cos(aac) = a / 1
Do a little function rearranging - multiply h over…
cos(aac) * 1 = a
Then there you go, you have your x axis translation from the middle of your circle.

Box.x = cos(aac) * 1
Box.y = sin(aac) * 1

Also, note that aac has to be in RADIANS. So… math.rad(aac). We have aac in degrees.

Then all you need to do is rotate it to look at the center. If you don’t know how to do this, ask and I will continue.

Hydroque’s method is definitely a valid option, but there is also another option using physics, which IMO is a good option since box2d is a physics engine, but either will work. The upside to this is that you aren’t risking messing up the physics simulation by manually editing positions.

So you have this diagram here, a box rotating at a distance r (center to center) from an object with velocity v and has a constant speed.

Now imagine the orbiting box is attached to the center object by a string. In order for that box to keep rotating around the center, the string needs to apply a force to it.
We know [quote]F=ma
[/quote]
However the acceleration here is centripetal acceleration because it is an object rotating at a constant radius and constant speed around an object.
Centripetal acceleration is [quote]mv2/r
[/quote]
so we can plug that in to the original equation [quote]F=m
v2/r
[/quote]
In order to keep the box rotating around the center object, you need to apply a force which is equal to [quote]m*v2/r
[/quote]
on the center of the orbiting object towards the center position. However you also have to make sure it has an initial velocity, otherwise it would just fall in to the center object. That initial velocity is just v and it needs to be tangent to the orbiting circle. For example, if the box starts on top, the velocity needs to be v in the positive or negative x direction.

Now if you want to have the object always facing the center: think of the moon. The same side of the moon always faces the Earth. This is because it takes the moon the same time to orbit around the Earth as it does for the moon to complete one full rotation.
The time it takes (in seconds) for the object to complete one rotation around the center is called the period (which is noted as T). The equation is:[quote]2πr/v
[/quote]
Now we can find the angular velocity so that the object always faces the center. The angular velocity is measured in radians per second. The object needs to rotate one full rotation, in the time it takes to travel once around the orbit. So, since we need to travel 2 PI radians in T seconds, we can find the angular velocity by using the equation: [quote]2π/T
[/quote]
which conveniently ends up being [quote]v/r
[/quote]
So to have the object always face the center, you need to set its angular velocity to be v/r and have its initial rotation be facing the object.

I wrote out the code for this and it is working, so if you decide to take this approach and run in to trouble I can gladly help you out.

Dragon, will this account for rotation?

Not sure exactly what rotation you are referring to, but the object in the center can have a rotation without it affecting the orbiting object.

Sorry, let me clairify. Will this algorithm let OP be able to freely set the rotation of the box orbiting the circle with ease? Or is it dependent on the current rotation of the object?

Are you talking about the position in the orbit? It is dependent on the current rotation, I guess, but it wouldn’t be hard to write some code to have the object rotate to a certain angle in the orbit.

edit: actually, the rotation of the orbiting object would be off, this method would work if sravia wanted to just have the object circle around, but if sravia wanted to set it to a certain angle in the orbit then it wouldn’t work.

So, from what you said, the object orbiting is free rotate, but still follows the path around the circle, for there is nothing in this algorithm that lets OP direct the rotation of the orbiting object.

Massive thank you for the answers but the math isnt really a problem for me. The biggest problem is putting it into the code. I have managed to do it with plain libgdx sprites but i have no idea how i should do this in box2d world.

What I have successfully done with RevoluteJointDef and WeldJointDef does not work at a constant speed.

Could we maybe see a snippet of your code? It would be useful to see what you have, maybe we can build off that. I was looking at the docs and I saw a couple things with RevoluteJointDef. I’m assuming you’ve tried this, but I would set the motorSpeed to whatever speed you want, and then the maxMotorTorque to a large value so that it can accelerate to that motorSpeed quickly.

Here is the code. Custom RevoluteJoint class, and everything else is in my main method.

I have no idea how to control the speed/smoothness of this thing. It is not moving in a constant speed + its way too fast.

UPDATE: I have done it by changing manually inertia of the object that rotates around. But that probably is not the best / good at all way to do this.
Probably bad solution:


 Body spike = CreateCircleBody(world, BodyDef.BodyType.DynamicBody, scale(Constants.WIDTH / 2), scale(Constants.HEIGHT / 2), 5);
MassData massData = new MassData();
massData.I = (float) 1;
spike.setMassData(massData);

All my code:

Body pivot = CreateCircleBody(world, BodyDef.BodyType.StaticBody, scale(Constants.WIDTH / 2), scale(Constants.HEIGHT / 2), 60);
Body spike = CreateCircleBody(world, BodyDef.BodyType.DynamicBody, scale(Constants.WIDTH / 2), scale(Constants.HEIGHT / 2), 5);

RevoluteJoint j = new RevoluteJoint(pivot, spike, false);
j.SetAnchorA(scale(0), scale(0));
j.SetAnchorB(scale(65), scale(0));
j.SetMotor(20, 360);
j.CreateJoint(world);

public Body CreateCircleBody(World world, BodyDef.BodyType bodyType, float posx, float posy,
                                 float radius) {
	BodyDef bodyDef = new BodyDef();
	bodyDef.type = bodyType;
	bodyDef.position.set(posx, posy);
	bodyDef.angle = 0;

	Body body = world.createBody(bodyDef);
	FixtureDef fixtureDef = new FixtureDef();
	fixtureDef.density = 1;
	fixtureDef.restitution = 1;
	fixtureDef.friction = 0;
	fixtureDef.shape = new CircleShape();
	fixtureDef.shape.setRadius(scale(radius));

	body.createFixture(fixtureDef);
	fixtureDef.shape.dispose();
	return body;
}


public class RevoluteJoint {
    RevoluteJointDef revoluteJointDef;

    public RevoluteJoint(Body bodyA, Body bodyB, boolean collideConnected){
        revoluteJointDef = new RevoluteJointDef();
        CreateRevoluteJoint(bodyA,bodyB,collideConnected);
    }

    void CreateRevoluteJoint(Body bodyA,Body bodyB,boolean collideConnected){
        revoluteJointDef.bodyA=bodyA;
        revoluteJointDef.bodyB=bodyB;
        revoluteJointDef.collideConnected=collideConnected;

    }

    public void SetAnchorA(float x,float y){
        revoluteJointDef.localAnchorA.set(x,y);
    }

    public void SetAnchorB(float x,float y){
        revoluteJointDef.localAnchorB.set(x,y);
    }

    public void SetMotor(float torque,float speed){
        revoluteJointDef.enableMotor=true;
        revoluteJointDef.maxMotorTorque=torque;
        revoluteJointDef.motorSpeed=speed*MathUtils.degreesToRadians;
    }

    public Joint CreateJoint(World world){
        return world.createJoint(revoluteJointDef);
    }
}