namespace TGS {
namespace COL {
template <typename TYPE, int DIM>
TgBOOL F_Axis_Seperation( PC_(AXIS_RESULT,DIM) ptgAxS, CR_(CAPSULE,DIM) tgCP0, CR_(CYLINDER,DIM) tgCY0 )
{
TgASSERT( tgCP0.Is_Valid() && tgCY0.Is_Valid() )
TYPE tyTest;
T_(VECTOR,DIM) tvTest;
C_(VECTOR,DIM) tvDS = MATH::F_SUB( tgCY0.Query_Origin(), tgCP0.Query_Origin() );
const TYPE tyDS_A1 = MATH::F_DOT( tvDS, tgCY0.Query_AxisUnit() );
ptgAxS->m_tyDepth = -LIMITS<TYPE>::MAX;
const TYPE tyABS_A0_A1 = P::ABS( MATH::F_DOT( tgCP0.Query_AxisUnit(), tgCY0.Query_AxisUnit() ) );
tyTest = P::ABS( tyDS_A1 ) - (tgCY0.Query_Extent() + tgCP0.Query_Radius() + tgCP0.Query_Extent()*tyABS_A0_A1);
if (tyTest > TYPE(0.0))
{
return (TgFALSE);
};
if (tyTest > ptgAxS->m_tyDepth)
{
ptgAxS->m_tvNormal = tyDS_A1 > TYPE(0.0) ? tgCY0.Query_AxisUnit() : MATH::F_NEG( tgCY0.Query_AxisUnit() );
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 1;
};
const TYPE tyRadSum = tgCP0.Query_Radius() + tgCY0.Query_Radius();
CR_(SEGMENT,DIM) tgSG_CP0 = tgCP0.Query_Segment();
CR_(SEGMENT,DIM) tgSG_CY0 = tgCY0.Query_Segment();
TYPE tyCA0,tyCA1, tyC0,tyC1, tyTMPA;
const TYPE tyDistSq = F_ClosestSq( &tyCA0, &tyCA1, tgSG_CP0, tgSG_CY0 );
if (tyDistSq > tyRadSum*tyRadSum)
{
return (TgFALSE);
};
C_(VECTOR,DIM) tvK0 = MATH::F_MUL( tyCA0, tgSG_CP0.Query_DirN() );
C_(VECTOR,DIM) tvK1 = MATH::F_MUL( tyCA1, tgSG_CY0.Query_DirN() );
C_(VECTOR,DIM) tvMin_CP0 = MATH::F_ADD( tgSG_CP0.Query_Origin(), tvK0 );
C_(VECTOR,DIM) tvMin_CY0 = MATH::F_ADD( tgSG_CY0.Query_Origin(), tvK1 );
T_(VECTOR,DIM) tvMinDirN;
TgBOOL bIntersecting = TgTRUE;
if (tyDistSq > LIMITS<TYPE>::EPSILON)
{
C_(VECTOR,DIM) tvMinDist = MATH::F_SUB( tvMin_CY0, tvMin_CP0 );
tvMinDirN = MATH::F_SUB( tvMin_CY0, tvMin_CP0 );
MATH::F_NORM( tvMinDirN );
TYPE tyT0,tyT1, tyT2,tyT3;
tgCP0.Project( &tyT0,&tyT1, tvMinDirN );
tgCY0.Project( &tyT2,&tyT3, tvMinDirN );
if (tyT1 - tyT2 < TYPE(0.0) || tyT3 - tyT0 < TYPE(0.0))
{
return (TgFALSE);
};
tyTest = tyT2 - tyT1;
if (tyTest > ptgAxS->m_tyDepth)
{
ptgAxS->m_tvPoint = tvMin_CY0;
ptgAxS->m_tvNormal = tvMinDirN;
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 2;
};
}
else
{
TYPE tyTest;
bIntersecting = TgFALSE;
tvMinDirN = MATH::F_NORM( &tyTest, tvDS );
if (Near_Zero( tyTest ))
{
return (TgTRUE);
};
};
tyC0 = MATH::F_DOT( tvMinDirN, tgCY0.Query_BasisUnit0() );
tyC1 = MATH::F_DOT( tvMinDirN, tgCY0.Query_BasisUnit1() );
C_(VECTOR,DIM) tvK2 = MATH::F_MUL( tyC0, tgCY0.Query_BasisUnit0() );
C_(VECTOR,DIM) tvK3 = MATH::F_MUL( tyC1, tgCY0.Query_BasisUnit1() );
tvTest = MATH::F_NORM( MATH::F_ADD( tvK2, tvK3 ) );
const TYPE tyABS_Ax_A0 = P::ABS( MATH::F_DOT(tvTest,tgCP0.Query_AxisUnit()) );
tyTest = P::ABS( MATH::F_DOT(tvTest,tvDS) ) - (tgCY0.Query_Radius() + tyABS_Ax_A0*tgCP0.Query_Extent() + tgCP0.Query_Radius());
if (tyTest > TYPE(0.0))
{
return (TgFALSE);
};
if (tyTest > ptgAxS->m_tyDepth)
{
ptgAxS->m_tvPoint = tvMin_CP0;
ptgAxS->m_tvNormal = tvTest;
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 2;
};
const TYPE tyABS_A0xA1 = P::SQRT( TYPE(1.0) - MIN( TYPE(1.0), tyABS_A0_A1*tyABS_A0_A1 ) );
if (!Near_One( tyABS_A0_A1 ) && !Near_Zero( tyABS_A0xA1 ))
{
tyC0 = MATH::F_DOT(tvMinDirN,tgCP0.Query_BasisUnit0());
tyC1 = MATH::F_DOT(tvMinDirN,tgCP0.Query_BasisUnit1());
C_(VECTOR,DIM) tvK4 = MATH::F_MUL( tyC0, tgCP0.Query_BasisUnit0() );
C_(VECTOR,DIM) tvK5 = MATH::F_MUL( tyC1, tgCP0.Query_BasisUnit1() );
tvTest = MATH::F_NORM( MATH::F_ADD( tvK4, tvK5 ) );
const TYPE tyABS_Ax_A1 = P::ABS( MATH::F_DOT(tvTest,tgCY0.Query_AxisUnit()) );
const TYPE tyAx_C10 = MATH::F_DOT(tvTest,tgCY0.Query_BasisUnit0());
const TYPE tyAx_C11 = MATH::F_DOT(tvTest,tgCY0.Query_BasisUnit1());
const TYPE tyK0 = tgCP0.Query_Radius() + tyABS_Ax_A1*tgCY0.Query_Extent();
tyTMPA = P::SQRT( tyAx_C10*tyAx_C10 + tyAx_C11*tyAx_C11 );
tyTest = P::ABS( MATH::F_DOT( tvTest, tvDS ) ) - (tyK0 + tyTMPA*tgCY0.Query_Radius());
if (tyTest > TYPE(0.0))
{
return (TgFALSE);
};
if (tyTest > ptgAxS->m_tyDepth)
{
ptgAxS->m_tvPoint = tvMin_CY0;
ptgAxS->m_tvNormal = tvTest;
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 2;
};
};
if (Near_One( tyCA1 ) || Near_Zero( tyCA1 ))
{
TYPE tyT0,tyT1, tyT2,tyT3;
T_(VECTOR,DIM) tvCI0, tvSG0;
CR_(SEGMENT,DIM) tgSG_CP0 = tgCP0.Query_Segment();
const TYPE tyDistSq = TTgCSQ_CILN<TYPE,DIM,1,1>::DO(
&tvCI0,&tvSG0, tvMin_CY0,tgCY0.Query_AxisUnit(), tgCY0.Query_Radius(), tgSG_CP0.Query_Origin(), tgSG_CP0.Query_DirN()
);
if (tyDistSq < TYPE(0.0))
{
return (TgTRUE);
};
tvTest = MATH::F_NORM( MATH::F_SUB( tvCI0, tvSG0 ) );
tgCP0.Project( &tyT0,&tyT1, tvTest );
tgCY0.Project( &tyT2,&tyT3, tvTest );
if (tyT1 - tyT2 < TYPE(0.0) || tyT3 - tyT0 < TYPE(0.0))
{
return (TgFALSE);
};
tyTest = tyT2 - tyT1;
if (tyTest > ptgAxS->m_tyDepth)
{
ptgAxS->m_tvPoint = tvCI0;
ptgAxS->m_tvNormal = tvTest;
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 3;
};
};
return (TgTRUE);
};
template TgBOOL F_Axis_Seperation( PC_TgF4AXIS_RESULT, CR_TgF4CAPSULE, CR_TgF4CYLINDER );
template <typename TYPE, int DIM>
TgRESULT F_Contact_Penetrate_CylAxis(
PC_(CONTACT_PACKET,DIM) ptgPacket, CR_(AXIS_RESULT,DIM) tgAxS, CR_(CAPSULE,DIM) tgCP0, CR_(CYLINDER,DIM) tgCY0
) {
C_(VECTOR,DIM) tvK0 = MATH::F_MUL( tgCY0.Query_Extent(), tgAxS.m_tvNormal );
C_(VECTOR,DIM) tvCYC = MATH::F_SUB( tgCY0.Query_Origin(), tvK0 );
const TYPE tyAX_N = MATH::F_DOT( tgCP0.Query_AxisUnit(), tgAxS.m_tvNormal );
C_TgINT niContact = ptgPacket->m_niContact;
P_(CONTACT,DIM) ptgContact;
T_(VECTOR,DIM) tvCPC, tvTest;
TYPE tyTest;
C_(VECTOR,DIM) tvK2 = MATH::F_MUL( P::FSEL( tyAX_N, TYPE(1.0), TYPE(-1.0) ), tgCP0.Query_HalfAxis() );
tvCPC = MATH::F_ADD( tgCP0.Query_Origin(), tvK2 );
tyTest = MATH::F_DOT( MATH::F_SUB( tvCPC, tvCYC ), tgAxS.m_tvNormal );
if (tyTest > TYPE(0.0) && tgCY0.Is_Contained( tvCPC ))
{
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
ptgContact->m_tvPos = MATH::F_ADD( tvCPC, MATH::F_MUL( tgCP0.Query_Radius(), tgAxS.m_tvNormal ) );
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tyTest;
++ptgPacket->m_niContact;
};
M_(VECTOR,DIM) tvBX0 = tgCP0.Query_BasisUnit0();
M_(VECTOR,DIM) tvBX1 = tgCP0.Query_BasisUnit1();
T_(VECTOR,DIM) tvT0, tvX0;
TYPE tyX,tyY,tyZ, tyT0,tyT1;
const TYPE tyUseBX = P::ABS( tyAX_N ) - (TYPE(1.0) - LIMITS<TYPE>::EPSILON);
tvT0 = MATH::F_SUB( tgAxS.m_tvNormal, MATH::F_MUL( tyAX_N, tgCP0.Query_AxisUnit() ) );
tyX = P::FSEL( tyUseBX, tvBX0.X(), tvT0.X() );
tyY = P::FSEL( tyUseBX, tvBX0.Y(), tvT0.Y() );
tyZ = P::FSEL( tyUseBX, tvBX0.Z(), tvT0.Z() );
tvX0 = MATH::F_NORM( MATH::F_SETV<TYPE,DIM>( tyX,tyY,tyZ ) );
T_(SEGMENT,DIM) tgCPAX = tgCP0.Query_Segment();
tgCPAX.Set_Origin( MATH::F_ADD( tgCPAX.Query_Origin(), MATH::F_MUL( tgCP0.Query_Radius(), tvX0 ) ) );
if (F_Clip( &tyT0,&tyT1, tgCY0,tgCPAX ) >= 0)
{
tvTest = MATH::F_ADD( tgCPAX.Query_Origin(), MATH::F_MUL( tyT0, tgCPAX.Query_DirN() ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvTest, tvCYC ), tgAxS.m_tvNormal );
if (tyTest > TYPE(0.0) && niContact == ptgPacket->m_niContact)
{
if (ptgPacket->m_niContact >= ptgPacket->m_niMaxContact)
{
return (TgS_MAXCONTACTS);
};
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
ptgContact->m_tvPos = tvTest;
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tyTest;
++ptgPacket->m_niContact;
};
tvTest = MATH::F_ADD( tgCPAX.Query_Origin(), MATH::F_MUL( tyT1, tgCPAX.Query_DirN() ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvTest, tvCYC ), tgAxS.m_tvNormal );
if (tyTest > TYPE(0.0) && !Near_Zero( tyT0 - tyT1 ))
{
if (ptgPacket->m_niContact >= ptgPacket->m_niMaxContact)
{
return (TgS_MAXCONTACTS);
};
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
ptgContact->m_tvPos = tvTest;
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tyTest;
++ptgPacket->m_niContact;
};
return (niContact != ptgPacket->m_niContact ? TgS_OK : TgE_NOINTERSECT);
};
C_(VECTOR,DIM) tvK1 = MATH::F_SUB( tgCP0.Query_AxisUnit(), MATH::F_MUL( tyAX_N, tgAxS.m_tvNormal ) );
tvX0 = MATH::F_NORM( MATH::F_MUL( P::FSEL( tyAX_N, TYPE(-1.0), TYPE(-1.0) ), tvK1 ) );
tvT0 = MATH::F_ADD( tvCYC, MATH::F_MUL( tgCY0.Query_Radius(), tvX0 ) );
tvTest = MATH::F_NORM( &tyTest, MATH::F_SUB( tvT0, tvCPC ) );
tyTest = MATH::F_DOT( tvTest, tgAxS.m_tvNormal ) * (tgCP0.Query_Radius() - tyTest);
if (tyTest > TYPE(0.0))
{
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
ptgContact->m_tvPos = tvT0;
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tyTest;
++ptgPacket->m_niContact;
};
tvT0 = MATH::F_SUB( tvCYC, MATH::F_MUL( tgCY0.Query_Radius(), tvX0 ) );
tvTest = MATH::F_NORM( &tyTest, MATH::F_SUB( tvT0, tvCPC ) );
tyTest = MATH::F_DOT( tvTest, tgAxS.m_tvNormal ) * (tgCP0.Query_Radius() - tyTest);
if (tyTest > TYPE(0.0))
{
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
ptgContact->m_tvPos = tvT0;
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tyTest;
++ptgPacket->m_niContact;
};
return (niContact != ptgPacket->m_niContact ? TgS_OK : TgE_NOINTERSECT);
};
template TgRESULT F_Contact_Penetrate_CylAxis( PC_TgF4CONTACT_PACKET, CR_TgF4AXIS_RESULT, CR_TgF4CAPSULE, CR_TgF4CYLINDER );
template <typename TYPE, int DIM>
TgRESULT F_Contact_Penetrate( PC_(CONTACT_PACKET,DIM) ptgPacket, CR_(CAPSULE,DIM) tgCP0, CR_(CYLINDER,DIM) tgCY0 )
{
TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_PENETRATE, (((TgUINT)ETgCAPSULE<<16)|(TgUINT)ETgCYLINDER))
TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) ))
TgASSERT(tgCY0.Is_Valid() && tgCP0.Is_Valid())
if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact)
{
return (TgE_FAIL);
};
TTgAXIS_RESULT<TYPE,DIM> tgAxS;
if (!F_Axis_Seperation( &tgAxS, tgCP0,tgCY0 ))
{
return (TgE_NOINTERSECT);
};
TgASSERT( Near_One( MATH::F_LSQ(tgAxS.m_tvNormal) ) && tgAxS.m_tyDepth >= TYPE(0.0) )
P_(CONTACT,DIM) ptgContact;
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
switch (tgAxS.m_iAxis) {
case 7:
ptgContact->m_tvPos = tgAxS.m_tvPoint;
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tgAxS.m_tyDepth;
++ptgPacket->m_niContact;
return (TgS_OK);
case 2: {
T_(VECTOR,DIM) tvTest;
TYPE tyTest;
tvTest = tgCP0.Calc_Support_Point( tgAxS.m_tvNormal );
tyTest = MATH::F_DOT( MATH::F_SUB( tvTest, tgCY0.Query_Origin() ), tgAxS.m_tvNormal ) + tgCY0.Query_Radius();
if (tyTest <= TYPE(0.0))
{
COUT_NOOBJ(
WARNING, TgT("%-16.16s(%-48.48s): [CY][CP] Algorithm: Separation Axis found with no contacts generated.\n"),
TgT("Collision"), TgT("F_Contact_Penetrate")
);;
return (TgE_NOINTERSECT);
};
ptgContact->m_tvPos = MATH::F_SUB( tvTest, MATH::F_MUL( tyTest, tgAxS.m_tvNormal ) );
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tgAxS.m_tyDepth;
++ptgPacket->m_niContact;
return (TgS_OK);
};
case 1: {
return (F_Contact_Penetrate_CylAxis( ptgPacket, tgAxS, tgCP0, tgCY0 ));
};
default:
COUT_NOOBJ(
CRITICAL, TgT("%-16.16s(%-48.48s): [CY][CP] Algorithmic - Should not be able to reach this location.\n"),
TgT("Collision"), TgT("F_Contact_Penetrate")
);
return (TgE_FAIL);
};
COUT_NOOBJ(
CRITICAL, TgT("%-16.16s(%-48.48s): [CY][CP] Algorithmic - Should not be able to reach this location.\n"), TgT("Collision"),
TgT("F_Contact_Penetrate")
);
return (TgE_FAIL);
};
template TgRESULT F_Contact_Penetrate( PC_TgF4CONTACT_PACKET, CR_TgF4CAPSULE, CR_TgF4CYLINDER );
};
};