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

#include "cagd_loc.h"

/******************************************************************************
* Constructs a surface using a set of curves. Curves are made to be	      *
* compatible and then each is substituted in the resulting surface as a row.  *
*   Other direction order is at most the compatible curves order. If order is *
* less than number of curves a knot vector is formed uniformly (open end).    *
******************************************************************************/
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 = BspSrfNew(CrvVec[0] -> Length, NumCrvs, UOrder, VOrder,
			CrvVec[0] -> PType);
	IritFree((VoidPtr) Srf -> UKnotVector);
	Srf -> UKnotVector = BspKnotCopy(CrvVec[0] -> KnotVector,
					 CrvVec[0] -> Length + CrvVec[0] -> Order);
	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;
}
