// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Talina Gaming System (TgS) (∂)
//  »File«      TgS Common - Geometry 3D - Disk.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".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //

TgBOOL V(tgGM_Is_Valid_DK)( V(CPCU_TgDISK) ptgDK1 )
{
    if (!V(F_Is_Point_Valid)( &ptgDK1->m.m.tvOrigin ))
    {
        return (TgFALSE);
    };

    if (!V(F_Is_Vector_Valid)( &ptgDK1->m.m.tvNormal  ) || !F(tgCM_NR1)( V(F_LSQ)( &ptgDK1->m.m.tvNormal  ) ) )
    {
        return (TgFALSE);
    };

    if (F(tgCM_NaN)( ptgDK1->m_tyRadius ) || !(ptgDK1->m_tyRadius > MKL(0.0)) )
    {
        return (TgFALSE);
    };

    return (TgTRUE);
}


V(TgVEC) V(tgGM_Support_Point_DK)( V(CPCU_TgDISK) ptgDK1, V(CPCU_TgVEC) ptvDN )
{
    const TYPE                          tyD_N = V(F_DOT_VV)( ptvDN, &ptgDK1->m.m.tvNormal  );

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

    if (F(tgCM_NR0)( F(tgPM_ABS)( tyD_N ) - MKL(1.0) ))
    {
        return (ptgDK1->m.m.tvOrigin);
    }
    else
    {
        V(C_TgVEC)                          tvX0 = V(F_MUL_SV)( tyD_N, &ptgDK1->m.m.tvNormal  );
        V(C_TgVEC)                          tvX1 = V(F_SUB_VV)( ptvDN, &tvX0 );
        V(C_TgVEC)                          tvX2 = V(F_NORM)( &tvX1 );

        return (V(F_MAD_VSV)( &tvX2, ptgDK1->m_tyRadius, &ptgDK1->m.m.tvOrigin ));
    };
}


TgVOID V(tgGM_BA_DK)( V(PCU_TgBOXAA) ptgBA0, V(CPCU_TgDISK) ptgDK1 )
{
    TYPE                                tyTest;

    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_DK)( ptgDK1 ));

    if (!F(tgCM_NR0)( F(tgPM_ABS)( ptgDK1->m.m.tvNormal .m.x ) - MKL(1.0) ))
    {
        V(C_TgVEC)                          tvK0 = V(F_MUL_SV)( -ptgDK1->m.m.tvNormal .m.x, &ptgDK1->m.m.tvNormal  );
        V(C_TgVEC)                          tvK1 = V(F_ADD_VV)( &tvK0, &(V(TgKV_UNIT_X)) );
        V(C_TgVEC)                          tvA = V(F_NORM_LEN)( &tyTest, &tvK1 );
        const TYPE                          tyR_A = F(tgPM_ABS)( ptgDK1->m_tyRadius*tvA.m.x );

        TgASSERT( !F(tgCM_NR0)( tyTest ) );

        V(tgGM_Set_MinX_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.x - tyR_A );
        V(tgGM_Set_MaxX_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.x + tyR_A );
    }
    else
    {
        V(tgGM_Set_MinX_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.x );
        V(tgGM_Set_MaxX_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.x );
    };

    if (!F(tgCM_NR0)( F(tgPM_ABS)( ptgDK1->m.m.tvNormal .m.y ) - MKL(1.0) ))
    {
        V(C_TgVEC)                          tvK0 = V(F_MUL_SV)( -ptgDK1->m.m.tvNormal .m.y, &ptgDK1->m.m.tvNormal  );
        V(C_TgVEC)                          tvK1 = V(F_ADD_VV)( &tvK0, &(V(TgKV_UNIT_Y)) );
        V(C_TgVEC)                          tvA = V(F_NORM_LEN)( &tyTest, &tvK1 );
        const TYPE                          tyR_A = F(tgPM_ABS)( ptgDK1->m_tyRadius*tvA.m.y );

        TgASSERT( !F(tgCM_NR0)( tyTest ) );

        V(tgGM_Set_MinY_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.y - tyR_A );
        V(tgGM_Set_MaxY_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.y + tyR_A );
    }
    else
    {
        V(tgGM_Set_MinY_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.y );
        V(tgGM_Set_MaxY_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.y );
    };

    if (!F(tgCM_NR0)( F(tgPM_ABS)( ptgDK1->m.m.tvNormal .m.z ) - MKL(1.0) ))
    {
        V(C_TgVEC)                          tvK0 = V(F_MUL_SV)( -ptgDK1->m.m.tvNormal .m.z, &ptgDK1->m.m.tvNormal  );
        V(C_TgVEC)                          tvK1 = V(F_ADD_VV)( &tvK0, &(V(TgKV_UNIT_Z)) );
        V(C_TgVEC)                          tvA = V(F_NORM_LEN)( &tyTest, &tvK1 );
        const TYPE                          tyR_A = F(tgPM_ABS)( ptgDK1->m_tyRadius*tvA.m.z );

        TgASSERT( !F(tgCM_NR0)( tyTest ) );

        V(tgGM_Set_MinZ_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.z - tyR_A );
        V(tgGM_Set_MaxZ_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.z + tyR_A );
    }
    else
    {
        V(tgGM_Set_MinZ_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.z );
        V(tgGM_Set_MaxZ_BA)( ptgBA0, ptgDK1->m.m.tvOrigin.m.z );
    };
}


TgVOID V(tgGM_Project_DK)( PCU_TYPE ptyMin, PCU_TYPE ptyMax, V(CPCU_TgDISK) ptgDK1, V(CPCU_TgVEC) ptvDN )
{
    const TYPE                          tyAx_N = V(F_DOT_VV)( ptvDN, &ptgDK1->m.m.tvNormal );
    const TYPE                          tyOR_DN = V(F_DOT_VV)( &ptgDK1->m.m.tvOrigin, ptvDN );

    TgGEOM_ASSERT_PARAM(0 != ptyMin && 0 != ptyMax && V(tgGM_Is_Valid_DK)( ptgDK1 ) && V(F_Is_Vector_Valid)( ptvDN ));

    if (F(tgCM_NR0)( F(tgPM_ABS)( tyAx_N ) - MKL(1.0) ))
    {
        *ptyMin = tyOR_DN;
        *ptyMax = tyOR_DN;
    }
    else
    {
        TYPE                                tyTest;

        V(C_TgVEC)                          tvX0 = V(F_MUL_SV)( tyAx_N, &ptgDK1->m.m.tvNormal  );
        V(C_TgVEC)                          tvX1 = V(F_SUB_VV)( ptvDN, &tvX0 );
        V(C_TgVEC)                          tvX2 = V(F_NORM_LEN)( &tyTest, &tvX1 );
        const TYPE                          tyX2_DN = V(F_DOT_VV)( ptvDN, &tvX2 );
        const TYPE                          tyRS_AX = F(tgPM_ABS)( ptgDK1->m_tyRadius * tyX2_DN );

        TgASSERT( !F(tgCM_NR0)( tyTest ) );

        *ptyMin = tyOR_DN - tyRS_AX;
        *ptyMax = tyOR_DN + tyRS_AX;
    };
}