No BSD License  

Highlights from
NRBLOFT

NRBLOFT

by

 

30 Mar 2007 (Updated )

Loft nurbs surface from adjacent curves or lines

[srf]=nrbloft(X,Y,Z,dir,mode)
function [srf]=nrbloft(X,Y,Z,dir,mode)
% NRBLOFT  Loft Univariate NURBS curves into a NURBS surface
%
%  NRBLOFT constructs a surface by lofting NURBS curves.  This is performed
%  by an interpolation of the new control points from the ones specified in
%  each curve.
%
%  NRBLOFT(CURVES) where CURVES is either a cell array or structure array 
%  of NURBS representation structures created from NRBMAK in the NURBS
%  toolbox.  NRBLOFT performs the lofting procedure in the order which the
%  elements are specified in CURVES.
%
%  NRBLOFT(X,Y,Z) lofts a NURBS surface based on the data in the rows of
%  each element of the 2D arrays specified in X,Y,Z. 
%
%  NRBLOFT(X,Y,Z,dir) allows the user to switch from row-wise interpolation
%  to columnwise (dir = 1 or 2, respectively).  NRBLOFT forces the degree 
%  of the specified direction (dir) to be 4th order (cubic).
%
%  NRBLOFT(...,mode) specifies an interpolation mode used in generating
%  a control point mesh for the surface.  The default for mode is 2, but
%  the user can also specify mode = 1.  This is not recommended, and often
%  causes computation time to increase exponentially.  However, it may be
%  useful to try this mode in certain instances.
%
%  NRBLOFT requires the NURBS toolbox found at:
%  http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId
%  =312&objectType=file
%  
%
%  %Example 1:
%  [X,Y,Z]=peaks(15);
%  nrb = nrbloft(X,Y,Z);
%  figure; nrbplot(nrb,[50,50]);
%
%  %Example 2:
%  pnts = [ 0.0  3.0  4.5  6.5 8.0 10.0; 0.0  0.0  0.0  0.0 0.0  0.0;... 
%             2.0  2.0  7.0  4.0 7.0  9.0];   
%  testcrv = nrbmak(pnts, [0 0 0 1/3 0.5 2/3 1 1 1]);
%  crv{1} = testcrv; crv{2} = testcrv;  crv{3} = testcrv;
%  crv{2}.coefs(2,:) = 5;  crv{3}.coefs(2,:) = 10;
%  crv{2}.coefs(3,:) = 2*crv{2}.coefs(3,:);
%  crv{3}.coefs(3,:) = -crv{3}.coefs(3,:)+10;
%  nrb = nrbloft(crv);
%  figure; hold on; for i=1:3, nrbplot(crv{i},50); end
%  axis equal; axis tight
%  view(135,45); pause(2);  nrbplot(nrb,[50,50]);
%
%  See Also:  NRBMAK

if nargin == 1,
    mode = 2;
end

if ~isstruct(X) && ~iscell(X)
    switch nargin
        case 3
            dir = 1;
            mode = 2;
        case 4
            mode = 2;
        case 5
        otherwise
            error('At least 3 inputs required for array inputs');
    end
    switch dir
        case 1
            for i=1:size(X,1)
                u(i) = nrbinterp(X(i,:),Y(i,:), Z(i,:),1);
            end
        case 2
            for i=1:size(X,2)
                u(i) = nrbinterp(X(:,i), Y(:,i), Z(:,i),1);
            end
        otherwise
            error('4th argument must either be 1 or 2')
    end
else
    u = X;
    if nargin == 2
        mode = Y;
    end
    if iscell(u)
       for i=1:length(u)
          uu(i) = u{i}; 
       end
       u = uu;
    end
end

if isstruct(u(1)) && isfield(u(1),'form')
    field = getfield(u(1),'form');
    if ~strcmp(field(1:2),'B-')
        error('Curves must be in B-NURBS form');
    end
else
    error('Each element of a single input must be a NURBS structure array');
end

nn = length(u);

% ensure all curves have a common degree in u-direction
u = commonDegree(u);
% merge the knot vectors, to obtain a common knot vector in u-direction
u = mergeKnots(u);

for i=1:nn
    coefs(:,:,i) = u(i).coefs;
end

% all u direction curves have the same knot vector so we only need one
uknots = u(1).knots;

% extract x,y,z coefficient data
x = squeeze(coefs(1,:,:));
y = squeeze(coefs(2,:,:));
z = squeeze(coefs(3,:,:));

% Interpolate through control points
for i=1:size(x,1)
    v(i) = nrbinterp(x(i,:),y(i,:),z(i,:),mode);
end
% ensure all curves have a common degree in v-direction
v = commonDegree(v);
% merge the knot vectors, to obtain a common knot vector in v-direction
v = mergeKnots(v);
% all v direction curves have the same knot vector so we only need one
vknots = v(1).knots;
% assemble new surface coefficient array from each curve 
for i=1:length(v)
    c(:,:,i) = v(i).coefs;
end

srf = nrbmak(c,{vknots uknots});
srf = nrbtransp(srf);


return





function crv = commonDegree(crv)
nn = length(crv);
% d = max(cell2vec({crv.order}));
for i=1:nn
    d(i) = crv(i).order;
end
d = max(d);
for i=1:nn,
    degree_raised = d - crv(i).order;
    if degree_raised < 0
       disp('NRBLOFT: Problem may have occured during degree elevation');
    end
    if degree_raised > 0
        crv(i) = nrbdegelev(crv(i), degree_raised);
    end
end


function crv = mergeKnots(crv)
nn = length(crv);
k = ({crv.knots});
ku = unique(cell2vec(k));
n = length(ku);
ka = cell(1,nn);
for i = 1:n
    for j=1:nn
        ii(j) = length(find(k{j} == ku(i)));
    end
    m = max(ii);
    for j=1:nn
        ka{j} = [ka{j} ku(i)*ones(1,m-ii(j))];
    end
end

% Do knot insertion where necessary in each curve
for i=1:nn
    crv(i) = nrbkntins(crv(i), ka{i});
end



function v = cell2vec(c)
n = numel(c);
v = [];
for i=1:n
    t = c{i};
    t = t(:);
    v = [v; t];
end


function nrb = nrbinterp(x,y,z,mode)

ctrlpts = [x(:)'; y(:)'; z(:)'];

switch mode
    case 1
        sp = cscvn(ctrlpts);
    case 2
        sp = nintrp1(ctrlpts);
    otherwise
        error('Invalid mode type');
end

% Convert piecewise polynomial to nurbs
nrb = pp2nrb(sp);


function sp = nintrp1(ctrlpts)
n = size(ctrlpts,2);
x = linspace(0,1,n);
sp = csapi(x,ctrlpts);


function nrb = pp2nrb(pp)
b = pp2sp(pp);
nrb = nrbmak(b.coefs,b.knots);

Contact us