/**************************************************************************
 *{@C
 *      Copyright:      1988-2023 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         Utilities
 *      Filename:       UTT_VecLib.c
 *
 *      Author:         Paul Obermeier
 *
 *      Description:    The command library for the Tcl wrap of the
 *                      vector and matrix math library.
 *
 *      Additional documentation:
 *                      None.
 *
 *      Exported functions:
 *
 **************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "UT_Compat.h"

#include "UT_Error.h"
#include "UT_Memory.h"

#include "UT_Vector.h"

#include <tcl.h>
#include "UTT_TclIf.h"

#include "UTT_Private.h"
#include "UTT_VecTclIf.h"

/* 
 *  The configuration tables for the Tcl vector and matrix library
 */

static UT_Bool
    initialized = UT_False;

static UTT_TclElemFunc vecFuncTbl[] =
{
    {UTT_TfmCopy2D,             "TfmCopy2D"},
    {UTT_TfmCopy3D,             "TfmCopy3D"},
    {UTT_TfmBuildTrans2D,       "TfmBuildTrans2D"},
    {UTT_TfmBuildTrans3D,       "TfmBuildTrans3D"},
    {UTT_TfmBuildRot2D,         "TfmBuildRot2D"},
    {UTT_TfmBuildRot3D,         "TfmBuildRot3D"},
    {UTT_TfmBuildScale2D,       "TfmBuildScale2D"},
    {UTT_TfmBuildScale3D,       "TfmBuildScale3D"},
    {UTT_TfmBuildRotArb3D,      "TfmBuildRotArb3D"},
    {UTT_TfmBuildRotArbLos3D,   "TfmBuildRotArbLos3D"},
    {UTT_TfmBuildLookAt3D,      "TfmBuildLookAt3D"},
    {UTT_TfmBuildLookAtVec3D,   "TfmBuildLookAtVec3D"},
    {UTT_TfmConcat2D,           "TfmConcat2D"},
    {UTT_TfmConcat3D,           "TfmConcat3D"},
    {UTT_TfmConcatTrans2D,      "TfmConcatTrans2D"},
    {UTT_TfmConcatTrans3D,      "TfmConcatTrans3D"},
    {UTT_TfmConcatRot2D,        "TfmConcatRot2D"},
    {UTT_TfmConcatRot3D,        "TfmConcatRot3D"},
    {UTT_TfmMultTrans3D,        "TfmMultTrans3D"},
    {UTT_TfmMultRot3D,          "TfmMultRot3D"},
    {UTT_TfmConcatScale2D,      "TfmConcatScale2D"},
    {UTT_TfmConcatScale3D,      "TfmConcatScale3D"},
    {UTT_TfmInvert2D,           "TfmInvert2D"},
    {UTT_TfmInvert3D,           "TfmInvert3D"},
    {UTT_TfmTranspose3D,        "TfmTranspose3D"},
    {UTT_TfmCoord2D,            "TfmCoord2D"},
    {UTT_TfmCoord3D,            "TfmCoord3D"},
    {UTT_TfmInitCoord2D,        "TfmInitCoord2D"},
    {UTT_TfmInitCoord3D,        "TfmInitCoord3D"},
    {UTT_TfmApply2D,            "TfmApply2D"},
    {UTT_TfmApply3D,            "TfmApply3D"},
    {UTT_TfmApplyNormal3D,      "TfmApplyNormal3D"},
    {UTT_VecAngle2D,            "VecAngle2D"},
    {UTT_VecAngle3D,            "VecAngle3D"},
    {UTT_VecDistPointLine2D,    "VecDistPointLine2D"},
    {UTT_VecDistPointLine3D,    "VecDistPointLine3D"},
    {UTT_VecPointInTria2D,      "VecPointInTria2D"},
    {UTT_VecPointInTria3D,      "VecPointInTria3D"},
    {UTT_VecIsectPlaneLine2D,   "VecIsectPlaneLine2D"},
    {UTT_VecIsectPlaneLine3D,   "VecIsectPlaneLine3D"},
    {UTT_VecDistLineLine3D,     "VecDistLineLine3D"},
    {UTT_VecIsectPlanePlane3D,  "VecIsectPlanePlane3D"},
    {UTT_VecCopy2D,             "VecCopy2D"},
    {UTT_VecCopy3D,             "VecCopy3D"},
    {UTT_VecAdd2D,              "VecAdd2D"},
    {UTT_VecAdd3D,              "VecAdd3D"},
    {UTT_VecSub2D,              "VecSub2D"},
    {UTT_VecSub3D,              "VecSub3D"},
    {UTT_VecScale2D,            "VecScale2D"},
    {UTT_VecScale3D,            "VecScale3D"},
    {UTT_VecCrossProd2D,        "VecCrossProd2D"},
    {UTT_VecCrossProd3D,        "VecCrossProd3D"},
    {UTT_VecDotProd2D,          "VecDotProd2D"},
    {UTT_VecDotProd3D,          "VecDotProd3D"},
    {UTT_VecLength2D,           "VecLength2D"},
    {UTT_VecLength3D,           "VecLength3D"},
    {UTT_VecDist2D,             "VecDist2D"},
    {UTT_VecDist3D,             "VecDist3D"},
    {UTT_VecUnit2D,             "VecUnit2D"},
    {UTT_VecUnit3D,             "VecUnit3D"},
    {UTT_VecLinComb2D,          "VecLinComb2D"},
    {UTT_VecLinComb3D,          "VecLinComb3D"},
    {UTT_VecReflect2D,          "VecReflect2D"},
    {UTT_VecReflect3D,          "VecReflect3D"},
    {UTT_VecDecompose2D,        "VecDecompose2D"},
    {UTT_VecDecompose3D,        "VecDecompose3D"},
};

static int VecCmd (TCLPARAMLIST)
{
    Int32 i;
    UT_Bool found = UT_False;

    if (argc == 2 && argv[1][0] == '?') {
        for (i=0; i< sizeof (vecFuncTbl) / sizeof (UTT_TclElemFunc); i++) {
            Tcl_AppendResult (interp, vecFuncTbl[i].name, "\n", (char *)NULL);
        }
        return TCL_OK;
    }
    if (argc < 2) {
        Tcl_AppendResult (interp, "Available poVec commands:\n", (char *)NULL); 
        for (i=0; i< sizeof (vecFuncTbl) / sizeof (UTT_TclElemFunc); i++)
            Tcl_AppendResult (interp, "\t", vecFuncTbl[i].name, "\n",
                              (char *)NULL);
        return TCL_ERROR;
    }
    for (i=0; i< sizeof (vecFuncTbl) / sizeof (UTT_TclElemFunc); i++) {
        if (strcmp (argv[1], vecFuncTbl[i].name) == 0) {
            if (!vecFuncTbl[i].func ((ClientData)NULL, interp, argc, argv)) {
                Tcl_AppendResult (interp, UT_ErrStr, "\n(",
                                  UT_ErrAddStr, ")\n", (char *)NULL); 
                return TCL_ERROR;
            } else {
                found = UT_True;
                break;
            }
        }
    }
    if (!found) {
        Tcl_AppendResult (interp, "Available poVec commands:\n", (char *)NULL);
        for (i=0; i< sizeof (vecFuncTbl) / sizeof (UTT_TclElemFunc); i++) {
            Tcl_AppendResult (interp, "\t", vecFuncTbl[i].name, "\n",
                              (char *)NULL);
        }
        return TCL_ERROR;
    }

    return TCL_OK;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetVec2D
 *
 *      Usage:          Get a Tcl function parameter of type UT_Vec2D.
 *
 *      Synopsis:       UT_Bool UTT_GetVec2D (TCLPARAMLIST, Int32 n, UT_Vec2D v)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_Vec2D".
 *                      The vector is expected as a Tcl list of length 2.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetVec2D (TCLPARAMLIST, Int32 n, UT_Vec2D v)
{
    Float32 *tmp;
    Int32   tmplen;

    UTT_GetFixFloat32List (n, tmp, tmplen, 2);
    UT_VecCopy2D (tmp, v);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetVec3D
 *
 *      Usage:          Get a Tcl function parameter of type UT_Vec3D.
 *
 *      Synopsis:       UT_Bool UTT_GetVec3D (TCLPARAMLIST, Int32 n, UT_Vec3D v)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_Vec3D".
 *                      The vector is expected as a Tcl list of length 3.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetVec3D (TCLPARAMLIST, Int32 n, UT_Vec3D v)
{
    Float32 *tmp;
    Int32   tmplen;

    UTT_GetFixFloat32List (n, tmp, tmplen, 3);
    UT_VecCopy3D (tmp, v);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetVec2D
 *
 *      Usage:          Set a Tcl function parameter of type UT_Vec2D.
 *
 *      Synopsis:       UT_Bool UTT_SetVec2D (TCLPARAMLIST, Int32 n, UT_Vec2D v)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a vector of type "UT_Vec2D". 
 *                      The vector is set as a Tcl list of length 2.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetVec2D (TCLPARAMLIST, Int32 n, const UT_Vec2D v)
{
    Float32 tmp[2];

    UT_VecCopy2D (v, tmp);
    UTT_SetFixFloat32List (n, tmp, 2);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetVec3D
 *
 *      Usage:          Set a Tcl function parameter of type UT_Vec3D.
 *
 *      Synopsis:       UT_Bool UTT_SetVec3D (TCLPARAMLIST, Int32 n, const UT_Vec3D v)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a vector of type "UT_Vec3D". 
 *                      The vector is set as a Tcl list of length 3.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetVec3D (TCLPARAMLIST, Int32 n, const UT_Vec3D v)
{
    Float32 tmp[3];

    UT_VecCopy3D (v, tmp);
    UTT_SetFixFloat32List (n, tmp, 3);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetDVec2D
 *
 *      Usage:          Get a Tcl function parameter of type UT_DVec2D.
 *
 *      Synopsis:       UT_Bool UTT_GetDVec2D (TCLPARAMLIST, Int32 n, UT_DVec2D v)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_DVec2D".
 *                      The vector is expected as a Tcl list of length 2.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetDVec2D (TCLPARAMLIST, Int32 n, UT_DVec2D v)
{
    Float64 *tmp;
    Int32   tmplen;

    UTT_GetFixFloat64List (n, tmp, tmplen, 2);
    UT_DVecCopy2D (tmp, v);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetDVec3D
 *
 *      Usage:          Get a Tcl function parameter of type UT_DVec3D.
 *
 *      Synopsis:       UT_Bool UTT_DGetVec3D (TCLPARAMLIST, Int32 n, UT_DVec3D v)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_DVec3D".
 *                      The vector is expected as a Tcl list of length 3.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetDVec3D (TCLPARAMLIST, Int32 n, UT_DVec3D v)
{
    Float64 *tmp;
    Int32   tmplen;

    UTT_GetFixFloat64List (n, tmp, tmplen, 3);
    UT_DVecCopy3D (tmp, v);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetDVec2D
 *
 *      Usage:          Set a Tcl function parameter of type UT_DVec2D.
 *
 *      Synopsis:       UT_Bool UTT_SetDVec2D 
 *                              (TCLPARAMLIST, Int32 n, const UT_DVec2D v)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a vector of type "UT_DVec2D". 
 *                      The vector is set as a Tcl list of length 2.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetDVec2D (TCLPARAMLIST, Int32 n, const UT_DVec2D v)
{
    Float64 tmp[2];

    UT_DVecCopy2D (v, tmp);
    UTT_SetFixFloat64List (n, tmp, 2);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetDVec3D
 *
 *      Usage:          Set a Tcl function parameter of type UT_DVec3D.
 *
 *      Synopsis:       UT_Bool UTT_SetDVec3D 
 *                              (TCLPARAMLIST, Int32 n, const UT_DVec3D v)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a vector of type "UT_DVec3D". 
 *                      The vector is set as a Tcl list of length 3.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetDVec3D (TCLPARAMLIST, Int32 n, const UT_DVec3D v)
{
    Float64 tmp[3];

    UT_DVecCopy3D (v, tmp);
    UTT_SetFixFloat64List (n, tmp, 3);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetTfm2D
 *
 *      Usage:          Get a Tcl function parameter of type UT_Tfm2D.
 *
 *      Synopsis:       UT_Bool UTT_GetTfm2D (TCLPARAMLIST, Int32 n, UT_Tfm2D T)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_Tfm2D".
 *                      The matrix is expected as a Tcl list of length 6.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetTfm2D (TCLPARAMLIST, Int32 n, UT_Tfm2D T)
{
    Float32 *tmp;
    Int32 tmplen;

    UTT_GetFixFloat32List (n, tmp, tmplen, 6);
    UT_VecCopy2D (tmp + 0, T[0]);
    UT_VecCopy2D (tmp + 2, T[1]);
    UT_VecCopy2D (tmp + 4, T[2]);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetTfm3D
 *
 *      Usage:          Get a Tcl function parameter of type UT_Tfm3D.
 *
 *      Synopsis:       UT_Bool UTT_GetTfm3D (TCLPARAMLIST, Int32 n, UT_Tfm3D T)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_Tfm3D".
 *                      The matrix is expected as a Tcl list of length 12.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetTfm3D (TCLPARAMLIST, Int32 n, UT_Tfm3D T)
{
    Float32 *tmp;
    Int32 tmplen;

    UTT_GetFixFloat32List (n, tmp, tmplen, 12);
    UT_VecCopy3D (tmp + 0, T[0]);
    UT_VecCopy3D (tmp + 3, T[1]);
    UT_VecCopy3D (tmp + 6, T[2]);
    UT_VecCopy3D (tmp + 9, T[3]);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetTfm2D
 *
 *      Usage:          Set a Tcl function parameter of type UT_Tfm2D.
 *
 *      Synopsis:       UT_Bool UTT_SetTfm2D 
 *                              (TCLPARAMLIST, Int32 n, const UT_Tfm2D T)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a matrix of type "UT_Tfm2D". 
 *                      The matrix is set as a Tcl list of length 6.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetTfm2D (TCLPARAMLIST, Int32 n, const UT_Tfm2D T)
{
    Float32 tmp[6];

    UT_VecCopy2D (T[0], tmp + 0);
    UT_VecCopy2D (T[1], tmp + 2);
    UT_VecCopy2D (T[2], tmp + 4);
    UTT_SetFixFloat32List (n, tmp, 6);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetTfm3D
 *
 *      Usage:          Set a Tcl function parameter of type UT_Tfm3D.
 *
 *      Synopsis:       UT_Bool UTT_SetTfm3D 
 *                              (TCLPARAMLIST, Int32 n, const UT_Tfm3D T)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a matrix of type "UT_Tfm3D". 
 *                      The matrix is set as a Tcl list of length 12.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetTfm3D (TCLPARAMLIST, Int32 n, const UT_Tfm3D T)
{
    Float32 tmp[12];

    UT_VecCopy3D (T[0], tmp + 0);
    UT_VecCopy3D (T[1], tmp + 3);
    UT_VecCopy3D (T[2], tmp + 6);
    UT_VecCopy3D (T[3], tmp + 9);
    UTT_SetFixFloat32List (n, tmp, 12);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetCoSys2D
 *
 *      Usage:          Get a Tcl function parameter of type UT_CoSys2D.
 *
 *      Synopsis:       UT_Bool UTT_GetCoSys2D (TCLPARAMLIST, Int32 n, UT_CoSys2D *c)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_CoSys2D".
 *                      The coordinate system is expected as a Tcl list
 *                      of length 6.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetCoSys2D (TCLPARAMLIST, Int32 n, UT_CoSys2D *c)
{
    Float32 *tmp;
    Int32 tmplen;

    UTT_GetFixFloat32List (n, tmp, tmplen, 6);
    UT_VecCopy2D (tmp + 0, c->off);
    UT_VecCopy2D (tmp + 2, c->ori[0]);
    UT_VecCopy2D (tmp + 4, c->ori[1]);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_GetCoSys3D
 *
 *      Usage:          Get a Tcl function parameter of type UT_CoSys3D.
 *
 *      Synopsis:       UT_Bool UTT_GetCoSys3D (TCLPARAMLIST, Int32 n, UT_CoSys3D *c)
 *
 *      Description:    Get the value of the nth parameter of a Tcl function
 *                      and convert it to type "UT_CoSys3D".
 *                      The coordinate system is expected as a Tcl list
 *                      of length 12.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_GetCoSys3D (TCLPARAMLIST, Int32 n, UT_CoSys3D *c)
{
    Float32 *tmp;
    Int32 tmplen;

    UTT_GetFixFloat32List (n, tmp, tmplen, 12);
    UT_VecCopy3D (tmp + 0, c->off);
    UT_VecCopy3D (tmp + 3, c->ori[0]);
    UT_VecCopy3D (tmp + 6, c->ori[1]);
    UT_VecCopy3D (tmp + 9, c->ori[2]);
    UT_MemFree (tmp);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetCoSys2D
 *
 *      Usage:          Set a Tcl function parameter of type UT_CoSys2D.
 *
 *      Synopsis:       UT_Bool UTT_SetCoSys2D 
 *                              (TCLPARAMLIST, Int32 n, const UT_CoSys2D *c)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a coordinate system of type "UT_CoSys2D". 
 *                      The coordinate system is set as a Tcl list of length 6.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetCoSys2D (TCLPARAMLIST, Int32 n, const UT_CoSys2D *c)
{
    Float32 tmp[6];

    UT_VecCopy2D (c->off,    tmp + 0);
    UT_VecCopy2D (c->ori[0], tmp + 2);
    UT_VecCopy2D (c->ori[1], tmp + 4);
    UTT_SetFixFloat32List (n, tmp, 6);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_SetCoSys3D
 *
 *      Usage:          Set a Tcl function parameter of type UT_CoSys3D.
 *
 *      Synopsis:       UT_Bool UTT_SetCoSys3D 
 *                              (TCLPARAMLIST, Int32 n, const UT_CoSys3D *c)
 *
 *      Description:    Set the value of the nth parameter of a Tcl function 
 *                      from a coordinate system of type "UT_CoSys3D". 
 *                      The coordinate system is set as a Tcl list of length 12.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool UTT_SetCoSys3D (TCLPARAMLIST, Int32 n, const UT_CoSys3D *c)
{
    Float32 tmp[12];

    UT_VecCopy3D (c->off,    tmp + 0);
    UT_VecCopy3D (c->ori[0], tmp + 3);
    UT_VecCopy3D (c->ori[1], tmp + 6);
    UT_VecCopy3D (c->ori[2], tmp + 9);
    UTT_SetFixFloat32List (n, tmp, 12);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UTT_InitTclVecLib
 *
 *      Usage:          Make the vector and matrix math functions and data
 *                      types available to the Tcl interpreter.
 *
 *      Synopsis:       int UTT_InitTclVecLib (Tcl_Interp *interp)
 *
 *      Description:
 *
 *      Return value:   TCL_OK if successful, else TCL_ERROR.
 *
 *      See also:
 *
 ***************************************************************************/

int UTT_InitTclVecLib (Tcl_Interp *interp)
{
    if (initialized) {
        return TCL_OK;
    }
    Tcl_CreateCommand (interp, "poVec", (Tcl_CmdProc *) VecCmd,
                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
    initialized = UT_True;
    return TCL_OK;
}
