Search code examples
javaentityrectanglesjbox2d

How to get half width and half height from a body in jbox2d


So I have Body body that is a rectangle. How do I get its half width and half height?(I could not find an answer anywhere else)


Solution

  • Unfortunately, it's not perfectly straight forward as Box2D (and thus JBox2D) does not have any concept of rectangles per se. The rectangle is a PolygonShape, whose shape was probably specified using setAsBox(halfWidth, halfHeight).

    To get that halfWidth and halfHeight after creating a Fixture, consider the following (please refactor it as needed):

    public void checkOutThisFixture(Fixture fixture) {
        Shape fixtureShape = fixture.getShape();
        if (fixtureShape instanceof PolygonShape) {
            PolygonShape polygonShape = (PolygonShape) fixtureShape;
            Float minX = null;
            Float maxX = null;
            Float minY = null;
            Float maxY = null;
            for (int i = 0; i < polygonShape.getVertexCount(); i++) {
                Vec2 nextVertex = polygonShape.getVertex(i);
                float x = nextVertex.x;
                float y = nextVertex.y;
                if (minX == null || x < minX) {
                    minX = x;
                }
                if (maxX == null || x > maxX) {
                    maxX = x;
                }
                if (minY == null || y < minY) {
                    minY = y;
                }
                if (maxY == null || y > maxY) {
                    maxY = y;
                }
            }
            float width = maxX - minX;
            float height = maxY - minY;
            float halfWidth = width / 2;
            float halfHeight = height / 2;
            System.out.println("The polygon has half width & height of: " + halfWidth + " & " + halfHeight);
        } else if (fixtureShape instanceof CircleShape) {
            float radius = ((CircleShape) fixtureShape).m_radius;
            System.out.println("The circle has a radius of : " + radius);
        } else {
            // TODO handle other shapes
        }
    }
    

    To get this information from a Body use:

    public void checkOutTheseFixtures(Body body) {
        for (Fixture fixture = body.getFixtureList(); fixture != null; fixture = fixture.getNext()) {
            checkOutThisFixture(fixture);
        }
    }
    

    And a few tests:

    World world = new World(new Vec2(0, 0), true);
    Body body = world.createBody(new BodyDef());
    
    // Add a circle
    CircleShape circle = new CircleShape();
    circle.m_radius = 20;
    body.createFixture(circle, 5);
    
    // Add a box
    PolygonShape rectangle = new PolygonShape();
    rectangle.setAsBox(137, 42);
    body.createFixture(rectangle, 10);
    
    // Add a more complex polygon
    PolygonShape polygon = new PolygonShape();
    Vec2[] vertices = new Vec2[5];
    vertices[0] = new Vec2(-1, 2);
    vertices[1] = new Vec2(-1, 0);
    vertices[2] = new Vec2(0, -3);
    vertices[3] = new Vec2(1, 0);
    vertices[4] = new Vec2(1, 1);
    polygon.set(vertices, 5);
    body.createFixture(polygon, 10);
    
    checkOutTheseFixtures(body);
    

    Prints:

    The polygon has half width & height of: 1.0 & 2.5

    The polygon has half width & height of: 137.0 & 42.0

    The circle has a radius of : 20.0

    Hope that helps.


    On a similar note, here's a terse way to get the dimensions for a PolygonShape:

      public static Vec2 getDimensions( final PolygonShape shape ) {
        float minX = Float.MAX_VALUE;
        float maxX = Float.MIN_VALUE;
        float minY = Float.MAX_VALUE;
        float maxY = Float.MIN_VALUE;
        
        final int vertices = shape.getVertexCount();
        
        for( int i = 0; i < vertices; i++ ) {
          final Vec2 v = shape.getVertex( i );
          
          minX = (v.x < minX) ? v.x : minX;
          maxX = (v.x > maxX) ? v.x : maxX;
          minY = (v.y < minY) ? v.y : minY;
          maxY = (v.y > maxY) ? v.y : maxY;
        }
            
        return new Vec2( maxX - minX, maxY - minY );
      }
    

    Dividing the returned Vec2's dimensions in half will also retrieve the desired value.