0001 function [ Elements, varargout ] = ply_read ( Path, Str )
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 [ fid, Msg ] = fopen ( Path, 'rt' );
0063
0064 if ( fid == -1 )
0065 error ( Msg );
0066 end
0067
0068 Buf = fscanf ( fid, '%s', 1 );
0069
0070 if ( ~strcmp ( Buf, 'ply' ) )
0071 fclose ( fid );
0072 error('Not a PLY file.');
0073 end
0074
0075
0076
0077 Position = ftell(fid);
0078 Format = '';
0079 NumComments = 0;
0080 Comments = {};
0081 NumElements = 0;
0082 NumProperties = 0;
0083 Elements = [];
0084 ElementCount = [];
0085 PropertyTypes = [];
0086 ElementNames = {};
0087 PropertyNames = [];
0088
0089 while ( 1 )
0090
0091
0092
0093 Buf = fgetl ( fid );
0094 BufRem = Buf;
0095 Token = {};
0096 Count = 0;
0097
0098
0099
0100 while ( ~isempty(BufRem) )
0101
0102 [ tmp, BufRem ] = strtok(BufRem);
0103
0104
0105
0106 if ( ~isempty ( tmp ) )
0107 Count = Count + 1;
0108 Token{Count} = tmp;
0109 end
0110
0111 end
0112
0113
0114
0115 if ( Count )
0116
0117 switch lower ( Token{1} )
0118
0119
0120
0121 case 'format'
0122
0123 if ( 2 <= Count )
0124
0125 Format = lower ( Token{2} );
0126
0127 if ( Count == 3 & ~strcmp ( Token{3}, '1.0' ) )
0128 fclose ( fid );
0129 error('Only PLY format version 1.0 supported.');
0130 end
0131 end
0132
0133
0134
0135 case 'comment'
0136
0137 NumComments = NumComments + 1;
0138 Comments{NumComments} = '';
0139 for i = 2 : Count
0140 Comments{NumComments} = [Comments{NumComments},Token{i},' '];
0141 end
0142
0143
0144
0145 case 'element'
0146
0147 if ( 3 <= Count )
0148
0149 if ( isfield(Elements,Token{2}) )
0150 fclose ( fid );
0151 error(['Duplicate element name, ''',Token{2},'''.']);
0152 end
0153
0154 NumElements = NumElements + 1;
0155 NumProperties = 0;
0156 Elements = setfield(Elements,Token{2},[]);
0157 PropertyTypes = setfield(PropertyTypes,Token{2},[]);
0158 ElementNames{NumElements} = Token{2};
0159 PropertyNames = setfield(PropertyNames,Token{2},{});
0160 CurElement = Token{2};
0161 ElementCount(NumElements) = str2double(Token{3});
0162
0163 if ( isnan(ElementCount(NumElements)) )
0164 fclose ( fid );
0165 error(['Bad element definition: ',Buf]);
0166 end
0167
0168 else
0169
0170 error(['Bad element definition: ',Buf]);
0171
0172 end
0173
0174
0175
0176 case 'property'
0177
0178 if ( ~isempty(CurElement) & Count >= 3 )
0179
0180 NumProperties = NumProperties + 1;
0181 eval(['tmp=isfield(Elements.',CurElement,',Token{Count});'],...
0182 'fclose(fid);error([''Error reading property: '',Buf])');
0183
0184 if ( tmp )
0185 error(['Duplicate property name, ''',CurElement,'.',Token{2},'''.']);
0186 end
0187
0188
0189
0190 eval(['Elements.',CurElement,'.',Token{Count},'=[];'], ...
0191 'fclose(fid);error([''Error reading property: '',Buf])');
0192
0193
0194
0195 eval(['PropertyTypes.',CurElement,'.',Token{Count},'={Token{2:Count-1}};'], ...
0196 'fclose(fid);error([''Error reading property: '',Buf])');
0197
0198
0199
0200 eval(['PropertyNames.',CurElement,'{NumProperties}=Token{Count};'], ...
0201 'fclose(fid);error([''Error reading property: '',Buf])');
0202
0203 else
0204
0205 fclose ( fid );
0206
0207 if ( isempty(CurElement) )
0208 error(['Property definition without element definition: ',Buf]);
0209 else
0210 error(['Bad property definition: ',Buf]);
0211 end
0212
0213 end
0214
0215
0216
0217 case 'end_header'
0218 break;
0219
0220 end
0221 end
0222 end
0223
0224
0225
0226 if ( isempty ( Format ) )
0227 warning('Data format unspecified, assuming ASCII.');
0228 Format = 'ascii';
0229 end
0230
0231 switch Format
0232
0233 case 'ascii'
0234 Format = 0;
0235 case 'binary_little_endian'
0236 Format = 1;
0237 case 'binary_big_endian'
0238 Format = 2;
0239 otherwise
0240 fclose ( fid );
0241 error(['Data format ''',Format,''' not supported.']);
0242
0243 end
0244
0245
0246
0247 if ( ~Format )
0248 Buf = fscanf ( fid, '%f' );
0249 BufOff = 1;
0250 else
0251
0252
0253
0254 fclose ( fid );
0255
0256
0257
0258 if ( Format == 1 )
0259 fid = fopen ( Path, 'r', 'ieee-le.l64' );
0260 else
0261 fid = fopen ( Path, 'r', 'ieee-be.l64' );
0262 end
0263
0264
0265
0266
0267 BufSize = 8192;
0268 Buf = [ blanks(10), char(fread(fid,BufSize,'uchar')') ];
0269 i = [];
0270 tmp = -11;
0271
0272 while ( isempty(i) )
0273
0274 i = findstr(Buf,['end_header',13,10]);
0275 i = [i,findstr(Buf,['end_header',10])];
0276
0277 if ( isempty(i) )
0278 tmp = tmp + BufSize;
0279 Buf = [Buf(BufSize+1:BufSize+10),char(fread(fid,BufSize,'uchar')')];
0280 end
0281
0282 end
0283
0284
0285
0286 fseek ( fid, i + tmp + 11 + (Buf(i + 10) == 13), -1 );
0287
0288 end
0289
0290
0291
0292
0293
0294 PlyTypeNames = {'char','uchar','short','ushort','int','uint','float','double', ...
0295 'char8','uchar8','short16','ushort16','int32','uint32','float32','double64'};
0296
0297 MatlabTypeNames = {'schar','uchar','int16','uint16','int32','uint32','single','double'};
0298
0299 SizeOf = [1,1,2,2,4,4,4,8];
0300
0301 for i = 1 : NumElements
0302
0303
0304
0305 eval(['CurPropertyNames=PropertyNames.',ElementNames{i},';']);
0306 eval(['CurPropertyTypes=PropertyTypes.',ElementNames{i},';']);
0307 NumProperties = size(CurPropertyNames,2);
0308
0309
0310
0311
0312
0313 if ( ~Format )
0314
0315 for j = 1 : NumProperties
0316
0317 Token = getfield(CurPropertyTypes,CurPropertyNames{j});
0318
0319 if ( strcmpi(Token{1},'list') )
0320 Type(j) = 1;
0321 else
0322 Type(j) = 0;
0323 end
0324
0325 end
0326
0327
0328
0329 if ( ~any(Type) )
0330
0331
0332
0333 Data = reshape ( ...
0334 Buf(BufOff:BufOff+ElementCount(i)*NumProperties-1), ...
0335 NumProperties, ElementCount(i) )';
0336
0337 BufOff = BufOff + ElementCount(i) * NumProperties;
0338
0339 else
0340
0341 ListData = cell(NumProperties,1);
0342
0343 for k = 1 : NumProperties
0344 ListData{k} = cell(ElementCount(i),1);
0345 end
0346
0347
0348
0349 for j = 1 : ElementCount(i)
0350 for k = 1 : NumProperties
0351
0352 if ( ~Type(k) )
0353 Data(j,k) = Buf(BufOff);
0354 BufOff = BufOff + 1;
0355 else
0356 tmp = Buf(BufOff);
0357 ListData{k}{j} = Buf(BufOff+(1:tmp))';
0358 BufOff = BufOff + tmp + 1;
0359 end
0360
0361 end
0362 end
0363
0364 end
0365
0366
0367
0368 else
0369
0370 ListFlag = 0;
0371 SameFlag = 1;
0372
0373 for j = 1 : NumProperties
0374
0375 Token = getfield(CurPropertyTypes,CurPropertyNames{j});
0376
0377
0378
0379 if ( ~strcmp(Token{1},'list' ) )
0380
0381 tmp = rem(strmatch(Token{1},PlyTypeNames,'exact')-1,8)+1;
0382
0383 if ( ~isempty(tmp) )
0384
0385 TypeSize(j) = SizeOf(tmp);
0386 Type{j} = MatlabTypeNames{tmp};
0387 TypeSize2(j) = 0;
0388 Type2{j} = '';
0389
0390 SameFlag = SameFlag & strcmp(Type{1},Type{j});
0391
0392 else
0393
0394 fclose(fid);
0395 error(['Unknown property data type, ''',Token{1},''', in ', ...
0396 ElementNames{i},'.',CurPropertyNames{j},'.']);
0397
0398 end
0399
0400 else
0401
0402 if ( length(Token) == 3 )
0403
0404 ListFlag = 1;
0405 SameFlag = 0;
0406 tmp = rem(strmatch(Token{2},PlyTypeNames,'exact')-1,8)+1;
0407 tmp2 = rem(strmatch(Token{3},PlyTypeNames,'exact')-1,8)+1;
0408
0409 if ( ~isempty(tmp) & ~isempty(tmp2) )
0410 TypeSize(j) = SizeOf(tmp);
0411 Type{j} = MatlabTypeNames{tmp};
0412 TypeSize2(j) = SizeOf(tmp2);
0413 Type2{j} = MatlabTypeNames{tmp2};
0414 else
0415 fclose(fid);
0416 error(['Unknown property data type, ''list ',Token{2},' ',Token{3},''', in ', ...
0417 ElementNames{i},'.',CurPropertyNames{j},'.']);
0418 end
0419
0420 else
0421
0422 fclose(fid);
0423 error(['Invalid list syntax in ',ElementNames{i},'.',CurPropertyNames{j},'.']);
0424
0425 end
0426
0427 end
0428
0429 end
0430
0431
0432
0433 if ( ~ListFlag )
0434
0435
0436
0437 if ( SameFlag )
0438
0439 Data = fread(fid,[NumProperties,ElementCount(i)],Type{1})';
0440
0441
0442
0443 else
0444
0445 Data = zeros(ElementCount(i),NumProperties);
0446
0447 for j = 1 : ElementCount(i)
0448 for k = 1 : NumProperties
0449 Data(j,k) = fread(fid,1,Type{k});
0450 end
0451 end
0452
0453 end
0454
0455 else
0456
0457 ListData = cell(NumProperties,1);
0458
0459 for k = 1 : NumProperties
0460 ListData{k} = cell(ElementCount(i),1);
0461 end
0462
0463 if ( NumProperties == 1 )
0464
0465 BufSize = 512;
0466 SkipNum = 4;
0467 j = 0;
0468
0469
0470
0471 while ( j < ElementCount(i) )
0472
0473 BufSize = min(ElementCount(i)-j,BufSize);
0474 Position = ftell(fid);
0475
0476
0477
0478 [Buf,BufSize] = fread(fid,BufSize,Type{1},SkipNum*TypeSize2(1));
0479 Miss = find(Buf ~= SkipNum);
0480 fseek(fid,Position + TypeSize(1),-1);
0481
0482 if ( isempty(Miss) )
0483
0484 Buf = fread(fid,[SkipNum,BufSize],[int2str(SkipNum),'*',Type2{1}],TypeSize(1))';
0485 fseek(fid,-TypeSize(1),0);
0486
0487 for k = 1:BufSize
0488 ListData{1}{j+k} = Buf(k,:);
0489 end
0490
0491 j = j + BufSize;
0492 BufSize = floor(1.5*BufSize);
0493
0494 else
0495
0496
0497
0498 if ( 1 < Miss(1) )
0499
0500 Buf2 = fread(fid,[SkipNum,Miss(1)-1],[int2str(SkipNum),'*',Type2{1}],TypeSize(1))';
0501
0502 for k = 1:Miss(1)-1
0503 ListData{1}{j+k} = Buf2(k,:);
0504 end
0505
0506 j = j + k;
0507
0508 end
0509
0510
0511
0512 SkipNum = Buf(Miss(1));
0513 j = j + 1;
0514 ListData{1}{j} = fread(fid,[1,SkipNum],Type2{1});
0515 BufSize = ceil(0.6*BufSize);
0516
0517 end
0518 end
0519
0520 else
0521
0522
0523
0524 Data = zeros(ElementCount(i),NumProperties);
0525
0526 for j = 1:ElementCount(i)
0527 for k = 1:NumProperties
0528
0529 if ( isempty(Type2{k}) )
0530 Data(j,k) = fread(fid,1,Type{k});
0531 else
0532 tmp = fread(fid,1,Type{k});
0533 ListData{k}{j} = fread(fid,[1,tmp],Type2{k});
0534 end
0535
0536 end
0537 end
0538 end
0539 end
0540 end
0541
0542
0543
0544 for k = 1 : NumProperties
0545
0546 if ( ( ~Format && ~Type(k) ) || (Format && isempty(Type2{k})) )
0547 eval(['Elements.',ElementNames{i},'.',CurPropertyNames{k},'=Data(:,k);']);
0548 else
0549 eval(['Elements.',ElementNames{i},'.',CurPropertyNames{k},'=ListData{k};']);
0550 end
0551
0552 end
0553
0554 end
0555
0556 clear Data
0557 clear ListData;
0558
0559 fclose ( fid );
0560
0561
0562
0563 if ( ( nargin > 1 && strcmpi(Str,'Tri') ) || nargout > 2 )
0564
0565
0566
0567 Name = {'vertex','Vertex','point','Point','pts','Pts'};
0568 Names = [];
0569
0570 for i = 1 : length(Name)
0571
0572 if ( any ( strcmp ( ElementNames, Name{i} ) ) )
0573 Names = getfield(PropertyNames,Name{i});
0574 Name = Name{i};
0575 break;
0576 end
0577
0578 end
0579
0580 if ( any(strcmp(Names,'x')) & any(strcmp(Names,'y')) & any(strcmp(Names,'z')) )
0581 eval(['varargout{1}=[Elements.',Name,'.x,Elements.',Name,'.y,Elements.',Name,'.z];']);
0582 else
0583 varargout{1} = zeros(1,3);
0584 end
0585 varargout{1} = varargout{1}';
0586
0587 varargout{2} = Elements;
0588 varargout{3} = Comments;
0589 Elements = [];
0590
0591
0592
0593 Name = {'face','Face','poly','Poly','tri','Tri'};
0594 Names = [];
0595
0596 for i = 1 : length(Name)
0597 if ( any(strcmp(ElementNames,Name{i})) )
0598 Names = getfield(PropertyNames,Name{i});
0599 Name = Name{i};
0600 break;
0601 end
0602 end
0603
0604 if ( ~isempty(Names) )
0605
0606 PropertyName = {'vertex_indices','vertex_indexes','vertex_index','indices','indexes'};
0607
0608 for i = 1 : length(PropertyName)
0609 if ( any(strcmp(Names,PropertyName{i})) )
0610 PropertyName = PropertyName{i};
0611 break;
0612 end
0613 end
0614
0615
0616
0617 if ( ~iscell(PropertyName) )
0618
0619 eval(['FaceIndices=varargout{2}.',Name,'.',PropertyName,';']);
0620 N = length(FaceIndices);
0621 Elements = zeros(3,N*2);
0622 Extra = 0;
0623
0624 for k = 1 : N
0625
0626 Elements(1:3,k) = FaceIndices{k}(1:3)';
0627
0628
0629
0630 for j = 4 : length(FaceIndices{k})
0631 Extra = Extra + 1;
0632 Elements(1,N + Extra) = FaceIndices{k}(1);
0633 Elements(2,N + Extra) = FaceIndices{k}(j-1);
0634 Elements(3,N + Extra) = FaceIndices{k}(j);
0635 end
0636
0637 end
0638
0639
0640
0641 Elements = Elements(:,1:N+Extra) + 1;
0642
0643 end
0644 end
0645
0646 else
0647
0648 varargout{1} = Comments;
0649
0650 end
0651
0652 return
0653 end