b2_time_of_impact.cpp
Go to the documentation of this file.
1 // MIT License
2 
3 // Copyright (c) 2019 Erin Catto
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 
23 #include "box2d/b2_collision.h"
24 #include "box2d/b2_distance.h"
25 #include "box2d/b2_circle_shape.h"
26 #include "box2d/b2_polygon_shape.h"
28 #include "box2d/b2_timer.h"
29 
30 #include <stdio.h>
31 
35 
36 //
38 {
39  enum Type
40  {
44  };
45 
46  // TODO_ERIN might not need to return the separation
47 
48  float Initialize(const b2SimplexCache* cache,
49  const b2DistanceProxy* proxyA, const b2Sweep& sweepA,
50  const b2DistanceProxy* proxyB, const b2Sweep& sweepB,
51  float t1)
52  {
53  m_proxyA = proxyA;
54  m_proxyB = proxyB;
55  int32 count = cache->count;
56  b2Assert(0 < count && count < 3);
57 
58  m_sweepA = sweepA;
59  m_sweepB = sweepB;
60 
61  b2Transform xfA, xfB;
62  m_sweepA.GetTransform(&xfA, t1);
63  m_sweepB.GetTransform(&xfB, t1);
64 
65  if (count == 1)
66  {
67  m_type = e_points;
68  b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]);
69  b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
70  b2Vec2 pointA = b2Mul(xfA, localPointA);
71  b2Vec2 pointB = b2Mul(xfB, localPointB);
72  m_axis = pointB - pointA;
73  float s = m_axis.Normalize();
74  return s;
75  }
76  else if (cache->indexA[0] == cache->indexA[1])
77  {
78  // Two points on B and one on A.
79  m_type = e_faceB;
80  b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]);
81  b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]);
82 
83  m_axis = b2Cross(localPointB2 - localPointB1, 1.0f);
84  m_axis.Normalize();
85  b2Vec2 normal = b2Mul(xfB.q, m_axis);
86 
87  m_localPoint = 0.5f * (localPointB1 + localPointB2);
88  b2Vec2 pointB = b2Mul(xfB, m_localPoint);
89 
90  b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]);
91  b2Vec2 pointA = b2Mul(xfA, localPointA);
92 
93  float s = b2Dot(pointA - pointB, normal);
94  if (s < 0.0f)
95  {
96  m_axis = -m_axis;
97  s = -s;
98  }
99  return s;
100  }
101  else
102  {
103  // Two points on A and one or two points on B.
104  m_type = e_faceA;
105  b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]);
106  b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]);
107 
108  m_axis = b2Cross(localPointA2 - localPointA1, 1.0f);
109  m_axis.Normalize();
110  b2Vec2 normal = b2Mul(xfA.q, m_axis);
111 
112  m_localPoint = 0.5f * (localPointA1 + localPointA2);
113  b2Vec2 pointA = b2Mul(xfA, m_localPoint);
114 
115  b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
116  b2Vec2 pointB = b2Mul(xfB, localPointB);
117 
118  float s = b2Dot(pointB - pointA, normal);
119  if (s < 0.0f)
120  {
121  m_axis = -m_axis;
122  s = -s;
123  }
124  return s;
125  }
126  }
127 
128  //
129  float FindMinSeparation(int32* indexA, int32* indexB, float t) const
130  {
131  b2Transform xfA, xfB;
132  m_sweepA.GetTransform(&xfA, t);
133  m_sweepB.GetTransform(&xfB, t);
134 
135  switch (m_type)
136  {
137  case e_points:
138  {
139  b2Vec2 axisA = b2MulT(xfA.q, m_axis);
140  b2Vec2 axisB = b2MulT(xfB.q, -m_axis);
141 
142  *indexA = m_proxyA->GetSupport(axisA);
143  *indexB = m_proxyB->GetSupport(axisB);
144 
145  b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
146  b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
147 
148  b2Vec2 pointA = b2Mul(xfA, localPointA);
149  b2Vec2 pointB = b2Mul(xfB, localPointB);
150 
151  float separation = b2Dot(pointB - pointA, m_axis);
152  return separation;
153  }
154 
155  case e_faceA:
156  {
157  b2Vec2 normal = b2Mul(xfA.q, m_axis);
158  b2Vec2 pointA = b2Mul(xfA, m_localPoint);
159 
160  b2Vec2 axisB = b2MulT(xfB.q, -normal);
161 
162  *indexA = -1;
163  *indexB = m_proxyB->GetSupport(axisB);
164 
165  b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
166  b2Vec2 pointB = b2Mul(xfB, localPointB);
167 
168  float separation = b2Dot(pointB - pointA, normal);
169  return separation;
170  }
171 
172  case e_faceB:
173  {
174  b2Vec2 normal = b2Mul(xfB.q, m_axis);
175  b2Vec2 pointB = b2Mul(xfB, m_localPoint);
176 
177  b2Vec2 axisA = b2MulT(xfA.q, -normal);
178 
179  *indexB = -1;
180  *indexA = m_proxyA->GetSupport(axisA);
181 
182  b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
183  b2Vec2 pointA = b2Mul(xfA, localPointA);
184 
185  float separation = b2Dot(pointA - pointB, normal);
186  return separation;
187  }
188 
189  default:
190  b2Assert(false);
191  *indexA = -1;
192  *indexB = -1;
193  return 0.0f;
194  }
195  }
196 
197  //
198  float Evaluate(int32 indexA, int32 indexB, float t) const
199  {
200  b2Transform xfA, xfB;
201  m_sweepA.GetTransform(&xfA, t);
202  m_sweepB.GetTransform(&xfB, t);
203 
204  switch (m_type)
205  {
206  case e_points:
207  {
208  b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
209  b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
210 
211  b2Vec2 pointA = b2Mul(xfA, localPointA);
212  b2Vec2 pointB = b2Mul(xfB, localPointB);
213  float separation = b2Dot(pointB - pointA, m_axis);
214 
215  return separation;
216  }
217 
218  case e_faceA:
219  {
220  b2Vec2 normal = b2Mul(xfA.q, m_axis);
221  b2Vec2 pointA = b2Mul(xfA, m_localPoint);
222 
223  b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
224  b2Vec2 pointB = b2Mul(xfB, localPointB);
225 
226  float separation = b2Dot(pointB - pointA, normal);
227  return separation;
228  }
229 
230  case e_faceB:
231  {
232  b2Vec2 normal = b2Mul(xfB.q, m_axis);
233  b2Vec2 pointB = b2Mul(xfB, m_localPoint);
234 
235  b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
236  b2Vec2 pointA = b2Mul(xfA, localPointA);
237 
238  float separation = b2Dot(pointA - pointB, normal);
239  return separation;
240  }
241 
242  default:
243  b2Assert(false);
244  return 0.0f;
245  }
246  }
247 
254 };
255 
256 // CCD via the local separating axis method. This seeks progression
257 // by computing the largest time at which separation is maintained.
258 void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input)
259 {
260  b2Timer timer;
261 
262  ++b2_toiCalls;
263 
264  output->state = b2TOIOutput::e_unknown;
265  output->t = input->tMax;
266 
267  const b2DistanceProxy* proxyA = &input->proxyA;
268  const b2DistanceProxy* proxyB = &input->proxyB;
269 
270  b2Sweep sweepA = input->sweepA;
271  b2Sweep sweepB = input->sweepB;
272 
273  // Large rotations can make the root finder fail, so we normalize the
274  // sweep angles.
275  sweepA.Normalize();
276  sweepB.Normalize();
277 
278  float tMax = input->tMax;
279 
280  float totalRadius = proxyA->m_radius + proxyB->m_radius;
281  float target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop);
282  float tolerance = 0.25f * b2_linearSlop;
283  b2Assert(target > tolerance);
284 
285  float t1 = 0.0f;
286  const int32 k_maxIterations = 20; // TODO_ERIN b2Settings
287  int32 iter = 0;
288 
289  // Prepare input for distance query.
290  b2SimplexCache cache;
291  cache.count = 0;
292  b2DistanceInput distanceInput;
293  distanceInput.proxyA = input->proxyA;
294  distanceInput.proxyB = input->proxyB;
295  distanceInput.useRadii = false;
296 
297  // The outer loop progressively attempts to compute new separating axes.
298  // This loop terminates when an axis is repeated (no progress is made).
299  for(;;)
300  {
301  b2Transform xfA, xfB;
302  sweepA.GetTransform(&xfA, t1);
303  sweepB.GetTransform(&xfB, t1);
304 
305  // Get the distance between shapes. We can also use the results
306  // to get a separating axis.
307  distanceInput.transformA = xfA;
308  distanceInput.transformB = xfB;
309  b2DistanceOutput distanceOutput;
310  b2Distance(&distanceOutput, &cache, &distanceInput);
311 
312  // If the shapes are overlapped, we give up on continuous collision.
313  if (distanceOutput.distance <= 0.0f)
314  {
315  // Failure!
317  output->t = 0.0f;
318  break;
319  }
320 
321  if (distanceOutput.distance < target + tolerance)
322  {
323  // Victory!
324  output->state = b2TOIOutput::e_touching;
325  output->t = t1;
326  break;
327  }
328 
329  // Initialize the separating axis.
331  fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1);
332 #if 0
333  // Dump the curve seen by the root finder
334  {
335  const int32 N = 100;
336  float dx = 1.0f / N;
337  float xs[N+1];
338  float fs[N+1];
339 
340  float x = 0.0f;
341 
342  for (int32 i = 0; i <= N; ++i)
343  {
344  sweepA.GetTransform(&xfA, x);
345  sweepB.GetTransform(&xfB, x);
346  float f = fcn.Evaluate(xfA, xfB) - target;
347 
348  printf("%g %g\n", x, f);
349 
350  xs[i] = x;
351  fs[i] = f;
352 
353  x += dx;
354  }
355  }
356 #endif
357 
358  // Compute the TOI on the separating axis. We do this by successively
359  // resolving the deepest point. This loop is bounded by the number of vertices.
360  bool done = false;
361  float t2 = tMax;
362  int32 pushBackIter = 0;
363  for (;;)
364  {
365  // Find the deepest point at t2. Store the witness point indices.
366  int32 indexA, indexB;
367  float s2 = fcn.FindMinSeparation(&indexA, &indexB, t2);
368 
369  // Is the final configuration separated?
370  if (s2 > target + tolerance)
371  {
372  // Victory!
374  output->t = tMax;
375  done = true;
376  break;
377  }
378 
379  // Has the separation reached tolerance?
380  if (s2 > target - tolerance)
381  {
382  // Advance the sweeps
383  t1 = t2;
384  break;
385  }
386 
387  // Compute the initial separation of the witness points.
388  float s1 = fcn.Evaluate(indexA, indexB, t1);
389 
390  // Check for initial overlap. This might happen if the root finder
391  // runs out of iterations.
392  if (s1 < target - tolerance)
393  {
394  output->state = b2TOIOutput::e_failed;
395  output->t = t1;
396  done = true;
397  break;
398  }
399 
400  // Check for touching
401  if (s1 <= target + tolerance)
402  {
403  // Victory! t1 should hold the TOI (could be 0.0).
404  output->state = b2TOIOutput::e_touching;
405  output->t = t1;
406  done = true;
407  break;
408  }
409 
410  // Compute 1D root of: f(x) - target = 0
411  int32 rootIterCount = 0;
412  float a1 = t1, a2 = t2;
413  for (;;)
414  {
415  // Use a mix of the secant rule and bisection.
416  float t;
417  if (rootIterCount & 1)
418  {
419  // Secant rule to improve convergence.
420  t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
421  }
422  else
423  {
424  // Bisection to guarantee progress.
425  t = 0.5f * (a1 + a2);
426  }
427 
428  ++rootIterCount;
429  ++b2_toiRootIters;
430 
431  float s = fcn.Evaluate(indexA, indexB, t);
432 
433  if (b2Abs(s - target) < tolerance)
434  {
435  // t2 holds a tentative value for t1
436  t2 = t;
437  break;
438  }
439 
440  // Ensure we continue to bracket the root.
441  if (s > target)
442  {
443  a1 = t;
444  s1 = s;
445  }
446  else
447  {
448  a2 = t;
449  s2 = s;
450  }
451 
452  if (rootIterCount == 50)
453  {
454  break;
455  }
456  }
457 
458  b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount);
459 
460  ++pushBackIter;
461 
462  if (pushBackIter == b2_maxPolygonVertices)
463  {
464  break;
465  }
466  }
467 
468  ++iter;
469  ++b2_toiIters;
470 
471  if (done)
472  {
473  break;
474  }
475 
476  if (iter == k_maxIterations)
477  {
478  // Root finder got stuck. Semi-victory.
479  output->state = b2TOIOutput::e_failed;
480  output->t = t1;
481  break;
482  }
483  }
484 
486 
487  float time = timer.GetMilliseconds();
489  b2_toiTime += time;
490 }
b2Vec2 b2Mul(const b2Mat22 &A, const b2Vec2 &v)
Definition: b2_math.h:422
float b2Dot(const b2Vec2 &a, const b2Vec2 &b)
Perform the dot product on two vectors.
Definition: b2_math.h:395
const b2DistanceProxy * m_proxyA
b2Rot q
Definition: b2_math.h:361
f
#define B2_API
Definition: b2_api.h:49
uint8 indexA[3]
vertices on shape A
Definition: b2_distance.h:69
B2_API int32 b2_toiCalls
float Evaluate(int32 indexA, int32 indexB, float t) const
XmlRpcServer s
b2DistanceProxy proxyA
Definition: b2_distance.h:78
#define b2_linearSlop
Definition: b2_common.h:65
Input parameters for b2TimeOfImpact.
geometry_msgs::TransformStamped t
A 2D column vector.
Definition: b2_math.h:41
b2DistanceProxy proxyA
signed int int32
Definition: b2_types.h:28
b2DistanceProxy proxyB
B2_API int32 b2_toiMaxRootIters
int32 GetSupport(const b2Vec2 &d) const
Get the supporting vertex index in the given direction.
Definition: b2_distance.h:137
b2Transform transformA
Definition: b2_distance.h:80
T b2Max(T a, T b)
Definition: b2_math.h:637
float b2Cross(const b2Vec2 &a, const b2Vec2 &b)
Perform the cross product on two vectors. In 2D this produces a scalar.
Definition: b2_math.h:401
b2Transform transformB
Definition: b2_distance.h:81
B2_API void b2Distance(b2DistanceOutput *output, b2SimplexCache *cache, const b2DistanceInput *input)
uint8 indexB[3]
vertices on shape B
Definition: b2_distance.h:70
B2_API int32 b2_toiRootIters
float FindMinSeparation(int32 *indexA, int32 *indexB, float t) const
const b2DistanceProxy * m_proxyB
Output for b2Distance.
Definition: b2_distance.h:86
void Normalize()
Normalize the angles.
Definition: b2_math.h:707
Output parameters for b2TimeOfImpact.
b2Vec2 b2MulT(const b2Mat22 &A, const b2Vec2 &v)
Definition: b2_math.h:429
float Initialize(const b2SimplexCache *cache, const b2DistanceProxy *proxyA, const b2Sweep &sweepA, const b2DistanceProxy *proxyB, const b2Sweep &sweepB, float t1)
float Normalize()
Convert this vector into a unit vector. Returns the length.
Definition: b2_math.h:102
B2_API float b2_toiTime
#define b2_maxPolygonVertices
Definition: b2_settings.h:53
B2_API float b2_toiMaxTime
T b2Abs(T a)
Definition: b2_math.h:610
B2_API int32 b2_toiIters
void b2TimeOfImpact(b2TOIOutput *output, const b2TOIInput *input)
void GetTransform(b2Transform *transform, float beta) const
Definition: b2_math.h:687
const b2Vec2 & GetVertex(int32 index) const
Get a vertex by index. Used by b2Distance.
Definition: b2_distance.h:131
#define b2Assert(A)
Definition: b2_common.h:37
b2DistanceProxy proxyB
Definition: b2_distance.h:79
B2_API int32 b2_toiMaxIters
float GetMilliseconds() const
Get the time since construction or the last reset.
Definition: b2_timer.cpp:120


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:19