Home | History | Annotate | Download | only in Collision
      1 /*
      2  * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
      3  *
      4  * This software is provided 'as-is', without any express or implied
      5  * warranty.  In no event will the authors be held liable for any damages
      6  * arising from the use of this software.
      7  * Permission is granted to anyone to use this software for any purpose,
      8  * including commercial applications, and to alter it and redistribute it
      9  * freely, subject to the following restrictions:
     10  * 1. The origin of this software must not be misrepresented; you must not
     11  * claim that you wrote the original software. If you use this software
     12  * in a product, an acknowledgment in the product documentation would be
     13  * appreciated but is not required.
     14  * 2. Altered source versions must be plainly marked as such, and must not be
     15  * misrepresented as being the original software.
     16  * 3. This notice may not be removed or altered from any source distribution.
     17  */
     18 
     19 #include <Box2D/Collision/b2Collision.h>
     20 #include <Box2D/Collision/Shapes/b2CircleShape.h>
     21 #include <Box2D/Collision/Shapes/b2EdgeShape.h>
     22 #include <Box2D/Collision/Shapes/b2PolygonShape.h>
     23 
     24 
     25 // Compute contact points for edge versus circle.
     26 // This accounts for edge connectivity.
     27 void b2CollideEdgeAndCircle(b2Manifold* manifold,
     28 							const b2EdgeShape* edgeA, const b2Transform& xfA,
     29 							const b2CircleShape* circleB, const b2Transform& xfB)
     30 {
     31 	manifold->pointCount = 0;
     32 
     33 	// Compute circle in frame of edge
     34 	b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p));
     35 
     36 	b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2;
     37 	b2Vec2 e = B - A;
     38 
     39 	// Barycentric coordinates
     40 	float32 u = b2Dot(e, B - Q);
     41 	float32 v = b2Dot(e, Q - A);
     42 
     43 	float32 radius = edgeA->m_radius + circleB->m_radius;
     44 
     45 	b2ContactFeature cf;
     46 	cf.indexB = 0;
     47 	cf.typeB = b2ContactFeature::e_vertex;
     48 
     49 	// Region A
     50 	if (v <= 0.0f)
     51 	{
     52 		b2Vec2 P = A;
     53 		b2Vec2 d = Q - P;
     54 		float32 dd = b2Dot(d, d);
     55 		if (dd > radius * radius)
     56 		{
     57 			return;
     58 		}
     59 
     60 		// Is there an edge connected to A?
     61 		if (edgeA->m_hasVertex0)
     62 		{
     63 			b2Vec2 A1 = edgeA->m_vertex0;
     64 			b2Vec2 B1 = A;
     65 			b2Vec2 e1 = B1 - A1;
     66 			float32 u1 = b2Dot(e1, B1 - Q);
     67 
     68 			// Is the circle in Region AB of the previous edge?
     69 			if (u1 > 0.0f)
     70 			{
     71 				return;
     72 			}
     73 		}
     74 
     75 		cf.indexA = 0;
     76 		cf.typeA = b2ContactFeature::e_vertex;
     77 		manifold->pointCount = 1;
     78 		manifold->type = b2Manifold::e_circles;
     79 		manifold->localNormal.SetZero();
     80 		manifold->localPoint = P;
     81 		manifold->points[0].id.key = 0;
     82 		manifold->points[0].id.cf = cf;
     83 		manifold->points[0].localPoint = circleB->m_p;
     84 		return;
     85 	}
     86 
     87 	// Region B
     88 	if (u <= 0.0f)
     89 	{
     90 		b2Vec2 P = B;
     91 		b2Vec2 d = Q - P;
     92 		float32 dd = b2Dot(d, d);
     93 		if (dd > radius * radius)
     94 		{
     95 			return;
     96 		}
     97 
     98 		// Is there an edge connected to B?
     99 		if (edgeA->m_hasVertex3)
    100 		{
    101 			b2Vec2 B2 = edgeA->m_vertex3;
    102 			b2Vec2 A2 = B;
    103 			b2Vec2 e2 = B2 - A2;
    104 			float32 v2 = b2Dot(e2, Q - A2);
    105 
    106 			// Is the circle in Region AB of the next edge?
    107 			if (v2 > 0.0f)
    108 			{
    109 				return;
    110 			}
    111 		}
    112 
    113 		cf.indexA = 1;
    114 		cf.typeA = b2ContactFeature::e_vertex;
    115 		manifold->pointCount = 1;
    116 		manifold->type = b2Manifold::e_circles;
    117 		manifold->localNormal.SetZero();
    118 		manifold->localPoint = P;
    119 		manifold->points[0].id.key = 0;
    120 		manifold->points[0].id.cf = cf;
    121 		manifold->points[0].localPoint = circleB->m_p;
    122 		return;
    123 	}
    124 
    125 	// Region AB
    126 	float32 den = b2Dot(e, e);
    127 	b2Assert(den > 0.0f);
    128 	b2Vec2 P = (1.0f / den) * (u * A + v * B);
    129 	b2Vec2 d = Q - P;
    130 	float32 dd = b2Dot(d, d);
    131 	if (dd > radius * radius)
    132 	{
    133 		return;
    134 	}
    135 
    136 	b2Vec2 n(-e.y, e.x);
    137 	if (b2Dot(n, Q - A) < 0.0f)
    138 	{
    139 		n.Set(-n.x, -n.y);
    140 	}
    141 	n.Normalize();
    142 
    143 	cf.indexA = 0;
    144 	cf.typeA = b2ContactFeature::e_face;
    145 	manifold->pointCount = 1;
    146 	manifold->type = b2Manifold::e_faceA;
    147 	manifold->localNormal = n;
    148 	manifold->localPoint = A;
    149 	manifold->points[0].id.key = 0;
    150 	manifold->points[0].id.cf = cf;
    151 	manifold->points[0].localPoint = circleB->m_p;
    152 }
    153 
    154 // This structure is used to keep track of the best separating axis.
    155 struct b2EPAxis
    156 {
    157 	enum Type
    158 	{
    159 		e_unknown,
    160 		e_edgeA,
    161 		e_edgeB
    162 	};
    163 
    164 	Type type;
    165 	int32 index;
    166 	float32 separation;
    167 };
    168 
    169 // This holds polygon B expressed in frame A.
    170 struct b2TempPolygon
    171 {
    172 	b2Vec2 vertices[b2_maxPolygonVertices];
    173 	b2Vec2 normals[b2_maxPolygonVertices];
    174 	int32 count;
    175 };
    176 
    177 // Reference face used for clipping
    178 struct b2ReferenceFace
    179 {
    180 	int32 i1, i2;
    181 
    182 	b2Vec2 v1, v2;
    183 
    184 	b2Vec2 normal;
    185 
    186 	b2Vec2 sideNormal1;
    187 	float32 sideOffset1;
    188 
    189 	b2Vec2 sideNormal2;
    190 	float32 sideOffset2;
    191 };
    192 
    193 // This class collides and edge and a polygon, taking into account edge adjacency.
    194 struct b2EPCollider
    195 {
    196 	void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
    197 				 const b2PolygonShape* polygonB, const b2Transform& xfB);
    198 	b2EPAxis ComputeEdgeSeparation();
    199 	b2EPAxis ComputePolygonSeparation();
    200 
    201 	enum VertexType
    202 	{
    203 		e_isolated,
    204 		e_concave,
    205 		e_convex
    206 	};
    207 
    208 	b2TempPolygon m_polygonB;
    209 
    210 	b2Transform m_xf;
    211 	b2Vec2 m_centroidB;
    212 	b2Vec2 m_v0, m_v1, m_v2, m_v3;
    213 	b2Vec2 m_normal0, m_normal1, m_normal2;
    214 	b2Vec2 m_normal;
    215 	VertexType m_type1, m_type2;
    216 	b2Vec2 m_lowerLimit, m_upperLimit;
    217 	float32 m_radius;
    218 	bool m_front;
    219 };
    220 
    221 // Algorithm:
    222 // 1. Classify v1 and v2
    223 // 2. Classify polygon centroid as front or back
    224 // 3. Flip normal if necessary
    225 // 4. Initialize normal range to [-pi, pi] about face normal
    226 // 5. Adjust normal range according to adjacent edges
    227 // 6. Visit each separating axes, only accept axes within the range
    228 // 7. Return if _any_ axis indicates separation
    229 // 8. Clip
    230 void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
    231 						   const b2PolygonShape* polygonB, const b2Transform& xfB)
    232 {
    233 	m_xf = b2MulT(xfA, xfB);
    234 
    235 	m_centroidB = b2Mul(m_xf, polygonB->m_centroid);
    236 
    237 	m_v0 = edgeA->m_vertex0;
    238 	m_v1 = edgeA->m_vertex1;
    239 	m_v2 = edgeA->m_vertex2;
    240 	m_v3 = edgeA->m_vertex3;
    241 
    242 	bool hasVertex0 = edgeA->m_hasVertex0;
    243 	bool hasVertex3 = edgeA->m_hasVertex3;
    244 
    245 	b2Vec2 edge1 = m_v2 - m_v1;
    246 	edge1.Normalize();
    247 	m_normal1.Set(edge1.y, -edge1.x);
    248 	float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1);
    249 	float32 offset0 = 0.0f, offset2 = 0.0f;
    250 	bool convex1 = false, convex2 = false;
    251 
    252 	// Is there a preceding edge?
    253 	if (hasVertex0)
    254 	{
    255 		b2Vec2 edge0 = m_v1 - m_v0;
    256 		edge0.Normalize();
    257 		m_normal0.Set(edge0.y, -edge0.x);
    258 		convex1 = b2Cross(edge0, edge1) >= 0.0f;
    259 		offset0 = b2Dot(m_normal0, m_centroidB - m_v0);
    260 	}
    261 
    262 	// Is there a following edge?
    263 	if (hasVertex3)
    264 	{
    265 		b2Vec2 edge2 = m_v3 - m_v2;
    266 		edge2.Normalize();
    267 		m_normal2.Set(edge2.y, -edge2.x);
    268 		convex2 = b2Cross(edge1, edge2) > 0.0f;
    269 		offset2 = b2Dot(m_normal2, m_centroidB - m_v2);
    270 	}
    271 
    272 	// Determine front or back collision. Determine collision normal limits.
    273 	if (hasVertex0 && hasVertex3)
    274 	{
    275 		if (convex1 && convex2)
    276 		{
    277 			m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
    278 			if (m_front)
    279 			{
    280 				m_normal = m_normal1;
    281 				m_lowerLimit = m_normal0;
    282 				m_upperLimit = m_normal2;
    283 			}
    284 			else
    285 			{
    286 				m_normal = -m_normal1;
    287 				m_lowerLimit = -m_normal1;
    288 				m_upperLimit = -m_normal1;
    289 			}
    290 		}
    291 		else if (convex1)
    292 		{
    293 			m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
    294 			if (m_front)
    295 			{
    296 				m_normal = m_normal1;
    297 				m_lowerLimit = m_normal0;
    298 				m_upperLimit = m_normal1;
    299 			}
    300 			else
    301 			{
    302 				m_normal = -m_normal1;
    303 				m_lowerLimit = -m_normal2;
    304 				m_upperLimit = -m_normal1;
    305 			}
    306 		}
    307 		else if (convex2)
    308 		{
    309 			m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
    310 			if (m_front)
    311 			{
    312 				m_normal = m_normal1;
    313 				m_lowerLimit = m_normal1;
    314 				m_upperLimit = m_normal2;
    315 			}
    316 			else
    317 			{
    318 				m_normal = -m_normal1;
    319 				m_lowerLimit = -m_normal1;
    320 				m_upperLimit = -m_normal0;
    321 			}
    322 		}
    323 		else
    324 		{
    325 			m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
    326 			if (m_front)
    327 			{
    328 				m_normal = m_normal1;
    329 				m_lowerLimit = m_normal1;
    330 				m_upperLimit = m_normal1;
    331 			}
    332 			else
    333 			{
    334 				m_normal = -m_normal1;
    335 				m_lowerLimit = -m_normal2;
    336 				m_upperLimit = -m_normal0;
    337 			}
    338 		}
    339 	}
    340 	else if (hasVertex0)
    341 	{
    342 		if (convex1)
    343 		{
    344 			m_front = offset0 >= 0.0f || offset1 >= 0.0f;
    345 			if (m_front)
    346 			{
    347 				m_normal = m_normal1;
    348 				m_lowerLimit = m_normal0;
    349 				m_upperLimit = -m_normal1;
    350 			}
    351 			else
    352 			{
    353 				m_normal = -m_normal1;
    354 				m_lowerLimit = m_normal1;
    355 				m_upperLimit = -m_normal1;
    356 			}
    357 		}
    358 		else
    359 		{
    360 			m_front = offset0 >= 0.0f && offset1 >= 0.0f;
    361 			if (m_front)
    362 			{
    363 				m_normal = m_normal1;
    364 				m_lowerLimit = m_normal1;
    365 				m_upperLimit = -m_normal1;
    366 			}
    367 			else
    368 			{
    369 				m_normal = -m_normal1;
    370 				m_lowerLimit = m_normal1;
    371 				m_upperLimit = -m_normal0;
    372 			}
    373 		}
    374 	}
    375 	else if (hasVertex3)
    376 	{
    377 		if (convex2)
    378 		{
    379 			m_front = offset1 >= 0.0f || offset2 >= 0.0f;
    380 			if (m_front)
    381 			{
    382 				m_normal = m_normal1;
    383 				m_lowerLimit = -m_normal1;
    384 				m_upperLimit = m_normal2;
    385 			}
    386 			else
    387 			{
    388 				m_normal = -m_normal1;
    389 				m_lowerLimit = -m_normal1;
    390 				m_upperLimit = m_normal1;
    391 			}
    392 		}
    393 		else
    394 		{
    395 			m_front = offset1 >= 0.0f && offset2 >= 0.0f;
    396 			if (m_front)
    397 			{
    398 				m_normal = m_normal1;
    399 				m_lowerLimit = -m_normal1;
    400 				m_upperLimit = m_normal1;
    401 			}
    402 			else
    403 			{
    404 				m_normal = -m_normal1;
    405 				m_lowerLimit = -m_normal2;
    406 				m_upperLimit = m_normal1;
    407 			}
    408 		}
    409 	}
    410 	else
    411 	{
    412 		m_front = offset1 >= 0.0f;
    413 		if (m_front)
    414 		{
    415 			m_normal = m_normal1;
    416 			m_lowerLimit = -m_normal1;
    417 			m_upperLimit = -m_normal1;
    418 		}
    419 		else
    420 		{
    421 			m_normal = -m_normal1;
    422 			m_lowerLimit = m_normal1;
    423 			m_upperLimit = m_normal1;
    424 		}
    425 	}
    426 
    427 	// Get polygonB in frameA
    428 	m_polygonB.count = polygonB->m_count;
    429 	for (int32 i = 0; i < polygonB->m_count; ++i)
    430 	{
    431 		m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]);
    432 		m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]);
    433 	}
    434 
    435 	m_radius = 2.0f * b2_polygonRadius;
    436 
    437 	manifold->pointCount = 0;
    438 
    439 	b2EPAxis edgeAxis = ComputeEdgeSeparation();
    440 
    441 	// If no valid normal can be found than this edge should not collide.
    442 	if (edgeAxis.type == b2EPAxis::e_unknown)
    443 	{
    444 		return;
    445 	}
    446 
    447 	if (edgeAxis.separation > m_radius)
    448 	{
    449 		return;
    450 	}
    451 
    452 	b2EPAxis polygonAxis = ComputePolygonSeparation();
    453 	if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius)
    454 	{
    455 		return;
    456 	}
    457 
    458 	// Use hysteresis for jitter reduction.
    459 	const float32 k_relativeTol = 0.98f;
    460 	const float32 k_absoluteTol = 0.001f;
    461 
    462 	b2EPAxis primaryAxis;
    463 	if (polygonAxis.type == b2EPAxis::e_unknown)
    464 	{
    465 		primaryAxis = edgeAxis;
    466 	}
    467 	else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
    468 	{
    469 		primaryAxis = polygonAxis;
    470 	}
    471 	else
    472 	{
    473 		primaryAxis = edgeAxis;
    474 	}
    475 
    476 	b2ClipVertex ie[2];
    477 	b2ReferenceFace rf;
    478 	if (primaryAxis.type == b2EPAxis::e_edgeA)
    479 	{
    480 		manifold->type = b2Manifold::e_faceA;
    481 
    482 		// Search for the polygon normal that is most anti-parallel to the edge normal.
    483 		int32 bestIndex = 0;
    484 		float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]);
    485 		for (int32 i = 1; i < m_polygonB.count; ++i)
    486 		{
    487 			float32 value = b2Dot(m_normal, m_polygonB.normals[i]);
    488 			if (value < bestValue)
    489 			{
    490 				bestValue = value;
    491 				bestIndex = i;
    492 			}
    493 		}
    494 
    495 		int32 i1 = bestIndex;
    496 		int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0;
    497 
    498 		ie[0].v = m_polygonB.vertices[i1];
    499 		ie[0].id.cf.indexA = 0;
    500 		ie[0].id.cf.indexB = static_cast<uint8>(i1);
    501 		ie[0].id.cf.typeA = b2ContactFeature::e_face;
    502 		ie[0].id.cf.typeB = b2ContactFeature::e_vertex;
    503 
    504 		ie[1].v = m_polygonB.vertices[i2];
    505 		ie[1].id.cf.indexA = 0;
    506 		ie[1].id.cf.indexB = static_cast<uint8>(i2);
    507 		ie[1].id.cf.typeA = b2ContactFeature::e_face;
    508 		ie[1].id.cf.typeB = b2ContactFeature::e_vertex;
    509 
    510 		if (m_front)
    511 		{
    512 			rf.i1 = 0;
    513 			rf.i2 = 1;
    514 			rf.v1 = m_v1;
    515 			rf.v2 = m_v2;
    516 			rf.normal = m_normal1;
    517 		}
    518 		else
    519 		{
    520 			rf.i1 = 1;
    521 			rf.i2 = 0;
    522 			rf.v1 = m_v2;
    523 			rf.v2 = m_v1;
    524 			rf.normal = -m_normal1;
    525 		}
    526 	}
    527 	else
    528 	{
    529 		manifold->type = b2Manifold::e_faceB;
    530 
    531 		ie[0].v = m_v1;
    532 		ie[0].id.cf.indexA = 0;
    533 		ie[0].id.cf.indexB = static_cast<uint8>(primaryAxis.index);
    534 		ie[0].id.cf.typeA = b2ContactFeature::e_vertex;
    535 		ie[0].id.cf.typeB = b2ContactFeature::e_face;
    536 
    537 		ie[1].v = m_v2;
    538 		ie[1].id.cf.indexA = 0;
    539 		ie[1].id.cf.indexB = static_cast<uint8>(primaryAxis.index);
    540 		ie[1].id.cf.typeA = b2ContactFeature::e_vertex;
    541 		ie[1].id.cf.typeB = b2ContactFeature::e_face;
    542 
    543 		rf.i1 = primaryAxis.index;
    544 		rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0;
    545 		rf.v1 = m_polygonB.vertices[rf.i1];
    546 		rf.v2 = m_polygonB.vertices[rf.i2];
    547 		rf.normal = m_polygonB.normals[rf.i1];
    548 	}
    549 
    550 	rf.sideNormal1.Set(rf.normal.y, -rf.normal.x);
    551 	rf.sideNormal2 = -rf.sideNormal1;
    552 	rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1);
    553 	rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2);
    554 
    555 	// Clip incident edge against extruded edge1 side edges.
    556 	b2ClipVertex clipPoints1[2];
    557 	b2ClipVertex clipPoints2[2];
    558 	int32 np;
    559 
    560 	// Clip to box side 1
    561 	np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1);
    562 
    563 	if (np < b2_maxManifoldPoints)
    564 	{
    565 		return;
    566 	}
    567 
    568 	// Clip to negative box side 1
    569 	np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);
    570 
    571 	if (np < b2_maxManifoldPoints)
    572 	{
    573 		return;
    574 	}
    575 
    576 	// Now clipPoints2 contains the clipped points.
    577 	if (primaryAxis.type == b2EPAxis::e_edgeA)
    578 	{
    579 		manifold->localNormal = rf.normal;
    580 		manifold->localPoint = rf.v1;
    581 	}
    582 	else
    583 	{
    584 		manifold->localNormal = polygonB->m_normals[rf.i1];
    585 		manifold->localPoint = polygonB->m_vertices[rf.i1];
    586 	}
    587 
    588 	int32 pointCount = 0;
    589 	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
    590 	{
    591 		float32 separation;
    592 
    593 		separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1);
    594 
    595 		if (separation <= m_radius)
    596 		{
    597 			b2ManifoldPoint* cp = manifold->points + pointCount;
    598 
    599 			if (primaryAxis.type == b2EPAxis::e_edgeA)
    600 			{
    601 				cp->localPoint = b2MulT(m_xf, clipPoints2[i].v);
    602 				cp->id = clipPoints2[i].id;
    603 			}
    604 			else
    605 			{
    606 				cp->localPoint = clipPoints2[i].v;
    607 				cp->id.cf.typeA = clipPoints2[i].id.cf.typeB;
    608 				cp->id.cf.typeB = clipPoints2[i].id.cf.typeA;
    609 				cp->id.cf.indexA = clipPoints2[i].id.cf.indexB;
    610 				cp->id.cf.indexB = clipPoints2[i].id.cf.indexA;
    611 			}
    612 
    613 			++pointCount;
    614 		}
    615 	}
    616 
    617 	manifold->pointCount = pointCount;
    618 }
    619 
    620 b2EPAxis b2EPCollider::ComputeEdgeSeparation()
    621 {
    622 	b2EPAxis axis;
    623 	axis.type = b2EPAxis::e_edgeA;
    624 	axis.index = m_front ? 0 : 1;
    625 	axis.separation = FLT_MAX;
    626 
    627 	for (int32 i = 0; i < m_polygonB.count; ++i)
    628 	{
    629 		float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1);
    630 		if (s < axis.separation)
    631 		{
    632 			axis.separation = s;
    633 		}
    634 	}
    635 
    636 	return axis;
    637 }
    638 
    639 b2EPAxis b2EPCollider::ComputePolygonSeparation()
    640 {
    641 	b2EPAxis axis;
    642 	axis.type = b2EPAxis::e_unknown;
    643 	axis.index = -1;
    644 	axis.separation = -FLT_MAX;
    645 
    646 	b2Vec2 perp(-m_normal.y, m_normal.x);
    647 
    648 	for (int32 i = 0; i < m_polygonB.count; ++i)
    649 	{
    650 		b2Vec2 n = -m_polygonB.normals[i];
    651 
    652 		float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1);
    653 		float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2);
    654 		float32 s = b2Min(s1, s2);
    655 
    656 		if (s > m_radius)
    657 		{
    658 			// No collision
    659 			axis.type = b2EPAxis::e_edgeB;
    660 			axis.index = i;
    661 			axis.separation = s;
    662 			return axis;
    663 		}
    664 
    665 		// Adjacency
    666 		if (b2Dot(n, perp) >= 0.0f)
    667 		{
    668 			if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop)
    669 			{
    670 				continue;
    671 			}
    672 		}
    673 		else
    674 		{
    675 			if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop)
    676 			{
    677 				continue;
    678 			}
    679 		}
    680 
    681 		if (s > axis.separation)
    682 		{
    683 			axis.type = b2EPAxis::e_edgeB;
    684 			axis.index = i;
    685 			axis.separation = s;
    686 		}
    687 	}
    688 
    689 	return axis;
    690 }
    691 
    692 void b2CollideEdgeAndPolygon(	b2Manifold* manifold,
    693 							 const b2EdgeShape* edgeA, const b2Transform& xfA,
    694 							 const b2PolygonShape* polygonB, const b2Transform& xfB)
    695 {
    696 	b2EPCollider collider;
    697 	collider.Collide(manifold, edgeA, xfA, polygonB, xfB);
    698 }
    699