box2d, need help with relaxation

edited July 2015 in Library Questions

I'm working on some code that should be able able to do a relaxation on a bunch of rectangles.

This is the idea / what I have:

A box has prismatic joints connected with a CircleShape:

enter image description here

Those joints have a motor force so the CircleShapes start moving away from the box:

enter image description here

After a while the start touching the side pushing the box away:

enter image description here

Then around this time the box is where I wan't it since the length on the left is equal to the length on the right and the same for top and down. (I say length in this case, but force might be a better description).

enter image description here

Now it goes wrong, the box keeps moving:

enter image description here

It goes to the corner:

enter image description here

And after that It goes back in the opposite direction (and so on back and forth):

enter image description here

What I wonder, why doesn't it wiggle in the center? (caused by equal forces on the opposite side).

(this part of the question is also here but none of the places about box2d seem to be very active). (http://stackoverflow.com/questions/31386566/box2d-relaxation-approach)

To continue:

I made a bare bones example that is slightly simpler then the sketch that produced the images above.

If only horizontal it works fine (with 1 box)

Screen Shot 2015-07-14 at 11.20.00 AM

Screen Shot 2015-07-14 at 11.20.07 AM

But with both horizontal and vertical it goes to this position: Screen Shot 2015-07-14 at 11.20.29 AM

Does someone know why it behaves like this and how I can prevent it? If you change the 2 in: for (int i = 0; i < 2; i++) { // change 2 to 4 to have vertical joints to 4 then you get vertical joints as well.

I really hope someone can help cause this is for a really great project.

package box2dTests;

import org.jbox2d.callbacks.DebugDraw;
import org.jbox2d.collision.shapes.ChainShape;
import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.joints.DistanceJoint;
import org.jbox2d.dynamics.joints.DistanceJointDef;
import org.jbox2d.dynamics.joints.PrismaticJointDef;
import processing.core.PApplet;
import shiffman.box2d.Box2DProcessing;

import java.util.ArrayList;

/**
 * Created by doekewartena on 7/14/15.
 */
public class RelaxBareBones extends PApplet {

    public static void main(String[] args) {
        PApplet.main("box2dTests.RelaxBareBones", args);
    }

    Box2DProcessing box2d;

    Box2dP5DebugDraw debugDraw;

    ArrayList<DistanceJoint> distanceJoints = new ArrayList<>();

    public void settings() {
        size(600, 600);
    }

    public void setup() {

        box2d = new Box2DProcessing(this);
        box2d.createWorld();
        box2d.setGravity(0, 0);

        debugDraw = new Box2dP5DebugDraw();
        debugDraw.box2d = box2d;
        debugDraw.g = g;

        debugDraw.setFlags(
                DebugDraw.e_shapeBit +
                        DebugDraw.e_jointBit
                //DebugDraw.e_aabbBit
                //DebugDraw.e_pairBit +
                //DebugDraw.e_centerOfMassBit +
                //DebugDraw.e_dynamicTreeBit +
                //DebugDraw.e_wireframeDrawingBit

        );
        box2d.world.setDebugDraw(debugDraw);

        createBoundary();

        createTest(width / 3, height / 3);

        // next is 2 of them
        //createTest(width - width / 3, height / 3 + 20);


    }

    void createBoundary() {

        BodyDef bd = new BodyDef();
        Body body = box2d.world.createBody(bd);

        ChainShape chainShape = new ChainShape();

        Vec2[] vec2s = createVec2Arr(
                10, 10,
                width - 10, 10,
                width - 10, height - 10,
                10, height - 10);

        chainShape.createLoop(vec2s, vec2s.length);

        // 0 is default density
        body.createFixture(chainShape, 0);
    }


    void createTest(float x, float y) {

        // first the box

        Body theBox;

        {
            BodyDef bd = new BodyDef();
            bd.setType(BodyType.DYNAMIC);
            bd.setFixedRotation(true);
            bd.setPosition(box2d.coordPixelsToWorld(x, y));

            Body body = box2d.createBody(bd);

            PolygonShape ps = new PolygonShape();
            float box2dW = box2d.scalarPixelsToWorld(100 / 2);
            float box2dH = box2d.scalarPixelsToWorld(50 / 2);
            ps.setAsBox(box2dW, box2dH);

            FixtureDef fd = new FixtureDef();
            fd.setDensity(1);
            fd.setFriction(0);
            fd.setRestitution(0);
            fd.setShape(ps);

            body.createFixture(fd);

            theBox = body;

        }
        // now we want to have 2 distance joints, one
        // on the left and one on the right
        // the should push out to keep the box in the
        // center of the screen
        // to keep them horizontal we create a prismatic joint
        for (int i = 0; i < 2; i++) { // change 2 to 4 to have vertical joints

            int xDir, yDir;

            if (i == 0) {
                xDir = -1;
                yDir = 0;
            }
            else if (i == 1) {
                xDir = 1;
                yDir = 0;
            }
            else if (i == 2) {
                xDir = 0;
                yDir = -1;
            }
            else { // (i == 3)
                xDir = 0;
                yDir = 1;
            }



            // fist we need a shape to connect the joint to
            BodyDef bd = new BodyDef();
            bd.setType(BodyType.DYNAMIC);
            bd.setFixedRotation(true);
            bd.setPosition(box2d.coordPixelsToWorld(x + (100 * xDir), y + (100 * yDir)));

            Body body = box2d.createBody(bd);

            CircleShape cs = new CircleShape();
            cs.setRadius(box2d.scalarPixelsToWorld(10));

            FixtureDef fd = new FixtureDef();
            fd.setDensity(1);
            fd.setFriction(0);
            fd.setRestitution(0);
            fd.setShape(cs);

            body.createFixture(fd);

            // now the prismatic joint for the direction
            PrismaticJointDef pjd = new PrismaticJointDef();
            pjd.bodyA = theBox;
            pjd.bodyB = body;
            pjd.collideConnected = true;
            pjd.localAxisA.set(xDir, -yDir).normalize();

            box2d.createJoint(pjd);

            // a distance joint that we will use to tweak it's length
            DistanceJointDef djd = new DistanceJointDef();
            djd.bodyA = theBox;
            djd.bodyB = body;
            djd.collideConnected = true;

            DistanceJoint dj = (DistanceJoint) box2d.createJoint(djd);
            distanceJoints.add(dj);

        }


    }

    public void draw() {
        background(0);

        colorMode(RGB, 1, 1, 1);
        box2d.world.drawDebugData();

        if (mousePressed) {
            for (DistanceJoint dj : distanceJoints) {
                float l = box2d.scalarWorldToPixels(dj.getLength());
                println(l);
                dj.setLength(box2d.scalarPixelsToWorld(l + 1));

                // why does it not get active?
                dj.getBodyA().setActive(true);
                dj.getBodyB().setActive(true);

                dj.getBodyA().setAwake(true);
                dj.getBodyB().setAwake(true);

            }
            box2d.step();
        }


    }


    public Vec2[] createVec2Arr(float... xy) {

        Vec2[] result = new Vec2[xy.length/2];

        int c = 0;
        for (int i = 0; i < result.length; i++) {
            result[i] = box2d.coordPixelsToWorld(xy[c], xy[c+1]);//new Vec2(xy[c], xy[c+1]);
            c += 2;
        }
        return result;
    }

}

The class to draw can be found in this topic: http://forum.processing.org/two/discussion/11669/box2d-debug-draw-class

Tagged:
Sign In or Register to comment.