WorldManifold.cpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2007-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 
25 
26 namespace playrho {
27 namespace d2 {
28 
29 namespace {
30 
31 inline WorldManifold GetForCircles(const Manifold& manifold,
32  const Transformation xfA, const Length radiusA,
33  const Transformation xfB, const Length radiusB)
34 {
35  assert(manifold.GetPointCount() == 1);
36 
37  const auto pointA = Transform(manifold.GetLocalPoint(), xfA);
38  const auto pointB = Transform(manifold.GetPoint(0).localPoint, xfB);
39  const auto normal = GetUnitVector(pointB - pointA, UnitVec::GetRight());
40  const auto cA = pointA + (radiusA * normal);
41  const auto cB = pointB - (radiusB * normal);
42  const auto p0 = (cA + cB) / Real{2};
43  const auto c0 = manifold.GetContactImpulses(0);
44  const auto s0 = Dot(cB - cA, normal);
45  return WorldManifold{normal, WorldManifold::PointData{p0, c0, s0}};
46 }
47 
48 inline WorldManifold GetForFaceA(const Manifold& manifold,
49  const Transformation xfA, const Length radiusA,
50  const Transformation xfB, const Length radiusB)
51 {
52  const auto normal = Rotate(manifold.GetLocalNormal(), xfA.q);
53  const auto planePoint = Transform(manifold.GetLocalPoint(), xfA);
54  const auto pointFn = [&](Manifold::size_type index) {
55  const auto impulses = manifold.GetContactImpulses(index);
56  const auto clipPoint = Transform(manifold.GetPoint(index).localPoint, xfB);
57  const auto cA = clipPoint + (radiusA - Dot(clipPoint - planePoint, normal)) * normal;
58  const auto cB = clipPoint - (radiusB * normal);
59  return WorldManifold::PointData{(cA + cB) / Real{2}, impulses, Dot(cB - cA, normal)};
60  };
61 
62  assert(manifold.GetPointCount() <= 2);
63 
64  switch (manifold.GetPointCount())
65  {
66  case 1: return WorldManifold{normal, pointFn(0)};
67  case 2: return WorldManifold{normal, pointFn(0), pointFn(1)};
68  default: break; // should never be reached
69  }
70 
71  // should never be reached
72  return WorldManifold{normal};
73 }
74 
75 inline WorldManifold GetForFaceB(const Manifold& manifold,
76  const Transformation xfA, const Length radiusA,
77  const Transformation xfB, const Length radiusB)
78 {
79  const auto normal = Rotate(manifold.GetLocalNormal(), xfB.q);
80  const auto planePoint = Transform(manifold.GetLocalPoint(), xfB);
81  const auto pointFn = [&](Manifold::size_type index) {
82  const auto impulses = manifold.GetContactImpulses(index);
83  const auto clipPoint = Transform(manifold.GetPoint(index).localPoint, xfA);
84  const auto cB = clipPoint + (radiusB - Dot(clipPoint - planePoint, normal)) * normal;
85  const auto cA = clipPoint - (radiusA * normal);
86  return WorldManifold::PointData{(cA + cB) / Real{2}, impulses, Dot(cA - cB, normal)};
87  };
88 
89  assert(manifold.GetPointCount() <= 2);
90 
91  // Negate normal given to world manifold constructor to ensure it points from A to B.
92  switch (manifold.GetPointCount())
93  {
94  case 1: return WorldManifold{-normal, pointFn(0)};
95  case 2: return WorldManifold{-normal, pointFn(0), pointFn(1)};
96  default: break; // should never be reached
97  }
98 
99  // should never be reached
100  return WorldManifold{-normal};
101 }
102 
103 } // anonymous namespace
104 
106  Transformation xfA, Length radiusA,
107  Transformation xfB, Length radiusB)
108 {
109  const auto type = manifold.GetType();
110 
111  assert((type == Manifold::e_circles) || (type == Manifold::e_faceA) ||
112  (type == Manifold::e_faceB) || (type == Manifold::e_unset));
113 
114  switch (type)
115  {
116  case Manifold::e_circles: return GetForCircles(manifold, xfA, radiusA, xfB, radiusB);
117  case Manifold::e_faceA: return GetForFaceA(manifold, xfA, radiusA, xfB, radiusB);
118  case Manifold::e_faceB: return GetForFaceB(manifold, xfA, radiusA, xfB, radiusB);
119  default: break;
120  }
121 
122  // When type == Manifold::e_unset (or is an undefined value & NDEBUG is defined)...
123  return WorldManifold{};
124 }
125 
127 {
128  const auto fA = contact.GetFixtureA();
129  const auto iA = contact.GetChildIndexA();
130  const auto xfA = GetTransformation(*fA);
131  const auto radiusA = GetVertexRadius(fA->GetShape(), iA);
132 
133  const auto fB = contact.GetFixtureB();
134  const auto iB = contact.GetChildIndexB();
135  const auto xfB = GetTransformation(*fB);
136  const auto radiusB = GetVertexRadius(fB->GetShape(), iB);
137 
138  return GetWorldManifold(contact.GetManifold(), xfA, radiusA, xfB, radiusB);
139 }
140 
141 } /* namespace d2 */
142 } /* namespace playrho */