/******************************************************************************
* CBspEval.c - Bezier curves handling routines - evaluation routines.	      *
*******************************************************************************
* Written by Gershon Elber, Mar. 90.					      *
******************************************************************************/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "cagd_loc.h"

/******************************************************************************
* Assumes Vec holds control points for scalar bspline curve of order Order    *
* length Len and knot vector KnotVector.				      *
* Evaluates and returns that curve value at parameter value t.		      *
* Vec is incremented by VecInc (usually by 1) after each iteration.	      *
******************************************************************************/
CagdRType BspCrvEvalVecAtParam(CagdRType *Vec, int VecInc,
			       CagdRType *KnotVector, int Order, int Len,
			       CagdRType t)
{
    int i, IndexFirst;
    CagdRType
	R = 0.0,
	*BasisFunc = BspCrvCoxDeBoorBasis(KnotVector, Order, Len, t,
								&IndexFirst);

    if (VecInc == 1) {
	Vec += IndexFirst;
	for (i = 0; i < Order; i++)
	    R += BasisFunc[i] * *Vec++;
    }
    else {
	Vec += IndexFirst * VecInc;
	for (i = 0; i < Order; i++) {
	    R += BasisFunc[i]  * *Vec;
	    Vec += VecInc;
	}
    }

    return R;
}

/******************************************************************************
* Returns a pointer to a static data, holding the value of the curve at given *
* parametric location t. The curve is assumed to be Bspline.		      *
* Uses the Cox de Boor recursive algorithm (is this fastest for single eval?) *
******************************************************************************/
CagdRType *BspCrvEvalAtParam(CagdCrvStruct *Crv, CagdRType t)
{
    return BspCrvEvalCoxDeBoor(Crv, t);
}

/******************************************************************************
* Samples the curves at FineNess location equally spaced in the Bspline       *
* parametric domain.							      *
*   Computes a refinement alpha matrix (If FineNess > 0), refine the curve    *
* and use refined control polygon as the approximation to the curve.	      *
*   If FineNess == 0, Alpha matrix A is used instead.			      *
*   Returns the actual number of points in polyline (<= FineNess).	      *
* Note bezier curves may call this routine.				      *
******************************************************************************/
int CagdCrvEvalToPolyline(CagdCrvStruct *Crv, int FineNess,
			  CagdRType *Points[], BspKnotAlphaCoeffType *A)
{
    CagdBType
	IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
    int i, j, Count,
	Len = Crv -> Length,
    	n = FineNess == 0 ? A -> RefLength : (1 << FineNess),
	Order = Crv -> Order,
	MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
    CagdRType Tmin, Tmax;

    if (Crv -> Order == 2) {		 /* Simply copy the control polygon. */
	CagdRType **CrvPoints = Crv -> Points;

	for (Count = 0; Count < n && Count < Len; Count++)
	    for (i = IsNotRational; i <= MaxCoord; i++)
	        Points[i][Count] = CrvPoints[i][Count];
	return Count;
    }

    if (CAGD_IS_BEZIER_CRV(Crv)) {
	Tmin = 0.0;
	Tmax = 1.0;
    }
    else
	BspCrvDomain(Crv, &Tmin, &Tmax);

    if (FineNess > 0) {
	CagdRType *RefKV;

	if (n <= Len)
	    FATAL_ERROR(CAGD_ERR_REF_LESS_ORIG);

	RefKV = BspKnotPrepEquallySpaced(n - Len, Tmin, Tmax);

	if (CAGD_IS_BEZIER_CRV(Crv)) {
	    CagdRType
		*KV = BspKnotUniformOpen(Crv -> Length, Crv -> Order, NULL);

	    A = BspKnotEvalAlphaCoefMerge(Order, KV, Len, RefKV, n - Len);

	    IritFree((VoidPtr) KV);
	}
	else
	    A = BspKnotEvalAlphaCoefMerge(Order, Crv -> KnotVector, Len,
					  RefKV, n - Len);

	IritFree((VoidPtr) RefKV);
    }

    /* Compute the refined control polygon straight to destination Points. */
    for (j = IsNotRational; j <= MaxCoord; j++) {
	CagdRType
	    *ROnePts = Points[j],
	    *OnePts = Crv -> Points[j];
	for (i = 0; i < n; i++, ROnePts++)
	    CAGD_ALPHA_BLEND(A, i, OnePts, ROnePts);
    }

    if (FineNess > 0)
	BspKnotFreeAlphaCoef(A);

    return n;
}
