Collision.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 
22 #include <cmath>
23 
24 namespace playrho {
25 namespace d2 {
26 
27 PointStates GetPointStates(const Manifold& manifold1, const Manifold& manifold2) noexcept
28 {
29  auto retval = PointStates{};
30 
31  // Detect persists and removes.
32  for (auto i = decltype(manifold1.GetPointCount()){0}; i < manifold1.GetPointCount(); ++i)
33  {
34  const auto cf = manifold1.GetContactFeature(i);
35 
36  retval.state1[i] = PointState::RemoveState;
37 
38  for (auto j = decltype(manifold2.GetPointCount()){0}; j < manifold2.GetPointCount(); ++j)
39  {
40  if (manifold2.GetContactFeature(j) == cf)
41  {
42  retval.state1[i] = PointState::PersistState;
43  break;
44  }
45  }
46  }
47 
48  // Detect persists and adds.
49  for (auto i = decltype(manifold2.GetPointCount()){0}; i < manifold2.GetPointCount(); ++i)
50  {
51  const auto cf = manifold2.GetContactFeature(i);
52 
53  retval.state2[i] = PointState::AddState;
54 
55  for (auto j = decltype(manifold1.GetPointCount()){0}; j < manifold1.GetPointCount(); ++j)
56  {
57  if (manifold1.GetContactFeature(j) == cf)
58  {
59  retval.state2[i] = PointState::PersistState;
60  break;
61  }
62  }
63  }
64 
65  return retval;
66 }
67 
68 ClipList ClipSegmentToLine(const ClipList& vIn, const UnitVec& normal, Length offset,
69  ContactFeature::Index indexA)
70 {
71  ClipList vOut;
72 
73  if (size(vIn) == 2) // must have two points (for a segment)
74  {
75  // Use Sutherland-Hodgman clipping:
76  // (https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm ).
77 
78  // Calculate the distance of end points to the line
79  const auto distance0 = Dot(normal, vIn[0].v) - offset;
80  const auto distance1 = Dot(normal, vIn[1].v) - offset;
81 
82  // If the points are behind the plane...
83  // Ideally they are. Then we get face-vertex contact features which are simpler to
84  // calculate. Note that it also helps to avoid changing the contact feature from the
85  // given clip vertices. So the code here also accepts distances that are just slightly
86  // over zero.
87  if (distance0 <= 0_m || AlmostZero(StripUnit(distance0)))
88  {
89  vOut.push_back(vIn[0]);
90  }
91  if (distance1 <= 0_m || AlmostZero(StripUnit(distance1)))
92  {
93  vOut.push_back(vIn[1]);
94  }
95 
96  // If we didn't already find two points & the points are on different sides of the plane...
97  if (size(vOut) < 2 && signbit(StripUnit(distance0)) != signbit(StripUnit(distance1)))
98  {
99  // Neither distance0 nor distance1 is 0 and either one or the other is negative (but not both).
100  // Find intersection point of edge and plane
101  // Vertex A is hitting edge B.
102  const auto interp = distance0 / (distance0 - distance1);
103  const auto vertex = vIn[0].v + (vIn[1].v - vIn[0].v) * interp;
104  vOut.push_back(ClipVertex{vertex, GetVertexFaceContactFeature(indexA, vIn[0].cf.indexB)});
105  }
106  }
107 
108  return vOut;
109 }
110 
111 } // namespace d2
112 } // namespace playrho