MATLAB Answers

How can I get a variable as an output and use it in my main script?

6 views (last 30 days)
Mete Naz
Mete Naz on 28 Jul 2018
Commented: Mete Naz on 29 Jul 2018
Hi! I have Xvec,Yvec and Zvec in my function and I want to use them in another function however I cannot take them out to put them in my main script. Everytime I try, it gives me:
Output argument "Xvec" (and maybe others) not assigned during call to "surfnorm1".
Error in NormalLinesFatMap (line 98)
[Nx,Ny,Nz] = surfnorm1(x,y,z);
I do not know how I will be able to call it in my main script. Could anyone please help me fix it?
function [Xvec,Yvec,Zvec] = surfnorm1(varargin)
%SURFNORM Surface normals.
% [Nx,Ny,Nz] = SURFNORM(X,Y,Z) returns the components of the 3-D
% surface normal for the surface with components (X,Y,Z). The
% normal is normalized to length 1.
% [Nx,Ny,Nz] = SURFNORM(Z) returns the surface normal components
% for the surface Z.
% Without lefthand arguments, SURFNORM(X,Y,Z) or SURFNORM(Z)
% plots the surface with the normals emanating from it.
% SURFNORM(AX,...) plots into AX instead of GCA.
% SURFNORM(...,'PropertyName',PropertyValue,...) can be used to set
% the value of the specified surface property. Multiple property
% values can be set with a single statement.
% The surface normals returned are based on a bicubic fit of
% the data. Use SURFNORM(X',Y',Z') to reverse the direction
% of the normals.
% Clay M. Thompson 1-15-91
% Revised 8-5-91, 9-17-91 by cmt.
[cax,args] = axescheck(varargin{:});
[reg, prop]=parseparams(args);
if nargs < 1
elseif nargs > 3
if rem(length(prop),2)~=0
if nargs==1
z = x;
[m,n] = size(z);
[x,y] = meshgrid(1:n,1:m);
elseif nargs==2
elseif nargs==3
[m,n] = size(x);
if ~isequal(size(y),[m,n])
if ~isequal(size(z),[m,n])
if any([m n]<3), error(message('MATLAB:surfnorm:InvalidZValue')); end
stencil1 = [1 0 -1]/2;
stencil2 = [-1;0;1]/2;
if nargout==0 % If plotting, then scale to match plot aspect ratio.
% Determine plot scaling factors for a cube-like plot domain.
if isempty(cax)
cax = gca;
nextPlot = cax.NextPlot;
a = [get(cax,'xlim') get(cax,'ylim') get(cax,'zlim')];
Sx = a(2)-a(1);
Sy = a(4)-a(3);
Sz = a(6)-a(5);
scale = max([Sx,Sy,Sz]);
Sx = Sx/scale; Sy = Sy/scale; Sz = Sz/scale;
% Scale surface
xx = x/Sx; yy = y/Sy; zz = z/Sz;
xx = x; yy = y; zz = z;
% Expand x,y,z so interpolation is valid at the boundaries.
xx = [3*xx(1,:)-3*xx(2,:)+xx(3,:);xx;3*xx(m,:)-3*xx(m-1,:)+xx(m-2,:)];
xx = [3*xx(:,1)-3*xx(:,2)+xx(:,3),xx,3*xx(:,n)-3*xx(:,n-1)+xx(:,n-2)];
yy = [3*yy(1,:)-3*yy(2,:)+yy(3,:);yy;3*yy(m,:)-3*yy(m-1,:)+yy(m-2,:)];
yy = [3*yy(:,1)-3*yy(:,2)+yy(:,3),yy,3*yy(:,n)-3*yy(:,n-1)+yy(:,n-2)];
zz = [3*zz(1,:)-3*zz(2,:)+zz(3,:);zz;3*zz(m,:)-3*zz(m-1,:)+zz(m-2,:)];
zz = [3*zz(:,1)-3*zz(:,2)+zz(:,3),zz,3*zz(:,n)-3*zz(:,n-1)+zz(:,n-2)];
rows = 2:m+1; cols = 2:n+1;
ax = filter2(stencil1,xx); ax = ax(rows,cols);
ay = filter2(stencil1,yy); ay = ay(rows,cols);
az = filter2(stencil1,zz); az = az(rows,cols);
bx = filter2(stencil2,xx); bx = bx(rows,cols);
by = filter2(stencil2,yy); by = by(rows,cols);
bz = filter2(stencil2,zz); bz = bz(rows,cols);
% Perform cross product to get normals
nx = -(ay.*bz - az.*by);
ny = -(az.*bx - ax.*bz);
nz = -(ax.*by - ay.*bx);
if nargout==0
% Set the length of the surface normals
mag = sqrt(nx.*nx+ny.*ny+nz.*nz)*(10/scale);
d = find(mag==0); mag(d) = eps*ones(size(d));
nx = nx ./mag;
ny = ny ./mag;
nz = nz ./mag;
% Normal vector points
xc = x; yc = y; zc = z;
% Set NextPlot to 'add' so that the line is added to the existing axes.
% 'surf' calls 'newplot', so the Figure's NextPlot property will
% already be set to 'add' at this point.
cax.NextPlot = 'add';
movieName = sprintf('normalLines_%.2d.avi');
vidObj = VideoWriter(movieName);
vidObj.Quality = 100;
vidObj.FrameRate = 10;
% use nan trick here
xp = [xc(:) Sx*nx(:)+xc(:) nan([numel(xc) 1])]';
yp = [yc(:) Sy*ny(:)+yc(:) nan([numel(xc) 1])]';
zp = [zc(:) Sz*nz(:)+zc(:) nan([numel(xc) 1])]';
for jj=1:length(nz(1,:))
for ii=1:length(nz(:,1))
t = 0.5;
k = 3;
x1 = x(ii,jj) - t*nx(ii,jj);
y1 = y(ii,jj) - t*ny(ii,jj);
z1 = z(ii,jj) - t*nz(ii,jj);
x2 = x(ii,jj) + k*nx(ii,jj);
y2 = y(ii,jj) + k*ny(ii,jj);
z2 = z(ii,jj) + k*nz(ii,jj);
Xvec(ii,:) = [x1, x2];
Yvec(ii,:) = [y1, y2];
Zvec(ii,:) = [z1, z2];
axis equal
% grab current plot for movie frame
currFrame = getframe(gcf);
% Restore the original value for NextPlot.
cax.NextPlot = nextPlot;
% Normalize the length of the surface normals to 1.
mag = sqrt(nx.*nx+ny.*ny+nz.*nz);
d = find(mag==0); mag(d) = eps*ones(size(d));
nxout = nx ./mag;
nyout = ny ./mag;
nzout = nz ./mag;
Copyright 1984-2017 The MathWorks, Inc.


Show 5 older comments
Mete Naz
Mete Naz on 28 Jul 2018
I have one more question.. I am really sorry.. The output is now different than Xvec,Yvec,Zvec.. Is it getting the last 3 lines as output? There are nxout,nyout and nzout at the end... Do you have an idea how to get Xvec,Yvec,Zvec as an output? Do I have to change the last 3 lines?
Thanks in advance!
dpb on 28 Jul 2018
As I suggested, you need to read the code in detail to understand what it is doing and where to make changes to accomplish a specific objective.
The function definition is
function [Xvec,Yvec,Zvec] = surfnorm1(varargin)
so only whatever is computed for those three variables will be returned; any other variables in the function are purely local variables not to be seen outside the function.
As it currently is written, none of that code after the end of the second if nargout ... block has any bearing on anything either inside nor outside the function--it computes some things, but there is nothing done with them afterwards so effectively it's "do nothing" code.
What you get returned is what was calculated for the three variables; whether that's what you were expecting or not we can't answer but the code is what it is...
No idea who did what when in the code, but it looks kinda' like the returned values instead of [XYZ]vec really ought to be those normalized values; they're calculated irrespective of the value of nargout (albeit done twice if nargout>0 altho there is a scaling difference between plotting and not for some reason) so that probably what actually want is
function [nxout,nyout,nzout] = surfnorm1(varargin)
and put the original logic test back as it was.
If the function were mine, however, I'd move that calculation that is inside the if construct out since it's needed either way and remove the duplication at the end simply fixing up the normalization, but it's so little actual code that other than aesthetics and having duplicated code it's not that big a deal, it's just kinda' klunky.
Mete Naz
Mete Naz on 29 Jul 2018
Hi dpb, I have been going through the code line by line since yesterday. I have fixed the problem based on your directions now I can get Xvec Yvec and Zvec as outputs which I only needs them out to use them in another function. There is only one issue.. The code only gets the last loop data for XYZvec matrixes. I assume the problem is here:
Xvec(ii,:) = [x1, x2]; Yvec(ii,:) = [y1, y2]; Zvec(ii,:) = [z1, z2];
Would you possibly have any suggestions on what I should change to get all the data collected from the loop? I really appreciate your help!

Sign in to comment.

Answers (0)

Community Treasure Hunt

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

Start Hunting!