World.cpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
3  * Modified work Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 
35 
49 
54 
59 
64 
65 #include <algorithm>
66 #include <new>
67 #include <functional>
68 #include <type_traits>
69 #include <memory>
70 #include <set>
71 #include <vector>
72 #include <unordered_map>
73 
74 #ifdef DO_PAR_UNSEQ
75 #include <atomic>
76 #endif
77 
78 //#define DO_THREADED
79 #if defined(DO_THREADED)
80 #include <future>
81 #endif
82 
83 #define PLAYRHO_MAGIC(x) (x)
84 
85 using std::for_each;
86 using std::remove;
87 using std::sort;
88 using std::transform;
89 using std::unique;
90 
91 namespace playrho {
92 namespace d2 {
93 
94 using playrho::size;
95 
97 using BodyPtr = Body*;
98 
100 using BodyConstraintsPair = std::pair<const Body* const, BodyConstraint*>;
101 
103 using BodyConstraints = std::vector<BodyConstraint>;
104 
106 using PositionConstraints = std::vector<PositionConstraint>;
107 
109 using VelocityConstraints = std::vector<VelocityConstraint>;
110 
111 namespace {
112 
113  inline void IntegratePositions(BodyConstraints& bodies, Time h)
114  {
115  assert(IsValid(h));
116  for_each(begin(bodies), end(bodies), [&](BodyConstraint& bc) {
117  const auto velocity = bc.GetVelocity();
118  const auto translation = h * velocity.linear;
119  const auto rotation = h * velocity.angular;
120  bc.SetPosition(bc.GetPosition() + Position{translation, rotation});
121  });
122  }
123 
130  inline void Report(ContactListener& listener,
131  Span<Contact*> contacts,
132  const VelocityConstraints& constraints,
134  {
135  const auto numContacts = size(contacts);
136  for (auto i = decltype(numContacts){0}; i < numContacts; ++i)
137  {
138  listener.PostSolve(*contacts[i], GetContactImpulses(constraints[i]), solved);
139  }
140  }
141 
142  inline void AssignImpulses(Manifold& var, const VelocityConstraint& vc)
143  {
144  assert(var.GetPointCount() >= vc.GetPointCount());
145 
146  auto assignProc = [&](VelocityConstraint::size_type i) {
148  };
149 #if 0
150  // Branch free assignment causes problems in TilesComeToRest test.
151  assignProc(1);
152  assignProc(0);
153 #else
154  const auto count = vc.GetPointCount();
155  for (auto i = decltype(count){0}; i < count; ++i)
156  {
157  assignProc(i);
158  }
159 #endif
160  }
161 
162  inline void WarmStartVelocities(const VelocityConstraints& velConstraints)
163  {
164  for_each(cbegin(velConstraints), cend(velConstraints),
165  [&](const VelocityConstraint& vc) {
166  const auto vp = CalcWarmStartVelocityDeltas(vc);
167  const auto bodyA = vc.GetBodyA();
168  const auto bodyB = vc.GetBodyB();
169  bodyA->SetVelocity(bodyA->GetVelocity() + std::get<0>(vp));
170  bodyB->SetVelocity(bodyB->GetVelocity() + std::get<1>(vp));
171  });
172  }
173 
174  BodyConstraintsMap GetBodyConstraintsMap(const Island::Bodies& bodies,
175  BodyConstraints &bodyConstraints)
176  {
177  auto map = BodyConstraintsMap{};
178  map.reserve(size(bodies));
179  for_each(cbegin(bodies), cend(bodies), [&](const BodyPtr& body) {
180  const auto i = static_cast<size_t>(&body - data(bodies));
181  assert(i < size(bodies));
182 #ifdef USE_VECTOR_MAP
183  map.push_back(BodyConstraintPair{body, &bodyConstraints[i]});
184 #else
185  map[body] = &bodyConstraints[i];
186 #endif
187  });
188 #ifdef USE_VECTOR_MAP
189  sort(begin(map), end(map), [](BodyConstraintPair a, BodyConstraintPair b) {
190  return std::get<const Body*>(a) < std::get<const Body*>(b);
191  });
192 #endif
193  return map;
194  }
195 
196  BodyConstraints GetBodyConstraints(const Island::Bodies& bodies, Time h, MovementConf conf)
197  {
198  auto constraints = BodyConstraints{};
199  constraints.reserve(size(bodies));
200  transform(cbegin(bodies), cend(bodies), back_inserter(constraints), [&](const BodyPtr &b) {
201  return GetBodyConstraint(*b, h, conf);
202  });
203  return constraints;
204  }
205 
206  PositionConstraints GetPositionConstraints(const Island::Contacts& contacts,
207  BodyConstraintsMap& bodies)
208  {
209  auto constraints = PositionConstraints{};
210  constraints.reserve(size(contacts));
211  transform(cbegin(contacts), cend(contacts), back_inserter(constraints), [&](const Contact *contact) {
212  const auto& manifold = static_cast<const Contact*>(contact)->GetManifold();
213 
214  const auto& fixtureA = *(GetFixtureA(*contact));
215  const auto& fixtureB = *(GetFixtureB(*contact));
216  const auto indexA = GetChildIndexA(*contact);
217  const auto indexB = GetChildIndexB(*contact);
218 
219  const auto bodyA = GetBodyA(*contact);
220  const auto shapeA = fixtureA.GetShape();
221 
222  const auto bodyB = GetBodyB(*contact);
223  const auto shapeB = fixtureB.GetShape();
224 
225  const auto bodyConstraintA = At(bodies, bodyA);
226  const auto bodyConstraintB = At(bodies, bodyB);
227 
228  const auto radiusA = GetVertexRadius(shapeA, indexA);
229  const auto radiusB = GetVertexRadius(shapeB, indexB);
230 
231  return PositionConstraint{
232  manifold, *bodyConstraintA, radiusA, *bodyConstraintB, radiusB
233  };
234  });
235  return constraints;
236  }
237 
245  VelocityConstraints GetVelocityConstraints(const Island::Contacts& contacts,
246  BodyConstraintsMap& bodies,
247  const VelocityConstraint::Conf conf)
248  {
249  auto velConstraints = VelocityConstraints{};
250  velConstraints.reserve(size(contacts));
251  transform(cbegin(contacts), cend(contacts), back_inserter(velConstraints), [&](const ContactPtr& contact) {
252  const auto& manifold = contact->GetManifold();
253  const auto fixtureA = contact->GetFixtureA();
254  const auto fixtureB = contact->GetFixtureB();
255  const auto friction = contact->GetFriction();
256  const auto restitution = contact->GetRestitution();
257  const auto tangentSpeed = contact->GetTangentSpeed();
258  const auto indexA = GetChildIndexA(*contact);
259  const auto indexB = GetChildIndexB(*contact);
260 
261  const auto bodyA = fixtureA->GetBody();
262  const auto shapeA = fixtureA->GetShape();
263 
264  const auto bodyB = fixtureB->GetBody();
265  const auto shapeB = fixtureB->GetShape();
266 
267  const auto bodyConstraintA = At(bodies, bodyA);
268  const auto bodyConstraintB = At(bodies, bodyB);
269 
270  const auto radiusA = GetVertexRadius(shapeA, indexA);
271  const auto radiusB = GetVertexRadius(shapeB, indexB);
272 
273  const auto xfA = GetTransformation(bodyConstraintA->GetPosition(),
274  bodyConstraintA->GetLocalCenter());
275  const auto xfB = GetTransformation(bodyConstraintB->GetPosition(),
276  bodyConstraintB->GetLocalCenter());
277  const auto worldManifold = GetWorldManifold(manifold, xfA, radiusA, xfB, radiusB);
278 
279  return VelocityConstraint{friction, restitution, tangentSpeed, worldManifold,
280  *bodyConstraintA, *bodyConstraintB, conf};
281  });
282  return velConstraints;
283  }
284 
290  Momentum SolveVelocityConstraintsViaGS(VelocityConstraints& velConstraints)
291  {
292  auto maxIncImpulse = 0_Ns;
293  for_each(begin(velConstraints), end(velConstraints), [&](VelocityConstraint& vc)
294  {
295  maxIncImpulse = std::max(maxIncImpulse, GaussSeidel::SolveVelocityConstraint(vc));
296  });
297  return maxIncImpulse;
298  }
299 
306  Length SolvePositionConstraintsViaGS(PositionConstraints& posConstraints,
308  {
309  auto minSeparation = std::numeric_limits<Length>::infinity();
310 
311  for_each(begin(posConstraints), end(posConstraints), [&](PositionConstraint &pc) {
312  assert(pc.GetBodyA() != pc.GetBodyB()); // Confirms ContactManager::Add() did its job.
313  const auto res = GaussSeidel::SolvePositionConstraint(pc, true, true, conf);
314  pc.GetBodyA()->SetPosition(res.pos_a);
315  pc.GetBodyB()->SetPosition(res.pos_b);
316  minSeparation = std::min(minSeparation, res.min_separation);
317  });
318 
319  return minSeparation;
320  }
321 
322 #if 0
323  Length SolvePositionConstraints(PositionConstraints& posConstraints,
340  const BodyConstraint* bodyConstraintA, const BodyConstraint* bodyConstraintB,
342  {
343  auto minSeparation = std::numeric_limits<Length>::infinity();
344 
345  for_each(begin(posConstraints), end(posConstraints), [&](PositionConstraint &pc) {
346  const auto moveA = (pc.GetBodyA() == bodyConstraintA) || (pc.GetBodyA() == bodyConstraintB);
347  const auto moveB = (pc.GetBodyB() == bodyConstraintA) || (pc.GetBodyB() == bodyConstraintB);
348  const auto res = SolvePositionConstraint(pc, moveA, moveB, conf);
349  pc.GetBodyA()->SetPosition(res.pos_a);
350  pc.GetBodyB()->SetPosition(res.pos_b);
351  minSeparation = std::min(minSeparation, res.min_separation);
352  });
353 
354  return minSeparation;
355  }
356 #endif
357 
358  inline Time GetUnderActiveTime(const Body& b, const StepConf& conf) noexcept
359  {
360  const auto underactive = IsUnderActive(b.GetVelocity(), conf.linearSleepTolerance,
361  conf.angularSleepTolerance);
362  const auto sleepable = b.IsSleepingAllowed();
363  return (sleepable && underactive)? b.GetUnderActiveTime() + conf.GetTime(): 0_s;
364  }
365 
366  inline Time UpdateUnderActiveTimes(Island::Bodies& bodies, const StepConf& conf)
367  {
368  auto minUnderActiveTime = std::numeric_limits<Time>::infinity();
369  for_each(cbegin(bodies), cend(bodies), [&](Body *b)
370  {
371  if (b->IsSpeedable())
372  {
373  const auto underActiveTime = GetUnderActiveTime(*b, conf);
374  b->SetUnderActiveTime(underActiveTime);
375  minUnderActiveTime = std::min(minUnderActiveTime, underActiveTime);
376  }
377  });
378  return minUnderActiveTime;
379  }
380 
381  inline BodyCounter Sleepem(Island::Bodies& bodies)
382  {
383  auto unawoken = BodyCounter{0};
384  for_each(cbegin(bodies), cend(bodies), [&](Body *b)
385  {
386  if (Unawaken(*b))
387  {
388  ++unawoken;
389  }
390  });
391  return unawoken;
392  }
393 
394  inline bool IsValidForTime(TOIOutput::State state) noexcept
395  {
396  return state == TOIOutput::e_touching;
397  }
398 
399  void FlagContactsForFiltering(const Body& bodyA, const Body& bodyB) noexcept
400  {
401  for (auto& ci: bodyB.GetContacts())
402  {
403  const auto contact = GetContactPtr(ci);
404  const auto fA = contact->GetFixtureA();
405  const auto fB = contact->GetFixtureB();
406  const auto bA = fA->GetBody();
407  const auto bB = fB->GetBody();
408  const auto other = (bA != &bodyB)? bA: bB;
409  if (other == &bodyA)
410  {
411  // Flag the contact for filtering at the next time step (where either
412  // body is awake).
413  contact->FlagForFiltering();
414  }
415  }
416  }
417 
418 } // anonymous namespace
419 
421  m_tree{def.initialTreeSize},
422  m_minVertexRadius{def.minVertexRadius},
423  m_maxVertexRadius{def.maxVertexRadius}
424 {
425  if (def.minVertexRadius > def.maxVertexRadius)
426  {
427  throw InvalidArgument("max vertex radius must be >= min vertex radius");
428  }
429  m_proxyKeys.reserve(1024);
430  m_proxies.reserve(1024);
431 }
432 
433 World::World(const World& other):
434  m_tree{other.m_tree},
435  m_destructionListener{other.m_destructionListener},
436  m_contactListener{other.m_contactListener},
437  m_flags{other.m_flags},
438  m_inv_dt0{other.m_inv_dt0},
439  m_minVertexRadius{other.m_minVertexRadius},
440  m_maxVertexRadius{other.m_maxVertexRadius}
441 {
442  auto bodyMap = std::map<const Body*, Body*>();
443  auto fixtureMap = std::map<const Fixture*, Fixture*>();
444  CopyBodies(bodyMap, fixtureMap, other.GetBodies());
445  CopyJoints(bodyMap, other.GetJoints());
446  CopyContacts(bodyMap, fixtureMap, other.GetContacts());
447 }
448 
450 {
451  Clear();
452 
453  m_destructionListener = other.m_destructionListener;
454  m_contactListener = other.m_contactListener;
455  m_flags = other.m_flags;
456  m_inv_dt0 = other.m_inv_dt0;
457  m_minVertexRadius = other.m_minVertexRadius;
458  m_maxVertexRadius = other.m_maxVertexRadius;
459  m_tree = other.m_tree;
460 
461  auto bodyMap = std::map<const Body*, Body*>();
462  auto fixtureMap = std::map<const Fixture*, Fixture*>();
463  CopyBodies(bodyMap, fixtureMap, other.GetBodies());
464  CopyJoints(bodyMap, other.GetJoints());
465  CopyContacts(bodyMap, fixtureMap, other.GetContacts());
466 
467  return *this;
468 }
469 
470 World::~World() noexcept
471 {
472  InternalClear();
473 }
474 
476 {
477  if (IsLocked())
478  {
479  throw WrongState("World::Clear: world is locked");
480  }
481  InternalClear();
482 }
483 
484 void World::InternalClear() noexcept
485 {
486  m_proxyKeys.clear();
487  m_proxies.clear();
488  m_fixturesForProxies.clear();
489  m_bodiesForProxies.clear();
490 
491  for_each(cbegin(m_joints), cend(m_joints), [&](const Joint *j) {
492  if (m_destructionListener)
493  {
494  m_destructionListener->SayGoodbye(*j);
495  }
496  JointAtty::Destroy(j);
497  });
498  for_each(begin(m_bodies), end(m_bodies), [&](Bodies::value_type& body) {
499  auto& b = GetRef(body);
500  BodyAtty::ClearContacts(b);
501  BodyAtty::ClearJoints(b);
502  BodyAtty::ClearFixtures(b, [&](Fixture& fixture) {
503  if (m_destructionListener)
504  {
505  m_destructionListener->SayGoodbye(fixture);
506  }
507  DestroyProxies(fixture);
508  });
509  });
510 
511  for_each(cbegin(m_bodies), cend(m_bodies), [&](const Bodies::value_type& b) {
512  BodyAtty::Delete(GetPtr(b));
513  });
514  for_each(cbegin(m_contacts), cend(m_contacts), [&](const Contacts::value_type& c){
515  delete GetPtr(std::get<Contact*>(c));
516  });
517 
518  m_bodies.clear();
519  m_joints.clear();
520  m_contacts.clear();
521 }
522 
523 void World::CopyBodies(std::map<const Body*, Body*>& bodyMap,
524  std::map<const Fixture*, Fixture*>& fixtureMap,
525  SizedRange<World::Bodies::const_iterator> range)
526 {
527  for (const auto& otherBody: range)
528  {
529  const auto newBody = CreateBody(GetBodyConf(GetRef(otherBody)));
530  for (const auto& of: GetRef(otherBody).GetFixtures())
531  {
532  const auto& otherFixture = GetRef(of);
533  const auto shape = otherFixture.GetShape();
534  const auto fixtureConf = GetFixtureConf(otherFixture);
535  const auto newFixture = FixtureAtty::Create(*newBody, fixtureConf, shape);
536  BodyAtty::AddFixture(*newBody, newFixture);
537  fixtureMap[&otherFixture] = newFixture;
538  const auto childCount = otherFixture.GetProxyCount();
539  auto proxies = std::make_unique<FixtureProxy[]>(childCount);
540  for (auto childIndex = decltype(childCount){0}; childIndex < childCount; ++childIndex)
541  {
542  const auto fp = otherFixture.GetProxy(childIndex);
543  proxies[childIndex] = FixtureProxy{fp.treeId};
544  const auto newData = DynamicTree::LeafData{newBody, newFixture, childIndex};
545  m_tree.SetLeafData(fp.treeId, newData);
546  }
547  FixtureAtty::SetProxies(*newFixture, std::move(proxies), childCount);
548  }
549  newBody->SetMassData(GetMassData(GetRef(otherBody)));
550  bodyMap[GetPtr(otherBody)] = newBody;
551  }
552 }
553 
554 void World::CopyContacts(const std::map<const Body*, Body*>& bodyMap,
555  const std::map<const Fixture*, Fixture*>& fixtureMap,
556  SizedRange<World::Contacts::const_iterator> range)
557 {
558  for (const auto& contact: range)
559  {
560  auto& otherContact = GetRef(std::get<Contact*>(contact));
561  const auto otherFixtureA = otherContact.GetFixtureA();
562  const auto otherFixtureB = otherContact.GetFixtureB();
563  const auto childIndexA = otherContact.GetChildIndexA();
564  const auto childIndexB = otherContact.GetChildIndexB();
565  const auto newFixtureA = fixtureMap.at(otherFixtureA);
566  const auto newFixtureB = fixtureMap.at(otherFixtureB);
567  const auto newBodyA = bodyMap.at(otherFixtureA->GetBody());
568  const auto newBodyB = bodyMap.at(otherFixtureB->GetBody());
569  const auto newContact = new Contact{newFixtureA, childIndexA, newFixtureB, childIndexB};
570  assert(newContact);
571  if (newContact)
572  {
573  const auto key = std::get<ContactKey>(contact);
574  m_contacts.push_back(KeyedContactPtr{key, newContact});
575 
576  BodyAtty::Insert(*newBodyA, key, newContact);
577  BodyAtty::Insert(*newBodyB, key, newContact);
578  // No need to wake up the bodies - this should already be done due to above copy
579 
580  newContact->SetFriction(otherContact.GetFriction());
581  newContact->SetRestitution(otherContact.GetRestitution());
582  newContact->SetTangentSpeed(otherContact.GetTangentSpeed());
583  auto& manifold = ContactAtty::GetMutableManifold(*newContact);
584  manifold = otherContact.GetManifold();
585  ContactAtty::CopyFlags(*newContact, otherContact);
586  if (otherContact.HasValidToi())
587  {
588  ContactAtty::SetToi(*newContact, otherContact.GetToi());
589  }
590  ContactAtty::SetToiCount(*newContact, otherContact.GetToiCount());
591  }
592  }
593 }
594 
595 void World::CopyJoints(const std::map<const Body*, Body*>& bodyMap,
596  SizedRange<World::Joints::const_iterator> range)
597 {
598  class JointCopier: public ConstJointVisitor
599  {
600  public:
601 
602  JointCopier(World& w, std::map<const Body*, Body*> bodies):
603  world{w}, bodyMap{std::move(bodies)}
604  {
605  // Intentionally empty.
606  }
607 
608  void Visit(const RevoluteJoint& oldJoint) override
609  {
610  auto def = GetRevoluteJointConf(oldJoint);
611  def.bodyA = bodyMap.at(def.bodyA);
612  def.bodyB = bodyMap.at(def.bodyB);
613  jointMap[&oldJoint] = Add(JointAtty::Create(def));
614  }
615 
616  void Visit(const PrismaticJoint& oldJoint) override
617  {
618  auto def = GetPrismaticJointConf(oldJoint);
619  def.bodyA = bodyMap.at(def.bodyA);
620  def.bodyB = bodyMap.at(def.bodyB);
621  jointMap[&oldJoint] = Add(JointAtty::Create(def));
622  }
623 
624  void Visit(const DistanceJoint& oldJoint) override
625  {
626  auto def = GetDistanceJointConf(oldJoint);
627  def.bodyA = bodyMap.at(def.bodyA);
628  def.bodyB = bodyMap.at(def.bodyB);
629  jointMap[&oldJoint] = Add(JointAtty::Create(def));
630  }
631 
632  void Visit(const PulleyJoint& oldJoint) override
633  {
634  auto def = GetPulleyJointConf(oldJoint);
635  def.bodyA = bodyMap.at(def.bodyA);
636  def.bodyB = bodyMap.at(def.bodyB);
637  jointMap[&oldJoint] = Add(JointAtty::Create(def));
638  }
639 
640  void Visit(const TargetJoint& oldJoint) override
641  {
642  auto def = GetTargetJointConf(oldJoint);
643  def.bodyA = (def.bodyA)? bodyMap.at(def.bodyA): nullptr;
644  def.bodyB = (def.bodyB)? bodyMap.at(def.bodyB): nullptr;
645  jointMap[&oldJoint] = Add(JointAtty::Create(def));
646  }
647 
648  void Visit(const GearJoint& oldJoint) override
649  {
650  auto def = GetGearJointConf(oldJoint);
651  def.bodyA = bodyMap.at(def.bodyA);
652  def.bodyB = bodyMap.at(def.bodyB);
653  def.joint1 = jointMap.at(def.joint1);
654  def.joint2 = jointMap.at(def.joint2);
655  jointMap[&oldJoint] = Add(JointAtty::Create(def));
656  }
657 
658  void Visit(const WheelJoint& oldJoint) override
659  {
660  auto def = GetWheelJointConf(oldJoint);
661  def.bodyA = bodyMap.at(def.bodyA);
662  def.bodyB = bodyMap.at(def.bodyB);
663  jointMap[&oldJoint] = Add(JointAtty::Create(def));
664  }
665 
666  void Visit(const WeldJoint& oldJoint) override
667  {
668  auto def = GetWeldJointConf(oldJoint);
669  def.bodyA = bodyMap.at(def.bodyA);
670  def.bodyB = bodyMap.at(def.bodyB);
671  jointMap[&oldJoint] = Add(JointAtty::Create(def));
672  }
673 
674  void Visit(const FrictionJoint& oldJoint) override
675  {
676  auto def = GetFrictionJointConf(oldJoint);
677  def.bodyA = bodyMap.at(def.bodyA);
678  def.bodyB = bodyMap.at(def.bodyB);
679  jointMap[&oldJoint] = Add(JointAtty::Create(def));
680  }
681 
682  void Visit(const RopeJoint& oldJoint) override
683  {
684  auto def = GetRopeJointConf(oldJoint);
685  def.bodyA = bodyMap.at(def.bodyA);
686  def.bodyB = bodyMap.at(def.bodyB);
687  jointMap[&oldJoint] = Add(JointAtty::Create(def));
688  }
689 
690  void Visit(const MotorJoint& oldJoint) override
691  {
692  auto def = GetMotorJointConf(oldJoint);
693  def.bodyA = bodyMap.at(def.bodyA);
694  def.bodyB = bodyMap.at(def.bodyB);
695  jointMap[&oldJoint] = Add(JointAtty::Create(def));
696  }
697 
698  Joint* Add(Joint* newJoint)
699  {
700  world.Add(newJoint);
701  return newJoint;
702  }
703 
704  World& world;
705  const std::map<const Body*, Body*> bodyMap;
706  std::map<const Joint*, Joint*> jointMap;
707  };
708 
709  auto copier = JointCopier{*this, bodyMap};
710  auto jointMap = std::map<const Joint*, Joint*>();
711  for (const auto& otherJoint: range)
712  {
713  otherJoint->Accept(copier);
714  }
715 }
716 
718 {
719  if (IsLocked())
720  {
721  throw WrongState("World::CreateBody: world is locked");
722  }
723 
724  if (size(m_bodies) >= MaxBodies)
725  {
726  throw LengthError("World::CreateBody: operation would exceed MaxBodies");
727  }
728 
729  auto& b = *BodyAtty::CreateBody(this, def);
730 
731  // Add to world bodies collection.
732  //
733  // Note: the order in which bodies are added matters! At least in-so-far as
734  // causing different results to occur when adding to the back vs. adding to
735  // the front. The World TilesComeToRest unit test for example runs faster
736  // with bodies getting added to the back (than when bodies are added to the
737  // front).
738  //
739  m_bodies.push_back(&b);
740 
741  return &b;
742 }
743 
744 void World::Remove(const Body& b) noexcept
745 {
746  UnregisterForProxies(b);
747  const auto it = find_if(cbegin(m_bodies), cend(m_bodies), [&](const Bodies::value_type& body) {
748  return GetPtr(body) == &b;
749  });
750  if (it != end(m_bodies))
751  {
752  BodyAtty::Delete(GetPtr(*it));
753  m_bodies.erase(it);
754  }
755 }
756 
757 void World::Destroy(Body* body)
758 {
759  assert(body);
760  assert(body->GetWorld() == this);
761 
762  if (IsLocked())
763  {
764  throw WrongState("World::Destroy: world is locked");
765  }
766 
767  // Delete the attached joints.
768  BodyAtty::ClearJoints(*body, [&](Joint& joint) {
769  if (m_destructionListener)
770  {
771  m_destructionListener->SayGoodbye(joint);
772  }
773  InternalDestroy(joint);
774  });
775 
776  // Destroy the attached contacts.
777  BodyAtty::EraseContacts(*body, [&](Contact& contact) {
778  Destroy(&contact, body);
779  return true;
780  });
781 
782  // Delete the attached fixtures. This destroys broad-phase proxies.
783  BodyAtty::ClearFixtures(*body, [&](Fixture& fixture) {
784  if (m_destructionListener)
785  {
786  m_destructionListener->SayGoodbye(fixture);
787  }
788  UnregisterForProxies(fixture);
789  DestroyProxies(fixture);
790  FixtureAtty::Delete(&fixture);
791  });
792 
793  Remove(*body);
794 }
795 
797 {
798  if (IsLocked())
799  {
800  throw WrongState("World::CreateJoint: world is locked");
801  }
802 
803  if (size(m_joints) >= MaxJoints)
804  {
805  throw LengthError("World::CreateJoint: operation would exceed MaxJoints");
806  }
807 
808  // Note: creating a joint doesn't wake the bodies.
809  const auto j = JointAtty::Create(def);
810 
811  Add(j);
812 
813  const auto bodyA = j->GetBodyA();
814  const auto bodyB = j->GetBodyB();
815 
816  // If the joint prevents collisions, then flag any contacts for filtering.
817  if ((!def.collideConnected) && bodyA && bodyB)
818  {
819  FlagContactsForFiltering(*bodyA, *bodyB);
820  }
821 
822  return j;
823 }
824 
825 bool World::Add(Joint* j)
826 {
827  assert(j);
828  m_joints.push_back(j);
829  const auto bodyA = j->GetBodyA();
830  const auto bodyB = j->GetBodyB();
831  BodyAtty::Insert(bodyA, j);
832  BodyAtty::Insert(bodyB, j);
833  return true;
834 }
835 
836 void World::Remove(const Joint& j) noexcept
837 {
838  const auto endIter = cend(m_joints);
839  const auto iter = find(cbegin(m_joints), endIter, &j);
840  assert(iter != endIter);
841  m_joints.erase(iter);
842 }
843 
844 void World::Destroy(Joint* joint)
845 {
846  if (joint)
847  {
848  if (IsLocked())
849  {
850  throw WrongState("World::Destroy: world is locked");
851  }
852  InternalDestroy(*joint);
853  }
854 }
855 
856 void World::InternalDestroy(Joint& joint) noexcept
857 {
858  Remove(joint);
859 
860  // Disconnect from island graph.
861  const auto bodyA = joint.GetBodyA();
862  const auto bodyB = joint.GetBodyB();
863 
864  // Wake up connected bodies.
865  if (bodyA)
866  {
867  bodyA->SetAwake();
868  BodyAtty::Erase(*bodyA, &joint);
869  }
870  if (bodyB)
871  {
872  bodyB->SetAwake();
873  BodyAtty::Erase(*bodyB, &joint);
874  }
875 
876  const auto collideConnected = joint.GetCollideConnected();
877 
878  JointAtty::Destroy(&joint);
879 
880  // If the joint prevented collisions, then flag any contacts for filtering.
881  if ((!collideConnected) && bodyA && bodyB)
882  {
883  FlagContactsForFiltering(*bodyA, *bodyB);
884  }
885 }
886 
887 void World::AddToIsland(Island& island, Body& seed,
888  Bodies::size_type& remNumBodies,
889  Contacts::size_type& remNumContacts,
890  Joints::size_type& remNumJoints)
891 {
892  assert(!IsIslanded(&seed));
893  assert(seed.IsSpeedable());
894  assert(seed.IsAwake());
895  assert(seed.IsEnabled());
896  assert(remNumBodies != 0);
897  assert(remNumBodies < MaxBodies);
898 
899  // Perform a depth first search (DFS) on the constraint graph.
900 
901  // Create a stack for bodies to be is-in-island that aren't already in the island.
902  auto stack = BodyStack{};
903  stack.reserve(remNumBodies);
904 
905  stack.push_back(&seed);
906  SetIslanded(&seed);
907  AddToIsland(island, stack, remNumBodies, remNumContacts, remNumJoints);
908 }
909 
910 void World::AddToIsland(Island& island, BodyStack& stack,
911  Bodies::size_type& remNumBodies,
912  Contacts::size_type& remNumContacts,
913  Joints::size_type& remNumJoints)
914 {
915  while (!empty(stack))
916  {
917  // Grab the next body off the stack and add it to the island.
918  const auto b = stack.back();
919  stack.pop_back();
920 
921  assert(b);
922  assert(b->IsEnabled());
923  island.m_bodies.push_back(b);
924  assert(remNumBodies > 0);
925  --remNumBodies;
926 
927  // Don't propagate islands across bodies that can't have a velocity (static bodies).
928  // This keeps islands smaller and helps with isolating separable collision clusters.
929  if (!b->IsSpeedable())
930  {
931  continue;
932  }
933 
934  // Make sure the body is awake (without resetting sleep timer).
935  BodyAtty::SetAwakeFlag(*b);
936 
937  const auto oldNumContacts = size(island.m_contacts);
938  // Adds appropriate contacts of current body and appropriate 'other' bodies of those contacts.
939  AddContactsToIsland(island, stack, b);
940 
941  const auto newNumContacts = size(island.m_contacts);
942  assert(newNumContacts >= oldNumContacts);
943  const auto netNumContacts = newNumContacts - oldNumContacts;
944  assert(remNumContacts >= netNumContacts);
945  remNumContacts -= netNumContacts;
946 
947  const auto numJoints = size(island.m_joints);
948  // Adds appropriate joints of current body and appropriate 'other' bodies of those joint.
949  AddJointsToIsland(island, stack, b);
950 
951  remNumJoints -= size(island.m_joints) - numJoints;
952  }
953 }
954 
955 void World::AddContactsToIsland(Island& island, BodyStack& stack, const Body* b)
956 {
957  const auto contacts = b->GetContacts();
958  for_each(cbegin(contacts), cend(contacts), [&](const KeyedContactPtr& ci) {
959  const auto contact = GetContactPtr(ci);
960  if (!IsIslanded(contact) && contact->IsEnabled() && contact->IsTouching())
961  {
962  const auto fA = contact->GetFixtureA();
963  const auto fB = contact->GetFixtureB();
964  if (!fA->IsSensor() && !fB->IsSensor())
965  {
966  const auto bA = fA->GetBody();
967  const auto bB = fB->GetBody();
968  const auto other = (bA != b)? bA: bB;
969  island.m_contacts.push_back(contact);
970  SetIslanded(contact);
971  if (!IsIslanded(other))
972  {
973  stack.push_back(other);
974  SetIslanded(other);
975  }
976  }
977  }
978  });
979 }
980 
981 void World::AddJointsToIsland(Island& island, BodyStack& stack, const Body* b)
982 {
983  const auto joints = b->GetJoints();
984  for_each(cbegin(joints), cend(joints), [&](const Body::KeyedJointPtr& ji) {
985  // Use data of ji before dereferencing its pointers.
986  const auto other = std::get<Body*>(ji);
987  const auto joint = std::get<Joint*>(ji);
988  assert(!other || other->IsEnabled() || !other->IsAwake());
989  if (!IsIslanded(joint) && (!other || other->IsEnabled()))
990  {
991  island.m_joints.push_back(joint);
992  SetIslanded(joint);
993  if (other && !IsIslanded(other))
994  {
995  // Only now dereference ji's pointers.
996  const auto bodyA = joint->GetBodyA();
997  const auto bodyB = joint->GetBodyB();
998  const auto rwOther = bodyA != b? bodyA: bodyB;
999  assert(rwOther == other);
1000  stack.push_back(rwOther);
1001  SetIslanded(rwOther);
1002  }
1003  }
1004  });
1005 }
1006 
1007 World::Bodies::size_type World::RemoveUnspeedablesFromIslanded(const std::vector<Body*>& bodies)
1008 {
1009  auto numRemoved = Bodies::size_type{0};
1010  for_each(begin(bodies), end(bodies), [&](Body* body) {
1011  if (!body->IsSpeedable())
1012  {
1013  // Allow static bodies to participate in other islands.
1014  UnsetIslanded(body);
1015  ++numRemoved;
1016  }
1017  });
1018  return numRemoved;
1019 }
1020 
1021 RegStepStats World::SolveReg(const StepConf& conf)
1022 {
1023  auto stats = RegStepStats{};
1024  assert(stats.islandsFound == 0);
1025  assert(stats.islandsSolved == 0);
1026 
1027  auto remNumBodies = size(m_bodies);
1028  auto remNumContacts = size(m_contacts);
1029  auto remNumJoints = size(m_joints);
1030 
1031  // Clear all the island flags.
1032  // This builds the logical set of bodies, contacts, and joints eligible for resolution.
1033  // As bodies, contacts, or joints get added to resolution islands, they're essentially
1034  // removed from this eligible set.
1035  for_each(begin(m_bodies), end(m_bodies), [](Bodies::value_type& b) {
1036  BodyAtty::UnsetIslanded(GetRef(b));
1037  });
1038  for_each(begin(m_contacts), end(m_contacts), [](Contacts::value_type& c) {
1039  ContactAtty::UnsetIslanded(GetRef(std::get<Contact*>(c)));
1040  });
1041  for_each(begin(m_joints), end(m_joints), [](Joints::value_type& j) {
1042  JointAtty::UnsetIslanded(GetRef(j));
1043  });
1044 
1045 #if defined(DO_THREADED)
1046  std::vector<std::future<World::IslandSolverResults>> futures;
1047  futures.reserve(remNumBodies);
1048 #endif
1049  // Build and simulate all awake islands.
1050  for (auto&& b: m_bodies)
1051  {
1052  auto& body = GetRef(b);
1053  assert(!body.IsAwake() || body.IsSpeedable());
1054  if (!IsIslanded(&body) && body.IsAwake() && body.IsEnabled())
1055  {
1056  ++stats.islandsFound;
1057 
1058  // Size the island for the remaining un-evaluated bodies, contacts, and joints.
1059  Island island(remNumBodies, remNumContacts, remNumJoints);
1060 
1061  AddToIsland(island, body, remNumBodies, remNumContacts, remNumJoints);
1062  remNumBodies += RemoveUnspeedablesFromIslanded(island.m_bodies);
1063 
1064 #if defined(DO_THREADED)
1065  // Updates bodies' sweep.pos0 to current sweep.pos1 and bodies' sweep.pos1 to new positions
1066  futures.push_back(std::async(std::launch::async, &World::SolveRegIslandViaGS,
1067  this, conf, island));
1068 #else
1069  const auto solverResults = SolveRegIslandViaGS(conf, island);
1070  Update(stats, solverResults);
1071 #endif
1072  }
1073  }
1074 
1075 #if defined(DO_THREADED)
1076  for (auto&& future: futures)
1077  {
1078  const auto solverResults = future.get();
1079  Update(stats, solverResults);
1080  }
1081 #endif
1082 
1083  for (auto&& b: m_bodies)
1084  {
1085  auto& body = GetRef(b);
1086  // A non-static body that was in an island may have moved.
1087  if (IsIslanded(&body) && body.IsSpeedable())
1088  {
1089  // Update fixtures (for broad-phase).
1090  stats.proxiesMoved += Synchronize(body, GetTransform0(body.GetSweep()), body.GetTransformation(),
1091  conf.displaceMultiplier, conf.aabbExtension);
1092  }
1093  }
1094 
1095  // Look for new contacts.
1096  stats.contactsAdded = FindNewContacts();
1097 
1098  return stats;
1099 }
1100 
1101 IslandStats World::SolveRegIslandViaGS(const StepConf& conf, Island island)
1102 {
1103  assert(!empty(island.m_bodies) || !empty(island.m_contacts) || !empty(island.m_joints));
1104 
1105  auto results = IslandStats{};
1106  results.positionIterations = conf.regPositionIterations;
1107  const auto h = conf.GetTime();
1108 
1109  // Update bodies' pos0 values.
1110  for_each(cbegin(island.m_bodies), cend(island.m_bodies), [&](Body* body) {
1111  BodyAtty::SetPosition0(*body, GetPosition1(*body)); // like Advance0(1) on the sweep.
1112  });
1113 
1114  // Copy bodies' pos1 and velocity data into local arrays.
1115  auto bodyConstraints = GetBodyConstraints(island.m_bodies, h, GetMovementConf(conf));
1116  auto bodyConstraintsMap = GetBodyConstraintsMap(island.m_bodies, bodyConstraints);
1117  auto posConstraints = GetPositionConstraints(island.m_contacts, bodyConstraintsMap);
1118  auto velConstraints = GetVelocityConstraints(island.m_contacts, bodyConstraintsMap,
1120 
1121  if (conf.doWarmStart)
1122  {
1123  WarmStartVelocities(velConstraints);
1124  }
1125 
1126  const auto psConf = GetRegConstraintSolverConf(conf);
1127 
1128  for_each(cbegin(island.m_joints), cend(island.m_joints), [&](Joint* joint) {
1129  JointAtty::InitVelocityConstraints(*joint, bodyConstraintsMap, conf, psConf);
1130  });
1131 
1132  results.velocityIterations = conf.regVelocityIterations;
1133  for (auto i = decltype(conf.regVelocityIterations){0}; i < conf.regVelocityIterations; ++i)
1134  {
1135  auto jointsOkay = true;
1136  for_each(cbegin(island.m_joints), cend(island.m_joints), [&](Joint* j) {
1137  jointsOkay &= JointAtty::SolveVelocityConstraints(*j, bodyConstraintsMap, conf);
1138  });
1139 
1140  // Note that the new incremental impulse can potentially be orders of magnitude
1141  // greater than the last incremental impulse used in this loop.
1142  const auto newIncImpulse = SolveVelocityConstraintsViaGS(velConstraints);
1143  results.maxIncImpulse = std::max(results.maxIncImpulse, newIncImpulse);
1144 
1145  if (jointsOkay && (newIncImpulse <= conf.regMinMomentum))
1146  {
1147  // No joint related velocity constraints were out of tolerance.
1148  // No body related velocity constraints were out of tolerance.
1149  // There does not appear to be any benefit to doing more loops now.
1150  // XXX: Is it really safe to bail now? Not certain of that.
1151  // Bail now assuming that this is helpful to do...
1152  results.velocityIterations = i + 1;
1153  break;
1154  }
1155  }
1156 
1157  // updates array of tentative new body positions per the velocities as if there were no obstacles...
1158  IntegratePositions(bodyConstraints, h);
1159 
1160  // Solve position constraints
1161  for (auto i = decltype(conf.regPositionIterations){0}; i < conf.regPositionIterations; ++i)
1162  {
1163  const auto minSeparation = SolvePositionConstraintsViaGS(posConstraints, psConf);
1164  results.minSeparation = std::min(results.minSeparation, minSeparation);
1165  const auto contactsOkay = (minSeparation >= conf.regMinSeparation);
1166 
1167  auto jointsOkay = true;
1168  for_each(cbegin(island.m_joints), cend(island.m_joints), [&](Joint* j) {
1169  jointsOkay &= JointAtty::SolvePositionConstraints(*j, bodyConstraintsMap, psConf);
1170  });
1171 
1172  if (contactsOkay && jointsOkay)
1173  {
1174  // Reached tolerance, early out...
1175  results.positionIterations = i + 1;
1176  results.solved = true;
1177  break;
1178  }
1179  }
1180 
1181  // Update normal and tangent impulses of contacts' manifold points
1182  for_each(cbegin(velConstraints), cend(velConstraints), [&](const VelocityConstraint& vc) {
1183  const auto i = static_cast<VelocityConstraints::size_type>(&vc - data(velConstraints));
1184  auto& manifold = ContactAtty::GetMutableManifold(*island.m_contacts[i]);
1185  AssignImpulses(manifold, vc);
1186  });
1187 
1188  for_each(cbegin(bodyConstraints), cend(bodyConstraints), [&](const BodyConstraint& bc) {
1189  const auto i = static_cast<size_t>(&bc - data(bodyConstraints));
1190  assert(i < size(bodyConstraints));
1191  // Could normalize position here to avoid unbounded angles but angular
1192  // normalization isn't handled correctly by joints that constrain rotation.
1193  UpdateBody(*island.m_bodies[i], bc.GetPosition(), bc.GetVelocity());
1194  });
1195 
1196  // XXX: Should contacts needing updating be updated now??
1197 
1198  if (m_contactListener)
1199  {
1200  Report(*m_contactListener, island.m_contacts, velConstraints,
1201  results.solved? results.positionIterations - 1: StepConf::InvalidIteration);
1202  }
1203 
1204  results.bodiesSlept = BodyCounter{0};
1205  const auto minUnderActiveTime = UpdateUnderActiveTimes(island.m_bodies, conf);
1206  if ((minUnderActiveTime >= conf.minStillTimeToSleep) && results.solved)
1207  {
1208  results.bodiesSlept = static_cast<decltype(results.bodiesSlept)>(Sleepem(island.m_bodies));
1209  }
1210 
1211  return results;
1212 }
1213 
1214 void World::ResetBodiesForSolveTOI() noexcept
1215 {
1216  for_each(begin(m_bodies), end(m_bodies), [&](Bodies::value_type& body) {
1217  auto& b = GetRef(body);
1218  BodyAtty::UnsetIslanded(b);
1219  BodyAtty::ResetAlpha0(b);
1220  });
1221 }
1222 
1223 void World::ResetContactsForSolveTOI() noexcept
1224 {
1225  for_each(begin(m_contacts), end(m_contacts), [&](Contacts::value_type &c) {
1226  auto& contact = GetRef(std::get<Contact*>(c));
1227  ContactAtty::UnsetIslanded(contact);
1228  ContactAtty::UnsetToi(contact);
1229  ContactAtty::ResetToiCount(contact);
1230  });
1231 }
1232 
1233 World::UpdateContactsData World::UpdateContactTOIs(const StepConf& conf)
1234 {
1235  auto results = UpdateContactsData{};
1236 
1237  const auto toiConf = GetToiConf(conf);
1238 
1239  for (auto&& contact: m_contacts)
1240  {
1241  auto& c = GetRef(std::get<Contact*>(contact));
1242  if (c.HasValidToi())
1243  {
1244  ++results.numValidTOI;
1245  continue;
1246  }
1247  if (!c.IsEnabled() || HasSensor(c) || !IsActive(c) || !IsImpenetrable(c))
1248  {
1249  continue;
1250  }
1251  if (c.GetToiCount() >= conf.maxSubSteps)
1252  {
1253  // What are the pros/cons of this?
1254  // Larger m_maxSubSteps slows down the simulation.
1255  // m_maxSubSteps of 44 and higher seems to decrease the occurrance of tunneling
1256  // of multiple bullet body collisions with static objects.
1257  ++results.numAtMaxSubSteps;
1258  continue;
1259  }
1260 
1261  const auto fA = c.GetFixtureA();
1262  const auto fB = c.GetFixtureB();
1263  const auto bA = fA->GetBody();
1264  const auto bB = fB->GetBody();
1265 
1266  /*
1267  * Put the sweeps onto the same time interval.
1268  * Presumably no unresolved collisions happen before the maximum of the bodies'
1269  * alpha-0 times. So long as the least TOI of the contacts is always the first
1270  * collision that gets dealt with, this presumption is safe.
1271  */
1272  const auto alpha0 = std::max(bA->GetSweep().GetAlpha0(), bB->GetSweep().GetAlpha0());
1273  assert(alpha0 >= 0 && alpha0 < 1);
1274  BodyAtty::Advance0(*bA, alpha0);
1275  BodyAtty::Advance0(*bB, alpha0);
1276 
1277  // Compute the TOI for this contact (one or both bodies are active and impenetrable).
1278  // Computes the time of impact in interval [0, 1]
1279  const auto output = CalcToi(c, toiConf);
1280 
1281  // Use Min function to handle floating point imprecision which possibly otherwise
1282  // could provide a TOI that's greater than 1.
1283  const auto toi = IsValidForTime(output.state)?
1284  std::min(alpha0 + (1 - alpha0) * output.time, Real{1}): Real{1};
1285  assert(toi >= alpha0 && toi <= 1);
1286  ContactAtty::SetToi(c, toi);
1287 
1288  results.maxDistIters = std::max(results.maxDistIters, output.stats.max_dist_iters);
1289  results.maxToiIters = std::max(results.maxToiIters, output.stats.toi_iters);
1290  results.maxRootIters = std::max(results.maxRootIters, output.stats.max_root_iters);
1291  ++results.numUpdatedTOI;
1292  }
1293 
1294  return results;
1295 }
1296 
1297 World::ContactToiData World::GetSoonestContact() const noexcept
1298 {
1299  auto minToi = nextafter(Real{1}, Real{0});
1300  auto found = static_cast<Contact*>(nullptr);
1301  auto count = ContactCounter{0};
1302  for (auto&& contact: m_contacts)
1303  {
1304  const auto c = GetPtr(std::get<Contact*>(contact));
1305  if (c->HasValidToi())
1306  {
1307  const auto toi = c->GetToi();
1308  if (minToi > toi)
1309  {
1310  minToi = toi;
1311  found = c;
1312  count = 1;
1313  }
1314  else if (minToi == toi)
1315  {
1316  // Have multiple contacts at the current minimum time of impact.
1317  ++count;
1318  }
1319  }
1320  }
1321  return ContactToiData{found, minToi, count};
1322 }
1323 
1324 ToiStepStats World::SolveToi(const StepConf& conf)
1325 {
1326  auto stats = ToiStepStats{};
1327 
1328  if (IsStepComplete())
1329  {
1330  ResetBodiesForSolveTOI();
1331  ResetContactsForSolveTOI();
1332  }
1333 
1334  const auto subStepping = GetSubStepping();
1335 
1336  // Find TOI events and solve them.
1337  for (;;)
1338  {
1339  const auto updateData = UpdateContactTOIs(conf);
1340  stats.contactsAtMaxSubSteps += updateData.numAtMaxSubSteps;
1341  stats.contactsUpdatedToi += updateData.numUpdatedTOI;
1342  stats.maxDistIters = std::max(stats.maxDistIters, updateData.maxDistIters);
1343  stats.maxRootIters = std::max(stats.maxRootIters, updateData.maxRootIters);
1344  stats.maxToiIters = std::max(stats.maxToiIters, updateData.maxToiIters);
1345 
1346  const auto next = GetSoonestContact();
1347  const auto contact = next.contact;
1348  const auto ncount = next.simultaneous;
1349  if (!contact)
1350  {
1351  // No more TOI events to handle within the current time step. Done!
1352  SetStepComplete(true);
1353  break;
1354  }
1355 
1356  stats.maxSimulContacts = std::max(stats.maxSimulContacts,
1357  static_cast<decltype(stats.maxSimulContacts)>(ncount));
1358  stats.contactsFound += ncount;
1359  auto islandsFound = 0u;
1360  if (!IsIslanded(contact))
1361  {
1362  /*
1363  * Confirm that contact is as it's supposed to be according to contract of the
1364  * GetSoonestContacts method from which this contact was obtained.
1365  */
1366  assert(contact->IsEnabled());
1367  assert(!HasSensor(*contact));
1368  assert(IsActive(*contact));
1369  assert(IsImpenetrable(*contact));
1370 
1371  const auto solverResults = SolveToi(conf, *contact);
1372  stats.minSeparation = std::min(stats.minSeparation, solverResults.minSeparation);
1373  stats.maxIncImpulse = std::max(stats.maxIncImpulse, solverResults.maxIncImpulse);
1374  stats.islandsSolved += solverResults.solved;
1375  stats.sumPosIters += solverResults.positionIterations;
1376  stats.sumVelIters += solverResults.velocityIterations;
1377  if ((solverResults.positionIterations > 0) || (solverResults.velocityIterations > 0))
1378  {
1379  ++islandsFound;
1380  }
1381  stats.contactsUpdatedTouching += solverResults.contactsUpdated;
1382  stats.contactsSkippedTouching += solverResults.contactsSkipped;
1383  }
1384  stats.islandsFound += islandsFound;
1385 
1386  // Reset island flags and synchronize broad-phase proxies.
1387  for (auto&& b: m_bodies)
1388  {
1389  auto& body = GetRef(b);
1390  if (IsIslanded(&body))
1391  {
1392  UnsetIslanded(&body);
1393  if (body.IsAccelerable())
1394  {
1395  const auto xfm0 = GetTransform0(body.GetSweep());
1396  const auto xfm1 = body.GetTransformation();
1397  stats.proxiesMoved += Synchronize(body, xfm0, xfm1,
1398  conf.displaceMultiplier, conf.aabbExtension);
1399  ResetContactsForSolveTOI(body);
1400  }
1401  }
1402  }
1403 
1404  // Commit fixture proxy movements to the broad-phase so that new contacts are created.
1405  // Also, some contacts can be destroyed.
1406  stats.contactsAdded += FindNewContacts();
1407 
1408  if (subStepping)
1409  {
1410  SetStepComplete(false);
1411  break;
1412  }
1413  }
1414  return stats;
1415 }
1416 
1417 IslandStats World::SolveToi(const StepConf& conf, Contact& contact)
1418 {
1419  // Note:
1420  // This method is what used to be b2World::SolveToi(const b2TimeStep& step).
1421  // It also differs internally from Erin's implementation.
1422  //
1423  // Here's some specific behavioral differences:
1424  // 1. Bodies don't get their under-active times reset (like they do in Erin's code).
1425 
1426  auto contactsUpdated = ContactCounter{0};
1427  auto contactsSkipped = ContactCounter{0};
1428 
1429  /*
1430  * Confirm that contact is as it's supposed to be according to contract of the
1431  * GetSoonestContacts method from which this contact should have been obtained.
1432  */
1433  assert(contact.IsEnabled());
1434  assert(!HasSensor(contact));
1435  assert(IsActive(contact));
1436  assert(IsImpenetrable(contact));
1437  assert(!IsIslanded(&contact));
1438 
1439  const auto toi = contact.GetToi();
1440  const auto bA = contact.GetFixtureA()->GetBody();
1441  const auto bB = contact.GetFixtureB()->GetBody();
1442 
1443  /* XXX: if (toi != 0)? */
1444  /* if (bA->GetSweep().GetAlpha0() != toi || bB->GetSweep().GetAlpha0() != toi) */
1445  // Seems contact manifold needs updating regardless.
1446  {
1447  const auto backupA = bA->GetSweep();
1448  const auto backupB = bB->GetSweep();
1449 
1450  // Advance the bodies to the TOI.
1451  assert(toi != 0 || (bA->GetSweep().GetAlpha0() == 0 && bB->GetSweep().GetAlpha0() == 0));
1452  BodyAtty::Advance(*bA, toi);
1453  BodyAtty::Advance(*bB, toi);
1454 
1455  // The TOI contact likely has some new contact points.
1456  contact.SetEnabled();
1457  if (contact.NeedsUpdating())
1458  {
1459  ContactAtty::Update(contact, Contact::GetUpdateConf(conf), m_contactListener);
1460  ++contactsUpdated;
1461  }
1462  else
1463  {
1464  ++contactsSkipped;
1465  }
1466  ContactAtty::UnsetToi(contact);
1467  ContactAtty::IncrementToiCount(contact);
1468 
1469  // Is contact disabled or separated?
1470  //
1471  // XXX: Not often, but sometimes, contact.IsTouching() is false now.
1472  // Seems like this is a bug, or at least suboptimal, condition.
1473  // This method shouldn't be getting called unless contact has an
1474  // impact indeed at the given TOI. Seen this happen in an edge-polygon
1475  // contact situation where the polygon had a larger than default
1476  // vertex radius. CollideShapes had called GetManifoldFaceB which
1477  // was failing to see 2 clip points after GetClipPoints was called.
1478  if (!contact.IsEnabled() || !contact.IsTouching())
1479  {
1480  // assert(!contact.IsEnabled() || contact.IsTouching());
1481  contact.UnsetEnabled();
1482  BodyAtty::Restore(*bA, backupA);
1483  BodyAtty::Restore(*bB, backupB);
1484  auto results = IslandStats{};
1485  results.contactsUpdated += contactsUpdated;
1486  results.contactsSkipped += contactsSkipped;
1487  return results;
1488  }
1489  }
1490 #if 0
1491  else if (!contact.IsTouching())
1492  {
1493  const auto newManifold = contact.Evaluate();
1494  assert(contact.IsTouching());
1495  return IslandSolverResults{};
1496  }
1497 #endif
1498 
1499  if (bA->IsSpeedable())
1500  {
1501  BodyAtty::SetAwakeFlag(*bA);
1502  // XXX should the body's under-active time be reset here?
1503  // Erin's code does for here but not in b2World::Solve(const b2TimeStep& step).
1504  // Calling Body::ResetUnderActiveTime() has performance implications.
1505  }
1506 
1507  if (bB->IsSpeedable())
1508  {
1509  BodyAtty::SetAwakeFlag(*bB);
1510  // XXX should the body's under-active time be reset here?
1511  // Erin's code does for here but not in b2World::Solve(const b2TimeStep& step).
1512  // Calling Body::ResetUnderActiveTime() has performance implications.
1513  }
1514 
1515  // Build the island
1516  Island island(size(m_bodies), size(m_contacts), 0);
1517 
1518  // These asserts get triggered sometimes if contacts within TOI are iterated over.
1519  assert(!IsIslanded(bA));
1520  assert(!IsIslanded(bB));
1521 
1522  island.m_bodies.push_back(bA);
1523  SetIslanded(bA);
1524  island.m_bodies.push_back(bB);
1525  SetIslanded(bB);
1526  island.m_contacts.push_back(&contact);
1527  SetIslanded(&contact);
1528 
1529  // Process the contacts of the two bodies, adding appropriate ones to the island,
1530  // adding appropriate other bodies of added contacts, and advancing those other
1531  // bodies sweeps and transforms to the minimum contact's TOI.
1532  if (bA->IsAccelerable())
1533  {
1534  const auto procOut = ProcessContactsForTOI(island, *bA, toi, conf);
1535  contactsUpdated += procOut.contactsUpdated;
1536  contactsSkipped += procOut.contactsSkipped;
1537  }
1538  if (bB->IsAccelerable())
1539  {
1540  const auto procOut = ProcessContactsForTOI(island, *bB, toi, conf);
1541  contactsUpdated += procOut.contactsUpdated;
1542  contactsSkipped += procOut.contactsSkipped;
1543  }
1544 
1545  RemoveUnspeedablesFromIslanded(island.m_bodies);
1546 
1547  // Now solve for remainder of time step.
1548  //
1549  // Note: subConf is written the way it is because MSVS2017 emitted errors when
1550  // written as:
1551  // SolveToi(StepConf{conf}.SetTime((1 - toi) * conf.GetTime()), island);
1552  //
1553  auto subConf = StepConf{conf};
1554  auto results = SolveToiViaGS(subConf.SetTime((1 - toi) * conf.GetTime()), island);
1555  results.contactsUpdated += contactsUpdated;
1556  results.contactsSkipped += contactsSkipped;
1557  return results;
1558 }
1559 
1560 void World::UpdateBody(Body& body, const Position& pos, const Velocity& vel)
1561 {
1562  assert(IsValid(pos));
1563  assert(IsValid(vel));
1564  BodyAtty::SetVelocity(body, vel);
1565  BodyAtty::SetPosition1(body, pos);
1566  BodyAtty::SetTransformation(body, GetTransformation(GetPosition1(body), body.GetLocalCenter()));
1567 }
1568 
1569 IslandStats World::SolveToiViaGS(const StepConf& conf, Island& island)
1570 {
1571  auto results = IslandStats{};
1572 
1573  /*
1574  * Presumably the regular phase resolution has already taken care of updating the
1575  * body's velocity w.r.t. acceleration and damping such that this call here to get
1576  * the body constraint doesn't need to pass an elapsed time (and doesn't need to
1577  * update the velocity from what it already is).
1578  */
1579  auto bodyConstraints = GetBodyConstraints(island.m_bodies, 0_s, GetMovementConf(conf));
1580  auto bodyConstraintsMap = GetBodyConstraintsMap(island.m_bodies, bodyConstraints);
1581 
1582  // Initialize the body state.
1583 #if 0
1584  for (auto&& contact: island.m_contacts)
1585  {
1586  const auto fixtureA = contact->GetFixtureA();
1587  const auto fixtureB = contact->GetFixtureB();
1588  const auto bodyA = fixtureA->GetBody();
1589  const auto bodyB = fixtureB->GetBody();
1590 
1591  bodyConstraintsMap[bodyA] = GetBodyConstraint(*bodyA);
1592  bodyConstraintsMap[bodyB] = GetBodyConstraint(*bodyB);
1593  }
1594 #endif
1595 
1596  auto posConstraints = GetPositionConstraints(island.m_contacts, bodyConstraintsMap);
1597 
1598  // Solve TOI-based position constraints.
1599  assert(results.minSeparation == std::numeric_limits<Length>::infinity());
1600  assert(results.solved == false);
1601  results.positionIterations = conf.toiPositionIterations;
1602  {
1603  const auto psConf = GetToiConstraintSolverConf(conf);
1604 
1605  for (auto i = decltype(conf.toiPositionIterations){0}; i < conf.toiPositionIterations; ++i)
1606  {
1607  //
1608  // Note: There are two flavors of the SolvePositionConstraints function.
1609  // One takes an extra two arguments that are the indexes of two bodies that are
1610  // okay tomove. The other one does not.
1611  // Calling the selective solver (that takes the two additional arguments) appears
1612  // to result in phsyics simulations that are more prone to tunneling. Meanwhile,
1613  // using the non-selective solver would presumably be slower (since it appears to
1614  // have more that it will do). Assuming that slower is preferable to tunnelling,
1615  // then the non-selective function is the one to be calling here.
1616  //
1617  const auto minSeparation = SolvePositionConstraintsViaGS(posConstraints, psConf);
1618  results.minSeparation = std::min(results.minSeparation, minSeparation);
1619  if (minSeparation >= conf.toiMinSeparation)
1620  {
1621  // Reached tolerance, early out...
1622  results.positionIterations = i + 1;
1623  results.solved = true;
1624  break;
1625  }
1626  }
1627  }
1628 
1629  // Leap of faith to new safe state.
1630  // Not doing this results in slower simulations.
1631  // Originally this update was only done to island.m_bodies 0 and 1.
1632  // Unclear whether rest of bodies should also be updated. No difference noticed.
1633 #if 0
1634  for (auto&& contact: island.m_contacts)
1635  {
1636  const auto fixtureA = contact->GetFixtureA();
1637  const auto fixtureB = contact->GetFixtureB();
1638  const auto bodyA = fixtureA->GetBody();
1639  const auto bodyB = fixtureB->GetBody();
1640 
1641  BodyAtty::SetPosition0(*bodyA, bodyConstraintsMap.at(bodyA).GetPosition());
1642  BodyAtty::SetPosition0(*bodyB, bodyConstraintsMap.at(bodyB).GetPosition());
1643  }
1644 #else
1645  for_each(cbegin(bodyConstraints), cend(bodyConstraints), [&](const BodyConstraint& bc) {
1646  const auto i = static_cast<size_t>(&bc - data(bodyConstraints));
1647  assert(i < size(bodyConstraints));
1648  BodyAtty::SetPosition0(*island.m_bodies[i], bc.GetPosition());
1649  });
1650 #endif
1651 
1652  auto velConstraints = GetVelocityConstraints(island.m_contacts, bodyConstraintsMap,
1654 
1655  // No warm starting is needed for TOI events because warm
1656  // starting impulses were applied in the discrete solver.
1657 
1658  // Solve velocity constraints.
1659  assert(results.maxIncImpulse == 0_Ns);
1660  results.velocityIterations = conf.toiVelocityIterations;
1661  for (auto i = decltype(conf.toiVelocityIterations){0}; i < conf.toiVelocityIterations; ++i)
1662  {
1663  const auto newIncImpulse = SolveVelocityConstraintsViaGS(velConstraints);
1664  if (newIncImpulse <= conf.toiMinMomentum)
1665  {
1666  // No body related velocity constraints were out of tolerance.
1667  // There does not appear to be any benefit to doing more loops now.
1668  // XXX: Is it really safe to bail now? Not certain of that.
1669  // Bail now assuming that this is helpful to do...
1670  results.velocityIterations = i + 1;
1671  break;
1672  }
1673  results.maxIncImpulse = std::max(results.maxIncImpulse, newIncImpulse);
1674  }
1675 
1676  // Don't store TOI contact forces for warm starting because they can be quite large.
1677 
1678  IntegratePositions(bodyConstraints, conf.GetTime());
1679 
1680  for_each(cbegin(bodyConstraints), cend(bodyConstraints), [&](const BodyConstraint& bc) {
1681  const auto i = static_cast<size_t>(&bc - data(bodyConstraints));
1682  assert(i < size(bodyConstraints));
1683  UpdateBody(*island.m_bodies[i], bc.GetPosition(), bc.GetVelocity());
1684  });
1685 
1686  if (m_contactListener)
1687  {
1688  Report(*m_contactListener, island.m_contacts, velConstraints, results.positionIterations);
1689  }
1690 
1691  return results;
1692 }
1693 
1694 void World::ResetContactsForSolveTOI(Body& body) noexcept
1695 {
1696  // Invalidate all contact TOIs on this displaced body.
1697  const auto contacts = body.GetContacts();
1698  for_each(cbegin(contacts), cend(contacts), [&](KeyedContactPtr ci) {
1699  const auto contact = GetContactPtr(ci);
1700  UnsetIslanded(contact);
1701  ContactAtty::UnsetToi(*contact);
1702  });
1703 }
1704 
1705 World::ProcessContactsOutput
1706 World::ProcessContactsForTOI(Island& island, Body& body, Real toi,
1707  const StepConf& conf)
1708 {
1709  assert(IsIslanded(&body));
1710  assert(body.IsAccelerable());
1711  assert(toi >= 0 && toi <= 1);
1712 
1713  auto results = ProcessContactsOutput{};
1714  assert(results.contactsUpdated == 0);
1715  assert(results.contactsSkipped == 0);
1716 
1717  const auto updateConf = Contact::GetUpdateConf(conf);
1718 
1719  auto processContactFunc = [&](Contact* contact, Body* other)
1720  {
1721  const auto otherIslanded = IsIslanded(other);
1722  {
1723  const auto backup = other->GetSweep();
1724  if (!otherIslanded /* && other->GetSweep().GetAlpha0() != toi */)
1725  {
1726  BodyAtty::Advance(*other, toi);
1727  }
1728 
1729  // Update the contact points
1730  contact->SetEnabled();
1731  if (contact->NeedsUpdating())
1732  {
1733  ContactAtty::Update(*contact, updateConf, m_contactListener);
1734  ++results.contactsUpdated;
1735  }
1736  else
1737  {
1738  ++results.contactsSkipped;
1739  }
1740 
1741  // Revert and skip if contact disabled by user or not touching anymore (very possible).
1742  if (!contact->IsEnabled() || !contact->IsTouching())
1743  {
1744  BodyAtty::Restore(*other, backup);
1745  return;
1746  }
1747  }
1748  island.m_contacts.push_back(contact);
1749  SetIslanded(contact);
1750  if (!otherIslanded)
1751  {
1752  if (other->IsSpeedable())
1753  {
1754  BodyAtty::SetAwakeFlag(*other);
1755  }
1756  island.m_bodies.push_back(other);
1757  SetIslanded(other);
1758 #if 0
1759  if (other->IsAccelerable())
1760  {
1761  contactsUpdated += ProcessContactsForTOI(island, *other, toi);
1762  }
1763 #endif
1764  }
1765 #ifndef NDEBUG
1766  else
1767  {
1768  /*
1769  * If other is-in-island but not in current island, then something's gone wrong.
1770  * Other needs to be in current island but was already in the island.
1771  * A previous contact island didn't grow to include all the bodies it needed or
1772  * perhaps the current contact is-touching while another one wasn't and the
1773  * inconsistency is throwing things off.
1774  */
1775  assert(Count(island, other) > 0);
1776  }
1777 #endif
1778  };
1779 
1780  // Note: the original contact (for body of which this method was called) already is-in-island.
1781  const auto bodyImpenetrable = body.IsImpenetrable();
1782  for (auto&& ci: body.GetContacts())
1783  {
1784  const auto contact = GetContactPtr(ci);
1785  if (!IsIslanded(contact))
1786  {
1787  const auto fA = contact->GetFixtureA();
1788  const auto fB = contact->GetFixtureB();
1789  if (!fA->IsSensor() && !fB->IsSensor())
1790  {
1791  const auto bA = fA->GetBody();
1792  const auto bB = fB->GetBody();
1793  const auto other = (bA != &body)? bA: bB;
1794  if (bodyImpenetrable || other->IsImpenetrable())
1795  {
1796  processContactFunc(contact, other);
1797  }
1798  }
1799  }
1800  }
1801  return results;
1802 }
1803 
1805 {
1806  assert((Length{m_maxVertexRadius} * Real{2}) +
1807  (Length{conf.linearSlop} / Real{4}) > (Length{m_maxVertexRadius} * Real{2}));
1808 
1809  if (IsLocked())
1810  {
1811  throw WrongState("World::Step: world is locked");
1812  }
1813 
1814  // "Named return value optimization" (NRVO) will make returning this more efficient.
1815  auto stepStats = StepStats{};
1816  {
1817  FlagGuard<decltype(m_flags)> flagGaurd(m_flags, e_locked);
1818 
1819  CreateAndDestroyProxies(conf);
1820  stepStats.pre.proxiesMoved = SynchronizeProxies(conf);
1821  // pre.proxiesMoved is usually zero but sometimes isn't.
1822 
1823  {
1824  // Note: this may update bodies (in addition to the contacts container).
1825  const auto destroyStats = DestroyContacts(m_contacts);
1826  stepStats.pre.destroyed = destroyStats.erased;
1827  }
1828 
1829  if (HasNewFixtures())
1830  {
1831  UnsetNewFixtures();
1832 
1833  // New fixtures were added: need to find and create the new contacts.
1834  // Note: this may update bodies (in addition to the contacts container).
1835  stepStats.pre.added = FindNewContacts();
1836  }
1837 
1838  if (conf.GetTime() != 0_s)
1839  {
1840  m_inv_dt0 = conf.GetInvTime();
1841 
1842  // Could potentially run UpdateContacts multithreaded over split lists...
1843  const auto updateStats = UpdateContacts(m_contacts, conf);
1844  stepStats.pre.ignored = updateStats.ignored;
1845  stepStats.pre.updated = updateStats.updated;
1846  stepStats.pre.skipped = updateStats.skipped;
1847 
1848  // Integrate velocities, solve velocity constraints, and integrate positions.
1849  if (IsStepComplete())
1850  {
1851  stepStats.reg = SolveReg(conf);
1852  }
1853 
1854  // Handle TOI events.
1855  if (conf.doToi)
1856  {
1857  stepStats.toi = SolveToi(conf);
1858  }
1859  }
1860  }
1861  return stepStats;
1862 }
1863 
1864 void World::ShiftOrigin(Length2 newOrigin)
1865 {
1866  if (IsLocked())
1867  {
1868  throw WrongState("World::ShiftOrigin: world is locked");
1869  }
1870 
1871  const auto bodies = GetBodies();
1872  for (auto&& body: bodies)
1873  {
1874  auto& b = GetRef(body);
1875 
1876  auto transformation = b.GetTransformation();
1877  transformation.p -= newOrigin;
1878  BodyAtty::SetTransformation(b, transformation);
1879 
1880  auto sweep = b.GetSweep();
1881  sweep.pos0.linear -= newOrigin;
1882  sweep.pos1.linear -= newOrigin;
1883  BodyAtty::SetSweep(b, sweep);
1884  }
1885 
1886  for_each(begin(m_joints), end(m_joints), [&](Joints::value_type& j) {
1887  GetRef(j).ShiftOrigin(newOrigin);
1888  });
1889 
1890  m_tree.ShiftOrigin(newOrigin);
1891 }
1892 
1893 void World::InternalDestroy(Contact* contact, Body* from)
1894 {
1895  if (m_contactListener && contact->IsTouching())
1896  {
1897  // EndContact hadn't been called in DestroyOrUpdateContacts() since is-touching, so call it now
1898  m_contactListener->EndContact(*contact);
1899  }
1900 
1901  const auto fixtureA = contact->GetFixtureA();
1902  const auto fixtureB = contact->GetFixtureB();
1903  const auto bodyA = fixtureA->GetBody();
1904  const auto bodyB = fixtureB->GetBody();
1905 
1906  if (bodyA != from)
1907  {
1908  BodyAtty::Erase(*bodyA, contact);
1909  }
1910  if (bodyB != from)
1911  {
1912  BodyAtty::Erase(*bodyB, contact);
1913  }
1914 
1915  if ((contact->GetManifold().GetPointCount() > 0) &&
1916  !fixtureA->IsSensor() && !fixtureB->IsSensor())
1917  {
1918  // Contact may have been keeping accelerable bodies of fixture A or B from moving.
1919  // Need to awaken those bodies now in case they are again movable.
1920  bodyA->SetAwake();
1921  bodyB->SetAwake();
1922  }
1923 
1924  delete contact;
1925 }
1926 
1927 void World::Destroy(Contact* contact, Body* from)
1928 {
1929  assert(contact);
1930 
1931  InternalDestroy(contact, from);
1932 
1933  const auto it = find_if(cbegin(m_contacts), cend(m_contacts),
1934  [&](const Contacts::value_type& c) {
1935  return GetPtr(std::get<Contact*>(c)) == contact;
1936  });
1937  if (it != cend(m_contacts))
1938  {
1939  m_contacts.erase(it);
1940  }
1941 }
1942 
1943 World::DestroyContactsStats World::DestroyContacts(Contacts& contacts)
1944 {
1945  const auto beforeSize = size(contacts);
1946  contacts.erase(std::remove_if(begin(contacts), end(contacts), [&](Contacts::value_type& c)
1947  {
1948  const auto key = std::get<ContactKey>(c);
1949  auto& contact = GetRef(std::get<Contact*>(c));
1950 
1951  if (!TestOverlap(m_tree, key.GetMin(), key.GetMax()))
1952  {
1953  // Destroy contacts that cease to overlap in the broad-phase.
1954  InternalDestroy(&contact);
1955  return true;
1956  }
1957 
1958  // Is this contact flagged for filtering?
1959  if (contact.NeedsFiltering())
1960  {
1961  const auto fixtureA = contact.GetFixtureA();
1962  const auto fixtureB = contact.GetFixtureB();
1963  const auto bodyA = fixtureA->GetBody();
1964  const auto bodyB = fixtureB->GetBody();
1965 
1966  if (!ShouldCollide(*bodyB, *bodyA) || !ShouldCollide(*fixtureA, *fixtureB))
1967  {
1968  InternalDestroy(&contact);
1969  return true;
1970  }
1971  ContactAtty::UnflagForFiltering(contact);
1972  }
1973 
1974  return false;
1975  }), end(contacts));
1976  const auto afterSize = size(contacts);
1977 
1978  auto stats = DestroyContactsStats{};
1979  stats.ignored = static_cast<ContactCounter>(afterSize);
1980  stats.erased = static_cast<ContactCounter>(beforeSize - afterSize);
1981  return stats;
1982 }
1983 
1984 World::UpdateContactsStats World::UpdateContacts(Contacts& contacts, const StepConf& conf)
1985 {
1986 #ifdef DO_PAR_UNSEQ
1987  atomic<uint32_t> ignored;
1988  atomic<uint32_t> updated;
1989  atomic<uint32_t> skipped;
1990 #else
1991  auto ignored = uint32_t{0};
1992  auto updated = uint32_t{0};
1993  auto skipped = uint32_t{0};
1994 #endif
1995 
1996  const auto updateConf = Contact::GetUpdateConf(conf);
1997 
1998 #if defined(DO_THREADED)
1999  std::vector<Contact*> contactsNeedingUpdate;
2000  contactsNeedingUpdate.reserve(size(contacts));
2001  std::vector<std::future<void>> futures;
2002  futures.reserve(size(contacts));
2003 #endif
2004 
2005  // Update awake contacts.
2006  for_each(/*execution::par_unseq,*/ begin(contacts), end(contacts),
2007  [&](Contacts::value_type& c) {
2008  auto& contact = GetRef(std::get<Contact*>(c));
2009 #if 0
2010  ContactAtty::Update(contact, updateConf, m_contactListener);
2011  ++updated;
2012 #else
2013  const auto bodyA = GetBodyA(contact);
2014  const auto bodyB = GetBodyB(contact);
2015 
2016  // Awake && speedable (dynamic or kinematic) means collidable.
2017  // At least one body must be collidable
2018  assert(!bodyA->IsAwake() || bodyA->IsSpeedable());
2019  assert(!bodyB->IsAwake() || bodyB->IsSpeedable());
2020  if (!bodyA->IsAwake() && !bodyB->IsAwake())
2021  {
2022  assert(!contact.HasValidToi());
2023  ++ignored;
2024  return;
2025  }
2026 
2027  // Possible that bodyA->GetSweep().GetAlpha0() != 0
2028  // Possible that bodyB->GetSweep().GetAlpha0() != 0
2029 
2030  // Update the contact manifold and notify the listener.
2031  contact.SetEnabled();
2032 
2033  // Note: ideally contacts are only updated if there was a change to:
2034  // - The fixtures' sensor states.
2035  // - The fixtures bodies' transformations.
2036  // - The "maxCirclesRatio" per-step configuration state if contact IS NOT for sensor.
2037  // - The "maxDistanceIters" per-step configuration state if contact IS for sensor.
2038  //
2039  if (contact.NeedsUpdating())
2040  {
2041  // The following may call listener but is otherwise thread-safe.
2042 #if defined(DO_THREADED)
2043  contactsNeedingUpdate.push_back(&contact);
2044  //futures.push_back(async(&ContactAtty::Update, *contact, conf, m_contactListener)));
2045  //futures.push_back(async(launch::async, [=]{ ContactAtty::Update(*contact, conf, m_contactListener); }));
2046 #else
2047  ContactAtty::Update(contact, updateConf, m_contactListener);
2048 #endif
2049  ++updated;
2050  }
2051  else
2052  {
2053  ++skipped;
2054  }
2055 #endif
2056  });
2057 
2058 #if defined(DO_THREADED)
2059  auto numJobs = size(contactsNeedingUpdate);
2060  const auto jobsPerCore = numJobs / 4;
2061  for (auto i = decltype(numJobs){0}; numJobs > 0 && i < 3; ++i)
2062  {
2063  futures.push_back(std::async(std::launch::async, [=]{
2064  const auto offset = jobsPerCore * i;
2065  for (auto j = decltype(jobsPerCore){0}; j < jobsPerCore; ++j)
2066  {
2067  ContactAtty::Update(*contactsNeedingUpdate[offset + j], updateConf, m_contactListener);
2068  }
2069  }));
2070  numJobs -= jobsPerCore;
2071  }
2072  if (numJobs > 0)
2073  {
2074  futures.push_back(std::async(std::launch::async, [=]{
2075  const auto offset = jobsPerCore * 3;
2076  for (auto j = decltype(numJobs){0}; j < numJobs; ++j)
2077  {
2078  ContactAtty::Update(*contactsNeedingUpdate[offset + j], updateConf, m_contactListener);
2079  }
2080  }));
2081  }
2082  for (auto&& future: futures)
2083  {
2084  future.get();
2085  }
2086 #endif
2087 
2088  return UpdateContactsStats{
2089  static_cast<ContactCounter>(ignored),
2090  static_cast<ContactCounter>(updated),
2091  static_cast<ContactCounter>(skipped)
2092  };
2093 }
2094 
2095 void World::UnregisterForProcessing(ProxyId pid) noexcept
2096 {
2097  const auto itEnd = end(m_proxies);
2098  auto it = find(/*execution::par_unseq,*/ begin(m_proxies), itEnd, pid);
2099  if (it != itEnd)
2100  {
2101  *it = DynamicTree::GetInvalidSize();
2102  }
2103 }
2104 
2105 ContactCounter World::FindNewContacts()
2106 {
2107  m_proxyKeys.clear();
2108 
2109  // Accumalate contact keys for pairs of nodes that are overlapping and aren't identical.
2110  // Note that if the dynamic tree node provides the body pointer, it's assumed to be faster
2111  // to eliminate any node pairs that have the same body here before the key pairs are
2112  // sorted.
2113  for_each(cbegin(m_proxies), cend(m_proxies), [&](ProxyId pid) {
2114  const auto body0 = m_tree.GetLeafData(pid).body;
2115  const auto aabb = m_tree.GetAABB(pid);
2116  Query(m_tree, aabb, [&](DynamicTree::Size nodeId) {
2117  const auto body1 = m_tree.GetLeafData(nodeId).body;
2118  // A proxy cannot form a pair with itself.
2119  if ((nodeId != pid) && (body0 != body1))
2120  {
2121  m_proxyKeys.push_back(ContactKey{nodeId, pid});
2122  }
2123  return DynamicTreeOpcode::Continue;
2124  });
2125  });
2126  m_proxies.clear();
2127 
2128  // Sort and eliminate any duplicate contact keys.
2129  sort(begin(m_proxyKeys), end(m_proxyKeys));
2130  m_proxyKeys.erase(unique(begin(m_proxyKeys), end(m_proxyKeys)), end(m_proxyKeys));
2131 
2132  const auto numContactsBefore = size(m_contacts);
2133  for_each(cbegin(m_proxyKeys), cend(m_proxyKeys), [&](ContactKey key)
2134  {
2135  Add(key);
2136  });
2137  const auto numContactsAfter = size(m_contacts);
2138  return static_cast<ContactCounter>(numContactsAfter - numContactsBefore);
2139 }
2140 
2141 bool World::Add(ContactKey key)
2142 {
2143  const auto minKeyLeafData = m_tree.GetLeafData(key.GetMin());
2144  const auto maxKeyLeafData = m_tree.GetLeafData(key.GetMax());
2145 
2146  const auto fixtureA = minKeyLeafData.fixture;
2147  const auto indexA = minKeyLeafData.childIndex;
2148  const auto fixtureB = maxKeyLeafData.fixture;
2149  const auto indexB = maxKeyLeafData.childIndex;
2150 
2151  const auto bodyA = minKeyLeafData.body; // fixtureA->GetBody();
2152  const auto bodyB = maxKeyLeafData.body; // fixtureB->GetBody();
2153 
2154 #if 0
2155  // Are the fixtures on the same body? They can be, and they often are.
2156  // Don't need nor want a contact for these fixtures if they are on the same body.
2157  if (bodyA == bodyB)
2158  {
2159  return false;
2160  }
2161 #endif
2162  assert(bodyA != bodyB);
2163 
2164  // Does a joint override collision? Is at least one body dynamic?
2165  if (!ShouldCollide(*bodyB, *bodyA) || !ShouldCollide(*fixtureA, *fixtureB))
2166  {
2167  return false;
2168  }
2169 
2170 #ifndef NO_RACING
2171  // Code herein may be racey in a multithreaded context...
2172  // Would need a lock on bodyA, bodyB, and m_contacts.
2173  // A global lock on the world instance should work but then would it have so much
2174  // contention as to make multi-threaded handing of adding new connections senseless?
2175 
2176  // Have to quickly figure out if there's a contact already added for the current
2177  // fixture-childindex pair that this method's been called for.
2178  //
2179  // In cases where there's a bigger bullet-enabled object that's colliding with lots of
2180  // smaller objects packed tightly together and overlapping like in the Add Pair Stress
2181  // Test demo that has some 400 smaller objects, the bigger object could have 387 contacts
2182  // while the smaller object has 369 or more, and the total world contact count can be over
2183  // 30,495. While searching linearly through the object with less contacts should help,
2184  // that may still be a lot of contacts to be going through in the context this method
2185  // is being called. OTOH, speed seems to be dominated by cache hit-ratio...
2186  //
2187  // With compiler optimization enabled and 400 small bodies and Real=double...
2188  // For world:
2189  // World::set<Contact*> shows up as .524 seconds max step
2190  // World::list<Contact> shows up as .482 seconds max step.
2191  // For body:
2192  // using contact map w/ proxy ID keys shows up as .561
2193  // W/ unordered_map: .529 seconds max step (step 15).
2194  // W/ World::list<Contact> and Body::list<ContactKey,Contact*> .444s@step15, 1.063s-sumstep20
2195  // W/ World::list<Contact> and Body::list<ContactKey,Contact*> .393s@step15, 1.063s-sumstep20
2196  // W/ World::list<Contact> and Body::list<ContactKey,Contact*> .412s@step15, 1.012s-sumstep20
2197  // W/ World::list<Contact> and Body::vector<ContactKey,Contact*> .219s@step15, 0.659s-sumstep20
2198 
2199  // Does a contact already exist?
2200  // Identify body with least contacts and search it.
2201  // NOTE: Time trial testing found the following rough ordering of data structures, to be
2202  // fastest to slowest: vector, list, unorderered_set, unordered_map,
2203  // set, map.
2204  const auto searchBody = (size(bodyA->GetContacts()) < size(bodyB->GetContacts()))?
2205  bodyA: bodyB;
2206 
2207  const auto contacts = searchBody->GetContacts();
2208  const auto it = find_if(cbegin(contacts), cend(contacts), [&](KeyedContactPtr ci) {
2209  return std::get<ContactKey>(ci) == key;
2210  });
2211  if (it != cend(contacts))
2212  {
2213  return false;
2214  }
2215 
2216  assert(size(m_contacts) < MaxContacts);
2217  if (size(m_contacts) >= MaxContacts)
2218  {
2219  // New contact was needed, but denied due to MaxContacts count being reached.
2220  return false;
2221  }
2222 
2223  const auto contact = new Contact{fixtureA, indexA, fixtureB, indexB};
2224 
2225  // Insert into the contacts container.
2226  //
2227  // Should the new contact be added at front or back?
2228  //
2229  // Original strategy added to the front. Since processing done front to back, front
2230  // adding means container more a LIFO container, while back adding means more a FIFO.
2231  //
2232  m_contacts.push_back(KeyedContactPtr{key, contact});
2233 
2234  BodyAtty::Insert(*bodyA, key, contact);
2235  BodyAtty::Insert(*bodyB, key, contact);
2236 
2237  // Wake up the bodies
2238  if (!fixtureA->IsSensor() && !fixtureB->IsSensor())
2239  {
2240  if (bodyA->IsSpeedable())
2241  {
2242  BodyAtty::SetAwakeFlag(*bodyA);
2243  }
2244  if (bodyB->IsSpeedable())
2245  {
2246  BodyAtty::SetAwakeFlag(*bodyB);
2247  }
2248  }
2249 #endif
2250 
2251  return true;
2252 }
2253 
2254 void World::RegisterForProxies(Fixture& fixture)
2255 {
2256  assert(fixture.GetBody()->GetWorld() == this);
2257  m_fixturesForProxies.push_back(&fixture);
2258 }
2259 
2260 void World::UnregisterForProxies(const Fixture& fixture)
2261 {
2262  assert(fixture.GetBody()->GetWorld() == this);
2263  const auto first = remove(begin(m_fixturesForProxies), end(m_fixturesForProxies), &fixture);
2264  m_fixturesForProxies.erase(first, end(m_fixturesForProxies));
2265 }
2266 
2267 void World::RegisterForProxies(Body& body)
2268 {
2269  assert(body.GetWorld() == this);
2270  m_bodiesForProxies.push_back(&body);
2271 }
2272 
2273 void World::UnregisterForProxies(const Body& body)
2274 {
2275  assert(body.GetWorld() == this);
2276  const auto first = remove(begin(m_bodiesForProxies), end(m_bodiesForProxies), &body);
2277  m_bodiesForProxies.erase(first, end(m_bodiesForProxies));
2278 }
2279 
2280 void World::CreateAndDestroyProxies(const StepConf& conf)
2281 {
2282  for_each(begin(m_fixturesForProxies), end(m_fixturesForProxies), [&](Fixture *f) {
2283  CreateAndDestroyProxies(*f, conf);
2284  });
2285  m_fixturesForProxies.clear();
2286 }
2287 
2288 void World::CreateAndDestroyProxies(Fixture& fixture, const StepConf& conf)
2289 {
2290  const auto body = fixture.GetBody();
2291  const auto enabled = body->IsEnabled();
2292 
2293  const auto proxyCount = fixture.GetProxyCount();
2294  if (proxyCount == 0)
2295  {
2296  if (enabled)
2297  {
2298  CreateProxies(fixture, conf.aabbExtension);
2299  }
2300  }
2301  else
2302  {
2303  if (!enabled)
2304  {
2305  UnregisterForProxies(fixture);
2306  DestroyProxies(fixture);
2307 
2308  // Destroy any contacts associated with the fixture.
2309  BodyAtty::EraseContacts(*body, [&](Contact& contact) {
2310  const auto fixtureA = contact.GetFixtureA();
2311  const auto fixtureB = contact.GetFixtureB();
2312  if ((fixtureA == &fixture) || (fixtureB == &fixture))
2313  {
2314  Destroy(&contact, body);
2315  return true;
2316  }
2317  return false;
2318  });
2319  }
2320  }
2321 }
2322 
2323 PreStepStats::counter_type World::SynchronizeProxies(const StepConf& conf)
2324 {
2325  auto proxiesMoved = PreStepStats::counter_type{0};
2326  for_each(begin(m_bodiesForProxies), end(m_bodiesForProxies), [&](Body *b) {
2327  const auto xfm = b->GetTransformation();
2328  // Not always true: assert(GetTransform0(b->GetSweep()) == xfm);
2329  proxiesMoved += Synchronize(*b, xfm, xfm, conf.displaceMultiplier, conf.aabbExtension);
2330  });
2331  m_bodiesForProxies.clear();
2332  return proxiesMoved;
2333 }
2334 
2335 void World::SetType(Body& body, playrho::BodyType type)
2336 {
2337  assert(body.GetWorld() == this);
2338  if (body.GetType() == type)
2339  {
2340  return;
2341  }
2342 
2343  if (IsLocked())
2344  {
2345  throw WrongState("World::SetType: world is locked");
2346  }
2347 
2348  BodyAtty::SetTypeFlags(body, type);
2349  body.ResetMassData();
2350 
2351  // Destroy the attached contacts.
2352  BodyAtty::EraseContacts(body, [&](Contact& contact) {
2353  Destroy(&contact, &body);
2354  return true;
2355  });
2356 
2357  if (type == BodyType::Static)
2358  {
2359 #ifndef NDEBUG
2360  const auto xfm1 = GetTransform0(body.GetSweep());
2361  const auto xfm2 = body.GetTransformation();
2362  assert(xfm1 == xfm2);
2363 #endif
2364  RegisterForProxies(body);
2365  }
2366  else
2367  {
2368  body.SetAwake();
2369  const auto fixtures = body.GetFixtures();
2370  for_each(begin(fixtures), end(fixtures), [&](Body::Fixtures::value_type& f) {
2371  InternalTouchProxies(GetRef(f));
2372  });
2373  }
2374 }
2375 
2376 Fixture* World::CreateFixture(Body& body, const Shape& shape,
2377  const FixtureConf& def, bool resetMassData)
2378 {
2379  assert(body.GetWorld() == this);
2380 
2381  {
2382  const auto childCount = GetChildCount(shape);
2383  const auto minVertexRadius = GetMinVertexRadius();
2384  const auto maxVertexRadius = GetMaxVertexRadius();
2385  for (auto i = ChildCounter{0}; i < childCount; ++i)
2386  {
2387  const auto vr = GetVertexRadius(shape, i);
2388  if (!(vr >= minVertexRadius))
2389  {
2390  throw InvalidArgument("World::CreateFixture: vertex radius < min");
2391  }
2392  if (!(vr <= maxVertexRadius))
2393  {
2394  throw InvalidArgument("World::CreateFixture: vertex radius > max");
2395  }
2396  }
2397  }
2398 
2399  if (IsLocked())
2400  {
2401  throw WrongState("World::CreateFixture: world is locked");
2402  }
2403 
2404  //const auto fixture = BodyAtty::CreateFixture(body, shape, def);
2405  const auto fixture = FixtureAtty::Create(body, def, shape);
2406  BodyAtty::AddFixture(body, fixture);
2407 
2408  if (body.IsEnabled())
2409  {
2410  RegisterForProxies(*fixture);
2411  }
2412 
2413  // Adjust mass properties if needed.
2414  if (fixture->GetDensity() > 0_kgpm2)
2415  {
2416  BodyAtty::SetMassDataDirty(body);
2417  if (resetMassData)
2418  {
2419  body.ResetMassData();
2420  }
2421  }
2422 
2423  // Let the world know we have a new fixture. This will cause new contacts
2424  // to be created at the beginning of the next time step.
2425  SetNewFixtures();
2426 
2427  return fixture;
2428 }
2429 
2430 bool World::Destroy(Fixture& fixture, bool resetMassData)
2431 {
2432  auto& body = *fixture.GetBody();
2433  assert(body.GetWorld() == this);
2434 
2435  if (IsLocked())
2436  {
2437  throw WrongState("World::Destroy: world is locked");
2438  }
2439 
2440 #if 0
2441  /*
2442  * XXX: Should the destruction listener be called when the user requested that
2443  * the fixture be destroyed or only when the fixture is destroyed indirectly?
2444  */
2445  if (m_destructionListener)
2446  {
2447  m_destructionListener->SayGoodbye(fixture);
2448  }
2449 #endif
2450 
2451  // Destroy any contacts associated with the fixture.
2452  BodyAtty::EraseContacts(body, [&](Contact& contact) {
2453  const auto fixtureA = contact.GetFixtureA();
2454  const auto fixtureB = contact.GetFixtureB();
2455  if ((fixtureA == &fixture) || (fixtureB == &fixture))
2456  {
2457  Destroy(&contact, &body);
2458  return true;
2459  }
2460  return false;
2461  });
2462 
2463  UnregisterForProxies(fixture);
2464  DestroyProxies(fixture);
2465 
2466  if (!BodyAtty::RemoveFixture(body, &fixture))
2467  {
2468  // Fixture probably destroyed already.
2469  return false;
2470  }
2471  FixtureAtty::Delete(&fixture);
2472 
2473  BodyAtty::SetMassDataDirty(body);
2474  if (resetMassData)
2475  {
2476  body.ResetMassData();
2477  }
2478 
2479  return true;
2480 }
2481 
2482 void World::CreateProxies(Fixture& fixture, Length aabbExtension)
2483 {
2484  assert(fixture.GetProxyCount() == 0);
2485 
2486  const auto body = fixture.GetBody();
2487  const auto shape = fixture.GetShape();
2488  const auto xfm = GetTransformation(fixture);
2489 
2490  // Reserve proxy space and create proxies in the broad-phase.
2491  const auto childCount = GetChildCount(shape);
2492  auto proxies = std::make_unique<FixtureProxy[]>(childCount);
2493  for (auto childIndex = decltype(childCount){0}; childIndex < childCount; ++childIndex)
2494  {
2495  const auto dp = GetChild(shape, childIndex);
2496  const auto aabb = playrho::d2::ComputeAABB(dp, xfm);
2497 
2498  // Note: treeId from CreateLeaf can be higher than the number of fixture proxies.
2499  const auto fattenedAABB = GetFattenedAABB(aabb, aabbExtension);
2500  const auto treeId = m_tree.CreateLeaf(fattenedAABB, DynamicTree::LeafData{
2501  body, &fixture, childIndex});
2502  RegisterForProcessing(treeId);
2503  proxies[childIndex] = FixtureProxy{treeId};
2504  }
2505 
2506  FixtureAtty::SetProxies(fixture, std::move(proxies), childCount);
2507 }
2508 
2509 void World::DestroyProxies(Fixture& fixture) noexcept
2510 {
2511  const auto proxies = FixtureAtty::GetProxies(fixture);
2512  const auto childCount = size(proxies);
2513  if (childCount > 0)
2514  {
2515  // Destroy proxies in reverse order from what they were created in.
2516  for (auto i = childCount - 1; i < childCount; --i)
2517  {
2518  const auto treeId = proxies[i].treeId;
2519  UnregisterForProcessing(treeId);
2520  m_tree.DestroyLeaf(treeId);
2521  }
2522  }
2523  FixtureAtty::ResetProxies(fixture);
2524 }
2525 
2526 void World::TouchProxies(Fixture& fixture) noexcept
2527 {
2528  assert(fixture.GetBody()->GetWorld() == this);
2529  InternalTouchProxies(fixture);
2530 }
2531 
2532 void World::InternalTouchProxies(Fixture& fixture) noexcept
2533 {
2534  const auto proxyCount = fixture.GetProxyCount();
2535  for (auto i = decltype(proxyCount){0}; i < proxyCount; ++i)
2536  {
2537  RegisterForProcessing(fixture.GetProxy(i).treeId);
2538  }
2539 }
2540 
2541 ContactCounter World::Synchronize(Body& body,
2542  Transformation xfm1, Transformation xfm2,
2543  Real multiplier, Length extension)
2544 {
2545  assert(::playrho::IsValid(xfm1));
2546  assert(::playrho::IsValid(xfm2));
2547 
2548  auto updatedCount = ContactCounter{0};
2549  const auto displacement = multiplier * (xfm2.p - xfm1.p);
2550  const auto fixtures = body.GetFixtures();
2551  for_each(begin(fixtures), end(fixtures), [&](Body::Fixtures::value_type& f) {
2552  updatedCount += Synchronize(GetRef(f), xfm1, xfm2, displacement, extension);
2553  });
2554  return updatedCount;
2555 }
2556 
2557 ContactCounter World::Synchronize(Fixture& fixture,
2558  Transformation xfm1, Transformation xfm2,
2559  Length2 displacement, Length extension)
2560 {
2561  assert(::playrho::IsValid(xfm1));
2562  assert(::playrho::IsValid(xfm2));
2563 
2564  auto updatedCount = ContactCounter{0};
2565  const auto shape = fixture.GetShape();
2566  const auto proxies = FixtureAtty::GetProxies(fixture);
2567  auto childIndex = ChildCounter{0};
2568  for (auto& proxy: proxies)
2569  {
2570  const auto treeId = proxy.treeId;
2571 
2572  // Compute an AABB that covers the swept shape (may miss some rotation effect).
2573  const auto aabb = ComputeAABB(GetChild(shape, childIndex), xfm1, xfm2);
2574  if (!Contains(m_tree.GetAABB(treeId), aabb))
2575  {
2576  const auto newAabb = GetDisplacedAABB(GetFattenedAABB(aabb, extension),
2577  displacement);
2578  m_tree.UpdateLeaf(treeId, newAabb);
2579  RegisterForProcessing(treeId);
2580  ++updatedCount;
2581  }
2582  ++childIndex;
2583  }
2584  return updatedCount;
2585 }
2586 
2587 // Free functions...
2588 
2589 StepStats Step(World& world, Time delta, TimestepIters velocityIterations,
2590  TimestepIters positionIterations)
2591 {
2592  StepConf conf;
2593  conf.SetTime(delta);
2594  conf.regVelocityIterations = velocityIterations;
2595  conf.regPositionIterations = positionIterations;
2596  conf.toiVelocityIterations = velocityIterations;
2597  if (positionIterations == 0)
2598  {
2599  conf.toiPositionIterations = 0;
2600  }
2601  conf.dtRatio = delta * world.GetInvDeltaTime();
2602  return world.Step(conf);
2603 }
2604 
2605 ContactCounter GetTouchingCount(const World& world) noexcept
2606 {
2607  const auto contacts = world.GetContacts();
2608  return static_cast<ContactCounter>(count_if(cbegin(contacts), cend(contacts),
2609  [&](const World::Contacts::value_type &c) {
2610  return GetRef(std::get<Contact*>(c)).IsTouching();
2611  }));
2612 }
2613 
2614 size_t GetFixtureCount(const World& world) noexcept
2615 {
2616  auto sum = size_t{0};
2617  const auto bodies = world.GetBodies();
2618  for_each(cbegin(bodies), cend(bodies),
2619  [&](const World::Bodies::value_type &body) {
2620  sum += GetFixtureCount(GetRef(body));
2621  });
2622  return sum;
2623 }
2624 
2625 size_t GetShapeCount(const World& world) noexcept
2626 {
2627  auto shapes = std::set<const void*>();
2628  const auto bodies = world.GetBodies();
2629  for_each(cbegin(bodies), cend(bodies), [&](const World::Bodies::value_type &b) {
2630  const auto fixtures = GetRef(b).GetFixtures();
2631  for_each(cbegin(fixtures), cend(fixtures), [&](const Body::Fixtures::value_type& f) {
2632  shapes.insert(GetData(GetRef(f).GetShape()));
2633  });
2634  });
2635  return size(shapes);
2636 }
2637 
2638 BodyCounter GetAwakeCount(const World& world) noexcept
2639 {
2640  const auto bodies = world.GetBodies();
2641  return static_cast<BodyCounter>(count_if(cbegin(bodies), cend(bodies),
2642  [&](const World::Bodies::value_type &b) {
2643  return GetRef(b).IsAwake(); }));
2644 }
2645 
2646 BodyCounter Awaken(World& world) noexcept
2647 {
2648  // Can't use count_if since body gets modified.
2649  auto awoken = BodyCounter{0};
2650  const auto bodies = world.GetBodies();
2651  for_each(begin(bodies), end(bodies), [&](World::Bodies::value_type &b) {
2652  if (playrho::d2::Awaken(GetRef(b)))
2653  {
2654  ++awoken;
2655  }
2656  });
2657  return awoken;
2658 }
2659 
2660 void SetAccelerations(World& world, Acceleration acceleration) noexcept
2661 {
2662  const auto bodies = world.GetBodies();
2663  for_each(begin(bodies), end(bodies), [&](World::Bodies::value_type &b) {
2664  SetAcceleration(GetRef(b), acceleration);
2665  });
2666 }
2667 
2668 void SetAccelerations(World& world, LinearAcceleration2 acceleration) noexcept
2669 {
2670  const auto bodies = world.GetBodies();
2671  for_each(begin(bodies), end(bodies), [&](World::Bodies::value_type &b) {
2672  SetLinearAcceleration(GetRef(b), acceleration);
2673  });
2674 }
2675 
2676 Body* FindClosestBody(const World& world, Length2 location) noexcept
2677 {
2678  const auto bodies = world.GetBodies();
2679  auto found = static_cast<decltype(bodies)::iterator_type::value_type>(nullptr);
2680  auto minLengthSquared = std::numeric_limits<Area>::infinity();
2681  for (const auto& b: bodies)
2682  {
2683  auto& body = GetRef(b);
2684  const auto bodyLoc = body.GetLocation();
2685  const auto lengthSquared = GetMagnitudeSquared(bodyLoc - location);
2686  if (minLengthSquared > lengthSquared)
2687  {
2688  minLengthSquared = lengthSquared;
2689  found = &body;
2690  }
2691  }
2692  return found;
2693 }
2694 
2695 } // namespace d2
2696 
2697 RegStepStats& Update(RegStepStats& lhs, const IslandStats& rhs) noexcept
2698 {
2699  lhs.maxIncImpulse = std::max(lhs.maxIncImpulse, rhs.maxIncImpulse);
2700  lhs.minSeparation = std::min(lhs.minSeparation, rhs.minSeparation);
2701  lhs.islandsSolved += rhs.solved;
2702  lhs.sumPosIters += rhs.positionIterations;
2703  lhs.sumVelIters += rhs.velocityIterations;
2704  lhs.bodiesSlept += rhs.bodiesSlept;
2705  return lhs;
2706 }
2707 
2708 } // namespace playrho