/******************************************************************************
* CagdRuld.c - Ruled srf operator out of given two profiles.		      *
*******************************************************************************
* Written by Gershon Elber, May. 91.					      *
******************************************************************************/

#include "cagd_loc.h"

/******************************************************************************
* Constructs a ruled surface between the two provided curves. The two curves  *
* must have the same number of points, same curve type and same point type.   *
* OtherOrder and OtherLen (equal for Bezier) specifies the desired order and  *
* refineness level (if Bspline) of the other ruled direction.		      *
******************************************************************************/
CagdSrfStruct *CagdRuledSrf(CagdCrvStruct *Crv1, CagdCrvStruct *Crv2,
			    int OtherOrder, int OtherLen)
{
    CagdSrfStruct *Srf;
    int i, j, k, MaxCoord, Len;
    CagdPointType PType;
    CagdBType IsNotRational;
    CagdRType **SrfPoints, *Crv1SrcPt, *Crv2SrcPt, *SrfDestPt, t, t1,
						 **Crv1Points, **Crv2Points;

    Crv1 = CagdCrvCopy(Crv1);
    Crv2 = CagdCrvCopy(Crv2);

    CagdMakeCrvsCompatible(&Crv1, &Crv2, TRUE, TRUE);

    MaxCoord = CAGD_NUM_OF_PT_COORD(Crv1 -> PType),
    Len = Crv1 -> Length;
    PType = Crv1 -> PType;
    IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv1);
    Crv1Points = Crv1 -> Points;
    Crv2Points = Crv2 -> Points;

    switch (Crv1 -> GType) {
	case CAGD_CBEZIER_TYPE:
	    Srf = BzrSrfNew(Len, OtherLen, PType);
	    break;
	case CAGD_CBSPLINE_TYPE:
	    Srf = BspSrfNew(Len, OtherLen, Crv1 -> Order, OtherOrder, PType);
	    CAGD_GEN_COPY(Srf -> UKnotVector, Crv1 -> KnotVector,
			  sizeof(CagdRType) * (Len + Crv1 -> Order));
	    BspKnotUniformOpen(OtherLen, OtherOrder, Srf -> VKnotVector);
	    break;
	case CAGD_CPOWER_TYPE:
	    FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    FATAL_ERROR(CAGD_ERR_UNDEF_CRV);
	    return NULL;
    }

    /* Copy the control mesh - first row is exactly the same as the first    */
    /* curve while last row is the same as second curve.		     */
    /* The middle rows are convex blend of the first/last rows.		     */
    SrfPoints = Srf -> Points;

    for (i = IsNotRational; i <= MaxCoord; i++)		       /* First row. */
	CAGD_GEN_COPY(SrfPoints[i], Crv1Points[i],
		      sizeof(CagdRType) * Len);

    /* Make a copy of the last row. */
    for (i = IsNotRational; i <= MaxCoord; i++)		        /* Last row. */
	CAGD_GEN_COPY(&SrfPoints[i][Len * (OtherLen - 1)], Crv2Points[i],
		      sizeof(CagdRType) * Len);

    /* And compute the internal rows, if any: */
    for (j = 1; j < OtherLen - 1; j++) {
	t = ((CagdRType) j) / (OtherLen - 1);
	t1 = 1.0 - t;
	for (i = IsNotRational; i <= MaxCoord; i++) {
	    SrfDestPt = &SrfPoints[i][Len * j];
	    Crv1SrcPt = Crv1Points[i];
	    Crv2SrcPt = Crv2Points[i];
	    for (k = 0; k < Len; k++)
		SrfDestPt[k] = t1 * Crv1SrcPt[k] + t * Crv2SrcPt[k];
	}
    }		

    CagdCrvFree(Crv1);
    CagdCrvFree(Crv2);

    return Srf;
}

/******************************************************************************
* Promote a curve to a surface by creating a ruled surface between the curve  *
* and itself. Dir controls if the curve should be U or V surface direction.   *
******************************************************************************/
CagdSrfStruct *CagdPromoteCrvToSrf(CagdCrvStruct *Crv, CagdSrfDirType Dir)
{
    CagdSrfStruct *TSrf,
	*Srf = CagdRuledSrf(Crv, Crv, 2, 2);

    switch (Dir) {
	case CAGD_CONST_U_DIR:
	    break;
	case CAGD_CONST_V_DIR:
	    TSrf = CagdSrfReverse2(Srf);
	    CagdSrfFree(Srf);
	    Srf = TSrf;
	    break;
	default:
	    FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV);
	    break;
	
    }
    return Srf;
}


