Home

Resume

Blog

Teikitu


// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Teikitu Gaming System (TgS) (∂)
//  »File«      TgS Collision - F - Rectangle-Linear.c_inc
//  »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
//  »Version«   4.0
//  »Keywords«  Collision;Distance;Closest;Intersect;Penetrate;Sweep;Rectangle;Line;Ray;Segment;
// ------------------------------------------------------------------------------------------------------------------------------ //
//  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".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
// == Collision ================================================================================================================= //

// ---- tgCO_FI_ParamSq_RT_LR --------------------------------------------------------------------------------------------------- //
// Input:  psRT0: Rectangle primitive
// Input:  vS0,vD0: Origin and Direction for the Linear
// Output: _fRT0, _fRT1: Parametric parameters to generate point of minimal distance on the rectangle
// Output: _tyLN0: Parametric parameter to generate point of minimal distance on the linear
// Return: Minimal distance between the two primitives or negative type max if they intersect or are invalid.
// ------------------------------------------------------------------------------------------------------------------------------ //
TYPE  VI(tgCO_FI_ParamSq_RT_LR)(
    PCU_TYPE pfRT0, PCU_TYPE pfRT1, PCU_TYPE pfLN0, V(CPCU_TgRECTANGLE) psRT0, V(CPCU_TgVEC) pvS0, V(CPCU_TgVEC) pvD0 )
{
    V(C_TgVEC)                          vX0 = V(F_SUB_VV)( pvS0, &psRT0->m_vOrigin );
    const TYPE                          fX0_X0 = V(F_LSQ)( &vX0 );

    TgASSERT( V(tgGM_Is_Valid_RT)( psRT0 ) && V(F_Is_Point_Valid)( pvS0 ) && V(F_Is_Vector_Valid)( pvD0 ) );

    if (fX0_X0 <= F(KTgEPS))
    {
        // Quick Out - the point is within tolerance of rectangle origin.

        *pfRT0 = MKL(0.0);
        *pfRT1 = MKL(0.0);
        *pfLN0 = MKL(0.0);

        return (-F(KTgMAX));
    }
    else
    {
        const TYPE                          fE0_E0 = V(F_LSQ)( psRT0->m_avEdge + 0 );
        const TYPE                          fE1_E1 = V(F_LSQ)( psRT0->m_avEdge + 1 );
        const TYPE                          fD1_N = V(F_DOT_VV)( pvD0, &psRT0->m_vNormal );
        const TYPE                          fX0_N = V(F_DOT_VV)( &vX0, &psRT0->m_vNormal );

        if (fE0_E0 <= F(KTgEPS) || fE1_E1 <= F(KTgEPS))
        {
            // Degenerate rectangle - One or both of the edges has a near-zero length
            return (-F(KTgMAX));
        }
        else if (F(tgPM_ABS)( fD1_N ) > F(KTgEPS))
        {
            // Non-trivial plane normal-component in the linear direction.  Check the intersection of the two primitives.

            const TYPE                          fInt = -(fX0_N / fD1_N);

            if ((!LN_CAP_0 || fInt >= MKL(0.0)) && (!LN_CAP_1 || fInt <= MKL(1.0)))
            {
                V(C_TgVEC)                          vK1 = V(F_MUL_SV)( fInt, pvD0 );
                V(C_TgVEC)                          vK0 = V(F_ADD_VV)( &vX0, &vK1 );

                const TYPE                          fINT_EN0 = V(F_DOT_VV)( psRT0->m_avEdge + 1, &vK0 );
                const TYPE                          fINT_EN1 = V(F_DOT_VV)( psRT0->m_avEdge + 0, &vK0 );

                if (fINT_EN0 >= MKL(0.0) && fINT_EN0 <= fE1_E1 && fINT_EN1 >= MKL(0.0) && fINT_EN1 <= fE0_E0)
                {
                    *pfRT0 = fINT_EN1 / fE0_E0;
                    *pfRT1 = fINT_EN0 / fE1_E1;
                    *pfLN0 = fInt;

                    return (-F(KTgMAX));
                };
            };
        };

        {
            V(C_TgVEC)                          vK0 = V(F_SUB_VV)( pvS0, &psRT0->m_vOrigin );
            V(C_TgVEC)                          vX1 = V(F_ADD_VV)( &vK0, pvD0 );

            const TYPE                          f00 = V(F_DOT_VV)( psRT0->m_avEdge + 1, &vX0 );
            const TYPE                          f01 = V(F_DOT_VV)( psRT0->m_avEdge + 0, &vX0 );
            const TYPE                          f10 = V(F_DOT_VV)( psRT0->m_avEdge + 1, LN_CAP_1 ? &vX1 : pvD0 );
            const TYPE                          f11 = V(F_DOT_VV)( psRT0->m_avEdge + 0, LN_CAP_1 ? &vX1 : pvD0 );

            TgSINT32                            iTest = 0;

            C_TgBOOL                            bK0 = LN_CAP_0 ? (f00 < F(KTgEPS)) : (f10 > F(KTgEPS));
            C_TgBOOL                            bK1 = LN_CAP_1 ? (f10 < F(KTgEPS)) : (f10 < -F(KTgEPS));
            C_TgBOOL                            bK2 = LN_CAP_0 ? (f01 < F(KTgEPS)) : (f11 > F(KTgEPS));
            C_TgBOOL                            bK3 = LN_CAP_1 ? (f11 < F(KTgEPS)) : (f11 < -F(KTgEPS));
            C_TgBOOL                            bK4 = LN_CAP_0 ? (fE1_E1 - f00 < F(KTgEPS)) : (f10 < -F(KTgEPS));
            C_TgBOOL                            bK5 = LN_CAP_1 ? (fE1_E1 - f10 < F(KTgEPS)) : (f10 > F(KTgEPS));
            C_TgBOOL                            bK6 = LN_CAP_0 ? (fE0_E0 - f01 < F(KTgEPS)) : (f11 < -F(KTgEPS));
            C_TgBOOL                            bK7 = LN_CAP_1 ? (fE0_E0 - f11 < F(KTgEPS)) : (f11 > F(KTgEPS));
            C_TgBOOL                            bK8 = LN_CAP_0 && f00 >= MKL(0.0) && f01 >= MKL(0.0) && f00 <= fE1_E1 && f01 <= fE0_E0;
            C_TgBOOL                            bK9 = LN_CAP_1 && f10 >= MKL(0.0) && f11 >= MKL(0.0) && f10 <= fE1_E1 && f11 <= fE0_E0;

            TYPE                                fRT0 = MKL(0.0), fRT1 = MKL(0.0), fG1 = MKL(0.0), fT0 = MKL(0.0), fT1 = MKL(0.0);
            TYPE                                fTest = MKL(0.0), fDistSq = F(KTgMAX);

            iTest |= bK0 ? (1 << 0) : 0;
            iTest |= bK1 ? (1 << 0) : 0;
            iTest |= bK2 ? (1 << 1) : 0;
            iTest |= bK3 ? (1 << 1) : 0;
            iTest |= bK4 ? (1 << 2) : 0;
            iTest |= bK5 ? (1 << 2) : 0;
            iTest |= bK6 ? (1 << 3) : 0;
            iTest |= bK7 ? (1 << 3) : 0;
            iTest |= bK8 ? (1 << 4) : 0;
            iTest |= bK9 ? (1 << 5) : 0;

            // Distance calculation for the linear's origin if its capped and within the rectangle's normal-extruded space.

            if (iTest & (1 << 4))
            {
                fDistSq = fX0_N * fX0_N;
                fRT0 = f01 / fE0_E0;
                fRT1 = f00 / fE1_E1;
                fG1 = MKL(0.0);
            };

            // Distance calculation for the linear's termination if its capped and within the rectangle's normal-extruded space.

            if (iTest & (1 << 5))
            {
                const TYPE                          fX1_N = V(F_DOT_VV)( &vX1, &psRT0->m_vNormal );

                fTest = fX1_N * fX1_N;
                if (fTest < fDistSq)
                {
                    fDistSq = fTest;
                    fRT0 = f11 / fE0_E0;
                    fRT1 = f10 / fE1_E1;
                    fG1 = MKL(1.0);
                };

                // Check to see if the segment is fully contained within the extruded rectangle space.
                if (iTest & (1 << 4))
                {
                    *pfRT0 = fRT0;
                    *pfRT1 = fRT1;
                    *pfLN0 = fG1;

                    return (fDistSq);
                };
            };

            // Compare the segment against the four rectangle edges.

            if (iTest & (1 << 0))
            {
                fTest = V(tgCO_F_ParamSq_LR11_LR11)( &fT0,&fT1, &psRT0->m_vOrigin,psRT0->m_avEdge + 0, pvS0,pvD0 );

                if (fTest < fDistSq)
                {
                    fDistSq = fTest;
                    fRT0 = fT0;
                    fRT1 = MKL(0.0);
                    fG1 = fT1;
                }
            }

            if (iTest & (1 << 1))
            {
                fTest = V(tgCO_F_ParamSq_LR11_LR11)( &fT0,&fT1, &psRT0->m_vOrigin,psRT0->m_avEdge + 1, pvS0,pvD0 );

                if (fTest < fDistSq)
                {
                    fDistSq = fTest;
                    fRT0 = MKL(0.0);
                    fRT1 = fT0;
                    fG1 = fT1;
                }
            }

            if (iTest & (1 << 2))
            {
                V(C_TgVEC)                          vK1 = V(tgGM_Query_Point_2_RT)( psRT0 );

                fTest = V(tgCO_F_ParamSq_LR11_LR11)( &fT0,&fT1, &vK1,psRT0->m_avEdge + 0, pvS0,pvD0 );

                if (fTest < fDistSq)
                {
                    fDistSq = fTest;
                    fRT0 = fT0;
                    fRT1 = MKL(1.0);
                    fG1 = fT1;
                }
            }

            if (iTest & (1 << 3))
            {
                V(C_TgVEC)                          vK1 = V(tgGM_Query_Point_1_RT)( psRT0 );

                fTest = V(tgCO_F_ParamSq_LR11_LR11)( &fT0,&fT1, &vK1,psRT0->m_avEdge + 1, pvS0,pvD0 );

                if (fTest < fDistSq)
                {
                    fDistSq = fTest;
                    fRT0 = MKL(1.0);
                    fRT1 = fT0;
                    fG1 = fT1;
                }
            }

            *pfRT0 = fRT0;
            *pfRT1 = fRT1;
            *pfLN0 = fG1;

            return (fDistSq);
        };
    };
}


// ---- tgCO_FI_Clip_Param_RT_LR ------------------------------------------------------------------------------------------------ //
// Input:  psRT0: Rectangle primitive - F_Clip-space is the region defined by the infinite extrusion along the normal.
// Input:  vS0,vD0: Origin and Direction for the Linear
// Output: fLN0,fLN1: Parametric parameter to generate the two points of the linear contained inside the clip space.
// Return: Result Code.
// ------------------------------------------------------------------------------------------------------------------------------ //
TgRESULT VI(tgCO_FI_Clip_Param_RT_LR00)(
    PCU_TYPE pfLN0, PCU_TYPE pfLN1, V(CPCU_TgRECTANGLE) psRT0, V(CPCU_TgVEC) pvS0, V(CPCU_TgVEC) pvD0 )
{
    const TYPE                          fE0_E0 = V(F_LSQ)( psRT0->m_avEdge + 0 );
    const TYPE                          fE1_E1 = V(F_LSQ)( psRT0->m_avEdge + 1 );
    V(C_TgVEC)                          vDS = V(F_SUB_VV)( pvS0, &psRT0->m_vOrigin );
    TYPE                                fDS_N, fD1_N;
    TYPE                                fMin = -F(KTgMAX);
    TYPE                                fMax =  F(KTgMAX);

    if (fE0_E0 <= F(KTgEPS) || fE1_E1 <= F(KTgEPS))
    {
        // Degenerate rectangle - One or both of the edges has a near-zero length
        return (TgE_FAIL);
    };

    // Quick out - Does the linear exist outside of the clip region.

    fDS_N = V(F_DOT_VV)( psRT0->m_avEdge + 0, &vDS );
    fD1_N = V(F_DOT_VV)( psRT0->m_avEdge + 0, pvD0 );

    if (LN_CAP_0 && fDS_N < MKL(0.0))
    {
        if (fD1_N < MKL(0.0) || (LN_CAP_1 && (fDS_N + fD1_N < MKL(0.0))))
        {
            return (ETgE_NO_INTERSECT);
        };
    }
    else if (LN_CAP_0 && fDS_N > fE0_E0)
    {
        if (fD1_N > MKL(0.0) || (LN_CAP_1 && (fDS_N + fD1_N > fE0_E0)))
        {
            return (ETgE_NO_INTERSECT);
        };
    };

    // Find the non-capped intersections of this linear with the two enclosing planes.

    if (fD1_N < -F(KTgEPS))
    {
        fMin = F(tgPM_FSEL)( fDS_N + fD1_N*fMin - fE0_E0, (fE0_E0 - fDS_N) / fD1_N, fMin );
        fMax = F(tgPM_FSEL)( fDS_N + fD1_N*fMax, fMax, -fDS_N / fD1_N );
    }
    else if (fD1_N > F(KTgEPS))
    {
        fMin = F(tgPM_FSEL)( fD1_N*fMin + fDS_N, fMin, -fDS_N / fD1_N );
        fMax = F(tgPM_FSEL)( fDS_N + fD1_N*fMax - fE0_E0, (fE0_E0 - fDS_N) / fD1_N, fMax );
    };

    // Quick out - Does the linear exist outside of the clip region.

    fDS_N = V(F_DOT_VV)( psRT0->m_avEdge + 1, &vDS );
    fD1_N = V(F_DOT_VV)( psRT0->m_avEdge + 1, pvD0 );

    if (LN_CAP_0 && fDS_N < MKL(0.0))
    {
        if (fD1_N < MKL(0.0) || (LN_CAP_1 && (fDS_N + fD1_N < MKL(0.0))))
        {
            return (ETgE_NO_INTERSECT);
        };
    }
    else if (LN_CAP_0 && fDS_N > fE1_E1)
    {
        if (fD1_N > MKL(0.0) || (LN_CAP_1 && (fDS_N + fD1_N > fE1_E1)))
        {
            return (ETgE_NO_INTERSECT);
        };
    };

    // Find the non-capped intersections of this linear with the two enclosing planes.

    if (fD1_N < -F(KTgEPS))
    {
        fMin = F(tgPM_FSEL)( fDS_N + fD1_N*fMin - fE1_E1, (fE1_E1 - fDS_N) / fD1_N, fMin );
        fMax = F(tgPM_FSEL)( fDS_N + fD1_N*fMax, fMax, -fDS_N / fD1_N );
    }
    else if (fD1_N > F(KTgEPS))
    {
        fMin = F(tgPM_FSEL)( fD1_N*fMin + fDS_N, fMin, -fDS_N / fD1_N );
        fMax = F(tgPM_FSEL)( fDS_N + fD1_N*fMax - fE1_E1, (fE1_E1 - fDS_N) / fD1_N, fMax );
    };

    // Return the results - capped to the linear legal region.

    if (fMin > fMax || fMin <= -F(KTgMAX) || fMax >= F(KTgMAX))
    {
        return (TgE_FAIL);
    };

    if (LN_CAP_0)
    {
        *pfLN0 = F(tgPM_FSEL)( *pfLN0, *pfLN0, MKL(0.0) );
        *pfLN1 = F(tgPM_FSEL)( *pfLN1, *pfLN1, MKL(0.0) );
    };

    if (LN_CAP_1)
    {
        *pfLN0 = F(tgPM_FSEL)( *pfLN0 - MKL(1.0), *pfLN0, MKL(1.0) );
        *pfLN1 = F(tgPM_FSEL)( *pfLN1 - MKL(1.0), *pfLN1, MKL(1.0) );
    };

    return (TgS_OK);
}