Plotting multiple 3D rectangles using patch in Matlab - matlab

I have x, y, and z coordinates of multiple rectangles' corners. All coordinates are in one matrix; ordered as x, y, z. Every three columns contain one rectangle's four corner coordinates. I want to show all rectangles in one plot. However, it does not show any of rectangles. Here is my code:
%Coordinates(1,3*i-2:3*i) = top left corners' x y z coordinates
%Coordinates(2,3*i-2:3*i) = down left corners' x y z coordinates
%Coordinates(3,3*i-2:3*i) = down right corners' x y z coordinates
%Coordinates(4,3*i-2:3*i) = top right corners' x y z coordinates
This code works fine...
[~,c] = size(coordinates);
for i = 1:3:c
patch(coordinates(:,i),coordinates(:,i+1),coordinates(:,i+2))
hold on
end

If I'm right, you're looking for somthing like the following solution. The idea is taken from Amro's answer here.
Idea
The code first creates vectors with start and stop vertices. It then creates a matrix holding lines with the start vertex, stop vertex and inserts a nan line. Then it uses patch to plot a surface and makes the face invisible. Note, that for reeeaally many vertices, this "wastes" some memory for the nans but the patch command is quite fast, as it creates only one object.
Code
% Sample coordinates
coord = [ 1 -1.3 -1;...
-1 -1.3 -1;...
-1 -1.3 1;...
1 -1.3 1;...
1 1.3 -1;...
-1 1.3 -1;...
-1 1.3 1;...
1 1.3 1;...
-1.3 1 -1;...
-1.3 -1 -1;...
-1.3 -1 1;...
-1.3 1 1;...
1.3 1 -1;...
1.3 -1 -1;...
1.3 -1 1;...
1.3 1 1;...
1 -1 -1.3;...
-1 -1 -1.3;...
-1 1 -1.3;...
1 1 -1.3;...
1 -1 1.3;...
-1 -1 1.3;...
-1 1 1.3;...
1 1 1.3];
nlines = size(coord, 1);
% Vectors for vertices
X = zeros(2, nlines);
Y = zeros(2, nlines);
Z = zeros(2, nlines);
C = zeros(1, nlines);
% One iteration per vertex
for ii = 1:nlines
% Here comes the edge back to the first vertex
if mod(ii,4) == 0
X(1, ii) = coord(ii, 1);
Y(1, ii) = coord(ii, 2);
Z(1, ii) = coord(ii, 3);
X(2, ii) = coord(ii-3, 1);
Y(2, ii) = coord(ii-3, 2);
Z(2, ii) = coord(ii-3, 3);
% Here come all other edges
else
X(1, ii) = coord(ii, 1);
Y(1, ii) = coord(ii, 2);
Z(1, ii) = coord(ii, 3);
X(2, ii) = coord(ii+1, 1);
Y(2, ii) = coord(ii+1, 2);
Z(2, ii) = coord(ii+1, 3);
end
% One color for each rectangle
C(ii) = floor((ii-1)/4);
end
% Insert nans between lines
X(end+1, :) = nan;
Xf = X(:);
Y(end+1, :) = nan;
Yf = Y(:);
Z(end+1, :) = nan;
Zf = Z(:);
% Setup patch matrix
p = [Xf, Yf, Zf];
% Prepare color matrix
r = repmat(C.', 1, 3)';
clr = r(:);
% Make a figure
f = figure;
% Plot patch
surface(p(:,[1 1]), p(:,[2 2]), p(:,[3 3]), [clr clr], ...
'EdgeColor', 'flat', ....
'FaceColor', 'None')
grid on
view([55, 36]);
xlabel('X')
ylabel('Y')
zlabel('Z')
Plot

I am still dot understand fully how your data is saved, but let me try with what I understood:
[~,c] = size(coordinates);
hold on
for ii = 1:1:c/4
patch(coordinates(1+(ii-1)*4:4+(ii-1)*4,1),coordinates(1+(ii-1)*4:4+(ii-1)*4,2),coordinates(1+(ii-1)*4:4+(ii-1)*4,3));
end
If this does not work, please post an example of your data so I can actually try it.
NOTE: do not use i as variable name in Matlab, as it is the imaginary unit.

Related

Order area plots by their visible area, to maximize displayed information

I'm trying to plot a series of area plots in front of each others (not stacked). The problem is they sometimes hide each other. Take a look at this example:
clc; close all; clear variables;
%% generate some data
p = {[0 1 0 1.1];
[0 1 0 1];
[0 1 0 0.2];
[0.1 0.9 0 1.1]};
t = linspace(0, 2*pi);
y = cell2mat(cellfun(#(p) abs(p(1) + p(2)*sin(p(3)+p(4)*t)), p, 'UniformOutput', 0));
%% area plots without any order
n = size(p, 1);
C = lines(n);
h(1) = figure; hold on
for i=1:n
area(t, y(i, :), 'facecolor', C(i, :))
end
I tried to sort surfaces by their area to get a better result:
%% order surfaces by their area
integral = sum(y, 2);
[~, order] = sort(integral, 'descend');
h(2) = figure; hold on
for i=1:n
area(t, y(order(i), :), 'facecolor', C(order(i), :))
end
But the result is not satisfactory yet. I think the objective here is to maximize the area of least visible surface.
%% order surfaces by VISIBLE area
betterOrderIMO = [3 1 4 2 ];
h(3) = figure; hold on
for i=1:n
area(t, y(betterOrderIMO(i), :), 'facecolor', C(betterOrderIMO(i), :))
end
%% test visible area
N = zeros(3, n);
C = floor(C*256);
for i=1:3
f = getframe(h(i));
I = (f.cdata);
for j=1:n
N(i, j) = sum(sum(I(:, :, 1)==C(j, 1)& I(:, :, 2)==C(j, 2)&I(:, :, 3)==C(j, 3)));
end
end
min(N, [], 2)
ans = -> No. of pixels of the least visible surface
2363 -> not ordered
3034 -> ordered by area
4146 -> ordered manually
I can run an optimization (e.g. ga), but that seems overkill.
So are there any other options to get the bast order of a series of area plots, that maximizes the area of least visible plot?
It appears that your problem is to display a lot of signals/functions at the same time, based on your comments. How about you use a 3-dimensional perspective?
%% generate some data
p = {[0 1 0 1.1];
[0 1 0 1];
[0 1 0 0.2];
[0.1 0.9 0 1.1]};
t = linspace(0, 2*pi);
y = cell2mat(cellfun(#(p) abs(p(1) + p(2)*sin(p(3)+p(4)*t)), p, 'UniformOutput', 0));
%% area plots without any order
n = size(p, 1);
C = lines(n);
h(1) = figure; hold on
for i=1:n
patch( i*ones([1 numel(t)+2]), [t(1) t t(end)], [0 y(i,:) 0], C(i,:) );
end
view(3);
grid on;
You may want to replace the tick labels along the x axis with something more meaningful.
Another option would be this:
%% generate some data
p = {[0 1 0 1.1];
[0 1 0 1];
[0 1 0 0.2];
[0.1 0.9 0 1.1]};
t = linspace(0, 2*pi);
y = cell2mat(cellfun(#(p) abs(p(1) + p(2)*sin(p(3)+p(4)*t)), p, 'UniformOutput', 0));
%% area plots without any order
n = size(p, 1);
C = lines(n);
h(1) = figure;
h_patch=waterfall( [t(1) t t(end)], 1:n, [zeros([n 1]) y zeros([n 1])], (1:n).'.*ones([n numel(t)+2]) );
colormap(C);
set(h_patch,'FaceColor','none');
set(h_patch,'LineWidth',2);
view(-15,75);

How do I resolve this issue with 3D image visualization?

I have this 3D image data that I need to visualize. I have been able to visualize it with 2D slices using imshow3D, but I would like to see the image data in 3D space.
The code I used is as follows (courtesy: How do i create a rectangular mask at known angles?), but I can't tell why it isn't displaying:
% create input image
imageSizeX = 120;
imageSizeY = 200;
imageSizeZ = 50
% generate 3D grid
[columnsInImage, rowsInImage, pagesInImage] = meshgrid(1:imageSizeX, 1:imageSizeY, 1:imageSizeZ);
% create the sphere in the image.
centerY = imageSizeY/2;
centerX = imageSizeX/2;
centerZ = imageSizeZ/2;
diameter = 56;
radius = diameter/2;
sphereVoxels = (rowsInImage - centerY).^2 ...
+ (columnsInImage - centerX).^2 + (pagesInImage - centerZ).^2 <= radius.^2;
% change image from logical to numeric labels.
Img = double(sphereVoxels);
for ii = 1:numel(Img)
if Img(ii) == 0
Img(ii) = 2; % intermediate phase voxels
end
end
% specify the desired angle
angle = 60;
% specify desired pixel height and width of solid
width = imageSizeX;
height = imageSizeY;
page = imageSizeZ;
% Find the row point at which theta will be created
y = centerY - ( radius*cos(angle * pi/180) )
% determine top of the solid bar
y0 = max(1, y-height);
% label everything from y0 to y to be = 3 (solid)
Img(y0:y, 1:width, 1:page)=3;
% figure, imshow3D(Img);
% axis on;
% grid on;
% display it using an isosurface
fv = isosurface(Img, 0);
patch(fv,'FaceColor',[0 0 .7],'EdgeColor',[0 0 1]); title('Binary volume of a sphere');
view(45,45);
axis tight;
grid on;
xlabel('x-axis [pixels]'); ylabel('y-axis [pixels]'); zlabel('z-axis [pixels]')
Although, the solid bar is not diagonal as the figure attached below, I would expect the image to be something similar to this:
I do not know exactly what I am doing wrong here.
With regard to the problem in your code, it appears that you set points inside the sphere to 1, then set all the remaining points outside the sphere to 2, then a section through the y plane to 3. There is no value of 0 in the volume in this case, so trying to get an isosurface at the value of 0 isn't going to find anything.
However, if you'd rather create a "voxelated" Minecraft-like surface, like in your sample image showing the facets of your voxels, then I have another option for you...
First, I created a set of volume data as you did in your example, with the exception that I omitted the for loop that sets values to 2, and instead set the values of the solid bar to 2.
Next, I made use of a function build_voxels that I've used in a few 3D projects of mine:
function [X, Y, Z, C] = build_voxels(roiMask)
maskSize = size(roiMask);
% Create the ROI surface patches pointing toward -x:
index = find(diff(padarray(roiMask, [1 0 0], 'pre'), 1, 1) > 0);
[X1, Y1, Z1, C1] = make_patches([-1 -1 -1 -1], [1 1 -1 -1], [-1 1 1 -1]);
% Create the ROI surface patches pointing toward +x:
index = find(diff(padarray(roiMask, [1 0 0], 'post'), 1, 1) < 0);
[X2, Y2, Z2, C2] = make_patches([1 1 1 1], [-1 -1 1 1], [-1 1 1 -1]);
% Create the ROI surface patches pointing toward -y:
index = find(diff(padarray(roiMask, [0 1 0], 'pre'), 1, 2) > 0);
[X3, Y3, Z3, C3] = make_patches([-1 -1 1 1], [-1 -1 -1 -1], [-1 1 1 -1]);
% Create the ROI surface patches pointing toward +y:
index = find(diff(padarray(roiMask, [0 1 0], 'post'), 1, 2) < 0);
[X4, Y4, Z4, C4] = make_patches([1 1 -1 -1], [1 1 1 1], [-1 1 1 -1]);
% Create the ROI surface patches pointing toward -z:
index = find(diff(padarray(roiMask, [0 0 1], 'pre'), 1, 3) > 0);
[X5, Y5, Z5, C5] = make_patches([1 1 -1 -1], [-1 1 1 -1], [-1 -1 -1 -1]);
% Create the ROI surface patches pointing toward +z:
index = find(diff(padarray(roiMask, [0 0 1], 'post'), 1, 3) < 0);
[X6, Y6, Z6, C6] = make_patches([-1 -1 1 1], [-1 1 1 -1], [1 1 1 1]);
% Collect patch data:
X = [X1 X2 X3 X4 X5 X6];
Y = [Y1 Y2 Y3 Y4 Y5 Y6];
Z = [Z1 Z2 Z3 Z4 Z5 Z6];
C = [C1 C2 C3 C4 C5 C6];
function [Xp, Yp, Zp, Cp] = make_patches(Xo, Yo, Zo)
[Xp, Yp, Zp] = ind2sub(maskSize, index);
Xp = bsxfun(#plus, Xp, Xo./2).';
Yp = bsxfun(#plus, Yp, Yo./2).';
Zp = bsxfun(#plus, Zp, Zo./2).';
Cp = index(:).';
end
end
This function accepts a 3D matrix, ideally a logical mask of the volume region(s) to create a surface for, and returns 4 4-by-N matrices: X/Y/Z matrices for the voxel face patches and an index matrix C that can be used to get values from the volume data matrix for use in coloring each surface.
Here's the code to render the surfaces:
[X, Y, Z, C] = build_voxels(Img > 0);
rgbData = reshape([1 0 0; 1 1 0], [2 1 3]);
hSurface = patch(X, Y, Z, rgbData(Img(C), :, :), ...
'AmbientStrength', 0.5, ...
'BackFaceLighting', 'unlit', ...
'EdgeColor', 'none', ...
'FaceLighting', 'flat');
axis equal;
axis tight;
view(45, 45);
grid on;
xlabel('x-axis (voxels)');
ylabel('y-axis (voxels)');
zlabel('z-axis (voxels)');
light('Position', get(gca, 'CameraPosition'), 'Style', 'local');
And here's the plot:
Note that the sphere and bar surfaces are colored differently since they are labeled with values 1 and 2, respectively, in the volume data Img. These values are extracted from Img using C and then used as an index into rgbData, which contains red (first row) and yellow (second row) RGB triplets. This will create an N-by-1-by-3 matrix of polygon face colors.

Filling an area above a curve with many colors (matlab, surf)

I'm trying to create a figure in matlab that looks like this:
desired figure
I am doing so by: (i) assigning value points to each x,y coordinate, (ii) plotting a surf, and (iii) change the view point so the third axis is not seen. Here is the code:
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
z = linspace(0, 1, 10);
z = repmat(z, 10, 1);
z = flipud(triu(z));
z(z==0) = nan;
hold off
surf(x, y, z, 'linestyle', 'none')
colormap([linspace(0.39, 1, 20)',linspace(0.58, 0.25, 20)', linspace(0.93, 0.25, 20)']);
colorbar
xlim([x(1) x(end)])
shading interp
view([90 -90])
hold on
plot(x, 1-y, 'linewidth', 2)
I get the following figure: matlab figure I get
As you can see, there a lot of white spaces above the line which I would like to be in color as well. Unfortunately, I cannot add any more grid points as calculating the actual value of the points takes a lot of time (unlike the example above).
Is there a way to have matlab draw colors in those white spaces as well?
Thanks!
You can try to use patch function to create filled polygon.
See http://www.mathworks.com/help/matlab/ref/patch.html
Try the following code:
vert = [0 1;1 1;1 0]; % x and y vertex coordinates
fac = [1 2 3]; % vertices to connect to make triangle
fvc = [1 0 0; 1 1 1; 0 0 1];
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp');
Result is close:
I was managed to get closer to the desired figure:
close all
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
%colorbar
xlim([x(1) x(end)])
%Fill rectangle.
vert = [0 0; 1 0; 1 1; 0 1]; % x and y vertex coordinates
fac = [1 2 3 4]; % vertices to connect to make squares
%patch('Faces',fac,'Vertices',vert,'FaceColor','red')
fvc = [1 0 0; 0.6 0.7 1; 0.6 0.7 1; 1 0 0]; %Color of vertices (selected to be close to example image).
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp')
hold on
%Fill lower triangle with white color.
vert = [0 0;0 1;1 0]; % x and y vertex coordinates
fac = [1 2 3]; % vertices to connect to make triangle
fvc = [1 1 1; 1, 1, 1; 1, 1, 1]; %White color
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp');
plot(x, 1-y, 'linewidth', 2)
set(gca,'Xtick',[],'Ytick',[]); %Remove tick marks
Result:
Thank you Rotem! I wasn't aware of the patch function and indeed it solved the issue!
The colors on the actual figure I'm trying to achieve are not linear, so I just used patch for all the empty triangles. Here is the adjusted code I use for the simple example (again, this is just a bit more general just to be able to have non linear colors in the area above the curve):
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
z = linspace(0, 1, 10);
z = repmat(z, 10, 1)+0.1;
z = flipud(triu(z));
z(z==0) = nan;
z = z-0.1;
hold off
surf(x, y, z, 'linestyle', 'none')
colormap([linspace(0.39, 1, 20)',linspace(0.58, 0.25, 20)', linspace(0.93, 0.25, 20)']);
colorbar
xlim([x(1) x(end)])
shading interp
view([90 -90])
hold on
patch_cor_y = kron((length(y):-1:1)', ones(3, 1));
patch_cor_x = kron((1:length(x))', ones(3, 1));
patch_cor = [y(patch_cor_y(2:end-2))', x(patch_cor_x(3:end-1))'];
patch_path = reshape(1:length(patch_cor),3, length(patch_cor)/3)';
patch_col = z(sub2ind(size(z), patch_cor_x(3:end-1), patch_cor_y(2:end-2)));
patch('Faces',patch_path,'Vertices',patch_cor,'FaceVertexCData',patch_col,'FaceColor','interp', 'EdgeColor', 'none');
plot(x, 1-y, 'linewidth', 2)
The figure achieved: figure

connect four matlab

Ok, right now i'm trying to create a connect four game through Matlab coding; now the game is still infant but my problem is that I either can't get the figure to plot in each grid square or I can't get the 'circle' figure to plot at all. Please help in any way possible. Also if anyone knows about any connect four matlab tutorials, it would be greatly appreciated.
function [] = Kinect4(nrRows, nrCols)
board = zeros(nrRows, nrCols);
nrMoves = 0;
set(gca, 'xlim', [0 nrCols]);
set(gca, 'ylim', [0 nrRows]);
for r = 1 : 1 : nrRows - 1
line([0, nrCols], [r, r], ...
'LineWidth', 4, 'Color', [0 0 1]);
end
for c = 1 : 1 : nrCols - 1
line([c, c], [0, nrRows], ...
'LineWidth', 4, 'Color', [0 0 1]);
end
DrawBoard(nrRows, nrCols)
hold on;
while nrMoves < nrRows * nrCols %Computes ability to move polygon
[x, y] = ginput(1);
r = ceil(y); % convert to row index
c = ceil(x); % convert to column index
angles = 0 : 1 : 360;
x = cx + r .* cosd(angles);
y = cy + r .* sind(angles);
plot(x, y, 'Color', [1 1 1], 'LineWidth', 3);
axis square;
end
end
Here are some fixes to the code.
removed the line DrawBoard(nrRows, nrCols). Not sure if you put it there as a comment as you have already drawn the board or if DrawBoard is a separate function.
Changed the calculation for r and c to give the center of the cell you wan the put the peg in. This is done by subtracting 0.5 from each.
Changed the line x = cx + r .* cosd(angles); to x = c + 0.5*cosd(angles);. In the previous one, variable cx is undefined and instead of r being the radius of the peg, I used 0.5 you can replace it by appropriate variable. But the idea is to draw a circle of radius 0.5 (so that it fits in a cell) with the center offset by c along x-axis. Similar change for y to offset the peg along y-axis.
Changed the color in plot command to [0 0 0], which is black. [1 1 1] is white and is impossible to see on white background :). I would suggest using 'k' for black, 'b' for blue and so on. See matlab documentation for basic color specifications.
I am guessing you are yet to implement gravity so that the peg moves down. Also you need to check is a cell is already filled. All these and other improvements (like removing unnecessary for-loops, better way to draw pegs, etc.) are left once you get to a working code.
Here's a "working" code:
function [] = Kinect4(nrRows, nrCols)
board = zeros(nrRows, nrCols);
nrMoves = 0;
set(gca, 'xlim', [0 nrCols]);
set(gca, 'ylim', [0 nrRows]);
for r = 1 : 1 : nrRows - 1
line([0, nrCols], [r, r], ...
'LineWidth', 4, 'Color', [0 0 1]);
end
for c = 1 : 1 : nrCols - 1
line([c, c], [0, nrRows], ...
'LineWidth', 4, 'Color', [0 0 1]);
end
axis square;
hold on;
while nrMoves < nrRows * nrCols %Computes ability to move polygon
[x, y] = ginput(1);
r = ceil(y) - 0.5;
c = ceil(x) - 0.5;
angles = 0 : 1 : 360;
x = c + 0.5*cosd(angles);
y = r + 0.5*sind(angles);
plot(x, y, 'Color', [0 0 0], 'LineWidth', 3);
end
end

How to plot 3D grid (cube) in Matlab

Hi I would like to plot transparent cube-shaped grid with lines in it. Something like this:
However, I managed only to draw a 2D grid:
[X,Y] = meshgrid(-8:.5:8);
Z = X+1;
surf(X,Y,Z)
I use Matlab R2009b.
If it is impossible to plot this in matlab could you recommend me a software I could use.
Consider this vectorized solution. It has the advantage that it creates a single graphic object:
%# these don't all have to be the same
x = -8:2:8; y = -8:2:8; z = -8:2:8;
[X1 Y1 Z1] = meshgrid(x([1 end]),y,z);
X1 = permute(X1,[2 1 3]); Y1 = permute(Y1,[2 1 3]); Z1 = permute(Z1,[2 1 3]);
X1(end+1,:,:) = NaN; Y1(end+1,:,:) = NaN; Z1(end+1,:,:) = NaN;
[X2 Y2 Z2] = meshgrid(x,y([1 end]),z);
X2(end+1,:,:) = NaN; Y2(end+1,:,:) = NaN; Z2(end+1,:,:) = NaN;
[X3 Y3 Z3] = meshgrid(x,y,z([1 end]));
X3 = permute(X3,[3 1 2]); Y3 = permute(Y3,[3 1 2]); Z3 = permute(Z3,[3 1 2]);
X3(end+1,:,:) = NaN; Y3(end+1,:,:) = NaN; Z3(end+1,:,:) = NaN;
%#figure('Renderer','opengl')
h = line([X1(:);X2(:);X3(:)], [Y1(:);Y2(:);Y3(:)], [Z1(:);Z2(:);Z3(:)]);
set(h, 'Color',[0.5 0.5 1], 'LineWidth',1, 'LineStyle','-')
%#set(gca, 'Box','on', 'LineWidth',2, 'XTick',x, 'YTick',y, 'ZTick',z, ...
%# 'XLim',[x(1) x(end)], 'YLim',[y(1) y(end)], 'ZLim',[z(1) z(end)])
%#xlabel x, ylabel y, zlabel z
axis off
view(3), axis vis3d
camproj perspective, rotate3d on
If you don't mind a few for loops, something like this will work:
clf
figure(1)
for g = 0:.2:2
for i = 0:.2:2
plot3([g g], [0 2], [i, i])
hold on
end
end
for g = 0:.2:2
for i = 0:.2:2
plot3([0 2], [g g], [i, i])
hold on
end
end
for g = 0:.2:2
for i = 0:.2:2
plot3([i i], [g g], [0 2])
hold on
end
end
You will just need to make the grid transparent by probably changing line properties, I don't think you can change alpha values to accomplish this. Hope that is helpful.
A more vectorized version of Stephen's answer might be the following:
i = 0:0.2:2;
[X Y] = meshgrid(i,i);
x = [X(:) X(:)]';
y = [Y(:) Y(:)]';
z = [repmat(i(1),1,length(x)); repmat(i(end),1,length(x))];
col = 'b';
hold on;
plot3(x,y,z,col);
plot3(y,z,x,col);
plot3(z,x,y,col);
Unfortunately, MATLAB does not currently support transparent lines (to my knowledge). If you really need them to be transparent I'd suggest using 'patch'.
I understand this is a late reply but it is still valid in case anyone else is looking at doing the same thing.
Assuming you are plotting cubes (/their edges), an alternative to the answers already provided is to use the 'plotcube' code from Oliver:
plotcube
The advantage of this solution is that you can:
Change the transparency of the faces (FaceAlpha), and/or,
Change the transparency of the edges (EdgeAlpha), and/or,
Change the colour of the lines (EdgeColor).
All of these can be constants, or variables.
(e.g. fixed edge colour, or a colour that changes with Z-value etc.)
To add in functionality of 2. and 3. (above) change the 'cellfun(#patch...' section in Olivers code, adding in the four extra lines of code as follows: (replace the whole cellfun section with this; including the new 'EdgeAlpha' and 'EdgeColor' lines):
cellfun(#patch,XYZ{1},XYZ{2},XYZ{3},...
repmat({clr},6,1),...
repmat({'FaceAlpha'},6,1),...
repmat({alpha},6,1),...
repmat({'EdgeAlpha'},6,1),...
repmat({0.2},6,1),... % Set this value to whatever you want; even a variable / matrix
repmat({'EdgeColor'},6,1),...
repmat({'black'},6,1)...
);
For more info on 'patch' please see patch documentation.
An important note:
- for large models (many cubes) this is very slow to run.
e.g. running this 'plotcube' function in a 'for' loop in MATLAB over thousands of blocks. I believe this is from calling the 'patch' function multiple times.
A better solution would be to vectorise; to put all your points (vertices/faces/whatever) together in a single matrix first and then call the #patch function only once (no 'for' loop). This would require changing the code somehow to update all the XYZ data.
I hope that helps someone.
Here is the 'plotcube' code in case the link to the original code by Oliver breaks someday:
function plotcube(varargin)
% PLOTCUBE - Display a 3D-cube in the current axes
%
% PLOTCUBE(EDGES,ORIGIN,ALPHA,COLOR) displays a 3D-cube in the current axes
% with the following properties:
% * EDGES : 3-elements vector that defines the length of cube edges
% * ORIGIN: 3-elements vector that defines the start point of the cube
% * ALPHA : scalar that defines the transparency of the cube faces (from 0
% to 1)
% * COLOR : 3-elements vector that defines the faces color of the cube
%
% Example:
% >> plotcube([5 5 5],[ 2 2 2],.8,[1 0 0]);
% >> plotcube([5 5 5],[10 10 10],.8,[0 1 0]);
% >> plotcube([5 5 5],[20 20 20],.8,[0 0 1]);
% Default input arguments
inArgs = { ...
[10 56 100] , ... % Default edge sizes (x,y and z)
[10 10 10] , ... % Default coordinates of the origin point of the cube
.7 , ... % Default alpha value for the cube's faces
[1 0 0] ... % Default Color for the cube
};
% Replace default input arguments by input values
inArgs(1:nargin) = varargin;
% Create all variables
[edges,origin,alpha,clr] = deal(inArgs{:});
XYZ = { ...
[0 0 0 0] [0 0 1 1] [0 1 1 0] ; ...
[1 1 1 1] [0 0 1 1] [0 1 1 0] ; ...
[0 1 1 0] [0 0 0 0] [0 0 1 1] ; ...
[0 1 1 0] [1 1 1 1] [0 0 1 1] ; ...
[0 1 1 0] [0 0 1 1] [0 0 0 0] ; ...
[0 1 1 0] [0 0 1 1] [1 1 1 1] ...
};
XYZ = mat2cell(...
cellfun( #(x,y,z) x*y+z , ...
XYZ , ...
repmat(mat2cell(edges,1,[1 1 1]),6,1) , ...
repmat(mat2cell(origin,1,[1 1 1]),6,1) , ...
'UniformOutput',false), ...
6,[1 1 1]);
cellfun(#patch,XYZ{1},XYZ{2},XYZ{3},...
repmat({clr},6,1),...
repmat({'FaceAlpha'},6,1),...
repmat({alpha},6,1)...
);
view(3);
you can make the inside line kind of transparent by setting color = [0.65, 0.65, 0.65]. And you can use dash line style for interior lines and solid lines for boundary to make it more like a 3-D object.
In my software package, I code a mesh3 function to plot the 3-D tensor product meshes.
clear all
close all
clc
Nx=11;
Ny=11;
Nz=11;
clf
hold on
[i,j]=meshgrid(1:Nx,1:Ny);
k=zeros(Ny,Nx)+Nz;
surf(i,j,k)
[i,k]=meshgrid(1:Nx,1:Nz);
j=zeros(Nz,Nx)+Ny;
surf(i,j,k)
[j,k]=meshgrid(1:Ny,1:Nz);
i=zeros(Nz,Ny)+Nx;
surf(i,j,k)
[i,j]=meshgrid(1:Nx,1:Ny);
k=zeros(Ny,Nx)+1;
surf(i,j,k)
[i,k]=meshgrid(1:Nx,1:Nz);
j=zeros(Nz,Nx)+1;
surf(i,j,k)
[j,k]=meshgrid(1:Ny,1:Nz);
i=zeros(Nz,Ny)+1;
surf(i,j,k)
view(30,30)