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

TgINLINE TgVOID V(tgGM_Constructor_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0 )
{
    ptgPE0->m_tvOrigin   = V(F_SETP_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
    ptgPE0->m_atvEdge[0] = V(F_SETV_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
    ptgPE0->m_atvEdge[1] = V(F_SETV_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
    ptgPE0->m_tvNormal   = V(F_SETV_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
}


TgINLINE TgVOID V(tgGM_Reset_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0 )
{
    ptgPE0->m_tvOrigin   = V(F_SETP_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
    ptgPE0->m_atvEdge[0] = V(F_SETV_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
    ptgPE0->m_atvEdge[1] = V(F_SETV_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
    ptgPE0->m_tvNormal   = V(F_SETV_ELEM)( MKL(0.0), MKL(0.0), MKL(0.0) );
}


TgINLINE TgBOOL V(tgGM_Is_Valid_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    V(C_TgVEC)                          tvNormal = V(F_CX)( ptgPE1->m_atvEdge + 0, ptgPE1->m_atvEdge + 1 );

    if (   !V(F_Is_Point_Valid)( &ptgPE1->m_tvOrigin )
        || !V(F_Is_Vector_Valid)( ptgPE1->m_atvEdge + 0 )
        || !V(F_Is_Vector_Valid)( ptgPE1->m_atvEdge + 1 )
        || (V(F_LSQ)( ptgPE1->m_atvEdge + 0 ) <= F(TgEPS))
        || (F(tgCM_NR0)( V(F_LSQ)( &tvNormal ) ))
        || (V(F_LSQ)( ptgPE1->m_atvEdge + 1 ) <= F(TgEPS))
    ) {
        return (TgFALSE);
    };

    return (TgTRUE);
}


TgINLINE V(TgVEC) V(tgGM_Support_Point_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1, V(CPCU_TgVEC) ptvDN )
{
    const TYPE                          tyAx_E0 = V(F_DOT_VV)( ptvDN, ptgPE1->m_atvEdge + 0 );
    const TYPE                          tyAx_E1 = V(F_DOT_VV)( ptvDN, ptgPE1->m_atvEdge + 1 );
    const TYPE                          tyE0 = F(tgPM_FSEL)( tyAx_E0, MKL(1.0), MKL(0.0) );
    const TYPE                          tyE1 = F(tgPM_FSEL)( tyAx_E1, MKL(1.0), MKL(0.0) );
    V(C_TgVEC)                          tvE0 = V(F_MUL_SV)( tyE0, ptgPE1->m_atvEdge + 0 );
    V(C_TgVEC)                          tvE1 = V(F_MUL_SV)( tyE1, ptgPE1->m_atvEdge + 1 );
    V(C_TgVEC)                          tvB0 = V(F_ADD_VV)( &tvE0, &tvE1 );

    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ) && V(F_Is_Vector_Valid)( ptvDN ));

    return (V(F_ADD_VV)( &ptgPE1->m_tvOrigin, &tvB0 ));
}


TgINLINE TYPE V(tgGM_Area_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    V(C_TgVEC)                          tvX0 = V(F_CX)( ptgPE1->m_atvEdge + 0, ptgPE1->m_atvEdge + 1 );

    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ));

    return (V(F_LEN)( &tvX0 ));
}


TgINLINE TgVOID V(tgGM_BA_PE)( V(PCU_TgBOXAA) ptgBA0, V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    V(C_TgVEC)                          tvX0 = V(F_ADD_VV)( &ptgPE1->m_tvOrigin, ptgPE1->m_atvEdge + 0 );
    V(C_TgVEC)                          tvX1 = V(F_ADD_VV)( &ptgPE1->m_tvOrigin, ptgPE1->m_atvEdge + 1 );
    V(C_TgVEC)                          tvX2 = V(F_ADD_VV)( &tvX0, ptgPE1->m_atvEdge + 1 );

    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ));

    V(tgGM_Init_PT_BA)( ptgBA0, &ptgPE1->m_tvOrigin );
    V(tgGM_Union_PT_BA)( ptgBA0, &tvX0 );
    V(tgGM_Union_PT_BA)( ptgBA0, &tvX1 );
    V(tgGM_Union_PT_BA)( ptgBA0, &tvX2 );
}


TgINLINE TgVOID V(tgGM_Sweep_BA_PE)( V(PCU_TgBOXAA) ptgBA0, V(CPCU_TgPARALLELOGRAM) ptgPE1, V(CPCU_TgVEC) ptvDT )
{
    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ) && V(F_Is_Vector_Valid)( ptvDT ));

    V(tgGM_BA_PE)( ptgBA0, ptgPE1 );
    V(tgGM_Sweep_BA)( ptgBA0, ptvDT );
}


TgINLINE TgVOID V(tgGM_Project_PE)(
    PCU_TYPE ptyMin, PCU_TYPE ptyMax, V(CPCU_TgPARALLELOGRAM) ptgPE1, V(CPCU_TgVEC) ptvDN )
{
    const TYPE                          tyAx_E0 = V(F_DOT_VV)( ptvDN, ptgPE1->m_atvEdge + 0 );
    const TYPE                          tyAx_E1 = V(F_DOT_VV)( ptvDN, ptgPE1->m_atvEdge + 1 );
    const TYPE                          tyK0 = V(F_DOT_VV)( ptvDN, &ptgPE1->m_tvOrigin );

    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ) && V(F_Is_Vector_Valid)( ptvDN ));

    *ptyMin = tyK0;
    *ptyMax = tyK0;

    *ptyMin += F(tgPM_FSEL)( tyAx_E0, MKL(0.0), tyAx_E0 );
    *ptyMax += F(tgPM_FSEL)( tyAx_E0, tyAx_E0, MKL(0.0) );
    *ptyMin += F(tgPM_FSEL)( tyAx_E1, MKL(0.0), tyAx_E1 );
    *ptyMax += F(tgPM_FSEL)( tyAx_E1, tyAx_E1, MKL(0.0) );
}


TgINLINE TgBOOL V(tgGM_Is_Contained_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1, V(CPCU_TgVEC) ptvS0 )
{
    V(C_TgVEC)                          tvDS    = V(F_SUB_VV)( ptvS0, &ptgPE1->m_tvOrigin );
    const TYPE                          tyDS_E0 = V(F_DOT_VV)( ptgPE1->m_atvEdgeNormal + 0, &tvDS );
    const TYPE                          tyDS_E1 = V(F_DOT_VV)( ptgPE1->m_atvEdgeNormal + 1, &tvDS );
    const TYPE                          tyN0_E1 = V(F_DOT_VV)( ptgPE1->m_atvEdgeNormal + 0, ptgPE1->m_atvEdge + 0 );
    const TYPE                          tyN1_E0 = V(F_DOT_VV)( ptgPE1->m_atvEdgeNormal + 1, ptgPE1->m_atvEdge + 1 );

    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ) && V(F_Is_Point_Valid)( ptvS0 ));

    return (tyDS_E0 >= MKL(0.0) && tyDS_E1 >= MKL(0.0) && tyN0_E1 >= tyDS_E0 && tyN1_E0 >= tyDS_E1);
}


TgINLINE TgVOID V(tgGM_TX_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, M34(CPCU_TgMAT) ptmM0 )
{
    TgGEOM_ASSERT_PARAM(!M34(F_NaN)( ptmM0 ));

    ptgPE0->m_atvEdge[0]       = V(F_TX_V_34)( ptmM0, ptgPE0->m_atvEdge + 0       );
    ptgPE0->m_atvEdge[1]       = V(F_TX_V_34)( ptmM0, ptgPE0->m_atvEdge + 1       );
    ptgPE0->m_tvNormal         = V(F_TX_V_34)( ptmM0, &ptgPE0->m_tvNormal         );
    ptgPE0->m_tvOrigin         = V(F_TX_P_34)( ptmM0, &ptgPE0->m_tvOrigin         );
    ptgPE0->m_atvEdgeNormal[0] = V(F_TX_V_34)( ptmM0, ptgPE0->m_atvEdgeNormal + 0 );
    ptgPE0->m_atvEdgeNormal[1] = V(F_TX_V_34)( ptmM0, ptgPE0->m_atvEdgeNormal + 1 );
}


TgINLINE TgVOID V(tgGM_Copy_TX_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, V(CPCU_TgPARALLELOGRAM) ptgPE1, M34(CPCU_TgMAT) ptmM0 )
{
    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ) && !M34(F_NaN)( ptmM0 ));

    ptgPE0->m_atvEdge[0]       = V(F_TX_V_34)( ptmM0, ptgPE1->m_atvEdge + 0       );
    ptgPE0->m_atvEdge[1]       = V(F_TX_V_34)( ptmM0, ptgPE1->m_atvEdge + 1       );
    ptgPE0->m_tvNormal         = V(F_TX_V_34)( ptmM0, &ptgPE1->m_tvNormal         );
    ptgPE0->m_tvOrigin         = V(F_TX_P_34)( ptmM0, &ptgPE1->m_tvOrigin         );
    ptgPE0->m_atvEdgeNormal[0] = V(F_TX_V_34)( ptmM0, ptgPE1->m_atvEdgeNormal + 0 );
    ptgPE0->m_atvEdgeNormal[1] = V(F_TX_V_34)( ptmM0, ptgPE1->m_atvEdgeNormal + 1 );
}


TgINLINE TgVOID V(tgGM_Init_PE)(
    V(PCU_TgPARALLELOGRAM) ptgPE0, V(CPCU_TgVEC) ptvOrigin, V(CPCU_TgVEC) ptvEdge0, V(CPCU_TgVEC) ptvEdge1 )
{
    TgGEOM_ASSERT_PARAM(V(F_Is_Vector_Valid)( ptvEdge0 ) && V(F_Is_Vector_Valid)( ptvEdge1 ));
    TgGEOM_ASSERT_PARAM(V(F_Is_Point_Valid)( ptvOrigin ));

    ptgPE0->m_tvOrigin = *ptvOrigin;
    ptgPE0->m_atvEdge[0] = *ptvEdge0;
    ptgPE0->m_atvEdge[1] = *ptvEdge1;
    ptgPE0->m_tvNormal = V(F_UCX)( ptvEdge0, ptvEdge1 );
    ptgPE0->m_atvEdgeNormal[0] = V(F_CX)( &ptgPE0->m_tvNormal, ptvEdge0 );
    ptgPE0->m_atvEdgeNormal[1] = V(F_CX)( ptvEdge1, &ptgPE0->m_tvNormal );
}


TgINLINE TgVOID V(tgGM_Copy_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ));

    ptgPE0->m_tvOrigin = ptgPE1->m_tvOrigin;
    ptgPE0->m_atvEdge[0] = ptgPE1->m_atvEdge[0];
    ptgPE0->m_atvEdge[1] = ptgPE1->m_atvEdge[1];
    ptgPE0->m_tvNormal = ptgPE1->m_tvNormal;
    ptgPE0->m_atvEdgeNormal[0] = ptgPE1->m_atvEdgeNormal[0];
    ptgPE0->m_atvEdgeNormal[1] = ptgPE1->m_atvEdgeNormal[1];
}


TgINLINE TgVOID V(tgGM_Set_Origin_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, V(CPCU_TgVEC) ptvOrigin )
{
    TgGEOM_ASSERT_PARAM(V(F_Is_Point_Valid)( ptvOrigin ));
    ptgPE0->m_tvOrigin = *ptvOrigin;
}


TgINLINE TgVOID V(tgGM_Set_Edge_0_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, V(CPCU_TgVEC) ptvEdge0 )
{
    TgGEOM_ASSERT_PARAM(V(F_Is_Vector_Valid)( ptvEdge0 ));

    ptgPE0->m_atvEdge[0] = *ptvEdge0;
    ptgPE0->m_tvNormal = V(F_UCX)( ptvEdge0, ptgPE0->m_atvEdge + 1 );
    ptgPE0->m_atvEdgeNormal[0] = V(F_CX)( &ptgPE0->m_tvNormal, ptvEdge0 );
}


TgINLINE TgVOID V(tgGM_Set_Edge_1_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, V(CPCU_TgVEC) ptvEdge1 )
{
    TgGEOM_ASSERT_PARAM(V(F_Is_Vector_Valid)( ptvEdge1 ));

    ptgPE0->m_atvEdge[1] = *ptvEdge1;
    ptgPE0->m_tvNormal = V(F_UCX)( ptgPE0->m_atvEdge + 0, ptvEdge1 );
    ptgPE0->m_atvEdgeNormal[1] = V(F_CX)( ptvEdge1, &ptgPE0->m_tvNormal );
}


TgINLINE V(CP_TgVEC) V(tgGM_Query_Origin_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (&ptgPE1->m_tvOrigin);
}


TgINLINE V(CP_TgVEC) V(tgGM_Query_Edge_0_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (ptgPE1->m_atvEdge + 0);
}


TgINLINE V(CP_TgVEC) V(tgGM_Query_Edge_1_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (ptgPE1->m_atvEdge + 1);
}


TgINLINE V(CP_TgVEC) V(tgGM_Query_Normal_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (&ptgPE1->m_tvNormal);
}


TgINLINE V(CP_TgVEC) V(tgGM_Query_Edge_Normal_0_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (ptgPE1->m_atvEdgeNormal + 0);
}


TgINLINE V(CP_TgVEC) V(tgGM_Query_Edge_Normal_1_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (ptgPE1->m_atvEdgeNormal + 1);
}


TgINLINE V(CP_TgVEC) V(tgGM_Query_Point_0_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (&ptgPE1->m_tvOrigin);
}


TgINLINE V(TgVEC) V(tgGM_Query_Point_1_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (V(F_ADD_VV)( &ptgPE1->m_tvOrigin, ptgPE1->m_atvEdge + 0 ));
}


TgINLINE V(TgVEC) V(tgGM_Query_Point_2_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    return (V(F_ADD_VV)( &ptgPE1->m_tvOrigin, ptgPE1->m_atvEdge + 1 ));
}


TgINLINE V(TgVEC) V(tgGM_Query_Point_3_PE)( V(CPCU_TgPARALLELOGRAM) ptgPE1 )
{
    V(C_TgVEC)                          tvX0 = V(F_ADD_VV)( ptgPE1->m_atvEdge + 0, ptgPE1->m_atvEdge + 1 );

    return (V(F_ADD_VV)( &ptgPE1->m_tvOrigin, &tvX0 ));
}


//TgINLINE TgVOID V(tgGM_M_TX_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, M34(CPCU_TgMAT) ptmM0 )
//{
//    TgGEOM_ASSERT_PARAM(!M34(F_NaN)( ptmM0 ));
//
//    ptgPE0->m_atvEdge[0]       = V(tgGM_M_TX)( ptmM0, ptgPE0->m_atvEdge[0]       );
//    ptgPE0->m_atvEdge[1]       = V(tgGM_M_TX)( ptmM0, ptgPE0->m_atvEdge[1]       );
//    ptgPE0->m_tvNormal         = V(tgGM_M_TX)( ptmM0, ptgPE0->m_tvNormal         );
//    ptgPE0->m_tvOrigin         = V(tgGM_M_TX)( ptmM0, ptgPE0->m_tvOrigin         );
//    ptgPE0->m_atvEdgeNormal[0] = V(tgGM_M_TX)( ptmM0, ptgPE0->m_atvEdgeNormal[0] );
//    ptgPE0->m_atvEdgeNormal[1] = V(tgGM_M_TX)( ptmM0, ptgPE0->m_atvEdgeNormal[1] );
//};
//
//
//TgINLINE TgVOID V(tgGM_M_TX_PE)( V(PCU_TgPARALLELOGRAM) ptgPE0, V(CPCU_TgPARALLELOGRAM) ptgPE1, M34(CPCU_TgMAT) ptmM0 )
//{
//    TgGEOM_ASSERT_PARAM(V(tgGM_Is_Valid_PE)( ptgPE1 ) && !M34(F_NaN)( ptmM0 ));
//
//    ptgPE0->m_atvEdge[0]       = V(tgGM_M_TX)( ptmM0, ptgPE1->m_atvEdge[0]       );
//    ptgPE0->m_atvEdge[1]       = V(tgGM_M_TX)( ptmM0, ptgPE1->m_atvEdge[1]       );
//    ptgPE0->m_tvNormal         = V(tgGM_M_TX)( ptmM0, ptgPE1->m_tvNormal         );
//    ptgPE0->m_tvOrigin         = V(tgGM_M_TX)( ptmM0, ptgPE1->m_tvOrigin         );
//    ptgPE0->m_atvEdgeNormal[0] = V(tgGM_M_TX)( ptmM0, ptgPE1->m_atvEdgeNormal[0] );
//    ptgPE0->m_atvEdgeNormal[1] = V(tgGM_M_TX)( ptmM0, ptgPE1->m_atvEdgeNormal[1] );
//};