Generate mesh and refine mesh of triangles - matlab

I need to find a way to mesh triangles then to refine using refine.
My vertices of my original triangles are stored inside a matrix of size nb_points * 2.
My faces are stored in a nb_faces * 3 matrix.
The data for each face is stored in a nb_face * 1 matrix.
The meshing is done by diving the area using the middles of the segments of the triangles.
Example :
Origin :
vertices = [0 1 ;
2 3 ;
4 1 ;
4 5];
faces = [1 2 3;
2 3 4];
data = [1 2];
Result expected after meshing :
vertices = [0 1;
2 3;
4 1;
4 5;
1 2;
3 2;
2 1;
3 4;
4 3];
faces = [1 5 7;
2 5 6;
5 6 7;
7 6 3;
2 6 8;
6 8 9;
6 9 3;
8 4 9];
data = [1 1 1 1 2 2 2 2];
I am displaying using :
FV.Vertices = vertices;
FV.Faces = faces;
FV.FaceVertexCData = data;
figure; hold on; axis equal; grid on;
patch(FV,'FaceColor','flat');
Precision :
I do not want to use the following functions which gives way too many vertices and faces :
generateMesh()
refinemesh()
The data are temperatures since this is a simulation of heat transfer.

With a for loop it can be done quite easily, here is one solution:
% Dummy data
vertices = [0 1 ;
2 3 ;
4 1 ;
4 5];
faces = [1 2 3;
2 3 4];
data = [1 2];
% Number of vertices
vnum = size(vertices,1);
% new faces empty vector
nfaces = [];
% triangular shift
tshift = [2,-1,-1].';
% Run the algorithm
for ii = 1:size(faces,1)
% For each triangle get the 3 pairs of vertices
nsk = [faces(ii,1), faces(ii,2);faces(ii,2), faces(ii,3);faces(ii,3), faces(ii,1)];
% Compute the center of each pair of vertices
cmiddle = (vertices(nsk(:,1),:)+vertices(nsk(:,2),:))/2
% Compute the new faces
nfaces = [nfaces;[nsk(:,1),vnum+(ii*3-3+[1:3].'),vnum+(ii*3-3+[1:3].')+tshift];[(vnum+(ii*3-2)):(vnum+(ii*3))]]
% Add the new vertices
vertices = [vertices;cmiddle];
end
% Delete the duplicate vertices
[vertices,~,ind] = unique(vertices,'rows');
faces = ind(nfaces);
% Plot
figure; hold on; axis equal; grid on;
patch('Faces',faces,'Vertices',vertices,'FaceVertexCData',kron(data,ones(1,4)).','FaceColor','flat')
colorbar
If you find a way to generate the nsk vector without for loop you could even get rid of the loop. This code will only work on triangle, but it can be adapted if needed.
Result:
You can repeat the operation:

Related

Generation of cubic grid

I am trying to generate a cubic grid in Matlab so that I can produce a grid of M x N x Q cubes with M, N and Q being integer numbers. I don't need to plot it but rather to produce a B-Rep of the grid (vertex matrix and faces matrix - with no duplicate internal faces). I have tried two approaches:
Copy and translate points in the X, Y, Z direction, eliminate duplicate points and try to generate the new topology (I have no idea how).
Use the Matlab Neuronal Neural Network toolbox, specifically the gridplot function that produces a 3D grid of points but the faces matrix cannot be generated from this function.
Any suggestions?
Thank you.
Update
The vertex matrix contains all 8 points of each cube and the faces matrix all 6 faces of each cube. I can generate that with the following code:
clc
clear
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];
vert_total = [];
face_total = fac;
for x = 0 : 1
for y = 0 : 1
for z = 0 : 1
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;
vert_total = [vert_total; vert];
face = face_total(end-5:end,:);
face_total = [face_total; face+8];
end
end
end
The problem with this code is that it contains duplicate vertex and duplicate faces. Eliminating the repeated vertex is pretty straightforward using the unique function, but I don't know how to handle the topology (faces matrix) when I eliminate the repeated points (obviously, some of the faces should be eliminated as well).
Any sugestions with that?
You can create the 3D grid, and then keep only those at 6 faces. Someone else may point a better way than this.
M = 5; N = 6; Q = 7;
[X, Y, Z] = ndgrid(1:M, 1:N, 1:Q); % 3D
faces = X==1 | X==M | Y==1 | Y==N | Z==1 | Z==Q;
X = X(faces);
Y = Y(faces);
Z = Z(faces);
Now [X Y Z] are coordinates for faces.

How to save indices and values from Matrix in Matlab?

I have a 3x3 Matrix and want to save the indices and values into a new 9x3 matrix. For example A = [1 2 3 ; 4 5 6 ; 7 8 9] so that I will get a matrix x = [1 1 1; 1 2 2; 1 3 3; 2 1 4; 2 2 5; ...] With my code I only be able to store the last values x = [3 3 9].
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x=[];
for i = 1:size(A)
for j = 1:size(A)
x =[i j A(i,j)]
end
end
Thanks for your help
Vectorized approach
Here's one way to do it that avoids loops:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
[ii, jj] = ndgrid(1:size(A,1), 1:size(A,2)); % row and column indices
vv = A.'; % values. Transpose because column changes first in the result, then row
x = [jj(:) ii(:) vv(:)]; % result
Using your code
You're only missing concatenation with previous x:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = [];
for i = 1:size(A)
for j = 1:size(A)
x = [x; i j A(i,j)]; % concatenate new row to previous x
end
end
Two additional suggestions:
Don't use i and j as variable names, because that shadows the imaginary unit.
Preallocate x instead of having it grow in each iteration, to increase speed.
The modified code is:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = NaN(numel(A),3); % preallocate
n = 0;
for ii = 1:size(A)
for jj = 1:size(A)
n = n + 1; % update row counter
x(n,:) = [ii jj A(ii,jj)]; % fill row n
end
end
I developed a solution that works much faster. Here is the code:
% Generate subscripts from linear index
[i, j] = ind2sub(size(A),1:numel(A));
% Just concatenate subscripts and values
x = [i' j' A(:)];
Try it out and let me know ;)

Merging 4 separate subplots in 1 figure having 4 subplots

I have 4 different figures. Each figure contains 2 subplots (2 rows and 1 column)
The figures can be generated using the following code.
y = [2 2 3; 2 5 6; 2 8 9; 2 11 12];
for i = 1 : 4
figure(i)
subplot(2,1,1)
bar(y)
subplot(2,1,2)
bar(y)
end
Having these 4 figures, is it possible to combine them in 1 figure?
the solution provided does not work with this other example where I create the figure using barwitherr..why?
for i = 1 : 4
figure(i)
subplot(2,1,1)
barwitherr([1 2 3 4;1 2 1 2], [5 6 7 8;1 2 3 4])
subplot(2,1,2)
barwitherr([1 2 3 4;1 2 1 2], [5 6 7 8;1 2 3 4])
end
for i = 1:4
figure(i);
ax = gca;
f = get(ax, 'children');
figure(5);
s = subplot(2, 2, i);
copyobj(f, s);
end
This may not be exactly what you want but is very extensible. You can loop through each of the original 4 figures and get handles for each of the subplots within it. Once the figure we are interested in using figure(i) is the current gcf object we can get a handle to each of the subplot elements with s = subplot(2, 1, i) providing we know the structure of the subplots and i is the subplot we are interested in.
We can then we use copyobj() and allchild() to copy over each of the subplots to a new subplot in the new figure
copyobj(allchild(h), s)
allchild() copies over all of the information in barwitherr() that is left out from the code you've copied from a previous edit of my answer to your question.
If we put all this together we can produce the full code as
for i = 1:4
figure(5);
n = i + (i - 1);
s1 = subplot(4, 2, n);
s2 = subplot(4, 2, n+1);
h = figure(i);
hs1 = subplot(2, 1, 1);
hs2 = subplot(2, 1, 2);
copyobj(allchild(hs1), s1)
copyobj(allchild(hs2), s2)
end
n = i + (i - 1); is used to replicate the original ordering. The output produced by this is

shifting versions of a matrix

I have a m-by-n matrix and I want to shift each row elements k no. of times (" one resultant matrix for each one shift so a total of k matrices corresponding to each row shifts ")(k can be different for different rows and 0<=k<=n) and want to index all the resultant matrices corresponding to each individual shift.
Eg: I have the matrix: [1 2 3 4; 5 6 7 8; 2 3 4 5]. Now, say, I want to shift row1 by 2 times (i.e. k=2 for row1) and row2 by 3times (i.e. k=3 for row2) and want to index all the shifted versions of matrices (It is similar to combinatorics of rows but with limited and diffeent no. of shifts to each row).
Can someone help to write up the code? (please help to write the general code but not for the example I mentioned here)
I found the following question useful to some extent, but it won't solve my problem as my problem looks like a special case of this problem:
Matlab: How to get all the possible different matrices by shifting it's rows (Update: each row has a different step)
See if this works for you -
%// Input m-by-n matrix
A = rand(2,5) %// Edit this to your data
%// Initialize shifts, k for each row. The number of elements would be m.
sr = [2 3]; %// Edit this to your data
[m,n] = size(A); %// Get size
%// Get all the shits in one go
sr_ind = arrayfun(#(x) 0:x,sr,'un',0); %//'
shifts = allcomb(sr_ind{:},'matlab')'; %//'
for k1 = 1:size(shifts,2)
%// Get shift to be used for each row for each iteration
shift1 = shifts(:,k1);
%// Get circularly shifted column indices
t2 = mod(bsxfun(#minus,1:n,shift1),n);
t2(t2==0) = n;
%// Get the linear indices and use them to index into input to get the output
ind = bsxfun(#plus,[1:m]',(t2-1)*m); %//'
all_matrices = A(ind) %// outputs
end
Please note that this code uses MATLAB file-exchange code allcomb.
If your problem in reality is not more complex than what you showed us, it can be done by a double loop. However, i don't like my solution, because you would need another nested loop for each row you want to shift. Also it generates all shift-combinations from your given k-numbers, so it has alot of overhead. But this can be a start:
% input
m = [1 2 3 4; 5 6 7 8; 2 3 4 5];
shift_times = {0:2, 0:3}; % 2 times for row 1, 3 times for row 2
% desird results
desired_matrices{1} = [4 1 2 3; 5 6 7 8; 2 3 4 5];
desired_matrices{2} = [3 4 1 2; 5 6 7 8; 2 3 4 5];
desired_matrices{3} = [1 2 3 4; 8 5 6 7; 2 3 4 5];
desired_matrices{4} = [4 1 2 3; 8 5 6 7; 2 3 4 5];
desired_matrices{5} = [3 4 1 2; 8 5 6 7; 2 3 4 5];
% info needed:
[rows, cols] = size(m);
count = 0;
% make all shift combinations
for shift1 = shift_times{1}
% shift row 1
m_shifted = m;
idx_shifted = [circshift([1:cols]',shift1)]';
m_shifted(1, :) = m_shifted(1, idx_shifted);
for shift2 = shift_times{2}
% shift row 2
idx_shifted = [circshift([1:cols]',shift2)]';
m_shifted(2, :) = m_shifted(r_s, idx_shifted);
% store them
store{shift1+1, shift2+1} = m_shifted;
end
end
% store{i+1, j+1} stores row 1 shifted by i and row 2 shifted by j
% example
all(all(store{2,1} == desired_matrices{1})) % row1: 1, row2: 0
all(all(store{2,2} == desired_matrices{4})) % row1: 1, row2: 1
all(all(store{3,2} == desired_matrices{5})) % row1: 2, row2: 1

Remove internal edges in 3D MATLAB plot using patch function

I am plotting a 3D object, say a cube, in MATLAB.
Node = [0 0 0; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 1 0 1; 1 1 1; 0 1 1];
Elem = cell(1); Elem{1} = 1:8;
figure
for elm = 1:size(Elem,1)
X = Node(Elem{elm},:); K = convhulln(X); hold on;
patch('Faces',K,'Vertices',X,'FaceColor',rand(1,3),'FaceAlpha',1.0);
end
view(3); grid off; axis equal; cameramenu; axis off;
In the plot, how do I remove the internal diagonal lines? The plot should just show edges of cube. I am looking for a general solution which is applicable to any polyhedron.
the output of K=convhulln(X); is causing this, because convex hull will have triangular facets... (that's the default).
if instead you'd define K to be:
K= [1 2 3 4; ...
2 6 7 3; ...
4 3 7 8; ...
1 5 8 4; ...
1 2 6 5; ...
5 6 7 8];
You'll get it right.
Another option is to use geom3D from the FEX.