MATLAB: Approximating ‘y’ coordinates of a b-spline’s coefficients.

b-splinecurvecurvesdistancefnpltknotsknotvectorlooploopsMATLABpolynomialsplinespmak

I have created a B-spline using the following method:
cp_x=[0
11.19
28.26
59.12
88.99
90.82
100];
cp_y=[0
9.90
23.58
27.65
75.90
85.22
100];
knotVector = [0 0 0 0 0 0.3333 0.6667 1 1 1 1 1];
cp=[cp_x(1),cp_x(2),cp_x(3),cp_x(4),cp_x(5),cp_x(6),cp_x(7);cp_y(1),cp_y(2),cp_y(3),cp_y(4),cp_y(5),cp_y(6),cp_y(7)];
sp = spmak(knotVector,cp);
points = fnplt(sp);
I now want to create a B-spline which matches the existing spline as closely as possible; however, I want to change the 'x' coordinates of the coefficients to:
cp_x=[0
10
25
50
75
90
100];
I now need to work out what values of "cp_y" will give me a b-spline closely resembling the original spline.
I had an idea (which definitely isn't the most efficient way of carrying out this task) of running a loop which iterates through various 'y' coordinates and creates a spline. I then find the max distance between the 2 splines and keep iterating through the 'y' coordinates until the maximum distance is minimised. I think this will be a very time consuming and process though.
Any help with finding a better solution would be greatly appreciated.

Best Answer

I have managed to come up with a solution which works for my case:
%%Baseline Spline %%
cp_x=[0
11.19
28.26
59.12
88.99
90.82
100];
cp_y=[0
9.90
23.58
27.65
75.90
85.22
100];
knotVector = [0 0 0 0 0 0.3333 0.6667 1 1 1 1 1];
cp=[cp_x(1),cp_x(2),cp_x(3),cp_x(4),cp_x(5),cp_x(6),cp_x(7);cp_y(1),cp_y(2),cp_y(3),cp_y(4),cp_y(5),cp_y(6),cp_y(7)];
sp = spmak(knotVector,cp);
points = fnplt(sp);
%%New Spline %%
cp_x_new=[0
10
25
50
75
90
100];
cp_y_new=[0
10
25
50
75
90
100];
cp_new=[cp_x_new(1),cp_x_new(2),cp_x_new(3),cp_x_new(4),cp_x_new(5),cp_x_new(6),cp_x_new(7);cp_y_new(1),cp_y_new(2),cp_y_new(3),cp_y_new(4),cp_y_new(5),cp_y_new(6),cp_y_new(7)];
sp_new= spmak(knotVector,cp_new);
points_new = fnplt(sp_new);
%%Iterations %%
tol=0.1;
count=0;
MaxDist=tol+1;
cp_y_iterate=cp_y_new;
points_iterate=points_new;
splitter=[18;38;63;83;100];
CntrlPtsX=[10;25;50;75;90];
tStart=tic;
for i = 1 : length(CntrlPtsX)
for j = 1 : length(points_iterate)
xPos(i, j) = abs(CntrlPtsX(i,1) - points_iterate(1,j));
end
[minXpos(i),Xindex(i)]=min(abs(xPos(i,:)));
end
while MaxDist > tol
tEnd=toc(tStart);
if(tEnd>=30)
disp('It has spent 30 seconds');
break
end
minDistance = inf;
for i = 1 : length(points)
for j = 1 : length(points_iterate)
distances(i, j) = abs(points(1,i) - points_iterate(1,j));
end
[minDistances(i),index(i)]=min(abs(distances(i,:)));
end
delta_points=points(2,:)-points_iterate(2,index(:));
[max_delta1, loc1]=max(abs(delta_points(Xindex(1))));
max_delta1=max_delta1*sign(delta_points(Xindex(1)-1+loc1));
[max_delta2, loc2]=max(abs(delta_points(Xindex(2))));
max_delta2=max_delta2*sign(delta_points(Xindex(2)-1+loc2));
[max_delta3, loc3]=max(abs(delta_points(Xindex(3))));
max_delta3=max_delta3*sign(delta_points(Xindex(3)-1+loc3));
[max_delta4, loc4]=max(abs(delta_points(Xindex(4))));
max_delta4=max_delta4*sign(delta_points(Xindex(4)-1+loc4));
[max_delta5, loc5]=max(abs(delta_points(Xindex(5))));
max_delta5=max_delta5*sign(delta_points(Xindex(5)-1+loc5));
MaxDeltaMat=[max_delta1,max_delta2,max_delta3,max_delta4,max_delta5];
MaxDist=max(abs(MaxDeltaMat));
if max_delta1 >= 10*tol
cp_y_iterate(2)=cp_y_iterate(2)+1;
elseif max_delta1 <= -10*tol
cp_y_iterate(2)=cp_y_iterate(2)-1;
elseif max_delta1 >= tol
cp_y_iterate(2)=cp_y_iterate(2)+0.0005;
elseif max_delta1 <= -1*tol
cp_y_iterate(2)=cp_y_iterate(2)-0.0005;
else
cp_y_iterate(2)=cp_y_iterate(2);
end
if max_delta2 >= 10*tol
cp_y_iterate(3)=cp_y_iterate(3)+1;
elseif max_delta2 <= -10*tol
cp_y_iterate(3)=cp_y_iterate(3)-1;
elseif max_delta2 >= tol
cp_y_iterate(3)=cp_y_iterate(3)+0.0005;
elseif max_delta2 <= -1*tol
cp_y_iterate(3)=cp_y_iterate(3)-0.0005;
else
cp_y_iterate(3)=cp_y_iterate(3);
end
if max_delta3 >= 10*tol
cp_y_iterate(4)=cp_y_iterate(4)+1;
elseif max_delta3 <= -10*tol
cp_y_iterate(4)=cp_y_iterate(4)-1;
elseif max_delta3 >= tol
cp_y_iterate(4)=cp_y_iterate(4)+0.0005;
elseif max_delta3 <= -1*tol
cp_y_iterate(4)=cp_y_iterate(4)-0.0005;
else
cp_y_iterate(4)=cp_y_iterate(4);
end
if max_delta4 >= 10*tol
cp_y_iterate(5)=cp_y_iterate(5)+1;
elseif max_delta4 <= -10*tol
cp_y_iterate(5)=cp_y_iterate(5)-1;
elseif max_delta4 >= tol
cp_y_iterate(5)=cp_y_iterate(5)+0.0005;
elseif max_delta4 <= -1*tol
cp_y_iterate(5)=cp_y_iterate(5)-0.0005;
else
cp_y_iterate(5)=cp_y_iterate(5);
end
if max_delta5 >= 10*tol
cp_y_iterate(6)=cp_y_iterate(6)+1;
elseif max_delta5 <= -10*tol
cp_y_iterate(6)=cp_y_iterate(6)-1;
elseif max_delta5 >= tol
cp_y_iterate(6)=cp_y_iterate(6)+0.0005;
elseif max_delta5 <= -1*tol
cp_y_iterate(6)=cp_y_iterate(6)-0.0005;
else
cp_y_iterate(6)=cp_y_iterate(6);
end
cp_iterate=[cp_x_new(1),cp_x_new(2),cp_x_new(3),cp_x_new(4),cp_x_new(5),cp_x_new(6),cp_x_new(7);cp_y_iterate(1),cp_y_iterate(2),cp_y_iterate(3),cp_y_iterate(4),cp_y_iterate(5),cp_y_iterate(6),cp_y_iterate(7)];
sp_iterate= spmak(knotVector,cp_iterate);
points_iterate = fnplt(sp_iterate);
count=count+1
end
disp(cp_iterate)
%%Plot %%
close all
figure
plot(points(1,:),points(2,:),'k')
hold on
scatter(cp(1,:),cp(2,:),'k+')
plot(points_new(1,:),points_new(2,:),'r')
scatter(cp_new(1,:),cp_new(2,:),'r*')
plot(points_iterate(1,:),points_iterate(2,:),'g')
scatter(cp_iterate(1,:),cp_iterate(2,:),'gs')
Again, definitely not the most efficient way, but it approximates the spline quite well using different coefficients (see image: black = original/target spline; red = new spline starting point; green = new spline final approximation of black spline).