8 changed files with 339 additions and 17 deletions
@ -0,0 +1,141 @@ |
|||||
|
|
||||
|
#include <Simplex.h> |
||||
|
|
||||
|
|
||||
|
Vector3 polyhedron_support(Vector3AV polyhedron, const Vector3& direction) { |
||||
|
assert(polyhedron.size() > 0); |
||||
|
|
||||
|
Index best = 0; |
||||
|
Real best_dot = polyhedron[0].dot(direction); |
||||
|
|
||||
|
for (Index index = 1; index < polyhedron.size(); index += 1) { |
||||
|
Real dot = polyhedron[index].dot(direction); |
||||
|
if (dot > best_dot) { |
||||
|
best = index; |
||||
|
best_dot = dot; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return polyhedron[best]; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
Simplex::Simplex() = default; |
||||
|
Simplex::Simplex(const Vector3& point) |
||||
|
: m_points{ point, Vector3{}, Vector3{}, Vector3{} } |
||||
|
, m_point_count(1) |
||||
|
{} |
||||
|
|
||||
|
|
||||
|
Gjk::Gjk(Vector3AV polyhedron0, Vector3AV polyhedron1, const Vector3& direction) |
||||
|
: m_polyhedron0(polyhedron0) |
||||
|
, m_polyhedron1(polyhedron1) |
||||
|
, m_direction(direction) |
||||
|
{} |
||||
|
|
||||
|
Gjk::~Gjk() = default; |
||||
|
|
||||
|
const Vector3& Gjk::direction() const { |
||||
|
return m_direction; |
||||
|
} |
||||
|
|
||||
|
bool Gjk::operator()() { |
||||
|
while (true) { |
||||
|
m_simplex.push(support(m_direction)); |
||||
|
|
||||
|
if (m_simplex.last().dot(m_direction) < Real(0)) |
||||
|
return false; |
||||
|
|
||||
|
if (nextSimplex()) |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool Gjk::nextSimplex() { |
||||
|
switch(m_simplex.point_count()) { |
||||
|
case 1: return nextFromPoint(); |
||||
|
case 2: return nextFromLine(); |
||||
|
case 3: return nextFromTriangle(); |
||||
|
case 4: return nextFromTetrahedron(); |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool Gjk::nextFromPoint() { |
||||
|
m_direction = -m_simplex.last(); |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool Gjk::nextFromLine() { |
||||
|
Vector3 v01 = m_simplex.point(1) - m_simplex.point(0); |
||||
|
Vector3 v1o = -m_simplex.point(1); |
||||
|
|
||||
|
m_direction = v01.cross(v1o).cross(v01); |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool Gjk::nextFromTriangle() { |
||||
|
Vector3 v20 = m_simplex.point(0) - m_simplex.point(2); |
||||
|
Vector3 v21 = m_simplex.point(1) - m_simplex.point(2); |
||||
|
Vector3 v2o = -m_simplex.point(2); |
||||
|
|
||||
|
Vector3 n = v20.cross(v21); |
||||
|
Vector3 n0 = n.cross(v21); |
||||
|
Vector3 n1 = v20.cross(n); |
||||
|
|
||||
|
if(n0.dot(v2o) > Real(0)) { |
||||
|
m_simplex.pop(0); |
||||
|
m_direction = n0; |
||||
|
} |
||||
|
else if(n1.dot(v2o) > Real(0)) { |
||||
|
m_simplex.pop(1); |
||||
|
m_direction = n1; |
||||
|
} |
||||
|
else if(n.dot(v2o) > Real(0)) { |
||||
|
m_direction = n; |
||||
|
} |
||||
|
else { |
||||
|
m_simplex.swap(0, 1); |
||||
|
m_direction = -n; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool Gjk::nextFromTetrahedron() { |
||||
|
Vector3 v30 = m_simplex.point(0) - m_simplex.point(3); |
||||
|
Vector3 v31 = m_simplex.point(1) - m_simplex.point(3); |
||||
|
Vector3 v32 = m_simplex.point(2) - m_simplex.point(3); |
||||
|
Vector3 v3o = -m_simplex.point(3); |
||||
|
|
||||
|
Vector3 n[3] = { |
||||
|
v31.cross(v32), |
||||
|
v32.cross(v30), |
||||
|
v30.cross(v31), |
||||
|
}; |
||||
|
|
||||
|
Real d[3] = { |
||||
|
n[0].dot(v3o), |
||||
|
n[1].dot(v3o), |
||||
|
n[2].dot(v3o), |
||||
|
}; |
||||
|
|
||||
|
Index best = (d[0] > d[1])? ((d[0] > d[2])? 0: 2): |
||||
|
((d[1] > d[2])? 1: 2); |
||||
|
|
||||
|
if(d[best] <= Real(0)) |
||||
|
return true; |
||||
|
|
||||
|
m_simplex.pop(best); |
||||
|
m_direction = n[best]; |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
Vector3 Gjk::support(const Vector3& direction) const |
||||
|
{ |
||||
|
return polyhedron_support(m_polyhedron0, direction) |
||||
|
- polyhedron_support(m_polyhedron1, -direction); |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <core.h> |
||||
|
|
||||
|
|
||||
|
class Simplex { |
||||
|
public: |
||||
|
Simplex(); |
||||
|
Simplex(const Vector3& point); |
||||
|
|
||||
|
inline Index point_count() const { |
||||
|
return m_point_count; |
||||
|
} |
||||
|
|
||||
|
inline const Vector3& point(Index index) const { |
||||
|
assert(index < m_point_count); |
||||
|
return m_points[index]; |
||||
|
} |
||||
|
|
||||
|
inline const Vector3& last() const { |
||||
|
assert(m_point_count > 0); |
||||
|
return point(m_point_count - 1); |
||||
|
} |
||||
|
|
||||
|
inline void push(const Vector3& point) { |
||||
|
assert(m_point_count < MaxPointCount); |
||||
|
m_points[m_point_count] = point; |
||||
|
m_point_count += 1; |
||||
|
} |
||||
|
|
||||
|
inline void pop(Index index) { |
||||
|
assert(index < m_point_count); |
||||
|
for(Index i = index; i + 1 < m_point_count; i += 1) |
||||
|
m_points[i] = m_points[i + 1]; |
||||
|
m_point_count -= 1; |
||||
|
} |
||||
|
|
||||
|
inline void swap(Index index0, Index index1) { |
||||
|
using std::swap; |
||||
|
swap(m_points[index0], m_points[index1]); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
static constexpr Index MaxPointCount = 4; |
||||
|
|
||||
|
private: |
||||
|
Vector3 m_points[MaxPointCount]; |
||||
|
Index m_point_count = 0; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
class Gjk { |
||||
|
public: |
||||
|
Gjk(Vector3AV polyhedron0, Vector3AV polyhedron1, const Vector3& direction=Vector3::UnitX()); |
||||
|
~Gjk(); |
||||
|
|
||||
|
const Vector3& direction() const; |
||||
|
|
||||
|
bool operator()(); |
||||
|
|
||||
|
private: |
||||
|
bool nextSimplex(); |
||||
|
bool nextFromPoint(); |
||||
|
bool nextFromLine(); |
||||
|
bool nextFromTriangle(); |
||||
|
bool nextFromTetrahedron(); |
||||
|
|
||||
|
Vector3 support(const Vector3& direction) const; |
||||
|
|
||||
|
private: |
||||
|
Vector3AV m_polyhedron0; |
||||
|
Vector3AV m_polyhedron1; |
||||
|
Simplex m_simplex; |
||||
|
Vector3 m_direction; |
||||
|
}; |
||||
Loading…
Reference in new issue