I like to visualize conics with Matlab or Octave. The (general) conic is given by the equation 0 = ax² + bxy + cy² +dxz +eyz+f*z² for a point p=(x,y,z). How can I plot this with Matlab or octave if I know the parameters a,b,c,d,e and f? Or respectively, how can I find the points that satisfy this equation?
Since you are asking for the conics, I understand that you are probably referring to the 2D contours of the general conic equation. I will also cover how to visualize this equation in other different ways.
For all the following examples, I have set the conic constants so that I obtain a hiperboloid.
My code is written in MATLAB syntax. If you are using Octave, it might differ slightly.
Visualizing 2D Conics with CONTOUR
I have isolated z in terms of x and y, from the general conic equation:
z = (1/2)*(-d*x-e*y±sqrt(-4*a*f*x.^2-4*b*f*x.*y-4*c*f*y.^2+d^2*x.^2+2*d*e*x.*y+e^2*y.^2))/f;
Since z is a piecewise function due to (± sqrt), I need to make sure that I plot both hemispheres. I designate z1 for +sqrt, and z2 for -sqrt.
Finally, I plot the contours for z1 and z2 that will yield the set of conics in 2D. This conics will be circles of different radius.
Code:
clear all;
clc;
% Conic constants.
a = 1;
b = 0;
c = 1;
d = 0;
e = 0;
f = -1;
% Value for x and y domain.
v = 10;
% Domain for x and y.
x = linspace(-v,v);
y = linspace(-v,v);
% Generate a 2D mesh with x and y.
[x,y] = meshgrid(x,y);
% Isolate z in terms of x and y.
z1 = (1/2)*(-d*x-e*y+sqrt(-4*a*f*x.^2-4*b*f*x.*y-4*c*f*y.^2+d^2*x.^2+2*d*e*x.*y+e^2*y.^2))/f;
z2 = (1/2)*(-d*x-e*y-sqrt(-4*a*f*x.^2-4*b*f*x.*y-4*c*f*y.^2+d^2*x.^2+2*d*e*x.*y+e^2*y.^2))/f;
% Find complex entries in z.
i = find(real(z1)~=z1);
j = find(real(z2)~=z2);
% Replace complex entries with NaN.
z1(i) = NaN;
z2(j) = NaN;
figure;
subplot(1,2,1);
% Draw lower hemisphere.
contour(x,y,z1,'ShowText','on');
% Adjust figure properties.
title('2D Conics: Lower hemishphere');
xlabel('x-axis');
ylabel('y-axis');
axis equal;
grid on;
box on;
axis([-10 10 -10 10]);
subplot(1,2,2);
% Draw upper hemisphere.
contour(x,y,z2,'ShowText','on');
hold off;
% Adjust figure properties.
title('2D Conics: Upper hemishphere');
xlabel('x-axis');
ylabel('y-axis');
axis equal;
grid on;
box on;
axis([-10 10 -10 10]);
Output:
Visualizing 3D Conics with CONTOUR3
Same as on the previous example, but now we plot the set of conics in 3D.
Code:
clear all;
clc;
% Conic constants.
a = 1;
b = 0;
c = 1;
d = 0;
e = 0;
f = -1;
% Value for x and y domain.
v = 10;
% Domain for x and y.
x = linspace(-v,v);
y = linspace(-v,v);
% Generate a 2D mesh with x and y.
[x,y] = meshgrid(x,y);
% Isolate z in terms of x and y.
z1 = (1/2)*(-d*x-e*y+sqrt(-4*a*f*x.^2-4*b*f*x.*y-4*c*f*y.^2+d^2*x.^2+2*d*e*x.*y+e^2*y.^2))/f;
z2 = (1/2)*(-d*x-e*y-sqrt(-4*a*f*x.^2-4*b*f*x.*y-4*c*f*y.^2+d^2*x.^2+2*d*e*x.*y+e^2*y.^2))/f;
% Find complex entries in z.
i = find(real(z1)~=z1);
j = find(real(z2)~=z2);
% Replace complex entries with NaN.
z1(i) = NaN;
z2(j) = NaN;
% Lower hemisphere. Draw 20 conics.
contour3(x,y,z1,20);
hold on;
% Upper hemisphere. Draw 20 conics.
contour3(x,y,z2,20);
hold off;
% Adjust figure properties.
title('3D Conics');
xlabel('x-axis');
ylabel('y-axis');
zlabel('z-axis');
axis equal;
grid on;
box on;
axis([-10 10 -10 10 -10 10]);
Output:
Visualizing Quadrics with ISOSURFACE
I have isolated f in terms of x, y and z, from the general conic equation, and renamed it to f_eq:
f_eq = -(a*x.^2+b*x.*y+c*y.^2+d*x.*z+e*y.*z)./z.^2;
Finally, I obtain the set of points that satisfy the equation f_eq = f, which is in fact an isosurface that yields a quadric; in this example a hiperboloid.
Code:
clear all;
clc;
% Conic constants.
a = 1;
b = 0;
c = 1;
d = 0;
e = 0;
f = -1;
% Value for x, y and z domain.
v = 10;
% Domain for x ,y and z.
x = linspace(-v,v);
y = linspace(-v,v);
z = linspace(-v,v);
% Generate a 3D mesh with x, y and z.
[x,y,z] = meshgrid(x,y,z);
% Evaluate function (3D volume of data).
f_eq = -(a*x.^2+b*x.*y+c*y.^2+d*x.*z+e*y.*z)./z.^2;
% Draw the surface that matches f_eq = f.
p = patch(isosurface(x,y,z,f_eq,f));
isonormals(x,y,z,f_eq,p)
p.FaceColor = 'red';
p.EdgeColor = 'none';
% Adjust figure properties.
title('Quadric');
xlabel('x-axis');
ylabel('y-axis');
zlabel('z-axis');
axis equal;
grid on;
box on;
axis([-10 10 -10 10 -10 10]);
camlight left;
lighting phong;
Output:
Related
I made two 3D plots on the same axis. now I desire to give them different colors for easy identification. How do I do this coloring? The MATLAB code is shown below.
tic
Nx = 50;
Ny = 50;
x = linspace(0,1,Nx);
y = linspace(0,0.5,Ny);
[X,Y] = meshgrid(x,y);
[M,N] = size(X);
for m=1:M
for n=1:N
%get x,y coordinate
x_mn = X(m,n);
y_mn = Y(m,n);
%%% X=D2 and Y=D1
%Check if x_mn and y_mn satisfy requirement
if(x_mn >= y_mn)
%evaluate function 1
Z(m,n) = (x_mn^2 - 2*x_mn*y_mn + y_mn^2);
Z_1(m,n) = (x_mn^2);
elseif(x_mn < y_mn)
%evaluate function 2
Z(m,n) = 0;
Z_1(m,n) = (x_mn^2);
%% Z(m,n) = 2*(2*x_mn*y_mn + y_mn - y_mn^2 - 2*x_mn);
else
Z(m,n) = 0;
end
end
end
%Plot the surface
figure
surf(X,Y,Z) %first plot
surfc(X,Y,Z)
hold on
surf(X,Y,Z_1) %second plot
xlabel('Dm');
ylabel('D');
zlabel('pR');
grid on
shading interp
toc
disp('DONE!')
How can I create two differently colored surfaces?
figure
surf(X,Y,Z) %first plot
surfc(X,Y,Z)
hold on
surf(X,Y,Z_1)
Your surfc() call actually overwrites your surf() call, is this intended?
As to your colour: the documentation is a marvellous thing:
surfc(X,Y,Z,C) additionally specifies the surface color.
In other words: just specify the colour as you want it. C needs to be a matrix of size(Z) with the desired colours, i.e. set all of them equal to create an monocoloured surface:
x = 1:100;
y = 1:100;
z = rand(100);
figure;
surfc(x,y,z,ones(size(z)))
hold on
surfc(x,y,z+6,ones(size(z))+4)
Results in (MATLAB R2007b, but the syntax is the same nowadays)
I am trying to generate a semi ellipsoidal dome shape by using x, y, z values. In my code below, I define the x,y,z values but I am unable to assign those values to sphere.
How do I resolve this?
clc
x = [65 55.2125 50.8267 46.7398 42.9232 39.3476 35.9815 32.7882 29.7175 26.6833 23.4690 18.7605];
y = x;
z = [0.0,0.9,2.7,5.2,8.2,11.8,15.8,20.3,25.2,30.7,37.1,47.5]; % max height of dome is 47.5
[x,y,z] = sphere(20);
x = x(12:end,:);
y = y(12:end,:);
z = z(12:end,:);
r = 65; % radius of the dome
surf(r.*x,r.*y,r.*z);
axis equal;
It will be simpler or at least more elegant to use the parametric equations of an ellipsoide.
% semi axis parameters
a = 65; % x-axis
b = 65; % y-axis
c = 47.5; % z-axis
%% Parametrisation
%
% To reach each point of the ellipsoide we need two angle:
% phi ∈ [0,2𝜋]
% theta ∈ [0, 𝜋]
%
% But since we only need half of an ellipsoide we can set
% theta ∈ [0,𝜋/2]
[theta,phi] = ndgrid(linspace(0,pi/2,50),linspace(0,2*pi,50));
x = a*sin(theta).*cos(phi);
y = b*sin(theta).*sin(phi);
z = c*cos(theta);
%plot
surf(x,y,z)
axis equal
Result:
You can remove the bottom half of the sphere by assigning NaNs to the approptiate elements of x and y:
[x,y,z] = sphere(20);
I = (z<0);
x(I) = NaN;
y(I) = NaN;
surf(x,y,z)
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 would like to plot a sine curve in Matlab. But I want it blue for the positive values and red for the negative values.
The following code just makes everything red...
x = [];
y = [];
for i = -180 : 180
x = [x i];
y = [y sin(i*pi/180)];
end
p = plot(x, y)
set(p, 'Color', 'red')
Plot 2 lines with different colours, and NaN values at the positive/negative regions
% Let's vectorise your code for efficiency too!
x = -pi:0.01:pi; % Linearly spaced x between -pi and pi
y = sin(x); % Compute sine of x
bneg = y<0; % Logical array of negative y
y_pos = y; y_pos(bneg) = NaN; % Array of only positive y
y_neg = y; y_neg(~bneg)= NaN; % Array of only negative y
figure; hold on; % Hold on for multiple plots
plot(x, y_neg, 'b'); % Blue for negative
plot(x, y_pos, 'r'); % Red for positive
Output:
Note: If you're happy with scatter plots, you don't need the NaN values. They just act to break the line so you don't get join-ups between regions. You could just do
x = -pi:0.01:pi;
y = sin(x);
bneg = y<0;
figure; hold on;
plot(x(bneg), y(bneg), 'b.');
plot(x(~bneg), y(~bneg), 'r.');
Output:
This is so clear because my points are only 0.01 apart. Further spaced points would appear more like a scatter plot.
As we can make contour plot of f=(x.^2) + (y.^2); in 2-D as follows:
[x,y]= meshgrid(-10:10, -10:10);
contour(x,y, (x.^2)+(y.^2));
and we can make contour plot of f=(x.^2) + (y.^2); in 3-D using contour3
Can we make contour plot of f=(x.^2) + (y.^2) + (z.^2); in 3-D
The matlab function isosurface can do what you are asking. However you can also achieve the results you want using other alternatives, like using surf. I will cover both methods.
Method 1: Using isosurface
We need to create the domain for x, y and z and then generate a 3D mesh with those values so that we can evaluate the function f(x,y,z) = x^2 + y^2 + z^2. Then, we shall give a value to the constant k and feed all this information to isosurface, so that we can obtain the family of (x,y,z) values that satisfy the condition: f(x,y,z) = k. Note that this contours are in fact spheres! Finally we can use patch to generate a surface with those values.
It is very interesting to give different values for k iterativelly and see the contours associated with those values.
% Value for x, y and z domain.
a = 10;
% Domain for x ,y and z.
x = linspace(-a,a);
y = linspace(-a,a);
z = linspace(-a,a);
% Generate a 3D mesh with x, y and z.
[x,y,z] = meshgrid(x,y,z);
% Evaluate function (3D volume of data).
f = x.^2 + y.^2 + z.^2;
% Do contours from k = 0 to k = 100 in steps of 1 unit.
for k = 0:100
% Draw the contour that matches k.
p = patch(isosurface(x,y,z,f,k));
isonormals(x,y,z,f,p)
p.FaceColor = 'red';
p.EdgeColor = 'none';
% Adjust figure properties.
title(sprintf('Contours of f(x,y,z) = x^2 + y^2 + z^2\nwith f(x,y,z) = k = %d',k));
xlabel('x-axis');
ylabel('y-axis');
zlabel('z-axis');
axis equal;
grid on;
box on;
axis([-10 10 -10 10 -10 10]);
camlight left;
lighting phong;
% Update figure.
drawnow;
% Clear axes.
cla;
end
This is the output:
Method 2: Using surf
As in the previous method, to contour the function f(x,y,z) = x^2 + y^2 + z^2, we need to match the function to a constant value, this is f(x,y,z) = k, where k is any constant value you choose.
If we isolate z in terms of k, x and y we have: z = ± sqrt(k-x.^2-y.^2), so we have the explicit values for x, y and z. Now, let's give different values for k iterativelly and see the results that we get with the surf function!
% Do contours from k = 0 to k = 100 in steps of 1 unit.
for k = 0:100
% Find the value where: k - x^2 - y^2 = 0
a = sqrt(k);
% Domain for x and y.
x = linspace(-a,a);
y = linspace(-a,a);
[x,y] = meshgrid(x, y);
% Isolate z in terms of k, x and y.
z = sqrt(k-x.^2-y.^2);
% Find complex entries in z.
i = find(real(z)~=z);
% Replace complex entries with NaN.
z(i) = NaN;
% Draw upper hemisphere of surface.
surf(x,y,z,'FaceColor','red','EdgeColor','none');
hold on;
% Draw lower hemisphere of surface.
surf(x,y,-z,'FaceColor','red','EdgeColor','none');
% Adjust figure properties.
title(sprintf('Contours of f(x,y,z) = x^2 + y^2 + z^2\nwith f(x,y,z) = k = %d',k));
xlabel('x-axis');
ylabel('y-axis');
zlabel('z-axis');
axis equal;
grid on;
box on;
axis([-10 10 -10 10 -10 10]);
camlight left;
lighting phong;
% Update figure.
drawnow;
hold off;
end
This is the output:
References
I took some of the ideas from David Arnold's article "Complex Numbers and Plotting in Matlab", which is well worth a read and will help you understand how to plot functions that generate complex numbers.