Home

Resume

Blog

Teikitu


// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Teikitu Gaming System (TgS) (∂)
//  »File«      TgS Common - Geometry 3D - Cylinder.inl
//  »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
//  »Version«   4.0
// ------------------------------------------------------------------------------------------------------------------------------ //
//  Copyright: © 2002-2010, Andrew Aye.  All Rights Reserved.
//  This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met: 
//    Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. 
//    Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following
//      disclaimers in the documentation and other materials provided with the distribution. 
//  Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived
//  from this software without specific prior written permission. 
//  The intellectual property rights of the algorithms used reside with Andrew Aye.  You may not use this software, in whole or
//  in part, in support of any commercial product without the express written consent of the author.
//  There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //

V(TgVEC) V(tgGM_Support_Point_CY)( V(CPCU_TgTUBE) ptgCY0, V(CPCU_TgVEC) ptvDirN )
{
    const TYPE                          tyUAX_N = V(F_DOT_VV)( ptvDirN, &ptgCY0->m.m.vU_HAX );
    V(TgVEC)                            tvResult;
    TYPE                                fTest;

    TgASSERT( F(tgCM_NR1)( V(F_LSQ)( ptvDirN ) ) && V(F_Is_Vector_Valid)( ptvDirN ) );

    if (tyUAX_N > F(KTgEPS))
    {
        tvResult = V(F_ADD_VV)( &ptgCY0->m.m.vOrigin, &ptgCY0->m_vHAX );
    }
    else if (tyUAX_N < -F(KTgEPS))
    {
        tvResult = V(F_SUB_VV)( &ptgCY0->m.m.vOrigin, &ptgCY0->m_vHAX );
    }
    else
    {
        tvResult = ptgCY0->m.m.vOrigin;
    }

    {
        V(C_TgVEC)                          tvX0 = V(F_MUL_SV)( tyUAX_N, &ptgCY0->m.m.vU_HAX );
        V(C_TgVEC)                          tvX1 = V(F_SUB_VV)( ptvDirN, &tvX0 );
        V(C_TgVEC)                          tvRadial = V(F_NORM_LEN)( &fTest, &tvX1 );

        if (fTest > F(KTgEPS))
        {
            tvResult = V(F_MAD_SVV)( ptgCY0->m_fRadius, &tvRadial, &tvResult );
        };
    }

    return (tvResult);
}


TgBOOL V(tgGM_Is_Cap_Contained_CY)(
    V(PCU_TgELLIPSE) ptgEL0, V(CPCU_TgTUBE) ptgCY0, const TYPE tyDS_C0A, V(CPCU_TgTUBE) ptgCY1, const TYPE tyDS_C1A
) {
    // Containment Test - the projection of the cap of cylinder 1 onto the cap of cylinder 0

    V(C_TgVEC)                          tvX0 = V(F_MUL_SV)( ptgCY0->m.m.vU_HAX.m.x, &ptgCY0->m.m.vU_HAX );
    V(C_TgVEC)                          tvX1 = V(F_MUL_SV)( ptgCY0->m.m.vU_HAX.m.y, &ptgCY0->m.m.vU_HAX );
    V(C_TgVEC)                          tvX2 = V(F_MUL_SV)( ptgCY0->m.m.vU_HAX.m.z, &ptgCY0->m.m.vU_HAX );
    V(C_TgVEC)                          tvXF0 = V(F_SUB_VV)( &(V(KTgV_UNIT_X)), &tvX0 );
    V(C_TgVEC)                          tvXF1 = V(F_SUB_VV)( &(V(KTgV_UNIT_Y)), &tvX1 );
    V(C_TgVEC)                          tvXF2 = V(F_SUB_VV)( &(V(KTgV_UNIT_Z)), &tvX2 );

    // Transform the centre of the caps of closest proximity

    V(C_TgVEC)                          tvB0 = V(F_MUL_SV)( F(tgPM_FSEL)(tyDS_C0A, MKL(1.0), MKL(-1.0)), &ptgCY0->m_vHAX );
    V(C_TgVEC)                          tvB1 = V(F_MUL_SV)( F(tgPM_FSEL)(tyDS_C1A, MKL(-1.0), MKL(1.0)), &ptgCY1->m_vHAX );
    V(C_TgVEC)                          tvW0 = V(F_ADD_VV)( &ptgCY0->m.m.vOrigin, &tvB0 );
    V(C_TgVEC)                          tvW1 = V(F_ADD_VV)( &ptgCY1->m.m.vOrigin, &tvB1 );
    const TYPE                          tyA0 = V(F_DOT_VV)( &tvXF0, &tvW0 );
    const TYPE                          tyA1 = V(F_DOT_VV)( &tvXF1, &tvW0 );
    const TYPE                          tyA2 = V(F_DOT_VV)( &tvXF2, &tvW0 );
    const TYPE                          tyB0 = V(F_DOT_VV)( &tvXF0, &tvW1 );
    const TYPE                          tyB1 = V(F_DOT_VV)( &tvXF1, &tvW1 );
    const TYPE                          tyB2 = V(F_DOT_VV)( &tvXF2, &tvW1 );
    V(C_TgVEC)                          tvW2 = V(F_SETP_ELEM)( tyA0, tyA1, tyA2 );
    V(C_TgVEC)                          tvW3 = V(F_SETP_ELEM)( tyB0, tyB1, tyB2 );
    const TYPE                          tyU0 = V(F_DOT_VV)( &tvXF0, &ptgCY1->m.m.vU_HAX );
    const TYPE                          tyU1 = V(F_DOT_VV)( &tvXF1, &ptgCY1->m.m.vU_HAX );
    const TYPE                          tyU2 = V(F_DOT_VV)( &tvXF2, &ptgCY1->m.m.vU_HAX );

    V(TgVEC)                            tvA0, tvA1;
    V(TgVEC)                            tvAxis;
    TYPE                                tyRadiusRatio;

    // Ellipse Axes

    tvAxis = V(F_SETV_ELEM)( tyU0, tyU1, tyU2 );

    if (V(F_LSQ)( &tvAxis ) > F(KTgEPS))
    {
        tvA0 = V(F_UCX)( &tvAxis, &ptgCY0->m.m.vU_HAX );
        tvAxis = V(F_CX)( &ptgCY1->m.m.vU_HAX, &tvA0 );
        tvA1 = V(F_SETV_ELEM)( V(F_DOT_VV)(&tvXF0, &tvAxis), V(F_DOT_VV)(&tvXF1, &tvAxis), V(F_DOT_VV)(&tvXF2, &tvAxis) );
    }
    else
    {
        tvA0 = ptgCY0->m.m.vU_Basis0;
        tvA1 = ptgCY0->m.m.vU_Basis1;
    };

    tvA1 = V(F_NORM_LEN)( &tyRadiusRatio, &tvA1 );

    {
        const TYPE                          tyMajRad = tyRadiusRatio*ptgCY1->m_fRadius;
        const TYPE                          tyA00 = V(F_DOT_VV)( &tvA0, &ptgCY0->m.m.vU_Basis0 );
        const TYPE                          tyA01 = V(F_DOT_VV)( &tvA0, &ptgCY0->m.m.vU_Basis1 );
        const TYPE                          tyA10 = V(F_DOT_VV)( &tvA1, &ptgCY0->m.m.vU_Basis0 );
        const TYPE                          tyA11 = V(F_DOT_VV)( &tvA1, &ptgCY0->m.m.vU_Basis1 );
        const TYPE                          tyR00 = tyA00 * ptgCY1->m_fRadius;
        const TYPE                          tyR01 = tyA01 * ptgCY1->m_fRadius;
        const TYPE                          tyR10 = tyA10 * tyMajRad;
        const TYPE                          tyR11 = tyA11 * tyMajRad;
        V(C_TgVEC)                          tvW32 = V(F_SUB_VV)( &tvW3, &tvW2 );
        const TYPE                          tyWC0 = V(F_DOT_VV)( &tvW32, &ptgCY0->m.m.vU_Basis0 );
        const TYPE                          tyWC1 = V(F_DOT_VV)( &tvW32, &ptgCY0->m.m.vU_Basis1 );

        // Initialize the resulting ellipse formed by the projection

        V(tgGM_Set_Origin_EL)( ptgEL0, &tvW3 ); // ptgEllipse->Get_Origin().Set( tvW3*ptgCY0->m.m.vU_Basis0, tvW3*ptgCY0->m.m.vU_Basis1 );
        V(tgGM_Set_Minor_Unit_EL)( ptgEL0, &tvA0 ); // ptgEllipse->Get_Minor_Axis().Set( tyA00, tyA01 );
        V(tgGM_Set_Normal_EL)( ptgEL0, &ptgCY0->m.m.vU_HAX );
        V(tgGM_Set_Major_Unit_EL)( ptgEL0, &tvA1 ); // ptgEllipse->Get_Major_Axis().Set( tyA10, tyA11 );
        V(tgGM_Set_Minor_Radius_EL)( ptgEL0, ptgCY1->m_fRadius );
        V(tgGM_Set_Major_Radius_EL)( ptgEL0, tyMajRad );

        if (
            (tyWC0 + tyR00)*(tyWC0 + tyR00) + (tyWC1 + tyR01)*(tyWC1 + tyR01) > ptgCY0->m_fRadiusSq ||
            (tyWC0 - tyR00)*(tyWC0 - tyR00) + (tyWC1 - tyR01)*(tyWC1 - tyR01) > ptgCY0->m_fRadiusSq ||
            (tyWC0 + tyR10)*(tyWC0 + tyR10) + (tyWC1 + tyR11)*(tyWC1 + tyR11) > ptgCY0->m_fRadiusSq || 
            (tyWC0 - tyR10)*(tyWC0 - tyR10) + (tyWC1 - tyR11)*(tyWC1 - tyR11) > ptgCY0->m_fRadiusSq
        ) {
            return (TgFALSE);
        };
    };

    return (TgTRUE);
}