/******************************************************************************
* CagdCSrf.c - Construct a surface using a set of curves.                     *
*******************************************************************************
* Written by Gershon Elber, Sep. 91.					      *
******************************************************************************/

#include "cagd_loc.h"

/*****************************************************************************
* DESCRIPTION:                                                               M
* Constructs a surface using a set of curves. Curves are made to be	     M
* compatible and then each is substituted into the new surface's mesh as a   M
* row.									     M
*   If the OtherOrder is less than the number of curves, number of curves is M
* used.									     M
*   A knot vector is formed with uniform open end for the other direction,   M
* so it interpolates the first and last curves.			             M
*   Note, however, that only the first and the last curves are interpolated  M
* if OtherOrder is greater than 2.                                           M
*                                                                            *
* PARAMETERS:                                                                M
*   CrvList:      List of curves to consturct a surface with.                M
*   OtherOrder:   Other order of surface.				     M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdSrfStruct *:  Constructed surface from curves.                       M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdSrfFromCrvs, surface constructors                                    M
*****************************************************************************/
CagdSrfStruct *CagdSrfFromCrvs(CagdCrvStruct *CrvList, int OtherOrder)
{
    CagdBType IsNotRational;
    int i, j, NumCrvs, UOrder, VOrder, MaxCoord, Length;
    CagdRType **SrfPoints;
    CagdCrvStruct *Crv, **CrvVec;
    CagdSrfStruct *Srf;

    /* Find out how many curves we have and put them in a linear vector.     */
    /* Note the vector have a COPY of the curves so we can modify them.      */
    for (NumCrvs = 0, Crv = CrvList;
	 Crv != NULL;
	 NumCrvs++, Crv = Crv -> Pnext);
    CrvVec = (CagdCrvStruct **) IritMalloc(sizeof(CagdCrvStruct *) * NumCrvs);
    for (i = 0, Crv = CrvList;
	 i < NumCrvs;
	 i++, Crv = Crv -> Pnext)
	CrvVec[i] = CagdCrvCopy(Crv);

    /* Traverse vector in a O(n^2) fashion and make all curves compatible.   */
    for (i = 0; i < NumCrvs - 1; i++)
	for (j = i + 1; j < NumCrvs; j++)
	    CagdMakeCrvsCompatible(&CrvVec[i], &CrvVec[j], TRUE, TRUE);

    /* Construct the surface. All required information is now available.     */
    UOrder = CrvVec[0] -> Order;
    VOrder = MIN(NumCrvs, OtherOrder);
    if (NumCrvs == VOrder && CrvVec[0] -> GType == CAGD_CBEZIER_TYPE) {
    	/* Allocate a bezier surface. */
	Srf = BzrSrfNew(CrvVec[0] -> Length, NumCrvs, CrvVec[0] -> PType);
    }
    else {
	/* Allocate a bspline surface. */
	Srf = BspPeriodicSrfNew(CrvVec[0] -> Length, NumCrvs, UOrder, VOrder,
				CrvVec[0] -> Periodic, FALSE,
				CrvVec[0] -> PType);
	IritFree((VoidPtr) Srf -> UKnotVector);
	Srf -> UKnotVector = BspKnotCopy(CrvVec[0] -> KnotVector,
					 CAGD_CRV_PT_LST_LEN(CrvVec[0]) +
					 UOrder);
	BspKnotUniformOpen(NumCrvs, VOrder, Srf -> VKnotVector);
    }

    /* Substitute each curve as a row into the surface mesh and delete it. */
    SrfPoints = Srf -> Points;
    i = 0;
    MaxCoord = CAGD_NUM_OF_PT_COORD(CrvVec[0] -> PType),
    IsNotRational = !CAGD_IS_RATIONAL_CRV(CrvVec[0]);
    Length = CrvVec[0] -> Length;

    for (j = 0; j < NumCrvs; j++) {
	int k;
	CagdRType
	    **CrvPoints = CrvVec[j] -> Points;

    	for (k = IsNotRational; k <= MaxCoord; k++)
	    CAGD_GEN_COPY(&SrfPoints[k][i], CrvPoints[k],
			  sizeof(CagdRType) * Length);

	CagdCrvFree(CrvVec[j]);
	i += Length;
    }

    IritFree((VoidPtr) CrvVec);

    return Srf;
}
