namespace TGS {
namespace COL {
template <typename TYPE, int DIM>
TgBOOL F_Axis_Seperation( PC_(AXIS_RESULT,DIM) ptgAxS, CR_(CYLINDER,DIM) tgCY0, CR_(CYLINDER,DIM) tgCY1 )
{
TgASSERT( tgCY0.Is_Valid() && tgCY1.Is_Valid() )
TYPE tyTest;
C_(VECTOR,DIM) tvDS = MATH::F_SUB( tgCY1.Query_Origin(), tgCY0.Query_Origin() );
const TYPE tyDS_A0 = MATH::F_DOT(tvDS,tgCY0.Query_AxisUnit());
const TYPE tyDS_A1 = MATH::F_DOT(tvDS,tgCY1.Query_AxisUnit());
ptgAxS->m_tyDepth = LIMITS<TYPE>::MAX;
const TYPE tyABS_A0_A1 = P::ABS( MATH::F_DOT(tgCY0.Query_AxisUnit(),tgCY1.Query_AxisUnit()) );
const TYPE tyABS_A0xA1 = P::SQRT( TYPE(1.0) - MIN( TYPE(1.0), tyABS_A0_A1*tyABS_A0_A1 ) );
tyTest = (tgCY0.Query_Extent() + tgCY1.Query_Radius()*tyABS_A0xA1 + tgCY1.Query_Extent()*tyABS_A0_A1) - P::ABS( tyDS_A0 );
if (tyTest <= TYPE(0.0))
{
return (TgFALSE);
};
if (tyTest < ptgAxS->m_tyDepth)
{
ptgAxS->m_tvNormal = tyDS_A0 > TYPE(0.0) ? tgCY0.Query_AxisUnit() : MATH::F_NEG( tgCY0.Query_AxisUnit() );
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 0;
};
const TYPE tyRadSum = tgCY0.Query_Radius() + tgCY1.Query_Radius();
if (Near_One( tyABS_A0_A1 ) || Near_Zero( tyABS_A0xA1 ))
{
tyTest = MATH::F_LSQ( tvDS ) - tyDS_A0*tyDS_A0;
if (tyTest > tyRadSum*tyRadSum)
{
return (TgFALSE);
};
tyTest = tyRadSum - P::SQRT( tyTest );
if (tyTest < ptgAxS->m_tyDepth)
{
ptgAxS->m_tvNormal = MATH::F_SUB( tvDS, MATH::F_MUL( tyDS_A0, tgCY0.Query_AxisUnit() ) );
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 4;
MATH::F_NORM( ptgAxS->m_tvNormal );
};
return (TgTRUE);
};
tyTest = (tgCY1.Query_Extent() + tgCY0.Query_Radius()*tyABS_A0xA1 + tgCY0.Query_Extent()*tyABS_A0_A1) - P::ABS( tyDS_A1 );
if (tyTest <= TYPE(0.0))
{
return (TgFALSE);
};
if (tyTest < ptgAxS->m_tyDepth)
{
ptgAxS->m_tvNormal = tyDS_A1 > TYPE(0.0) ? MATH::F_NEG( tgCY1.Query_AxisUnit() ) : tgCY1.Query_AxisUnit();
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 2;
};
CR_(SEGMENT,DIM) tgSG_CY0 = tgCY0.Query_Segment();
CR_(SEGMENT,DIM) tgSG_CY1 = tgCY1.Query_Segment();
TYPE tyCA0,tyCA1;
TYPE tyT0,tyT1, tyT2,tyT3;
const TYPE tyDistSq = F_ClosestSq( &tyCA0,&tyCA1, tgSG_CY0, tgSG_CY1 );
if (tyDistSq > tyRadSum*tyRadSum)
{
return (TgFALSE);
};
C_(VECTOR,DIM) tvK14 = MATH::F_MUL( tyCA0, tgSG_CY0.Query_DirN() );
C_(VECTOR,DIM) tvK15 = MATH::F_MUL( tyCA1, tgSG_CY1.Query_DirN() );
C_(VECTOR,DIM) tvMin_CY0 = MATH::F_ADD( tgSG_CY0.Query_Origin(), tvK14 );
C_(VECTOR,DIM) tvMin_CY1 = MATH::F_ADD( tgSG_CY1.Query_Origin(), tvK15 );
C_(VECTOR,DIM) tvMinDist = MATH::F_SUB( tvMin_CY1, tvMin_CY0 );
C_(VECTOR,DIM) tvMinDirN = MATH::F_SUB( tvMin_CY1, tvMin_CY0 );
MATH::F_NORM( tvMinDirN );
C_TgBOOL bCapContact0 = Near_One( tyCA0 ) || Near_Zero( tyCA0 );
C_TgBOOL bCapContact1 = Near_One( tyCA1 ) || Near_Zero( tyCA1 );
if (!bCapContact0 && !bCapContact1)
{
tgCY0.Project( &tyT0,&tyT1, tvMinDirN );
tgCY1.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 = MATH::F_SUB( tvMin_CY1, MATH::F_MUL( tgCY1.Query_Radius(), tvMinDirN ) );
ptgAxS->m_tvNormal = tvMinDirN;
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 5;
};
};
if (bCapContact0)
{
const TYPE tyK00 = MATH::F_DOT( tvMinDist, tgCY0.Query_BasisUnit0() );
const TYPE tyK01 = MATH::F_DOT( tvMinDist, tgCY0.Query_BasisUnit1() );
C_(VECTOR,DIM) tvK00 = MATH::F_MUL( tyK00, tgCY0.Query_BasisUnit0() );
C_(VECTOR,DIM) tvK01 = MATH::F_MUL( tyK01, tgCY0.Query_BasisUnit1() );
C_(VECTOR,DIM) tvX00 = MATH::F_NORM( MATH::F_ADD( tvK00, tvK01 ) );
const TYPE tyABS_Ax_A1 = P::ABS( MATH::F_DOT( tvX00, tgCY1.Query_AxisUnit() ) );
const TYPE tyAx_C10 = MATH::F_DOT( tvX00, tgCY1.Query_BasisUnit0() );
const TYPE tyAx_C11 = MATH::F_DOT( tvX00, tgCY1.Query_BasisUnit1() );
const TYPE tyK02 = P::SQRT( tyAx_C10*tyAx_C10 + tyAx_C11*tyAx_C11 );
const TYPE tyK03 = tgCY0.Query_Radius() + tyABS_Ax_A1*tgCY1.Query_Extent();
const TYPE tyK04 = (tyK03 + tyK02*tgCY1.Query_Radius()) - P::ABS( MATH::F_DOT( tvX00, tvDS ) );
if (tyK04 <= TYPE(0.0))
{
return (TgFALSE);
};
if (tyK04 < ptgAxS->m_tyDepth)
{
ptgAxS->m_tvNormal = tvX00;
ptgAxS->m_tyDepth = tyK04;
ptgAxS->m_iAxis = 6;
};
};
if (bCapContact1)
{
const TYPE tyK06 = MATH::F_DOT( tvMinDist, tgCY1.Query_BasisUnit0() );
const TYPE tyK07 = MATH::F_DOT( tvMinDist, tgCY1.Query_BasisUnit1() );
C_(VECTOR,DIM) tvK06 = MATH::F_MUL( tyK06, tgCY1.Query_BasisUnit0() );
C_(VECTOR,DIM) tvK07 = MATH::F_MUL( tyK07, tgCY1.Query_BasisUnit1() );
C_(VECTOR,DIM) tvX10 = MATH::F_NORM( MATH::F_ADD( tvK06, tvK07 ) );
const TYPE tyABS_Ax_A0 = P::ABS( MATH::F_DOT( tvX10, tgCY0.Query_AxisUnit() ) );
const TYPE tyAx_C00 = MATH::F_DOT( tvX10, tgCY0.Query_BasisUnit0() );
const TYPE tyAx_C01 = MATH::F_DOT( tvX10, tgCY0.Query_BasisUnit1() );
const TYPE tyK08 = P::SQRT( tyAx_C00*tyAx_C00 + tyAx_C01*tyAx_C01 );
const TYPE tyK09 = tgCY1.Query_Radius() + tyABS_Ax_A0*tgCY0.Query_Extent();
const TYPE tyK10 = (tyK09 + tyK08*tgCY1.Query_Radius()) - P::ABS( MATH::F_DOT( tvX10, tvDS ) );
if (tyK10 <= TYPE(0.0))
{
return (TgFALSE);
};
if (tyK10 < ptgAxS->m_tyDepth)
{
ptgAxS->m_tvNormal = tvX10;
ptgAxS->m_tyDepth = tyK10;
ptgAxS->m_iAxis = 7;
};
};
if (!bCapContact0 || !bCapContact1 || MATH::F_LSQ( tvDS ) < LIMITS<TYPE>::ROOTEPSILON)
{
return (TgTRUE);
};
const TYPE tyA0_A1 = MATH::F_DOT( tgCY0.Query_AxisUnit(), tgCY1.Query_AxisUnit() );
const TYPE tyA = TYPE(1.0) - tyA0_A1*tyA0_A1;
if (tyA <= LIMITS<TYPE>::ROOTEPSILON)
{
return (TgTRUE);
};
const TYPE tyInvA = TYPE(1.0) / tyA;
const TYPE tyD_CY0 = MATH::F_DOT( tgCY0.Query_AxisUnit(), tvMin_CY0 );
const TYPE tyD_CY1 = MATH::F_DOT( tgCY1.Query_AxisUnit(), tvMin_CY1 );
tyT0 = (tyD_CY0 - tyD_CY1*tyA0_A1) * tyInvA;
tyT1 = (tyD_CY1 - tyD_CY0*tyA0_A1) * tyInvA;
T_(VECTOR,DIM) tvD0, tvTest, tvT0,tvT1;
T_(LINE,DIM) tgLN0;
tgLN0.Set_Origin( MATH::F_ADD( MATH::F_MUL( tyT0, tgCY0.Query_AxisUnit() ), MATH::F_MUL( tyT1, tgCY1.Query_AxisUnit() ) ) );
tgLN0.Set_DirN( MATH::F_CX( tgCY0.Query_AxisUnit(), tgCY1.Query_AxisUnit() ) );
F_Clip( &tyT0,&tyT1, static_cast<CR_(TUBE,DIM)>(tgCY0), tgLN0 );
tvT0 = MATH::F_ADD( tgLN0.Query_Origin(), MATH::F_MUL( tyT0, tgLN0.Query_DirN() ) );
if (MATH::F_LSQ( MATH::F_SUB( tvT0, tvMin_CY1 ) ) >= tgCY1.Query_RadiusSq())
{
tvT0 = MATH::F_ADD( tgLN0.Query_Origin(), MATH::F_MUL( tyT1, tgLN0.Query_DirN() ) );
if (MATH::F_LSQ( MATH::F_SUB( tvT0, tvMin_CY1 ) ) >= tgCY1.Query_RadiusSq())
{
COUT_NOOBJ(
WARNING, TgT("%-16.16s(%-48.48s): [CY][CY] Not 100% that this type of thing should happen - record for test case.\n"),
TgT("Collision"), TgT("F_Axis_Seperation")
);
return (TgFALSE);
};
}
else
{
tvTest = MATH::F_ADD( tgLN0.Query_Origin(), MATH::F_MUL( tyT1, tgLN0.Query_DirN() ) );
if (MATH::F_LSQ( MATH::F_SUB( tvTest, tvMin_CY1 ) ) <= tgCY1.Query_RadiusSq())
{
return (TgTRUE);
};
};
F_Clip( &tyT0,&tyT1, static_cast<CR_(TUBE,DIM)>(tgCY1), tgLN0 );
tvT1 = MATH::F_ADD( tgLN0.Query_Origin(), MATH::F_MUL( tyT0, tgLN0.Query_DirN() ) );
if (MATH::F_LSQ( MATH::F_SUB( tvT1, tvMin_CY1 ) ) >= tgCY0.Query_RadiusSq())
{
tvT1 = MATH::F_ADD( tgLN0.Query_Origin(), MATH::F_MUL( tyT1, tgLN0.Query_DirN() ) );
if (MATH::F_LSQ( MATH::F_SUB( tvT1, tvMin_CY1 ) ) >= tgCY0.Query_RadiusSq())
{
COUT_NOOBJ(
WARNING, TgT("%-16.16s(%-48.48s): [CY][CY] Not 100% that this type of thing should happen - record for test case.\n"),
TgT("Collision"), TgT("F_Axis_Seperation")
);
return (TgFALSE);
};
}
else
{
tvTest = MATH::F_ADD( tgLN0.Query_Origin(), MATH::F_MUL( tyT1, tgLN0.Query_DirN() ) );
if (MATH::F_LSQ( MATH::F_SUB( tvTest, tvMin_CY1 ) ) <= tgCY0.Query_RadiusSq())
{
return (TgTRUE);
};
};
T_(VECTOR,DIM) tvD1;
tvD0 = MATH::F_CX( MATH::F_SUB( tvT0, tvMin_CY0 ), tgCY0.Query_AxisUnit() );
tvD1 = MATH::F_CX( MATH::F_SUB( tvT0, tvMin_CY1 ), tgCY1.Query_AxisUnit() );
if (MATH::F_UCX( &tvTest, tvD0,tvD1 ) > LIMITS<TYPE>::ROOTEPSILON)
{
tgCY0.Project( &tyT0,&tyT1, tvTest );
tgCY1.Project( &tyT2,&tyT3, tvTest );
tyT1 -= tyT2;
tyT3 -= tyT0;
if (tyT1 < TYPE(0.0) || tyT3 < TYPE(0.0))
{
return (TgFALSE);
};
tyTest = -TgMIN( tyT1, tyT3 );
if (tyTest < ptgAxS->m_tyDepth)
{
ptgAxS->m_tvPoint = tvT0;
ptgAxS->m_tvNormal = MATH::F_MUL( P::FSEL( tyT1 - tyT3, TYPE(-1.0), TYPE(1.0) ), tvTest );
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 8;
};
};
tvD0 = MATH::F_CX( MATH::F_SUB( tvT1, tvMin_CY0 ), tgCY0.Query_AxisUnit() );
tvD1 = MATH::F_CX( MATH::F_SUB( tvT1, tvMin_CY1 ), tgCY1.Query_AxisUnit() );
if (MATH::F_UCX( &tvTest, tvD0,tvD1 ) > LIMITS<TYPE>::ROOTEPSILON)
{
tgCY0.Project( &tyT0,&tyT1, tvTest );
tgCY1.Project( &tyT2,&tyT3, tvTest );
tyT1 -= tyT2;
tyT3 -= tyT0;
if (tyT1 < TYPE(0.0) || tyT3 < TYPE(0.0))
{
return (TgFALSE);
};
tyTest = -TgMIN( tyT1, tyT3 );
if (tyTest < ptgAxS->m_tyDepth)
{
ptgAxS->m_tvPoint = tvT1;
ptgAxS->m_tvNormal = MATH::F_MUL( P::FSEL( tyT1 - tyT3, TYPE(-1.0), TYPE(1.0) ), tvTest );
ptgAxS->m_tyDepth = tyTest;
ptgAxS->m_iAxis = 8;
};
};
return (TgTRUE);
};
template TgBOOL F_Axis_Seperation( PC_TgF4AXIS_RESULT, CR_TgF4CYLINDER, CR_TgF4CYLINDER );
template <typename TYPE, int DIM> TgFORCEINLINE
TgRESULT F_Internal_CapCap(
T_(CONTACT,DIM) aF_Contact[4], TgUINT32& nuiPoint, M_(VECTOR,DIM) tvNormal, CR_(ELLIPSE,DIM) tgEL1, CR_(CYLINDER,DIM) tgCY0, CR_(CYLINDER,DIM) tgCY1
) {
const TYPE tyDN0 = P::FSEL( MATH::F_DOT(tvNormal,tgCY0.Query_AxisUnit()), TYPE(1.0), TYPE(-1.0) );
const TYPE tyDN1 = P::FSEL( MATH::F_DOT(tvNormal,tgCY1.Query_AxisUnit()), TYPE(-1.0), TYPE(1.0) );
C_(VECTOR,DIM) tvC0 = MATH::F_ADD( tgCY0.Query_Origin(), MATH::F_MUL( tyDN0, tgCY0.Query_HalfAxis() ) );
C_(VECTOR,DIM) tvC1 = MATH::F_ADD( tgCY1.Query_Origin(), MATH::F_MUL( tyDN1, tgCY1.Query_HalfAxis() ) );
T_(VECTOR,DIM) tvX10,tvX11, tvTest;
TYPE tyT0,tyT1, tyTest;
nuiPoint = 0;
const TYPE tyK0 = -tyDN1*MATH::F_DOT( tgCY0.Query_BasisUnit0(), tgCY1.Query_AxisUnit() );
const TYPE tyK1 = -tyDN1*MATH::F_DOT( tgCY0.Query_BasisUnit1(), tgCY1.Query_AxisUnit() );
C_(VECTOR,DIM) tvK0 = MATH::F_MUL( tyK0, tgCY0.Query_BasisUnit0() );
C_(VECTOR,DIM) tvK1 = MATH::F_MUL( tyK1, tgCY0.Query_BasisUnit1() );
tvX10 = MATH::F_NORM( &tyTest, MATH::F_ADD( tvK0, tvK1 ) );
if (tyTest <= LIMITS<TYPE>::EPSILON)
{
tvX10 = tgCY1.Query_BasisUnit0();
tvX11 = tgCY1.Query_BasisUnit1();
}
else
{
MATH::F_UCX( &tvX11, tvX10, tgCY1.Query_AxisUnit() );
MATH::F_UCX( &tvX10, tvX11, tgCY1.Query_AxisUnit() );
};
tvTest = MATH::F_MUL( tgCY1.Query_Radius(), tvX10 );
if (TTgCLP_CYLN<TYPE,DIM,1,1>::DO( &tyT0,&tyT1, tgCY0, MATH::F_SUB( tvC1, tvTest ), MATH::F_MUL( TYPE(2.0), tvTest ) ) >= 0)
{
tvTest = MATH::F_ADD( tvC1, MATH::F_MUL( TYPE(2.0)*tyT1 - TYPE(1.0), tvTest ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvC0, tvTest ), tvNormal );
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tyDepth = tyTest;
aF_Contact[nuiPoint++].m_tvPos = tvTest;
};
};
T_(VECTOR,DIM) tvT0, tvT1;
const TYPE tyABS_A0_A1 = P::ABS( MATH::F_DOT( tgCY0.Query_AxisUnit(), tgCY1.Query_AxisUnit() ) );
TgRESULT tgResult = TgE_NOINTERSECT;
if (tyABS_A0_A1 >= KF32_SQRT1_2)
{
if (Near_Zero( tgEL1.Query_Major_Radius() - tgEL1.Query_Minor_Radius() ))
{
T_(CIRCLE,DIM) tgCI0, tgCI1;
tgCI0.Set( tgCY0.Query_BasisUnit0(), tgCY0.Query_AxisUnit(), tgCY0.Query_BasisUnit1(), tvC0, tgCY0.Query_Radius() );
tgCI1.Set( tgCY1.Query_BasisUnit0(), tgCY1.Query_AxisUnit(), tgCY1.Query_BasisUnit1(), tvC1, tgCY1.Query_Radius() );
tgResult = F_Contact_Intersect2D( &tvT0,&tvT1, tgCI0,tgCI1 );
}
else
{
T_(ELLIPSE,DIM) tgEL0;
tgEL0.Set(
tvC0, tgCY0.Query_BasisUnit0(), tgCY0.Query_AxisUnit(), tgCY0.Query_BasisUnit1(),
tgCY0.Query_Radius(), tgCY0.Query_Radius()
);
tgResult = F_Contact_Intersect2D( &tvT0,&tvT1, tgEL0,tgEL1 );
};
};
if (TgE_NOINTERSECT == tgResult)
{
C_(VECTOR,DIM) tvK0 = MATH::F_ADD( tvX10, MATH::F_MUL( KF32_SQRT3, tvX11 ) );
tvTest = MATH::F_MUL( tgCY1.Query_Radius()*TYPE(-0.5), tvK0 );
if (TTgCLP_CYLN<TYPE,DIM,1,1>::DO( &tyT0,&tyT1, tgCY0, tvC1,tvTest ) >= 0)
{
tvTest = MATH::F_ADD( tvC1, MATH::F_MUL( tyT1, tvTest ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvC0, tvTest ), tvNormal );
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tyDepth = tyTest;
aF_Contact[nuiPoint++].m_tvPos = tvTest;
};
};
C_(VECTOR,DIM) tvK1 = MATH::F_SUB( tvX10, MATH::F_MUL( KF32_SQRT3, tvX11 ) );
tvTest = MATH::F_MUL( tgCY1.Query_Radius()*TYPE(-0.5), tvK1 );
if (TTgCLP_CYLN<TYPE,DIM,1,1>::DO( &tyT0,&tyT1, tgCY0, tvC1,tvTest ) >= 0)
{
tvTest = MATH::F_ADD( tvC1, MATH::F_MUL( tyT1, tvTest ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvC0, tvTest ), tvNormal );
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tyDepth = tyTest;
aF_Contact[nuiPoint++].m_tvPos = tvTest;
};
};
return (0 != nuiPoint ? TgS_OK : TgE_NOINTERSECT);
}
if (tgResult < 0)
{
TgASSERT_MSG( TgFALSE, TgT("F_Internal_CapCap: No intersection points found between the two caps.") );
return (TgE_FAIL);
};
const TYPE tyFactor = -tyDN1 / tyABS_A0_A1;
tyTest = tyFactor*(MATH::F_DOT( MATH::F_SUB( tvT0, tvC1 ), tgCY1.Query_AxisUnit() ));
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tyDepth = tyTest;
aF_Contact[nuiPoint++].m_tvPos = MATH::F_SUB( tvT0, MATH::F_MUL( tyDN0*tyTest, tgCY0.Query_AxisUnit() ) );
};
tyTest = tyFactor*(MATH::F_DOT( MATH::F_SUB( tvT1, tvC1 ), tgCY1.Query_AxisUnit() ));
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tyDepth = tyTest;
aF_Contact[nuiPoint++].m_tvPos = MATH::F_SUB( tvT1, MATH::F_MUL( tyDN0*tyTest, tgCY0.Query_AxisUnit() ) );
};
tvTest = MATH::F_NORM( MATH::F_SUB( MATH::F_MUL( TYPE(0.5), MATH::F_ADD( tvT0, tvT1 ) ), tvC1 ) );
tvTest = MATH::F_ADD( MATH::F_MUL( tvTest, tgCY1.Query_Radius() ), tvC1 );
tyTest = MATH::F_DOT( MATH::F_SUB( tvTest, tvC1 ), tgCY1.Query_AxisUnit() )*tyFactor;
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tyDepth = tyTest;
aF_Contact[nuiPoint++].m_tvPos = MATH::F_SUB( tvTest, MATH::F_MUL( tyDN0*tyTest, tgCY0.Query_AxisUnit() ) );
};
return (TgS_OK);
};
template <typename TYPE, int DIM> TgFORCEINLINE
TgRESULT F_Internal_CapContained(
T_(CONTACT,DIM) aF_Contact[4], TgUINT32 &nuiPoint, M_(VECTOR,DIM) tvNormal, CR_(CYLINDER,DIM) tgCY0, CR_(CYLINDER,DIM) tgCY1
) {
const TYPE tyDN0 = P::FSEL( MATH::F_DOT(tvNormal,tgCY0.Query_AxisUnit()), TYPE(1.0), TYPE(-1.0) );
const TYPE tyDN1 = P::FSEL( MATH::F_DOT(tvNormal,tgCY1.Query_AxisUnit()), TYPE(-1.0), TYPE(1.0) );
C_(VECTOR,DIM) tvC0 = MATH::F_ADD( tgCY0.Query_Origin(), MATH::F_MUL( tyDN0, tgCY0.Query_HalfAxis() ) );
C_(VECTOR,DIM) tvC1 = MATH::F_ADD( tgCY1.Query_Origin(), MATH::F_MUL( tyDN1, tgCY1.Query_HalfAxis() ) );
T_(VECTOR,DIM) tvX10,tvX11, tvTest;
TYPE tyTest;
const TYPE tyK0 = -tyDN1*MATH::F_DOT( tgCY0.Query_BasisUnit0(), tgCY1.Query_AxisUnit() );
const TYPE tyK1 = -tyDN1*MATH::F_DOT( tgCY0.Query_BasisUnit1(), tgCY1.Query_AxisUnit() );
C_(VECTOR,DIM) tvK0 = MATH::F_MUL( tyK0, tgCY0.Query_BasisUnit0() );
C_(VECTOR,DIM) tvK1 = MATH::F_MUL( tyK1, tgCY0.Query_BasisUnit1() );
tvX10 = MATH::F_NORM( &tyTest, MATH::F_ADD( tvK0, tvK1 ) );
if (tyTest <= LIMITS<TYPE>::EPSILON)
{
tvX10 = tgCY1.Query_BasisUnit0();
tvX11 = tgCY1.Query_BasisUnit1();
}
else
{
MATH::F_UCX( &tvX11, tvX10, tgCY1.Query_AxisUnit() );
};
tvTest = MATH::F_ADD( tvC1, MATH::F_MUL( tgCY1.Query_Radius(), tvX10 ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvC0, tvTest ), tvNormal );
if (tyTest < TYPE(0.0))
{
TgASSERT_MSG( TgFALSE, TgT("F_Internal_CapContained: Axis determined a fully contained cylinder but found no contacts.") );
return (TgE_FAIL);
};
aF_Contact[0].m_tyDepth = tyTest;
aF_Contact[0].m_tvPos = tvTest;
nuiPoint = 1;
C_(VECTOR,DIM) tvK2 = MATH::F_ADD( tvX10, MATH::F_MUL( KF32_SQRT3, tvX11 ) );
tvTest = MATH::F_ADD( tvC1, MATH::F_MUL( tgCY1.Query_Radius()*TYPE(-0.5), tvK2 ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvC0, tvTest ), tvNormal );
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tvPos = tvTest;
aF_Contact[nuiPoint].m_tyDepth = tyTest;
++nuiPoint;
};
C_(VECTOR,DIM) tvK3 = MATH::F_SUB( tvX10, MATH::F_MUL( KF32_SQRT3, tvX11 ) );
tvTest = MATH::F_ADD( tvC1, MATH::F_MUL( tgCY1.Query_Radius()*TYPE(-0.5), tvK3 ) );
tyTest = MATH::F_DOT( MATH::F_SUB( tvC0, tvTest ), tvNormal );
if (tyTest > TYPE(0.0))
{
aF_Contact[nuiPoint].m_tvPos = tvTest;
aF_Contact[nuiPoint].m_tyDepth = tyTest;
++nuiPoint;
};
return (TgS_OK);
};
template <typename TYPE, int DIM> TgFORCEINLINE
TgRESULT F_Internal_AxisCap(
T_(CONTACT,DIM) aF_Contact[4], TgUINT32 &nuiPoint, C_(VECTOR,DIM) tvNormal, CR_(CYLINDER,DIM) tgCY0, CR_(CYLINDER,DIM) tgCY1
) {
const TYPE tyDN0 = P::FSEL( MATH::F_DOT(tvNormal,tgCY0.Query_AxisUnit()), TYPE(-1.0), TYPE(1.0) );
const TYPE tyDN1 = P::FSEL( MATH::F_DOT(tvNormal,tgCY1.Query_AxisUnit()), TYPE(1.0), TYPE(-1.0) );
C_(VECTOR,DIM) tvC0 = MATH::F_ADD( tgCY0.Query_Origin(), MATH::F_MUL( tyDN0, tgCY0.Query_HalfAxis() ) );
C_(VECTOR,DIM) tvC1 = MATH::F_ADD( tgCY1.Query_Origin(), MATH::F_MUL( tyDN1, tgCY1.Query_HalfAxis() ) );
CR_(SEGMENT,DIM) tgSG_CY0 = tgCY0.Query_Segment();
T_(VECTOR,DIM) tvX10,tvX11;
TYPE tyT0,tyT1;
const TYPE tyK0 = -tyDN1*MATH::F_DOT( tgCY0.Query_BasisUnit0(), tgCY1.Query_AxisUnit() );
const TYPE tyK1 = -tyDN1*MATH::F_DOT( tgCY0.Query_BasisUnit1(), tgCY1.Query_AxisUnit() );
C_(VECTOR,DIM) tvK0 = MATH::F_MUL( tyK0, tgCY0.Query_BasisUnit0() );
C_(VECTOR,DIM) tvK1 = MATH::F_MUL( tyK1, tgCY0.Query_BasisUnit1() );
tvX10 = MATH::F_NORM( MATH::F_ADD( tvK0, tvK1 ) );
MATH::F_UCX( &tvX11, tvX10, tgCY0.Query_AxisUnit() );
TgASSERT_MSG( Near_One( MATH::F_LSQ( tvX10 ) ), TgT("F_Internal_AxisCap: Degenerate basis set formed.") );
T_(VECTOR,DIM) tvS0 = MATH::F_ADD( tgSG_CY0.Query_Origin(), MATH::F_MUL( tgCY0.Query_Radius(), tvX10 ) );
T_(VECTOR,DIM) tvD0 = tgSG_CY0.Query_DirN();
if (TTgCLP_TULN<TYPE,DIM,1,1>::DO( &tyT0,&tyT1, static_cast<CR_(TUBE,DIM)>(tgCY1), tvS0, tvD0 ) < 0)
{
return (TgE_NOINTERSECT);
};
T_(PLANE,DIM) tgPN0;
tgPN0.Set( tvNormal, tvC1 );
tvS0 = MATH::F_MUL( tvS0, tyT0 );
tvD0 = MATH::F_MUL( tvD0, tyT1 - tyT0 );
if (TTgCLP_PNLN<TYPE,DIM,1,1>::DO( &tyT0,&tyT1, tgPN0, tvS0, tvD0 ) < 0)
{
return (TgE_NOINTERSECT);
};
TYPE tyDH0, tyDH1;
T_(VECTOR,DIM) tvT0, tvT1;
tvT0 = MATH::F_ADD( tvS0, MATH::F_MUL( tyT0, tgSG_CY0.Query_DirN() ) );
tyDH0 = MATH::F_DOT( MATH::F_SUB( tvT0, tvC1 ), tvNormal );
tvT1 = MATH::F_ADD( tvS0, MATH::F_MUL( tyT1, tgSG_CY0.Query_DirN() ) );
tyDH1 = MATH::F_DOT( MATH::F_SUB( tvT1, tvC1 ), tvNormal );
aF_Contact[0].m_tvPos = tyDH0 - tyDH1 > TYPE(0.0) ? tvT0 : tvT1;
aF_Contact[0].m_tyDepth = P::FSEL( tyDH0 - tyDH1, tyDH0, tyDH1 );
aF_Contact[1].m_tvPos = tyDH0 - tyDH1 > TYPE(0.0) ? tvT1 : tvT0;
aF_Contact[1].m_tyDepth = P::FSEL( tyDH0 - tyDH1, tyDH1, tyDH0 );
nuiPoint = !Near_Zero( tyT0 - tyT1 ) && ((tyT0 - TYPE(0.5) < TYPE(0.0)) ^ (tyT1 - TYPE(0.5) < TYPE(0.0))) ? 2 : 1;
return (TgS_OK);
};
template <typename TYPE, int DIM>
TgRESULT F_Contact_Penetrate( PC_(CONTACT_PACKET,DIM) ptgPacket, CR_(CYLINDER,DIM) tgCY0, CR_(CYLINDER,DIM) tgCY1 )
{
TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) ))
TgASSERT(tgCY0.Is_Valid() && tgCY1.Is_Valid())
if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact)
{
return (TgE_FAIL);
};
T_(AXIS_RESULT,DIM) tgAxS;
if (!F_Axis_Seperation( &tgAxS, tgCY0,tgCY1 ))
{
return (TgE_NOINTERSECT);
};
TgASSERT( Near_One( MATH::F_LSQ(tgAxS.m_tvNormal) ) && tgAxS.m_tyDepth >= TYPE(0.0) )
P_(CONTACT,DIM) ptgContact;
T_(CONTACT,DIM) aF_Contact[4];
TgUINT32 nuiPoint = 0;
C_(VECTOR,DIM) tvDS = MATH::F_SUB( tgCY1.Query_Origin(), tgCY0.Query_Origin() );
const TYPE tyDS_A0 = MATH::F_DOT(tvDS,tgCY0.Query_AxisUnit());
const TYPE tyDS_A1 = MATH::F_DOT(tvDS,tgCY1.Query_AxisUnit());
switch (tgAxS.m_iAxis)
{
case 0: {
T_(ELLIPSE,DIM) tgEL1;
if (Is_Cap_Contained( tgEL1, tgCY0,tyDS_A0,tgCY1,tyDS_A1 ))
{
if (P::ABS( MATH::F_DOT(tgCY0.Query_AxisUnit(),tgCY1.Query_AxisUnit()) ) < KF32_SQRT1_2)
{
if (F_Internal_AxisCap( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgCY0,tgCY1 ) >= 0)
{
break;
};
}
else if (F_Internal_CapContained( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgCY0,tgCY1 ) >= 0)
{
break;
};
}
else
{
if (P::ABS( MATH::F_DOT(tgCY0.Query_AxisUnit(),tgCY1.Query_AxisUnit()) ) < KF32_SQRT1_2)
{
if (F_Internal_AxisCap( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgCY0, tgCY1 ) >= 0)
{
break;
};
}
else if (F_Internal_CapCap( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgEL1, tgCY0,tgCY1 ) >= 0)
{
break;
};
};
return (TgE_NOINTERSECT);
};
case 2: {
T_(ELLIPSE,DIM) tgEL0;
if (Is_Cap_Contained( tgEL0, tgCY1,-tyDS_A1,tgCY0,-tyDS_A0 ))
{
if (P::ABS( MATH::F_DOT(tgCY0.Query_AxisUnit(),tgCY1.Query_AxisUnit()) ) < KF32_SQRT1_2)
{
C_TgRESULT tgResult = F_Internal_AxisCap( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgCY1,tgCY0 );
if (tgResult >= 0)
{
for (TgUINT32 uiIndex = 0; uiIndex < nuiPoint; ++uiIndex)
{
C_(VECTOR,DIM) tvK20 = MATH::F_MUL( aF_Contact[uiIndex].m_tyDepth, tgAxS.m_tvNormal );
aF_Contact[uiIndex].m_tvPos = MATH::F_SUB( aF_Contact[uiIndex].m_tvPos, tvK20 );
};
break;
};
}
else
{
C_TgRESULT tgResult = F_Internal_CapContained( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgCY1,tgCY0 );
if (tgResult >= 0)
{
for (TgUINT32 uiIndex = 0; uiIndex < nuiPoint; ++uiIndex)
{
C_(VECTOR,DIM) tvK21 = MATH::F_MUL( aF_Contact[uiIndex].m_tyDepth, tgAxS.m_tvNormal );
aF_Contact[uiIndex].m_tvPos = MATH::F_ADD( aF_Contact[uiIndex].m_tvPos, tvK21 );
};
tgAxS.m_tvNormal = MATH::F_NEG( tgAxS.m_tvNormal );
break;
};
};
}
else
{
if (P::ABS( MATH::F_DOT(tgCY0.Query_AxisUnit(),tgCY1.Query_AxisUnit()) ) < KF32_SQRT1_2)
{
C_TgRESULT tgResult = F_Internal_AxisCap( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgCY0,tgCY1 );
if (tgResult >= 0)
{
for (TgUINT32 uiIndex = 0; uiIndex < nuiPoint; ++uiIndex)
{
C_(VECTOR,DIM) tvK22 = MATH::F_MUL( aF_Contact[uiIndex].m_tyDepth, tgAxS.m_tvNormal );
aF_Contact[uiIndex].m_tvPos = MATH::F_SUB( aF_Contact[uiIndex].m_tvPos, tvK22 );
};
break;
};
}
C_TgRESULT tgResult = F_Internal_CapCap( aF_Contact, nuiPoint, tgAxS.m_tvNormal, tgEL0, tgCY0,tgCY1 );
if (tgResult >= 0)
{
for (TgUINT32 uiIndex = 0; uiIndex < nuiPoint; ++uiIndex)
{
C_(VECTOR,DIM) tvK23 = MATH::F_MUL( aF_Contact[uiIndex].m_tyDepth, tgAxS.m_tvNormal );
aF_Contact[uiIndex].m_tvPos = MATH::F_SUB( aF_Contact[uiIndex].m_tvPos, tvK23 );
};
break;
};
};
return (TgE_NOINTERSECT);
};
case 4: {
C_(VECTOR,DIM) tvDS = MATH::F_SUB( tgCY0.Query_Origin(), tgCY1.Query_Origin() );
const TYPE tyDS_A1 = MATH::F_DOT( tvDS, tgCY1.Query_AxisUnit() );
const TYPE tyMinY = TgMAX( -tgCY1.Query_Extent(), tyDS_A1 - tgCY0.Query_Extent() );
const TYPE tyMaxY = TgMIN( tgCY1.Query_Extent(), tyDS_A1 + tgCY0.Query_Extent() );
P_(CONTACT,DIM) ptgContact;
if (!Near_Zero(tyMinY - tyMaxY))
{
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
C_(VECTOR,DIM) tvK30 = MATH::F_MUL( tyMinY, tgCY1.Query_AxisUnit() );
C_(VECTOR,DIM) tvK31 = MATH::F_MUL( tgCY1.Query_Radius(), tgAxS.m_tvNormal );
ptgContact->m_tvPos = MATH::F_SUB( MATH::F_ADD( tgCY1.Query_Origin(), tvK30 ), tvK31 );
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tgAxS.m_tyDepth;
++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);
C_(VECTOR,DIM) tvK32 = MATH::F_MUL( tyMaxY, tgCY1.Query_AxisUnit() );
C_(VECTOR,DIM) tvK33 = MATH::F_MUL( tgCY1.Query_Radius(), tgAxS.m_tvNormal );
ptgContact->m_tvPos = MATH::F_SUB( MATH::F_ADD( tgCY1.Query_Origin(), tvK32 ), tvK33 );
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 8:
case 5: {
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
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 6: {
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
ptgContact->m_tvPos = tgCY1.Calc_Support_Point( MATH::F_NEG( 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 7: {
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
C_(VECTOR,DIM) tvK34 = MATH::F_MUL( tgAxS.m_tyDepth, tgAxS.m_tvNormal );
ptgContact->m_tvPos = MATH::F_SUB( tgCY0.Calc_Support_Point( tgAxS.m_tvNormal ), tvK34 );
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = tgAxS.m_tyDepth;
++ptgPacket->m_niContact;
return (TgS_OK);
};
};
C_TgUINT32 nuiMax = TgMIN(nuiPoint,(TgUINT32)(ptgPacket->m_niMaxContact - ptgPacket->m_niContact));
for (TgUINT32 iIdx = 0; iIdx < nuiMax; ++iIdx)
{
ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride);
ptgContact->m_tvPos = aF_Contact[iIdx].m_tvPos;
ptgContact->m_tvNormal = tgAxS.m_tvNormal;
ptgContact->m_tyT0 = TYPE(0.0);
ptgContact->m_tyDepth = aF_Contact[iIdx].m_tyDepth;
++ptgPacket->m_niContact;
};
return (nuiMax != nuiPoint ? TgS_MAXCONTACTS : TgS_OK);
};
template TgRESULT F_Contact_Penetrate( PC_TgF4CONTACT_PACKET, CR_TgF4CYLINDER, CR_TgF4CYLINDER );
};
};