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 }