Simplex.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 
21 
22 namespace playrho {
23 namespace d2 {
24 
25 IndexPair3 GetIndexPairs(const SimplexEdges& collection) noexcept
26 {
28  switch (size(collection))
29  {
30  case 3: list[2] = collection[2].GetIndexPair(); // fall through
31  case 2: list[1] = collection[1].GetIndexPair(); // fall through
32  case 1: list[0] = collection[0].GetIndexPair(); // fall through
33  }
34  return list;
35 }
36 
37 Length2 CalcSearchDirection(const SimplexEdges& simplexEdges) noexcept
38 {
39  switch (size(simplexEdges))
40  {
41  case 1:
42  {
43  return -GetPointDelta(simplexEdges[0]);
44  }
45  case 2:
46  {
47  const auto e12 = GetPointDelta(simplexEdges[1]) - GetPointDelta(simplexEdges[0]);
48  const auto e0 = GetPointDelta(simplexEdges[0]);
49  const auto sgn = Cross(e12, -e0);
50  // If sgn > 0, then origin is left of e12, else origin is right of e12.
51  return (sgn > 0_m2)? GetRevPerpendicular(e12): GetFwdPerpendicular(e12);
52  }
53  default:
54  break;
55  }
56  assert(size(simplexEdges) < 4);
57  return Length2{0_m, 0_m};
58 }
59 
60 Simplex Simplex::Get(const SimplexEdge& s0) noexcept
61 {
62  return Simplex{{s0}, {1}};
63 }
64 
65 Simplex Simplex::Get(const SimplexEdge& s0, const SimplexEdge& s1) noexcept
66 {
67  assert(s0.GetIndexPair() != s1.GetIndexPair() || s0 == s1);
68 
69  // Solves the given line segment simplex using barycentric coordinates.
70  //
71  // p = a1 * w1 + a2 * w2
72  // a1 + a2 = 1
73  //
74  // The vector from the origin to the closest point on the line is
75  // perpendicular to the line.
76  // e12 = w2 - w1
77  // dot(p, e) = 0
78  // a1 * dot(w1, e) + a2 * dot(w2, e) = 0
79  //
80  // 2-by-2 linear system
81  // [1 1 ][a1] = [1]
82  // [w1.e12 w2.e12][a2] = [0]
83  //
84  // Define
85  // d12_1 = dot(w2, e12)
86  // d12_2 = -dot(w1, e12)
87  // d12_sum = d12_1 + d12_2
88  //
89  // Solution
90  // a1 = d12_1 / d12_sum
91  // a2 = d12_2 / d12_sum
92 
93  const auto w1 = GetPointDelta(s0);
94  const auto w2 = GetPointDelta(s1);
95  const auto e12 = w2 - w1;
96 
97  // w1 region
98  const auto d12_2 = -Dot(w1, e12);
99  if (d12_2 <= 0_m2)
100  {
101  // a2 <= 0, so we clamp it to 0
102  return Simplex{{s0}, {1}};
103  }
104 
105  // w2 region
106  const auto d12_1 = Dot(w2, e12);
107  if (d12_1 <= 0_m2)
108  {
109  // a1 <= 0, so we clamp it to 0
110  return Simplex{{s1}, {1}};
111  }
112 
113  // Must be in e12 region.
114  const auto inv_sum = Real{1} / (d12_1 + d12_2);
115  return Simplex{{s0, s1}, {d12_1 * inv_sum, d12_2 * inv_sum}};
116 }
117 
118 Simplex Simplex::Get(const SimplexEdge& s0, const SimplexEdge& s1, const SimplexEdge& s2) noexcept
119 {
120  // Solves the given 3-edge simplex.
121  //
122  // Possible regions:
123  // - points[2]
124  // - edge points[0]-points[2]
125  // - edge points[1]-points[2]
126  // - inside the triangle
127 
128  const auto w1 = GetPointDelta(s0);
129  const auto w2 = GetPointDelta(s1);
130  const auto w3 = GetPointDelta(s2);
131 
132  // Edge12
133  // [1 1 ][a1] = [1]
134  // [w1.e12 w2.e12][a2] = [0]
135  // a3 = 0
136  const auto e12 = w2 - w1;
137  const auto d12_1 = Dot(w2, e12);
138  const auto d12_2 = -Dot(w1, e12);
139 
140  // Edge13
141  // [1 1 ][a1] = [1]
142  // [w1.e13 w3.e13][a3] = [0]
143  // a2 = 0
144  const auto e13 = w3 - w1;
145  const auto d13_1 = Dot(w3, e13);
146  const auto d13_2 = -Dot(w1, e13);
147 
148  // Edge23
149  // [1 1 ][a2] = [1]
150  // [w2.e23 w3.e23][a3] = [0]
151  // a1 = 0
152  const auto e23 = w3 - w2;
153  const auto d23_1 = Dot(w3, e23);
154  const auto d23_2 = -Dot(w2, e23);
155 
156  // w1 region
157  if ((d12_2 <= 0_m2) && (d13_2 <= 0_m2))
158  {
159  return Simplex{{s0}, {1}};
160  }
161 
162  // w2 region
163  if ((d12_1 <= 0_m2) && (d23_2 <= 0_m2))
164  {
165  return Simplex{{s1}, {1}};
166  }
167 
168  // w3 region
169  if ((d13_1 <= 0_m2) && (d23_1 <= 0_m2))
170  {
171  return Simplex{{s2}, {1}};
172  }
173 
174  // Triangle123
175  const auto n123 = Cross(e12, e13);
176 
177  // e12
178  const auto cp_w1_w2 = Cross(w1, w2);
179  const auto d123_3 = n123 * cp_w1_w2;
180  if ((d12_1 > 0_m2) && (d12_2 > 0_m2) && (d123_3 <= 0 * SquareMeter * SquareMeter))
181  {
182  const auto inv_sum = Real{1} / (d12_1 + d12_2);
183  return Simplex{{s0, s1}, {d12_1 * inv_sum, d12_2 * inv_sum}};
184  }
185 
186  // e13
187  const auto cp_w3_w1 = Cross(w3, w1);
188  const auto d123_2 = n123 * cp_w3_w1;
189  if ((d13_1 > 0_m2) && (d13_2 > 0_m2) && (d123_2 <= 0 * SquareMeter * SquareMeter))
190  {
191  const auto inv_sum = Real{1} / (d13_1 + d13_2);
192  return Simplex{{s0, s2}, {d13_1 * inv_sum, d13_2 * inv_sum}};
193  }
194 
195  // e23
196  const auto cp_w2_w3 = Cross(w2, w3);
197  const auto d123_1 = n123 * cp_w2_w3;
198  if ((d23_1 > 0_m2) && (d23_2 > 0_m2) && (d123_1 <= 0 * SquareMeter * SquareMeter))
199  {
200  const auto inv_sum = Real{1} / (d23_1 + d23_2);
201  return Simplex{{s2, s1}, {d23_2 * inv_sum, d23_1 * inv_sum}};
202  }
203 
204  // Must be in triangle123
205  const auto inv_sum = Real{1} / (d123_1 + d123_2 + d123_3);
206  return Simplex{{s0, s1, s2}, {d123_1 * inv_sum, d123_2 * inv_sum, d123_3 * inv_sum}};
207 }
208 
209 Simplex Simplex::Get(const SimplexEdges& edges) noexcept
210 {
211  const auto count = edges.size();
212  assert(count < 4);
213  switch (count)
214  {
215  case 1: return Get(edges[0]);
216  case 2: return Get(edges[0], edges[1]);
217  case 3: return Get(edges[0], edges[1], edges[2]);
218  default: break; // should be zero in this case
219  }
220  return Simplex{};
221 }
222 
224 {
225  assert(simplexEdges.size() < 4);
226  switch (simplexEdges.size())
227  {
228  case 1: return Real{0};
229  case 2:
230  {
231  const auto delta = GetPointDelta(simplexEdges[1]) - GetPointDelta(simplexEdges[0]);
232  return StripUnit(GetMagnitude(delta)); // Length
233  }
234  case 3:
235  {
236  const auto delta10 = GetPointDelta(simplexEdges[1]) - GetPointDelta(simplexEdges[0]);
237  const auto delta20 = GetPointDelta(simplexEdges[2]) - GetPointDelta(simplexEdges[0]);
238  return StripUnit(Cross(delta10, delta20)); // Area
239  }
240  default: break; // should be zero in this case
241  }
242  return Real{0};
243 }
244 
245 } // namespace d2
246 } // namespace playrho