/*****************************************************************************
*   "Irit" - the 3d (not only polygonal) solid modeller.		     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
******************************************************************************
*   Module to provide the required interfact for the cagd library for the    *
* free form surfaces and curves.					     *
*****************************************************************************/

#include <stdio.h>
#include <math.h>
#include "program.h"
#include "allocate.h"
#include "attribut.h"
#include "objects.h"
#include "primitiv.h"
#include "windows.h"
#include "ip_cnvrt.h"
#include "freeform.h"

static IPObjectStruct *GetControlTVMesh(IPObjectStruct *LstLstObjList,
					int UOrder,
					int VOrder,
					int WOrder,
					TrivGeomType GType,
					char **ErrStr);

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Construct a trimmed surfcae, given the parametric surface and its	     M
* trimming curves.							     M
*                                                                            *
* PARAMETERS:                                                                M
*   SrfObj:         To construct the trimmed surface with.                   M
*   TrimmedCrvsObj: To trim srf with. No real validity testing is performed. M
*		    Can be NULL Create a structure of trimmed surface,       M
*		    untrimmed.						     M
*   RHasTopLvlTrim: TRUE if needs to add a top level rectangular boundary.   M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A trimmed surface object.                            M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenTrimmedSurface                                                        M
*****************************************************************************/
IPObjectStruct *GenTrimmedSurface(IPObjectStruct *SrfObj,
				  IPObjectStruct *TrimmedCrvsObj,
				  RealType *RHasTopLvlTrim)
{
    CagdCrvStruct
	*Crvs = NULL;
    CagdBType
	HasTopLvlTrim = REAL_PTR_TO_INT(RHasTopLvlTrim);

    if (IP_IS_CRV_OBJ(TrimmedCrvsObj)) {
	Crvs = CagdCrvCopyList(TrimmedCrvsObj -> U.Crvs);
    }
    else if (IP_IS_OLST_OBJ(TrimmedCrvsObj)) {
	int NumCrvs = 0;
	IPObjectStruct *CrvObj;

	while ((CrvObj = ListObjectGet(TrimmedCrvsObj, NumCrvs++)) != NULL) {
	    CagdCrvStruct *Crv;

	    if (!IP_IS_CRV_OBJ(CrvObj)) {
		IritPrsrFatalError("Non curve object as a trimmed curve");
		return NULL;
	    }

	    Crv = CagdCrvCopy(CrvObj -> U.Crvs);
	    LIST_PUSH(Crv, Crvs);
	}
    }

    return GenTRIMSRFObject(TrimSrfNew2(CagdSrfCopy(SrfObj -> U.Srfs),
					Crvs, HasTopLvlTrim));
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Extracts the parametric surface of a trimmed surface.                    M
*                                                                            *
* PARAMETERS:                                                                M
*   TrimmedSrfObj:   To extract parametric surface from.                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:    Extracted parametric surface.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetSrfFromTrimmedSrf                                                     M
*****************************************************************************/
IPObjectStruct *GetSrfFromTrimmedSrf(IPObjectStruct *TrimmedSrfObj)
{
    return GenSRFObject(CagdSrfCopy(TrimmedSrfObj -> U.TrimSrfs -> Srf));
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Extracts trimming curves of trimming surface, either in parametric or    M
* Euclidean space.                                                           M
*                                                                            *
* PARAMETERS:                                                                M
*   TrimmedSrfObj:   To extract trimming curves from.                        M
*   RParamSpace:     TRUE for parametric space, FALSE for Euclidean space.   M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Extracted trimming curves.                           M
*                                                                            *
* KEYWORDS:                                                                  M
*   GetTrimCrvsFromTrimmedSrf                                                M
*****************************************************************************/
IPObjectStruct *GetTrimCrvsFromTrimmedSrf(IPObjectStruct *TrimmedSrfObj,
					  RealType *RParamSpace)
{
    int Count = 0,
	ParamSpace = REAL_PTR_TO_INT(RParamSpace);
    CagdCrvStruct
	*Crvs = TrimGetTrimmingCurves(TrimmedSrfObj -> U.TrimSrfs, ParamSpace);
    IPObjectStruct
	*ListObj = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);

    while (Crvs) {
	CagdCrvStruct
	    *Crv = Crvs;

	Crvs = Crvs -> Pnext;
	Crv -> Pnext = NULL;
	ListObjectInsert(ListObj, Count++, GenCRVObject(Crv));
    }

    ListObjectInsert(ListObj, Count, NULL);
    return ListObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Routine to copy the control mesh lists to a trivariate control mesh.       *
*   The trivariate is allocated here as well.				     *
*   Returns the trivariate if o.k., otherwise NULL.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   LstLstObjList:  A list object of lists of lists of control points.       *
*   UOrder:     U order of trivar.                                           *
*   VOrder:     V order of trivar.                                           *
*   WOrder:     V order of trivar.                                           *
*   GType:      Geometry type - Bezier, Bspline etc.                         *
*   ErrStr:     If an error, detected, this is initialized with description. *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPObjectStruct *:   A trivar object if successful, NULL otherwise.       *
*****************************************************************************/
static IPObjectStruct *GetControlTVMesh(IPObjectStruct *LstLstObjList,
					int UOrder,
					int VOrder,
					int WOrder,
					TrivGeomType GType,
					char **ErrStr)
{
    int i, j, k, l, PtSize, NumPlane,
	NumVertices = 0,
	NumVerticesFirst = -1,
        NumLists = 0,
	NumListsFirst = -1,
        NumListLists = 0;
    CagdRType **r;
    RealType *v;
    IPObjectStruct *TrivarObj, *LstObjList, *ObjList, *PtObj;
    CagdPointType
	PtType = CAGD_PT_E1_TYPE;

    while ((LstObjList = ListObjectGet(LstLstObjList, NumListLists)) != NULL) {
	if (!IP_IS_OLST_OBJ(LstObjList)) {
	    *ErrStr = "Non list object found in list";
	    return NULL;
	}

	while ((ObjList = ListObjectGet(LstObjList, NumLists)) != NULL) {
	    if (!IP_IS_OLST_OBJ(ObjList)) {
		*ErrStr = "Non list object found in list";
		return NULL;
	    }

	    NumVertices = -1;
	    while ((PtObj = ListObjectGet(ObjList, ++NumVertices)) != NULL) {
		if (!IP_IS_CTLPT_OBJ(PtObj) &&
		    !IP_IS_POINT_OBJ(PtObj) &&
		    !IP_IS_VEC_OBJ(PtObj)) {
		    *ErrStr = "Non point object found in list";
		    return NULL;
		}
	    }
	    if ((PtType = IritPrsrCoerceCommonSpace(ObjList, PtType)) ==
								CAGD_PT_NONE) {
		*ErrStr = "";
		return NULL;
	    }

	    if (NumLists++ == 0 && NumListLists == 0)
		NumVerticesFirst = NumVertices;
	    else if (NumVerticesFirst != NumVertices) {
		*ErrStr = "Different size of point lists";
		return NULL;
	    }
	}

	if (NumListLists++ == 0)
	    NumListsFirst = NumLists;
	else if (NumListsFirst != NumLists) {
	    *ErrStr = "Different size of list lists";
	    return NULL;
	}
    }

    /* Coerce all points to a common space, in place. */
    while ((LstObjList = ListObjectGet(LstLstObjList, NumListLists)) != NULL)
	while ((ObjList = ListObjectGet(LstObjList, NumLists)) != NULL)
	    if (IritPrsrCoercePtsListTo(ObjList, PtType) == CAGD_PT_NONE) {
		*ErrStr = "";
		return NULL;
	    }

    if (NumVertices < 2 || NumLists < 2 || NumListLists < 2) {
	*ErrStr = "Less than 2 points in a row/col/depth";
	return NULL;
    }

    TrivarObj = GenTRIVARObject(NULL);
    switch (GType) {
	case TRIV_TVBEZIER_TYPE:
	    TrivarObj -> U.Trivars = TrivBzrTVNew(NumVertices, NumLists,
						  NumListLists, PtType);
	    break;
	case TRIV_TVBSPLINE_TYPE:
	    TrivarObj -> U.Trivars = TrivBspTVNew(NumVertices, NumLists,
						  NumListLists, UOrder,
						  VOrder, WOrder, PtType);
	    break;
	default:
	    break;
    }
    AttrSetObjectColor(TrivarObj, GlblPrimColor);  /* Set its default color. */
    PtSize = CAGD_IS_RATIONAL_PT(PtType) + CAGD_NUM_OF_PT_COORD(PtType);

    NumPlane = NumVertices * NumLists;
    for (r = TrivarObj -> U.Trivars -> Points, i = 0; i < NumListLists; i++) {
	LstObjList = ListObjectGet(LstLstObjList, i);

        for (j = 0; j < NumLists; j++) {
	    IPObjectStruct
		*ObjList = ListObjectGet(LstObjList, j);

	    for (k = 0; k < NumVertices; k++) {
		IPObjectStruct
		    *VObj = ListObjectGet(ObjList, k);

		v = VObj -> U.CtlPt.Coords;

		if (CAGD_IS_RATIONAL_PT(PtType))
		    for (l = 0; l < PtSize; l++)
			r[l][i * NumPlane + j * NumVertices + k] = *v++;
		else
		    for (l = 1; l <= PtSize; l++)
			r[l][i * NumPlane + j * NumVertices + k] = *++v;
	    }
	}
    }

    return TrivarObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to create a Bezier trivar geometric object defined by a list of  M
* lists of lists of control points.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   LstLstObjList: A list object of lists of lists of control points.        M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *: A Bezier trivar object if successful, NULL otherwise.  M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenBezierTrivarObject                                                    M
*****************************************************************************/
IPObjectStruct *GenBezierTrivarObject(IPObjectStruct *LstLstObjList)
{
    char *ErrStr, Line[LINE_LEN];
    IPObjectStruct
	*TrivObj = GetControlTVMesh(LstLstObjList, -1, -1, -1,
				    TRIV_TVBEZIER_TYPE, &ErrStr);

    if (TrivObj == NULL) {
	sprintf(Line, "TBEZIER: %s, empty object result.\n", ErrStr);
	IritPrsrFatalError(Line);
    }

    return TrivObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to create a Bspline trivar geometric object defined by a list    M
* of lists of lists of control points.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   RUOrder:     U order of trivar.                                          M
*   RVOrder:     V order of trivar.                                          M
*   RWOrder:     W order of trivar.                                          M
*   LstObjList:  A list object of lists of control points.                   M
*   KntObjList:  A list of knots (numeric values).                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *: A Bspline trivar object if successful, NULL otherwise. M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenBsplineTrivarObject                                                   M
*****************************************************************************/
IPObjectStruct *GenBsplineTrivarObject(RealType *RUOrder,
				       RealType *RVOrder,
				       RealType *RWOrder,
				       IPObjectStruct *LstLstObjList,
				       IPObjectStruct *KntObjList)
{
    int Len1, Len2, Len3,
	UOrder = REAL_PTR_TO_INT(RUOrder),
	VOrder = REAL_PTR_TO_INT(RVOrder),
	WOrder = REAL_PTR_TO_INT(RWOrder);
    char *ErrStr, Line[LINE_LEN];
    IPObjectStruct
	*TrivObj = GetControlTVMesh(LstLstObjList, UOrder, VOrder, WOrder,
				    TRIV_TVBSPLINE_TYPE, &ErrStr);

    if (TrivObj == NULL) {
	sprintf(Line, "TBSPLINE: Ctl mesh, %s, empty object result.\n", ErrStr);
	IritPrsrFatalError(Line);
	return NULL;
    }

    if (!IP_IS_OLST_OBJ(KntObjList) || ListObjectLength(KntObjList) != 3) {
	IPFreeObject(TrivObj);
	IritPrsrFatalError("TBSPLINE: Exactly three knot vectors expected");
	return NULL;
    }

    if (TrivObj -> U.Trivars -> ULength < TrivObj -> U.Trivars -> UOrder ||
	TrivObj -> U.Trivars -> VLength < TrivObj -> U.Trivars -> VOrder ||
	TrivObj -> U.Trivars -> WLength < TrivObj -> U.Trivars -> WOrder) {
	IPFreeObject(TrivObj);
	IritPrsrFatalError("TBSPLINE: Trivar mesh length smaller than order.");
	return NULL;
    }

    IritFree((VoidPtr) TrivObj -> U.Trivars -> UKnotVector);
    TrivObj -> U.Trivars -> UKnotVector = NULL;
    IritFree((VoidPtr) TrivObj -> U.Trivars -> VKnotVector);
    TrivObj -> U.Trivars -> VKnotVector = NULL;
    IritFree((VoidPtr) TrivObj -> U.Trivars -> WKnotVector);
    TrivObj -> U.Trivars -> WKnotVector = NULL;
    Len1 = TrivObj -> U.Trivars -> ULength;
    Len2 = TrivObj -> U.Trivars -> VLength;
    Len3 = TrivObj -> U.Trivars -> WLength;
    if ((TrivObj -> U.Trivars -> UKnotVector =
	 GetKnotVector(ListObjectGet(KntObjList, 0), UOrder,
		       &Len1, &ErrStr)) == NULL ||
	(TrivObj -> U.Trivars -> VKnotVector =
	 GetKnotVector(ListObjectGet(KntObjList, 1), VOrder,
		       &Len2, &ErrStr)) == NULL ||
	(TrivObj -> U.Trivars -> WKnotVector =
	 GetKnotVector(ListObjectGet(KntObjList, 2), WOrder,
		       &Len3, &ErrStr)) == NULL) {
	sprintf(Line, "TBSPLINE: Knot vectors, %s, empty object result.\n",
		ErrStr);
	IPFreeObject(TrivObj);
	IritPrsrFatalError(Line);
	return NULL;
    }

    if (Len1 != TrivObj -> U.Trivars -> ULength + UOrder) {
	if (Len1 == TrivObj -> U.Trivars -> ULength + UOrder + UOrder - 1)
	    TrivObj -> U.Trivars -> UPeriodic = TRUE;
	else {
	    IPFreeObject(TrivObj);
	    IritPrsrFatalError("Wrong knot vector length");
	    return NULL;
	}
    }
    if (Len2 != TrivObj -> U.Trivars -> VLength + VOrder) {
	if (Len2 == TrivObj -> U.Trivars -> VLength + VOrder + VOrder - 1)
	    TrivObj -> U.Trivars -> VPeriodic = TRUE;
	else {
	    IPFreeObject(TrivObj);
	    IritPrsrFatalError("Wrong knot vector length");
	    return NULL;
	}
    }
    if (Len3 != TrivObj -> U.Trivars -> WLength + WOrder) {
	if (Len3 == TrivObj -> U.Trivars -> WLength + WOrder + WOrder - 1)
	    TrivObj -> U.Trivars -> WPeriodic = TRUE;
	else {
	    IPFreeObject(TrivObj);
	    IritPrsrFatalError("Wrong knot vector length");
	    return NULL;
	}
    }

    return TrivObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Evaluate a trivariate function, at the prescribed parametric location.   M
*                                                                            *
* PARAMETERS:                                                                M
*   TVObj:    Trivariate to evaluate.                                        M
*   u, v, w:  Parametric location to evaluate at.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A control point of the same type TV has.              M
*                                                                            *
* KEYWORDS:                                                                  M
*   EvalTrivarObject                                                         M
*****************************************************************************/
IPObjectStruct *EvalTrivarObject(IPObjectStruct *TVObj,
				 RealType *u,
				 RealType *v,
				 RealType *w)
{
    CagdRType
	*Pt = TrivTVEval(TVObj -> U.Trivars, *u, *v, *w);
    IPObjectStruct
	*CtlPtObj = GenCTLPTObject(TVObj -> U.Trivars -> PType, Pt, NULL);

    return CtlPtObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Extracts an isoparametric surface out of the trivariate.                 M
*                                                                            M
*                                                                            *
* PARAMETERS:                                                                M
*   TVObj:     Trivariate to extract surface from.                           M
*   RDir:      Direction of extarction. One of U, V, W.                      M
*   ParamVal:  Parameter value of trivariate.                                M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   An isoparametric surface.                            M
*                                                                            *
* KEYWORDS:                                                                  M
*   SurfaceFromTrivar                                                        M
*****************************************************************************/
IPObjectStruct *SurfaceFromTrivar(IPObjectStruct *TVObj,
				  RealType *RDir,
				  RealType *ParamVal)
{
    int Dir = REAL_PTR_TO_INT(RDir);

    CagdSrfStruct
	*Srf = TrivSrfFromTV(TVObj -> U.Trivars, *ParamVal, Dir);

    if (Srf == NULL)
	return NULL;

    return GenSRFObject(Srf);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to subdivide a trivariate function into two in specified direction M
* (1 or 2) and specified parameter value.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   TVObj:        Trivariate to subdivide.                                   M
*   RDir:         Direction of subdivision. Either U, V, or W.               M
*   ParamVal:     Parameter value at which subdivision should occur.         M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A list object of two trivar objects, result of the    M
*		       subdivision.					     M
*                                                                            *
* KEYWORDS:                                                                  M
*   DivideTrivarObject                                                       M
*****************************************************************************/
IPObjectStruct *DivideTrivarObject(IPObjectStruct *TVObj,
				    RealType *RDir,
				    RealType *ParamVal)
{
    int Dir = REAL_PTR_TO_INT(RDir);
    TrivTVStruct
	*TV = TrivTVSubdivAtParam(TVObj -> U.Trivars, *ParamVal, Dir);
    IPObjectStruct *TV1, *TV2, *TVList;

    if (TV == NULL)
	return NULL;

    TV1 = GenTRIVARObject(TV),
    AttrSetObjectColor(TV1, AttrGetObjectColor(TVObj));
    TV2 = GenTRIVARObject(TV -> Pnext),
    AttrSetObjectColor(TV2, AttrGetObjectColor(TVObj));
    TV -> Pnext = NULL;

    TVList = IPAllocObject("", IP_OBJ_LIST_OBJ, NULL);
    ListObjectInsert(TVList, 0, TV1);
    ListObjectInsert(TVList, 1, TV2);
    ListObjectInsert(TVList, 2, NULL);

    return TVList;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to extract a region of a trivariate in specified direction (1 or   M
* 2) and specified parameter values.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   TVObj:       Trivariate to extract a region from.                        M
*   RDir:        Direction of region extraction. Either U or V.              M
*   ParamVal1:   Parameter of beginning of region.                           M
*   ParamVal2:   Parameter of end of region.                                 M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:  A region of TVObj,                                    M
*                                                                            *
* KEYWORDS:                                                                  M
*   RegionFromTrivarObject                                                   M
*****************************************************************************/
IPObjectStruct *RegionFromTrivarObject(IPObjectStruct *TVObj, 
					RealType *RDir,
					RealType *ParamVal1,
					RealType *ParamVal2)
{
    int Dir = REAL_PTR_TO_INT(RDir);
    TrivTVStruct
	*TV = TrivTVRegionFromTV(TVObj -> U.Trivars,
				 *ParamVal1, *ParamVal2, Dir);

    if (TV == NULL)
	return NULL;

    TVObj = GenTRIVARObject(TV);

    return TVObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to refine a trivariate function in specified direction (1 or 2)    M
* and knot vector.							     M
*   If, however, Replace is non zero, KnotsObj REPLACES current vector.      M
*                                                                            *
* PARAMETERS:                                                                M
*   TVObj:      Trivariate to refine in direction RDir.                      M
*   RDir:       Direction of refinement. Either U or V,                      M
*   RReplace:   If TRUE KnotsObj will replace the RDir knot vector of TVObj. M
*		Otherwise, the knots in KnotsObj will be added to it.	     M
*   KnotsObj:   A list of knots.                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A refined trivar, or a trivar with a replaced knot   M
*                       vector.                                              M
*                                                                            *
* KEYWORDS:                                                                  M
*   RefineTrivarObject                                                       M
*****************************************************************************/
IPObjectStruct *RefineTrivarObject(IPObjectStruct *TVObj,
				    RealType *RDir,
				    RealType *RReplace,
				    IPObjectStruct *KnotsObj)
{
    int n,
	Replace = REAL_PTR_TO_INT(RReplace),
	Dir = REAL_PTR_TO_INT(RDir);
    char *ErrStr, Line[LINE_LEN];
    CagdRType
	*t = GetKnotVector(KnotsObj, 0, &n, &ErrStr);
    TrivTVStruct *RefTV;
    IPObjectStruct *RefTVObj;

    if (t == NULL) {
	IPFreeObject(TVObj);
	sprintf(Line, "REFINE: %s, empty object result.\n", ErrStr);
	IritPrsrFatalError(Line);
	return NULL;
    }
    RefTV = TrivTVRefineAtParams(TVObj -> U.Trivars, Dir, Replace, t, n);
    IritFree((VoidPtr) t);
    if (RefTV == NULL)
	return NULL;

    RefTVObj = GenTRIVARObject(RefTV),
    AttrSetObjectColor(RefTVObj, AttrGetObjectColor(TVObj));
    return RefTVObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to differentiate a trivariate function in Dir of SrfObj.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   SrfObj:    Trivar to differentiate.                                      M
*   Dir:       Direction of differentiation. Either U or V.                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A differentiated trivar.                             M
*                                                                            *
* KEYWORDS:                                                                  M
*   DeriveTrivarObject                                                       M
*****************************************************************************/
IPObjectStruct *DeriveTrivarObject(IPObjectStruct *TVObj, RealType *Dir)
{
    TrivTVStruct
	*DerivTV = TrivTVDerive(TVObj -> U.Trivars, REAL_PTR_TO_INT(Dir));
    IPObjectStruct
	*DerivTVObj = GenTRIVARObject(DerivTV);

    return DerivTVObj;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Interpolates a three dimensional grid.                                   M
*                                                                            *
* PARAMETERS:                                                                M
*   TVObj:     Trivariate to interpolate its control points.                 M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   Interpolating trivar, with same order as original.   M
*                                                                            *
* KEYWORDS:                                                                  M
*   InterpolateTrivar                                                        M
*****************************************************************************/
IPObjectStruct *InterpolateTrivar(IPObjectStruct *TVObj)
{
    TrivTVStruct
	*NewTV = TrivInterpTrivar(TVObj -> U.Trivars);

    if (NewTV == NULL)
	return NULL;

    return GenTRIVARObject(NewTV);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Computes moments of freeform curves.                                     M
*                                                                            *
* PARAMETERS:                                                                M
*   CrvObj:    Curve to compute moment for.                                  M
*   RMoment:   Order of moment.                                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   An E3 vector representing the approximated moment.   M
*                                                                            *
* KEYWORDS:                                                                  M
*   ComputeCrvMoments, moments                                               M
*****************************************************************************/
IPObjectStruct *ComputeCrvMoments(IPObjectStruct *CrvObj, RealType *RMoment)
{
    CagdPType Pt;
    CagdVType Vec;
    int Moment = REAL_PTR_TO_INT(RMoment);

    CagdCrvFirstMoments(CrvObj -> U.Crvs, 100, Pt, Vec);

    switch (Moment) {
	case 0:
	    return GenPTObject(&Pt[0], &Pt[1], &Pt[2]);
	case 1:
	    return GenVECObject(&Vec[0], &Vec[1], &Vec[2]);
	default:
	    IritPrsrFatalError("Moment: Only moments of order zero or one");
	    return NULL;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Construct a trivariate out of the provided surface list.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   CrvList:     A list of surfaces to approximate a trivariate through.     M
*   OtherOrder:  Other, third, order of trivariate.                          M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPObjectStruct *:   A trivariate approximately traversing through the    M
*			given surfaces.                                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   GenTVFromSrfsObject                                                      M
*****************************************************************************/
IPObjectStruct *GenTVFromSrfsObject(IPObjectStruct *SrfList,
				    RealType *OtherOrder)
{
    int i,
	NumSrfs = 0;
    IPObjectStruct *TVObj, *SrfObj, *PrevSrfObj, *HeadSrfObj;
    TrivTVStruct *TV;
    CagdSrfStruct *Srf,
	*Srfs = NULL;


    if (!IP_IS_OLST_OBJ(SrfList))
	IritFatalError("TFROMSRF: Not object list object!");

    while ((SrfObj = ListObjectGet(SrfList, NumSrfs)) != NULL) {
	if (!IP_IS_SRF_OBJ(SrfObj)) {
	    IritFatalError("TFROMSRF: List contains non surface object(s).");
	    return NULL;
	}
	if (SrfObj -> U.Srfs -> Pnext != NULL) {
	    IritFatalError("TFROMSRF: nested surface lists are disallowed.");
	    return NULL;
	}
	NumSrfs++;
    }

    /* Chain all surfaces into a single list and invoke the TV constructor: */
    HeadSrfObj = PrevSrfObj = ListObjectGet(SrfList, 0);
    for (i = 0; i < NumSrfs; i++) {
	SrfObj = ListObjectGet(SrfList, i);
	Srf = CagdSrfCopy(SrfObj -> U.Srfs);
	LIST_PUSH(Srf, Srfs);
    }

    Srfs = CagdListReverse(Srfs);
    TV = TrivTVFromSrfs(Srfs, REAL_PTR_TO_INT(OtherOrder));
    CagdSrfFreeList(Srf);

    if (TV == NULL)
	return NULL;

    TVObj = GenTRIVARObject(TV);

    return TVObj;
}
