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

#include "cagd_loc.h"

/*****************************************************************************
* DESCRIPTION:                                                               M
* Constructs a ruled surface between the two provided curves.                M
* OtherOrder and OtherLen (equal for Bezier) specifies the desired order and M
* refineness level (if Bspline) of the other ruled direction.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv1, Crv2: The two curves to form a ruled surface in between.           M
*   OtherOrder: Usually two, but one can specify higher orders in the ruled  M
*               direction. OtherOrder must never be larger than OrderLen.    M
*   OtherLen:   Usually two control points in the ruled direction which      M
*               necesitates a linear interpolation.			     M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdSrfStruct *:  The rule surface.                                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdRuledSrf, ruled surface, surface constructors                        M
*****************************************************************************/
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 = BspPeriodicSrfNew(Len, OtherLen, Crv1 -> Order, OtherOrder,
				    Crv1 -> Periodic, FALSE, PType);
	    CAGD_GEN_COPY(Srf -> UKnotVector, Crv1 -> KnotVector,
			  sizeof(CagdRType) * (CAGD_CRV_PT_LST_LEN(Crv1) +
					       Crv1 -> Order));
	    BspKnotUniformOpen(OtherLen, OtherOrder, Srf -> VKnotVector);
	    break;
	case CAGD_CPOWER_TYPE:
	    CAGD_FATAL_ERROR(CAGD_ERR_POWER_NO_SUPPORT);
	    return NULL;
	default:
	    CAGD_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;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Constructs a bilinear surface between the four provided points.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   Pt00, Pt01, Pt10, Pt11: The four points to consturct a bilinear between. M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdSrfStruct *:  A bilinear surface with four corners at Ptij.          M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdBilinearSrf, Bilinear surface, surface constructors                  M
*****************************************************************************/
CagdSrfStruct *CagdBilinearSrf(CagdPtStruct *Pt00,
			       CagdPtStruct *Pt01,
			       CagdPtStruct *Pt10,
			       CagdPtStruct *Pt11)
{
    CagdCrvStruct
	*Crv1 = CagdMergePtPt(Pt00, Pt01),
	*Crv2 = CagdMergePtPt(Pt10, Pt11);
    CagdSrfStruct
	*Srf = CagdRuledSrf(Crv1, Crv2, 2, 2);

    CagdCrvFree(Crv1);
    CagdCrvFree(Crv2);

    return Srf;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Promotes a curve to a surface by creating a ruled surface between the      M 
* curve to itself. Dir controls if the curve should be U or V surface        M
* direction.	                                                             M
*   The resulting surface is degenerate in that its speed is zero in the     M
* ruled direction and hence thesurface is not regular.                       M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:      A Crv to promote into a surface                                M
*   Dir:      Direction of ruling. Either U or V.                            M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdSrfStruct *: The surface promoted from Crv.                          M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdPromoteCrvToSrf                                                      M
*****************************************************************************/
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:
	    CAGD_FATAL_ERROR(CAGD_ERR_DIR_NOT_CONST_UV);
	    break;
	
    }
    return Srf;
}


