READ_stlascii Read mesh data in the form of an <*.stl> file ========================================================================== FILENAME: READ_stl.m AUTHOR: Adam H. Aitkenhead INSTITUTION: The Christie NHS Foundation Trust CONTACT: adam.aitkenhead@physics.cr.man.ac.uk DATE: 29th March 2010 PURPOSE: Read mesh data in the form of an <*.stl> file. USAGE: [coordVERTICES,coordNORMALS,stlNAME] = READ_stl(stlFILENAME,stlFORMAT) INPUT PARAMETERS: stlFILENAME - String - Mandatory - The filename of the STL file. stlFORMAT - String - Optional - The format of the STL file: 'ascii' or 'binary' OUTPUT PARAMETERS: coordVERTICES - Nx3x3 array - Mandatory - An array defining the vertex positions for each of the N facets, with: 1 row for each facet 3 cols for the x,y,z coordinates 3 pages for the three vertices coordNORMALS - Nx3 array - Optional - An array defining the normal vector for each of the N facets, with: 1 row for each facet 3 cols for the x,y,z components of the vector stlNAME - String - Optional - The name of the STL object. ==========================================================================
0001 function [coordVERTICES,varargout] = READ_stl(stlFILENAME,varargin) 0002 % READ_stlascii Read mesh data in the form of an <*.stl> file 0003 %========================================================================== 0004 % FILENAME: READ_stl.m 0005 % AUTHOR: Adam H. Aitkenhead 0006 % INSTITUTION: The Christie NHS Foundation Trust 0007 % CONTACT: adam.aitkenhead@physics.cr.man.ac.uk 0008 % DATE: 29th March 2010 0009 % PURPOSE: Read mesh data in the form of an <*.stl> file. 0010 % 0011 % USAGE: 0012 % 0013 % [coordVERTICES,coordNORMALS,stlNAME] = READ_stl(stlFILENAME,stlFORMAT) 0014 % 0015 % INPUT PARAMETERS: 0016 % 0017 % stlFILENAME - String - Mandatory - The filename of the STL file. 0018 % 0019 % stlFORMAT - String - Optional - The format of the STL file: 0020 % 'ascii' or 'binary' 0021 % 0022 % OUTPUT PARAMETERS: 0023 % 0024 % coordVERTICES - Nx3x3 array - Mandatory 0025 % - An array defining the vertex positions 0026 % for each of the N facets, with: 0027 % 1 row for each facet 0028 % 3 cols for the x,y,z coordinates 0029 % 3 pages for the three vertices 0030 % 0031 % coordNORMALS - Nx3 array - Optional 0032 % - An array defining the normal vector for 0033 % each of the N facets, with: 0034 % 1 row for each facet 0035 % 3 cols for the x,y,z components of the vector 0036 % 0037 % stlNAME - String - Optional - The name of the STL object. 0038 % 0039 %========================================================================== 0040 0041 %========================================================================== 0042 % VERSION USER CHANGES 0043 % ------- ---- ------- 0044 % 100329 AHA Original version 0045 % 100513 AHA Totally reworked the code. Now use textscan to read the 0046 % file all at once, rather than one line at a time with 0047 % fgetl. Major speed improvment. 0048 % 100623 AHA Combined code which reads ascii STLS and code which reads 0049 % binary STLs into a single function. 0050 % 101126 AHA Small change to binary read code: Now use fread instead 0051 % of fseek. Gives large speed increase. 0052 %========================================================================== 0053 0054 %========================================================================== 0055 % STL ascii file format 0056 %====================== 0057 % ASCII STL files have the following structure. Technically each facet 0058 % could be any 2D shape, but in practice only triangular facets tend to be 0059 % used. The present code ONLY works for meshes composed of triangular 0060 % facets. 0061 % 0062 % solid object_name 0063 % facet normal x y z 0064 % outer loop 0065 % vertex x y z 0066 % vertex x y z 0067 % vertex x y z 0068 % endloop 0069 % endfacet 0070 % 0071 % <Repeat for all facets...> 0072 % 0073 % endsolid object_name 0074 %========================================================================== 0075 0076 %========================================================================== 0077 % STL binary file format 0078 %======================= 0079 % Binary STL files have an 84 byte header followed by 50-byte records, each 0080 % describing a single facet of the mesh. Technically each facet could be 0081 % any 2D shape, but that would screw up the 50-byte-per-facet structure, so 0082 % in practice only triangular facets are used. The present code ONLY works 0083 % for meshes composed of triangular facets. 0084 % 0085 % HEADER: 0086 % 80 bytes: Header text 0087 % 4 bytes: (int) The number of facets in the STL mesh 0088 % 0089 % DATA: 0090 % 4 bytes: (float) normal x 0091 % 4 bytes: (float) normal y 0092 % 4 bytes: (float) normal z 0093 % 4 bytes: (float) vertex1 x 0094 % 4 bytes: (float) vertex1 y 0095 % 4 bytes: (float) vertex1 z 0096 % 4 bytes: (float) vertex2 x 0097 % 4 bytes: (float) vertex2 y 0098 % 4 bytes: (float) vertex2 z 0099 % 4 bytes: (float) vertex3 x 0100 % 4 bytes: (float) vertex3 y 0101 % 4 bytes: (float) vertex3 z 0102 % 2 bytes: Padding to make the data for each facet 50-bytes in length 0103 % ...and repeat for next facet... 0104 %========================================================================== 0105 0106 if nargin==2 0107 stlFORMAT = lower(varargin{1}); 0108 else 0109 stlFORMAT = 'auto'; 0110 end 0111 0112 %If necessary, identify whether the STL is ascii or binary: 0113 if strcmp(stlFORMAT,'ascii')==0 && strcmp(stlFORMAT,'binary')==0 0114 stlFORMAT = IDENTIFY_stl_format(stlFILENAME); 0115 end 0116 0117 %Load the STL file: 0118 if strcmp(stlFORMAT,'ascii') 0119 [coordVERTICES,coordNORMALS,stlNAME] = READ_stlascii(stlFILENAME); 0120 elseif strcmp(stlFORMAT,'binary') 0121 [coordVERTICES,coordNORMALS] = READ_stlbinary(stlFILENAME); 0122 stlNAME = 'unnamed_object'; 0123 end %if 0124 0125 %Prepare the output arguments 0126 if nargout == 2 0127 varargout(1) = {coordNORMALS}; 0128 elseif nargout == 3 0129 varargout(1) = {coordNORMALS}; 0130 varargout(2) = {stlNAME}; 0131 end 0132 0133 end %function 0134 0135 0136 0137 %========================================================================== 0138 function [stlFORMAT] = IDENTIFY_stl_format(stlFILENAME) 0139 % IDENTIFY_stl_format Test whether an stl file is ascii or binary 0140 0141 % Open the file: 0142 fidIN = fopen(stlFILENAME); 0143 0144 % Check the file size first, since binary files MUST have a size of 84+(50*n) 0145 fseek(fidIN,0,1); % Go to the end of the file 0146 fidSIZE = ftell(fidIN); % Check the size of the file 0147 0148 if rem(fidSIZE-84,50) > 0 0149 0150 stlFORMAT = 'ascii'; 0151 0152 else 0153 0154 % Files with a size of 84+(50*n), might be either ascii or binary... 0155 0156 % Read first 80 characters of the file. 0157 % For an ASCII file, the data should begin immediately (give or take a few 0158 % blank lines or spaces) and the first word must be 'solid'. 0159 % For a binary file, the first 80 characters contains the header. 0160 % It is bad practice to begin the header of a binary file with the word 0161 % 'solid', so it can be used to identify whether the file is ASCII or 0162 % binary. 0163 fseek(fidIN,0,-1); % Go to the start of the file 0164 firsteighty = char(fread(fidIN,80,'uchar')'); 0165 0166 % Trim leading and trailing spaces: 0167 firsteighty = strtrim(firsteighty); 0168 0169 % Take the first five remaining characters, and check if these are 'solid': 0170 firstfive = firsteighty(1:min(5,length(firsteighty))); 0171 0172 % Double check by reading the last 80 characters of the file. 0173 % For an ASCII file, the data should end (give or take a few 0174 % blank lines or spaces) with 'endsolid <object_name>'. 0175 % If the last 80 characters contains the word 'endsolid' then this 0176 % confirms that the file is indeed ASCII. 0177 if strcmp(firstfive,'solid') 0178 0179 fseek(fidIN,-80,1); % Go to the end of the file minus 80 characters 0180 lasteighty = char(fread(fidIN,80,'uchar')'); 0181 0182 if findstr(lasteighty,'endsolid') 0183 stlFORMAT = 'ascii'; 0184 else 0185 stlFORMAT = 'binary'; 0186 end 0187 0188 else 0189 stlFORMAT = 'binary'; 0190 end 0191 0192 end 0193 0194 % Close the file 0195 fclose(fidIN); 0196 0197 end %function 0198 %========================================================================== 0199 0200 0201 0202 %========================================================================== 0203 function [coordVERTICES,coordNORMALS,stlNAME] = READ_stlascii(stlFILENAME) 0204 % READ_stlascii Read mesh data in the form of an ascii <*.stl> file 0205 0206 % Read the ascii STL file 0207 fidIN = fopen(stlFILENAME); 0208 fidCONTENTcell = textscan(fidIN,'%s','delimiter','\n'); %Read all the file 0209 fidCONTENT = fidCONTENTcell{:}(logical(~strcmp(fidCONTENTcell{:},''))); %Remove all blank lines 0210 fclose(fidIN); 0211 0212 % Read the STL name 0213 if nargout == 3 0214 line1 = char(fidCONTENT(1)); 0215 if (size(line1,2) >= 7) 0216 stlNAME = line1(7:end); 0217 else 0218 stlNAME = 'unnamed_object'; 0219 end 0220 end 0221 0222 % Read the vector normals 0223 if nargout >= 2 0224 stringNORMALS = char(fidCONTENT(logical(strncmp(fidCONTENT,'facet normal',12)))); 0225 coordNORMALS = str2num(stringNORMALS(:,13:end)); 0226 end 0227 0228 % Read the vertex coordinates 0229 facetTOTAL = sum(strcmp(fidCONTENT,'endfacet')); 0230 stringVERTICES = char(fidCONTENT(logical(strncmp(fidCONTENT,'vertex',6)))); 0231 coordVERTICESall = str2num(stringVERTICES(:,7:end)); 0232 cotemp = zeros(3,facetTOTAL,3); 0233 cotemp(:) = coordVERTICESall; 0234 coordVERTICES = shiftdim(cotemp,1); 0235 0236 end %function 0237 %========================================================================== 0238 0239 0240 0241 %========================================================================== 0242 function [coordVERTICES,coordNORMALS] = READ_stlbinary(stlFILENAME) 0243 % READ_stlbinary Read mesh data in the form of an binary <*.stl> file 0244 0245 % Open the binary STL file 0246 fidIN = fopen(stlFILENAME); 0247 0248 % Read the header 0249 fseek(fidIN,80,-1); % Move to the last 4 bytes of the header 0250 facetcount = fread(fidIN,1,'int32'); % Read the number of facets in the stl file 0251 0252 % Initialise arrays into which the STL data will be loaded: 0253 coordNORMALS = zeros(facetcount,3); 0254 coordVERTICES = zeros(facetcount,3,3); 0255 0256 % Read the data for each facet: 0257 for loopF = 1:facetcount 0258 0259 tempIN = fread(fidIN,3*4,'float'); 0260 0261 coordNORMALS(loopF,1:3) = tempIN(1:3); % x,y,z components of the facet's normal vector 0262 coordVERTICES(loopF,1:3,1) = tempIN(4:6); % x,y,z coordinates of vertex 1 0263 coordVERTICES(loopF,1:3,2) = tempIN(7:9); % x,y,z coordinates of vertex 2 0264 coordVERTICES(loopF,1:3,3) = tempIN(10:12); % x,y,z coordinates of vertex 3 0265 0266 fread(fidIN,1,'int16'); % Move to the start of the next facet. Using fread is much quicker than using fseek(fidIN,2,0); 0267 0268 end %for 0269 0270 % Close the binary STL file 0271 fclose(fidIN); 0272 0273 end %function 0274 %==========================================================================