@@ -150,31 +150,26 @@ class PCDLoader extends Loader {
150150 if ( size == 8 ) {
151151 return dataview.getFloat64 ( offset, endian );
152152 }
153-
154153 return dataview.getFloat32 ( offset, endian );
155154 }
156155
157156 case 'I' : {
158157 if ( size == 1 ) {
159158 return dataview.getInt8 ( offset );
160159 }
161-
162160 if ( size == 2 ) {
163161 return dataview.getInt16 ( offset, endian );
164162 }
165-
166163 return dataview.getInt32 ( offset, endian );
167164 }
168165
169166 case 'U' : {
170167 if ( size == 1 ) {
171168 return dataview.getUint8 ( offset );
172169 }
173-
174170 if ( size == 2 ) {
175171 return dataview.getUint16 ( offset, endian );
176172 }
177-
178173 return dataview.getUint32 ( offset, endian );
179174 }
180175 }
@@ -187,64 +182,91 @@ class PCDLoader extends Loader {
187182 * @param {ArrayBuffer} data - The raw PCD data as an array buffer.
188183 * @return {Points} The parsed point cloud.
189184 */
190- Points _parse (List < int > data ) {
185+ Points _parse (Uint8List data ) {
191186 // from https://gitlab.com/taketwo/three-pcd-loader/blob/master/decompress-lzf.js
192187
193- decompressLZF (Uint8Array inData, int outLength ) {
194- final inLength = inData.length ;
195- final outData = new Uint8Array ( outLength );
188+ Uint8List decompressLZF (Uint8List inData, int outLength) {
189+ final int inLength = inData.lengthInBytes ;
190+ final Uint8List outData = Uint8List ( outLength);
196191 int inPtr = 0 ;
197192 int outPtr = 0 ;
198- int ctrl = 0 ;
193+ int ctrl;
199194 int len;
200195 int ref;
201196
202- do {
203- ctrl = inData[ inPtr ++ ];
204- if ( ctrl < ( 1 << 5 ) ) {
197+ while (inPtr < inLength) {
198+ ctrl = inData[inPtr++ ];
205199
206- ctrl ++ ;
207- if ( outPtr + ctrl > outLength ) throw ( 'Output buffer is not large enough' );
208- if ( inPtr + ctrl > inLength ) throw ( 'Invalid compressed data' );
209- do {
210- outData[ outPtr ++ ] = inData[ inPtr ++ ];
211- } while ( -- ctrl >= 0 );
212-
213- }
214- else {
200+ if (ctrl < (1 << 5 )) {
201+ // Literal run
202+ ctrl++ ;
203+ if (outPtr + ctrl > outLength) {
204+ throw StateError ('Output buffer is not large enough' );
205+ }
206+ if (inPtr + ctrl > inLength) {
207+ throw StateError ('Invalid compressed data' );
208+ }
209+
210+ // Copy bytes one by one using a while loop
211+ int count = ctrl;
212+ while (count-- > 0 ) {
213+ outData[outPtr++ ] = inData[inPtr++ ];
214+ }
215+
216+ } else {
217+ // Back reference
215218 len = ctrl >> 5 ;
216- ref = outPtr - ( ( ctrl & 0x1f ) << 8 ) - 1 ;
217- if ( inPtr >= inLength ) throw ( 'Invalid compressed data' );
218- if ( len == 7 ) {
219- len += inData[ inPtr ++ ];
220- if ( inPtr >= inLength ) throw ( 'Invalid compressed data' );
219+ ref = outPtr - ((ctrl & 0x1f ) << 8 ) - 1 ;
220+
221+ if (inPtr >= inLength) {
222+ throw StateError ('Invalid compressed data' );
223+ }
224+
225+ if (len == 7 ) {
226+ len += inData[inPtr++ ];
227+ if (inPtr >= inLength) {
228+ throw StateError ('Invalid compressed data' );
229+ }
230+ }
231+
232+ ref -= inData[inPtr++ ];
233+
234+ // The length in JS was adjusted inside the do-while condition (len-- + 2)
235+ final int copyLength = len + 2 ;
236+
237+ if (outPtr + copyLength > outLength) {
238+ throw StateError ('Output buffer is not large enough' );
239+ }
240+ if (ref < 0 ) {
241+ throw StateError ('Invalid compressed data (reference < 0)' );
242+ }
243+ if (ref >= outPtr) {
244+ throw StateError ('Invalid compressed data (reference >= outPtr)' );
221245 }
222246
223- ref -= inData[ inPtr ++ ];
224- if ( outPtr + len + 2 > outLength ) throw ( 'Output buffer is not large enough' );
225- if ( ref < 0 ) throw ( 'Invalid compressed data' );
226- if ( ref >= outPtr ) throw ( 'Invalid compressed data' );
227- do {
228- outData[ outPtr ++ ] = outData[ ref ++ ];
229- } while ( (-- len + 2 ) > - 0 );
247+ // Copy bytes from the existing output data (back reference)
248+ int count = copyLength;
249+ while (count-- > 0 ) {
250+ outData[outPtr++ ] = outData[ref++ ];
251+ }
230252 }
231- } while ( inPtr < inLength );
253+ }
254+
232255 return outData;
233256 }
234-
235- PCDHeader parseHeader ( binaryData ) {
257+ PCDHeader parseHeader (Uint8List binaryData ) {
236258 PCDHeader PCDheader = PCDHeader ();
237- final buffer = new Uint8Array . fromList ( binaryData ) ;
259+ final buffer = binaryData;
238260
239- String data = '' ;
240- String line = '' ;
241- int i = 0 ;
242- bool end = false ;
261+ String sData = '' ;
262+ String line = '' ;
263+ int i = 0 ;
264+ bool end = false ;
243265
244266 final max = buffer.length;
245267
246268 while ( i < max && end == false ) {
247- final char = String .fromCharCode ( buffer[ i ++ ] );
269+ final char = String .fromCharCode ( buffer[ i ++ ] );
248270
249271 if ( char == '\n ' || char == '\r ' ) {
250272 if ( line.trim ().toLowerCase ().startsWith ( 'data' ) ) {
@@ -253,26 +275,24 @@ class PCDLoader extends Loader {
253275
254276 line = '' ;
255277 }
256- else {
278+ else {
257279 line += char;
258280 }
259281
260- data += char;
282+ sData += char;
261283 }
262284
263- final result1 = data .indexOf (RegExp (r'[\r\n]DATA\s(\S*)\s' ,caseSensitive: false ,));//data.search( /[\r\n]DATA\s(\S*)\s/i );
264- final result2 = RegExp (r'[\r\n]DATA\s(\S*)\s' ,caseSensitive: false ).firstMatch (data .substring (result1 - 1 ))? . group ( 1 ) ;/// [\r\n] DATA\s(\S*)\s/i.exec( data.slice( result1 - 1 ) );
265- print (result2 );
285+ final result1 = sData .indexOf (RegExp (r'[\r\n]DATA\s(\S*)\s' ,caseSensitive: false ,));//data.search( /[\r\n]DATA\s(\S*)\s/i );
286+ final result = RegExp (r'[\r\n]DATA\s(\S*)\s' ,caseSensitive: false ).firstMatch (sData .substring (result1 - 1 ));//
287+ final result2 = result ? . group ( 1 ); /// [\r\n] DATA\s(\S*)\s/i.exec( data.slice( result1 - 1 ) );
266288 PCDheader .data = result2! ;
267- PCDheader .headerLen = result2 .length + result1;
268- PCDheader .str = data .substring (0 , PCDheader .headerLen); //.slice( 0, PCDheader.headerLen );
289+ PCDheader .headerLen = result ! . group ( 0 ) ! .length + result1;
290+ PCDheader .str = sData .substring (0 , PCDheader .headerLen);
269291
270292 // remove comments
271-
272293 PCDheader .str = PCDheader .str? .replaceAll (RegExp (r'#.*' , caseSensitive: false ), '' );
273294
274295 // parse
275-
276296 final version = RegExp (r'^VERSION (.*)' ,caseSensitive: false ,multiLine: true ).firstMatch ( PCDheader .str! );//^VERSION (.*)/im.exec( PCDheader.str );
277297 final fields = RegExp (r'^FIELDS (.*)' ,caseSensitive: false ,multiLine: true ).firstMatch ( PCDheader .str! );//^FIELDS (.*)/im.exec( PCDheader.str );
278298 final size = RegExp (r'^SIZE (.*)' ,caseSensitive: false ,multiLine: true ).firstMatch ( PCDheader .str! );//^SIZE (.*)/im.exec( PCDheader.str );
@@ -284,7 +304,6 @@ class PCDLoader extends Loader {
284304 final points = RegExp (r'^POINTS (.*)' ,caseSensitive: false ,multiLine: true ).firstMatch ( PCDheader .str! );//^POINTS (.*)/im.exec( PCDheader.str );
285305
286306 // evaluate
287-
288307 if (version != null )
289308 PCDheader .version = double .tryParse (version.group (1 ) ?? '' );
290309
@@ -319,7 +338,7 @@ class PCDLoader extends Loader {
319338 return int .parse ( x, radix: 10 );
320339 } ).toList () ?? [];
321340 }
322- else {
341+ else {
323342 PCDheader .count = [];
324343 for (int i = 0 , l = PCDheader .fields.length; i < l; i ++ ) {
325344 PCDheader .count.add ( 1 );
@@ -331,17 +350,16 @@ class PCDLoader extends Loader {
331350 int sizeSum = 0 ;
332351
333352 for (int i = 0 , l = PCDheader .fields.length; i < l; i ++ ) {
334-
335353 if ( PCDheader .data == 'ascii' ) {
336354 PCDheader .offset! [ PCDheader .fields[ i ] ] = i;
337- } else {
355+ }
356+ else {
338357 PCDheader .offset! [ PCDheader .fields[ i ] ] = sizeSum;
339358 sizeSum += PCDheader .size[ i ] * PCDheader .count[ i ];
340359 }
341360 }
342361
343362 // for binary only
344-
345363 PCDheader .rowSize = sizeSum;
346364
347365 print (PCDheader .toString ());
@@ -365,13 +383,12 @@ class PCDLoader extends Loader {
365383 // ascii
366384
367385 if ( PCDheader .data == 'ascii' ) {
368-
369386 final offset = PCDheader .offset! ;
370- final textData = utf8.decode (data);//new TextDecoder().decode( data );
371- final pcdData = textData.substring ( PCDheader .headerLen );
387+ final textData = utf8.decode (data);
388+ final pcdData = textData.substring ( PCDheader .headerLen);
372389 final lines = pcdData.split ( '\n ' );
373390
374- for (int i = 1 , l = lines.length; i < l; i ++ ) {
391+ for (int i = 0 , l = lines.length; i < l; i ++ ) {
375392 if ( lines[ i ] == '' ) continue ;
376393 final line = lines[ i ].split ( ' ' );
377394
@@ -406,11 +423,9 @@ class PCDLoader extends Loader {
406423 }
407424
408425 if ( offset['normal_x' ] != null ) {
409-
410426 normal.add ( double .parse ( line[ offset['normal_x' ] ] ) );
411427 normal.add ( double .parse ( line[ offset['normal_y' ] ] ) );
412428 normal.add ( double .parse ( line[ offset['normal_z' ] ] ) );
413-
414429 }
415430
416431 if ( offset['intensity' ] != null ) {
@@ -430,11 +445,13 @@ class PCDLoader extends Loader {
430445 // that requires a totally different parsing approach compared to non-compressed data
431446
432447 if ( PCDheader .data == 'binary_compressed' ) {
433- final sizes = new Uint32Array .fromList ( data.sublist ( PCDheader .headerLen, PCDheader .headerLen + 8 ) );
434- final compressedSize = sizes[ 0 ];
435- final decompressedSize = sizes[ 1 ];
436- final decompressed = decompressLZF ( Uint8Array .fromList ( data.sublist (PCDheader .headerLen + 8 , compressedSize)), decompressedSize );
437- final dataview = new ByteData .view ( decompressed.toDartList ().buffer );
448+ final sizes = data.sublist (PCDheader .headerLen, PCDheader .headerLen + 8 ).buffer.asUint32List ();
449+ final compressedSize = sizes[0 ];
450+ final decompressedSize = sizes[1 ];
451+
452+ final t = data.sublist (PCDheader .headerLen + 8 , compressedSize);
453+ final decompressed = decompressLZF (t, decompressedSize);
454+ final dataview = ByteData .view (decompressed.buffer);
438455
439456 final offset = PCDheader .offset ?? {};
440457
@@ -484,10 +501,10 @@ class PCDLoader extends Loader {
484501 // binary
485502
486503 if ( PCDheader .data == 'binary' ) {
487- final dataview = new ByteData .view ( Uint8List .fromList (data).buffer, PCDheader .headerLen );
504+ final dataview = ByteData .view ( Uint8List .fromList (data).buffer, PCDheader .headerLen);
488505 final offset = PCDheader .offset! ;
489506
490- for ( int i = 0 , row = 0 ; i < PCDheader .points; i ++ , row += PCDheader .rowSize ) {
507+ for ( int i = 0 , row = 0 ; i < PCDheader .points; i++ , row += PCDheader .rowSize ) {
491508 if ( offset['x' ] != null ) {
492509 final xIndex = PCDheader .fields.indexOf ( 'x' );
493510 final yIndex = PCDheader .fields.indexOf ( 'y' );
@@ -540,15 +557,13 @@ class PCDLoader extends Loader {
540557 geometry.computeBoundingSphere ();
541558
542559 // build material
543-
544560 final material = new PointsMaterial .fromMap ( { 'size' : 0.005 } );
545561
546562 if ( color.length > 0 ) {
547563 material.vertexColors = true ;
548564 }
549565
550566 // build point cloud
551-
552567 return new Points ( geometry, material );
553568 }
554569}
0 commit comments