hx3d  1
2D/3D Simple Game Framework
polygon.cpp
1 #include "hx3d/physics/2d/colliders/polygon.hpp"
2 
3 #include "hx3d/math/vector_utils.hpp"
4 
5 namespace hx3d {
6 namespace physics2d {
7 namespace colliders {
8 
9 Polygon::Polygon(const Type colliderType):
10  Collider(Shape::Polygon, colliderType),
11  box(true)
12  {}
13 
14 void Polygon::setPoints(const std::vector<glm::vec2>& points) {
15  unsigned int rightMost = 0;
16  float highestXCoord = points[0].x;
17  for (unsigned int i = 1; i < points.size(); ++i) {
18  float x = points[i].x;
19 
20  if (x > highestXCoord) {
21  highestXCoord = x;
22  rightMost = i;
23  }
24 
25  else if (x == highestXCoord) {
26  if (points[i].y < points[rightMost].y) {
27  rightMost = i;
28  }
29  }
30  }
31 
32  std::vector<unsigned int> hull;
33  unsigned int outCount = 0;
34  unsigned int indexHull = rightMost;
35 
36  for (;;) {
37  hull[outCount] = indexHull;
38 
39  unsigned int nextHullIndex = 0;
40  for (unsigned int i = 1; i < points.size(); ++i) {
41  if (nextHullIndex == indexHull) {
42  nextHullIndex = i;
43  continue;
44  }
45 
46  glm::vec2 e1 = points[nextHullIndex] - points[hull[outCount]];
47  glm::vec2 e2 = points[i] - points[hull[outCount]];
48  float c = math::cross(e1, e2);
49  if (c < 0.f) {
50  nextHullIndex = i;
51  }
52 
53  if (c == 0.f && math::squareLength(e2) > math::squareLength(e1)) {
54  nextHullIndex = i;
55  }
56  }
57 
58  ++outCount;
59  indexHull = nextHullIndex;
60 
61  if (nextHullIndex == rightMost) {
62  vertexCount = outCount;
63  break;
64  }
65  }
66 
67  for (unsigned int i = 0; i < vertexCount; ++i) {
68  vertices.push_back(points[hull[i]]);
69  }
70 
71  for (unsigned int i = 0; i < vertexCount; ++i) {
72  glm::vec2 face = vertices[(i+1) % vertexCount] - vertices[i];
73 
74  normals.push_back(glm::normalize(glm::vec2({face.y, -face.x})));
75  }
76 
77  setDensity(1.f);
78 }
79 
80 glm::vec2 Polygon::getSupport(glm::vec2 dir) {
81  float bestProjection = -FLT_MAX;
82  glm::vec2 bestVertex;
83 
84  for (unsigned int i = 0; i < vertexCount; ++i) {
85  glm::vec2 v = vertices[i];
86  float projection = glm::dot(v, dir);
87 
88  if (projection > bestProjection) {
89  bestVertex = v;
90  bestProjection = projection;
91  }
92  }
93 
94  return bestVertex;
95 }
96 
97 void Polygon::setAsBox(const float width, const float height) {
98  vertexCount = 4;
99 
100  float hw = width / 2;
101  float hh = height / 2;
102 
103  vertices.push_back(glm::vec2(-hw, -hh));
104  vertices.push_back(glm::vec2(hw, -hh));
105  vertices.push_back(glm::vec2(hw, hh));
106  vertices.push_back(glm::vec2(-hw, hh));
107  normals.push_back(glm::vec2(0.f, -1.f));
108  normals.push_back(glm::vec2(1.f, 0.f));
109  normals.push_back(glm::vec2(0.f, 1.f));
110  normals.push_back(glm::vec2(-1.f, 0.f));
111 
112  setDensity(1.f);
113 }
114 
115 void Polygon::setOrientation(float angle) {
116  float c = std::cos(angle);
117  float s = std::sin(angle);
118 
119  u[0][0] = c;
120  u[1][0] = -s;
121  u[0][1] = s;
122  u[1][1] = c;
123 }
124 
125 void Polygon::computeMass(float density) {
126 
127  // if (box) {
128  // massData.setMass(density);
129  // massData.setInertia(density/2.f);
130  // return;
131  // }
132 
133  glm::vec2 centroid = {0.f, 0.f};
134  float area = 0.f;
135  float I = 0.f;
136  float inv3 = 1.f / 3.f;
137 
138  for (unsigned int i = 0; i < vertexCount; ++i) {
139  unsigned int j = i + 1 < vertexCount ? i + 1 : 0;
140  glm::vec2 p1 = vertices[i];
141  glm::vec2 p2 = vertices[j];
142 
143  float D = math::cross(p1, p2);
144  float triangleArea = 0.5f * D;
145 
146  area += triangleArea;
147 
148  centroid += triangleArea * inv3 * (p1 + p2);
149 
150  float intx2 = p1.x * p1.x + p2.x * p1.x + p2.x * p2.x;
151  float inty2 = p1.y * p1.y + p2.y * p1.y + p2.y * p2.y;
152 
153  I += (0.25f * inv3 * D) * (intx2 + inty2);
154  }
155 
156  centroid *= 1.f / area;
157 
158  for (unsigned int i = 0; i < vertexCount; ++i) {
159  vertices[i] -= centroid;
160  }
161 
162  massData.setMass(density * area);
163  massData.setInertia(I * density);
164 }
165 
166 }
167 }
168 } /* hx3d */
void setAsBox(const float width, const float height)
Set the polygon points as a box.
Definition: polygon.cpp:97
Mass massData
Mass data.
Definition: collider.hpp:175
void setDensity(float density)
Set collider density.
Definition: collider.cpp:66
std::vector< glm::vec2 > normals
Normals.
Definition: polygon.hpp:76
glm::vec2 getSupport(glm::vec2 dir)
Get the support vector following a direction.
Definition: polygon.cpp:80
void setPoints(const std::vector< glm::vec2 > &points)
Set the polygon points.
Definition: polygon.cpp:14
Type
Collider type.
Definition: collider.hpp:46
hx3d framework namespace
Definition: audio.hpp:26
float squareLength(glm::vec2 vec)
Compute the square length of a 2D vector.
virtual void computeMass(float density) override
Compute the collider mass.
Definition: polygon.cpp:125
Polygon(const Type colliderType=Type::Dynamic)
Create a polygon.
Definition: polygon.cpp:9
std::vector< glm::vec2 > vertices
Vertices.
Definition: polygon.hpp:74
unsigned int vertexCount
Vertex count.
Definition: polygon.hpp:72
virtual void setOrientation(float angle) override
Set the collider orientation.
Definition: polygon.cpp:115
Shape
Collider shape.
Definition: collider.hpp:58
void setInertia(float amount)
Set the current inertia.
Definition: mass.cpp:19
glm::mat2 u
Rotation matrix.
Definition: polygon.hpp:78
Physical collider.
Definition: collider.hpp:40
glm::vec2 cross(glm::vec2 vec, float v)
Calculate the cross product vector between a 2D vector and a scalar.
void setMass(float amount)
Set the current mass.
Definition: mass.cpp:14
Polygon or box shaped collider.
Definition: polygon.hpp:35