/******************************************************************************
* Cagd_gen.c - General routines used by all modules of CAGD_lib.	      *
*******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                 *
*******************************************************************************
* Written by Gershon Elber, Mar. 90.					      *
******************************************************************************/

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

/* Control of the linear order surface convertion to polygon: */
CagdLin2PolyType
    _CagdLin2Poly = CAGD_ONE_POLY_PER_COLIN;
static CagdPlgErrorFuncType
    PolygonErrFunc = NULL;

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates and copies a list of vector structures.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   VecList:       To be copied.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdVecStruct *:  A duplicated list of vectors.                          M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdVecCopyList, copy                                                    M
*****************************************************************************/
CagdVecStruct *CagdVecCopyList(CagdVecStruct *VecList)
{
    CagdVecStruct *VecTemp, *NewVecList;

    if (VecList == NULL)
	return NULL;
    VecTemp = NewVecList = CagdVecCopy(VecList);
    VecList = VecList -> Pnext;
    while (VecList) {
	VecTemp -> Pnext = CagdVecCopy(VecList);
	VecTemp = VecTemp -> Pnext;
	VecList = VecList -> Pnext;
    }
    return NewVecList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates and copies a list of plane structures.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   PlaneList:       To be copied.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdPlaneStruct *:  A duplicated list of planes.                         M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPlaneCopyList, copy                                                  M
*****************************************************************************/
CagdPlaneStruct *CagdPlaneCopyList(CagdPlaneStruct *PlaneList)
{
    CagdPlaneStruct *PlaneTemp, *NewPlaneList;

    if (PlaneList == NULL)
	return NULL;
    PlaneTemp = NewPlaneList = CagdPlaneCopy(PlaneList);
    PlaneList = PlaneList -> Pnext;
    while (PlaneList) {
	PlaneTemp -> Pnext = CagdPlaneCopy(PlaneList);
	PlaneTemp = PlaneTemp -> Pnext;
	PlaneList = PlaneList -> Pnext;
    }
    return NewPlaneList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates and copies a list of bbox structures.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   BBoxList:       To be copied.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdBBoxStruct *:  A duplicated list of bbox's.                          M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdBBoxCopyList, copy                                                   M
*****************************************************************************/
CagdBBoxStruct *CagdBBoxCopyList(CagdBBoxStruct *BBoxList)
{
    CagdBBoxStruct *BBoxTemp, *NewBBoxList;

    if (BBoxList == NULL)
	return NULL;
    BBoxTemp = NewBBoxList = CagdBBoxCopy(BBoxList);
    BBoxList = BBoxList -> Pnext;
    while (BBoxList) {
	BBoxTemp -> Pnext = CagdBBoxCopy(BBoxList);
	BBoxTemp = BBoxTemp -> Pnext;
	BBoxList = BBoxList -> Pnext;
    }
    return NewBBoxList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates and copies a list of polyline structures.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   PolyList:       To be copied.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdPolylineStruct *:  A duplicated list of polylines.                   M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPolylineCopyList, copy                                               M
*****************************************************************************/
CagdPolylineStruct *CagdPolylineCopyList(CagdPolylineStruct *PolyList)
{
    CagdPolylineStruct *PolyTemp, *NewPolyList;

    if (PolyList == NULL)
	return NULL;
    PolyTemp = NewPolyList = CagdPolylineCopy(PolyList);
    PolyList = PolyList -> Pnext;
    while (PolyList) {
	PolyTemp -> Pnext = CagdPolylineCopy(PolyList);
	PolyTemp = PolyTemp -> Pnext;
	PolyList = PolyList -> Pnext;
    }
    return NewPolyList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Allocates and copies a list of polygon structures.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   PolyList:       To be copied.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdPolygontruct *:  A duplicated list of polygons.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPolygonCopyList, copy                                                M
*****************************************************************************/
CagdPolygonStruct *CagdPolygonCopyList(CagdPolygonStruct *PolyList)
{
    CagdPolygonStruct *PolyTemp, *NewPolyList;

    if (PolyList == NULL)
	return NULL;
    PolyTemp = NewPolyList = CagdPolygonCopy(PolyList);
    PolyList = PolyList -> Pnext;
    while (PolyList) {
	PolyTemp -> Pnext = CagdPolygonCopy(PolyList);
	PolyTemp = PolyTemp -> Pnext;
	PolyList = PolyList -> Pnext;
    }
    return NewPolyList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a curve structure.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:       To be deallocated.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdCrvFree, free                                                        M
*****************************************************************************/
void CagdCrvFree(CagdCrvStruct *Crv)
{
    int i, MaxAxis;

    if (Crv == NULL)
	return;

    MaxAxis = CAGD_NUM_OF_PT_COORD(Crv -> PType);

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

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

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a curve structure list:				     M
*                                                                            *
* PARAMETERS:                                                                M
*   CrvList:  To be deallocated.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdCrvFreeList, free                                                    M
*****************************************************************************/
void CagdCrvFreeList(CagdCrvStruct *CrvList)
{
    CagdCrvStruct *CrvTemp;

    while (CrvList) {
	CrvTemp = CrvList -> Pnext;
	CagdCrvFree(CrvList);
	CrvList = CrvTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a surface sstructure.	             M
*                                                                            *
* PARAMETERS:                                                                M
*   Srf:       To be deallocated.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdSrfFree, free                                                        M
*****************************************************************************/
void CagdSrfFree(CagdSrfStruct *Srf)
{
    int i, MaxAxis;

    if (Srf == NULL)
	return;

    MaxAxis = CAGD_NUM_OF_PT_COORD(Srf -> PType);

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

    if (Srf -> UKnotVector != NULL)
	IritFree((VoidPtr) Srf -> UKnotVector);
    if (Srf -> VKnotVector != NULL)
	IritFree((VoidPtr) Srf -> VKnotVector);

    AttrFreeAttributes(&Srf -> Attr);

    if (Srf -> PAux != NULL) {
	CagdSrfEvalCashStruct
	    *SrfEvalCash = (CagdSrfEvalCashStruct *) Srf -> PAux;

        CagdCrvFree(SrfEvalCash -> IsoSubCrv);
	IritFree(SrfEvalCash);
    }

    IritFree((VoidPtr) Srf);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a surface structure list:			     M
*                                                                            *
* PARAMETERS:                                                                M
*   SrfList:  To be deallocated.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdSrfFreeList, free                                                    M
*****************************************************************************/
void CagdSrfFreeList(CagdSrfStruct *SrfList)
{
    CagdSrfStruct *SrfTemp;

    while (SrfList) {
	SrfTemp = SrfList -> Pnext;
	CagdSrfFree(SrfList);
	SrfList = SrfTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a UV structure.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   UV:       To be deallocated.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdUVFree, free                                                         M
*****************************************************************************/
void CagdUVFree(CagdUVStruct *UV)
{
    if (UV == NULL)
	return;

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a UV structure list:				     M
*                                                                            *
* PARAMETERS:                                                                M
*   UVList:  To be deallocated.                                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdUVFreeList, free                                                     M
*****************************************************************************/
void CagdUVFreeList(CagdUVStruct *UVList)
{
    CagdUVStruct *UVTemp;

    while (UVList) {
	UVTemp = UVList -> Pnext;
	CagdUVFree(UVList);
	UVList = UVTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees an array of UV structure.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   UVArray:     To be deallocated.                                          M
*   Size:        Of the deallocated array.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdUVArrayFree, free                                                    M
*****************************************************************************/
void CagdUVArrayFree(CagdUVStruct *UVArray, int Size)
{
    int i;

    for (i = 0; i < Size; i++)
	AttrFreeAttributes(&UVArray[i].Attr);

    IritFree((VoidPtr) UVArray);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a point structure.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   Pt:       To be deallocated.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPtFree, free                                                         M
*****************************************************************************/
void CagdPtFree(CagdPtStruct *Pt)
{
    if (Pt == NULL)
	return;

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a point structure list:				     M
*                                                                            *
* PARAMETERS:                                                                M
*   PtList:  To be deallocated.                                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPtFreeList, free                                                     M
*****************************************************************************/
void CagdPtFreeList(CagdPtStruct *PtList)
{
    CagdPtStruct *PtTemp;

    while (PtList) {
	PtTemp = PtList -> Pnext;
	CagdPtFree(PtList);
	PtList = PtTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees an array of Pt structure.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   PtArray:     To be deallocated.                                          M
*   Size:        Of the deallocated array.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPtArrayFree, free                                                    M
*****************************************************************************/
void CagdPtArrayFree(CagdPtStruct *PtArray, int Size)
{
    int i;

    for (i = 0; i < Size; i++)
	AttrFreeAttributes(&PtArray[i].Attr);

    IritFree((VoidPtr) PtArray);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a CtlPt structure.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   CtlPt:       To be deallocated.                                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdCtlPtFree, free                                                      M
*****************************************************************************/
void CagdCtlPtFree(CagdCtlPtStruct *CtlPt)
{
    if (CtlPt == NULL)
	return;

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a CtlPt structure list:				     M
*                                                                            *
* PARAMETERS:                                                                M
*   CtlPtList:  To be deallocated.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdCtlPtFreeList, free                                                  M
*****************************************************************************/
void CagdCtlPtFreeList(CagdCtlPtStruct *CtlPtList)
{
    CagdCtlPtStruct *CtlPtTemp;

    while (CtlPtList) {
	CtlPtTemp = CtlPtList -> Pnext;
	CagdCtlPtFree(CtlPtList);
	CtlPtList = CtlPtTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees an array of CtlPt structure.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   CtlPtArray:     To be deallocated.                                       M
*   Size:           Of the deallocated array.                                M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdCtlPtArrayFree, free                                                 M
*****************************************************************************/
void CagdCtlPtArrayFree(CagdCtlPtStruct *CtlPtArray, int Size)
{
    int i;

    for (i = 0; i < Size; i++)
	AttrFreeAttributes(&CtlPtArray[i].Attr);

    IritFree((VoidPtr) CtlPtArray);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a vector structure.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Vec:       To be deallocated.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdVecFree, free                                                        M
*****************************************************************************/
void CagdVecFree(CagdVecStruct *Vec)
{
    if (Vec == NULL)
	return;

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a vector structure list:			     M
*                                                                            *
* PARAMETERS:                                                                M
*   VecList:  To be deallocated.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdVecFreeList, free                                                    M
*****************************************************************************/
void CagdVecFreeList(CagdVecStruct *VecList)
{
    CagdVecStruct *VecTemp;

    while (VecList) {
	VecTemp = VecList -> Pnext;
	CagdVecFree(VecList);
	VecList = VecTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees an array of vector structure.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   VecArray:     To be deallocated.                                         M
*   Size:         Of the deallocated array.                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdVecArrayFree, free                                                   M
*****************************************************************************/
void CagdVecArrayFree(CagdVecStruct *VecArray, int Size)
{
    int i;

    for (i = 0; i < Size; i++)
	AttrFreeAttributes(&VecArray[i].Attr);

    IritFree((VoidPtr) VecArray);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a plane structure.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   Plane:       To be deallocated.                                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPlaneFree, free                                                      M
*****************************************************************************/
void CagdPlaneFree(CagdPlaneStruct *Plane)
{
    if (Plane == NULL)
	return;

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a plane structure list:				     M
*                                                                            *
* PARAMETERS:                                                                M
*   PlaneList:  To be deallocated.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPlaneFreeList, free                                                  M
*****************************************************************************/
void CagdPlaneFreeList(CagdPlaneStruct *PlaneList)
{
    CagdPlaneStruct *PlaneTemp;

    while (PlaneList) {
	PlaneTemp = PlaneList -> Pnext;
	CagdPlaneFree(PlaneList);
	PlaneList = PlaneTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees an array of plane structure.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   PlaneArray:     To be deallocated.                                       M
*   Size:           Of the deallocated array.                                M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPlaneArrayFree, free                                                 M
*****************************************************************************/
void CagdPlaneArrayFree(CagdPlaneStruct *PlaneArray, int Size)
{
    int i;

    for (i = 0; i < Size; i++)
	AttrFreeAttributes(&PlaneArray[i].Attr);

    IritFree((VoidPtr) PlaneArray);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a BBox structure.		             M
*                                                                            *
* PARAMETERS:                                                                M
*   BBox:       To be deallocated.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdBBoxFree, free                                                       M
*****************************************************************************/
void CagdBBoxFree(CagdBBoxStruct *BBox)
{
    if (BBox == NULL)
	return;

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a BBox structure list:				     M
*                                                                            *
* PARAMETERS:                                                                M
*   BBoxList:  To be deallocated.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdBBoxFreeList, free                                                   M
*****************************************************************************/
void CagdBBoxFreeList(CagdBBoxStruct *BBoxList)
{
    CagdBBoxStruct *BBoxTemp;

    while (BBoxList) {
	BBoxTemp = BBoxList -> Pnext;
	CagdBBoxFree(BBoxList);
	BBoxList = BBoxTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees an array of BBox structure.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   BBoxArray:    To be deallocated.                                         M
*   Size:         Of the deallocated array.                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdBBoxArrayFree, free                                                  M
*****************************************************************************/
void CagdBBoxArrayFree(CagdBBoxStruct *BBoxArray, int Size)
{
    int i;

    for (i = 0; i < Size; i++)
	AttrFreeAttributes(&BBoxArray[i].Attr);

    IritFree((VoidPtr) BBoxArray);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a polyline structure.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Poly:       To be deallocated.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPolylineFree, free                                                   M
*****************************************************************************/
void CagdPolylineFree(CagdPolylineStruct *Poly)
{
    if (Poly == NULL)
	return;

    IritFree((VoidPtr) Poly -> Polyline);
    AttrFreeAttributes(&Poly -> Attr);
    IritFree((VoidPtr) Poly);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a polyline structure list:			     M
*                                                                            *
* PARAMETERS:                                                                M
*   PolyList:  To be deallocated.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPolylineFreeList, free                                               M
*****************************************************************************/
void CagdPolylineFreeList(CagdPolylineStruct *PolyList)
{
    CagdPolylineStruct *PolyTemp;

    while (PolyList) {
	PolyTemp = PolyList -> Pnext;
	CagdPolylineFree(PolyList);
	PolyList = PolyTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees all slots of a polygon structure.	             M
*                                                                            *
* PARAMETERS:                                                                M
*   Poly:       To be deallocated.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPolygonFree, free                                                    M
*****************************************************************************/
void CagdPolygonFree(CagdPolygonStruct *Poly)
{
    if (Poly == NULL)
	return;

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

/*****************************************************************************
* DESCRIPTION:                                                               M
* Deallocates and frees a polygon structure list:			     M
*                                                                            *
* PARAMETERS:                                                                M
*   PolyList:  To be deallocated.                                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPolygonFreeList, free                                                M
*****************************************************************************/
void CagdPolygonFreeList(CagdPolygonStruct *PolyList)
{
    CagdPolygonStruct *PolyTemp;

    while (PolyList) {
	PolyTemp = PolyList -> Pnext;
	CagdPolygonFree(PolyList);
	PolyList = PolyTemp;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Reverses a list of cagd library objects, in place.                         M
*                                                                            *
* PARAMETERS:                                                                M
*   List:       To be reversed.                                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   VoidPtr:    Reversed list.                                               M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdListReverse, reverse                                                 M
*****************************************************************************/
VoidPtr CagdListReverse(VoidPtr List)
{
    CagdGenericStruct
	*OldHead = (CagdGenericStruct *) List,
	*NewHead = NULL;

    while (OldHead) {
	CagdGenericStruct
	    *TmpStruct = OldHead -> Pnext;

	OldHead -> Pnext = NewHead;
	NewHead = OldHead;

	OldHead = TmpStruct;
    }

    return (VoidPtr) NewHead;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Returns the last element of given list of cagd library objects.            M
*                                                                            *
* PARAMETERS:                                                                M
*   List:       To return its last element,                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   VoidPtr:    Last element.                                                M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdListLast		                                             M
*****************************************************************************/
VoidPtr CagdListLast(VoidPtr List)
{
    CagdGenericStruct
	*Head = (CagdGenericStruct *) List;

    if (Head == NULL)
	return NULL;

    for ( ; Head -> Pnext != NULL; Head = Head -> Pnext);

    return (VoidPtr) Head;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Inserts a new element NewElement into an ordered list List.  Ordering    M
* is prescribed by CompFunc.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   List:        The list to update, in place. Can be empty list.	     M
*   NewElement:  New element to insert, in place into List.		     M
*   CompFunc:    A comparison function.  Gets two elements of the list and   M
*		 compare and return a positive, zero, or negative values     M
*		 if first elements is smaller, equal, larger than second     M
*		 element, strcmp style.					     M
*   InsertEqual: If TRUE, a new item that is found to be equal to an item in M
*		 the list will be insert anyway. If FALSE, NULL is returned  M
*		 and no modification is made to the list, if equal.	     M
*                                                                            *
* RETURN VALUE:                                                              M
*   VoidPtr:	 The updated list.  NULL if !InsertEqual and found equality. M
*		 If NULL is returned, no modification was made to List.      M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdListInsert                                                           M
*****************************************************************************/
VoidPtr CagdListInsert(VoidPtr List,
		       VoidPtr NewElement,
		       CagdCompFuncType CompFunc,
		       CagdBType InsertEqual)
{
    int CompVal;
    CagdGenericStruct
	*GList = (CagdGenericStruct *) List,
	*GNewElement = (CagdGenericStruct *) NewElement;

    if (GList == NULL)
        GList = GNewElement;
    else if ((CompVal = CompFunc(GList, GNewElement)) > 0 ||
	     (CompVal == 0 && InsertEqual)) {
	/* Put new element as first. */
	GNewElement -> Pnext = GList;
	GList = GNewElement;
    }
    else if (CompVal == 0 && !InsertEqual) {
	return NULL;
    }
    else {
	CagdGenericStruct
	    *Last = GList,
	    *Trace = Last -> Pnext;

	while (Trace != NULL && CompFunc(Trace, GNewElement) < 0) {
	    Last = Trace;
	    Trace = Last -> Pnext;
	}

	if (Trace != NULL &&
	    CompFunc(Trace, GNewElement) == 0 &&
	    !InsertEqual)
	    return NULL;
	else {
	    Last -> Pnext = GNewElement;
	    GNewElement -> Pnext = Trace;
	}
    }

    return (VoidPtr) GList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Computes the length of a list.                                             M
*                                                                            *
* PARAMETERS:                                                                M
*   List:          List of cagd objects.                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:           Length of list.                                           M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdListLength                                                           M
*****************************************************************************/
int CagdListLength(VoidPtr List)
{
    CagdGenericStruct
	*Head = (CagdGenericStruct *) List;
    int i;

    for (i = 0; Head != NULL; Head = Head -> Pnext, i++);

    return i;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Appends two lists, in place.	                                             M
*                                                                            *
* PARAMETERS:                                                                M
*   List1, List2:  Two lists of cagd objects to append, in place.            M
*                                                                            *
* RETURN VALUE:                                                              M
*   VoidPtr:       Appended list.                                            M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdListAppend                                                           M
*****************************************************************************/
VoidPtr CagdListAppend(VoidPtr List1, VoidPtr List2)
{
    CagdGenericStruct
	*Head1 = (CagdGenericStruct *) List1;

    if (Head1 == NULL)
	return List2;

    for ( ; Head1 -> Pnext != NULL; Head1 = Head1 -> Pnext);
    Head1 -> Pnext = (CagdGenericStruct *) List2;

    return List1;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Applies an affine transform, in place, to given curve Crv as specified by  M
* Translate and Scale.							     M
*   Each control point is first translated by Translate and then scaled by   M
* Scale.		                                                     M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:         To be affinely transformed.                                 M
*   Translate:   Translation amount.                                         M
*   Scale:       Scaling amount.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   CagdSrfTransform, CagdTransform, CagdCrvMatTransform                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdCrvTransform, scaling, translation, transformations                  M
*****************************************************************************/
void CagdCrvTransform(CagdCrvStruct *Crv,
		      CagdRType *Translate,
		      CagdRType Scale)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	case CAGD_CBSPLINE_TYPE:
    	    CagdTransform(Crv -> Points,
			  Crv -> Length,
    			  CAGD_NUM_OF_PT_COORD(Crv -> PType),
    			  !CAGD_IS_RATIONAL_CRV(Crv),
			  Translate,
			  Scale);

	    break;
	case CAGD_CPOWER_TYPE:
	    CAGD_FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    CAGD_FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Applies an affine transform, in place, to given surface Srf as specified   M
* by Translate and Scale.						     M
*   Each control point is first translated by Translate and then scaled by   M
* Scale.		                                                     M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:         To be affinely transformed.                                 M
*   Translate:   Translation amount.                                         M
*   Scale:       Scaling amount.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   CagdCrvTransform, CagdTransform, CagdSrfMatTransform                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdSrfTransform, scaling, translation, transformations                  M
*****************************************************************************/
void CagdSrfTransform(CagdSrfStruct *Srf,
		      CagdRType *Translate,
		      CagdRType Scale)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	case CAGD_SBSPLINE_TYPE:
	    CagdTransform(Srf -> Points,
	    		  Srf -> ULength * Srf -> VLength,
	                  CAGD_NUM_OF_PT_COORD(Srf -> PType),
			  !CAGD_IS_RATIONAL_SRF(Srf),
		          Translate,
        	          Scale);
	    break;
	case CAGD_SPOWER_TYPE:
	    CAGD_FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    CAGD_FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Applies an affine transform, in place, to given set of points Points which M
* as array of vectors, each vector of length Len.                            M
*   Array Points optionally contains (if !IsNotRational) in Points[0] the    M
* weights coefficients and in Points[i] the coefficients of axis i, up to    M
* and include MaxCoord (X = 1, Y = 2, etc.).				     M
* Points are translated and scaled as prescribed by Translate and Scale.     M
*   Each control point is first translated by Translate and then scaled by   M
* Scale.		                                                     M
*                                                                            *
* PARAMETERS:                                                                M
*   Points:         To be affinely transformed. Array of vectors.            M
*   Len:            Of vectors of Points.                                    M
*   MaxCoord:       Maximum number of coordinates to be found in Points.     M
*   IsNotRational:  Do we have weights as vector Points[0]?                  M
*   Translate:      Translation amount.                                      M
*   Scale:          Scaling amount.                                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   CagdSrfTransform, CagdCrvTransform			                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdTransform, scaling, translation, transformations                     M
*****************************************************************************/
void CagdTransform(CagdRType **Points,
		   int Len,
		   int MaxCoord,
		   CagdBType IsNotRational,
		   CagdRType *Translate,
		   CagdRType Scale)
{
    int i, j;

    if (IsNotRational)
	for (i = 1; i <= MaxCoord; i++)
	    for (j = 0; j < Len; j++)
		Points[i][j] = (Points[i][j] + Translate[i - 1]) * Scale;
    else
	for (i = 1; i <= MaxCoord; i++)
	    for (j = 0; j < Len; j++)
		Points[i][j] = (Points[i][j] +
				Translate[i - 1] * Points[W][j]) * Scale;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Applies an homogeneous transformation, in place, to the given curve Crv as M
* specified by homogeneous transformation Mat.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:       To be transformed.                                            M
*   Mat:       Defining the transformation.                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   CagdTransform, CagdSrfMatTransform, CagdMatTransform                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdCrvMatTransform, scaling, rotation, translation, transformations     M
*****************************************************************************/
void CagdCrvMatTransform(CagdCrvStruct *Crv, CagdMType Mat)
{
    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	case CAGD_CBSPLINE_TYPE:
	    switch (Crv -> PType) {               /* Make sure input is 3D. */
		case CAGD_PT_E2_TYPE:
		case CAGD_PT_P2_TYPE:
		    {
			int i,
			    Len = Crv -> Length;

			Crv -> Points[3] =
			    (CagdRType *) IritMalloc(sizeof(CagdRType) * Len);

			for (i = 0; i < Len; i++)
			    Crv -> Points[3][i] = 0.0;
			Crv -> PType = (Crv -> PType == CAGD_PT_E2_TYPE ?
					CAGD_PT_E3_TYPE : CAGD_PT_P3_TYPE);
			break;
		    }
		case CAGD_PT_E3_TYPE:
		case CAGD_PT_P3_TYPE:
		    break;
		default:
		    CAGD_FATAL_ERROR(CAGD_ERR_ONLY_2D_OR_3D);
		    return;
	    }

	    CagdMatTransform(Crv -> Points,
    			     Crv -> Length,
                	     CAGD_NUM_OF_PT_COORD(Crv -> PType),
			     !CAGD_IS_RATIONAL_CRV(Crv),
		             Mat);
	    break;
	case CAGD_CPOWER_TYPE:
	    CAGD_FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    CAGD_FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Applies an homogeneous transformation, in place, to the given surface Srf  M
* as specified by homogeneous transformation Mat.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   Srf:       To be transformed.                                            M
*   Mat:       Defining the transformation.                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   CagdTransform, CagdCrvMatTransform, CagdMatTransform                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdSrfMatTransform, scaling, rotation, translation, transformations     M
*****************************************************************************/
void CagdSrfMatTransform(CagdSrfStruct *Srf, CagdMType Mat)
{
    switch (Srf -> GType) {
	case CAGD_SBEZIER_TYPE:
	case CAGD_SBSPLINE_TYPE:
	    switch (Srf -> PType) {               /* Make sure input is 3D. */
		case CAGD_PT_E2_TYPE:
		case CAGD_PT_P2_TYPE:
		    {
			int i,
			Len = Srf -> ULength * Srf ->VLength;

			Srf -> Points[3] =
			    (CagdRType *) IritMalloc(sizeof(CagdRType) * Len);

			for (i = 0; i < Len; i++)
			    Srf -> Points[3][i] = 0.0;
			Srf -> PType = (Srf -> PType == CAGD_PT_E2_TYPE ?
					CAGD_PT_E3_TYPE : CAGD_PT_P3_TYPE);
			break;
		    }
		case CAGD_PT_E3_TYPE:
		case CAGD_PT_P3_TYPE:
		    break;
		default:
		    CAGD_FATAL_ERROR(CAGD_ERR_ONLY_2D_OR_3D);
		    return;
	    }
	    CagdMatTransform(Srf -> Points,
    			     Srf -> ULength * Srf -> VLength,
        	             CAGD_NUM_OF_PT_COORD(Srf -> PType),
			     !CAGD_IS_RATIONAL_SRF(Srf),
		             Mat);
	    break;
	case CAGD_SPOWER_TYPE:
	    CAGD_FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    break;
	default:
	    CAGD_FATAL_ERROR(CAGD_ERR_UNDEF_SRF);
	    break;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Applies an homogeneous transformation, in place, to given set of points    M
* Points which as array of vectors, each vector of length Len.               M
*   Array Points optionally contains (if !IsNotRational) in Points[0] the    M
* weights coefficients and in Points[i] the coefficients of axis i, up to    M
* and include MaxCoord (X = 1, Y = 2, etc.).				     M
*                                                                            *
* PARAMETERS:                                                                M
*   Points:         To be affinely transformed. Array of vectors.            M
*   Len:            Of vectors of Points.                                    M
*   MaxCoord:       Maximum number of coordinates to be found in Points.     M
*   IsNotRational:  Do we have weights as vector Points[0]?                  M
*   Mat:       Defining the transformation.                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* SEE ALSO:                                                                  M
*   CagdTransform, CagdSrfMatTransform, CagdCrvMatTransform                  M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdMatTransform, scaling, rotation, translation, transformations        M
*****************************************************************************/
void CagdMatTransform(CagdRType **Points,
		      int Len,
		      int MaxCoord,
		      CagdBType IsNotRational,
		      CagdMType Mat)
{
    int i, j;
    CagdRType P[4], Q[4];

    if (MaxCoord > 3)
	MaxCoord = 3;

    if (IsNotRational)
	for (i = 0; i < Len; i++) {
	    for (j = 1; j <= MaxCoord; j++)
		P[j - 1] = Points[j][i];

	    /* Zero unused coords. */
	    for (j = MaxCoord + 1; j < 3; j++)
		P[j - 1] = 0.0;

            MatMultVecby4by4(Q, P, Mat);

	    for (j = 1; j <= MaxCoord; j++)
		Points[j][i] = Q[j - 1];
        }
    else
	for (i = 0; i < Len; i++) {
	    for (j = 1; j <= MaxCoord; j++)
		P[j - 1] = Points[j][i];
	    P[3] = Points[W][i];

	    /* Zero unused coords. */
	    for (j = MaxCoord + 1; j < 3; j++)
		P[j - 1] = 0.0;

            MatMultWVecby4by4(Q, P, Mat);

	    for (j = 1; j <= MaxCoord; j++)
		Points[j][i] = Q[j - 1];
	    Points[W][i] = Q[3];
        }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Returns TRUE if the given control points have poles - that is have both  M
* negative and positive weights.					     N
*                                                                            *
* PARAMETERS:                                                                M
*   Points:      Control points to consider.                                 M
*   Len:         Number of points in Points.                                 M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdBType:   TRUE if has poles, FALSE otherwise.                         M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPointsHasPoles                                                       M
*****************************************************************************/
CagdBType CagdPointsHasPoles(CagdRType **Points, int Len)
{
    int i;
    CagdRType
	*Weights = Points[0];
    CagdBType
	Positive = FALSE,
	Negative = FALSE;

    if (Weights == NULL)
	return FALSE;

    for (i = 0; i < Len; i++, Weights++) {
	if (*Weights > 0)
	    Positive = TRUE;
	if (*Weights < 0)
	    Negative = TRUE;
    }

    return Positive & Negative;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Sets the polygon approximation error function.  The error function       M
* will return a negative value if this triangle must be purged or otherwise  M
* a non negative error measure.                                              M
*                                                                            *
* PARAMETERS:                                                                M
*   Func:        New function to use, NULL to disable.                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdPlErrorFuncType:  Old value of function.                             M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPolygonSetErrFunc                                                    M
*****************************************************************************/
CagdPlgErrorFuncType CagdPolygonSetErrFunc(CagdPlgErrorFuncType Func)
{
    CagdPlgErrorFuncType
	OldFunc = PolygonErrFunc;

    PolygonErrFunc = Func;

    return OldFunc;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to create one triangular polygon, given its vertices.		     *
* Returns NULL if Triangle is degenerated.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   ComputeNormals:   If TRUE then use Nl? parameters. Nl? are valid.        *
*   ComputeUV:        If TRUE then use UV? parameters. UV? are valid.        *
*   Pt1, Pt2, Pt3:    Euclidean locations of vertices.                       *
*   Nl1, Nl2, Nl3:    Optional Normals of vertices (if ComputeNormals).      *
*   UV1, UV2, UV3:    Optional UV parametric location of vertices (if        *
*                     ComputeUV).                                            *
*                                                                            *
* RETURN VALUE:                                                              *
*   CagdPolygonStruct *:  A polygonal triangle structure, or NULL if points  *
*                         are colinear.                                      *
*                                                                            *
* KEYWORDS:                                                                  *
*   _CagdMakePolygon                                                         *
*****************************************************************************/
CagdPolygonStruct *_CagdMakePolygon(CagdBType ComputeNormals,
				    CagdBType ComputeUV,
				    CagdPtStruct *Pt1,
				    CagdPtStruct *Pt2,
				    CagdPtStruct *Pt3,
				    CagdVecStruct *Nl1,
				    CagdVecStruct *Nl2,
				    CagdVecStruct *Nl3,
				    CagdUVStruct *UV1,
				    CagdUVStruct *UV2,
				    CagdUVStruct *UV3)
{
    CagdPolygonStruct *Poly;

    if (GMColinear3Pts(Pt1 -> Pt, Pt2 -> Pt, Pt3 -> Pt) ||
	(PolygonErrFunc != NULL &&
	 PolygonErrFunc(Pt1 -> Pt, Pt2 -> Pt, Pt3 -> Pt) < 0.0))
	return NULL;

    Poly = CagdPolygonNew();

    PT_COPY(Poly -> Polygon[0].Pt, Pt1 -> Pt);
    PT_COPY(Poly -> Polygon[1].Pt, Pt2 -> Pt);
    PT_COPY(Poly -> Polygon[2].Pt, Pt3 -> Pt);

    if (ComputeNormals) {
	PT_COPY(Poly -> Polygon[0].Nrml, Nl1 -> Vec);
	PT_COPY(Poly -> Polygon[1].Nrml, Nl2 -> Vec);
	PT_COPY(Poly -> Polygon[2].Nrml, Nl3 -> Vec);
    }
    else {
	PT_RESET(Poly -> Polygon[0].Nrml);
	PT_RESET(Poly -> Polygon[1].Nrml);
	PT_RESET(Poly -> Polygon[2].Nrml);
    }

    if (ComputeUV) {
	UV_COPY(Poly -> Polygon[0].UV, UV1 -> UV);
	UV_COPY(Poly -> Polygon[1].UV, UV2 -> UV);
	UV_COPY(Poly -> Polygon[2].UV, UV3 -> UV);
    }
    else {
	UV_RESET(Poly -> Polygon[0].UV);
	UV_RESET(Poly -> Polygon[1].UV);
	UV_RESET(Poly -> Polygon[2].UV);
    }

    return Poly;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Sets the way (co)linear surfaces are converted into polygons.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Lin2Poly:  Specification.                                                M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdSetLinear2Poly, polygonization, polygonal approximation              M
*****************************************************************************/
void CagdSetLinear2Poly(CagdLin2PolyType Lin2Poly)
{
    _CagdLin2Poly = Lin2Poly;
}
