Home > 16-Surface-Reconstruction > Surface-Reconstruction > Functions > ply_write.m

ply_write

PURPOSE ^

*****************************************************************************80

SYNOPSIS ^

function ply_write ( Elements, Path, Format, Str )

DESCRIPTION ^

*****************************************************************************80

% PLY_WRITE writes 3D data as a PLY file.

   PLY_WRITE(DATA,FILENAME) writes the structure DATA as a binary
   PLY file.  Every field of DATA is interpreted as an element
   and every subfield as an element property.  Each subfield of
   property data must either be an array or a cell array of
   arrays.  All property data in an element must have the same
   length.

   A common PLY data structure has the following fields:
      DATA.vertex.x = x coordinates, [Nx1] real array
      DATA.vertex.y = y coordinates, [Nx1] real array
      DATA.vertex.z = z coordinates, [Nx1] real array

      DATA.face.vertex_indices = vertex index lists,
         an {Mx1} cell array where each cell holds a one-
         dimesional array (of any length) of vertex indices.
   Some other common data fields:
      DATA.vertex.nx = x coordinate of normal, [Nx1] real array
      DATA.vertex.ny = y coordinate of normal, [Nx1] real array
      DATA.vertex.nz = z coordinate of normal, [Nx1] real array

      DATA.edge.vertex1 = index to a vertex, [Px1] integer array
      DATA.edge.vertex2 = second vertex index, [Px1] integer array
   Many other fields and properties can be added.  The PLY format
   is not limited to the naming in the examples above -- they are
   only the conventional naming.

   PLY_WRITE(DATA,FILENAME,FORMAT) write the PLY with a specified
   data format, where FORMAT is
      'ascii'                  ASCII text data
      'binary_little_endian'   binary data, little endian
      'binary_big_endian'      binary data, big endian (default)

   PLY_WRITE(DATA,FILENAME,FORMAT,'double') or

   PLY_WRITE(DATA,FILENAME,'double') write floating-point data as
   double precision rather than in the default single precision.

   Example:
   % make a cube
   clear Data;
   Data.vertex.x = [0;0;0;0;1;1;1;1];
   Data.vertex.y = [0;0;1;1;0;0;1;1];
   Data.vertex.z = [0;1;1;0;0;1;1;0];
   Data.face.vertex_indices = {[0,1,2,3],[7,6,5,4], ...
         [0,4,5,1],[1,5,6,2],[2,6,7,3],[3,7,4,0]};
   plywrite(Data,'cube.ply','ascii');

  Licensing:

    This code is distributed under the GNU LGPL license.

  Modified:

    01 March 2007

  Author:

    Pascal Getreuer 2004

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function ply_write ( Elements, Path, Format, Str )
0002 
0003 %*****************************************************************************80
0004 %
0005 %% PLY_WRITE writes 3D data as a PLY file.
0006 %
0007 %   PLY_WRITE(DATA,FILENAME) writes the structure DATA as a binary
0008 %   PLY file.  Every field of DATA is interpreted as an element
0009 %   and every subfield as an element property.  Each subfield of
0010 %   property data must either be an array or a cell array of
0011 %   arrays.  All property data in an element must have the same
0012 %   length.
0013 %
0014 %   A common PLY data structure has the following fields:
0015 %      DATA.vertex.x = x coordinates, [Nx1] real array
0016 %      DATA.vertex.y = y coordinates, [Nx1] real array
0017 %      DATA.vertex.z = z coordinates, [Nx1] real array
0018 %
0019 %      DATA.face.vertex_indices = vertex index lists,
0020 %         an {Mx1} cell array where each cell holds a one-
0021 %         dimesional array (of any length) of vertex indices.
0022 %   Some other common data fields:
0023 %      DATA.vertex.nx = x coordinate of normal, [Nx1] real array
0024 %      DATA.vertex.ny = y coordinate of normal, [Nx1] real array
0025 %      DATA.vertex.nz = z coordinate of normal, [Nx1] real array
0026 %
0027 %      DATA.edge.vertex1 = index to a vertex, [Px1] integer array
0028 %      DATA.edge.vertex2 = second vertex index, [Px1] integer array
0029 %   Many other fields and properties can be added.  The PLY format
0030 %   is not limited to the naming in the examples above -- they are
0031 %   only the conventional naming.
0032 %
0033 %   PLY_WRITE(DATA,FILENAME,FORMAT) write the PLY with a specified
0034 %   data format, where FORMAT is
0035 %      'ascii'                  ASCII text data
0036 %      'binary_little_endian'   binary data, little endian
0037 %      'binary_big_endian'      binary data, big endian (default)
0038 %
0039 %   PLY_WRITE(DATA,FILENAME,FORMAT,'double') or
0040 %
0041 %   PLY_WRITE(DATA,FILENAME,'double') write floating-point data as
0042 %   double precision rather than in the default single precision.
0043 %
0044 %   Example:
0045 %   % make a cube
0046 %   clear Data;
0047 %   Data.vertex.x = [0;0;0;0;1;1;1;1];
0048 %   Data.vertex.y = [0;0;1;1;0;0;1;1];
0049 %   Data.vertex.z = [0;1;1;0;0;1;1;0];
0050 %   Data.face.vertex_indices = {[0,1,2,3],[7,6,5,4], ...
0051 %         [0,4,5,1],[1,5,6,2],[2,6,7,3],[3,7,4,0]};
0052 %   plywrite(Data,'cube.ply','ascii');
0053 %
0054 %  Licensing:
0055 %
0056 %    This code is distributed under the GNU LGPL license.
0057 %
0058 %  Modified:
0059 %
0060 %    01 March 2007
0061 %
0062 %  Author:
0063 %
0064 %    Pascal Getreuer 2004
0065 %
0066   if ( nargin < 4 )
0067 
0068     Str = '';
0069 
0070     if ( nargin < 3 )
0071       Format = 'binary_big_endian';
0072     elseif strcmpi(Format,'double')
0073       Str = 'double';
0074       Format = 'binary_big_endian';
0075     end
0076 
0077   end
0078 
0079   [ fid, Msg ] = fopen ( Path, 'wt' );
0080 
0081   if ( fid == -1 )
0082     error(Msg);
0083   end
0084 
0085   PlyTypeNames = {'char','uchar','short','ushort','int','uint','float','double', ...
0086     'char8','uchar8','short16','ushort16','int32','uint32','float32','double64'};
0087   FWriteTypeNames = {'schar','uchar','int16','uint16','int32','uint32','single','double'};
0088   MatlabTypeNames = {'int8','uint8','int16','uint16','int32','uint32','single','double'};
0089   PrintfTypeChar = {'%d','%u','%d','%u','%d','%u','%-.6f','%-.14e'};
0090   IntegerDataMin = [-128,0,-2^15,-2^31,0];
0091   IntegerDataMax = [127,255,2^16-1,2^31-1,2^32-1];
0092 %
0093 %  write PLY header
0094 %
0095   fprintf(fid,'ply\nformat %s 1.0\ncomment created by MATLAB ply_write\n',Format);
0096   ElementNames = fieldnames(Elements);
0097   NumElements = length(ElementNames);
0098   Data = cell(NumElements,1);
0099 
0100   for i = 1 : NumElements
0101 
0102     eval(['tmp=isa(Elements.',ElementNames{i},',''struct'');']);
0103 
0104     if ( tmp )
0105       eval(['PropertyNames{i}=fieldnames(Elements.',ElementNames{i},');']);
0106     else
0107       PropertyNames{i} = [];
0108     end
0109 
0110     if ( ~isempty(PropertyNames{i}) )
0111       eval(['Data{i}{1}=Elements.',ElementNames{i},'.',PropertyNames{i}{1},';']);
0112       ElementCount(i) = prod(size(Data{i}{1}));
0113       Type{i} = zeros(length(PropertyNames{i}),1);
0114     else
0115       ElementCount(i) = 0;
0116     end
0117 
0118     fprintf(fid,'element %s %u\n',ElementNames{i},ElementCount(i));
0119 
0120     for j = 1 : length(PropertyNames{i})
0121 
0122       eval(['Data{i}{j}=Elements.',ElementNames{i},'.',PropertyNames{i}{j},';']);
0123 
0124       if ( ElementCount(i) ~= prod(size(Data{i}{j})) )
0125         fclose(fid);
0126         error('All property data in an element must have the same length.');
0127       end
0128 
0129       if ( iscell(Data{i}{j}) )
0130         Type{i}(j) = 9;
0131         Data{i}{j} = Data{i}{j}{1};
0132       end
0133 
0134       for k = 1 : length(MatlabTypeNames)
0135         if ( isa(Data{i}{j},MatlabTypeNames{k}) )
0136           Type{i}(j) = Type{i}(j) + k;
0137           break;
0138         end
0139       end
0140 
0141       if ( ~rem(Type{i}(j),9) )
0142         fclose(fid);
0143         error('Unsupported data structure.');
0144       end
0145 %
0146 %  Try to convert float data to integer data
0147 %
0148 %  Array data.
0149 %
0150       if ( Type{i}(j) <= 8 )
0151         if any(strcmp({'single','double'},MatlabTypeNames{Type{i}(j)}))
0152           if ~any(floor(Data{i}{j}) ~= Data{i}{j})  % data is integer
0153             MinValue = min(min(Data{i}{j}));
0154             MaxValue = max(max(Data{i}{j}));
0155 
0156                % choose smallest possible integer data format
0157             tmp = max(min(find(MinValue >= IntegerDataMin)),min(find(MaxValue <= IntegerDataMax)));
0158 
0159             if ~isempty(tmp)
0160               Type{i}(j) = tmp;
0161             end
0162           end
0163         end
0164       else        % cell array data
0165         eval(['Data{i}{j}=Elements.',ElementNames{i},'.',PropertyNames{i}{j},';']);
0166         tmp = 1;
0167 
0168         for k = 1:prod(size(Data{i}{j}))
0169           tmp = tmp & all(floor(Data{i}{j}{k}) == Data{i}{j}{k});
0170         end
0171 
0172         if tmp  % data is integer
0173           MinValue = inf;
0174           MaxValue = -inf;
0175 
0176           for k = 1:prod(size(Data{i}{j}))
0177             MinValue = min(MinValue,min(Data{i}{j}{k}));
0178             MaxValue = max(MaxValue,max(Data{i}{j}{k}));
0179           end
0180 
0181             % choose smallest possible integer data format
0182           tmp = max(min(find(MinValue >= IntegerDataMin)),min(find(MaxValue <= IntegerDataMax)));
0183 
0184           if ~isempty(tmp)
0185             Type{i}(j) = tmp + 9;
0186           end
0187 
0188         end
0189       end
0190 
0191       % convert double to single if specified
0192       if rem(Type{i}(j),9) == 8 & ~strcmpi(Str,'double')
0193         Type{i}(j) = Type{i}(j) - 1;
0194       end
0195 
0196       if Type{i}(j) <= 8
0197         fprintf(fid,'property %s %s\n',PlyTypeNames{Type{i}(j)},PropertyNames{i}{j});
0198       else
0199         fprintf(fid,'property list uchar %s %s\n',PlyTypeNames{Type{i}(j)-9},PropertyNames{i}{j});
0200       end
0201     end
0202   end
0203 
0204   fprintf(fid,'end_header\n');
0205 
0206   switch Format
0207     case 'ascii'
0208       Format = 0;
0209     case 'binary_little_endian'
0210       fclose(fid);
0211       fid = fopen(Path,'a','ieee-le');
0212       Format = 1;
0213     case 'binary_big_endian'
0214       fclose(fid);
0215       fid = fopen(Path,'a','ieee-be');
0216       Format = 2;
0217   end
0218 
0219   for i = 1 : NumElements
0220     if ~isempty(PropertyNames{i})
0221       if ~Format          % write ASCII data
0222         for k = 1:ElementCount(i)
0223           for j = 1:length(PropertyNames{i})
0224             if Type{i}(j) <= 8
0225               fprintf(fid,[PrintfTypeChar{Type{i}(j)},' '],Data{i}{j}(k));
0226             else
0227               fprintf(fid,'%u%s ',length(Data{i}{j}{k}),sprintf([' ',PrintfTypeChar{Type{i}(j)-9}],Data{i}{j}{k}));
0228             end
0229           end
0230 
0231           fprintf(fid,'\n');
0232         end
0233       else            % write binary data
0234         if all(Type{i} <= 8) & all(Type{i} == Type{i}(1))
0235           % property data without list types (fast)
0236           tmp = zeros(length(PropertyNames{i}),ElementCount(i));
0237 
0238           for j = 1:length(PropertyNames{i})
0239             tmp(j,:) = Data{i}{j}(:)';
0240           end
0241 
0242           fwrite(fid,tmp,FWriteTypeNames{Type{i}(j)});
0243         elseif all(Type{i} > 8)
0244         % only list types
0245           Type{i} = Type{i} - 9;
0246 
0247           if length(PropertyNames{i}) == 1
0248            % only one list property
0249             tmp = FWriteTypeNames{Type{i}(1)};
0250 
0251             for k = 1:ElementCount(i)
0252               fwrite(fid,length(Data{i}{1}{k}),'uchar');
0253               fwrite(fid,Data{i}{1}{k},tmp);
0254             end
0255           else
0256            % multiple list properties
0257             for k = 1:ElementCount(i)
0258               for j = 1:length(PropertyNames{i})
0259                 fwrite(fid,length(Data{i}{j}{k}),'uchar');
0260                 fwrite(fid,Data{i}{j}{k},FWriteTypeNames{Type{i}(j)});
0261               end
0262             end
0263           end
0264         else
0265         % mixed type
0266           for k = 1:ElementCount(i)
0267             for j = 1:length(PropertyNames{i})
0268               if Type{i}(j) <= 8
0269                 fwrite(fid,Data{i}{j}(k),FWriteTypeNames{Type{i}(j)});
0270               else
0271                 fwrite(fid,length(Data{i}{j}{k}),'uchar');
0272                 fwrite(fid,Data{i}{j}{k},FWriteTypeNames{Type{i}(j)-9});
0273               end
0274             end
0275           end
0276         end
0277       end
0278     end
0279   end
0280 
0281   fclose(fid);
0282 
0283   return
0284 end

Generated on Sat 21-Jul-2018 20:56:10 by m2html © 2005