box2d debug draw class

edited September 2015 in Share Your Work

I made a simple class to draw the box2d world. It's kind of a work in progress but this is all I needed so far. If you update it then please be so friendly to post it here.

  
    package box2dTests;
    
    import org.jbox2d.callbacks.DebugDraw;
    import org.jbox2d.common.Color3f;
    import org.jbox2d.common.Transform;
    import org.jbox2d.common.Vec2;
    import org.jbox2d.particle.ParticleColor;
    import processing.core.PConstants;
    import processing.core.PGraphics;
    import shiffman.box2d.Box2DProcessing;
    
    /**
     * Created by doekewartena on 6/30/15.
     */
    public class Box2dP5DebugDraw extends DebugDraw {
    
        Box2DProcessing box2d;
        PGraphics g;
    
        @ Override
        public void drawPoint(Vec2 argPoint, float argRadiusOnScreen, Color3f argColor) {
            System.out.println("drawPoint");
        }
    
        @ Override
        public void drawSolidPolygon(Vec2[] vertices, int vertexCount, Color3f color) {
    
            g.noStroke();
            g.fill(color.x, color.y, color.z);
    
            g.beginShape();
            for (int i = 0; i < vertexCount; i++) {
                Vec2 pixelVec = box2d.coordWorldToPixels(vertices[i]);
                g.vertex(pixelVec.x, pixelVec.y);
            }
            g.endShape();
    
        }
    
        @ Override
        public void drawCircle(Vec2 center, float radius, Color3f color) {
    
            center = box2d.coordWorldToPixels(center);
            radius = box2d.scalarWorldToPixels(radius);
    
            g.ellipseMode(PConstants.CENTER);
            g.stroke(color.x, color.y, color.z);
            g.noFill();
            g.ellipse(center.x, center.y, radius * 2, radius * 2);
        }
    
        @ Override
        public void drawSolidCircle(Vec2 center, float radius, Vec2 axis, Color3f color) {
    
            center = box2d.coordWorldToPixels(center);
            radius = box2d.scalarWorldToPixels(radius);
    
            g.ellipseMode(PConstants.CENTER);
            g.fill(color.x, color.y, color.z);
            g.noStroke();
            g.ellipse(center.x, center.y, radius * 2, radius * 2);
        }
    
        @ Override
        public void drawSegment(Vec2 p1, Vec2 p2, Color3f color) {
    
    //        System.out.println();
    //        System.out.println("drawSegment");
    //        System.out.println(p1.x+" "+p1.y);
    //        System.out.println(p2.x+" "+p2.y);
    //        System.out.println(color.x+" "+color.y+" "+color.z);
    //        System.out.println();
    
            Vec2 v1 = box2d.coordWorldToPixels(p1);
            Vec2 v2 = box2d.coordWorldToPixels(p2);
            g.stroke(color.x, color.y, color.z);
            g.line(v1.x, v1.y, v2.x, v2.y);
    
        }
         
        // thanks to xnastudio   
        @ Override 
        public void drawTransform(Transform xf) {
            float k_axisScale = 0.4f;
            Vec2 p1 =xf.p;
            Vec2 p2 = new Vec2();
            p2.setZero();
            p2.x =p1.x + k_axisScale*xf.q.c;
            p2.y =p1.y + k_axisScale*xf.q.s;
            Vec2 v1 = box2d.coordWorldToPixels(p1);
            Vec2 v2 = box2d.coordWorldToPixels(p2);
            g.stroke(1, 0, 0);
            g.line(v1.x, v1.y, v2.x, v2.y);
             
            g.stroke(0, 1, 0);
            p2.x = xf.p.x + -k_axisScale*xf.q.s;
            p2.y = xf.p.y + k_axisScale*xf.q.c;
            v2 = box2d.coordWorldToPixels(p2);
            g.line(v1.x, v1.y, v2.x, v2.y);
        }
      
        // thanks to xnastudio 
        @ Override
        public void drawString(float x, float y, String s, Color3f color_) {
            Vec2 v1 = box2d.coordWorldToPixels(x, y);
            g.fill(color_.x, color_.y, color_.z);
            g.text(s, v1.x, v1.y);
        }
    
        @ Override
        public void drawParticles(Vec2[] centers, float radius, ParticleColor[] colors, int count) {
            System.out.println("drawParticles");
        }
    
        @ Override
        public void drawParticlesWireframe(Vec2[] centers, float radius, ParticleColor[] colors, int count) {
            System.out.println("drawParticlesWireframe");
        }
    }

Usage:

  

            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);

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

Comments

  • Either add a space between the @ & Override or replace all @ w/ &#64;: @Override. :-B

  • edited July 2015

    thanks!, space it is...

  • edited August 2015

    Thank you very much.clankill3r . Every thing is fine except that I want to enable "DebugDraw.e_dynamicTreeBit".But got a nullpointer exception ??? If I comment out the dynamicTreeBit, every thing is find.

  • If you post code to reproduce I will check it out.

  • edited August 2015

    I have changed Shiffman's example code a little to show that there is problem with the ""DebugDraw.e_dynamicTreeBit"" . You can download the zip code from the below google share.

  • You can try this code , I just make some little change from Shiffman's example code. Just comment out the display method and add your debugdraw class.

    https://drive.google.com/open?id=0B78LVqW-tfEfVTVGYUlmWmJPUk0

  • and one more request, I can't see the "DebugDraw.e_centerOfMassBit" , maybe it is the problem of "color"

  • I'm on my windows without a good IDE so I can't check proper now. I think the problem with DebugDraw.e_dynamicTreeBit is a bug in jbox2d.

    For DebugDraw.e_centerOfMassBit, I didn't do all methods since I only did the ones I needed. If correct you will have printlines in your console with "drawTransform" for example.

    One reason I didn't do drawTransform for example is cause I never had the case so I was not sure how to do it.

        public void drawTransform(Transform transform) {
        System.out.println("drawTransform");
        // we can push a matrix but when do we need to pop?
        // we would need to count the pushes
        // Vec2 p = box2d.coordWorldToPixels(transform.p);
        // System.out.println("p.x: "+p.x+"  p.y: "+p.y);
    
      }
    

    I will come back to you probably tomorrow.

  • edited August 2015

    After I checked the JBox2D github, I found this.

    https://github.com/jbox2d/jbox2d/blob/master/jbox2d-testbed/src/main/java/org/jbox2d/testbed/framework/j2d/DebugDrawJ2D.java

    And I just copy the code for drawTransform() .

    @ Override public void drawTransform(Transform xf) {

    float k_axisScale = 0.4f;
    Vec2 p1 =xf.p;
    Vec2 p2 = new Vec2();
    p2.setZero();
    p2.x =p1.x + k_axisScale*xf.q.c;
    p2.y =p1.y + k_axisScale*xf.q.s;
    Vec2 v1 = box2d.coordWorldToPixels(p1);
    Vec2 v2 = box2d.coordWorldToPixels(p2);
    g.stroke(1, 0, 0);
    g.line((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y);
    
    g.stroke(0, 1, 0);
    p2.x = xf.p.x + -k_axisScale*xf.q.s;
    p2.y = xf.p.y + k_axisScale*xf.q.c;
    v2 = box2d.coordWorldToPixels(p2);
    g.line((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y);
    

    }

  • Cool, I updated the first post to contain the drawTransform. Only 4 methods left :)

    BTW, don't you think shiffman's example would have been more easy by using a debug draw?

  • edited August 2015

    maybe I should change the code like this, since the above code will make a new Vec2 p2 object with every drawTransform call . And it is very strange, with the above code, I didn't define p1 and the code still work.

    private Vec2 p1 = new Vec2();
    private Vec2 p2 = new Vec2();
    
    @ Override
    public void drawTransform(Transform xf) {
        float k_axisScale = 0.4f;
        p1 =xf.p;
        //p2.setZero();
        p2.x =p1.x + k_axisScale*xf.q.c;
        p2.y =p1.y + k_axisScale*xf.q.s;
        Vec2 v1 = box2d.coordWorldToPixels(p1);
        Vec2 v2 = box2d.coordWorldToPixels(p2);
        g.stroke(1, 0, 0);
        g.line((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y);
    
        p2.x = p1.x + -k_axisScale*xf.q.s;
        p2.y = p1.y + k_axisScale*xf.q.c;
        v2 = box2d.coordWorldToPixels(p2);
        g.stroke(0, 1, 0);
        g.line((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y);
    }
    
  • edited August 2015

    In fact, JBox2D has already a java version of debugdraw. It just didn't use the processing API. I think it is easy to implement all the method. Just copy the code and do some small changes.

    https://github.com/jbox2d/jbox2d/blob/master/jbox2d-testbed/src/main/java/org/jbox2d/testbed/framework/j2d/DebugDrawJ2D.java

  • Thanks for pointing that out.

  • edited August 2015

    I still can't fix the enable "DebugDraw.e_dynamicTreeBit" nullpointer exception. I only use Processing IDE, you can't debug with Processing IDE and I don't know which object is null.

    I found the latest Box2D Testbed don't include this selection for enable DebugDraw.e_dynamicTreeBit. But I found a 2012 post with JBox2D Testbed with the selection. And I change the drawTransform method:

    private Vec2 p1 = new Vec2();
    private Vec2 p2 = new Vec2();
    @ Override
    public void drawTransform(Transform xf) {
        float k_axisScale = 0.4f;
        p1 =xf.p;
        p2.x =p1.x + k_axisScale*xf.q.c;
        p2.y =p1.y + k_axisScale*xf.q.s;
        drawSegment(p1, p2, Color3f.RED);
        p2.x = p1.x + -k_axisScale*xf.q.s;
        p2.y = p1.y + k_axisScale*xf.q.c;
        drawSegment(p1, p2, Color3f.GREEN);
    }
    
  • edited August 2015

    The latest Box2D TestBed without a Draw Dynamic Tree selection.

    Screen Shot 2015-08-28 at 9.28.08 pm

  • Did you program that? And I don't have internet on my laptop atm so I can't look into the issue.

  • I just followed this youtube and build the JBox2D Testbed. It can draw dynamic tree of the body in the world.

  • I looked where it goes wrong.

     public void drawTree(DebugDraw argDraw, DynamicTreeNode node, int spot, int height) {
            node.aabb.getVertices(this.drawVecs);
            this.color.set(1.0F, (float)(height - spot) * 1.0F / (float)height, (float)(height - spot) * 1.0F / (float)height);
            argDraw.drawPolygon(this.drawVecs, 4, this.color);
            argDraw.getViewportTranform().getWorldToScreen(node.aabb.upperBound, this.textVec);
            argDraw.drawString(this.textVec.x, this.textVec.y, node.id + "-" + (spot + 1) + "/" + height, this.color);
            if(node.child1 != null) {
                this.drawTree(argDraw, node.child1, spot + 1, height);
            }
    
            if(node.child2 != null) {
                this.drawTree(argDraw, node.child2, spot + 1, height);
            }
    
        }
    

    This is the line:

    argDraw.getViewportTranform().getWorldToScreen(node.aabb.upperBound, this.textVec);

    getViewportTranform() returns null instead of IViewportTranform.

    I hope this helps. I don't have the time and willing to fix this.

  • Thank you for your help. It is a great job to implement the debugdraw. I will try when I am not busy. I am so tired today.

  • edited August 2015

    After a good sleep. I finally got the answer. You just need to add

    debugDraw.setViewportTransform(new OBBViewportTransform());

    after :

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

    I want to ask a question: how did you find "getViewportTranform()" return null ? Is it easy ? Because I don't know how to use eclipse to write Processing program.

  • edited September 2015

    @ Override

    public void drawString(float x, float y, String s, Color3f color_) {
    Vec2 v1 = box2d.coordWorldToPixels(x,y);
    g.fill(color_.x, color_.y, color_.z);
    g.text(s, (int)v1.x, (int)v1.y);}
    
  • I don't use eclipse anymore, intelliJ is so much better. Anyway, it is easy to find. Just run the sketch, so you get the error:

    Screen Shot 2015-09-01 at 9.45.54 AM

    Then you can just click on the line numbers and it would decompile and show you the line.

  • edited September 2015

    Thank you for your advice. Now I am learning IntelliJ .

  • edited September 2015

    I removed the casts from the methods you have posted. Or did you had a good reason for it?

    About IntelliJ, one advice, add the libraries to the global libraries (command + ";" on mac). Then in a project you can go to the global libraries, press right mouse "add to module".

    There are more neat things but I don't want to spoil this topic.

  • edited September 2015

    Some codes just copy from JBox2D. I don't know why the original programmer cast float to int. Just do as you like. I am a beginner.

    https://github.com/jbox2d/jbox2d/blob/master/jbox2d-testbed/src/main/java/org/jbox2d/testbed/framework/j2d/DebugDrawJ2D.java

    The next thing I want to do about the debugdraw is to create a camera or "viewport" class that can zoom in/out , move up / down /left /right or follow the object . There are example code in JBox2D, I just need to find out and rewrite it in Processing API.

  • edited September 2015

    a new bug?

        OBBViewportTransform myViewport = new OBBViewportTransform();
        myViewport.setYFlip(true);
        debugDraw.setViewportTransform(myViewport);
    

    I expect the "world" will flip upside down. But only the strings of the dynamic tree's nodes upside down.

    1

  • Maybe it's an idea to set up a github?

Sign In or Register to comment.