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 | |