% ------------------------------------------------------------------------------
% ImportSTL - Import a 3D mesh from an ASCII .STL file and return
%       Faces, Vertices and CData matrices which can be used by patch().
%       Written by unknown author.  Last modified 06 Nov 2005.
%
% Call: [Faces, Vertices, CData] = ImportSTL(filename)
% Args: filename - a string giving the fully qualified name of the .STL file
% Rtns: f - matrix in which rows hold the indices of the vertices in faces
%       v - matrix in which rows hold the coordinates of vertices
%       c - matrix in which rows hold the color specs at vertices
% ------------------------------------------------------------------------------

function [f, v, c] = ImportSTL(filename)

  fid = fopen(filename, 'r'); %open the ASCII .STL file
  if fid == -1
    error(sprintf('File %s could not be opened.', filename));
  end

  % Example .STL file contents:
  %   
  % solid BLOCK
  %   color 1.000 1.000 1.000
  %   facet
  %     normal 0.000000e+00 0.000000e+00 -1.000000e+00
  %     normal 0.000000e+00 0.000000e+00 -1.000000e+00
  %     normal 0.000000e+00 0.000000e+00 -1.000000e+00
  %   outer loop
  %     vertex 5.000000e-01 -5.000000e-01 -5.000000e-01
  %     vertex -5.000000e-01 -5.000000e-01 -5.000000e-01
  %     vertex -5.000000e-01 5.000000e-01 -5.000000e-01
  %   endloop
  % endfacet
  %
  % The first line is the object name, followed by multiple facet and
  % vertex lines.  A color specifier is next, followed by the faces of
  % that color, until the next color line.

  % object name, if present; some STL files have it, some don't.
  ObjectName = sscanf(fgetl(fid), '%*s %s');

  vNum = 0; % vertex counter
  vClr = [248 248 248]/255; % very light grey, just in case...
  nSkip = 0; nPrint = 249; % report status every 250 vertices

  while feof(fid) == 0
    % read a line and get the leading word
    txtLine = fgetl(fid); wrdFirst = sscanf(txtLine, '%s ');
    % Check for color
    if strncmpi(wrdFirst, 'c', 1) == 1; % leading word is "color"
       % get a color and make it the current color
      vClr = sscanf(txtLine, '%*s %f %f %f');
    elseif strncmpi(wrdFirst, 'v', 1) == 1; % leading word is "vertex"
      vNum = vNum + 1;
      % get the vertex coordinates and assign the current color to the vertex
      v(:,vNum) = sscanf(txtLine, '%*s %f %f %f'); c(:,vNum) = vClr;
      if nSkip < nPrint, nSkip = nSkip + 1;
      else fprintf('  vertex: %d\r', vNum); nSkip = 0; end
    end
  end

  fclose(fid); % finished reading vertices

  % STL is all triangles, so we have 3 vertices per face.  The order of the
  % vertices in the file is such that we just need to group their indices in
  % columns of 3 to get a matrix in which the nth column gives the indices of
  % the vertices of the nth face.  That is,
  % f = [
  %   1 4 7 ... (3 * nFaces - 2)
  %   2 5 8 ... (3 * nFaces - 1)
  %   3 6 9 ... (3 * nFaces)
  % ];
  f = reshape(1:vNum, 3, vNum/3);

  % transpose the arrays for direct use by patch
  f = f'; v = v'; c = c';
end
