I need to plot lines on a 3d surface in matlab. I wrote two scripts one to plot the surface and one to plot the lines on the surface.
script1
function figHandle = plotFunction(funchandle, a , b)
x_vec = -a:.1:a;
y_vec = -b:.1:b;
figHandle = figure();
[X,Y] = meshgrid(x_vec, y_vec);
Z = [];
z_temp = [];
for i = x_vec
for j = y_vec
z_temp =[z_temp; funchandle([i; j])];
end;
Z = [Z, z_temp];
z_temp = [];
end;
h = surf(X,Y,Z);
set(h, 'edgecolor', 'none');
%colormap gray;
colorbar;
view(0,90);
end
script2
function plotStep(figHandle,funcHandle, P1, P2)
figure(figHandle);
hold on;
plot3(P1(1), P1(2), funcHandle([P1(1);P1(2)]), 'r*');
if ~isequal(P1,P2)
Z = [];
X = [];
Y = [];
d = [P2(1)-P1(1), P2(2) - P1(2)];
if (P1(1) < P2(1))
X = P1(1):0.0001:P2(1);
if (P1(2) ~= P2(2))
Y = X.*(d(2)/d(1))+(P1(2)-(d(2)/d(1))*P1(1));
else
for i = X
Y = [Y, P1(2)];
end
end
elseif P1(1) > P2(1)
X = P1(1):-0.0001:P2(1);
if (P1(2) ~= P2(2))
Y = X.*(d(2)/d(1))+(P1(2)-(d(2)/d(1))*P1(1));
else
for i = X
Y = [Y, P1(2)];
end
end
else
if P1(2) < P2(2)
Y = P1(2):0.0001:P2(2);
for i = Y
X = [X, P1(1)];
end
else
Y = P1(2):-0.0001:P2(2);
for i = Y
X = [X, P1(1)];
end
end
end
for i = 1:length(X)
Z = [Z;funcHandle([X(i);Y(i)])];
end
plot3(X, Y, Z, 'r', 'LineWidth', 2);
end
My problem is no matter how close too each other I make the points which form the line after zooming in on the line it does not seem to be continuous.
The simplest way to fix this is to raise the line a little bit off the surface,
plot3(X, Y, Z+1, 'r', 'LineWidth', 2);
but you may have to experiment with the offset. It can sometimes help to make the line a little wider, and to try the different renderers as well.
Related
I am having an issue with plotting my airfoil on matlab. It appears that there are some abberations with only one or two values. I have checked again and again with the formulas so they should be good. I have not converted to degrees so that's not the issue.
%% setup
clc
clear all
%type of airfoil
typeNACA = '2312';
%extract values of airfoil type
M = str2double(typeNACA(1)); % max camber %chord
P = str2double(typeNACA(2)); % chordwise position
Thmax = str2double(typeNACA(3:4));
M=M/100;
P=P/100
Thmax=Thmax/100;
% gridpoints
gridpoints = 1000;
% Airfoil grid
x = linspace(0,1,gridpoints);
%camber equations
%yc1(x) = (M/P^2)*(2*P*x-x^2);
%yc(x) = (M/(1-P)^2*(1-2*P+2*Px-x^2); % (for P =< x <1)
%dyc1 = (2*M/P^2)*(P-x)
%dyc2 = (2*M)/(1-P^2)*(P-x)
%Camber and gradient
yc = ones(gridpoints,1);
dyc= ones(gridpoints,1);
theta=ones(gridpoints,1);
for i=1:gridpoints
if (x(i) >= 0 && x(i) < P)
yc(i) = (M/P^2)*(2*P*x(i)-x(i)^2); % (for 0 =< x < P)
dyc(i)= ((2*M)/P^2)*(P - x(i)); %dyc/dx
elseif (x(i) >= P && x(i) <= 1) % (for P =< x <1)
yc(i)=(M/(1-P)^2)*(1-2*P+2*P*x(i)-x(i)^2);
dyc(i) = (2*M)/((1-P)^2*(P-x(i)));
end
theta(i) = atan(dyc(i)); %angle theta
end
% thickness coefficients
a0 = 0.2969;
a1 = -0.126;
a2 = -0.3516;
a3 = 0.2843;
a4 = -0.1036; % -0.1015 for open TE -0.1036 for closed TE
%thickness distribution
yt = ones(gridpoints,1);
for i=1:1:gridpoints
yt(i) = (Thmax/0.2)*(a0*x(i)^0.5 + a1*x(i) + a2*x(i)^2 + a3*x(i)^3 + a4*x(i)^4);
end
% Upper surface points
xu = ones(gridpoints,1);
yu = ones(gridpoints,1);
for i= 1:gridpoints
xu(i) = x(i) - yt(i)*sin(theta(i));
yu(i) = yc(i) + yt(i)*cos(theta(i));
end
% Lower surface points
xl = ones(gridpoints,1);
yl = ones(gridpoints,1);
for i=1:1:gridpoints
xl(i) = x(i) + yt(i)*sin(theta(i));
yl(i) = yc(i) - yt(i)*cos(theta(i));
end
%PLOT
f1 = figure(1);
hold on; grid on;
axis equal
plot(xu,yu,'r';
plot(xl,yl,'b');
well! The first problem is you've forgotten the closing parenthesis in the second line from the end. But if you want me to check your code, I need to have your typeNACA() function .m file to revise it. Or u can post its code here.
%PLOT
f1 = figure(1);
hold on; grid on;
axis equal
plot(xu,yu,'r';
plot(xl,yl,'b');
I need to extract the isoline coordinates of a 4D variable from a 3D surface defined using a triangulated mesh in MATLAB. I need the isoline coordinates to be a ordered in such a manner that if they were followed in order they would trace the path i.e. the order of the points a 3D printer would follow.
I have found a function that can calculate the coordinates of these isolines (see Isoline function here) but the problem is this function does not consider the isolines to be joined in the correct order and is instead a series of 2 points separated by a Nan value. This makes this function only suitable for visualisation purposes and not the path to follow.
Here is a MWE of the problem of a simplified problem, the surface I'm applying it too is much more complex and I cannot share it. Where x, y and z are nodes, with TRI providing the element connectivity list and v is the variable of which I want the isolines extracted from and is not equal to z.
If anyone has any idea on either.....
A function to extract isoline values in the correct order for a 3D tri mesh.
How to sort the data given by the function Isoline so that they are in the correct order.
.... it would be very much appreciated.
Here is the MWE,
% Create coordinates
[x y] = meshgrid( -10:0.5:10, -10:0.5:10 );
z = (x.^2 + y.^2)/20; % Z height
v = x+y; % 4th dimension value
% Reshape coordinates into list to be converted to tri mesh
x = reshape(x,[],1); y = reshape(y,[],1); z = reshape(z,[],1); v = reshape(v,[],1);
TRI = delaunay(x,y); % Convertion to a tri mesh
% This function calculates the isoline coordinates
[xTows, yTows, zTows] = IsoLine( {TRI,[x, y, z]}, v, -18:2:18);
% Plotting
figure(1); clf(1)
subplot(1,2,1)
trisurf(TRI,x,y,z,v)
hold on
for i = 1:size(xTows,1)
plot3( xTows{i,1}, yTows{i,1}, zTows{i,1}, '-k')
end
hold off
shading interp
xlabel('x'); ylabel('y'); zlabel('z'); title('Isolines'), axis equal
%% This section is solely to show that the isolines are not in order
for i = 1:size(xTows,1)
% Arranging data into colums and getting rid of Nans that appear
xb = xTows{i,1}; yb = yTows{i,1}; zb = zTows{i,1};
xb = reshape(xb, 3, [])'; xb(:,3) = [];
yb = reshape(yb, 3, [])'; yb(:,3) = [];
zb = reshape(zb, 3, [])'; zb(:,3) = [];
subplot(1,2,2)
trisurf(TRI,x,y,z,v)
shading interp
view(2)
xlabel('x'); ylabel('y'); zlabel('z'); title('Plotting Isolines in Order')
axis equal; axis tight; hold on
for i = 1:size(xb,1)
plot3( [xb(i,1) xb(i,2)], [yb(i,1) yb(i,2)], [zb(i,1) zb(i,2)], '-k')
drawnow
end
end
and here is the function Isoline, which I have slightly adpated.
function [xTows, yTows, zTows] = IsoLine(Surf,F,V,Col)
if length(Surf)==3 % convert mesh to triangulation
P = [Surf{1}(:) Surf{2}(:) Surf{3}(:)];
Surf{1}(end,:) = 1i;
Surf{1}(:,end) = 1i;
i = find(~imag(Surf{1}(:)));
n = size(Surf{1},1);
T = [i i+1 i+n; i+1 i+n+1 i+n];
else
T = Surf{1};
P = Surf{2};
end
f = F(T(:));
if nargin==2
V = linspace(min(f),max(f),22);
V = V(2:end-1);
elseif numel(V)==1
V = linspace(min(f),max(f),V+2);
V = V(2:end-1);
end
if nargin<4
Col = 'k';
end
H = NaN + V(:);
q = [1:3 1:3];
% -------------------------------------------------------------------------
% Loop over iso-values ----------------------------------------------------
xTows = [];
yTows = [];
zTows = [];
for k = 1:numel(V)
R = {[],[]};
G = F(T) - V(k);
C = 1./(1-G./G(:,[2 3 1]));
f = unique(T(~isfinite(C))); % remove degeneracies by random perturbation
F(f) = F(f).*(1+1e-12*rand(size(F(f)))) + 1e-12*rand(size(F(f)));
G = F(T) - V(k);
C = 1./(1-G./G(:,[2 3 1]));
C(C<0|C>1) = -1;
% process active triangles
for i = 1:3
f = any(C>=0,2) & C(:,i)<0;
for j = i+1:i+2
w = C(f,q([j j j]));
R{j-i} = [R{j-i}; w.*P(T(f,q(j)),:)+(1-w).*P(T(f,q(j+1)),:)];
end
end
% define isoline
for i = 1:3
X{i} = [R{1}(:,i) R{2}(:,i) nan+R{1}(:,i)]';
% X{i} = [R{1}(:,i) R{2}(:,i)]'; % Changed by Matt
X{i} = X{i}(:)';
end
% plot isoline
if ~isempty(R{1})
% hold on
% H(k) = plot3(X{1},X{2},X{3},Col);
% Added by M.Thomas
xTows{k,1} = X{1};
yTows{k,1} = X{2};
zTows{k,1} = X{3};
end
end
What you will notice is that the isolines (xTows, yTows and zTows) are not in order there "jump around" when plotted sequentially. I need to sort the tows so that they give a smooth plot in order.
I have a code that creates the correct xy plot for elastic pendulum with spring. I would like to show an animation of the elastic spring pendulum on an xy plot as the system marches forward in time. How can this be done?
Here is my simulation code:
clc
clear all;
%Define parameters
global M K L g;
M = 1;
K = 25.6;
L = 1;
g = 9.8;
% define initial values for theta, thetad, del, deld
theta_0 = 0;
thetad_0 = .5;
del_0 = 1;
deld_0 = 0;
initialValues = [theta_0, thetad_0, del_0, deld_0];
% Set a timespan
t_initial = 0;
t_final = 36;
dt = .1;
N = (t_final - t_initial)/dt;
timeSpan = linspace(t_final, t_initial, N);
% Run ode45 to get z (theta, thetad, del, deld)
[t, z] = ode45(#OdeFunHndlSpngPdlmSym, timeSpan, initialValues);
% initialize empty column vectors for theta, thetad, del, deld
M_loop = zeros(N, 1);
L_loop = zeros(N, 1);
theta = zeros(N, 1);
thetad = zeros(N, 1);
del = zeros(N, 1);
deld = zeros(N, 1);
T = zeros(N, 1);
x = zeros(N, 1);
y = zeros(N, 1);
% Assign values for variables (theta, thetad, del, deld)
for i = 1:N
M_loop(i) = M;
L_loop(i) = L;
theta(i) = z(i, 1);
thetad(i) = z(i, 2);
del(i) = z(i, 3);
deld(i) = z(i, 4);
T(i) = (M*(thetad(i)^2*(L + del(i))^2 + deld(i)^2))/2;
V(i) = (K*del(i)^2)/2 + M*g*(L - cos(theta(i))*(L + del(i)));
E(i) = T(i) + V(i);
x(i) = (L + del(i))*sin(theta(i));
y(i) = -(L + del(i))*cos(theta(i));
end
figure(1)
plot(x, y,'r');
title('XY Plot');
xlabel('x position');
ylabel('y position');
Here is my function code:
function dz = OdeFunHndlSpngPdlmSym(~, z)
% Define Global Parameters
global M K L g
% Take output from SymDevFElSpringPdlm.m file for fy1 and fy2 and
% substitute into z2 and z4 respectively
%fy1=thetadd=z(2)= -(M*g*sin(z1)*(L + z3) + M*z2*z4*(2*L + 2*z3))/(M*(L + z3)^2)
%fy2=deldd=z(4)=((M*(2*L + 2*z3)*z2^2)/2 - K*z3 + M*g*cos(z1))/M
% return column vector [thetad; thetadd; deld; deldd]
dz = [z(2);
-(M*g*sin(z(1))*(L + z(3)) + M*z(2)*z(4)*(2*L + 2*z(3)))/(M*(L + z(3))^2);
z(4);
((M*(2*L + 2*z(3))*z(2)^2)/2 - K*z(3) + M*g*cos(z(1)))/M];
You can "simulate" animation in a plot with a continous updating FOR loop and assignig graphic object to variables.
Something like (I assume only to use x,y as arrays function of time array t)
%In order to block the axis and preventing continuous zoom, choose proper axes limit
x_lim = 100; %these values depends on you, these are examples
y_lim = 100;
axis equal
axis([-x_lim x_lim -y_lim y_lim]); %now x and y axes are fixed from -100 to 100
ax = gca;
for i=1:length(t)
if i > 1
delete(P);
delete(L);
end
P = plot(x(i),y(i)); %draw the point
hold on
L = quiver(0,0,x(i),y(i)); %draw a vector from 0,0 to the point
hold on
%other drawings
drawnow
pause(0.1) %pause in seconds needed to simulate animaton.
end
"Hold on" instruction after every plot instruction.
This is only a basic animation, of course.
This is a continuation from the question already posted here. I used the method that #Andrey suggested. But there seems to be a limitation. the set(handle, 'XData', x) command seems to work as long as x is a vector. what if x is a matrix?
Let me explain with an example.
Say we want to draw 3 rectangles whose vertices are given by the matrices x_vals (5,3 matrix) and y_vals (5,3 matrix). The command that will be used to plot is simply plot(x,y).
Now, we want to update the above plot. This time we want to draw 4 rectangles. whose vertices are present in the matrices x_new(5,4 matrix) and y_new (5,4 matrix) that we obtain after some calculations. Now using the command set(handle, 'XData', x, 'YData', y) after updating x and y with new values results in an error that states
Error using set
Value must be a column or row vector
Any way to solve this problem?
function [] = visualizeXYZ_struct_v3(super_struct, start_frame, end_frame)
% create first instance
no_objs = length(super_struct(1).result);
x = zeros(1,3000);
y = zeros(1,3000);
box_x = zeros(5, no_objs);
box_y = zeros(5, no_objs);
fp = 1;
% cascade values across structures in a frame so it can be plot at once;
for i = 1:1:no_objs
XYZ = super_struct(1).result(i).point_xyz;
[r,~] = size(XYZ);
x(fp:fp+r-1) = XYZ(:,1);
y(fp:fp+r-1) = XYZ(:,2);
% z(fp:fp+r-1) = xyz):,3);
fp = fp + r;
c = super_struct(1).result(i).box;
box_x(:,i) = c(:,1);
box_y(:,i) = c(:,2);
end
x(fp:end) = [];
y(fp:end) = [];
fig = figure('position', [50 50 1280 720]);
hScatter = scatter(x,y,1);
hold all
hPlot = plot(box_x,box_y,'r');
axis([-10000, 10000, -10000, 10000])
xlabel('X axis');
ylabel('Y axis');
hold off
grid off
title('Filtered Frame');
tic
for num = start_frame:1:end_frame
no_objs = length(super_struct(num).result);
x = zeros(1,3000);
y = zeros(1,3000);
box_x = zeros(5, no_objs);
box_y = zeros(5, no_objs);
fp = 1;
% cascade values accross structures in a frame so it can be plot at once;
for i = 1:1:no_objs
XYZ = super_struct(num).result(i).point_xyz;
[r,~] = size(XYZ);
x(fp:fp+r-1) = XYZ(:,1);
y(fp:fp+r-1) = XYZ(:,2);
fp = fp + r;
c = super_struct(num).result(i).box;
box_x(:,i) = c(:,1);
box_y(:,i) = c(:,2);
end
x(fp:end) = [];
y(fp:end) = [];
set(hScatter, 'XData', x, 'YData', y);
set(hPlot, 'XData', box_x, 'YData', box_y); % This is where the error occurs
end
toc
end
Each line on the plot has its own XData and YData properties, and each can be set to a vector individually. See the reference. I am not at a Matlab console right now, but as I recall...
kidnum = 1
h_axis = gca % current axis - lines are children of the axis
kids = get(h_axis,'Children')
for kid = kids
kid_type = get(kid,'type')
if kid_type == 'line'
set(kid,'XData',x_new(:,kidnum))
set(kid,'YData',y_new(:,kidnum))
kidnum = kidnum+1
end
end
Hope that helps! See also the overall reference to graphics objects and properties.
To add a series, say
hold on % so each "plot" won't touch the lines that are already there
plot(x_new(:,end), y_new(:,end)) % or whatever parameters you want to plot
After that, the new series will be a child of h_axis and can be modified.
It is beginning to annoy me that I can't get rid of this vertical line that keeps appearing when I plot the area;
[x y] = ginputExtra(4)
x = 0.1947 0.6118 0.8329 0.4136
y = 0.5746 0.8173 0.4225 0.3553
area([x x(1)],[y y(1)])
[x y] = ginputExtra(4,true)
x = 0.5087 0.6881 0.4954 0.3204
y = 0.4961 0.2382 0.1566 0.3566
hold on;
area([x x(1)],[y y(1)],'FaceColor',[1 0 0])
Is there any way to avoid this line?
BTW: the ginputExtra method call I use..
function [x y] = ginputExtra(n,booText)
% INPUT
% n: Number of points to plot
% booText: Boolean (default false) command to display point number in
% the plot.
% Author: Lasse Nørfeldt (Norfeldt)
% Date: 2012-04-09
if nargin ==2
bText = booText;
else
bText = false;
end
H = gca;
set(H, 'YLimMode', 'manual'); set(H, 'XLimMode', 'manual');
set(H, 'YLim', get(H,'YLim')); set(H, 'XLim', get(H,'XLim'));
numPoints = n; xg = []; yg = [];
for i=1:numPoints
[xi yi] = ginput(1);
xg = [xg xi]; yg = [yg yi];
if i == 1
hold on;
plot(H, xg(i),yg(i),'ro');
if bText text(xg(i),yg(i),num2str(i),'FontSize',14); end
else
plot(xg([i-1:i]),yg([i-1:i]),'r');
if bText text(xg(i),yg(i),num2str(i),'FontSize',14); end
end
end
hold off;
x = xg; y = yg;
Your issue might be in plotting by area(), as it seems to be primarily for stacking several vecotrs. If you zoom out a bit and see a similar vertical line from the first point in the blue area, the area function is most likely the issue.
The function:
fill([x x(1)],[y y(1)],COLOR)
Might do the trick for you, as it plots a filled polygon.
/Thomas