function [yi, ypi, yppi, c1x, c1y, c2x, c2y] = cbezier(x, y, xi)
% CBEZIER 1-D piecewise cubic Bezier spline interpolation
% CBEZIER(X,Y,XI) interpolates to find YI, the values of
% the underlying function Y at the points in the array XI, using
% piecewise subic Bezier spline interpolation. X and Y must
% be vectors of length N.
%
% [YI,YPI,YPPI] = CBEZIER() also returns the interpolated
% quadratic derivative and linear second derivative of the
% underlying function Y at points XI.
%
% [YI,YPI,YPPI,C1X,C1Y,C2X,C2Y] = CBEZIER() also returns the
% X and Y coordinates of the first and second Bezier control
% points.
% Joe Henning - Fall 2011
n = length(x);
u = zeros(1,n-1);
v = zeros(1,n-1);
if (n == 2)
% Bezier curve should be a straight line
c1x(1) = (2*x(1) + x(2))/3.0;
c1y(1) = (2*y(1) + y(2))/3.0;
c2x(1) = 2*c1x - x(1);
c2y(1) = 2*c1y - y(1);
else
% Calculate first Bezier control points
for i = 2:n-2
u(i) = 4*x(i) + 2*x(i+1);
v(i) = 4*y(i) + 2*y(i+1);
end
u(1) = x(1) + 2*x(2);
u(n-1) = (8*x(n-1) + x(n))/2.0;
v(1) = y(1) + 2*y(2);
v(n-1) = (8*y(n-1) + y(n))/2.0;
% Decomposition, forward substitution, and backsubstitution
tmp = zeros(1,n-1);
b = 2.0;
c1x(1) = u(1)/b;
for i = 2:n-1
tmp(i) = 1/b;
if (i < n-1)
b = 4.0 - tmp(i);
else
b = 3.5 - tmp(i);
end
c1x(i) = (u(i) - c1x(i-1))/b;
end
for i = 2:n-1
c1x(n-i) = c1x(n-i) - tmp(n-i+1)*c1x(n-i+1);
end
tmp = zeros(1,n-1);
b = 2.0;
c1y(1) = v(1)/b;
for i = 2:n-1
tmp(i) = 1/b;
if (i < n-1)
b = 4.0 - tmp(i);
else
b = 3.5 - tmp(i);
end
c1y(i) = (v(i) - c1y(i-1))/b;
end
for i = 2:n-1
c1y(n-i) = c1y(n-i) - tmp(n-i+1)*c1y(n-i+1);
end
% Calculate second Bezier control points
for i = 1:n-1
if (i < n-1)
c2x(i) = 2*x(i+1) - c1x(i+1);
c2y(i) = 2*y(i+1) - c1y(i+1);
else
c2x(i) = (x(n) + c1x(n-1))/2.0;
c2y(i) = (y(n) + c1y(n-1))/2.0;
end
end
end
for i = 1:length(xi)
% Find the right place in the table by means of a bisection.
klo = 1;
khi = n;
while (khi-klo > 1)
k = fix((khi+klo)/2.0);
if (x(k) > xi(i))
khi = k;
else
klo = k;
end
end
h = x(khi) - x(klo);
if (h == 0.0)
fprintf('??? Bad x input to cbezier ==> x values must be distinct\n');
yi(i) = NaN;
ypi(i) = NaN;
yppi(i) = NaN;
continue;
end
% Evaluate cubic Bezier polynomial
t = (xi(i) - x(klo))/h;
t2 = t*t;
t3 = t2*t;
h2 = h*h;
b00 = -t3 + 3*t2 - 3*t + 1;
b10 = 3*t3 - 6*t2 + 3*t;
b20 = -3*t3 + 3*t2;
b30 = t3;
yi(i) = b00*y(klo) + b10*c1y(klo) + b20*c2y(klo) + b30*y(khi);
% Differentiate to find the second-order interpolant
b00 = -3*t2 + 6*t - 3;
b10 = 9*t2 - 12*t + 3;
b20 = -9*t2 + 6*t;
b30 = 3*t2;
ypi(i) = b00*y(klo)/h + b10*c1y(klo)/h + b20*c2y(klo)/h + b30*y(khi)/h;
% Differentiate to find the first-order interpolant
b00 = -6*t + 6;
b10 = 18*t - 12;
b20 = -18*t + 6;
b30 = 6*t;
yppi(i) = b00*y(klo)/h2 + b10*c1y(klo)/h2 + b20*c2y(klo)/h2 + b30*y(khi)/h2;
end