Code covered by the BSD License  

Highlights from
geom2d

image thumbnail
from geom2d by David Legland
Geometry library for matlab. Performs geometric computations on points, lines, circles, polygons...

polynomialCurveFit(t, varargin)
function varargout = polynomialCurveFit(t, varargin)
%POLYNOMIALCURVEFIT Fit a polynomial curve to a series of points
%
%   [XC YC] = polynomialCurveFit(T, XT, YT, ORDER)
%   T is a Nx1 vector
%   XT and YT are coordinate for each parameter value (column vectors)
%   ORDER is the degree of the polynomial used for interpolation
%   XC and YC are polynomial coefficients, given in ORDER+1 row vectors,
%   starting from degree 0 and up to degree ORDER.
%
%	[XC YC] = polynomialCurveFit(T, POINTS, ORDER);
%   specifies coordinate of points in a Nx2 array.
%
%   Example:
%   N = 50;
%   t = linspace(0, 3*pi/4, N)';
%   xp = cos(t); yp = sin(t);
%   [xc yc] = polynomialCurveFit(t, xp, yp, 3);
%   curve = polynomialCurvePoint(t, xc, yc);
%   drawCurve(curve);
%
%
%	[XC YC] = polynomialCurveFit(..., T_I, COND_I);
%   Impose some specific conditions. T_I is a value of the parametrization
%   variable. COND_I is a cell array, with 2 columns, and as many rows as
%   the derivatives specified for the given T_I. Format for COND_I is:
%   COND_I = {X_I, Y_I; X_I', Y_I'; X_I", Y_I"; ...};
%   with X_I and Y_I being the imposed coordinate at position T_I, X_I' and
%   Y_I' being the imposed first derivatives, X_I" and Y_I" the imposed
%   second derivatives, and so on...
%   To specify a derivative without specifying derivative with lower
%   degree, value of lower derivative can be let empty, using '[]'
%
%   Example:
%   % defines a curve (circle arc) with small perturbations
%   N = 100;
%   t = linspace(0, 3*pi/4, N)';
%   xp = cos(t)+.1*randn(size(t)); yp = sin(t)+.1*randn(size(t));
%   
%   % plot the points
%   figure(1); clf; hold on;
%   axis([-1.2 1.2 -.2 1.2]); axis equal;
%   drawPoint(xp, yp);
%
%   % fit without knowledge on bounds
%   [xc0 yc0] = polynomialCurveFit(t, xp, yp, 5);
%   curve0 = polynomialCurvePoint(t, xc0, yc0);
%   drawCurve(curve0);
%
%   % fit by imposing coordinate on first point
%   [xc1 yc1] = polynomialCurveFit(t, xp, yp, 5, 0, {1, 0});
%   curve1 = polynomialCurvePoint(t, xc1, yc1);
%   drawCurve(curve1, 'r');
%
%   % fit by imposing coordinate (1,0) and derivative (0,1) on first point
%   [xc2 yc2] = polynomialCurveFit(t, xp, yp, 5, 0, {1, 0;0 1});
%   curve2 = polynomialCurvePoint(t, xc2, yc2);
%   drawCurve(curve2, 'g');
%
%   % fit by imposing several conditions on various points
%   [xc3 yc3] = polynomialCurveFit(t, xp, yp, 5, ...
%       0, {1, 0;0 1}, ...      % coord and first derivative of first point
%       3*pi/4, {-sqrt(2)/2, sqrt(2)/2}, ...    % coord of last point
%       pi/2, {[], [];-1, 0});      % derivative of point on the top of arc
%   curve3 = polynomialCurvePoint(t, xc3, yc3);
%   drawCurve(curve3, 'k');
%
%   Requires the optimization Toolbox.
%
%
%   Examples:
%   polynomialCurveFit
%
%   See also
%   polynomialCurves2d
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2007-02-27
% Copyright 2007 INRA - BIA PV Nantes - MIAJ Jouy-en-Josas.


%% extract input arguments

% extract curve coordinate
var = varargin{1};
if min(size(var))==1
    % curve given as separate arguments
    xt = varargin{1};
    yt = varargin{2};
    varargin(1:2)=[];
else
    % curve coordinate bundled in a matrix
    if size(var, 1)<size(var, 2)
        var = var';
    end
    xt = var(:,1);
    yt = var(:,2);
    varargin(1)=[];
end

% order of the polynom
var = varargin{1};
if length(var)>1
    Dx = var(1);
    Dy = var(2);
else
    Dx = var;
    Dy = var;
end
varargin(1)=[];


%% Initialize local conditions

% For a solution vector 'x', the following relation must hold:
%   Aeq * x == beq,
% with:
%   Aeq   Matrix M*N 
%   beq   column vector with length M
% The coefficients of the Aeq matrix are initialized as follow:
% First point and last point are considered successively. For each point,
% k-th condition is the value of the (k-1)th derivative. This value is
% computed using relation of the form:
%   value = sum_i ( fact(i) * t_j^pow(i) )
% with:
%   i     indice of the (i-1) derivative. 
%   fact  row vector containing coefficient of each power of t, initialized
%       with a row vector equals to [1 1 ... 1], and updated for each
%       derivative by multiplying by corresponding power minus 1.
%   pow   row vector of the powers of each monome. It is represented by a
%       row vector containing an increasing series of power, eventually
%       completed with zeros for lower degrees (for the k-th derivative,
%       the coefficients with power lower than k are not relevant).

% Example for degree 5 polynom:
%   iter deriv  pow                 fact
%   1    0      [0 1 2 3 4 5]       [1 1 1 1 1 1]
%   2    1      [0 0 1 2 3 4]       [0 1 2 3 4 5]
%   3    2      [0 0 0 1 2 3]       [0 0 1 2 3 4]
%   4    3      [0 0 0 0 1 2]       [0 0 0 1 2 3]
%   ...
%   The process is repeated for coordinate x and for coordinate y.

% Initialize empty matrices
Aeqx = zeros(0, Dx+1);
beqx = zeros(0, 1);
Aeqy = zeros(0, Dy+1);
beqy = zeros(0, 1);

% Process local conditions
while ~isempty(varargin)
    if length(varargin)==1
        warning('MatGeom:PolynomialCurveFit:ArgumentNumber', ...
            'Wrong number of arguments in polynomialCurvefit');
    end

    % extract parameter t, and cell array of local conditions
    ti = varargin{1};
    cond = varargin{2};

    % factors for coefficients of each polynomial. At the beginning, they
    % all equal 1. With successive derivatives, their value increase by the
    % corresponding powers.
    factX = ones(1, Dx+1);
    factY = ones(1, Dy+1);

    % start condition initialisations
    for i = 1:size(cond, 1)
        % degrees of each polynomial
        powX = [zeros(1, i) 1:Dx+1-i];
        powY = [zeros(1, i) 1:Dy+1-i];
        
        % update conditions for x coordinate
        if ~isempty(cond{i,1})
            Aeqx = [Aeqx ; factY.*power(ti, powX)]; %#ok<AGROW>
            beqx = [beqx; cond{i,1}]; %#ok<AGROW>
        end

        % update conditions for y coordinate
        if ~isempty(cond{i,2})
            Aeqy = [Aeqy ; factY.*power(ti, powY)]; %#ok<AGROW>
            beqy = [beqy; cond{i,2}]; %#ok<AGROW>
        end
        
        % update polynomial degrees for next derivative
        factX = factX.*powX;
        factY = factY.*powY;
    end
    
    varargin(1:2)=[];
end


%% Initialisations

% ensure column vectors
t  = t(:);
xt = xt(:);
yt = yt(:);

% number of points to fit
L = length(t);


%% Compute coefficients of each polynomial

% avoid optimization warnings
warning('off', 'optim:lsqlin:LinConstraints');

% options to turn display off
options = optimset('display', 'off');

% main matrix for x coordinate, size L*(degX+1)
T = ones(L, Dx+1);
for i = 1:Dx
    T(:, i+1) = power(t, i);
end

% compute interpolation
xc = lsqlin(T, xt, zeros(1, Dx+1), 1, Aeqx, beqx, [], [], [], options)';

% main matrix for y coordinate, size L*(degY+1)
T = ones(L, Dy+1);
for i = 1:Dy
    T(:, i+1) = power(t, i);
end

% compute interpolation
yc = lsqlin(T, yt, zeros(1, Dy+1), 1, Aeqy, beqy, [], [], [], options)';


%% Format output arguments
if nargout <= 1
    varargout{1} = {xc, yc};
else
    varargout{1} = xc;
    varargout{2} = yc;
end

Contact us