Simple cubic lattice using three-dimensional array - arrays

I want to draw a simple cubic lattice using MATLAB.
I have read How to plot 3D grid (cube) in Matlab, however, I want to color every small cube.
I have a three-dimensional array in MATLAB, such as,
cube(:,:,1) = [1 0 1
0 1 1
1 1 0]
cube(:,:,2) = [0 0 1
1 1 1
0 1 0]
cube(:,:,3) = [1 1 1
0 1 1
1 0 1]
How can I draw a simple cubic lattice using this array, in which cube(:,:,1) denotes the first floor of the cubic lattice, cube(:,:,2) denotes the second floor, and cube(:,:,3) the third floor.
A 0 denotes a small white cube, whilst a 1 denotes a small black cube.
The desired result is something like this: http://www.instructables.com/id/Puzzle-Cube/

I couldn't find anything simpler, so this is what it is!
C = randi(2,[3 3 3])-1;
colorC = char(repmat('k',[3 3 3]));
colorC(C == 0) = 'y';
figure(1);
for x = 0 : 2
for y = 0 : 2
for z = 0 : 2
vert = [1 1 0;
0 1 0;
0 1 1;
1 1 1;
0 0 1;
1 0 1;
1 0 0;
0 0 0];
vert(:,1) = vert(:,1) + x;
vert(:,2) = vert(:,2) + y;
vert(:,3) = vert(:,3) + z;
fac = [1 2 3 4;
4 3 5 6;
6 7 8 5;
1 2 8 7;
6 7 1 4;
2 3 5 8];
patch('Faces',fac,'Vertices',vert,'FaceColor',colorC(x + 1, y + 1, z + 1));
axis([0, 3, 0, 3, 0, 3]);
alpha('color');
alphamap('rampdown');
axis equal
hold on
end
end
end
Gives you this,
If you delete alpha('color'); and alphamap('rampdown');and use axis off, you get,

Related

Matlab : Sliding window using a matrix

I need some information on how to program the sliding window of matrix.
I have a diagonal matrix B defined below by:
I would like to deduce from the given matrix B and the size of the window W the different matrix for t ranging from 1 to the size L of the matrix.
Note: Each window has the same width and height. And the window moves on the diagonal.
Example: We have a matrix with size 5 by 8 and the size of the window is 3 by 4 and moves on the diagonal. The matrix B of the example is:
My code:
% Sliding window matrix
B = [ 1 1 0 0 0 0 0 0
2 2 1 1 0 0 0 0
0 0 2 2 1 1 0 0
0 0 0 0 2 2 1 1
0 0 0 0 0 0 2 2]; % Matrix B
W = 4; % Size of the window wanted here is 4
n = size(B,2) - W + 1;
X = zeros(size(B,1),W*n);
k = W-1:-1:0;
for i = 1:n
window = B(:,i:i+W-1)';
X(:,i*W - k) = B(:,i:i+W-1);
end
window;
With W = 4 and n of the for loop set to 1 I get:
window = [1 2 0 0 0
1 2 0 0 0
0 1 2 0 0
0 1 2 0 0];
Whereas I should get:
window = [1 1 0 0
2 2 1 1
0 0 2 2];
With my code I don't get exactly the different sub-matrix obtained by sliding window.
I would like my program to be able, depending on the matrix B and the choice of dimensions of my window, to return the diagonal matrix representing the window and shift one step to also recover the next diagonal matrix which is identical to the previous one, and so on until the end.
Any suggestions?
You need to specify window dimensions separately. Try this:
B = [ 1 1 0 0 0 0 0 0
2 2 1 1 0 0 0 0
0 0 2 2 1 1 0 0
0 0 0 0 2 2 1 1
0 0 0 0 0 0 2 2];
[bh, bw] = size(B); % matrix size
wh = 3; % window height
ww = 4; % window width
sx = 2; % sliding step length along 2nd dim
sy = 1; % sliding step length along 1st dim
wx = 1:sx:(bw-ww+1); % window left
wy = 1:sy:(bh-wh+1); % window top
n = min(numel(wx), numel(wy)); % number of windows which fit in matrix
for ii = 1:n
X = B((1:wh)+wy(ii)-1, (1:ww)+wx(ii)-1)
end
Note that the sliding window, as it is described in your question, does not necessarily visit the entire matrix diagonal. Unless you calculate the sx and sy based on the dimensions of the matrix.
B = randi(3, [8 13])
[bh, bw] = size(B); % matrix size
wh = 3; % window height
ww = 4; % window width
sx = 3; % slideing step length along 2nd dim
sy = 1; % slideing step length along 1st dim

How to unfold a Matrix on Matlab?

I have a given matrix H and I would like to unfold (expand) it to find a matrix B by following the method below :
Let H be a matrix of dimension m × n. Let x = gcd (m,n)
The matrix H is cut in two parts.
The cutting pattern being such that :
The "diagonal cut" is made by alternately moving c = n/x units to the right (we move c units to the right several times).
We alternately move c-b = m/x units down (i.e. b = (n-m)/x) (we move b units down several times).
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix B.
Exemple : Let the matrix H of dimension m × n = 5 × 10 defined by :
1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1
Let's calculate x = gcd (m,n) = gcd (5,10) = 5,
Alternatively move to the right : c = n/x = 10/5 = 2,
Alternatively move down : b = (n-m)/x = (10-5)/5 = 1.
Diagonal cutting diagram : The matrix H is cut in two parts.
The cutting pattern is such that :
We move c = 2 units to the right several times c = 2 units to the right,
We repeatedly move c - b = 1 unit downwards.
We get :
After applying this "diagonal cut" of the matrix, we copy and paste the two parts repeatedly to obtain the matrix :
Remark : In the matrices X, X1 and X2 the dashes are zeros.
The resulting matrix B is (L is factor) :
Any suggestions?
This can be done by creating a logical mask with the cutting pattern, and then element-wise multiplying the input by the mask and by its negation. Repeating by L can be done with blkdiag.
H = [1 0 1 1 1 0 1 1 0 0
0 1 1 0 0 1 1 0 1 1
1 1 0 1 1 1 0 1 0 0
0 1 1 0 1 0 1 0 1 1
1 0 0 1 0 1 0 1 1 1];
L = 2;
[m, n] = size(H);
x = gcd(m, n);
c = n / x;
b = (n-m)/x;
mask = repelem(tril(true(m/b)), b, c);
A = [H.*mask; H.*~mask];
A = repmat({A}, L, 1);
B = blkdiag(A{:});

Matlab array that decreases from the center

I've been trying to make a 2-dimensional array that has the largest number in the center, and numbers around it decrement by one like this:
[0 0 0 0 0 0 0;
0 1 1 1 1 1 0;
0 1 2 2 2 1 0;
0 1 2 3 2 1 0;
0 1 2 2 2 1 0;
0 1 1 1 1 1 0;
0 0 0 0 0 0 0]
Any help?
This is easy using implicit expansion:
M = 7; % desired size. Assumed to be odd
t = [0:(M-1)/2 (M-3)/2:-1:0].';
result = min(t, t.');
Alternatively, you can use the gallery function with the 'minij' option to produce one quadrant of the result, and then extend symmetrically:
M = 7; % desired size. Assumed to be odd
result = gallery('minij',(M+1)/2)-1;
result = [result result(:,end-1:-1:1)];
result = [result; result(end-1:-1:1,:)];
Another approach, using padarray from the Image Processing toolbox:
result = 0;
for k = 1:(M-1)/2;
result = padarray(result+1, [1 1]);
end

Matlab: vectorize assignment of values in matrix based on index

Apologies in advance if this question is a duplicate, or if the solution to this question is very straightforward in Matlab. I have a M x N matrix A, a 1 x M vector ind, and another vector val. For example,
A = zeros(6,5);
ind = [3 4 2 4 2 3];
val = [1 2 3];
I would like to vectorize the following code:
for i = 1 : size(A,1)
A(i, ind(i)-1 : ind(i)+1) = val;
end
>> A
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0
That is, for row i of A, I want to insert the vector val in a certain location, as specificied by the i'th entry of ind. What's the best way to do this in Matlab without a for loop?
It can be done using bsxfun's masking capability: build a mask telling where the values will be placed, and then fill those values in. In doing this, it's easier to work with columns instead of rows (because of Matlab's column major order), and transpose at the end.
The code below determines the minimum number of columns in the final A so that all values fit at the specified positions.
Your example applies a displacement of -1 with respect to ind. The code includes a generic displacement, which can be modified.
%// Data
ind = [3 4 2 4 2 3]; %// indices
val = [1 2 3]; %// values
d = -1; %// displacement for indices. -1 in your example
%// Let's go
n = numel(val);
m = numel(ind);
N = max(ind-1) + n + d; %// number of rows in A (rows before transposition)
mask = bsxfun(#ge, (1:N).', ind+d) & bsxfun(#le, (1:N).', ind+n-1+d); %// build mask
A = zeros(size(mask)); %/// define A with zeros
A(mask) = repmat(val(:), m, 1); %// fill in values as indicated by mask
A = A.'; %// transpose
Result in your example:
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0
Result with d = 0 (no displacement):
A =
0 0 1 2 3 0
0 0 0 1 2 3
0 1 2 3 0 0
0 0 0 1 2 3
0 1 2 3 0 0
0 0 1 2 3 0
If you can handle a bit of bsxfun overdose, here's one with bsxfun's adding capability -
N = numel(ind);
A(bsxfun(#plus,N*[-1:1]',(ind-1)*N + [1:N])) = repmat(val(:),1,N)
Sample run -
>> ind
ind =
3 4 2 4 2 3
>> val
val =
1 2 3
>> A = zeros(6,5);
>> N = numel(ind);
>> A(bsxfun(#plus,N*[-1:1]',(ind-1)*N + [1:N])) = repmat(val(:),1,N)
A =
0 1 2 3 0
0 0 1 2 3
1 2 3 0 0
0 0 1 2 3
1 2 3 0 0
0 1 2 3 0

matlab: inserting element after element?

Is there a way to insert an element into an array after verifying a certain element value? For example, take
A = [0 0 1 1 0 1 0]
After each 1 in the array, I want to insert another 1 to get
Anew = [0 0 1 1 1 1 0 1 1 0]
However I want a way to code this for a general case (any length 1 row array and the ones might be in any order).
A = [0 0 1 1 0 1 1];
i = (A == 1); % Test for number you want insert after
t = cumsum(i);
idx = [1 (2:numel(A)) + t(1:end-1)];
newSize = numel(A) + sum(i);
N = ones(newSize,1)*5; % Make this number you want to insert
N(idx) = A
Output:
N =
0 0 1 5 1 5 0 1 5 0
I made the inserted number 5 and split things onto multiple lines so it's easy to see what's going on.
If you wanted to do it in a loop (and this is how I would do it in real life where no-one can see me showing off)
A = [0 0 1 1 0 1 0];
idx = (A == 1); % Test for number you want insert after
N = zeros(1, numel(A) + sum(idx));
j = 1;
for i = 1:numel(A)
N(j) = A(i);
if idx(i)
j = j+1;
N(j) = 5; % Test for number you want to insert after
end
j = j+1;
end
N
Output:
N =
0 0 1 5 1 5 0 1 5 0
This code is not the most elegant, but it'll answer your question...
A=[0 0 1 1 0 1 0];
AA=[];
for ii=1:length(A);
AA=[AA A(ii)];
if A(ii)
AA=[AA 1];
end
end
I'm sure there will be also a vectorized way...
This should do the trick:
>> A = [0 0 1 1 0 1 0]
>>
>> sumA = sum(A);
>> Anew = zeros(1, 2*sumA+sum(~A));
>> I = find(A) + (0:sumA-1);
>> Anew(I) = 1;
>> Anew(I+1) = 8.2;
Anew =
0 0 1 8.2 1 8.2 0 1 8.2 0

Resources