Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Collision - F - Rectangle-Linear.c_inc
    »Keywords«  Collision;Distance;Closest;Intersect;Penetrate;Sweep;Rectangle;Line;Ray;Segment;
    »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
    »Version«   4.51 / »GUID« A9981407-3EC9-42AF-8B6F-8BE6DD919615                                                                                                        */
/*   -------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/*  Copyright: © 2002-2017, 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:
        Redistribution of source code must retain this copyright notice, this list of conditions and the following disclaimers.
        Redistribution 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.
    The name of the author may not 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".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */

MSVC_WARN_DISABLE_PUSH( 6235 ) /* Analysis - (<non-zero constant> || <expression>) is always a non-zero constant. */
MSVC_WARN_DISABLE_PUSH( 6240 ) /* Analysis - (<expression> && <non-zero constant>) always evaluates to the result of <expression>. */


/* == Collision ========================================================================================================================================================= */

/* ---- VI(tgCO_FI_RT_ParamSq_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_RT_ParamSq_LR)( TYPE *pfRT0, TYPE *pfRT1, TYPE *pfLN0, V(CPC_TgRECTANGLE) psRT0, V(CPC_TgVEC) pvS0, V(CPC_TgVEC) pvD0 )
{
    V(C_TgVEC)                          vX0 = V(F_SUB)(pvS0, &psRT0->m_vOrigin);
    const TYPE                          fX0_X0 = V(F_LSQ)(&vX0);

    TgERROR( V(tgGM_RT_Is_Valid)(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)(pvD0, &psRT0->m_vNormal);
        const TYPE                          fX0_N = V(F_DOT)(&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)(&vX0, &vK1);

                const TYPE                          fINT_EN0 = V(F_DOT)(psRT0->m_avEdge + 1, &vK0);
                const TYPE                          fINT_EN1 = V(F_DOT)(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)(pvS0, &psRT0->m_vOrigin);
            V(C_TgVEC)                          vX1 = V(F_ADD)(&vK0, pvD0);

            const TYPE                          f00 = V(F_DOT)(psRT0->m_avEdge + 1, &vX0);
            const TYPE                          f01 = V(F_DOT)(psRT0->m_avEdge + 0, &vX0);
            const TYPE                          f10 = V(F_DOT)(psRT0->m_avEdge + 1, LN_CAP_1 ? &vX1 : pvD0);
            const TYPE                          f11 = V(F_DOT)(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)(&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_LR11_ParamSq_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_LR11_ParamSq_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_RT_Query_Point_2)(psRT0);

                fTest = V(tgCO_F_LR11_ParamSq_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_RT_Query_Point_1)(psRT0);

                fTest = V(tgCO_F_LR11_ParamSq_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);
        };
    };
}


/* ---- VI(tgCO_FI_RT_Clip_Param_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_RT_Clip_Param_LR)( TYPE *pfLN0, TYPE *pfLN1, V(CPC_TgRECTANGLE) psRT0, V(CPC_TgVEC) pvS0, V(CPC_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)(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 (KTgE_FAIL);
    };

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

    fDS_N = V(F_DOT)(psRT0->m_avEdge + 0, &vDS);
    fD1_N = V(F_DOT)(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 (KTgE_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 (KTgE_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)(psRT0->m_avEdge + 1, &vDS);
    fD1_N = V(F_DOT)(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 (KTgE_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 (KTgE_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 (KTgE_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 (KTgS_OK);
}


MSVC_WARN_DISABLE_POP( 6235 )
MSVC_WARN_DISABLE_POP( 6240 )