Box2D Forums

It is currently Mon May 20, 2013 9:04 am

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Sun Feb 24, 2008 3:18 pm 
Offline

Joined: Fri Feb 08, 2008 7:40 am
Posts: 13
Hey,

I'm using the most recent SVN build of Box2D, and I'm running into trouble when trying to test a segment against a box. Specifically, an assertion fails in b2PolygonShape::TestSegment.
Code:
b2Assert(0.0f <= lower && lower <= maxLambda);

This is the assertion. "lower" is -5.0f, "upper" is 1.0f. The polygon is a rectangle; I am giving the routine a maxLambda of 1.0f.
The segment's p1 is contained inside the polygon which is causing the failure. Might this be why?

Thanks!


Top
 Profile  
 
PostPosted: Sun Feb 24, 2008 4:00 pm 
Offline

Joined: Fri Feb 08, 2008 7:40 am
Posts: 13
Created a different test case, with no overlap. Same thing happens, but the value of "lower" is a bit different.


Top
 Profile  
 
PostPosted: Tue Feb 26, 2008 12:38 am 
Offline
Site Admin

Joined: Thu Sep 06, 2007 12:34 am
Posts: 2931
This code isn't tested. I plan to begin supporting ray casts in version 2.1.

If you find a fix, I'll apply a patch. Otherwise you'll need to wait for 2.1.


Top
 Profile  
 
PostPosted: Thu Feb 28, 2008 1:22 pm 
Offline

Joined: Fri Feb 08, 2008 7:40 am
Posts: 13
Of course, of course.

Here is a new version of b2PolygonShape::TestSegment which works correctly as far as I can tell (hasn't been extensively tested yet). I hope you won't mind that it is largely a reimplementation and not a bug fix.

It basically treats the polygon as a line segment soup (except for the normals; it uses the precomputed normals stored in the polygon object the way that the current SVN version does), so you could probably use it pretty much as-is for the new line segment soup collision type.

Code:
bool b2PolygonShape::TestSegment(
   const b2XForm& xf,
   float32* lambda,
   b2Vec2* normal,
   const b2Segment& segment,
   float32 maxLambda) const
{
   float32 upper = maxLambda;

   b2Vec2 p1 = b2MulT(xf.R, segment.p1 - xf.position);
   b2Vec2 p2 = b2MulT(xf.R, segment.p2 - xf.position);
   b2Vec2 p_delta = p2 - p1;
   int32 index = -1;

   for( int32 i = 0; i < m_vertexCount; ++i )
   {
      // Test the segment from vertex i to vertex i+1
      b2Vec2 s1 = m_vertices[i];
      b2Vec2 s2 = m_vertices[(i+1)%m_vertexCount];
      b2Vec2 s_delta = s2 - s1;

      float32 denom = ( s_delta.y * p_delta.x ) - ( s_delta.x * p_delta.y );

      // If the segments are parallel, there can be no intersection.
      if( 0.0f == denom )
         continue;

      float32 lambda_s = ( p_delta.x * ( p1.y - s1.y ) ) - ( p_delta.y * ( p1.x - s1.x ) );
      lambda_s /= denom;

      // Make sure the collision occurs along the part of s that actually makes up a side of the polygon.
      if( ( 0.0f > lambda_s ) || ( 1.0f < lambda_s ) )
         continue;

      float32 lambda_p = ( s_delta.x * ( p1.y - s1.y ) ) - ( s_delta.y * ( p1.x - s1.x ) );
      lambda_p /= denom;

      // See if this is closer along p (the segment we are testing against this polygon) than any previous results.
      if( ( lambda_p < upper ) && ( lambda_p >= 0.0f ) )
      {
         upper = lambda_p;
         index = i;
      }
   }

   if (index >= 0)
   {
      *lambda = upper;
      *normal = b2Mul(xf.R, m_normals[index]);
      return true;
   }

   return false;
}


Top
 Profile  
 
PostPosted: Thu Feb 28, 2008 1:31 pm 
Offline

Joined: Fri Feb 08, 2008 7:40 am
Posts: 13
Also, this may be useful to help someone get started very quickly. I have a list of Entity objects, each of which implement getBody(), a function that returns a pointer to a b2Body.

This function just minimizes lambda by calling TestSegment on every entity in the scene. It's not even smart enough to use bounding volumes. I have some significantly better-performing implementations of raycast(), but they're more wired-in to my engine than this simpler one is.

Code:
Entity*
raycast( float32* lambda, b2Vec2* normal, const b2Segment& segment, float32 maxLambda )
{
   // TODO: this is exceptionally naive, and should be replaced by proper raycasting at some point
   float32 min_lambda = maxLambda, this_lambda;
   b2Vec2 min_normal, this_normal;
   Entity* min_entity = NULL;

   for( std::list<Entity*>::iterator it = entities.begin( ); it != entities.end( ); ++it )
   {
      b2Body* body = (*it)->getBody( );
      b2Shape* shape = body->m_shapeList;

      while( NULL != shape )
      {
         if( true == shape->TestSegment( body->GetXForm( ), &this_lambda, &this_normal, segment, maxLambda ) )
         {
            if( this_lambda < min_lambda )
            {
               min_lambda = this_lambda;
               min_normal = this_normal;
               min_entity = (*it);
            }
         }

         shape = shape->m_next;
      }
   }

   if( NULL != min_entity )
   {
      *lambda = min_lambda;
      *normal = min_normal;
   }

   return min_entity;
}


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: Exabot [Bot] and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group