Template:Team:Aachen/showCuvetteStl.js

From 2014.igem.org

Revision as of 20:07, 22 August 2014 by Mjoppich (Talk | contribs)
           var camera, scene, renderer,
           geometry, material, mesh, light1, stats;
           function trim (str) {
               str = str.replace(/^\s+/, );
               for (var i = str.length - 1; i >= 0; i--) {
                   if (/\S/.test(str.charAt(i))) {
                       str = str.substring(0, i + 1);
                       break;
                   }
               }
               return str;
           }
           // Notes:
           // - STL file format: http://en.wikipedia.org/wiki/STL_(file_format)
           // - 80 byte unused header
           // - All binary STLs are assumed to be little endian, as per wiki doc
           var parseStlBinary = function(stl) {
               var geo = new THREE.Geometry();
               var dv = new DataView(stl, 80); // 80 == unused header
               var isLittleEndian = true;
               var triangles = dv.getUint32(0, isLittleEndian); 
               // console.log('arraybuffer length:  ' + stl.byteLength);
               // console.log('number of triangles: ' + triangles);
               var offset = 4;
               for (var i = 0; i < triangles; i++) {
                   // Get the normal for this triangle
                   var normal = new THREE.Vector3(
                       dv.getFloat32(offset, isLittleEndian),
                       dv.getFloat32(offset+4, isLittleEndian),
                       dv.getFloat32(offset+8, isLittleEndian)
                   );
                   offset += 12;
                   // Get all 3 vertices for this triangle
                   for (var j = 0; j < 3; j++) {
                       geo.vertices.push(
                           new THREE.Vector3(
                               dv.getFloat32(offset, isLittleEndian),
                               dv.getFloat32(offset+4, isLittleEndian),
                               dv.getFloat32(offset+8, isLittleEndian)
                           )
                       );
                       offset += 12
                   }
                   // there's also a Uint16 "attribute byte count" that we
                   // don't need, it should always be zero.
                   offset += 2;   
                   // Create a new face for from the vertices and the normal             
                   geo.faces.push(new THREE.Face3(i*3, i*3+1, i*3+2, normal));
               }
               // The binary STL I'm testing with seems to have all
               // zeroes for the normals, unlike its ASCII counterpart.
               // We can use three.js to compute the normals for us, though,
               // once we've assembled our geometry. This is a relatively 
               // expensive operation, but only needs to be done once.
               geo.computeFaceNormals();
               mesh = new THREE.Mesh( 
                   geo,
                   // new THREE.MeshNormalMaterial({
                   //     overdraw:true
                   // }
                   new THREE.MeshLambertMaterial({
                       overdraw:true,
                       color: 0xaa0000,
                       shading: THREE.FlatShading
                   }
               ));
               scene.add(mesh);
               stl = null;
           };  
           var parseStl = function(stl) {
               var state = ;
               var lines = stl.split('\n');
               var geo = new THREE.Geometry();
               var name, parts, line, normal, done, vertices = [];
               var vCount = 0;
               stl = null;
               for (var len = lines.length, i = 0; i < len; i++) {
                   if (done) {
                       break;
                   }
                   line = trim(lines[i]);
                   parts = line.split(' ');
                   switch (state) {
                       case :
                           if (parts[0] !== 'solid') {
                               console.error(line);
                               console.error('Invalid state "' + parts[0] + '", should be "solid"');
                               return;
                           } else {
                               name = parts[1];
                               state = 'solid';
                           }
                           break;
                       case 'solid':
                           if (parts[0] !== 'facet' || parts[1] !== 'normal') {
                               console.error(line);
                               console.error('Invalid state "' + parts[0] + '", should be "facet normal"');
                               return;
                           } else {
                               normal = [
                                   parseFloat(parts[2]), 
                                   parseFloat(parts[3]), 
                                   parseFloat(parts[4])
                               ];
                               state = 'facet normal';
                           }
                           break;
                       case 'facet normal':
                           if (parts[0] !== 'outer' || parts[1] !== 'loop') {
                               console.error(line);
                               console.error('Invalid state "' + parts[0] + '", should be "outer loop"');
                               return;
                           } else {
                               state = 'vertex';
                           }
                           break;
                       case 'vertex': 
                           if (parts[0] === 'vertex') {
                               geo.vertices.push(new THREE.Vector3(
                                   parseFloat(parts[1]),
                                   parseFloat(parts[2]),
                                   parseFloat(parts[3])
                               ));
                           } else if (parts[0] === 'endloop') {
                               geo.faces.push( new THREE.Face3( vCount*3, vCount*3+1, vCount*3+2, new THREE.Vector3(normal[0], normal[1], normal[2]) ) );
                               vCount++;
                               state = 'endloop';
                           } else {
                               console.error(line);
                               console.error('Invalid state "' + parts[0] + '", should be "vertex" or "endloop"');
                               return;
                           }
                           break;
                       case 'endloop':
                           if (parts[0] !== 'endfacet') {
                               console.error(line);
                               console.error('Invalid state "' + parts[0] + '", should be "endfacet"');
                               return;
                           } else {
                               state = 'endfacet';
                           }
                           break;
                       case 'endfacet':
                           if (parts[0] === 'endsolid') {
                               //mesh = new THREE.Mesh( geo, new THREE.MeshNormalMaterial({overdraw:true}));
                               mesh = new THREE.Mesh( 
                                   geo, 
                                   new THREE.MeshLambertMaterial({
                                       overdraw:true,
                                       color: 0xaa0000,
                                       shading: THREE.FlatShading
                                   }
                               ));
                               scene.add(mesh);
                               done = true;
                           } else if (parts[0] === 'facet' && parts[1] === 'normal') {
                               normal = [
                                   parseFloat(parts[2]), 
                                   parseFloat(parts[3]), 
                                   parseFloat(parts[4])
                               ];
                               if (vCount % 1000 === 0) {
                                   console.log(normal);
                               }
                               state = 'facet normal';
                           } else {
                               console.error(line);
                               console.error('Invalid state "' + parts[0] + '", should be "endsolid" or "facet normal"');
                               return;
                           }
                           break;
                       default:
                           console.error('Invalid state "' + state + '"');
                           break;
                   }
               }
           };


           init();
           animate();

function arrayBufferToString(buffer) {

   var bufView = new Uint8Array(buffer);
   var length = bufView.length;
   var result = ;
   for(var i = 0;i<length;i+=65535)
   {
       var addition = 65535;
       if(i + 65535 > length)
       {
           addition = length - i;
       }
       result += String.fromCharCode.apply(null, bufView.subarray(i,i+addition));
   }

return result; }

           function init() {
               //Detector.addGetWebGLMessage();
               scene = new THREE.Scene();
               camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
               camera.position.z = 70;
               camera.position.y = 0;
               scene.add( camera );
               var directionalLight = new THREE.DirectionalLight( 0xffffff );
               directionalLight.position.x = 0; 
               directionalLight.position.y = 0; 
               directionalLight.position.z = 1; 
               directionalLight.position.normalize();
               scene.add( directionalLight );
               var xhr = new XMLHttpRequest();
               xhr.onreadystatechange = function () {
                   if ( xhr.readyState == 4 ) {
                       if ( xhr.status == 200 || xhr.status == 0 ) {
                           var rep = xhr.response; // || xhr.mozResponseArrayBuffer;
                           console.log(rep);
                           //parseStlBinary(rep);
                           parseStl(arrayBufferToString(rep));
                           mesh.rotation.x = 5;
                           mesh.rotation.z = .25;
                           console.log('done parsing');
                       }
                   }
               }
               xhr.onerror = function(e) {
                   console.log(e);
               }
               
               xhr.open( "GET", 'http://2014.igem.org/Template:Team:Aachen/cuvette.stl?action=raw&ctype=text/plain', true );
               xhr.responseType = "arraybuffer";
               //xhr.setRequestHeader("Accept","text/plain");
               //xhr.setRequestHeader("Content-Type","text/plain");
               //xhr.setRequestHeader('charset', 'x-user-defined');
               xhr.send( null );
               renderer = new THREE.WebGLRenderer(); //new THREE.CanvasRenderer();
               renderer.setSize( window.innerWidth, window.innerHeight );
               document.body.appendChild( renderer.domElement );
               stats = new Stats();
               stats.domElement.style.position = 'absolute';
               stats.domElement.style.top = '0px';
               document.body.appendChild(stats.domElement);
           }
           function animate() {
               // note: three.js includes requestAnimationFrame shim
               requestAnimationFrame( animate );
               render();
               stats.update();
           }
           function render() {
               //mesh.rotation.x += 0.01;
               if (mesh) {
                   mesh.rotation.z += 0.02;
               }
               //light1.position.z -= 1;
               renderer.render( scene, camera );
           }