ShapeSeparation.cpp
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  *
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 
24 #include <algorithm>
25 
26 namespace playrho {
27 namespace d2 {
28 
29 namespace {
30 
38 LengthIndices GetMinSeparationInfo(Length2 origin, UnitVec direction,
39  Range<DistanceProxy::ConstVertexIterator> vertices)
40 {
41  // Search for vertices most anti-parallel to directional normal from origin.
42  // See: https://en.wikipedia.org/wiki/Antiparallel_(mathematics)#Antiparallel_vectors
43  auto minSeparation = std::numeric_limits<Length>::infinity();
44  auto first = InvalidVertex;
45  auto second = InvalidVertex;
46  auto i = VertexCounter{0};
47  for (const auto& vertex: vertices)
48  {
49  const auto s = Dot(direction, vertex - origin);
50  if (minSeparation > s)
51  {
52  // most anti-parallel so far is a vertex
53  minSeparation = s;
54  first = i;
55  second = InvalidVertex;
56  }
57  else if (minSeparation == s)
58  {
59  // most anti-parallel so far is an edge
60  second = i;
61  }
62  ++i;
63  }
64  return LengthIndices{minSeparation, {{first, second}}};
65 }
66 
67 } // anonymous namespace
68 
70  const DistanceProxy& proxy2, Transformation xf2)
71 {
72  // Find the max separation between proxy1 and proxy2 using edge normals from proxy1.
73  auto separation = -std::numeric_limits<Length>::infinity();
74  auto firstIndex = InvalidVertex;
75  auto secondIndices = VertexCounter2{{InvalidVertex, InvalidVertex}};
76 #if 1
77  const auto xf = MulT(xf1, xf2);
78  const Length2 p2vertices[4] = {
79  Transform(proxy2.GetVertex(0), xf),
80  Transform(proxy2.GetVertex(1), xf),
81  Transform(proxy2.GetVertex(2), xf),
82  Transform(proxy2.GetVertex(3), xf),
83  };
84  const auto vertices = Range<DistanceProxy::ConstVertexIterator>(p2vertices, p2vertices + 4);
85 #else
86  const auto xf = MulT(xf2, xf1);
87  const auto vertices = proxy2.GetVertices();
88 #endif
89  for (auto i = VertexCounter{0}; i < VertexCounter{4}; ++i)
90  {
91  // Get proxy1 normal and vertex relative to proxy2.
92 #if 1
93  const auto origin = proxy1.GetVertex(i);
94  const auto normal = proxy1.GetNormal(i);
95  const auto ap = GetMinSeparationInfo(origin, normal, vertices);
96 #else
97  const auto origin = Transform(proxy1.GetVertex(i), xf);
98  const auto normal = Rotate(proxy1.GetNormal(i), xf.q);
99  const auto ap = GetMinIndexSeparation(origin, normal, vertices);
100 #endif
101  if (separation < ap.distance)
102  {
103  separation = ap.distance;
104  secondIndices = ap.indices;
105  firstIndex = i;
106  }
107  }
108  return SeparationInfo{separation, firstIndex, secondIndices};
109 }
110 
112  const DistanceProxy& proxy2, Transformation xf2)
113 {
114  // Find the max separation between proxy1 and proxy2 using edge normals from proxy1.
115  auto separation = -std::numeric_limits<Length>::infinity();
116  auto firstIndex = InvalidVertex;
117  auto secondIndices = VertexCounter2{{InvalidVertex, InvalidVertex}};
118  const auto count1 = proxy1.GetVertexCount();
119  const auto xf = MulT(xf2, xf1);
120  const auto proxy2vertices = proxy2.GetVertices();
121  for (auto i = VertexCounter{0}; i < count1; ++i)
122  {
123  // Get proxy1 normal and vertex relative to proxy2.
124  const auto origin = Transform(proxy1.GetVertex(i), xf);
125  const auto normal = Rotate(proxy1.GetNormal(i), xf.q);
126  const auto ap = GetMinSeparationInfo(origin, normal, proxy2vertices);
127  if (separation < ap.distance)
128  {
129  separation = ap.distance;
130  secondIndices = ap.indices;
131  firstIndex = i;
132  }
133  }
134  return SeparationInfo{separation, firstIndex, secondIndices};
135 }
136 
138  const DistanceProxy& proxy2, Transformation xf2,
139  Length stop)
140 {
141  // Find the max separation between proxy1 and proxy2 using edge normals from proxy1.
142  auto separation = -std::numeric_limits<Length>::infinity();
143  auto firstIndex = InvalidVertex;
144  auto secondIndices = VertexCounter2{{InvalidVertex, InvalidVertex}};
145  const auto xf = MulT(xf2, xf1);
146  const auto count1 = proxy1.GetVertexCount();
147  for (auto i = VertexCounter{0}; i < count1; ++i)
148  {
149  // Get proxy1 normal and vertex relative to proxy2.
150  const auto origin = Transform(proxy1.GetVertex(i), xf);
151  const auto normal = Rotate(proxy1.GetNormal(i), xf.q);
152  const auto ap = GetMinSeparationInfo(origin, normal, proxy2.GetVertices());
153  if (stop < ap.distance)
154  {
155  return SeparationInfo{ap.distance, i, ap.indices};
156  }
157  if (separation < ap.distance)
158  {
159  separation = ap.distance;
160  secondIndices = ap.indices;
161  firstIndex = i;
162  }
163  }
164  return SeparationInfo{separation, firstIndex, secondIndices};
165 }
166 
168  Length stop)
169 {
170  // Find the max separation between proxy1 and proxy2 using edge normals from proxy1.
171  auto separation = -std::numeric_limits<Length>::infinity();
172  auto firstIndex = InvalidVertex;
173  auto secondIndices = VertexCounter2{{InvalidVertex, InvalidVertex}};
174  const auto count1 = proxy1.GetVertexCount();
175  for (auto i = decltype(count1){0}; i < count1; ++i)
176  {
177  // Get proxy1 normal and vertex relative to proxy2.
178  const auto origin = proxy1.GetVertex(i);
179  const auto normal = proxy1.GetNormal(i);
180  const auto ap = GetMinSeparationInfo(origin, normal, proxy2.GetVertices());
181  if (stop < ap.distance)
182  {
183  return SeparationInfo{ap.distance, i, ap.indices};
184  }
185  if (separation < ap.distance)
186  {
187  separation = ap.distance;
188  secondIndices = ap.indices;
189  firstIndex = i;
190  }
191  }
192  return SeparationInfo{separation, firstIndex, secondIndices};
193 }
194 
195 } // namespace d2
196 } // namespace playrho