Parameterised Spline fit, calling with function handles, storage and calling in cell arrays

30 views (last 30 days)
I am trying to take a set of X and Y coordinate arrays of unknown (but matching) size, fit a spline to them in a manner that allows me to call the spline as a parametric function of 0 <= t <= 1 at high resolution. When I say high resolution, I mean that I want to use the parametric equation with an arbitrary double between 0 and 1, when I'm fitting my spline with anywhere from 8 to 2000 points.
Here's the annoying bit: I need to be able to do this in a "generate, store, then unpack and use later" format. These coordinate arrays are coming from another function in the form of a cell array, where each cell contains a set coordinates in another format where multiple splines worth of data is combined*. The purpose of the function I'm working on is to unpack them from the cell array one cell at a time, unstitch them into by-spline sets, then for each by-spline set fit a spline as a parametrically-evaluatable equation and then package all those back into organised cells so I can later call on and evaluate specific ones.
I found another answer on here that suggested a method for parametric splines using function handles, but it doesn't seem to work. I've stripped the problem down to just the fit-evaluate-store step, and I've put specific questions about clarifications in comments.
*to clarify: I'm converting isocontour matrices into sets of parameterised splines, where I have several isocontour matrices each for a different thing, each containing multiple (unknown number) isocontours.
function runtests
x=double([1 1 2.5 3.5 2 2.5 2 3 3.5 4 5 6 7 5 5 4 3 2 2.5 2.5 1]); %this is mock data, my actual sets are larger
y=double([2 3 5 4 2 4 3 4 5 6 5.5 4 3 2 1 1.5 2 3 4 4 2]);
%data sets are closed loops where the first and last point are the same, and tangents should be smooth.
n = size(x,2);
t = linspace(0,1,n); %--> I need a t for calling Spline (it seems)?
%There's a whole other problem here where t should be equally spaced along the arclength of the spline
% which with this method it is not, so there may actually be a whole preceeding step necessary
% where we fit the data with a simple spline(x,y) to assess arclength positions of the ource points
% and somehow evaluate it for t and then parameterise it? I'm hoping there's a more clever way of
% doing that
z = linspace(0,1,(4*n)); % --> once I generate pp as a spline fit for t,
% can I call it with a function handle that uses a different value in the
% @(), such as @(z) so long as they have the same total range (0 to 1)?
% If so, does z need to be initialised, or left uninitialised prior to the
% function handle call? Does z and t need to be the same size?
tailslope = ((y(2)-y(1))/(x(2)-x(1))+(y(n)-y(n-1))/(x(n)-x(n-1)))/2;
% this will be the assigned start and end slopes.
%This parametric spline code is from
% https://www.mathworks.com/matlabcentral/answers/1584539-blind-parametric-interpolation-fitting-for-a-set-of-points
pp = spline(t,[x(:),y(:)].'); %how do I add assigned start and end slopes to this (the Help example is much
%simpler and not parametric).
xy = @(t) ppval(pp,t) %parametric curve xy(t)
%can I then store "xy" to a cell for exporting to other functions? or would I need to store "pp"? how do I call
%these if I have multiple pp structures from multiple cells in a later function?
%can you do xy = @(t) ppval(cell{k},t) ?
hold on;
plot(x,y,"o"); % points used for spline
%once parameterised and a function handle of xy(t), how do I plot it from the function handle over 0<z<1 at a
%different resolution on an x-y plot?
end

Accepted Answer

Hitesh
Hitesh on 23 Dec 2024 at 6:12
You need to take care of the Arc Length Parameterization, Start and End slopes while plotting the spline.
  1. Arc Length Parameterization: This ensures that "t "is distributed according to the actual distances between points.
  2. Specifying Start and End Slopes: The "spline" function does not directly support specifying slopes for parametric data. "csape" is used to specify clamped boundary conditions with slopes.
  3. Plotting the Spline: The spline is plotted over a finer mesh for smoothness.
Here is the revised code and comments added for every piece of code, kindly refer to it
function runtests
x = double([1 1 2.5 3.5 2 2.5 2 3 3.5 4 5 6 7 5 5 4 3 2 2.5 2.5 1]);
y = double([2 3 5 4 2 4 3 4 5 6 5.5 4 3 2 1 1.5 2 3 4 4 2]);
% Compute arc length parameterization
d = sqrt(diff(x).^2 + diff(y).^2); % distances between points
arcLength = [0, cumsum(d)]; % cumulative arc length
t = arcLength / arcLength(end); % normalize to [0, 1]
% Calculate the average slope at the start and end
tailslopeX = ((x(2) - x(1)) + (x(end) - x(end-1))) / 2;
tailslopeY = ((y(2) - y(1)) + (y(end) - y(end-1))) / 2;
% Fit parametric splines using csape for end slopes
ppX = csape(t, x, 'clamped', [tailslopeX, tailslopeX]);
ppY = csape(t, y, 'clamped', [tailslopeY, tailslopeY]);
% Create a function handle for the parametric curve
xy = @(t) [ppval(ppX, t); ppval(ppY, t)];
% Store function handle in a cell array
splineCellArray = {xy};
% Plot original points
hold on;
plot(x, y, 'o');
% Plot the spline with higher resolution
z = linspace(0, 1, 1000); % high resolution
xyVals = xy(z);
plot(xyVals(1, :), xyVals(2, :), '-');
hold off;
% Example of later usage
xyStored = splineCellArray{1};
result = xyStored(0.5); % Evaluate at t = 0.5
disp('Evaluated point at t = 0.5:');
disp(result);
end
runtests
Evaluated point at t = 0.5: 4.2494 6.0063
For more information regarding "Spline Fitting", kindly refer to the following MATLAB documentation:

More Answers (0)

Products


Release

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!