# NRBLOFT

### Daniel Claxton (view profile)

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:
%  =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]);
%

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);
```