File indexing completed on 2025-08-03 03:49:56
0001 /* 0002 * Copyright (c) 2007-2009 Erin Catto http://www.gphysics.com 0003 * 0004 * This software is provided 'as-is', without any express or implied 0005 * warranty. In no event will the authors be held liable for any damages 0006 * arising from the use of this software. 0007 * Permission is granted to anyone to use this software for any purpose, 0008 * including commercial applications, and to alter it and redistribute it 0009 * freely, subject to the following restrictions: 0010 * 1. The origin of this software must not be misrepresented; you must not 0011 * claim that you wrote the original software. If you use this software 0012 * in a product, an acknowledgment in the product documentation would be 0013 * appreciated but is not required. 0014 * 2. Altered source versions must be plainly marked as such, and must not be 0015 * misrepresented as being the original software. 0016 * 3. This notice may not be removed or altered from any source distribution. 0017 */ 0018 0019 #include <Box2D/Collision/b2Distance.h> 0020 #include <Box2D/Collision/Shapes/b2CircleShape.h> 0021 #include <Box2D/Collision/Shapes/b2EdgeShape.h> 0022 #include <Box2D/Collision/Shapes/b2LoopShape.h> 0023 #include <Box2D/Collision/Shapes/b2PolygonShape.h> 0024 0025 // GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates. 0026 int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters; 0027 0028 void b2DistanceProxy::Set(const b2Shape* shape, int32 index) 0029 { 0030 switch (shape->GetType()) 0031 { 0032 case b2Shape::e_circle: 0033 { 0034 const b2CircleShape* circle = (b2CircleShape*)shape; 0035 m_vertices = &circle->m_p; 0036 m_count = 1; 0037 m_radius = circle->m_radius; 0038 } 0039 break; 0040 0041 case b2Shape::e_polygon: 0042 { 0043 const b2PolygonShape* polygon = (b2PolygonShape*)shape; 0044 m_vertices = polygon->m_vertices; 0045 m_count = polygon->m_vertexCount; 0046 m_radius = polygon->m_radius; 0047 } 0048 break; 0049 0050 case b2Shape::e_loop: 0051 { 0052 const b2LoopShape* loop = (b2LoopShape*)shape; 0053 b2Assert(0 <= index && index < loop->GetCount()); 0054 0055 m_buffer[0] = loop->GetVertex(index); 0056 if (index + 1 < loop->GetCount()) 0057 { 0058 m_buffer[1] = loop->GetVertex(index + 1); 0059 } 0060 else 0061 { 0062 m_buffer[1] = loop->GetVertex(0); 0063 } 0064 0065 m_vertices = m_buffer; 0066 m_count = 2; 0067 m_radius = loop->m_radius; 0068 } 0069 break; 0070 0071 case b2Shape::e_edge: 0072 { 0073 const b2EdgeShape* edge = (b2EdgeShape*)shape; 0074 m_vertices = &edge->m_vertex1; 0075 m_count = 2; 0076 m_radius = edge->m_radius; 0077 } 0078 break; 0079 0080 default: 0081 b2Assert(false); 0082 } 0083 } 0084 0085 0086 struct b2SimplexVertex 0087 { 0088 b2Vec2 wA; // support point in proxyA 0089 b2Vec2 wB; // support point in proxyB 0090 b2Vec2 w; // wB - wA 0091 qreal a; // barycentric coordinate for closest point 0092 int32 indexA; // wA index 0093 int32 indexB; // wB index 0094 }; 0095 0096 struct b2Simplex 0097 { 0098 void ReadCache( const b2SimplexCache* cache, 0099 const b2DistanceProxy* proxyA, const b2Transform& transformA, 0100 const b2DistanceProxy* proxyB, const b2Transform& transformB) 0101 { 0102 b2Assert(cache->count <= 3); 0103 0104 // Copy data from cache. 0105 m_count = cache->count; 0106 b2SimplexVertex* vertices = &m_v1; 0107 for (int32 i = 0; i < m_count; ++i) 0108 { 0109 b2SimplexVertex* v = vertices + i; 0110 v->indexA = cache->indexA[i]; 0111 v->indexB = cache->indexB[i]; 0112 b2Vec2 wALocal = proxyA->GetVertex(v->indexA); 0113 b2Vec2 wBLocal = proxyB->GetVertex(v->indexB); 0114 v->wA = b2Mul(transformA, wALocal); 0115 v->wB = b2Mul(transformB, wBLocal); 0116 v->w = v->wB - v->wA; 0117 v->a = 0.0f; 0118 } 0119 0120 // Compute the new simplex metric, if it is substantially different than 0121 // old metric then flush the simplex. 0122 if (m_count > 1) 0123 { 0124 qreal metric1 = cache->metric; 0125 qreal metric2 = GetMetric(); 0126 if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon) 0127 { 0128 // Reset the simplex. 0129 m_count = 0; 0130 } 0131 } 0132 0133 // If the cache is empty or invalid ... 0134 if (m_count == 0) 0135 { 0136 b2SimplexVertex* v = vertices + 0; 0137 v->indexA = 0; 0138 v->indexB = 0; 0139 b2Vec2 wALocal = proxyA->GetVertex(0); 0140 b2Vec2 wBLocal = proxyB->GetVertex(0); 0141 v->wA = b2Mul(transformA, wALocal); 0142 v->wB = b2Mul(transformB, wBLocal); 0143 v->w = v->wB - v->wA; 0144 m_count = 1; 0145 } 0146 } 0147 0148 void WriteCache(b2SimplexCache* cache) const 0149 { 0150 cache->metric = GetMetric(); 0151 cache->count = uint16(m_count); 0152 const b2SimplexVertex* vertices = &m_v1; 0153 for (int32 i = 0; i < m_count; ++i) 0154 { 0155 cache->indexA[i] = uint8(vertices[i].indexA); 0156 cache->indexB[i] = uint8(vertices[i].indexB); 0157 } 0158 } 0159 0160 b2Vec2 GetSearchDirection() const 0161 { 0162 switch (m_count) 0163 { 0164 case 1: 0165 return -m_v1.w; 0166 0167 case 2: 0168 { 0169 b2Vec2 e12 = m_v2.w - m_v1.w; 0170 qreal sgn = b2Cross(e12, -m_v1.w); 0171 if (sgn > 0.0f) 0172 { 0173 // Origin is left of e12. 0174 return b2Cross(1.0f, e12); 0175 } 0176 else 0177 { 0178 // Origin is right of e12. 0179 return b2Cross(e12, 1.0f); 0180 } 0181 } 0182 0183 default: 0184 b2Assert(false); 0185 return b2Vec2_zero; 0186 } 0187 } 0188 0189 b2Vec2 GetClosestPoint() const 0190 { 0191 switch (m_count) 0192 { 0193 case 0: 0194 b2Assert(false); 0195 return b2Vec2_zero; 0196 0197 case 1: 0198 return m_v1.w; 0199 0200 case 2: 0201 return m_v1.a * m_v1.w + m_v2.a * m_v2.w; 0202 0203 case 3: 0204 return b2Vec2_zero; 0205 0206 default: 0207 b2Assert(false); 0208 return b2Vec2_zero; 0209 } 0210 } 0211 0212 void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const 0213 { 0214 switch (m_count) 0215 { 0216 case 0: 0217 b2Assert(false); 0218 break; 0219 0220 case 1: 0221 *pA = m_v1.wA; 0222 *pB = m_v1.wB; 0223 break; 0224 0225 case 2: 0226 *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA; 0227 *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB; 0228 break; 0229 0230 case 3: 0231 *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA; 0232 *pB = *pA; 0233 break; 0234 0235 default: 0236 b2Assert(false); 0237 break; 0238 } 0239 } 0240 0241 qreal GetMetric() const 0242 { 0243 switch (m_count) 0244 { 0245 case 0: 0246 b2Assert(false); 0247 return 0.0; 0248 0249 case 1: 0250 return 0.0f; 0251 0252 case 2: 0253 return b2Distance(m_v1.w, m_v2.w); 0254 0255 case 3: 0256 return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w); 0257 0258 default: 0259 b2Assert(false); 0260 return 0.0f; 0261 } 0262 } 0263 0264 void Solve2(); 0265 void Solve3(); 0266 0267 b2SimplexVertex m_v1, m_v2, m_v3; 0268 int32 m_count; 0269 }; 0270 0271 0272 // Solve a line segment using barycentric coordinates. 0273 // 0274 // p = a1 * w1 + a2 * w2 0275 // a1 + a2 = 1 0276 // 0277 // The vector from the origin to the closest point on the line is 0278 // perpendicular to the line. 0279 // e12 = w2 - w1 0280 // dot(p, e) = 0 0281 // a1 * dot(w1, e) + a2 * dot(w2, e) = 0 0282 // 0283 // 2-by-2 linear system 0284 // [1 1 ][a1] = [1] 0285 // [w1.e12 w2.e12][a2] = [0] 0286 // 0287 // Define 0288 // d12_1 = dot(w2, e12) 0289 // d12_2 = -dot(w1, e12) 0290 // d12 = d12_1 + d12_2 0291 // 0292 // Solution 0293 // a1 = d12_1 / d12 0294 // a2 = d12_2 / d12 0295 void b2Simplex::Solve2() 0296 { 0297 b2Vec2 w1 = m_v1.w; 0298 b2Vec2 w2 = m_v2.w; 0299 b2Vec2 e12 = w2 - w1; 0300 0301 // w1 region 0302 qreal d12_2 = -b2Dot(w1, e12); 0303 if (d12_2 <= 0.0f) 0304 { 0305 // a2 <= 0, so we clamp it to 0 0306 m_v1.a = 1.0f; 0307 m_count = 1; 0308 return; 0309 } 0310 0311 // w2 region 0312 qreal d12_1 = b2Dot(w2, e12); 0313 if (d12_1 <= 0.0f) 0314 { 0315 // a1 <= 0, so we clamp it to 0 0316 m_v2.a = 1.0f; 0317 m_count = 1; 0318 m_v1 = m_v2; 0319 return; 0320 } 0321 0322 // Must be in e12 region. 0323 qreal inv_d12 = 1.0f / (d12_1 + d12_2); 0324 m_v1.a = d12_1 * inv_d12; 0325 m_v2.a = d12_2 * inv_d12; 0326 m_count = 2; 0327 } 0328 0329 // Possible regions: 0330 // - points[2] 0331 // - edge points[0]-points[2] 0332 // - edge points[1]-points[2] 0333 // - inside the triangle 0334 void b2Simplex::Solve3() 0335 { 0336 b2Vec2 w1 = m_v1.w; 0337 b2Vec2 w2 = m_v2.w; 0338 b2Vec2 w3 = m_v3.w; 0339 0340 // Edge12 0341 // [1 1 ][a1] = [1] 0342 // [w1.e12 w2.e12][a2] = [0] 0343 // a3 = 0 0344 b2Vec2 e12 = w2 - w1; 0345 qreal w1e12 = b2Dot(w1, e12); 0346 qreal w2e12 = b2Dot(w2, e12); 0347 qreal d12_1 = w2e12; 0348 qreal d12_2 = -w1e12; 0349 0350 // Edge13 0351 // [1 1 ][a1] = [1] 0352 // [w1.e13 w3.e13][a3] = [0] 0353 // a2 = 0 0354 b2Vec2 e13 = w3 - w1; 0355 qreal w1e13 = b2Dot(w1, e13); 0356 qreal w3e13 = b2Dot(w3, e13); 0357 qreal d13_1 = w3e13; 0358 qreal d13_2 = -w1e13; 0359 0360 // Edge23 0361 // [1 1 ][a2] = [1] 0362 // [w2.e23 w3.e23][a3] = [0] 0363 // a1 = 0 0364 b2Vec2 e23 = w3 - w2; 0365 qreal w2e23 = b2Dot(w2, e23); 0366 qreal w3e23 = b2Dot(w3, e23); 0367 qreal d23_1 = w3e23; 0368 qreal d23_2 = -w2e23; 0369 0370 // Triangle123 0371 qreal n123 = b2Cross(e12, e13); 0372 0373 qreal d123_1 = n123 * b2Cross(w2, w3); 0374 qreal d123_2 = n123 * b2Cross(w3, w1); 0375 qreal d123_3 = n123 * b2Cross(w1, w2); 0376 0377 // w1 region 0378 if (d12_2 <= 0.0f && d13_2 <= 0.0f) 0379 { 0380 m_v1.a = 1.0f; 0381 m_count = 1; 0382 return; 0383 } 0384 0385 // e12 0386 if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f) 0387 { 0388 qreal inv_d12 = 1.0f / (d12_1 + d12_2); 0389 m_v1.a = d12_1 * inv_d12; 0390 m_v2.a = d12_2 * inv_d12; 0391 m_count = 2; 0392 return; 0393 } 0394 0395 // e13 0396 if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f) 0397 { 0398 qreal inv_d13 = 1.0f / (d13_1 + d13_2); 0399 m_v1.a = d13_1 * inv_d13; 0400 m_v3.a = d13_2 * inv_d13; 0401 m_count = 2; 0402 m_v2 = m_v3; 0403 return; 0404 } 0405 0406 // w2 region 0407 if (d12_1 <= 0.0f && d23_2 <= 0.0f) 0408 { 0409 m_v2.a = 1.0f; 0410 m_count = 1; 0411 m_v1 = m_v2; 0412 return; 0413 } 0414 0415 // w3 region 0416 if (d13_1 <= 0.0f && d23_1 <= 0.0f) 0417 { 0418 m_v3.a = 1.0f; 0419 m_count = 1; 0420 m_v1 = m_v3; 0421 return; 0422 } 0423 0424 // e23 0425 if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f) 0426 { 0427 qreal inv_d23 = 1.0f / (d23_1 + d23_2); 0428 m_v2.a = d23_1 * inv_d23; 0429 m_v3.a = d23_2 * inv_d23; 0430 m_count = 2; 0431 m_v1 = m_v3; 0432 return; 0433 } 0434 0435 // Must be in triangle123 0436 qreal inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3); 0437 m_v1.a = d123_1 * inv_d123; 0438 m_v2.a = d123_2 * inv_d123; 0439 m_v3.a = d123_3 * inv_d123; 0440 m_count = 3; 0441 } 0442 0443 void b2Distance(b2DistanceOutput* output, 0444 b2SimplexCache* cache, 0445 const b2DistanceInput* input) 0446 { 0447 ++b2_gjkCalls; 0448 0449 const b2DistanceProxy* proxyA = &input->proxyA; 0450 const b2DistanceProxy* proxyB = &input->proxyB; 0451 0452 b2Transform transformA = input->transformA; 0453 b2Transform transformB = input->transformB; 0454 0455 // Initialize the simplex. 0456 b2Simplex simplex; 0457 simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB); 0458 0459 // Get simplex vertices as an array. 0460 b2SimplexVertex* vertices = &simplex.m_v1; 0461 const int32 k_maxIters = 20; 0462 0463 // These store the vertices of the last simplex so that we 0464 // can check for duplicates and prevent cycling. 0465 int32 saveA[3], saveB[3]; 0466 int32 saveCount = 0; 0467 0468 b2Vec2 closestPoint = simplex.GetClosestPoint(); 0469 qreal distanceSqr1 = closestPoint.LengthSquared(); 0470 qreal distanceSqr2 = distanceSqr1; 0471 0472 // Main iteration loop. 0473 int32 iter = 0; 0474 while (iter < k_maxIters) 0475 { 0476 // Copy simplex so we can identify duplicates. 0477 saveCount = simplex.m_count; 0478 for (int32 i = 0; i < saveCount; ++i) 0479 { 0480 saveA[i] = vertices[i].indexA; 0481 saveB[i] = vertices[i].indexB; 0482 } 0483 0484 switch (simplex.m_count) 0485 { 0486 case 1: 0487 break; 0488 0489 case 2: 0490 simplex.Solve2(); 0491 break; 0492 0493 case 3: 0494 simplex.Solve3(); 0495 break; 0496 0497 default: 0498 b2Assert(false); 0499 } 0500 0501 // If we have 3 points, then the origin is in the corresponding triangle. 0502 if (simplex.m_count == 3) 0503 { 0504 break; 0505 } 0506 0507 // Compute closest point. 0508 b2Vec2 p = simplex.GetClosestPoint(); 0509 distanceSqr2 = p.LengthSquared(); 0510 0511 // Ensure progress 0512 if (distanceSqr2 >= distanceSqr1) 0513 { 0514 //break; 0515 } 0516 distanceSqr1 = distanceSqr2; 0517 0518 // Get search direction. 0519 b2Vec2 d = simplex.GetSearchDirection(); 0520 0521 // Ensure the search direction is numerically fit. 0522 if (d.LengthSquared() < b2_epsilon * b2_epsilon) 0523 { 0524 // The origin is probably contained by a line segment 0525 // or triangle. Thus the shapes are overlapped. 0526 0527 // We can't return zero here even though there may be overlap. 0528 // In case the simplex is a point, segment, or triangle it is difficult 0529 // to determine if the origin is contained in the CSO or very close to it. 0530 break; 0531 } 0532 0533 // Compute a tentative new simplex vertex using support points. 0534 b2SimplexVertex* vertex = vertices + simplex.m_count; 0535 vertex->indexA = proxyA->GetSupport(b2MulT(transformA.R, -d)); 0536 vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA)); 0537 b2Vec2 wBLocal; 0538 vertex->indexB = proxyB->GetSupport(b2MulT(transformB.R, d)); 0539 vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB)); 0540 vertex->w = vertex->wB - vertex->wA; 0541 0542 // Iteration count is equated to the number of support point calls. 0543 ++iter; 0544 ++b2_gjkIters; 0545 0546 // Check for duplicate support points. This is the main termination criteria. 0547 bool duplicate = false; 0548 for (int32 i = 0; i < saveCount; ++i) 0549 { 0550 if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i]) 0551 { 0552 duplicate = true; 0553 break; 0554 } 0555 } 0556 0557 // If we found a duplicate support point we must exit to avoid cycling. 0558 if (duplicate) 0559 { 0560 break; 0561 } 0562 0563 // New vertex is ok and needed. 0564 ++simplex.m_count; 0565 } 0566 0567 b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter); 0568 0569 // Prepare output. 0570 simplex.GetWitnessPoints(&output->pointA, &output->pointB); 0571 output->distance = b2Distance(output->pointA, output->pointB); 0572 output->iterations = iter; 0573 0574 // Cache the simplex. 0575 simplex.WriteCache(cache); 0576 0577 // Apply radii if requested. 0578 if (input->useRadii) 0579 { 0580 qreal rA = proxyA->m_radius; 0581 qreal rB = proxyB->m_radius; 0582 0583 if (output->distance > rA + rB && output->distance > b2_epsilon) 0584 { 0585 // Shapes are still no overlapped. 0586 // Move the witness points to the outer surface. 0587 output->distance -= rA + rB; 0588 b2Vec2 normal = output->pointB - output->pointA; 0589 normal.Normalize(); 0590 output->pointA += rA * normal; 0591 output->pointB -= rB * normal; 0592 } 0593 else 0594 { 0595 // Shapes are overlapped when radii are considered. 0596 // Move the witness points to the middle. 0597 b2Vec2 p = 0.5f * (output->pointA + output->pointB); 0598 output->pointA = p; 0599 output->pointB = p; 0600 output->distance = 0.0f; 0601 } 0602 } 0603 }