No BSD License  

Highlights from
gspline

image thumbnail
from gspline by Daniel Claxton
GSPLINE - Interactively draw interpolating spline similar to gline

gspline(fig)
function h = gspline(fig)
% GSPLINE - Interactively draw interpolating spline similar to gline
%   GSPLINE(FIG) draws a spline by left - clicking the mouse at the control
%   points of the spline in the figure FIG. Right clicking will end the
%   spline.

%   H = GSPLINE(FIG) Returns the handle to the line.
%
%   GSPLINE with no input arguments draws in the current figure.


if nargin<1, 
  draw_fig = gcf;
  fig = draw_fig;
  s = 'start'; 
end

if isstr(fig), 
   s = fig;
   draw_fig = gcbf;
   ud = get(draw_fig,'UserData');
else
   s = 'start';
   draw_fig = fig; 
end

ax = get(draw_fig,'CurrentAxes');
if isempty(ax)
   ax = axes('Parent',draw_fig);
end

gcacolor = get(ax,'Color');

% Check to see if we're clicking to exit
mouse = get(draw_fig,'selectiontype');
% Normal:    Click left mouse button.
% Extend:    Shift - click left mouse button or click both left and right 
%            mouse buttons,  or click middle mouse button. 
% Alternate: Control - click left mouse button or click right mouse button.
% Open:      Double-click any mouse button.
if ~strcmp('start',s)
    switch lower(mouse(1:3))
        case 'nor'
        case 'ext'
            s = 'last';
        case 'alt'
            s = 'last';
        case 'ope'
            s = 'last';
    end
end

switch s
   case 'start'
   oldtag = get(draw_fig,'Tag');
   figure(draw_fig);
   if any(get(ax,'view')~=[0 90]), 
     set(draw_fig, 'Tag', oldtag);
     error('stats:gspline:NotTwoDimensional','gspline works only for 2-D plots.');
   end
   
   
   % Initialize spline
   xlimits = get(ax,'Xlim');
   x = (xlimits + flipud(xlimits))./2;
   ylimits = get(ax,'Ylim');
   y = (ylimits + flipud(ylimits))./2;
   hline = line(x,y,'Parent',ax,'Visible','off','eraseMode','normal');

   % Save current window functions and data
   bdown = get(draw_fig,'WindowButtonDownFcn');
   bup = get(draw_fig,'WindowButtonUpFcn');
   bmotion = get(draw_fig,'WindowButtonMotionFcn');
   oldud = get(draw_fig,'UserData');
   
   % Create new window functions
   set(draw_fig,'WindowButtonDownFcn','gspline(''first'')')
   set(draw_fig,'WindowButtonMotionFcn','gspline(''motion'')')
   set(draw_fig,'WindowButtonupFcn','')
   
   set(draw_fig,'doublebuffer','on')
 
   % Save drawing data as in 'UserData'
   ud.hline = hline;
   ud.pts = [];
   ud.buttonfcn = {bdown; bup; bmotion};
   ud.oldud = oldud;
   ud.oldtag = oldtag;
   ud.npts = 1;
   ud.xlimits = xlimits;
   ud.ylimits = ylimits;
   set(draw_fig,'UserData',ud);
   
   if nargout == 1
      h = hline;
   end

case 'motion'
   set(draw_fig,'Pointer','crosshair');

   if isempty(ud.pts);
      return;
   end

   [xspline,yspline] = splineInterp(ud.pts(:,1),ud.pts(:,2));
   
   set(ud.hline,'Xdata',xspline,'Ydata',yspline, ...
        'linestyle','-', 'linewidth', 1.5, 'Color',1-gcacolor,'Visible','on');
   Pt2 = get(ax,'CurrentPoint'); 
   Pt2 = Pt2(1,1:2);    
   ud.pts(ud.npts+1,:) = Pt2;

   set(draw_fig,'UserData',ud);

case 'first'   
   Pt1 = get(ax,'CurrentPoint'); 
   ud.pts = [Pt1(1,1:2); Pt1(1,1:2)];

   set(draw_fig,'WindowButtonDownFcn','gspline(''down'')','UserData',ud)
   
case 'down'         
   Pt1 = get(ax,'CurrentPoint'); 
   ud.pts = [ud.pts; Pt1(1,1:2)]; 
   ud.npts = ud.npts + 1;   
   [xspline,yspline] = splineInterp(ud.pts(:,1),ud.pts(:,2));
%    
%    set(ud.hline,'Xdata',xspline,'Ydata',yspline,'eraseMode','normal', ...
%         'linestyle','-', 'linewidth', 1.5, 'Color',1-gcacolor,'Visible','on');

   set(draw_fig,'WindowButtonDownFcn','gspline(''down'')','UserData',ud)
      
case 'last'
   bfcns = ud.buttonfcn;
   set(draw_fig,'windowbuttondownfcn',bfcns{1},'windowbuttonupfcn',bfcns{2}, ...
         'windowbuttonmotionfcn',bfcns{3},'Pointer','arrow', ...
		 'Tag',ud.oldtag,'UserData',ud.oldud)
   set(ud.hline,'UserData',ud.pts)

otherwise
   error('stats:gspline:BadCallBack','Invalid call-back.');
end

% Make sure the axis limits don't change
set(ax,'xlim',ud.xlimits,'ylim',ud.ylimits);



function [xout,yout] = splineInterp(x,y,BC)
% SPLINE_INTERP - Interpolate data with cardinal spline
%   SPLINE_INTERP(P,BC), where P is nx3 matrix of coordinates and BC is a
%   2x3 array containing the tangencies at the beginning and end of the
%   curve

z = zeros(size(x(:)));

P = [x(:) y(:) z(:)];

% Determine number of points
n = size(P,1);

if n <= 2
    xout = x;
    yout = y;
    return
end

% Determine number of tangencies to account for
m = n - 2;

% Our known vector Reduces to -3*(Pn - Pn+2)
Pa = P(1:m,:);
Pb = P(3:n,:);
PP = -3*(Pa - Pb); %;-[0.5*(1-t)*(1+b)*(1-c)*(Pa-Pb)];

% Create Try diagonal matrix (1,4,1)
TM = (diag(4*ones(n,1)) + diag(ones(n-1,1),1) + diag(ones(n-1,1),-1));

% Check for boundary conditions
if nargin == 2,
    % If no BC specified, impose zero curvature at endpoints
    PP = [6*(P(2,:) - P(1,:)); PP; 6*(P(n,:) - P(n-1,:))];
    TM(1,1:3) = [4 2 0];
    TM(n,n-2:n) = [0 2 4];
else
    % Use BC as tangencies at endpoints
%     BC = varargin{1};
    PP = [BC(1,:); PP; BC(2,:)];
    TM(1,1:2) = [1 0];
    TM(n,n-1:n) = [0 1];
end

% Solve for uknown tangencies 
P_dot = TM\PP; %inv(TM)*PP;     

% Set up matricies for solving
CMx = [P(1:n-1,1) P(2:n,1) P_dot(1:n-1,1) P_dot(2:n,1)];
CMy = [P(1:n-1,2) P(2:n,2) P_dot(1:n-1,2) P_dot(2:n,2)];
CMz = [P(1:n-1,3) P(2:n,3) P_dot(1:n-1,3) P_dot(2:n,3)];

% Calculate interpolated points
num_pts = 79;
res = .1;%(n-1)/(num_pts-1);                % Point frequency
j = 1;

% Sort our data points so that it makes sense for plotting
for u=0:res:1,
    for q = 1:n-1,
        M = [CMx*H(u) CMy*H(u) CMz*H(u)];
        MM(j,:,q) = M(q,:);        
    end
    j = j+1;
end
out = [];
for i=1:n-1,
    out = [out; MM(:,:,i)];
end

% Remove repeated points
out(find(diff(sqrt(sum(out.^2,2)))==0),:) = [];

xout = out(:,1);
yout = out(:,2);



% Calculate the Hermite Basis Functions
function h = H(u),
h = [(1-3*u^2) + 2*u^3; 3*u^2 - 2*u^3; u - 2*u^2 + u^3; u^3 - u^2;];

Contact us at files@mathworks.com