Home > arte3.2.0 > tools > stlwrite > stlwrite.m

stlwrite

PURPOSE ^

STLWRITE Write STL file from patch or surface data.

SYNOPSIS ^

function stlwrite(filename, varargin)

DESCRIPTION ^

STLWRITE   Write STL file from patch or surface data.

   STLWRITE(FILE,fv) writes a stereolithography (STL) file to FILE for a triangulated
   patch defined by FV (a structure with fields 'vertices' and 'faces').

   STLWRITE(FILE,FACES,VERTICES) takes faces and vertices separately, rather than in an FV struct

   STLWRITE(FILE,X,Y,Z) creates an STL file from surface data in X, Y, and Z. STLWRITE triangulates
   this gridded data into a triangulated surface using triangulations options specified below. X, Y
   and Z can be two-dimensional arrays with the same size. If X and Y are vectors with length equal
   to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed through MESHGRID to create gridded
   data. If X or Y are scalar values, they are used to specify the X and Y spacing between grid
   points.

   STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an STL file using the
   following property values:

   MODE          - File is written using 'binary' (default) or 'ascii'.

   TITLE         - Header text (max 80 characters) written to the STL file.

   TRIANGULATION - When used with gridded data, TRIANGULATION is either:
                       'delaunay'  - (default) Delaunay triangulation of X, Y
                       'f'         - Forward slash division of grid quadrilaterals
                       'b'         - Back slash division of quadrilaterals
                       'x'         - Cross division of quadrilaterals
                   Note that 'f', 'b', or 't' triangulations require FEX entry 28327, "mesh2tri".

   FACECOLOR     - (not currently implemented) When used with face/vertex input, specifies the
                   colour of each triangle face. If users request this feature, I will attempt to
                   implement it.

   Example 1:
       % Write binary STL from face/vertex data
       tmpvol = zeros(20,20,20);       % Empty voxel volume
       tmpvol(8:12,8:12,5:15) = 1;     % Turn some voxels on
       fv = isosurface(tmpvol, 0.99);  % Create the patch object
       stlwrite('test.stl',fv)         % Save to binary .stl

   Example 2:
       % Write ascii STL from gridded data
       [X,Y] = deal(1:40);             % Create grid reference
       Z = peaks(40);                  % Create grid height
       stlwrite('test.stl',X,Y,Z,'mode','ascii')

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function stlwrite(filename, varargin)
0002 %STLWRITE   Write STL file from patch or surface data.
0003 %
0004 %   STLWRITE(FILE,fv) writes a stereolithography (STL) file to FILE for a triangulated
0005 %   patch defined by FV (a structure with fields 'vertices' and 'faces').
0006 %
0007 %   STLWRITE(FILE,FACES,VERTICES) takes faces and vertices separately, rather than in an FV struct
0008 %
0009 %   STLWRITE(FILE,X,Y,Z) creates an STL file from surface data in X, Y, and Z. STLWRITE triangulates
0010 %   this gridded data into a triangulated surface using triangulations options specified below. X, Y
0011 %   and Z can be two-dimensional arrays with the same size. If X and Y are vectors with length equal
0012 %   to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed through MESHGRID to create gridded
0013 %   data. If X or Y are scalar values, they are used to specify the X and Y spacing between grid
0014 %   points.
0015 %
0016 %   STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an STL file using the
0017 %   following property values:
0018 %
0019 %   MODE          - File is written using 'binary' (default) or 'ascii'.
0020 %
0021 %   TITLE         - Header text (max 80 characters) written to the STL file.
0022 %
0023 %   TRIANGULATION - When used with gridded data, TRIANGULATION is either:
0024 %                       'delaunay'  - (default) Delaunay triangulation of X, Y
0025 %                       'f'         - Forward slash division of grid quadrilaterals
0026 %                       'b'         - Back slash division of quadrilaterals
0027 %                       'x'         - Cross division of quadrilaterals
0028 %                   Note that 'f', 'b', or 't' triangulations require FEX entry 28327, "mesh2tri".
0029 %
0030 %   FACECOLOR     - (not currently implemented) When used with face/vertex input, specifies the
0031 %                   colour of each triangle face. If users request this feature, I will attempt to
0032 %                   implement it.
0033 %
0034 %   Example 1:
0035 %       % Write binary STL from face/vertex data
0036 %       tmpvol = zeros(20,20,20);       % Empty voxel volume
0037 %       tmpvol(8:12,8:12,5:15) = 1;     % Turn some voxels on
0038 %       fv = isosurface(tmpvol, 0.99);  % Create the patch object
0039 %       stlwrite('test.stl',fv)         % Save to binary .stl
0040 %
0041 %   Example 2:
0042 %       % Write ascii STL from gridded data
0043 %       [X,Y] = deal(1:40);             % Create grid reference
0044 %       Z = peaks(40);                  % Create grid height
0045 %       stlwrite('test.stl',X,Y,Z,'mode','ascii')
0046 
0047 %   Original idea adapted from surf2stl by Bill McDonald. Huge speed
0048 %   improvements implemented by Oliver Woodford. Non-Delaunay triangulation
0049 %   of quadrilateral surface input requires mesh2tri by Kevin Moerman.
0050 %
0051 %   Author: Sven Holcombe, 11-24-11
0052 
0053 
0054 % % Check valid filename path
0055 % narginchk(2, inf)
0056 % path = fileparts(filename);
0057 % if ~isempty(path) && ~exist(path,'dir')
0058 %     error('Directory "%s" does not exist.',path);
0059 % end
0060 
0061 % Get faces, vertices, and user-defined options for writing
0062 [faces, vertices, options] = parseInputs(varargin{:});
0063 asciiMode = strcmp( options.mode ,'ascii');
0064 
0065 % Create the facets
0066 facets = single(vertices');
0067 facets = reshape(facets(:,faces'), 3, 3, []);
0068 
0069 % Compute their normals
0070 V1 = squeeze(facets(:,2,:) - facets(:,1,:));
0071 V2 = squeeze(facets(:,3,:) - facets(:,1,:));
0072 normals = V1([2 3 1],:) .* V2([3 1 2],:) - V2([2 3 1],:) .* V1([3 1 2],:);
0073 clear V1 V2
0074 normals = bsxfun(@times, normals, 1 ./ sqrt(sum(normals .* normals, 1)));
0075 facets = cat(2, reshape(normals, 3, 1, []), facets);
0076 clear normals
0077 
0078 % Open the file for writing
0079 permissions = {'w','wb+'};
0080 fid = fopen(filename, permissions{asciiMode+1});
0081 if (fid == -1)
0082     error('stlwrite:cannotWriteFile', 'Unable to write to %s', filename);
0083 end
0084 
0085 % Write the file contents
0086 if asciiMode
0087     % Write HEADER
0088     fprintf(fid,'solid %s\r\n',options.title);
0089     % Write DATA
0090     fprintf(fid,[...
0091         'facet normal %.7E %.7E %.7E\r\n' ...
0092         'outer loop\r\n' ...
0093         'vertex %.7E %.7E %.7E\r\n' ...
0094         'vertex %.7E %.7E %.7E\r\n' ...
0095         'vertex %.7E %.7E %.7E\r\n' ...
0096         'endloop\r\n' ...
0097         'endfacet\r\n'], facets);
0098     % Write FOOTER
0099     fprintf(fid,'endsolid %s\r\n',options.title);
0100     
0101 else % BINARY
0102     % Write HEADER
0103     fprintf(fid, '%-80s', options.title);             % Title
0104     fwrite(fid, size(facets, 3), 'uint32');           % Number of facets
0105     % Write DATA
0106     % Add one uint16(0) to the end of each facet using a typecasting trick
0107     facets = reshape(typecast(facets(:), 'uint16'), 12*2, []);
0108     facets(end+1,:) = 0;
0109     fwrite(fid, facets, 'uint16');
0110 end
0111 
0112 % Close the file
0113 fclose(fid);
0114 fprintf('Wrote %d facets\n',size(facets, 3));
0115 
0116 
0117 %% Input handling subfunctions
0118 function [faces, vertices, options] = parseInputs(varargin)
0119 % Determine input type
0120 if isstruct(varargin{1}) % stlwrite('file', FVstruct, ...)
0121     if ~all(isfield(varargin{1},{'vertices','faces'}))
0122         error( 'Variable p must be a faces/vertices structure' );
0123     end
0124     faces = varargin{1}.faces;
0125     vertices = varargin{1}.vertices;
0126     options = parseOptions(varargin{2:end});
0127     
0128 elseif isnumeric(varargin{1})
0129     firstNumInput = cellfun(@isnumeric,varargin);
0130     firstNumInput(find(~firstNumInput,1):end) = 0; % Only consider numerical input PRIOR to the first non-numeric
0131     numericInputCnt = nnz(firstNumInput);
0132     
0133     options = parseOptions(varargin{numericInputCnt+1:end});
0134     switch numericInputCnt
0135         case 3 % stlwrite('file', X, Y, Z, ...)
0136             % Extract the matrix Z
0137             Z = varargin{3};
0138             
0139             % Convert scalar XY to vectors
0140             ZsizeXY = fliplr(size(Z));
0141             for i = 1:2
0142                 if isscalar(varargin{i})
0143                     varargin{i} = (0:ZsizeXY(i)-1) * varargin{i};
0144                 end                    
0145             end
0146             
0147             % Extract X and Y
0148             if isequal(size(Z), size(varargin{1}), size(varargin{2}))
0149                 % X,Y,Z were all provided as matrices
0150                 [X,Y] = varargin{1:2};
0151             elseif numel(varargin{1})==ZsizeXY(1) && numel(varargin{2})==ZsizeXY(2)
0152                 % Convert vector XY to meshgrid
0153                 [X,Y] = meshgrid(varargin{1}, varargin{2});
0154             else
0155                 error('stlwrite:badinput', 'Unable to resolve X and Y variables');
0156             end
0157             
0158             % Convert to faces/vertices
0159             if strcmp(options.triangulation,'delaunay')
0160                 faces = delaunay(X,Y);
0161                 vertices = [X(:) Y(:) Z(:)];
0162             else
0163                 if ~exist('mesh2tri','file')
0164                     error('stlwrite:missing', '"mesh2tri" is required to convert X,Y,Z matrices to STL. It can be downloaded from:\n%s\n',...
0165                         'http://www.mathworks.com/matlabcentral/fileexchange/28327')
0166                 end
0167                 [faces, vertices] = mesh2tri(X, Y, Z, options.triangulation);
0168             end
0169             
0170         case 2 % stlwrite('file', FACES, VERTICES, ...)
0171             faces = varargin{1};
0172             vertices = varargin{2};
0173             
0174         otherwise
0175             error('stlwrite:badinput', 'Unable to resolve input types.');
0176     end
0177     
0178 end
0179 
0180 function options = parseOptions(varargin)
0181 IP = inputParser;
0182 IP.addParamValue('mode', 'binary', @ischar)
0183 IP.addParamValue('title', sprintf('Created by stlwrite.m %s',datestr(now)), @ischar);
0184 IP.addParamValue('triangulation', 'delaunay', @ischar);
0185 IP.addParamValue('facecolor',[], @isnumeric)
0186 IP.parse(varargin{:});
0187 options = IP.Results;

Generated on Fri 03-Jan-2014 12:20:01 by m2html © 2005