/******************************************************************************
* CagdEXTR.c - Extrusion operator out of a given profile and a direction vec. *
*******************************************************************************
* Written by Gershon Elber, Mar. 91.					      *
******************************************************************************/

#include "cagd_loc.h"

/*****************************************************************************
* DESCRIPTION:                                                               M
* Constructs an extrusion surface in the Vector direction for the given      M
* profile curve. Input curve can be either a Bspline or a Bezier curve and   M
* the resulting output surface will be of the same type.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Crv:     To exturde in direction specified by Vec.                       M
*   Vec:     Direction as well as magnitude of extursion.                    M
*                                                                            *
* RETURN VALUE:                                                              M
*   CagdSrfStruct *:   An extrusion surface with Orders of the original      M
*                      Crv order and 2 in the extrusion direction.           M
*                                                                            *
* KEYWORDS:                                                                  M
*   CagdExtrudeSrf, surface constructors                                     M
*****************************************************************************/
CagdSrfStruct *CagdExtrudeSrf(CagdCrvStruct *Crv, CagdVecStruct *Vec)
{
    CagdSrfStruct *Srf;
    int i, j,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType),
	Len = Crv -> Length;
    CagdPointType
	PType = Crv -> PType;
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    CagdRType **SrfPoints,
	**CrvPoints = Crv -> Points,
	*Dir = Vec->Vec;

    switch (PType) {
	case CAGD_PT_P2_TYPE:
	    PType = CAGD_PT_P3_TYPE;
	    break;
	case CAGD_PT_E2_TYPE:
	    PType = CAGD_PT_E3_TYPE;
	    break;
	case CAGD_PT_P3_TYPE:
	case CAGD_PT_E3_TYPE:
	    break;
	default:
	    CAGD_FATAL_ERROR(CAGD_ERR_UNSUPPORT_PT);
	    break;
    }

    switch (Crv -> GType) {
	case CAGD_CBEZIER_TYPE:
	    Srf = BzrSrfNew(Len, 2, PType);
	    break;
	case CAGD_CBSPLINE_TYPE:
	    Srf = BspPeriodicSrfNew(Len, 2,
				    Crv -> Order, 2,
				    Crv -> Periodic, FALSE,
				    PType);
	    CAGD_GEN_COPY(Srf -> UKnotVector, Crv -> KnotVector,
			  sizeof(CagdRType) * (CAGD_CRV_PT_LST_LEN(Crv) +
					       Crv -> Order));
	    Srf -> VKnotVector[0] = Srf -> VKnotVector[1] = 0.0;
	    Srf -> VKnotVector[2] = Srf -> VKnotVector[3] = 1.0;
	    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 curve    */
    /* while second one is the same as first one translated by Vec.          */
    SrfPoints = Srf -> Points;

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

    /* Make a copy of the Second row do we can "work" on it. */
    for (i = IsNotRational; i <= MaxCoord; i++)		      /* Second row. */
	CAGD_GEN_COPY(&SrfPoints[i][Len], CrvPoints[i],
		      sizeof(CagdRType) * Len);

    /* If the curve has lesser dimension (i.e. was 2D), Add zeros. */
    for (i = MaxCoord + 1; i <= 3; i++)
	for (j = 0; j < Len * 2; j++)
	    SrfPoints[i][j] = 0.0;

    for (i = 1; i <= 3; i++)			/* Translate the second row. */
	for (j = Len; j < Len * 2; j++)
	    SrfPoints[i][j] += IsNotRational ? Dir[i - 1] :
					       Dir[i - 1] * SrfPoints[W][j];

    return Srf;
}
