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