Convex cast when start position overlaps

Posts regarding potential bugs, enhancement requests, and general feedback on use of dyn4j
zoom
Posts: 143
Joined: Sun Mar 17, 2013 3:57 pm
Location: Stockholm, Sweden
Contact:

Convex cast when start position overlaps

Postby zoom » Sun Dec 15, 2013 7:05 am

I'm leaning towards that convex cast misses impacts if the convex I'm casting overlaps a body in the initial position. Or is this simply a mistake in my setup?

Code: Select all

public class AppTest
      extends TestCase {

   public static final double PHYSICS_STEP_TIME_IN_SECONDS = 1.0 / 60.0;

   public void testApp() {
      World world = initWorld();
      ExplosionTriangle[] explosionTriangles = initTriangles(1.0, 8, new Vector2(0, 0), 10);
      // This isn't detected
      addBody(world, new Vector2(0.5, 0.0), 0.0, new Rectangle(1, 1));
      // But this is
      addBody(world, new Vector2(5, 0.0), 0.0, new Rectangle(1, 1));

      int impactsFound = 0;

      for (ExplosionTriangle triangle : explosionTriangles) {
         final List<ConvexCastResult> result = new ArrayList<ConvexCastResult>();
         world.convexCast(triangle.triangle, triangle.transform, triangle.castDirectionAndLength, true, true, result);
         Collections.sort(result);

         for (final ConvexCastResult impact : result) {
            impactsFound++;
         }
      }
      System.out.println("Impacts: " + impactsFound);
      assertTrue("Found at least 1 impact", impactsFound > 1);
   }

   private ExplosionTriangle[] initTriangles(double startRadius, int numTriangles, Vector2 location, double sweepLength) {
      ExplosionTriangle[] explosionTriangles = new ExplosionTriangle[numTriangles];
      final double angleIncrement = 2 * Math.PI / explosionTriangles.length;
      final double halfAngleIncrement = angleIncrement / 2.0;
      for (int n = 0; n < explosionTriangles.length; n++) {
         final double angle = angleIncrement * n;
         final double ccvVertexAngle = angle - halfAngleIncrement;
         final double cvVertexAngle = angle + halfAngleIncrement;

         final Convex unitTriangle = new Triangle(
               new Vector2(0, 0),
               new Vector2(Math.sin(cvVertexAngle) * startRadius, Math.cos(cvVertexAngle) * startRadius),
               new Vector2(Math.sin(ccvVertexAngle) * startRadius, Math.cos(ccvVertexAngle) * startRadius)
         );
         ExplosionTriangle triangle = new ExplosionTriangle();
         triangle.triangle = unitTriangle;
         triangle.transform = new Transform();
         triangle.transform.rotate(angle);
         triangle.transform.setTranslation(location);
         triangle.castDirectionAndLength = new Vector2(angle).multiply(sweepLength);

         explosionTriangles[n] = triangle;
      }
      return explosionTriangles;
   }

   private World initWorld() {
      Settings s = new Settings();
      s.setStepFrequency(PHYSICS_STEP_TIME_IN_SECONDS);
      World world = new World();
      world.setSettings(s);
      world.setGravity(new Vector2(0, 0));
      return world;
   }

   private void addBody(final World world, Vector2 location, double density, Convex convex) {
      final Body body = new Body();
      final BodyFixture bodyFixture = body.addFixture(convex);
      if (density > 0.0f) {
         bodyFixture.setDensity(density);
         bodyFixture.createMass();
         body.setMass();
         body.translateToOrigin();
      }
      Transform transform = body.getTransform();
      transform.identity();
      transform.translate(location);
      transform.setRotation(0);
      body.setTransform(transform);
      world.addBody(body);
   }

   static class ExplosionTriangle {

      Transform transform;
      Vector2 castDirectionAndLength;
      Convex triangle;
      double rotation;
   }

}

zoom
Posts: 143
Joined: Sun Mar 17, 2013 3:57 pm
Location: Stockholm, Sweden
Contact:

Re: Convex cast when start position overlaps

Postby zoom » Sun Dec 15, 2013 7:08 am

Way to start off with a typo: "Found at least 1 impact" should of course be "Found more than 1 impact" :-)

zoom
Posts: 143
Joined: Sun Mar 17, 2013 3:57 pm
Location: Stockholm, Sweden
Contact:

Re: Convex cast when start position overlaps

Postby zoom » Sun Dec 15, 2013 7:40 am

Redid the same test with Raycast and that seems to have the same behavior. Bodies overlapping the start location of the ray are not included in the RaycastResult. So maybe this is the way it is supposed to work.

Is there some simple work around so I can find all bodies that intersect the ray even if I start inside the body? Maybe cast the ray in both directions and collect the results would work unless both start and end positions are inside (which they won't be in my use case).

Code: Select all

public class RayCastTest extends TestCase {

   private World initWorld() {
      Settings s = new Settings();
      s.setStepFrequency(PHYSICS_STEP_TIME_IN_SECONDS);
      World world = new World();
      world.setSettings(s);
      world.setGravity(new Vector2(0, 0));
      return world;
   }

   public void testRays() {
      World world = initWorld();
      Ray[] rays = initRays(1.0, 8, new Vector2(0, 0));
      // This isn't detected
      addBody(world, new Vector2(0.5, 0.0), 0.0, new Rectangle(1, 1));
      // But this is
      addBody(world, new Vector2(5, 0.0), 0.0, new Rectangle(1, 1));

      int impactsFound = 0;

      for (Ray ray : rays) {
         final List<RaycastResult> result = new ArrayList<RaycastResult>();
         world.raycast(ray, 10.0, true, true, result);
         Collections.sort(result);

         for (final RaycastResult impact : result) {
            impactsFound++;
         }
      }
      System.out.println("Impacts: " + impactsFound);
      assertTrue("Found more than 1 impact", impactsFound > 1);
   }

   private Ray[] initRays(double startRadius, int numTriangles, Vector2 location) {
      Ray[] rays = new Ray[numTriangles];
      final double angleIncrement = 2 * Math.PI / rays.length;
      final double halfAngleIncrement = angleIncrement / 2.0;
      for (int n = 0; n < rays.length; n++) {
         final double angle = angleIncrement * n;
         final double ccvVertexAngle = angle - halfAngleIncrement;
         final double cvVertexAngle = angle + halfAngleIncrement;

         final Convex unitTriangle = new Triangle(
               new Vector2(0, 0),
               new Vector2(Math.sin(cvVertexAngle) * startRadius, Math.cos(cvVertexAngle) * startRadius),
               new Vector2(Math.sin(ccvVertexAngle) * startRadius, Math.cos(ccvVertexAngle) * startRadius)
         );
         Ray ray = new Ray(location, angle);
         rays[n] = ray;
      }
      return rays;
   }

   private void addBody(final World world, Vector2 location, double density, Convex convex) {
      final Body body = new Body();
      final BodyFixture bodyFixture = body.addFixture(convex);
      if (density > 0.0f) {
         bodyFixture.setDensity(density);
         bodyFixture.createMass();
         body.setMass();
         body.translateToOrigin();
      }
      Transform transform = body.getTransform();
      transform.identity();
      transform.translate(location);
      transform.setRotation(0);
      body.setTransform(transform);
      world.addBody(body);
   }
}

William
Site Admin
Posts: 349
Joined: Sat Feb 06, 2010 10:23 pm

Re: Convex cast when start position overlaps

Postby William » Mon Dec 16, 2013 8:26 am

You are correct. For both ray casting and convex casting, if the cast begins inside a shape, that shape will not be detected. This is documented on the RaycastDetector.raycast and World.raycast methods but not on the convexCast methods. My mistake. I'll be sure to update the documentation. The end point, on the other hand, should work as expected.

As a work around for the start point limitation, depending on what you need, I would just do a point in body test as well.

Code: Select all

// do normal convex cast
List<ConvexCastResult> results = world.convexCast(...);

// do additional point in shape test
// start by filtering down the list of bodies to test with an arbitrarily
// sized AABB centered at the start point of the cast
AABB pointAABB = new AABB(...);
List<Body> potentials = world.detect(pointAABB);

// now check the filtered bodies for the start position
for (Body body : potentials) {
  if (body.contains(startPos)) {
    ConvexCastResult result = new ConvexCastResult();
    Separation separation = new Separation(...use the convex cast normal (dp)...?, 0, new Vector2(), new Vector2());
    result.setTimeOfImpact(new TimeOfImpact(0, separation));
    result.setBody(body);
    result.setFixture(...if you cared you could loop over the fixtures and find which one it intersected...);
    results.add(result);
  }
}


Something like that? The only problem is the normal. It won't always be in the direction of the cast. Another option, if you really needed the normal to be somewhat correct, you could instead do a quick collision test of a small circle (centered at the start point) and use its normal.

William

zoom
Posts: 143
Joined: Sun Mar 17, 2013 3:57 pm
Location: Stockholm, Sweden
Contact:

Re: Convex cast when start position overlaps

Postby zoom » Mon Dec 16, 2013 2:36 pm

William wrote:For both ray casting and convex casting, if the cast begins inside a shape, that shape will not be detected. This is documented on the RaycastDetector.raycast and World.raycast methods but not on the convexCast methods. My mistake. I'll be sure to update the documentation. The end point, on the other hand, should work as expected.


No problem, if I may suggest a @see RaycastDetector.raycast on the World#raycast methods. I think that's where most of us users will begin looking. I didn't think to look for the RaycastDetector javadoc (my bad).

Something like that? The only problem is the normal. It won't always be in the direction of the cast. Another option, if you really needed the normal to be somewhat correct, you could instead do a quick collision test of a small circle (centered at the start point) and use its normal.

William


Yes I figured that the normal wouldn't make sense in the case when starting inside something. For my use case I don't really need it so I'll look into your suggestion in the general thread - sorry to always start two threads for every topic :-)

zoom
Posts: 143
Joined: Sun Mar 17, 2013 3:57 pm
Location: Stockholm, Sweden
Contact:

Re: Convex cast when start position overlaps

Postby zoom » Mon Dec 16, 2013 3:18 pm

zoom wrote:No problem, if I may suggest a @see RaycastDetector.raycast on the World#raycast methods. I think that's where most of us users will begin looking. I didn't think to look for the RaycastDetector javadoc (my bad).


I must be freaking blind or something, the javadoc for world says Bodies that contain the start of the ray will not be included in the results.


Return to “Bugs, Enhancements, Feedback”

Who is online

Users browsing this forum: No registered users and 2 guests