/******************************************************************************
* Trng_gen.c - General routines used by all modules of trng_lib.	      *
*******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                 *
*******************************************************************************
* Written by Gershon Elber, sep. 94.					      *
******************************************************************************/

#include <string.h>
#include "trng_loc.h"
#include "geomat3d.h"
#include "miscattr.h"

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates the memory required for a new triangular surface.                M
*                                                                            *
* PARAMETERS:                                                                M
*   GType:      Type of geometry the curve should be - Bspline, Bezier etc.  M
*   PType:      Type of control points (E2, P3, etc.).                       M
*   Length:     Number of control points along the edge of the triangle.     M
*                                                                            *
* RETURN VALUE:                                                              M
*   TrngTriangSrfStruct *:    An uninitialized freeform triangular surface.  M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrfNew, triangular surfaces, allocation                           M
*****************************************************************************/
TrngTriangSrfStruct *TrngTriSrfNew(TrngGeomType GType,
				   CagdPointType PType,
				   int Length)
{
    int i,
	MaxAxis = CAGD_NUM_OF_PT_COORD(PType);
    TrngTriangSrfStruct
	*NewTriSrf = (TrngTriangSrfStruct *)
					IritMalloc(sizeof(TrngTriangSrfStruct));

    NewTriSrf -> GType = GType;
    NewTriSrf -> PType = PType;
    NewTriSrf -> Length = Length;
    NewTriSrf -> KnotVector = NULL;
    NewTriSrf -> Pnext = NULL;
    NewTriSrf -> Attr = NULL;
    NewTriSrf -> Points[0] = NULL;		    /* The rational element. */

    for (i = !CAGD_IS_RATIONAL_PT(PType); i <= MaxAxis; i++)
	NewTriSrf -> Points[i] = (CagdRType *) IritMalloc(sizeof(CagdRType) *
					     TRNG_TRISRF_MESH_SIZE(NewTriSrf));

    for (i = MaxAxis + 1; i <= CAGD_MAX_PT_COORD; i++)
	NewTriSrf -> Points[i] = NULL;

    return NewTriSrf;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates the memory required for a new Bspline triangular surface.        M
*                                                                            *
* PARAMETERS:                                                                M
*   Length:     Number of control points along the edge of the triangle.     M
*   Order:      Order of triangular surface in all U,V,W directions.         M
*   PType:      Type of control points (E2, P3, etc.).                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   TrngTriangSrfStruct *:    An uninitialized freeform triangular surface   M
*			   Bspline.					     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngBspTriSrfNew, triangular surfaces, allocation                        M
*****************************************************************************/
TrngTriangSrfStruct *TrngBspTriSrfNew(int Length, 
				      int Order,
				      CagdPointType PType)
{
    TrngTriangSrfStruct *TriSrf;

    if (Length < Order) {
	TRNG_FATAL_ERROR(TRNG_ERR_WRONG_ORDER);
	return NULL;
    }

    TriSrf = TrngTriSrfNew(TRNG_TRISRF_BSPLINE_TYPE, PType, Length);

    TriSrf -> KnotVector = (CagdRType *) IritMalloc(sizeof(CagdRType) *
                                                           (Order + Length));
    TriSrf -> Order = Order;

    return TriSrf;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates the memory required for a new Bezier triangular surface.         M
*                                                                            *
* PARAMETERS:                                                                M
*   Length:     Number of control points along the edge of the triangle.     M
*   PType:      Type of control points (E2, P3, etc.).                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   TrngTriangSrfStruct *:    An uninitialized freeform triangular surface   M
*			   Bezier.					     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngBzrTriSrfNew, triangular surfaces, allocation                        M
*****************************************************************************/
TrngTriangSrfStruct *TrngBzrTriSrfNew(int Length, CagdPointType PType)
{
    TrngTriangSrfStruct
	*TriSrf = TrngTriSrfNew(TRNG_TRISRF_BEZIER_TYPE, PType, Length);

    TriSrf -> Order = TriSrf -> Length = Length;

    TriSrf -> KnotVector = NULL;

    return TriSrf;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates and duplicates all slots of a triangular surface structure.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrf:        triangular surface to duplicate                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   TrngTriangSrfStruct *:    Duplicated triangular surface.                 M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrfCopy, triangular surfaces                                      M
*****************************************************************************/
TrngTriangSrfStruct *TrngTriSrfCopy(TrngTriangSrfStruct *TriSrf)
{
    int i, Len,
	MaxAxis = CAGD_NUM_OF_PT_COORD(TriSrf -> PType);
    TrngTriangSrfStruct
	*NewTriSrf = (TrngTriangSrfStruct *)
				       IritMalloc(sizeof(TrngTriangSrfStruct));

    NewTriSrf -> GType = TriSrf -> GType;
    NewTriSrf -> PType = TriSrf -> PType;
    NewTriSrf -> Length = TriSrf -> Length;
    NewTriSrf -> Order = TriSrf -> Order;
    if (TriSrf -> KnotVector != NULL)
	NewTriSrf -> KnotVector = BspKnotCopy(TriSrf -> KnotVector,
					   TriSrf -> Length + TriSrf -> Order);
    else
	NewTriSrf -> KnotVector = NULL;
    NewTriSrf -> Pnext = NULL;
    NewTriSrf -> Attr = NULL;
    NewTriSrf -> Points[0] = NULL;		    /* The rational element. */

    Len = TRNG_TRISRF_MESH_SIZE(TriSrf);
    for (i = !TRNG_IS_RATIONAL_TRISRF(TriSrf); i <= MaxAxis; i++) {
	NewTriSrf -> Points[i] =
	    (CagdRType *) IritMalloc(sizeof(CagdRType) * Len);
	CAGD_GEN_COPY(NewTriSrf -> Points[i], TriSrf -> Points[i],
		      sizeof(CagdRType) * Len);
    }

    for (i = MaxAxis + 1; i <= CAGD_MAX_PT_COORD; i++)
	NewTriSrf -> Points[i] = NULL;

    return NewTriSrf;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Duplicates a list of triangular surface structures.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrfList:    List of triangular surfaces to duplicate.                 M
*                                                                            *
* RETURN VALUE:                                                              M
*   TrngTriangSrfStruct *:  Duplicated list of triangular surfaces.          M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrfCopyList, triangular surfaces                                  M
*****************************************************************************/
TrngTriangSrfStruct *TrngTriSrfCopyList(TrngTriangSrfStruct *TriSrfList)
{
    TrngTriangSrfStruct *TriSrfTemp, *NewTriSrfList;

    if (TriSrfList == NULL)
	return NULL;
    TriSrfTemp = NewTriSrfList = TrngTriSrfCopy(TriSrfList);
    TriSrfList = TriSrfList -> Pnext;
    while (TriSrfList) {
	TriSrfTemp -> Pnext = TrngTriSrfCopy(TriSrfList);
	TriSrfTemp = TriSrfTemp -> Pnext;
	TriSrfList = TriSrfList -> Pnext;
    }
    return NewTriSrfList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a triangular surface structure.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrf:     triangular surface to free.                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrfFree, triangular surfaces                                      M
*****************************************************************************/
void TrngTriSrfFree(TrngTriangSrfStruct *TriSrf)
{
    int i, MaxAxis;

    if (TriSrf == NULL)
	return;

    MaxAxis = CAGD_NUM_OF_PT_COORD(TriSrf -> PType);

    for (i = !TRNG_IS_RATIONAL_TRISRF(TriSrf); i <= MaxAxis; i++)
	IritFree((VoidPtr) TriSrf -> Points[i]);

    if (TriSrf -> KnotVector != NULL)
	IritFree((VoidPtr) TriSrf -> KnotVector);

    AttrFreeAttributes(&TriSrf -> Attr);
    IritFree((VoidPtr) TriSrf);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a list of triangular surface structures.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrfList:    triangular surface list to free.                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrfFreeList, triangular surfaces                                  M
*****************************************************************************/
void TrngTriSrfFreeList(TrngTriangSrfStruct *TriSrfList)
{
    TrngTriangSrfStruct *TriSrfTemp;

    while (TriSrfList) {
	TriSrfTemp = TriSrfList -> Pnext;
	TrngTriSrfFree(TriSrfList);
	TriSrfList = TriSrfTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Linearly transforms, in place, given TriSrf as specified by Translate and  M
* Scale.								     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrf:        Triangular surface to transform.                          M
*   Translate:     Translation factor.                                       M
*   Scale:         Scaling factor.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrfTransform, triangular surfaces                                 M
*****************************************************************************/
void TrngTriSrfTransform(TrngTriangSrfStruct *TriSrf,
			 CagdRType *Translate,
			 CagdRType Scale)
{
    switch (TriSrf -> GType) {
	case TRNG_TRISRF_BEZIER_TYPE:
	case TRNG_TRISRF_BSPLINE_TYPE:
	    CagdTransform(TriSrf -> Points,
	    		  TRNG_TRISRF_MESH_SIZE(TriSrf),
	                  CAGD_NUM_OF_PT_COORD(TriSrf -> PType),
			  !TRNG_IS_RATIONAL_TRISRF(TriSrf),
		          Translate,
        	          Scale);
	    break;
	default:
	    TRNG_FATAL_ERROR(TRNG_ERR_UNDEF_GEOM);
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Transforms, in place, the given TV as specified by homogeneous matrix Mat. M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrf:        Triangular surface to transform.                          M
*   Mat:           Homogeneous transformation to apply to TriSrf.            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngTriSrfMatTransform, triangular surfaces                              M
*****************************************************************************/
void TrngTriSrfMatTransform(TrngTriangSrfStruct *TriSrf, CagdMType Mat)
{
    switch (TriSrf -> GType) {
	case TRNG_TRISRF_BEZIER_TYPE:
	case TRNG_TRISRF_BSPLINE_TYPE:
	    CagdMatTransform(TriSrf -> Points,
    			     TRNG_TRISRF_MESH_SIZE(TriSrf),
        	             CAGD_NUM_OF_PT_COORD(TriSrf -> PType),
			     !TRNG_IS_RATIONAL_TRISRF(TriSrf),
		             Mat);
	    break;
	default:
	    TRNG_FATAL_ERROR(TRNG_ERR_UNDEF_GEOM);
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Converts a Bezier triangular surface into a Bspline triangular surface by  M
* adding open end uniform knot vector to it.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   TriSrf:   A Bezier triangular surface to convert to a Bspline TriSrf.    M
*                                                                            *
* RETURN VALUE:                                                              M
*   TrngTriangSrfStruct *:  A Bspline triangular surface representing the    M
*			 same geometry as the given Bezier TriSrf.           M
*                                                                            *
* KEYWORDS:                                                                  M
*   TrngCnvrtBezier2BsplineTriSrf, conversion, triangular surface            M
*****************************************************************************/
TrngTriangSrfStruct *TrngCnvrtBezier2BsplineTriSrf(TrngTriangSrfStruct *TriSrf)
{
    TrngTriangSrfStruct *BspTriSrf;

    if (TriSrf -> GType != TRNG_TRISRF_BEZIER_TYPE) {
        TRNG_FATAL_ERROR(TRNG_ERR_UNDEF_GEOM);
        return NULL;
    }

    BspTriSrf = TrngTriSrfCopy(TriSrf);

    BspTriSrf -> Order = BspTriSrf -> Length;
    BspTriSrf -> KnotVector = BspKnotUniformOpen(BspTriSrf -> Length,
					         BspTriSrf -> Order, NULL);
    BspTriSrf -> GType = TRNG_TRISRF_BSPLINE_TYPE;
    return BspTriSrf;
}
