📄 wmlintrbox3box3.cpp
字号:
// Magic Software, Inc.
// http://www.magic-software.com
// http://www.wild-magic.com
// Copyright (c) 2003. All Rights Reserved
//
// The Wild Magic Library (WML) source code is supplied under the terms of
// the license agreement http://www.magic-software.com/License/WildMagic.pdf
// and may not be copied or disclosed except in accordance with the terms of
// that agreement.
#include "WmlIntrBox3Box3.h"
#include "WmlIntrUtilityLin3.h"
#include "WmlIntrUtilityBox3.h"
using namespace Wml;
//----------------------------------------------------------------------------
// stationary objects
//----------------------------------------------------------------------------
template <class Real>
bool Wml::TestIntersection (const Box3<Real>& rkBox0,
const Box3<Real>& rkBox1)
{
// Cutoff for cosine of angles between box axes. This is used to catch
// the cases when at least one pair of axes are parallel. If this happens,
// there is no need to test for separation along the Cross(A[i],B[j])
// directions.
const Real fCutoff = (Real)0.999999;
bool bExistsParallelPair = false;
int i;
// convenience variables
const Vector3<Real>* akA = rkBox0.Axes();
const Vector3<Real>* akB = rkBox1.Axes();
const Real* afEA = rkBox0.Extents();
const Real* afEB = rkBox1.Extents();
// compute difference of box centers, D = C1-C0
Vector3<Real> kD = rkBox1.Center() - rkBox0.Center();
Real aafC[3][3]; // matrix C = A^T B, c_{ij} = Dot(A_i,B_j)
Real aafAbsC[3][3]; // |c_{ij}|
Real afAD[3]; // Dot(A_i,D)
Real fR0, fR1, fR; // interval radii and distance between centers
Real fR01; // = R0 + R1
// axis C0+t*A0
for (i = 0; i < 3; i++)
{
aafC[0][i] = akA[0].Dot(akB[i]);
aafAbsC[0][i] = Math<Real>::FAbs(aafC[0][i]);
if ( aafAbsC[0][i] > fCutoff )
bExistsParallelPair = true;
}
afAD[0] = akA[0].Dot(kD);
fR = Math<Real>::FAbs(afAD[0]);
fR1 = afEB[0]*aafAbsC[0][0]+afEB[1]*aafAbsC[0][1]+afEB[2]*aafAbsC[0][2];
fR01 = afEA[0] + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A1
for (i = 0; i < 3; i++)
{
aafC[1][i] = akA[1].Dot(akB[i]);
aafAbsC[1][i] = Math<Real>::FAbs(aafC[1][i]);
if ( aafAbsC[1][i] > fCutoff )
bExistsParallelPair = true;
}
afAD[1] = akA[1].Dot(kD);
fR = Math<Real>::FAbs(afAD[1]);
fR1 = afEB[0]*aafAbsC[1][0]+afEB[1]*aafAbsC[1][1]+afEB[2]*aafAbsC[1][2];
fR01 = afEA[1] + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A2
for (i = 0; i < 3; i++)
{
aafC[2][i] = akA[2].Dot(akB[i]);
aafAbsC[2][i] = Math<Real>::FAbs(aafC[2][i]);
if ( aafAbsC[2][i] > fCutoff )
bExistsParallelPair = true;
}
afAD[2] = akA[2].Dot(kD);
fR = Math<Real>::FAbs(afAD[2]);
fR1 = afEB[0]*aafAbsC[2][0]+afEB[1]*aafAbsC[2][1]+afEB[2]*aafAbsC[2][2];
fR01 = afEA[2] + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*B0
fR = Math<Real>::FAbs(akB[0].Dot(kD));
fR0 = afEA[0]*aafAbsC[0][0]+afEA[1]*aafAbsC[1][0]+afEA[2]*aafAbsC[2][0];
fR01 = fR0 + afEB[0];
if ( fR > fR01 )
return false;
// axis C0+t*B1
fR = Math<Real>::FAbs(akB[1].Dot(kD));
fR0 = afEA[0]*aafAbsC[0][1]+afEA[1]*aafAbsC[1][1]+afEA[2]*aafAbsC[2][1];
fR01 = fR0 + afEB[1];
if ( fR > fR01 )
return false;
// axis C0+t*B2
fR = Math<Real>::FAbs(akB[2].Dot(kD));
fR0 = afEA[0]*aafAbsC[0][2]+afEA[1]*aafAbsC[1][2]+afEA[2]*aafAbsC[2][2];
fR01 = fR0 + afEB[2];
if ( fR > fR01 )
return false;
// At least one pair of box axes was parallel, so the separation is
// effectively in 2D where checking the "edge" normals is sufficient for
// the separation of the boxes.
if ( bExistsParallelPair )
return true;
// axis C0+t*A0xB0
fR = Math<Real>::FAbs(afAD[2]*aafC[1][0]-afAD[1]*aafC[2][0]);
fR0 = afEA[1]*aafAbsC[2][0] + afEA[2]*aafAbsC[1][0];
fR1 = afEB[1]*aafAbsC[0][2] + afEB[2]*aafAbsC[0][1];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A0xB1
fR = Math<Real>::FAbs(afAD[2]*aafC[1][1]-afAD[1]*aafC[2][1]);
fR0 = afEA[1]*aafAbsC[2][1] + afEA[2]*aafAbsC[1][1];
fR1 = afEB[0]*aafAbsC[0][2] + afEB[2]*aafAbsC[0][0];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A0xB2
fR = Math<Real>::FAbs(afAD[2]*aafC[1][2]-afAD[1]*aafC[2][2]);
fR0 = afEA[1]*aafAbsC[2][2] + afEA[2]*aafAbsC[1][2];
fR1 = afEB[0]*aafAbsC[0][1] + afEB[1]*aafAbsC[0][0];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A1xB0
fR = Math<Real>::FAbs(afAD[0]*aafC[2][0]-afAD[2]*aafC[0][0]);
fR0 = afEA[0]*aafAbsC[2][0] + afEA[2]*aafAbsC[0][0];
fR1 = afEB[1]*aafAbsC[1][2] + afEB[2]*aafAbsC[1][1];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A1xB1
fR = Math<Real>::FAbs(afAD[0]*aafC[2][1]-afAD[2]*aafC[0][1]);
fR0 = afEA[0]*aafAbsC[2][1] + afEA[2]*aafAbsC[0][1];
fR1 = afEB[0]*aafAbsC[1][2] + afEB[2]*aafAbsC[1][0];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A1xB2
fR = Math<Real>::FAbs(afAD[0]*aafC[2][2]-afAD[2]*aafC[0][2]);
fR0 = afEA[0]*aafAbsC[2][2] + afEA[2]*aafAbsC[0][2];
fR1 = afEB[0]*aafAbsC[1][1] + afEB[1]*aafAbsC[1][0];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A2xB0
fR = Math<Real>::FAbs(afAD[1]*aafC[0][0]-afAD[0]*aafC[1][0]);
fR0 = afEA[0]*aafAbsC[1][0] + afEA[1]*aafAbsC[0][0];
fR1 = afEB[1]*aafAbsC[2][2] + afEB[2]*aafAbsC[2][1];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A2xB1
fR = Math<Real>::FAbs(afAD[1]*aafC[0][1]-afAD[0]*aafC[1][1]);
fR0 = afEA[0]*aafAbsC[1][1] + afEA[1]*aafAbsC[0][1];
fR1 = afEB[0]*aafAbsC[2][2] + afEB[2]*aafAbsC[2][0];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
// axis C0+t*A2xB2
fR = Math<Real>::FAbs(afAD[1]*aafC[0][2]-afAD[0]*aafC[1][2]);
fR0 = afEA[0]*aafAbsC[1][2] + afEA[1]*aafAbsC[0][2];
fR1 = afEB[0]*aafAbsC[2][1] + afEB[1]*aafAbsC[2][0];
fR01 = fR0 + fR1;
if ( fR > fR01 )
return false;
return true;
}
//----------------------------------------------------------------------------
// moving objects
//----------------------------------------------------------------------------
template <class Real>
static bool BoxAxisFind (const Vector3<Real>& rkVelocity,
const Vector3<Real>& rkAxis, const Box3<Real>& rkBoxU,
const Box3<Real>& rkBoxV, Real& rfTFirst, Real& rfTLast, Real fTMax,
ContactSide& reSide, ContactConfig<Real>& rkTUC,
ContactConfig<Real>& rkTVC)
{
ContactConfig<Real> kUC;
GetBoxConfiguration(rkAxis,rkBoxU,kUC);
ContactConfig<Real> kVC;
GetBoxConfiguration(rkAxis,rkBoxV,kVC);
return AxisFind(rkVelocity,rkAxis,kUC,kVC,reSide,rkTUC,rkTVC,rfTFirst,
rfTLast,fTMax);
}
//----------------------------------------------------------------------------
template <class Real>
static void FindContactSetCoplanarRectRect (const Vector3<Real> akFace0[4],
const Vector3<Real> akFace1[4], int& riQuantity, Vector3<Real>* akP)
{
// The potential intersection is initialized to face 0, and then clipped
// against the four sides of face 1.
riQuantity = 4;
memcpy(akP,akFace0,4*sizeof(Vector3<Real>));
for (int i0 = 3, i1 = 0; i1 < 4; i0 = i1++)
{
Vector3<Real> kNormal = akFace1[i1] - akFace1[i0];
Real fConstant = kNormal.Dot(akFace1[i0]);
ClipConvexPolygonAgainstPlane(kNormal,fConstant,riQuantity,akP);
}
}
//----------------------------------------------------------------------------
template <class Real>
static void FindContactSet (const Box3<Real>& rkBox0,
const Box3<Real>& rkBox1, ContactSide eSide,
const ContactConfig<Real>& rkUC, const ContactConfig<Real>& rkVC,
const Vector3<Real>& rkVel0, const Vector3<Real>& rkVel1,
Real fTFirst, int& riQuantity, Vector3<Real>* akP)
{
// move boxes to new position
Box3<Real> kNewBox0, kNewBox1;
kNewBox0.Center() = rkBox0.Center() + fTFirst*rkVel0;
kNewBox1.Center() = rkBox1.Center() + fTFirst*rkVel1;
for (int i = 0; i < 3; i++)
{
kNewBox0.Axis(i) = rkBox0.Axis(i);
kNewBox0.Extent(i) = rkBox0.Extent(i);
kNewBox1.Axis(i) = rkBox1.Axis(i);
kNewBox1.Extent(i) = rkBox1.Extent(i);
}
if ( eSide == LEFT )
{
// box1 on left of box0
if ( rkUC.m_kMap == m1_1 )
{
riQuantity = 1;
akP[0] = GetPoint(rkUC.m_aiIndex[0],kNewBox0);
}
else if ( rkVC.m_kMap == m1_1 )
{
riQuantity = 1;
akP[0] = GetPoint(rkVC.m_aiIndex[7],kNewBox1);
}
else if ( rkUC.m_kMap == m2_2 )
{
if ( rkVC.m_kMap == m2_2 )
{
// box0edge-box1edge intersection
Vector3<Real> akEdge0[2], akEdge1[2];
akEdge0[0] = GetPoint(rkUC.m_aiIndex[0],kNewBox0);
akEdge0[1] = GetPoint(rkUC.m_aiIndex[1],kNewBox0);
akEdge1[0] = GetPoint(rkVC.m_aiIndex[6],kNewBox1);
akEdge1[1] = GetPoint(rkVC.m_aiIndex[7],kNewBox1);
FindContactSetLinLin(akEdge0,akEdge1,riQuantity,akP);
}
else // rkVC.m_kMap == m44
{
// box0edge-box1face intersection
Vector3<Real> akEdge0[2], akFace1[4];
akEdge0[0] = GetPoint(rkUC.m_aiIndex[0],kNewBox0);
akEdge0[1] = GetPoint(rkUC.m_aiIndex[1],kNewBox0);
akFace1[0] = GetPoint(rkVC.m_aiIndex[4],kNewBox1);
akFace1[1] = GetPoint(rkVC.m_aiIndex[5],kNewBox1);
akFace1[2] = GetPoint(rkVC.m_aiIndex[6],kNewBox1);
akFace1[3] = GetPoint(rkVC.m_aiIndex[7],kNewBox1);
FindContactSetCoplanarLineRect(akEdge0,akFace1,riQuantity,
akP);
}
}
else // rkUC.m_kMap == m44
{
if ( rkVC.m_kMap == m2_2 )
{
// box0face-box1edge intersection
Vector3<Real> akFace0[4], akEdge1[2];
akFace0[0] = GetPoint(rkUC.m_aiIndex[0],kNewBox0);
akFace0[1] = GetPoint(rkUC.m_aiIndex[1],kNewBox0);
akFace0[2] = GetPoint(rkUC.m_aiIndex[2],kNewBox0);
akFace0[3] = GetPoint(rkUC.m_aiIndex[3],kNewBox0);
akEdge1[0] = GetPoint(rkVC.m_aiIndex[6],kNewBox1);
akEdge1[1] = GetPoint(rkVC.m_aiIndex[7],kNewBox1);
FindContactSetCoplanarLineRect(akEdge1,akFace0,riQuantity,
akP);
}
else
{
// box0face-box1face intersection
Vector3<Real> akFace0[4], akFace1[4];
akFace0[0] = GetPoint(rkUC.m_aiIndex[0],kNewBox0);
akFace0[1] = GetPoint(rkUC.m_aiIndex[1],kNewBox0);
akFace0[2] = GetPoint(rkUC.m_aiIndex[2],kNewBox0);
akFace0[3] = GetPoint(rkUC.m_aiIndex[3],kNewBox0);
akFace1[0] = GetPoint(rkVC.m_aiIndex[4],kNewBox1);
akFace1[1] = GetPoint(rkVC.m_aiIndex[5],kNewBox1);
akFace1[2] = GetPoint(rkVC.m_aiIndex[6],kNewBox1);
akFace1[3] = GetPoint(rkVC.m_aiIndex[7],kNewBox1);
FindContactSetCoplanarRectRect(akFace0,akFace1,riQuantity,
akP);
}
}
}
else // rkSide == RIGHT
{
// box1 on right of box0
if ( rkUC.m_kMap == m1_1 )
{
riQuantity = 1;
akP[0] = GetPoint(rkUC.m_aiIndex[7],kNewBox0);
}
else if ( rkVC.m_kMap == m1_1 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -