0

In a Box2D project I need to create a RevoluteJoint between two PolygonShaped bodies at the exact point where the user double tapped.

I have the point of touch, and a list of vertices for each of the two shapes (obviously set not to collide with each other.) If I understand correctly, the point of touch is in terms of world location, and the vertices are describing the shape, which could reside in any world. But how do I "translate" from one to another?

For example, the user double tapped at (3.63,5.07).

The vertices for shape 1 are: [(0.37485206,-0.17777264), (-0.2880008,-0.033603553), (-0.1609711,-0.2395713), (-0.04113376,-0.31708732), (0.26274818,-0.38661742), (0.35696936,-0.29765773)]

The vertices for shape 2: [(-0.015462875,0.24353802), (-0.13529873,0.31698608), (-0.36852637,0.4127499), (-0.4136281,0.17009032), (-0.2880008,-0.033603553)]

The revoluteJoint:

RevoluteJointDef jd = new RevoluteJointDef();
jd.bodyA = touchedBodies.get(0);
jd.bodyB = touchedBodies.get(1);
jd.collideConnected = false;
jd.localAnchorA.set(?????);
jd.localAnchorB.set(?????);
world.createJoint(jd);

Any help would be greatly appreciated.

EDIT:

I made a bit of progress but still not there. What I'm doing now is finding an "average" location, based on the shape's vertices. I'm taking the first entry, and knowing that the vertices go counter clock wise calculate which one is the middle vertice, and assumes that it is the furthest from the first one. So I'm doing an average of the two, and setting the joint there.

Here's the code:

Shape shape1 = touchedFixtures.get(0).getShape();
Vec2 oneAverage = null;
if(shape1.getClass() == PolygonShape.class) {
    PolygonShape s = (PolygonShape)shape1;
    Vec2[] vs = s.m_vertices;
    List<Vec2> vsNonZero = new LinkedList<Vec2>();
    for(int i=0; i<vs.length; i++) {
        if(vs[i].x != 0 || vs[i].y != 0) {
            vsNonZero.add(vs[i]);
        }
    }
    Vec2 oneOne = vsNonZero.get(0);
    Vec2 oneMiddle = vsNonZero.get(Math.round(vsNonZero.size()/2));
    oneAverage = new Vec2((oneOne.x + oneMiddle.x)/2, (oneOne.y + oneMiddle.y)/2);
}

And the joint's local anchor:

jointDef.localAnchorA.set(oneAverage);

I'm doing the same for the second body of the joint. This finds a fairly decent proximity, but it's not perfect, especially if the shape is larger.

Any idea how to go closer to the actual touched point? What I need is something like shape.getTouchedPoint() but the API doesn't seem to provide it.

Eddy
  • 3,533
  • 13
  • 59
  • 89

2 Answers2

1

This is how you do it:

jd.localAnchorA = touchedBodies.get(0).getLocalPoint(locationWorld);
jd.localAnchorB = touchedBodies.get(1).getLocalPoint(locationWorld);

touchedBodies above is simply a list with the two bodies that were touched, so the above can be replaced with this:

jd.localAnchorA = bodyA.getLocalPoint(locationWorld);
jd.localAnchorB = bodyB.getLocalPoint(locationWorld);

Thank you iforce2d for providing this answer here (http://www.cocos2d-iphone.org/forum/topic/343137#post-507904) with some explanation, and C++ code.

Eddy
  • 3,533
  • 13
  • 59
  • 89
0

Local anchor refers to where the joint is 'connecting' to, in local body coordinates. Each body has it's own coordinate system, it's the system you use when you position the shape in the body. For example, when the body rotates in the world, the shape is in the same position in the body's local coordinates.

So the localAnchorA is the connection to body A in body A's local coordinate system, same for B with body B.

Basically, draw the shapes on graph paper with their shape coordinates that you gave when you created it, then use that coordinate system to pick a point for the joint's anchor.

Edit: for dynamic stuff, use the getLocalPoint method on the body object, or be cooler and use the getLocalPointToOut method. Something like:

jd.bodyA.getLocalPointToOut(worldLocation, jd.localAnchorA);
Daniel Murphy
  • 852
  • 7
  • 14
  • Thanks for replying, Daniel, but I need to set the joint dynamically so I can't choose it from a graph. What I need is something like shape.getTouchedPoint() but the API doesn't seem to provide it. – Eddy May 05 '13 at 13:35
  • I edited the question with some code I'm using now. There's progress, but I'm still not there. – Eddy May 05 '13 at 13:50
  • Ah I see, yes you want to use the getLocalPoint, as you found. To be even more efficient, you should use getLocalPointToOut(locationWorld, jd.localAnchorA); – Daniel Murphy May 07 '13 at 20:34