DistanceProxy.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  * 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 
22 #include <algorithm>
23 #include <iterator>
24 
25 namespace playrho {
26 namespace d2 {
27 
28 bool operator== (const DistanceProxy& lhs, const DistanceProxy& rhs) noexcept
29 {
30  if (lhs.GetVertexRadius() != rhs.GetVertexRadius())
31  {
32  return false;
33  }
34 
35  // No need to compare normals since they should be invariant to the vertices.
36  const auto lhr = lhs.GetVertices();
37  const auto rhr = rhs.GetVertices();
38  return std::equal(cbegin(lhr), cend(lhr), cbegin(rhr), cend(rhr));
39 }
40 
42 {
43  if (const auto numVertices = size(vertices); numVertices > 0)
44  {
45  auto i0 = decltype(numVertices){0};
46  auto max_x = GetX(vertices[0]);
47  for (auto i = decltype(numVertices){1}; i < numVertices; ++i)
48  {
49  const auto x = GetX(vertices[i]);
50  if ((max_x < x) || ((max_x == x) && (GetY(vertices[i]) < GetY(vertices[i0]))))
51  {
52  max_x = x;
53  i0 = i;
54  }
55  }
56  return i0;
57  }
58  return GetInvalid<std::size_t>();
59 }
60 
61 std::vector<Length2> GetConvexHullAsVector(Span<const Length2> vertices)
62 {
63  auto result = std::vector<Length2>{};
64 
65  // Create the convex hull using the Gift wrapping algorithm
66  // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm
67 
68  const auto index0 = FindLowestRightMostVertex(vertices);
69  if (index0 != GetInvalid<std::size_t>())
70  {
71  const auto numVertices = size(vertices);
72  auto hull = std::vector<decltype(size(vertices))>();
73 
74  auto ih = index0;
75  for (;;)
76  {
77  hull.push_back(ih);
78 
79  auto ie = decltype(numVertices){0};
80  for (auto j = decltype(numVertices){1}; j < numVertices; ++j)
81  {
82  if (ie == ih)
83  {
84  ie = j;
85  continue;
86  }
87 
88  const auto r = vertices[ie] - vertices[ih];
89  const auto v = vertices[j] - vertices[ih];
90  const auto c = Cross(r, v);
91  if ((c < 0_m2) || ((c == 0_m2) && (GetMagnitudeSquared(v) > GetMagnitudeSquared(r))))
92  {
93  ie = j;
94  }
95  }
96 
97  ih = ie;
98  if (ie == index0)
99  {
100  break;
101  }
102  }
103 
104  const auto count = size(hull);
105  for (auto i = decltype(count){0}; i < count; ++i)
106  {
107  result.emplace_back(vertices[hull[i]]);
108  }
109  }
110 
111  return result;
112 }
113 
114 bool TestPoint(const DistanceProxy& proxy, Length2 point) noexcept
115 {
116  const auto count = proxy.GetVertexCount();
117  const auto vr = proxy.GetVertexRadius();
118 
119  switch (count)
120  {
121  case 0:
122  return false;
123  case 1:
124  {
125  const auto v0 = proxy.GetVertex(0);
126  const auto delta = point - v0;
127  return GetMagnitudeSquared(delta) <= Square(vr);
128  }
129  default:
130  break;
131  }
132 
133  auto maxDot = -MaxFloat * Meter;
134  auto maxIdx = static_cast<decltype(count)>(-1);
135  for (auto i = decltype(count){0}; i < count; ++i)
136  {
137  const auto vi = proxy.GetVertex(i);
138  const auto delta = point - vi;
139  const auto dot = Dot(proxy.GetNormal(i), delta);
140  if (dot > vr)
141  {
142  return false;
143  }
144  if (maxDot < dot)
145  {
146  maxDot = dot;
147  maxIdx = i;
148  }
149  }
150  assert(maxIdx < count);
151 
152  const auto v0 = proxy.GetVertex(maxIdx);
153  const auto v1 = proxy.GetVertex(GetModuloNext(maxIdx, count));
154  const auto edge = v1 - v0;
155  if (const auto delta0 = v0 - point; Dot(edge, delta0) >= 0_m2)
156  {
157  // point is nearest v0 and not within edge
158  return GetMagnitudeSquared(delta0) <= Square(vr);
159  }
160  if (const auto delta1 = point - v1; Dot(edge, delta1) >= 0_m2)
161  {
162  // point is nearest v1 and not within edge
163  return GetMagnitudeSquared(delta1) <= Square(vr);
164  }
165  return true;
166 }
167 
168 } // namespace d2
169 } // namespace playrho