Files
create/src/Mod/Mesh/App/WildMagic4/Wm4IntrTriangle3Triangle3.cpp
2016-09-23 17:24:00 +02:00

1269 lines
37 KiB
C++

// Wild Magic Source Code
// David Eberly
// http://www.geometrictools.com
// Copyright (c) 1998-2007
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version. The license is available for reading at
// either of the locations:
// http://www.gnu.org/copyleft/lgpl.html
// http://www.geometrictools.com/License/WildMagicLicense.pdf
// The license applies to versions 0 through 4 of Wild Magic.
//
// Version: 4.0.2 (2006/07/25)
#include "Wm4FoundationPCH.h"
#include "Wm4IntrTriangle3Triangle3.h"
#include "Wm4Intersector1.h"
#include "Wm4IntrTriangle2Triangle2.h"
#include "Wm4Query2.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
IntrTriangle3Triangle3<Real>::IntrTriangle3Triangle3 (
const Triangle3<Real>& rkTriangle0, const Triangle3<Real>& rkTriangle1)
:
m_rkTriangle0(rkTriangle0),
m_rkTriangle1(rkTriangle1)
{
ReportCoplanarIntersections = true;
m_iQuantity = 0;
}
//----------------------------------------------------------------------------
template <class Real>
const Triangle3<Real>& IntrTriangle3Triangle3<Real>::GetTriangle0 () const
{
return m_rkTriangle0;
}
//----------------------------------------------------------------------------
template <class Real>
const Triangle3<Real>& IntrTriangle3Triangle3<Real>::GetTriangle1 () const
{
return m_rkTriangle1;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::Test ()
{
// get edge vectors for triangle0
Vector3<Real> akE0[3] =
{
m_rkTriangle0.V[1] - m_rkTriangle0.V[0],
m_rkTriangle0.V[2] - m_rkTriangle0.V[1],
m_rkTriangle0.V[0] - m_rkTriangle0.V[2]
};
// get normal vector of triangle0
Vector3<Real> kN0 = akE0[0].UnitCross(akE0[1]);
// project triangle1 onto normal line of triangle0, test for separation
Real fN0dT0V0 = kN0.Dot(m_rkTriangle0.V[0]);
Real fMin1, fMax1;
ProjectOntoAxis(m_rkTriangle1,kN0,fMin1,fMax1);
if (fN0dT0V0 < fMin1 || fN0dT0V0 > fMax1)
{
return false;
}
// get edge vectors for triangle1
Vector3<Real> akE1[3] =
{
m_rkTriangle1.V[1] - m_rkTriangle1.V[0],
m_rkTriangle1.V[2] - m_rkTriangle1.V[1],
m_rkTriangle1.V[0] - m_rkTriangle1.V[2]
};
// get normal vector of triangle1
Vector3<Real> kN1 = akE1[0].UnitCross(akE1[1]);
Vector3<Real> kDir;
Real fMin0, fMax0;
int i0, i1;
Vector3<Real> kN0xN1 = kN0.UnitCross(kN1);
if (kN0xN1.Dot(kN0xN1) >= Math<Real>::ZERO_TOLERANCE)
{
// triangles are not parallel
// Project triangle0 onto normal line of triangle1, test for
// separation.
Real fN1dT1V0 = kN1.Dot(m_rkTriangle1.V[0]);
ProjectOntoAxis(m_rkTriangle0,kN1,fMin0,fMax0);
if (fN1dT1V0 < fMin0 || fN1dT1V0 > fMax0)
{
return false;
}
// directions E0[i0]xE1[i1]
for (i1 = 0; i1 < 3; i1++)
{
for (i0 = 0; i0 < 3; i0++)
{
kDir = akE0[i0].UnitCross(akE1[i1]);
ProjectOntoAxis(m_rkTriangle0,kDir,fMin0,fMax0);
ProjectOntoAxis(m_rkTriangle1,kDir,fMin1,fMax1);
if (fMax0 < fMin1 || fMax1 < fMin0)
{
return false;
}
}
}
}
else // triangles are parallel (and, in fact, coplanar)
{
// directions N0xE0[i0]
for (i0 = 0; i0 < 3; i0++)
{
kDir = kN0.UnitCross(akE0[i0]);
ProjectOntoAxis(m_rkTriangle0,kDir,fMin0,fMax0);
ProjectOntoAxis(m_rkTriangle1,kDir,fMin1,fMax1);
if (fMax0 < fMin1 || fMax1 < fMin0)
{
return false;
}
}
// directions N1xE1[i1]
for (i1 = 0; i1 < 3; i1++)
{
kDir = kN1.UnitCross(akE1[i1]);
ProjectOntoAxis(m_rkTriangle0,kDir,fMin0,fMax0);
ProjectOntoAxis(m_rkTriangle1,kDir,fMin1,fMax1);
if (fMax0 < fMin1 || fMax1 < fMin0)
{
return false;
}
}
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::Find ()
{
int i, iM, iP;
// Get the plane of triangle0.
Plane3<Real> kPlane0(m_rkTriangle0.V[0],m_rkTriangle0.V[1],
m_rkTriangle0.V[2]);
// Compute the signed distances of triangle1 vertices to plane0. Use
// an epsilon-thick plane test.
int iPos1, iNeg1, iZero1, aiSign1[3];
Real afDist1[3];
TrianglePlaneRelations(m_rkTriangle1,kPlane0,afDist1,aiSign1,iPos1,iNeg1,
iZero1);
if (iPos1 == 3 || iNeg1 == 3)
{
// Triangle1 is fully on one side of plane0.
return false;
}
if (iZero1 == 3)
{
// Triangle1 is contained by plane0.
if (ReportCoplanarIntersections)
{
return GetCoplanarIntersection(kPlane0,m_rkTriangle0,
m_rkTriangle1);
}
return false;
}
// Check for grazing contact between triangle1 and plane0.
if (iPos1 == 0 || iNeg1 == 0)
{
if (iZero1 == 2)
{
// An edge of triangle1 is in plane0.
for (i = 0; i < 3; i++)
{
if (aiSign1[i] != 0)
{
iM = (i + 2) % 3;
iP = (i + 1) % 3;
return IntersectsSegment(m_rkTriangle0,
m_rkTriangle1.V[iM],m_rkTriangle1.V[iP]);
}
}
}
else // iZero1 == 1
{
// A vertex of triangle1 is in plane0.
for (i = 0; i < 3; i++)
{
if (aiSign1[i] == 0)
{
return ContainsPoint(m_rkTriangle0,kPlane0,
m_rkTriangle1.V[i]);
}
}
}
}
// At this point, triangle1 tranversely intersects plane 0. Compute the
// line segment of intersection. Then test for intersection between this
// segment and triangle 0.
Real fT;
Vector3<Real> kIntr0, kIntr1;
if (iZero1 == 0)
{
int iSign = (iPos1 == 1 ? +1 : -1);
for (i = 0; i < 3; i++)
{
if (aiSign1[i] == iSign)
{
iM = (i + 2) % 3;
iP = (i + 1) % 3;
fT = afDist1[i]/(afDist1[i] - afDist1[iM]);
kIntr0 = m_rkTriangle1.V[i] + fT*(m_rkTriangle1.V[iM] -
m_rkTriangle1.V[i]);
fT = afDist1[i]/(afDist1[i] - afDist1[iP]);
kIntr1 = m_rkTriangle1.V[i] + fT*(m_rkTriangle1.V[iP] -
m_rkTriangle1.V[i]);
return IntersectsSegment(m_rkTriangle0,kIntr0,kIntr1);
}
}
}
// iZero1 == 1
for (i = 0; i < 3; i++)
{
if (aiSign1[i] == 0)
{
iM = (i + 2) % 3;
iP = (i + 1) % 3;
fT = afDist1[iM]/(afDist1[iM] - afDist1[iP]);
kIntr0 = m_rkTriangle1.V[iM] + fT*(m_rkTriangle1.V[iP] -
m_rkTriangle1.V[iM]);
return IntersectsSegment(m_rkTriangle0,m_rkTriangle1.V[i],kIntr0);
}
}
assert(false);
return false;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::Test (Real fTMax,
const Vector3<Real>& rkVelocity0, const Vector3<Real>& rkVelocity1)
{
Real fTFirst = (Real)0.0;
Real fTLast = Math<Real>::MAX_REAL;
// velocity relative to triangle0
Vector3<Real> kVel = rkVelocity1 - rkVelocity0;
// compute edge and normal directions for triangle0
Vector3<Real> akE[3] =
{
m_rkTriangle0.V[1] - m_rkTriangle0.V[0],
m_rkTriangle0.V[2] - m_rkTriangle0.V[1],
m_rkTriangle0.V[0] - m_rkTriangle0.V[2]
};
Vector3<Real> kN = akE[0].UnitCross(akE[1]);
if (!TestOverlap(kN,fTMax,kVel,fTFirst,fTLast))
{
return false;
}
// compute edge and normal directions for triangle1
Vector3<Real> akF[3] =
{
m_rkTriangle1.V[1] - m_rkTriangle1.V[0],
m_rkTriangle1.V[2] - m_rkTriangle1.V[1],
m_rkTriangle1.V[0] - m_rkTriangle1.V[2]
};
Vector3<Real> kM = akF[0].UnitCross(akF[1]);
Vector3<Real> kDir;
int i0, i1;
if (Math<Real>::FAbs(kN.Dot(kM)) < 1.0f - Math<Real>::ZERO_TOLERANCE)
{
// triangles are not parallel
// direction M
if (!TestOverlap(kM,fTMax,kVel,fTFirst,fTLast))
{
return false;
}
// directions E[i0]xF[i1]
for (i1 = 0; i1 < 3; i1++)
{
for (i0 = 0; i0 < 3; i0++)
{
kDir = akE[i0].UnitCross(akF[i1]);
if (!TestOverlap(kDir,fTMax,kVel,fTFirst,fTLast))
{
return false;
}
}
}
}
else // triangles are parallel (and, in fact, coplanar)
{
// directions NxE[i0]
for (i0 = 0; i0 < 3; i0++)
{
kDir = kN.UnitCross(akE[i0]);
if (!TestOverlap(kDir,fTMax,kVel,fTFirst,fTLast))
{
return false;
}
}
// directions NxF[i1]
for (i1 = 0; i1 < 3; i1++)
{
kDir = kM.UnitCross(akF[i1]);
if (!TestOverlap(kDir,fTMax,kVel,fTFirst,fTLast))
{
return false;
}
}
}
m_fContactTime = fTFirst;
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::Find (Real fTMax,
const Vector3<Real>& rkVelocity0, const Vector3<Real>& rkVelocity1)
{
Real fTFirst = (Real)0.0;
Real fTLast = Math<Real>::MAX_REAL;
// velocity relative to triangle0
Vector3<Real> kVel = rkVelocity1 - rkVelocity0;
ContactSide eSide = CS_NONE;
Configuration kTCfg0, kTCfg1;
// compute edge and normal directions for triangle0
Vector3<Real> akE[3] =
{
m_rkTriangle0.V[1] - m_rkTriangle0.V[0],
m_rkTriangle0.V[2] - m_rkTriangle0.V[1],
m_rkTriangle0.V[0] - m_rkTriangle0.V[2]
};
Vector3<Real> kN = akE[0].UnitCross(akE[1]);
if (!FindOverlap(kN,fTMax,kVel,eSide,kTCfg0,kTCfg1,fTFirst,fTLast))
{
return false;
}
// compute edge and normal directions for triangle1
Vector3<Real> akF[3] =
{
m_rkTriangle1.V[1] - m_rkTriangle1.V[0],
m_rkTriangle1.V[2] - m_rkTriangle1.V[1],
m_rkTriangle1.V[0] - m_rkTriangle1.V[2]
};
Vector3<Real> kM = akF[0].UnitCross(akF[1]);
Vector3<Real> kDir;
int i0, i1;
if (Math<Real>::FAbs(kN.Dot(kM)) < 1.0f - Math<Real>::ZERO_TOLERANCE)
{
// triangles are not parallel
// direction M
if (!FindOverlap(kM,fTMax,kVel,eSide,kTCfg0,kTCfg1,fTFirst,fTLast))
{
return false;
}
// directions E[i0]xF[i1]
for (i1 = 0; i1 < 3; i1++)
{
for (i0 = 0; i0 < 3; i0++)
{
kDir = akE[i0].UnitCross(akF[i1]);
if (!FindOverlap(kDir,fTMax,kVel,eSide,kTCfg0,kTCfg1,fTFirst,
fTLast))
{
return false;
}
}
}
}
else // triangles are parallel (and, in fact, coplanar)
{
// directions NxE[i0]
for (i0 = 0; i0 < 3; i0++)
{
kDir = kN.UnitCross(akE[i0]);
if (!FindOverlap(kDir,fTMax,kVel,eSide,kTCfg0,kTCfg1,fTFirst,
fTLast))
{
return false;
}
}
// directions NxF[i1]
for (i1 = 0; i1 < 3; i1++)
{
kDir = kM.UnitCross(akF[i1]);
if (!FindOverlap(kDir,fTMax,kVel,eSide,kTCfg0,kTCfg1,fTFirst,
fTLast))
{
return false;
}
}
}
if (fTFirst <= (Real)0.0)
{
return false;
}
m_fContactTime = fTFirst;
// adjust U and V for first time of contact before finding contact set
Triangle3<Real> akMTri0, akMTri1;
for (i0 = 0; i0 < 3; i0++)
{
akMTri0.V[i0] = m_rkTriangle0.V[i0] + fTFirst*rkVelocity0;
akMTri1.V[i0] = m_rkTriangle1.V[i0] + fTFirst*rkVelocity1;
}
FindContactSet(akMTri0,akMTri1,eSide,kTCfg0,kTCfg1);
return true;
}
//----------------------------------------------------------------------------
template <class Real>
int IntrTriangle3Triangle3<Real>::GetQuantity () const
{
return m_iQuantity;
}
//----------------------------------------------------------------------------
template <class Real>
const Vector3<Real>& IntrTriangle3Triangle3<Real>::GetPoint (int i) const
{
assert(0 <= i && i < m_iQuantity);
return m_akPoint[i];
}
//----------------------------------------------------------------------------
template <class Real>
void IntrTriangle3Triangle3<Real>::ProjectOntoAxis (
const Triangle3<Real>& rkTri, const Vector3<Real>& rkAxis, Real& rfMin,
Real& rfMax)
{
Real fDot0 = rkAxis.Dot(rkTri.V[0]);
Real fDot1 = rkAxis.Dot(rkTri.V[1]);
Real fDot2 = rkAxis.Dot(rkTri.V[2]);
rfMin = fDot0;
rfMax = rfMin;
if (fDot1 < rfMin)
{
rfMin = fDot1;
}
else if (fDot1 > rfMax)
{
rfMax = fDot1;
}
if (fDot2 < rfMin)
{
rfMin = fDot2;
}
else if (fDot2 > rfMax)
{
rfMax = fDot2;
}
}
//----------------------------------------------------------------------------
template <class Real>
void IntrTriangle3Triangle3<Real>::TrianglePlaneRelations (
const Triangle3<Real>& rkTriangle, const Plane3<Real>& rkPlane,
Real afDistance[3], int aiSign[3], int& riPositive, int& riNegative,
int& riZero)
{
// Compute the signed distances of triangle vertices to the plane. Use
// an epsilon-thick plane test.
riPositive = 0;
riNegative = 0;
riZero = 0;
for (int i = 0; i < 3; i++)
{
afDistance[i] = rkPlane.DistanceTo(rkTriangle.V[i]);
if (afDistance[i] > Math<Real>::ZERO_TOLERANCE)
{
aiSign[i] = 1;
riPositive++;
}
else if (afDistance[i] < -Math<Real>::ZERO_TOLERANCE)
{
aiSign[i] = -1;
riNegative++;
}
else
{
afDistance[i] = (Real)0.0;
aiSign[i] = 0;
riZero++;
}
}
}
//----------------------------------------------------------------------------
template <class Real>
void IntrTriangle3Triangle3<Real>::GetInterval (
const Triangle3<Real>& rkTriangle, const Line3<Real>& rkLine,
const Real afDistance[3], const int aiSign[3], Real afParam[2])
{
// project triangle onto line
Real afProj[3];
int i;
for (i = 0; i < 3; i++)
{
Vector3<Real> kDiff = rkTriangle.V[i] - rkLine.Origin;
afProj[i] = rkLine.Direction.Dot(kDiff);
}
// compute transverse intersections of triangle edges with line
Real fNumer, fDenom;
int i0, i1, i2;
int iQuantity = 0;
for (i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
{
if (aiSign[i0]*aiSign[i1] < 0)
{
assert( iQuantity < 2 );
fNumer = afDistance[i0]*afProj[i1] - afDistance[i1]*afProj[i0];
fDenom = afDistance[i0] - afDistance[i1];
afParam[iQuantity++] = fNumer/fDenom;
}
}
// check for grazing contact
if (iQuantity < 2)
{
for (i0 = 1, i1 = 2, i2 = 0; i2 < 3; i0 = i1, i1 = i2, i2++)
{
if (aiSign[i2] == 0)
{
assert(iQuantity < 2);
afParam[iQuantity++] = afProj[i2];
}
}
}
// sort
assert(iQuantity == 1 || iQuantity == 2);
if (iQuantity == 2)
{
if (afParam[0] > afParam[1])
{
Real fSave = afParam[0];
afParam[0] = afParam[1];
afParam[1] = fSave;
}
}
else
{
afParam[1] = afParam[0];
}
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::ContainsPoint (
const Triangle3<Real>& rkTriangle, const Plane3<Real>& rkPlane,
const Vector3<Real>& rkPoint)
{
Vector3<Real> kU0, kU1;
Vector3<Real>::GenerateComplementBasis(kU0,kU1,rkPlane.Normal);
Vector3<Real> kPmV0 = rkPoint - rkTriangle.V[0];
Vector3<Real> kV1mV0 = rkTriangle.V[1] - rkTriangle.V[0];
Vector3<Real> kV2mV0 = rkTriangle.V[2] - rkTriangle.V[0];
Vector2<Real> kProjP(kU0.Dot(kPmV0),kU1.Dot(kPmV0));
Vector2<Real> akProjV[3] =
{
Vector2<Real>::ZERO,
Vector2<Real>(kU0.Dot(kV1mV0),kU1.Dot(kV1mV0)),
Vector2<Real>(kU0.Dot(kV2mV0),kU1.Dot(kV2mV0))
};
return Query2<Real>(3,akProjV).ToTriangle(kProjP,0,1,2) <= 0;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::IntersectsSegment (
const Triangle3<Real>& rkTriangle, const Vector3<Real>& rkEnd0,
const Vector3<Real>& rkEnd1)
{
// TO DO.
(void)rkTriangle;
(void)rkEnd0;
(void)rkEnd1;
return false;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::GetCoplanarIntersection (
const Plane3<Real>& rkPlane, const Triangle3<Real>& rkTri0,
const Triangle3<Real>& rkTri1)
{
(void)rkTri0;
(void)rkTri1;
// Project triangles onto coordinate plane most aligned with plane
// normal.
int iMaxNormal = 0;
Real fMax = Math<Real>::FAbs(rkPlane.Normal.X());
Real fAbs = Math<Real>::FAbs(rkPlane.Normal.Y());
if (fAbs > fMax)
{
iMaxNormal = 1;
fMax = fAbs;
}
fAbs = Math<Real>::FAbs(rkPlane.Normal.Z());
if (fAbs > fMax)
{
iMaxNormal = 2;
}
Triangle2<Real> kProjTri0, kProjTri1;
int i;
if (iMaxNormal == 0)
{
// project onto yz-plane
for (i = 0; i < 3; i++)
{
kProjTri0.V[i].X() = m_rkTriangle0.V[i].Y();
kProjTri0.V[i].Y() = m_rkTriangle0.V[i].Z();
kProjTri1.V[i].X() = m_rkTriangle1.V[i].Y();
kProjTri1.V[i].Y() = m_rkTriangle1.V[i].Z();
}
}
else if (iMaxNormal == 1)
{
// project onto xz-plane
for (i = 0; i < 3; i++)
{
kProjTri0.V[i].X() = m_rkTriangle0.V[i].X();
kProjTri0.V[i].Y() = m_rkTriangle0.V[i].Z();
kProjTri1.V[i].X() = m_rkTriangle1.V[i].X();
kProjTri1.V[i].Y() = m_rkTriangle1.V[i].Z();
}
}
else
{
// project onto xy-plane
for (i = 0; i < 3; i++)
{
kProjTri0.V[i].X() = m_rkTriangle0.V[i].X();
kProjTri0.V[i].Y() = m_rkTriangle0.V[i].Y();
kProjTri1.V[i].X() = m_rkTriangle1.V[i].X();
kProjTri1.V[i].Y() = m_rkTriangle1.V[i].Y();
}
}
// 2D triangle intersection routines require counterclockwise ordering
Vector2<Real> kSave;
Vector2<Real> kEdge0 = kProjTri0.V[1] - kProjTri0.V[0];
Vector2<Real> kEdge1 = kProjTri0.V[2] - kProjTri0.V[0];
if (kEdge0.DotPerp(kEdge1) < (Real)0.0)
{
// triangle is clockwise, reorder it
kSave = kProjTri0.V[1];
kProjTri0.V[1] = kProjTri0.V[2];
kProjTri0.V[2] = kSave;
}
kEdge0 = kProjTri1.V[1] - kProjTri1.V[0];
kEdge1 = kProjTri1.V[2] - kProjTri1.V[0];
if (kEdge0.DotPerp(kEdge1) < (Real)0.0)
{
// triangle is clockwise, reorder it
kSave = kProjTri1.V[1];
kProjTri1.V[1] = kProjTri1.V[2];
kProjTri1.V[2] = kSave;
}
IntrTriangle2Triangle2<Real> kIntr(kProjTri0,kProjTri1);
if (!kIntr.Find())
{
return false;
}
// map 2D intersections back to the 3D triangle space
m_iQuantity = kIntr.GetQuantity();
if (iMaxNormal == 0)
{
Real fInvNX = ((Real)1.0)/rkPlane.Normal.X();
for (i = 0; i < m_iQuantity; i++)
{
m_akPoint[i].Y() = kIntr.GetPoint(i).X();
m_akPoint[i].Z() = kIntr.GetPoint(i).Y();
m_akPoint[i].X() = fInvNX*(rkPlane.Constant -
rkPlane.Normal.Y()*m_akPoint[i].Y() -
rkPlane.Normal.Z()*m_akPoint[i].Z());
}
}
else if (iMaxNormal == 1)
{
Real fInvNY = ((Real)1.0)/rkPlane.Normal.Y();
for (i = 0; i < m_iQuantity; i++)
{
m_akPoint[i].X() = kIntr.GetPoint(i).X();
m_akPoint[i].Z() = kIntr.GetPoint(i).Y();
m_akPoint[i].Y() = fInvNY*(rkPlane.Constant -
rkPlane.Normal.X()*m_akPoint[i].X() -
rkPlane.Normal.Z()*m_akPoint[i].Z());
}
}
else
{
Real fInvNZ = ((Real)1.0)/rkPlane.Normal.Z();
for (i = 0; i < m_iQuantity; i++)
{
m_akPoint[i].X() = kIntr.GetPoint(i).X();
m_akPoint[i].Y() = kIntr.GetPoint(i).Y();
m_akPoint[i].Z() = fInvNZ*(rkPlane.Constant -
rkPlane.Normal.X()*m_akPoint[i].X() -
rkPlane.Normal.Y()*m_akPoint[i].Y());
}
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::TestOverlap (const Vector3<Real>& rkAxis,
Real fTMax, Real fSpeed, Real fUMin, Real fUMax, Real fVMin, Real fVMax,
Real& rfTFirst, Real& rfTLast)
{
(void)rkAxis;
// Constant velocity separating axis test.
Real fT;
if (fVMax < fUMin) // V on left of U
{
if (fSpeed <= (Real)0.0) // V moving away from U
{
return false;
}
// find first time of contact on this axis
fT = (fUMin - fVMax)/fSpeed;
if (fT > rfTFirst)
{
rfTFirst = fT;
}
// quick out: intersection after desired time interval
if (rfTFirst > fTMax)
{
return false;
}
// find last time of contact on this axis
fT = (fUMax - fVMin)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired time interval
if (rfTFirst > rfTLast)
{
return false;
}
}
else if ( fUMax < fVMin ) // V on right of U
{
if (fSpeed >= (Real)0.0) // V moving away from U
{
return false;
}
// find first time of contact on this axis
fT = (fUMax - fVMin)/fSpeed;
if (fT > rfTFirst)
{
rfTFirst = fT;
}
// quick out: intersection after desired time interval
if (rfTFirst > fTMax)
{
return false;
}
// find last time of contact on this axis
fT = (fUMin - fVMax)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired time interval
if (rfTFirst > rfTLast)
{
return false;
}
}
else // V and U on overlapping interval
{
if (fSpeed > (Real)0.0)
{
// find last time of contact on this axis
fT = (fUMax - fVMin)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired interval
if (rfTFirst > rfTLast)
{
return false;
}
}
else if (fSpeed < (Real)0.0)
{
// find last time of contact on this axis
fT = (fUMin - fVMax)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired interval
if (rfTFirst > rfTLast)
{
return false;
}
}
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::FindOverlap (const Vector3<Real>& rkAxis,
Real fTMax, Real fSpeed, const Configuration& rkUC,
const Configuration& rkVC, ContactSide& rkSide, Configuration& rkTUC,
Configuration& rkTVC, Real& rfTFirst, Real& rfTLast)
{
(void)rkAxis;
// Constant velocity separating axis test. UC and VC are the new
// potential configurations, and TUC and TVC are the best known
// configurations.
Real fT;
if (rkVC.Max < rkUC.Min) // V on left of U
{
if (fSpeed <= (Real)0.0) // V moving away from U
{
return false;
}
// find first time of contact on this axis
fT = (rkUC.Min - rkVC.Max)/fSpeed;
// If this is the new maximum first time of contact, set side and
// configuration.
if (fT > rfTFirst)
{
rfTFirst = fT;
rkSide = CS_LEFT;
rkTUC = rkUC;
rkTVC = rkVC;
}
// quick out: intersection after desired interval
if (rfTFirst > fTMax)
{
return false;
}
// find last time of contact on this axis
fT = (rkUC.Max - rkVC.Min)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired interval
if (rfTFirst > rfTLast)
{
return false;
}
}
else if (rkUC.Max < rkVC.Min) // V on right of U
{
if (fSpeed >= (Real)0.0) // V moving away from U
{
return false;
}
// find first time of contact on this axis
fT = (rkUC.Max - rkVC.Min)/fSpeed;
// If this is the new maximum first time of contact, set side and
// configuration.
if (fT > rfTFirst)
{
rfTFirst = fT;
rkSide = CS_RIGHT;
rkTUC = rkUC;
rkTVC = rkVC;
}
// quick out: intersection after desired interval
if (rfTFirst > fTMax)
{
return false;
}
// find last time of contact on this axis
fT = (rkUC.Min - rkVC.Max)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired interval
if (rfTFirst > rfTLast)
{
return false;
}
}
else // V and U on overlapping interval
{
if (fSpeed > (Real)0.0)
{
// find last time of contact on this axis
fT = (rkUC.Max - rkVC.Min)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired interval
if (rfTFirst > rfTLast)
{
return false;
}
}
else if ( fSpeed < (Real)0.0 )
{
// find last time of contact on this axis
fT = (rkUC.Min - rkVC.Max)/fSpeed;
if (fT < rfTLast)
{
rfTLast = fT;
}
// quick out: intersection before desired interval
if (rfTFirst > rfTLast)
{
return false;
}
}
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::TestOverlap (const Vector3<Real>& rkAxis,
Real fTMax, const Vector3<Real>& rkVelocity, Real& rfTFirst,
Real& rfTLast)
{
Real fMin0, fMax0, fMin1, fMax1;
ProjectOntoAxis(m_rkTriangle0,rkAxis,fMin0,fMax0);
ProjectOntoAxis(m_rkTriangle1,rkAxis,fMin1,fMax1);
Real fSpeed = rkVelocity.Dot(rkAxis);
return TestOverlap(rkAxis,fTMax,fSpeed,fMin0,fMax0,fMin1,fMax1,rfTFirst,
rfTLast);
}
//----------------------------------------------------------------------------
template <class Real>
bool IntrTriangle3Triangle3<Real>::FindOverlap (const Vector3<Real>& rkAxis,
Real fTMax, const Vector3<Real>& rkVelocity, ContactSide& reSide,
Configuration& rkTCfg0, Configuration& rkTCfg1, Real& rfTFirst,
Real& rfTLast)
{
Configuration kCfg0, kCfg1;
ProjectOntoAxis(m_rkTriangle0,rkAxis,kCfg0);
ProjectOntoAxis(m_rkTriangle1,rkAxis,kCfg1);
Real fSpeed = rkVelocity.Dot(rkAxis);
return FindOverlap(rkAxis,fTMax,fSpeed,kCfg0,kCfg1,reSide,rkTCfg0,rkTCfg1,
rfTFirst,rfTLast);
}
//----------------------------------------------------------------------------
template <class Real>
void IntrTriangle3Triangle3<Real>::ProjectOntoAxis (
const Triangle3<Real>& rkTri, const Vector3<Real>& rkAxis,
Configuration& rkCfg)
{
// find projections of vertices onto potential separating axis
Real fD0 = rkAxis.Dot(rkTri.V[0]);
Real fD1 = rkAxis.Dot(rkTri.V[1]);
Real fD2 = rkAxis.Dot(rkTri.V[2]);
// explicit sort of vertices to construct a Configuration object
if (fD0 <= fD1)
{
if (fD1 <= fD2) // D0 <= D1 <= D2
{
if (fD0 != fD1)
{
if (fD1 != fD2)
{
rkCfg.Map = M111;
}
else
{
rkCfg.Map = M12;
}
}
else // ( D0 == D1 )
{
if (fD1 != fD2)
{
rkCfg.Map = M21;
}
else
{
rkCfg.Map = M3;
}
}
rkCfg.Index[0] = 0;
rkCfg.Index[1] = 1;
rkCfg.Index[2] = 2;
rkCfg.Min = fD0;
rkCfg.Max = fD2;
}
else if (fD0 <= fD2) // D0 <= D2 < D1
{
if (fD0 != fD2)
{
rkCfg.Map = M111;
rkCfg.Index[0] = 0;
rkCfg.Index[1] = 2;
rkCfg.Index[2] = 1;
}
else
{
rkCfg.Map = M21;
rkCfg.Index[0] = 2;
rkCfg.Index[1] = 0;
rkCfg.Index[2] = 1;
}
rkCfg.Min = fD0;
rkCfg.Max = fD1;
}
else // D2 < D0 <= D1
{
if (fD0 != fD1)
{
rkCfg.Map = M111;
}
else
{
rkCfg.Map = M12;
}
rkCfg.Index[0] = 2;
rkCfg.Index[1] = 0;
rkCfg.Index[2] = 1;
rkCfg.Min = fD2;
rkCfg.Max = fD1;
}
}
else if (fD2 <= fD1) // D2 <= D1 < D0
{
if (fD2 != fD1)
{
rkCfg.Map = M111;
rkCfg.Index[0] = 2;
rkCfg.Index[1] = 1;
rkCfg.Index[2] = 0;
}
else
{
rkCfg.Map = M21;
rkCfg.Index[0] = 1;
rkCfg.Index[1] = 2;
rkCfg.Index[2] = 0;
}
rkCfg.Min = fD2;
rkCfg.Max = fD0;
}
else if (fD2 <= fD0) // D1 < D2 <= D0
{
if (fD2 != fD0)
{
rkCfg.Map = M111;
}
else
{
rkCfg.Map = M12;
}
rkCfg.Index[0] = 1;
rkCfg.Index[1] = 2;
rkCfg.Index[2] = 0;
rkCfg.Min = fD1;
rkCfg.Max = fD0;
}
else // D1 < D0 < D2
{
rkCfg.Map = M111;
rkCfg.Index[0] = 1;
rkCfg.Index[1] = 0;
rkCfg.Index[2] = 2;
rkCfg.Min = fD1;
rkCfg.Max = fD2;
}
}
//----------------------------------------------------------------------------
template <class Real>
void IntrTriangle3Triangle3<Real>::FindContactSet (
const Triangle3<Real>& rkTri0, const Triangle3<Real>& rkTri1,
ContactSide& reSide, Configuration& rkCfg0, Configuration& rkCfg1)
{
if (reSide == CS_RIGHT) // tri1 to the right of tri0
{
if (rkCfg0.Map == M21 || rkCfg0.Map == M111)
{
// tri0 touching tri1 at a single point
m_iQuantity = 1;
m_akPoint[0] = rkTri0.V[2];
}
else if (rkCfg1.Map == M12 || rkCfg1.Map == M111)
{
// tri1 touching tri0 at a single point
m_iQuantity = 1;
m_akPoint[0] = rkTri1.V[0];
}
else if (rkCfg0.Map == M12)
{
if (rkCfg1.Map == M21)
{
// edge0-edge1 intersection
GetEdgeEdgeIntersection(rkTri0.V[1],rkTri0.V[2],rkTri1.V[0],
rkTri1.V[1]);
}
else // rkCfg1.Map == m3
{
// uedge-vface intersection
//Vector3<Real> akEdge0[2] = { rkTri0.V[1], rkTri0.V[2] };
//FindContactSetColinearLineTri(akEdge0,rkTri1,riQuantity,
// akP);
}
}
else // rkCfg0.Map == M3
{
if (rkCfg1.Map == M21)
{
// face0-edge1 intersection
//Vector3<Real> akEdge1[2] = { rkTri1.V[0], rkTri1.V[1] };
//FindContactSetColinearLineTri(akEdge1,rkTri0,riQuantity,
// akP);
}
else // rkCfg1.Map == M3
{
// face0-face1 intersection
Plane3<Real> kPlane0(rkTri0.V[0],rkTri0.V[1],rkTri0.V[2]);
GetCoplanarIntersection(kPlane0,rkTri0,rkTri1);
}
}
}
else if (reSide == CS_LEFT) // tri1 to the left of tri0
{
if (rkCfg1.Map == M21 || rkCfg1.Map == M111)
{
// tri1 touching tri0 at a single point
m_iQuantity = 1;
m_akPoint[0] = rkTri1.V[2];
}
else if (rkCfg0.Map == M12 || rkCfg0.Map == M111)
{
// tri0 touching tri1 at a single point
m_iQuantity = 1;
m_akPoint[0] = rkTri0.V[0];
}
else if (rkCfg1.Map == M12)
{
if (rkCfg0.Map == M21)
{
// edge0-edge1 intersection
GetEdgeEdgeIntersection(rkTri0.V[0],rkTri0.V[1],rkTri1.V[1],
rkTri1.V[2]);
}
else // rkCfg0.Map == M3
{
// edge1-face0 intersection
//Vector3<Real> akEdge1[2] = { rkTri1.V[1], rkTri1.V[2] };
//FindContactSetColinearLineTri(akEdge1,rkTri0,riQuantity,
// akP);
}
}
else // rkCfg1.Map == M3
{
if (rkCfg0.Map == M21)
{
// edge0-face1 intersection
//Vector3<Real> akEdge0[2] = { rkTri0.V[0], rkTri0.V[1] };
//FindContactSetColinearLineTri(akEdge0,rkTri1,riQuantity,
// akP);
}
else // rkCfg0.Map == M
{
// face0-face1 intersection
Plane3<Real> kPlane0(rkTri0.V[0],rkTri0.V[1],rkTri0.V[2]);
GetCoplanarIntersection(kPlane0,rkTri0,rkTri1);
}
}
}
else // reSide == CS_NONE
{
// triangles are already intersecting tranversely
IntrTriangle3Triangle3<Real>(rkTri0,rkTri1).Find();
}
}
//----------------------------------------------------------------------------
template <class Real>
void IntrTriangle3Triangle3<Real>::GetEdgeEdgeIntersection (
const Vector3<Real>& rkU0, const Vector3<Real>& rkU1,
const Vector3<Real>& rkV0, const Vector3<Real>& rkV1)
{
// TO DO.
(void)rkU0;
(void)rkU1;
(void)rkV0;
(void)rkV1;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
class IntrTriangle3Triangle3<float>;
template WM4_FOUNDATION_ITEM
class IntrTriangle3Triangle3<double>;
//----------------------------------------------------------------------------
}