Manifold.hpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2006-2009 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  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  * 1. The origin of this software must not be misrepresented; you must not
12  * claim that you wrote the original software. If you use this software
13  * in a product, an acknowledgment in the product documentation would be
14  * appreciated but is not required.
15  * 2. Altered source versions must be plainly marked as such, and must not be
16  * misrepresented as being the original software.
17  * 3. This notice may not be removed or altered from any source distribution.
18  */
19 
20 #ifndef PLAYRHO_COLLISION_MANIFOLD_HPP
21 #define PLAYRHO_COLLISION_MANIFOLD_HPP
22 
23 #include <PlayRho/Common/Math.hpp>
26 
27 namespace playrho {
28 namespace d2 {
29 
30 class DistanceProxy;
31 struct Transformation;
32 
64 class alignas(64) Manifold
65 {
66 public:
67 
69  using size_type = std::remove_const<decltype(MaxManifoldPoints)>::type;
70 
73 
76 
77  struct Conf;
78 
81  enum Type: std::uint8_t
82  {
87 
97 
105 
113  };
114 
125  struct Point
126  {
138 
144 
150 
156  };
157 
158  // For Circles type manifolds...
159 
165  static inline Manifold GetForCircles(Length2 vA, CfIndex iA, Length2 vB, CfIndex iB) noexcept
166  {
167  return Manifold{e_circles, GetInvalid<UnitVec>(), vA, 1, {{
169  }}};
170  }
171 
172  // For Face A type manifolds...
173 
177  static inline Manifold GetForFaceA(UnitVec normalA, Length2 faceA) noexcept
178  {
179  return Manifold{e_faceA, normalA, faceA, 0, {{}}};
180  }
181 
186  static inline Manifold GetForFaceA(UnitVec ln, Length2 lp,
187  const Point& mp1) noexcept
188  {
189  //assert(mp1.contactFeature.typeA == ContactFeature::e_face || mp1.contactFeature.typeB == ContactFeature::e_face);
190  return Manifold{e_faceA, ln, lp, 1, {{mp1}}};
191  }
192 
198  static inline Manifold GetForFaceA(UnitVec ln, Length2 lp,
199  const Point& mp1, const Point& mp2) noexcept
200  {
201  //assert(mp1.contactFeature.typeA == ContactFeature::e_face || mp1.contactFeature.typeB == ContactFeature::e_face);
202  //assert(mp2.contactFeature.typeA == ContactFeature::e_face || mp2.contactFeature.typeB == ContactFeature::e_face);
203  //assert(mp1.contactFeature != mp2.contactFeature);
204  return Manifold{e_faceA, ln, lp, 2, {{mp1, mp2}}};
205  }
206 
207  // For Face B...
208 
212  static inline Manifold GetForFaceB(UnitVec ln, Length2 lp) noexcept
213  {
214  return Manifold{e_faceB, ln, lp, 0, {{}}};
215  }
216 
221  static inline Manifold GetForFaceB(UnitVec ln, Length2 lp,
222  const Point& mp1) noexcept
223  {
224  //assert(mp1.contactFeature.typeA == ContactFeature::e_face || mp1.contactFeature.typeB == ContactFeature::e_face);
225  return Manifold{e_faceB, ln, lp, 1, {{mp1}}};
226  }
227 
233  static inline Manifold GetForFaceB(UnitVec ln, Length2 lp,
234  const Point& mp1, const Point& mp2) noexcept
235  {
236  //assert(mp1.contactFeature.typeA == ContactFeature::e_face || mp1.contactFeature.typeB == ContactFeature::e_face);
237  //assert(mp2.contactFeature.typeA == ContactFeature::e_face || mp2.contactFeature.typeB == ContactFeature::e_face);
238  //assert(mp1.contactFeature != mp2.contactFeature);
239  return Manifold{e_faceB, ln, lp, 2, {{mp1, mp2}}};
240  }
241 
243  static inline Manifold GetForFaceA(UnitVec na, CfIndex ia, Length2 pa) noexcept
244  {
245  return Manifold{e_faceA, na, pa, 0, {{
246  Point{GetInvalid<Length2>(), ContactFeature{ContactFeature::e_face, ia, ContactFeature::e_face, 0}},
247  Point{GetInvalid<Length2>(), ContactFeature{ContactFeature::e_face, ia, ContactFeature::e_face, 0}}
248  }}};
249  }
250 
252  static inline Manifold GetForFaceB(UnitVec nb, CfIndex ib, Length2 pb) noexcept
253  {
254  return Manifold{e_faceB, nb, pb, 0, {{
255  Point{GetInvalid<Length2>(), ContactFeature{ContactFeature::e_face, 0, ContactFeature::e_face, ib}},
256  Point{GetInvalid<Length2>(), ContactFeature{ContactFeature::e_face, 0, ContactFeature::e_face, ib}}
257  }}};
258  }
259 
261  static inline Manifold GetForFaceA(UnitVec na, CfIndex ia, Length2 pa,
262  CfType tb0, CfIndex ib0, Length2 pb0) noexcept
263  {
264  return Manifold{e_faceA, na, pa, 1, {{
265  Point{pb0, ContactFeature{ContactFeature::e_face, ia, tb0, ib0}},
266  Point{pb0, ContactFeature{ContactFeature::e_face, ia, tb0, ib0}}
267  }}};
268  }
269 
271  static inline Manifold GetForFaceB(UnitVec nb, CfIndex ib, Length2 pb,
272  CfType ta0, CfIndex ia0, Length2 pa0) noexcept
273  {
274  return Manifold{e_faceB, nb, pb, 1, {{
275  Point{pa0, ContactFeature{ta0, ia0, ContactFeature::e_face, ib}},
276  Point{pa0, ContactFeature{ta0, ia0, ContactFeature::e_face, ib}}
277  }}};
278  }
279 
281  static inline Manifold GetForFaceA(UnitVec na, CfIndex ia, Length2 pa,
282  CfType tb0, CfIndex ib0, Length2 pb0,
283  CfType tb1, CfIndex ib1, Length2 pb1) noexcept
284  {
285  return Manifold{e_faceA, na, pa, 2, {{
286  Point{pb0, ContactFeature{ContactFeature::e_face, ia, tb0, ib0}},
287  Point{pb1, ContactFeature{ContactFeature::e_face, ia, tb1, ib1}}
288  }}};
289  }
290 
292  static inline Manifold GetForFaceB(UnitVec nb, CfIndex ib, Length2 pb,
293  CfType ta0, CfIndex ia0, Length2 pa0,
294  CfType ta1, CfIndex ia1, Length2 pa1) noexcept
295  {
296  return Manifold{e_faceB, nb, pb, 2, {{
297  Point{pa0, ContactFeature{ta0, ia0, ContactFeature::e_face, ib}},
298  Point{pa1, ContactFeature{ta1, ia1, ContactFeature::e_face, ib}}
299  }}};
300  }
301 
307  Manifold() = default;
308 
310  Manifold(const Manifold& copy) = default;
311 
317  PLAYRHO_CONSTEXPR inline Type GetType() const noexcept { return m_type; }
318 
332  PLAYRHO_CONSTEXPR inline size_type GetPointCount() const noexcept { return m_pointCount; }
333 
336  {
337  assert(index < m_pointCount);
338  return m_points[index].contactFeature;
339  }
340 
345  {
346  assert(index < m_pointCount);
347  return Momentum2{m_points[index].normalImpulse, m_points[index].tangentImpulse};
348  }
349 
353  void SetContactImpulses(size_type index, Momentum2 value) noexcept
354  {
355  assert(index < m_pointCount);
356  m_points[index].normalImpulse = get<0>(value);
357  m_points[index].tangentImpulse = get<1>(value);
358  }
359 
361  const Point& GetPoint(size_type index) const noexcept
362  {
363  assert((0 <= index) && (index < m_pointCount));
364  return m_points[index];
365  }
366 
369  {
370  assert((index < m_pointCount) || (index < MaxManifoldPoints && n == 0_Ns && t == 0_Ns));
371  m_points[index].normalImpulse = n;
372  m_points[index].tangentImpulse = t;
373  }
374 
381  void AddPoint(const Point& mp) noexcept;
382 
384  void AddPoint(CfType type, CfIndex index, Length2 point) noexcept;
385 
391  PLAYRHO_CONSTEXPR inline UnitVec GetLocalNormal() const noexcept
392  {
393  assert(m_type != e_unset);
394  assert(m_type != e_circles);
395  return m_localNormal;
396  }
397 
406  PLAYRHO_CONSTEXPR inline Length2 GetLocalPoint() const noexcept
407  {
408  assert(m_type != e_unset);
409  return m_localPoint;
410  }
411 
414  {
415  assert((0 <= index) && (index < m_pointCount));
416  return m_points[index].localPoint;
417  }
418 
419 private:
420 
422  struct PointArray
423  {
424  Point elements[MaxManifoldPoints];
425 
427  PLAYRHO_CONSTEXPR inline Point& operator[](std::size_t i) { return elements[i]; }
428 
430  PLAYRHO_CONSTEXPR const Point& operator[](std::size_t i) const { return elements[i]; }
431  };
432 
439  PLAYRHO_CONSTEXPR inline Manifold(Type t, UnitVec ln, Length2 lp, size_type n, const PointArray& mpa) noexcept;
440 
441  Type m_type = e_unset;
442  size_type m_pointCount = 0;
443 
447  UnitVec m_localNormal = GetInvalid<decltype(m_localNormal)>();
448 
452  Length2 m_localPoint = GetInvalid<Length2>();
453 
454  PointArray m_points;
455 };
456 
459 {
462 
466 
469 
475 };
476 
480 {
481  return Manifold::Conf{};
482 }
483 
484 PLAYRHO_CONSTEXPR inline Manifold::Manifold(Type t, UnitVec ln, Length2 lp, size_type n,
485  const PointArray& mpa) noexcept:
486  m_type{t}, m_pointCount{n}, m_localNormal{ln}, m_localPoint{lp}, m_points{mpa}
487 {
488  assert(t != e_unset || n == 0);
489  assert(t == e_unset || IsValid(lp));
490  assert((t == e_unset) || (t == e_circles) || IsValid(ln));
491  assert((t != e_circles) || (n == 1 && !IsValid(ln)));
492  //assert((t != e_circles) || (n == 1 && !IsValid(ln) && mpa[0].contactFeature.typeA == ContactFeature::e_vertex && mpa[0].contactFeature.typeB == ContactFeature::e_vertex));
493 }
494 
495 inline void Manifold::AddPoint(const Point& mp) noexcept
496 {
497  assert(m_type != e_unset);
498  assert(m_type != e_circles || m_pointCount == 0);
499  assert(m_pointCount < MaxManifoldPoints);
500  // assert((m_pointCount == 0) || (mp.contactFeature != m_points[0].contactFeature));
501  //assert((m_type != e_circles) || (mp.contactFeature.typeA == ContactFeature::e_vertex || mp.contactFeature.typeB == ContactFeature::e_vertex));
502  //assert((m_type != e_faceA) || ((mp.contactFeature.typeA == ContactFeature::e_face) && (m_pointCount == 0 || mp.contactFeature.indexA == m_points[0].contactFeature.indexA)));
503  //assert((m_type != e_faceB) || (mp.contactFeature.typeB == ContactFeature::e_face));
504  m_points[m_pointCount] = mp;
505  ++m_pointCount;
506 }
507 
508 inline void Manifold::AddPoint(CfType type, CfIndex index, Length2 point) noexcept
509 {
510  assert(m_pointCount < MaxManifoldPoints);
511  switch (m_type)
512  {
513  case e_unset:
514  break;
515  case e_circles:
516  break;
517  case e_faceA:
518  m_points[m_pointCount].localPoint = point;
519  m_points[m_pointCount].contactFeature.typeB = type;
520  m_points[m_pointCount].contactFeature.indexB = index;
521  ++m_pointCount;
522  break;
523  case e_faceB:
524  m_points[m_pointCount].localPoint = point;
525  m_points[m_pointCount].contactFeature.typeA = type;
526  m_points[m_pointCount].contactFeature.indexA = index;
527  ++m_pointCount;
528  break;
529  }
530 }
531 
532 // Free functions...
533 
536 bool operator==(const Manifold::Point& lhs, const Manifold::Point& rhs) noexcept;
537 
540 bool operator!=(const Manifold::Point& lhs, const Manifold::Point& rhs) noexcept;
541 
546 bool operator==(const Manifold& lhs, const Manifold& rhs) noexcept;
547 
551 bool operator!=(const Manifold& lhs, const Manifold& rhs) noexcept;
552 
568 Manifold GetManifold(bool flipped,
569  const DistanceProxy& shape0, const Transformation& xf0,
570  const VertexCounter idx0,
571  const DistanceProxy& shape1, const Transformation& xf1,
572  const VertexCounter2 indices1,
573  const Manifold::Conf conf);
574 
576 Manifold GetManifold(bool flipped, Length totalRadius,
577  const DistanceProxy& shape, const Transformation& sxf,
578  Length2 point, const Transformation& xfm);
579 
581 Manifold GetManifold(Length2 locationA, const Transformation& xfA,
582  Length2 locationB, const Transformation& xfB,
583  Length totalRadius) noexcept;
584 
593 Manifold CollideShapes(const DistanceProxy& shapeA, const Transformation& xfA,
594  const DistanceProxy& shapeB, const Transformation& xfB,
596 #if 0
597 Manifold CollideCached(const DistanceProxy& shapeA, const Transformation& xfA,
598  const DistanceProxy& shapeB, const Transformation& xfB,
600 #endif
601 
602 #ifdef DEFINE_GET_MANIFOLD
603 Manifold GetManifold(const DistanceProxy& proxyA, const Transformation& transformA,
604  const DistanceProxy& proxyB, const Transformation& transformB);
605 #endif
606 
607 #if 0
609  ContactFeature::Index index);
610 #endif
611 
613 const char* GetName(Manifold::Type type) noexcept;
614 
615 } // namespace d2
616 
619 template <>
620 PLAYRHO_CONSTEXPR inline bool IsValid(const d2::Manifold& value) noexcept
621 {
622  return value.GetType() != d2::Manifold::e_unset;
623 }
624 
625 } // namespace playrho
626 
627 #endif // PLAYRHO_COLLISION_MANIFOLD_HPP