PCDLoader.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /**
  2. * @author Filipe Caixeta / http://filipecaixeta.com.br
  3. *
  4. * Description: A THREE loader for PCD ascii and binary files.
  5. *
  6. * Limitations: Compressed binary files are not supported.
  7. *
  8. */
  9. THREE.PCDLoader = function( manager ) {
  10. this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
  11. this.littleEndian = true;
  12. };
  13. Object.assign( THREE.PCDLoader.prototype, THREE.EventDispatcher.prototype, {
  14. load: function( url, onLoad, onProgress, onError ) {
  15. var scope = this;
  16. var loader = new THREE.FileLoader( scope.manager );
  17. loader.setResponseType( 'arraybuffer' );
  18. loader.load( url, function( data ) {
  19. onLoad( scope.parse( data, url ) );
  20. }, onProgress, onError );
  21. },
  22. binarryToStr: function( data ) {
  23. var text = "";
  24. var charArray = new Uint8Array( data );
  25. for ( var i = 0; i < data.byteLength; i ++ ) {
  26. text += String.fromCharCode( charArray[ i ] );
  27. }
  28. return text;
  29. },
  30. parseHeader: function( data ) {
  31. var PCDheader = {};
  32. var result1 = data.search( /[\r\n]DATA\s(\S*)\s/i );
  33. var result2 = /[\r\n]DATA\s(\S*)\s/i.exec( data.substr( result1 - 1 ) );
  34. PCDheader.data = result2[ 1 ];
  35. PCDheader.headerLen = result2[ 0 ].length + result1;
  36. PCDheader.str = data.substr( 0, PCDheader.headerLen );
  37. // Remove comments
  38. PCDheader.str = PCDheader.str.replace( /\#.*/gi, "" );
  39. PCDheader.version = /VERSION (.*)/i.exec( PCDheader.str );
  40. if ( PCDheader.version != null )
  41. PCDheader.version = parseFloat( PCDheader.version[ 1 ] );
  42. PCDheader.fields = /FIELDS (.*)/i.exec( PCDheader.str );
  43. if ( PCDheader.fields != null )
  44. PCDheader.fields = PCDheader.fields[ 1 ].split( " " );
  45. PCDheader.size = /SIZE (.*)/i.exec( PCDheader.str );
  46. if ( PCDheader.size != null )
  47. PCDheader.size = PCDheader.size[ 1 ].split( " " ).map( function( x ) {
  48. return parseInt( x, 10 );
  49. } );
  50. PCDheader.type = /TYPE (.*)/i.exec( PCDheader.str );
  51. if ( PCDheader.type != null )
  52. PCDheader.type = PCDheader.type[ 1 ].split( " " );
  53. PCDheader.count = /COUNT (.*)/i.exec( PCDheader.str );
  54. if ( PCDheader.count != null )
  55. PCDheader.count = PCDheader.count[ 1 ].split( " " ).map( function( x ) {
  56. return parseInt( x, 10 );
  57. } );
  58. PCDheader.width = /WIDTH (.*)/i.exec( PCDheader.str );
  59. if ( PCDheader.width != null )
  60. PCDheader.width = parseInt( PCDheader.width[ 1 ] );
  61. PCDheader.height = /HEIGHT (.*)/i.exec( PCDheader.str );
  62. if ( PCDheader.height != null )
  63. PCDheader.height = parseInt( PCDheader.height[ 1 ] );
  64. PCDheader.viewpoint = /VIEWPOINT (.*)/i.exec( PCDheader.str );
  65. if ( PCDheader.viewpoint != null )
  66. PCDheader.viewpoint = PCDheader.viewpoint[ 1 ];
  67. PCDheader.points = /POINTS (.*)/i.exec( PCDheader.str );
  68. if ( PCDheader.points != null )
  69. PCDheader.points = parseInt( PCDheader.points[ 1 ], 10 );
  70. if ( PCDheader.points == null )
  71. PCDheader.points = PCDheader.width * PCDheader.height;
  72. if ( PCDheader.count == null ) {
  73. PCDheader.count = [];
  74. for ( var i = 0; i < PCDheader.fields; i ++ )
  75. PCDheader.count.push( 1 );
  76. }
  77. PCDheader.offset = {};
  78. var sizeSum = 0;
  79. for ( var i = 0; i < PCDheader.fields.length; i ++ ) {
  80. if ( PCDheader.data == "ascii" ) {
  81. PCDheader.offset[ PCDheader.fields[ i ]] = i;
  82. } else {
  83. PCDheader.offset[ PCDheader.fields[ i ]] = sizeSum;
  84. sizeSum += PCDheader.size[ i ];
  85. }
  86. }
  87. // For binary only
  88. PCDheader.rowSize = sizeSum;
  89. return PCDheader;
  90. },
  91. parse: function( data, url ) {
  92. var textData = this.binarryToStr( data );
  93. // Parse the header
  94. // Header is always ascii format
  95. var PCDheader = this.parseHeader( textData );
  96. // Parse the data
  97. var position = false;
  98. if ( PCDheader.offset.x != undefined )
  99. position = new Float32Array( PCDheader.points * 3 );
  100. var color = false;
  101. if ( PCDheader.offset.rgb != undefined)
  102. color = new Float32Array( PCDheader.points * 3 );
  103. var normal = false;
  104. if ( PCDheader.offset.normal_x != undefined )
  105. normal = new Float32Array( PCDheader.points * 3 );
  106. if ( PCDheader.data == "ascii" ) {
  107. var offset = PCDheader.offset;
  108. var pcdData = textData.substr( PCDheader.headerLen );
  109. var lines = pcdData.split( '\n' );
  110. var i3 = 0;
  111. for ( var i = 0; i < lines.length; i ++, i3 += 3 ) {
  112. var line = lines[ i ].split( " " );
  113. if ( offset.x != undefined ) {
  114. position[ i3 + 0 ] = parseFloat( line[ offset.x ] );
  115. position[ i3 + 1 ] = parseFloat( line[ offset.y ] );
  116. position[ i3 + 2 ] = parseFloat( line[ offset.z ] );
  117. }
  118. if ( offset.rgb != undefined ) {
  119. var c = new Float32Array([parseFloat( line[ offset.rgb ] )]);
  120. var dataview = new DataView( c.buffer, 0 );
  121. color[ i3 + 0 ] = dataview.getUint8(0)/255.0;
  122. color[ i3 + 1 ] = dataview.getUint8(1)/255.0;
  123. color[ i3 + 2 ] = dataview.getUint8(2)/255.0;
  124. }
  125. if ( offset.normal_x != undefined ) {
  126. normal[ i3 + 0 ] = parseFloat( line[ offset.normal_x ] );
  127. normal[ i3 + 1 ] = parseFloat( line[ offset.normal_y ] );
  128. normal[ i3 + 2 ] = parseFloat( line[ offset.normal_z ] );
  129. }
  130. }
  131. }
  132. if ( PCDheader.data == "binary_compressed" ) {
  133. console.error( 'THREE.PCDLoader: binary_compressed files are not supported' );
  134. return;
  135. }
  136. if ( PCDheader.data == "binary" ) {
  137. var row = 0;
  138. var dataview = new DataView( data, PCDheader.headerLen );
  139. var i = 0;
  140. var offset = PCDheader.offset;
  141. for ( var i3 = 0; i < PCDheader.points; i3 += 3, row += PCDheader.rowSize, i ++ ) {
  142. if ( offset.x != undefined ) {
  143. position[ i3 + 0 ] = dataview.getFloat32( row + offset.x, this.littleEndian );
  144. position[ i3 + 1 ] = dataview.getFloat32( row + offset.y, this.littleEndian );
  145. position[ i3 + 2 ] = dataview.getFloat32( row + offset.z, this.littleEndian );
  146. }
  147. if ( offset.rgb != undefined ) {
  148. color[ i3 + 0 ] = dataview.getUint8( row + offset.rgb + 0 ) / 255.0;
  149. color[ i3 + 1 ] = dataview.getUint8( row + offset.rgb + 1 ) / 255.0;
  150. color[ i3 + 2 ] = dataview.getUint8( row + offset.rgb + 2 ) / 255.0;
  151. }
  152. if ( offset.normal_x != undefined ) {
  153. normal[ i3 + 0 ] = dataview.getFloat32( row + offset.normal_x, this.littleEndian );
  154. normal[ i3 + 1 ] = dataview.getFloat32( row + offset.normal_y, this.littleEndian );
  155. normal[ i3 + 2 ] = dataview.getFloat32( row + offset.normal_z, this.littleEndian );
  156. }
  157. }
  158. }
  159. var geometry = new THREE.BufferGeometry();
  160. if ( position != false )
  161. geometry.addAttribute( 'position', new THREE.BufferAttribute( position, 3 ) );
  162. if ( color != false )
  163. geometry.addAttribute( 'color', new THREE.BufferAttribute( color, 3 ) );
  164. if ( normal != false )
  165. geometry.addAttribute( 'normal', new THREE.BufferAttribute( normal, 3 ) );
  166. geometry.computeBoundingSphere();
  167. var material = new THREE.PointsMaterial( { size: 0.005,
  168. vertexColors: !(color == false) } );
  169. if ( color == false )
  170. material.color.setHex( Math.random() * 0xffffff );
  171. var mesh = new THREE.Points( geometry, material );
  172. var name = url.split( '' ).reverse().join( '' );
  173. name = /([^\/]*)/.exec( name );
  174. name = name[ 1 ].split( '' ).reverse().join( '' );
  175. mesh.name = name;
  176. mesh.PCDheader = PCDheader;
  177. return mesh;
  178. },
  179. } );