/* * Routines for spline interpolation and approximation * - Cubic B-Spline (open, closed) * - Doubled Cubic B-Spline (open, closed) * - Quadratic B-Spline (open, closed) * - Catmull-Rom Spline (open, closed) * - Cubic Bezier spline (open, closed) * - Quadratic Bezier Spline (open, closed) */ #include #include #include "CNspline.h" #define SMALL 1.0e-5 static double eval_cubic_spline(); static double eval_quadr_spline(); static double eval_ctrom_spline(); static double eval_quadr_bezier_spline(); static double eval_cubic_bezier_spline(); /* * Retrun a string denoting the spline type */ char *CNsplinetype(splinetype) int splinetype; { char *plot; switch (splinetype) { case CN_SP_NONE : plot="Linear (Spline Interpolation is NOT used)"; break; case CN_SP_CUBICB : plot="Cubic B-Spline (Approximates control points)"; break; case CN_SP_DBLCUBICB : plot="Doubled Cubic B-Spline (Closer Approximation of control points)"; break; case CN_SP_QUADRB : plot="Quadratic B-Spline (Approximates control points)"; break; case CN_SP_CTROM : plot="Catmull-Rom Spline (Interpolates through control points)"; break; case CN_SP_QDBEZIER : plot="Quadratic Bezier Spline (Hits midpoints of control points)"; break; case CN_SP_CBBEZIER : default : plot="Cubic Bezier Spline (Hits midpoints of control points)"; break; } return(plot); } /* * Create a spline curve from a given array */ void CNcreate_spline(xarr,npts,xs,nspts,ndiv,splinetype,closed) double xarr[], xs[]; int npts, *nspts, ndiv, splinetype, closed; { switch (splinetype) { case CN_SP_CUBICB : /* Single cubic B-spline */ if (!closed) CNmake_cubic_B_spline(xarr,npts,xs,nspts,ndiv); else CNmake_closed_cubic_B_spline(xarr,npts,xs,nspts,ndiv); break; case CN_SP_DBLCUBICB: /* Double cubic B-spline */ if (!closed) CNmake_double_cubic_B_spline(xarr,npts,xs,nspts,ndiv); else CNmake_double_closed_cubic_B_spline(xarr,npts,xs,nspts,ndiv); break; case CN_SP_QUADRB : /* Single quadratic spline */ if (!closed) CNmake_quadr_B_spline(xarr,npts,xs,nspts,ndiv); else CNmake_closed_quadr_B_spline(xarr,npts,xs,nspts,ndiv); break; case CN_SP_CTROM : /* Single catmull-rom spline */ if (!closed) CNmake_ctrom_spline(xarr,npts,xs,nspts,ndiv); else CNmake_closed_ctrom_spline(xarr,npts,xs,nspts,ndiv); break; case CN_SP_QDBEZIER : /* Single Quadratic Bezier spline */ if (!closed) CNmake_quadr_bezier_spline(xarr,npts,xs,nspts,ndiv); else CNmake_closed_quadr_bezier_spline(xarr,npts,xs,nspts,ndiv); break; case CN_SP_CBBEZIER : default : /* Single Cubic Bezier spline */ if (!closed) CNmake_cubic_bezier_spline(xarr,npts,xs,nspts,ndiv); else CNmake_closed_cubic_bezier_spline(xarr,npts,xs,nspts,ndiv); break; } } /* * Single open cubic spline * Spline curve approximates the real curve and terminates at end-points * Control points are doubled only at the end-points */ void CNmake_cubic_B_spline(xarr,npts,xs,nspts,ndiv) double xarr[], xs[]; int npts, *nspts, ndiv; { double u,du; int i,j; /* If too few points, just copy the original array to the new array */ if (npts <= 2) { *nspts = npts; for (i=0; i 1.0 + SMALL) { (void) fprintf(stderr,"Error - attempt to evaluate u=%f outside [0,1] range\n",u); return(0.0); } c = u*u*u*(-1*xa + 3*xb - 3*xc + xd) + u*u*( 3*xa - 6*xb + 3*xc ) + u*(-3*xa + 3*xc ) + ( xa + 4*xb + xc ); c = c/6.0; return(c); } /* * Single quadratic B-spline * Spline curve approximates the real curve and terminates at end-points * Control points are doubled only at the end-points */ void CNmake_quadr_B_spline(xarr,npts,xs,nspts,ndiv) double xarr[], xs[]; int npts, *nspts, ndiv; { double u, du; int i, j; /* If too few points, just copy the original array to the new array */ if (npts <= 2) { *nspts = npts; for (i=0; i 1.0 + SMALL) { (void) fprintf(stderr,"Error - attempt to evaluate u=%f outside [0,1] range\n",u); return(0.0); } c = u*u*( xa - 2*xb + xc) + u*(-2*xa + 2*xb ) + ( xa + xb ); c = c/2.0; return(c); } /* * Single (Open) Catmull-Rom spline * The splines pass through the real datapoints. * Control points are doubled only at the end-points */ void CNmake_ctrom_spline(xarr,npts,xs,nspts,ndiv) double xarr[], xs[]; int npts, *nspts, ndiv; { double u, du; int i, j; /* If too few points, just copy the original array to the new array */ if (npts <= 2) { *nspts = npts; for (i=0; i 1.0 + SMALL) { (void) fprintf(stderr,"Error - attempt to evaluate u=%f outside [0,1] range\n",u); return(0.0); } c = u*u*u*( -B*xa + (2-B)*xb + (B-2)*xc + B*xd ) + u*u*(2*B*xa + (B-3)*xb + (3-2*B)*xc - B*xd ) + u*( -B*xa + B*xc ) + ( xb ); return(c); } /* * Single (Open) Quadratic Bezier spline * Spline curve approximates the real curve and terminates at end-points * Control points are doubled only at the end-points */ void CNmake_quadr_bezier_spline(xarr,npts,xs,nspts,ndiv) double xarr[], xs[]; int npts, *nspts, ndiv; { double xm1, xm2, xm3, u, du; int i, j; /* If too few points, just copy the original array to the new array */ if (npts <= 2) { *nspts = npts; for (i=0; i 1.0 + SMALL) { (void) fprintf(stderr,"Error - attempt to evaluate u=%f outside [0,1] range\n",u); return(0.0); } c = u*u*( xa - 2*xb + xc) + u*(-2*xa + 2*xb ) + ( xa ); return(c); } /* * Evaluate the cubic Bezier spline */ static double eval_cubic_bezier_spline(u,xa,xb,xc,xd) double u,xa,xb,xc,xd; { double c; /* Check the value of u */ if (u < -SMALL || u > 1.0 + SMALL) { (void) fprintf(stderr,"Error - attempt to evaluate u=%f outside [0,1] range\n",u); return(0.0); } c = u*u*u*( -xa + 3*xb - 3*xc + xd ) + u*u*( 3*xa - 6*xb + 3*xc ) + u*(-3*xa + 3*xb ) + ( xa ); return(c); }