├── example.mat
├── make_STL_of_Array_Example.m
├── README.md
├── stlwrite.m
└── make_STL_of_Array.m
/example.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmirHoseinSafari/Make-STL-of-3D-array-Optimal-for-3d-printing-/HEAD/example.mat
--------------------------------------------------------------------------------
/make_STL_of_Array_Example.m:
--------------------------------------------------------------------------------
1 | % LOADING DATA
2 | arr = load('example.mat');
3 | Data = arr.Data;
4 |
5 | scaleX = 0.084;
6 | scaleY = 0.084;
7 | scaleZ = 0.03;
8 |
9 | [Vertices, Triangle, Quads] = make_STL_of_Array('example.stl',Data,scaleX,scaleY,scaleZ);
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TrainingDataFor3D_Printing
2 |
3 | ### make_STL_of_Array Convert a voxelised object contained within a 3D logical array into an STL surface mesh
4 | ==========================================================================
5 |
AUTHOR:
Amir-Hosein Safari
6 | CONTACT:
amirsfr5353@gmail.com
7 | INSTITUTION:
Max-Planck institute for informatic
8 | DATE:
25th Aug 2018
9 |
10 | EXAMPLE:
make_STL_of_Array(FileName,Data,scaleX,scaleY,scaleZ)
11 | ..or..
[Vertices, Triangle, Quads] = make_STL_of_Array(FileName,Data,scaleX,scaleY,scaleZ)
12 |
13 | INPUTS
14 |
15 | FileName - string - Filename of the STL file.
16 |
17 | Data - 3D logical array - Voxelised data
18 | 1 => Inside the object
19 | 0 => Outside the object
20 | (FOR PRINTING WITH TWO MATERIALS YOU SHOULD INVERSE
21 | Data (Data = ~Data) AND RUN CODE AGAIN TO HAVE THE SECOND TYPE)
22 |
23 | scaleX - A number which means the X size of every
24 | voxel in mm
25 | scaleY - A number which means the Y size of every
26 | voxel in mm
27 | scaleZ - A number which means the Z size of every
28 | voxel in mm
29 |
30 |
31 | OUTPUTS
32 |
33 | vertices - Nx3 array - A list of the x,y,z coordinates of
34 | each vertex in the mesh.
35 |
36 | Triangle - Nx3 array - A list of the vertices used in
37 | each Triangle of the mesh, identified using the row
38 | number in the array vertices.
39 |
40 | Quads - Nx4 array - A list of the vertices used in
41 | each Quads of the mesh, identified using the row
42 | number in the array vertices.
43 | ==========================================================================
44 |
45 |
--------------------------------------------------------------------------------
/stlwrite.m:
--------------------------------------------------------------------------------
1 | function stlwrite(filename, varargin)
2 | %STLWRITE Write STL file from patch or surface data.
3 | %
4 | % STLWRITE(FILE, FV) writes a stereolithography (STL) file to FILE for a
5 | % triangulated patch defined by FV (a structure with fields 'vertices'
6 | % and 'faces').
7 | %
8 | % STLWRITE(FILE, FACES, VERTICES) takes faces and vertices separately,
9 | % rather than in an FV struct
10 | %
11 | % STLWRITE(FILE, X, Y, Z) creates an STL file from surface data in X, Y,
12 | % and Z. STLWRITE triangulates this gridded data into a triangulated
13 | % surface using triangulation options specified below. X, Y and Z can be
14 | % two-dimensional arrays with the same size. If X and Y are vectors with
15 | % length equal to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed
16 | % through MESHGRID to create gridded data. If X or Y are scalar values,
17 | % they are used to specify the X and Y spacing between grid points.
18 | %
19 | % STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an
20 | % STL file using the following property values:
21 | %
22 | % MODE - File is written using 'binary' (default) or 'ascii'.
23 | %
24 | % TITLE - Header text (max 80 chars) written to the STL file.
25 | %
26 | % TRIANGULATION - When used with gridded data, TRIANGULATION is either:
27 | % 'delaunay' - (default) Delaunay triangulation of X, Y
28 | % 'f' - Forward slash division of grid quads
29 | % 'b' - Back slash division of quadrilaterals
30 | % 'x' - Cross division of quadrilaterals
31 | % Note that 'f', 'b', or 't' triangulations now use an
32 | % inbuilt version of FEX entry 28327, "mesh2tri".
33 | %
34 | % FACECOLOR - Single colour (1-by-3) or one-colour-per-face (N-by-3)
35 | % vector of RGB colours, for face/vertex input. RGB range
36 | % is 5 bits (0:31), stored in VisCAM/SolidView format
37 | % (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL)
38 | %
39 | % Example 1:
40 | % % Write binary STL from face/vertex data
41 | % tmpvol = false(20,20,20); % Empty voxel volume
42 | % tmpvol(8:12,8:12,5:15) = 1; % Turn some voxels on
43 | % fv = isosurface(~tmpvol, 0.5); % Make patch w. faces "out"
44 | % stlwrite('test.stl',fv) % Save to binary .stl
45 | %
46 | % Example 2:
47 | % % Write ascii STL from gridded data
48 | % [X,Y] = deal(1:40); % Create grid reference
49 | % Z = peaks(40); % Create grid height
50 | % stlwrite('test.stl',X,Y,Z,'mode','ascii')
51 | %
52 | % Example 3:
53 | % % Write binary STL with coloured faces
54 | % cVals = fv.vertices(fv.faces(:,1),3); % Colour by Z height.
55 | % cLims = [min(cVals) max(cVals)]; % Transform height values
56 | % nCols = 255; cMap = jet(nCols); % onto an 8-bit colour map
57 | % fColsDbl = interp1(linspace(cLims(1),cLims(2),nCols),cMap,cVals);
58 | % fCols8bit = fColsDbl*255; % Pass cols in 8bit (0-255) RGB triplets
59 | % stlwrite('testCol.stl',fv,'FaceColor',fCols8bit)
60 |
61 | % Original idea adapted from surf2stl by Bill McDonald. Huge speed
62 | % improvements implemented by Oliver Woodford. Non-Delaunay triangulation
63 | % of quadrilateral surface courtesy of Kevin Moerman. FaceColor
64 | % implementation by Grant Lohsen.
65 | %
66 | % Author: Sven Holcombe, 11-24-11
67 |
68 |
69 | % Check valid filename path
70 | path = fileparts(filename);
71 | if ~isempty(path) && ~exist(path,'dir')
72 | error('Directory "%s" does not exist.',path);
73 | end
74 |
75 | % Get faces, vertices, and user-defined options for writing
76 | [faces, vertices, options] = parseInputs(varargin{:});
77 | asciiMode = strcmp( options.mode ,'ascii');
78 |
79 | % Create the facets
80 | facets = single(vertices');
81 | facets = reshape(facets(:,faces'), 3, 3, []);
82 |
83 | % Compute their normals
84 | V1 = squeeze(facets(:,2,:) - facets(:,1,:));
85 | V2 = squeeze(facets(:,3,:) - facets(:,1,:));
86 | normals = V1([2 3 1],:) .* V2([3 1 2],:) - V2([2 3 1],:) .* V1([3 1 2],:);
87 | clear V1 V2
88 | normals = bsxfun(@times, normals, 1 ./ sqrt(sum(normals .* normals, 1)));
89 | facets = cat(2, reshape(normals, 3, 1, []), facets);
90 | clear normals
91 |
92 | % Open the file for writing
93 | permissions = {'w','wb+'};
94 | fid = fopen(filename, permissions{asciiMode+1});
95 | if (fid == -1)
96 | error('stlwrite:cannotWriteFile', 'Unable to write to %s', filename);
97 | end
98 |
99 | % Write the file contents
100 | if asciiMode
101 | % Write HEADER
102 | fprintf(fid,'solid %s\r\n',options.title);
103 | % Write DATA
104 | fprintf(fid,[...
105 | 'facet normal %.7E %.7E %.7E\r\n' ...
106 | 'outer loop\r\n' ...
107 | 'vertex %.7E %.7E %.7E\r\n' ...
108 | 'vertex %.7E %.7E %.7E\r\n' ...
109 | 'vertex %.7E %.7E %.7E\r\n' ...
110 | 'endloop\r\n' ...
111 | 'endfacet\r\n'], facets);
112 | % Write FOOTER
113 | fprintf(fid,'endsolid %s\r\n',options.title);
114 |
115 | else % BINARY
116 | % Write HEADER
117 | fprintf(fid, '%-80s', options.title); % Title
118 | fwrite(fid, size(facets, 3), 'uint32'); % Number of facets
119 | % Write DATA
120 | % Add one uint16(0) to the end of each facet using a typecasting trick
121 | facets = reshape(typecast(facets(:), 'uint16'), 12*2, []);
122 | % Set the last bit to 0 (default) or supplied RGB
123 | facets(end+1,:) = options.facecolor;
124 | fwrite(fid, facets, 'uint16');
125 | end
126 |
127 | % Close the file
128 | fclose(fid);
129 | fprintf('Wrote %d faces\n',size(faces, 2));
130 |
131 |
132 | %% Input handling subfunctions
133 | function [faces, vertices, options] = parseInputs(varargin)
134 | % Determine input type
135 | if isstruct(varargin{1}) % stlwrite('file', FVstruct, ...)
136 | if ~all(isfield(varargin{1},{'vertices','faces'}))
137 | error( 'Variable p must be a faces/vertices structure' );
138 | end
139 | faces = varargin{1}.faces;
140 | vertices = varargin{1}.vertices;
141 | options = parseOptions(varargin{2:end});
142 |
143 | elseif isnumeric(varargin{1})
144 | firstNumInput = cellfun(@isnumeric,varargin);
145 | firstNumInput(find(~firstNumInput,1):end) = 0; % Only consider numerical input PRIOR to the first non-numeric
146 | numericInputCnt = nnz(firstNumInput);
147 |
148 | options = parseOptions(varargin{numericInputCnt+1:end});
149 | switch numericInputCnt
150 | case 3 % stlwrite('file', X, Y, Z, ...)
151 | % Extract the matrix Z
152 | Z = varargin{3};
153 |
154 | % Convert scalar XY to vectors
155 | ZsizeXY = fliplr(size(Z));
156 | for i = 1:2
157 | if isscalar(varargin{i})
158 | varargin{i} = (0:ZsizeXY(i)-1) * varargin{i};
159 | end
160 | end
161 |
162 | % Extract X and Y
163 | if isequal(size(Z), size(varargin{1}), size(varargin{2}))
164 | % X,Y,Z were all provided as matrices
165 | [X,Y] = varargin{1:2};
166 | elseif numel(varargin{1})==ZsizeXY(1) && numel(varargin{2})==ZsizeXY(2)
167 | % Convert vector XY to meshgrid
168 | [X,Y] = meshgrid(varargin{1}, varargin{2});
169 | else
170 | error('stlwrite:badinput', 'Unable to resolve X and Y variables');
171 | end
172 |
173 | % Convert to faces/vertices
174 | if strcmp(options.triangulation,'delaunay')
175 | faces = delaunay(X,Y);
176 | vertices = [X(:) Y(:) Z(:)];
177 | else
178 | if ~exist('mesh2tri','file')
179 | error('stlwrite:missing', '"mesh2tri" is required to convert X,Y,Z matrices to STL. It can be downloaded from:\n%s\n',...
180 | 'http://www.mathworks.com/matlabcentral/fileexchange/28327')
181 | end
182 | [faces, vertices] = mesh2tri(X, Y, Z, options.triangulation);
183 | end
184 |
185 | case 2 % stlwrite('file', FACES, VERTICES, ...)
186 | faces = varargin{1};
187 | vertices = varargin{2};
188 |
189 | otherwise
190 | error('stlwrite:badinput', 'Unable to resolve input types.');
191 | end
192 | end
193 |
194 | if size(faces,2)~=3
195 | errorMsg = {
196 | sprintf('The FACES input array should hold triangular faces (N x 3), but was detected as N x %d.',size(faces,2))
197 | 'The STL format is for triangulated surfaces (i.e., surfaces made from 3-sided triangles).'
198 | 'The Geom3d package (https://www.mathworks.com/matlabcentral/fileexchange/24484-geom3d) contains'
199 | 'a "triangulateFaces" function which can be used convert your faces into triangles.'
200 | };
201 | error('stlwrite:nonTriangles', '%s\n',errorMsg{:})
202 | end
203 |
204 | if ~isempty(options.facecolor) % Handle colour preparation
205 | facecolor = uint16(options.facecolor);
206 | %Set the Valid Color bit (bit 15)
207 | c0 = bitshift(ones(size(faces,1),1,'uint16'),15);
208 | %Red color (10:15), Blue color (5:9), Green color (0:4)
209 | c0 = bitor(bitshift(bitand(2^6-1, facecolor(:,1)),10),c0);
210 | c0 = bitor(bitshift(bitand(2^11-1, facecolor(:,2)),5),c0);
211 | c0 = bitor(bitand(2^6-1, facecolor(:,3)),c0);
212 | options.facecolor = c0;
213 | else
214 | options.facecolor = 0;
215 | end
216 |
217 | function options = parseOptions(varargin)
218 | IP = inputParser;
219 | IP.addParamValue('mode', 'binary', @ischar)
220 | IP.addParamValue('title', sprintf('Created by stlwrite.m %s',datestr(now)), @ischar);
221 | IP.addParamValue('triangulation', 'delaunay', @ischar);
222 | IP.addParamValue('facecolor',[], @isnumeric)
223 | IP.addParamValue('facecolour',[], @isnumeric)
224 | IP.parse(varargin{:});
225 | options = IP.Results;
226 | if ~isempty(options.facecolour)
227 | options.facecolor = options.facecolour;
228 | end
229 |
230 | function [F,V]=mesh2tri(X,Y,Z,tri_type)
231 | % function [F,V]=mesh2tri(X,Y,Z,tri_type)
232 | %
233 | % Available from http://www.mathworks.com/matlabcentral/fileexchange/28327
234 | % Included here for convenience. Many thanks to Kevin Mattheus Moerman
235 | % kevinmoerman@hotmail.com
236 | % 15/07/2010
237 | %------------------------------------------------------------------------
238 |
239 | [J,I]=meshgrid(1:1:size(X,2)-1,1:1:size(X,1)-1);
240 |
241 | switch tri_type
242 | case 'f'%Forward slash
243 | TRI_I=[I(:),I(:)+1,I(:)+1; I(:),I(:),I(:)+1];
244 | TRI_J=[J(:),J(:)+1,J(:); J(:),J(:)+1,J(:)+1];
245 | F = sub2ind(size(X),TRI_I,TRI_J);
246 | case 'b'%Back slash
247 | TRI_I=[I(:),I(:)+1,I(:); I(:)+1,I(:)+1,I(:)];
248 | TRI_J=[J(:)+1,J(:),J(:); J(:)+1,J(:),J(:)+1];
249 | F = sub2ind(size(X),TRI_I,TRI_J);
250 | case 'x'%Cross
251 | TRI_I=[I(:)+1,I(:); I(:)+1,I(:)+1; I(:),I(:)+1; I(:),I(:)];
252 | TRI_J=[J(:),J(:); J(:)+1,J(:); J(:)+1,J(:)+1; J(:),J(:)+1];
253 | IND=((numel(X)+1):numel(X)+prod(size(X)-1))';
254 | F = sub2ind(size(X),TRI_I,TRI_J);
255 | F(:,3)=repmat(IND,[4,1]);
256 | Fe_I=[I(:),I(:)+1,I(:)+1,I(:)]; Fe_J=[J(:),J(:),J(:)+1,J(:)+1];
257 | Fe = sub2ind(size(X),Fe_I,Fe_J);
258 | Xe=mean(X(Fe),2); Ye=mean(Y(Fe),2); Ze=mean(Z(Fe),2);
259 | X=[X(:);Xe(:)]; Y=[Y(:);Ye(:)]; Z=[Z(:);Ze(:)];
260 | end
261 |
262 | V=[X(:),Y(:),Z(:)];
--------------------------------------------------------------------------------
/make_STL_of_Array.m:
--------------------------------------------------------------------------------
1 | function [Vertices, Triangle, Quads] = make_STL_of_Array(FileName,Data,scaleX,scaleY,scaleZ)
2 | % make_STL_of_Array Convert a voxelised object contained within a 3D logical array into an STL surface mesh
3 | %==========================================================================
4 | % AUTHOR Amir-Hosein Safari
5 | % CONTACT amirsfr5353@gmail.com
6 | % INSTITUTION Max-Planck institute for informatic
7 | % DATE 25th Aug 2018
8 | %
9 | % EXAMPLE make_STL_of_Array(FileName,Data,scaleX,scaleY,scaleZ)
10 | % ..or.. [Vertices, Triangle, Quads] = make_STL_of_Array(FileName,Data,scaleX,scaleY,scaleZ)
11 | %
12 | % INPUTS FileName - string - Filename of the STL file.
13 | %
14 | % Data - 3D logical array - Voxelised data
15 | % 1 => Inside the object
16 | % 0 => Outside the object
17 | % (FOR PRINTING WITH TWO MATERIALS YOU SHOULD INVERSE
18 | % Data (Data = ~Data) AND RUN CODE AGAIN TO HAVE THE SECOND TYPE)
19 | %
20 | % scaleX - A number which means the X size of every
21 | % voxel in mm
22 | % scaleY - A number which means the Y size of every
23 | % voxel in mm
24 | % scaleZ - A number which means the Z size of every
25 | % voxel in mm
26 | %
27 | %
28 | % OUTPUTS vertices - Nx3 array - A list of the x,y,z coordinates of
29 | % each vertex in the mesh.
30 | %
31 | % Triangle - Nx3 array - A list of the vertices used in
32 | % each Triangle of the mesh, identified using the row
33 | % number in the array vertices.
34 | %
35 | % Quads - Nx4 array - A list of the vertices used in
36 | % each Quads of the mesh, identified using the row
37 | % number in the array vertices.
38 | %==========================================================================
39 |
40 | %======================================================
41 | % ALLOCATING THE MEMORY FOR MATRIXES
42 | %======================================================
43 |
44 | Vertices = zeros(8*size(Data,1)* size(Data,2)* size(Data,3), 3);
45 | Quads = zeros(6*size(Data,1)* size(Data,2)* size(Data,3), 4);
46 | Triangle = zeros(12*size(Data,1)* size(Data,2)* size(Data,3), 3);
47 |
48 | Vertices_Pointer = 1;
49 | Quads_Pointer = 1;
50 | Triangle_Pointer = 1;
51 | GoIn3D = 0;
52 | ZlayerVertexNum = 0;
53 | PrevZlayerVertexNum = 0;
54 | PrevVertexPointer = 0;
55 | %======================================================
56 | % LOOPING THROUGH EVERY ELEMENTS OF 3D LOGICAL ARRAY(Data)
57 | %======================================================
58 |
59 | for i3 = 1 : size(Data,3)
60 | ZlayerVertexNum = 0;
61 | for i2 = 1 : size(Data,2)
62 | for i1 = 1 : size(Data,1)
63 | % i1 and i2 will change inside a for loop so we use i11 and
64 | % i22 to save the value before changing and we will use them
65 | i11 = i1;
66 | i22 = i2;
67 |
68 | % check that Data(i1,i2,i3) is not surronded by 1s!
69 | if i1 ~= 1 && i2 ~= 1 && i3 ~= 1 && i1 ~= size(Data,1) && i2 ~= size(Data,2) && i3 ~= size(Data,3) && Data(i1 - 1,i2,i3) == 2 && Data(i1,i2 - 1,i3) == 2 && Data(i1,i2,i3 - 1) == 2 && (Data(i1 + 1,i2,i3) == 1 || Data(i1 + 1,i2,i3) == 2 ) && (Data(i1,i2 + 1,i3) == 1 || Data(i1,i2 + 1,i3) == 2 ) && (Data(i1,i2,i3 + 1) == 1 || Data(i1,i2,i3 + 1) == 2 ) && Data(i1,i2,i3) ~= 0
70 | Data(i1,i2,i3) = 2;
71 | continue;
72 | end
73 |
74 |
75 | if Data(i1,i2,i3) == 1
76 | %======================================================
77 | % LOOKING FOR THE BIGGEST RECTANGLE (BY ITS AREA) FROM THIS PONT
78 | % IN 2D!
79 | % FOR THIS WE LOOPING THROUGH X AND Y TILL FINDING A ZERO IN THAT DIRECTION!
80 | % WE SAVE THE INDEX OF X AND Y OF THE BIGGEST AREA IN
81 | % maxX, maxY
82 | %======================================================
83 |
84 | maxX = 0;
85 | maxY = 0;
86 |
87 | loop2Len = size(Data,2);
88 | for i1 = i1 : size(Data,1)
89 | i2 = i22;
90 | % IF WE REACH A VOXEL FROM OUTSIDE WE BREAK FROM THE
91 | % LOOP
92 | if Data(i1,i2,i3) ~= 1
93 | i1 = i1 - 1;
94 | break;
95 | end
96 | for i2 = i2 : loop2Len
97 | % IF WE REACH A VOXEL FROM OUTSIDE WE BREAK FROM THE
98 | % LOOP
99 | if Data(i1,i2,i3) ~= 1
100 | loop2Len = i2 -1;
101 | i2 = i2 - 1;
102 | break;
103 | else
104 | if maxX*maxY < (i1 - i11 + 1) * (i2 - i22 + 1)
105 | maxX = i1 - i11;
106 | maxY = i2 - i22;
107 | end
108 | end
109 | end
110 | end
111 |
112 | % WE CHANGE THE VALUE OF THE BIGGEST AREA TO 2, IT
113 | % MEANS THAT WE'LL NOT CONSIDER THIS AREA AGAIN
114 | Data(i11:i11 + maxX, i22:i22 + maxY, i3) = 2;
115 |
116 | % CREATE THE VERTICES AND ADD THEM TO Vertices MATRIX
117 | % AND INCREAS THE Vertices_Pointer
118 | V1 = [ (i11 - 1) * scaleX , (i22 - 1) * scaleY, (i3 - 1) * scaleZ];
119 | V2 = [ (i11 + maxX) * scaleX , (i22 - 1) * scaleY, (i3 - 1) * scaleZ];
120 | V3 = [ (i11 - 1) * scaleX , (i22 + maxY) * scaleY, (i3 - 1) * scaleZ];
121 | V4 = [ (i11 + maxX) * scaleX , (i22 + maxY) * scaleY, (i3 - 1) * scaleZ];
122 |
123 | V5 = [ (i11 - 1) * scaleX , (i22 - 1) * scaleY, (i3) * scaleZ];
124 | V6 = [ (i11 + maxX) * scaleX , (i22 - 1) * scaleY, (i3) * scaleZ];
125 | V7 = [ (i11 - 1) * scaleX , (i22 + maxY) * scaleY, (i3) * scaleZ];
126 | V8 = [ (i11 + maxX) * scaleX , (i22 + maxY) * scaleY, (i3) * scaleZ];
127 |
128 | % CHCK IF IT CAN GO IN DEPTH OR NOT
129 | GoIn3D = 0;
130 | if PrevVertexPointer > 0
131 | for i4 = PrevVertexPointer - PrevZlayerVertexNum : 8 : Vertices_Pointer - 8
132 | if size(Vertices) > 0
133 | if Vertices(i4,1) == V1(1) && Vertices(i4,2) == V1(2) && Vertices(i4 + 1,1) == V2(1) && Vertices(i4 + 1,2) == V2(2) && Vertices(i4 + 2,1) == V3(1) && Vertices(i4 + 2,2) == V3(2) && Vertices(i4 + 3,1) == V4(1) && Vertices(i4 + 3,2) == V4(2)
134 | GoIn3D = 1;
135 | Vertices(i4 + 4,3) = Vertices(i4 + 4,3) + scaleZ;
136 | Vertices(i4 + 5,3) = Vertices(i4 + 5,3) + scaleZ;
137 | Vertices(i4 + 6,3) = Vertices(i4 + 6,3) + scaleZ;
138 | Vertices(i4 + 7,3) = Vertices(i4 + 7,3) + scaleZ;
139 | break;
140 | end
141 | end
142 | end
143 | end
144 |
145 | if GoIn3D == 1
146 | continue;
147 | end
148 |
149 | ZlayerVertexNum = ZlayerVertexNum + 8;
150 |
151 | if Vertices_Pointer == 0
152 | Vertices = cat(1,Vertices,V1);
153 | end
154 |
155 | Vertices(Vertices_Pointer,:) = V1;
156 | V_pointer1 = Vertices_Pointer;
157 | Vertices_Pointer = Vertices_Pointer + 1;
158 |
159 | Vertices(Vertices_Pointer,:) = V2;
160 | V_pointer2 = Vertices_Pointer;
161 | Vertices_Pointer = Vertices_Pointer + 1;
162 |
163 | Vertices(Vertices_Pointer,:) = V3;
164 | V_pointer3 = Vertices_Pointer;
165 | Vertices_Pointer = Vertices_Pointer + 1;
166 |
167 | Vertices(Vertices_Pointer,:) = V4;
168 | V_pointer4 = Vertices_Pointer;
169 | Vertices_Pointer = Vertices_Pointer + 1;
170 |
171 | Vertices(Vertices_Pointer,:) = V5;
172 | V_pointer5 = Vertices_Pointer;
173 | Vertices_Pointer = Vertices_Pointer + 1;
174 |
175 | Vertices(Vertices_Pointer,:) = V6;
176 | V_pointer6 = Vertices_Pointer;
177 | Vertices_Pointer = Vertices_Pointer + 1;
178 |
179 | Vertices(Vertices_Pointer,:) = V7;
180 | V_pointer7 = Vertices_Pointer;
181 | Vertices_Pointer = Vertices_Pointer + 1;
182 |
183 | Vertices(Vertices_Pointer,:) = V8;
184 | V_pointer8 = Vertices_Pointer;
185 | Vertices_Pointer = Vertices_Pointer + 1;
186 | end
187 | end
188 | end
189 | PrevZlayerVertexNum = ZlayerVertexNum;
190 | PrevVertexPointer = Vertices_Pointer;
191 | end
192 |
193 | % CUT THE UNUSED ELEMENTS OF Vertices
194 | Vertices = Vertices(1:Vertices_Pointer - 1,:);
195 |
196 | % CREATE THE QUADS AND ADD THEM TO Quads MATRIX
197 | % AND INCREAS THE Quads_Pointer
198 | Quads_Pointer = 1;
199 | for iInVertices = 1 : 8: size(Vertices)
200 | Quads(Quads_Pointer,:) = [iInVertices, iInVertices + 1, iInVertices + 2, iInVertices + 3];
201 | Quads_Pointer = Quads_Pointer + 1;
202 | Quads(Quads_Pointer,:) = [iInVertices + 4, iInVertices + 5, iInVertices + 6, iInVertices + 7];
203 | Quads_Pointer = Quads_Pointer + 1;
204 | Quads(Quads_Pointer,:) = [iInVertices + 4, iInVertices + 5, iInVertices, iInVertices + 1];
205 | Quads_Pointer = Quads_Pointer + 1;
206 | Quads(Quads_Pointer,:) = [iInVertices + 2, iInVertices + 3, iInVertices + 6, iInVertices + 7];
207 | Quads_Pointer = Quads_Pointer + 1;
208 | Quads(Quads_Pointer,:) = [iInVertices + 4, iInVertices, iInVertices + 6, iInVertices + 2];
209 | Quads_Pointer = Quads_Pointer + 1;
210 | Quads(Quads_Pointer,:) = [iInVertices + 1, iInVertices + 5, iInVertices + 3, iInVertices + 7];
211 | Quads_Pointer = Quads_Pointer + 1;
212 | end
213 |
214 | % CUT THE UNUSED ELEMENTS OF Quads
215 | Quads = Quads(1:Quads_Pointer - 1,:);
216 |
217 | % REMOVE REPETITIOUS QUADS
218 | Quads = unique(Quads,'rows','stable');
219 |
220 | % CREATE THE TRIAGNLES FROM QUADS AND ADD THEM TO Triangle MATRIX
221 | % AND INCREAS THE Triangle_Pointer
222 | for i = 1 : size(Quads,1)
223 | Triangle(Triangle_Pointer,:) = [Quads(i,1) Quads(i,2) Quads(i,3)];
224 | Triangle_Pointer = Triangle_Pointer + 1;
225 | Triangle(Triangle_Pointer,:) = [Quads(i,4) Quads(i,2) Quads(i,3)];
226 | Triangle_Pointer = Triangle_Pointer + 1;
227 | end
228 |
229 | % CUT THE UNUSED ELEMENTS OF MATRIXES
230 | Triangle = Triangle(1:Triangle_Pointer - 1,:);
231 |
232 | % WRITE THE STL FILE
233 | stlwrite(FileName, Triangle, Vertices);
234 |
--------------------------------------------------------------------------------