2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
Bullet Continuous Collision Detection and Physics Library
|
|
|
|
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied warranty.
|
|
|
|
In no event will the authors be held liable for any damages arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it freely,
|
|
|
|
subject to the following restrictions:
|
|
|
|
|
|
|
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
|
|
|
|
Elsevier CDROM license agreements grants nonexclusive license to use the software
|
|
|
|
for any purpose, commercial or non-commercial as long as the following credit is included
|
|
|
|
identifying the original source of the software:
|
|
|
|
|
|
|
|
Parts of the source are "from the book Real-Time Collision Detection by
|
|
|
|
Christer Ericson, published by Morgan Kaufmann Publishers,
|
|
|
|
(c) 2005 Elsevier Inc."
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "b3VoronoiSimplexSolver.h"
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
#define VERTA 0
|
|
|
|
#define VERTB 1
|
|
|
|
#define VERTC 2
|
|
|
|
#define VERTD 3
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
#define B3_CATCH_DEGENERATE_TETRAHEDRON 1
|
2019-01-03 13:26:51 +00:00
|
|
|
void b3VoronoiSimplexSolver::removeVertex(int index)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Assert(m_numVertices > 0);
|
2017-08-01 12:30:58 +00:00
|
|
|
m_numVertices--;
|
|
|
|
m_simplexVectorW[index] = m_simplexVectorW[m_numVertices];
|
|
|
|
m_simplexPointsP[index] = m_simplexPointsP[m_numVertices];
|
|
|
|
m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices];
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
void b3VoronoiSimplexSolver::reduceVertices(const b3UsageBitfield& usedVerts)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
if ((numVertices() >= 4) && (!usedVerts.usedVertexD))
|
|
|
|
removeVertex(3);
|
|
|
|
|
|
|
|
if ((numVertices() >= 3) && (!usedVerts.usedVertexC))
|
|
|
|
removeVertex(2);
|
|
|
|
|
|
|
|
if ((numVertices() >= 2) && (!usedVerts.usedVertexB))
|
|
|
|
removeVertex(1);
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
if ((numVertices() >= 1) && (!usedVerts.usedVertexA))
|
|
|
|
removeVertex(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//clear the simplex, remove all the vertices
|
|
|
|
void b3VoronoiSimplexSolver::reset()
|
|
|
|
{
|
|
|
|
m_cachedValidClosest = false;
|
|
|
|
m_numVertices = 0;
|
|
|
|
m_needsUpdate = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
m_lastW = b3MakeVector3(b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT));
|
2017-08-01 12:30:58 +00:00
|
|
|
m_cachedBC.reset();
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
//add a vertex
|
2017-08-01 12:30:58 +00:00
|
|
|
void b3VoronoiSimplexSolver::addVertex(const b3Vector3& w, const b3Vector3& p, const b3Vector3& q)
|
|
|
|
{
|
|
|
|
m_lastW = w;
|
|
|
|
m_needsUpdate = true;
|
|
|
|
|
|
|
|
m_simplexVectorW[m_numVertices] = w;
|
|
|
|
m_simplexPointsP[m_numVertices] = p;
|
|
|
|
m_simplexPointsQ[m_numVertices] = q;
|
|
|
|
|
|
|
|
m_numVertices++;
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
bool b3VoronoiSimplexSolver::updateClosestVectorAndPoints()
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
if (m_needsUpdate)
|
|
|
|
{
|
|
|
|
m_cachedBC.reset();
|
|
|
|
|
|
|
|
m_needsUpdate = false;
|
|
|
|
|
|
|
|
switch (numVertices())
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
case 0:
|
2017-08-01 12:30:58 +00:00
|
|
|
m_cachedValidClosest = false;
|
|
|
|
break;
|
2019-01-03 13:26:51 +00:00
|
|
|
case 1:
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
m_cachedP1 = m_simplexPointsP[0];
|
|
|
|
m_cachedP2 = m_simplexPointsQ[0];
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedV = m_cachedP1 - m_cachedP2; //== m_simplexVectorW[0]
|
2017-08-01 12:30:58 +00:00
|
|
|
m_cachedBC.reset();
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedBC.setBarycentricCoordinates(b3Scalar(1.), b3Scalar(0.), b3Scalar(0.), b3Scalar(0.));
|
2017-08-01 12:30:58 +00:00
|
|
|
m_cachedValidClosest = m_cachedBC.isValid();
|
|
|
|
break;
|
|
|
|
};
|
2019-01-03 13:26:51 +00:00
|
|
|
case 2:
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
//closest point origin from line segment
|
|
|
|
const b3Vector3& from = m_simplexVectorW[0];
|
|
|
|
const b3Vector3& to = m_simplexVectorW[1];
|
|
|
|
b3Vector3 nearest;
|
|
|
|
|
|
|
|
b3Vector3 p = b3MakeVector3(b3Scalar(0.), b3Scalar(0.), b3Scalar(0.));
|
|
|
|
b3Vector3 diff = p - from;
|
|
|
|
b3Vector3 v = to - from;
|
|
|
|
b3Scalar t = v.dot(diff);
|
|
|
|
|
|
|
|
if (t > 0)
|
|
|
|
{
|
|
|
|
b3Scalar dotVV = v.dot(v);
|
|
|
|
if (t < dotVV)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
t /= dotVV;
|
|
|
|
diff -= t * v;
|
2017-08-01 12:30:58 +00:00
|
|
|
m_cachedBC.m_usedVertices.usedVertexA = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedBC.m_usedVertices.usedVertexB = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t = 1;
|
|
|
|
diff -= v;
|
|
|
|
//reduce to 1 point
|
|
|
|
m_cachedBC.m_usedVertices.usedVertexB = true;
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
t = 0;
|
|
|
|
//reduce to 1 point
|
|
|
|
m_cachedBC.m_usedVertices.usedVertexA = true;
|
|
|
|
}
|
|
|
|
m_cachedBC.setBarycentricCoordinates(1 - t, t);
|
|
|
|
nearest = from + t * v;
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]);
|
|
|
|
m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]);
|
|
|
|
m_cachedV = m_cachedP1 - m_cachedP2;
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
reduceVertices(m_cachedBC.m_usedVertices);
|
|
|
|
|
|
|
|
m_cachedValidClosest = m_cachedBC.isValid();
|
|
|
|
break;
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
//closest point origin from triangle
|
|
|
|
b3Vector3 p = b3MakeVector3(b3Scalar(0.), b3Scalar(0.), b3Scalar(0.));
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
const b3Vector3& a = m_simplexVectorW[0];
|
|
|
|
const b3Vector3& b = m_simplexVectorW[1];
|
|
|
|
const b3Vector3& c = m_simplexVectorW[2];
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
closestPtPointTriangle(p, a, b, c, m_cachedBC);
|
|
|
|
m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +
|
|
|
|
m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +
|
|
|
|
m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2];
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +
|
|
|
|
m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +
|
|
|
|
m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2];
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedV = m_cachedP1 - m_cachedP2;
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
reduceVertices(m_cachedBC.m_usedVertices);
|
|
|
|
m_cachedValidClosest = m_cachedBC.isValid();
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
break;
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
case 4:
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Vector3 p = b3MakeVector3(b3Scalar(0.), b3Scalar(0.), b3Scalar(0.));
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
const b3Vector3& a = m_simplexVectorW[0];
|
|
|
|
const b3Vector3& b = m_simplexVectorW[1];
|
|
|
|
const b3Vector3& c = m_simplexVectorW[2];
|
|
|
|
const b3Vector3& d = m_simplexVectorW[3];
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
bool hasSeperation = closestPtPointTetrahedron(p, a, b, c, d, m_cachedBC);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
if (hasSeperation)
|
|
|
|
{
|
|
|
|
m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +
|
2019-01-03 13:26:51 +00:00
|
|
|
m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +
|
|
|
|
m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] +
|
|
|
|
m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3];
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +
|
2019-01-03 13:26:51 +00:00
|
|
|
m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +
|
|
|
|
m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] +
|
|
|
|
m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3];
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedV = m_cachedP1 - m_cachedP2;
|
|
|
|
reduceVertices(m_cachedBC.m_usedVertices);
|
|
|
|
}
|
|
|
|
else
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
// printf("sub distance got penetration\n");
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
if (m_cachedBC.m_degenerate)
|
|
|
|
{
|
|
|
|
m_cachedValidClosest = false;
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|
|
|
|
else
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
m_cachedValidClosest = true;
|
|
|
|
//degenerate case == false, penetration = true + zero
|
2019-01-03 13:26:51 +00:00
|
|
|
m_cachedV.setValue(b3Scalar(0.), b3Scalar(0.), b3Scalar(0.));
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cachedValidClosest = m_cachedBC.isValid();
|
|
|
|
|
|
|
|
//closest point origin from tetrahedron
|
|
|
|
break;
|
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
default:
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
m_cachedValidClosest = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_cachedValidClosest;
|
|
|
|
}
|
|
|
|
|
|
|
|
//return/calculate the closest vertex
|
|
|
|
bool b3VoronoiSimplexSolver::closest(b3Vector3& v)
|
|
|
|
{
|
|
|
|
bool succes = updateClosestVectorAndPoints();
|
|
|
|
v = m_cachedV;
|
|
|
|
return succes;
|
|
|
|
}
|
|
|
|
|
|
|
|
b3Scalar b3VoronoiSimplexSolver::maxVertex()
|
|
|
|
{
|
|
|
|
int i, numverts = numVertices();
|
|
|
|
b3Scalar maxV = b3Scalar(0.);
|
2019-01-03 13:26:51 +00:00
|
|
|
for (i = 0; i < numverts; i++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
b3Scalar curLen2 = m_simplexVectorW[i].length2();
|
|
|
|
if (maxV < curLen2)
|
|
|
|
maxV = curLen2;
|
|
|
|
}
|
|
|
|
return maxV;
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
//return the current simplex
|
|
|
|
int b3VoronoiSimplexSolver::getSimplex(b3Vector3* pBuf, b3Vector3* qBuf, b3Vector3* yBuf) const
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
int i;
|
2019-01-03 13:26:51 +00:00
|
|
|
for (i = 0; i < numVertices(); i++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
yBuf[i] = m_simplexVectorW[i];
|
|
|
|
pBuf[i] = m_simplexPointsP[i];
|
|
|
|
qBuf[i] = m_simplexPointsQ[i];
|
|
|
|
}
|
|
|
|
return numVertices();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool b3VoronoiSimplexSolver::inSimplex(const b3Vector3& w)
|
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
int i, numverts = numVertices();
|
|
|
|
//b3Scalar maxV = b3Scalar(0.);
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
//w is in the current (reduced) simplex
|
2019-01-03 13:26:51 +00:00
|
|
|
for (i = 0; i < numverts; i++)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
#ifdef BT_USE_EQUAL_VERTEX_THRESHOLD
|
2019-01-03 13:26:51 +00:00
|
|
|
if (m_simplexVectorW[i].distance2(w) <= m_equalVertexThreshold)
|
2017-08-01 12:30:58 +00:00
|
|
|
#else
|
|
|
|
if (m_simplexVectorW[i] == w)
|
|
|
|
#endif
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//check in case lastW is already removed
|
|
|
|
if (w == m_lastW)
|
|
|
|
return true;
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
void b3VoronoiSimplexSolver::backup_closest(b3Vector3& v)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
v = m_cachedV;
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
bool b3VoronoiSimplexSolver::emptySimplex() const
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
return (numVertices() == 0);
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
void b3VoronoiSimplexSolver::compute_points(b3Vector3& p1, b3Vector3& p2)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
updateClosestVectorAndPoints();
|
|
|
|
p1 = m_cachedP1;
|
|
|
|
p2 = m_cachedP2;
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
bool b3VoronoiSimplexSolver::closestPtPointTriangle(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c, b3SubSimplexClosestResult& result)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
result.m_usedVertices.reset();
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
// Check if P in vertex region outside A
|
|
|
|
b3Vector3 ab = b - a;
|
|
|
|
b3Vector3 ac = c - a;
|
|
|
|
b3Vector3 ap = p - a;
|
|
|
|
b3Scalar d1 = ab.dot(ap);
|
|
|
|
b3Scalar d2 = ac.dot(ap);
|
|
|
|
if (d1 <= b3Scalar(0.0) && d2 <= b3Scalar(0.0))
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
result.m_closestPointOnSimplex = a;
|
|
|
|
result.m_usedVertices.usedVertexA = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
result.setBarycentricCoordinates(1, 0, 0);
|
|
|
|
return true; // a; // barycentric coordinates (1,0,0)
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
// Check if P in vertex region outside B
|
|
|
|
b3Vector3 bp = p - b;
|
|
|
|
b3Scalar d3 = ab.dot(bp);
|
|
|
|
b3Scalar d4 = ac.dot(bp);
|
|
|
|
if (d3 >= b3Scalar(0.0) && d4 <= d3)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
result.m_closestPointOnSimplex = b;
|
|
|
|
result.m_usedVertices.usedVertexB = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
result.setBarycentricCoordinates(0, 1, 0);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
return true; // b; // barycentric coordinates (0,1,0)
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
// Check if P in edge region of AB, if so return projection of P onto AB
|
|
|
|
b3Scalar vc = d1 * d4 - d3 * d2;
|
|
|
|
if (vc <= b3Scalar(0.0) && d1 >= b3Scalar(0.0) && d3 <= b3Scalar(0.0))
|
|
|
|
{
|
|
|
|
b3Scalar v = d1 / (d1 - d3);
|
2017-08-01 12:30:58 +00:00
|
|
|
result.m_closestPointOnSimplex = a + v * ab;
|
|
|
|
result.m_usedVertices.usedVertexA = true;
|
|
|
|
result.m_usedVertices.usedVertexB = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
result.setBarycentricCoordinates(1 - v, v, 0);
|
2017-08-01 12:30:58 +00:00
|
|
|
return true;
|
2019-01-03 13:26:51 +00:00
|
|
|
//return a + v * ab; // barycentric coordinates (1-v,v,0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if P in vertex region outside C
|
|
|
|
b3Vector3 cp = p - c;
|
|
|
|
b3Scalar d5 = ab.dot(cp);
|
|
|
|
b3Scalar d6 = ac.dot(cp);
|
|
|
|
if (d6 >= b3Scalar(0.0) && d5 <= d6)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
result.m_closestPointOnSimplex = c;
|
|
|
|
result.m_usedVertices.usedVertexC = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
result.setBarycentricCoordinates(0, 0, 1);
|
|
|
|
return true; //c; // barycentric coordinates (0,0,1)
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
// Check if P in edge region of AC, if so return projection of P onto AC
|
|
|
|
b3Scalar vb = d5 * d2 - d1 * d6;
|
|
|
|
if (vb <= b3Scalar(0.0) && d2 >= b3Scalar(0.0) && d6 <= b3Scalar(0.0))
|
|
|
|
{
|
|
|
|
b3Scalar w = d2 / (d2 - d6);
|
2017-08-01 12:30:58 +00:00
|
|
|
result.m_closestPointOnSimplex = a + w * ac;
|
|
|
|
result.m_usedVertices.usedVertexA = true;
|
|
|
|
result.m_usedVertices.usedVertexC = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
result.setBarycentricCoordinates(1 - w, 0, w);
|
2017-08-01 12:30:58 +00:00
|
|
|
return true;
|
2019-01-03 13:26:51 +00:00
|
|
|
//return a + w * ac; // barycentric coordinates (1-w,0,w)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if P in edge region of BC, if so return projection of P onto BC
|
|
|
|
b3Scalar va = d3 * d6 - d5 * d4;
|
|
|
|
if (va <= b3Scalar(0.0) && (d4 - d3) >= b3Scalar(0.0) && (d5 - d6) >= b3Scalar(0.0))
|
|
|
|
{
|
|
|
|
b3Scalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
result.m_closestPointOnSimplex = b + w * (c - b);
|
|
|
|
result.m_usedVertices.usedVertexB = true;
|
|
|
|
result.m_usedVertices.usedVertexC = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
result.setBarycentricCoordinates(0, 1 - w, w);
|
|
|
|
return true;
|
|
|
|
// return b + w * (c - b); // barycentric coordinates (0,1-w,w)
|
|
|
|
}
|
|
|
|
|
|
|
|
// P inside face region. Compute Q through its barycentric coordinates (u,v,w)
|
|
|
|
b3Scalar denom = b3Scalar(1.0) / (va + vb + vc);
|
|
|
|
b3Scalar v = vb * denom;
|
|
|
|
b3Scalar w = vc * denom;
|
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
result.m_closestPointOnSimplex = a + ab * v + ac * w;
|
|
|
|
result.m_usedVertices.usedVertexA = true;
|
|
|
|
result.m_usedVertices.usedVertexB = true;
|
|
|
|
result.m_usedVertices.usedVertexC = true;
|
2019-01-03 13:26:51 +00:00
|
|
|
result.setBarycentricCoordinates(1 - v - w, v, w);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
return true;
|
|
|
|
// return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = b3Scalar(1.0) - v - w
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Test if point p and d lie on opposite sides of plane through abc
|
|
|
|
int b3VoronoiSimplexSolver::pointOutsideOfPlane(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c, const b3Vector3& d)
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Vector3 normal = (b - a).cross(c - a);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Scalar signp = (p - a).dot(normal); // [AP AB AC]
|
|
|
|
b3Scalar signd = (d - a).dot(normal); // [AD AB AC]
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
#ifdef B3_CATCH_DEGENERATE_TETRAHEDRON
|
|
|
|
#ifdef BT_USE_DOUBLE_PRECISION
|
2019-01-03 13:26:51 +00:00
|
|
|
if (signd * signd < (b3Scalar(1e-8) * b3Scalar(1e-8)))
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (signd * signd < (b3Scalar(1e-4) * b3Scalar(1e-4)))
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
// printf("affine dependent/degenerate\n");//
|
2017-08-01 12:30:58 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
// Points on opposite sides if expression signs are opposite
|
2019-01-03 13:26:51 +00:00
|
|
|
return signp * signd < b3Scalar(0.);
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
bool b3VoronoiSimplexSolver::closestPtPointTetrahedron(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c, const b3Vector3& d, b3SubSimplexClosestResult& finalResult)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
b3SubSimplexClosestResult tempResult;
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
// Start out assuming point inside all halfspaces, so closest to itself
|
2017-08-01 12:30:58 +00:00
|
|
|
finalResult.m_closestPointOnSimplex = p;
|
|
|
|
finalResult.m_usedVertices.reset();
|
2019-01-03 13:26:51 +00:00
|
|
|
finalResult.m_usedVertices.usedVertexA = true;
|
2017-08-01 12:30:58 +00:00
|
|
|
finalResult.m_usedVertices.usedVertexB = true;
|
|
|
|
finalResult.m_usedVertices.usedVertexC = true;
|
|
|
|
finalResult.m_usedVertices.usedVertexD = true;
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d);
|
2017-08-01 12:30:58 +00:00
|
|
|
int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b);
|
2019-01-03 13:26:51 +00:00
|
|
|
int pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c);
|
|
|
|
int pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a);
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0)
|
|
|
|
{
|
|
|
|
finalResult.m_degenerate = true;
|
|
|
|
return false;
|
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
if (!pointOutsideABC && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Scalar bestSqDist = FLT_MAX;
|
|
|
|
// If point outside face abc then compute closest point on abc
|
|
|
|
if (pointOutsideABC)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
closestPtPointTriangle(p, a, b, c, tempResult);
|
2017-08-01 12:30:58 +00:00
|
|
|
b3Vector3 q = tempResult.m_closestPointOnSimplex;
|
2019-01-03 13:26:51 +00:00
|
|
|
|
|
|
|
b3Scalar sqDist = (q - p).dot(q - p);
|
|
|
|
// Update best closest point if (squared) distance is less than current best
|
|
|
|
if (sqDist < bestSqDist)
|
|
|
|
{
|
2017-08-01 12:30:58 +00:00
|
|
|
bestSqDist = sqDist;
|
|
|
|
finalResult.m_closestPointOnSimplex = q;
|
|
|
|
//convert result bitmask!
|
|
|
|
finalResult.m_usedVertices.reset();
|
|
|
|
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
|
|
|
|
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB;
|
|
|
|
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
|
|
|
|
finalResult.setBarycentricCoordinates(
|
2019-01-03 13:26:51 +00:00
|
|
|
tempResult.m_barycentricCoords[VERTA],
|
|
|
|
tempResult.m_barycentricCoords[VERTB],
|
|
|
|
tempResult.m_barycentricCoords[VERTC],
|
|
|
|
0);
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
// Repeat test for face acd
|
2019-01-03 13:26:51 +00:00
|
|
|
if (pointOutsideACD)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
closestPtPointTriangle(p, a, c, d, tempResult);
|
2017-08-01 12:30:58 +00:00
|
|
|
b3Vector3 q = tempResult.m_closestPointOnSimplex;
|
|
|
|
//convert result bitmask!
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Scalar sqDist = (q - p).dot(q - p);
|
|
|
|
if (sqDist < bestSqDist)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
bestSqDist = sqDist;
|
|
|
|
finalResult.m_closestPointOnSimplex = q;
|
|
|
|
finalResult.m_usedVertices.reset();
|
|
|
|
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
|
|
|
|
|
|
|
|
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB;
|
|
|
|
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC;
|
|
|
|
finalResult.setBarycentricCoordinates(
|
2019-01-03 13:26:51 +00:00
|
|
|
tempResult.m_barycentricCoords[VERTA],
|
|
|
|
0,
|
|
|
|
tempResult.m_barycentricCoords[VERTB],
|
|
|
|
tempResult.m_barycentricCoords[VERTC]);
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|
|
|
|
// Repeat test for face adb
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
if (pointOutsideADB)
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
closestPtPointTriangle(p, a, d, b, tempResult);
|
2017-08-01 12:30:58 +00:00
|
|
|
b3Vector3 q = tempResult.m_closestPointOnSimplex;
|
|
|
|
//convert result bitmask!
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Scalar sqDist = (q - p).dot(q - p);
|
|
|
|
if (sqDist < bestSqDist)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
bestSqDist = sqDist;
|
|
|
|
finalResult.m_closestPointOnSimplex = q;
|
|
|
|
finalResult.m_usedVertices.reset();
|
|
|
|
finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
|
|
|
|
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC;
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
|
|
|
|
finalResult.setBarycentricCoordinates(
|
2019-01-03 13:26:51 +00:00
|
|
|
tempResult.m_barycentricCoords[VERTA],
|
|
|
|
tempResult.m_barycentricCoords[VERTC],
|
|
|
|
0,
|
|
|
|
tempResult.m_barycentricCoords[VERTB]);
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|
|
|
|
// Repeat test for face bdc
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
if (pointOutsideBDC)
|
|
|
|
{
|
2019-01-03 13:26:51 +00:00
|
|
|
closestPtPointTriangle(p, b, d, c, tempResult);
|
2017-08-01 12:30:58 +00:00
|
|
|
b3Vector3 q = tempResult.m_closestPointOnSimplex;
|
|
|
|
//convert result bitmask!
|
2019-01-03 13:26:51 +00:00
|
|
|
b3Scalar sqDist = (q - p).dot(q - p);
|
|
|
|
if (sqDist < bestSqDist)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
bestSqDist = sqDist;
|
|
|
|
finalResult.m_closestPointOnSimplex = q;
|
|
|
|
finalResult.m_usedVertices.reset();
|
|
|
|
//
|
|
|
|
finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA;
|
|
|
|
finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
|
|
|
|
finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
|
|
|
|
|
|
|
|
finalResult.setBarycentricCoordinates(
|
2019-01-03 13:26:51 +00:00
|
|
|
0,
|
|
|
|
tempResult.m_barycentricCoords[VERTA],
|
|
|
|
tempResult.m_barycentricCoords[VERTC],
|
|
|
|
tempResult.m_barycentricCoords[VERTB]);
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|
2019-01-03 13:26:51 +00:00
|
|
|
}
|
2017-08-01 12:30:58 +00:00
|
|
|
|
|
|
|
//help! we ended up full !
|
2019-01-03 13:26:51 +00:00
|
|
|
|
2017-08-01 12:30:58 +00:00
|
|
|
if (finalResult.m_usedVertices.usedVertexA &&
|
|
|
|
finalResult.m_usedVertices.usedVertexB &&
|
|
|
|
finalResult.m_usedVertices.usedVertexC &&
|
2019-01-03 13:26:51 +00:00
|
|
|
finalResult.m_usedVertices.usedVertexD)
|
2017-08-01 12:30:58 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-03 13:26:51 +00:00
|
|
|
return true;
|
2017-08-01 12:30:58 +00:00
|
|
|
}
|