Template:Team:Aachen/showCuvetteStl.js
From 2014.igem.org
(Difference between revisions)
(9 intermediate revisions not shown) | |||
Line 166: | Line 166: | ||
scene.add(mesh); | scene.add(mesh); | ||
done = true; | done = true; | ||
- | } else if | + | } else if (parts[0] === 'facet' && parts[1] === 'normal') { |
normal = [ | normal = [ | ||
parseFloat(parts[2]), | parseFloat(parts[2]), | ||
Line 193: | Line 193: | ||
init(); | init(); | ||
animate(); | 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() { | function init() { | ||
Line 218: | Line 236: | ||
var rep = xhr.response; // || xhr.mozResponseArrayBuffer; | var rep = xhr.response; // || xhr.mozResponseArrayBuffer; | ||
console.log(rep); | console.log(rep); | ||
- | parseStlBinary(rep); | + | //parseStlBinary(rep); |
- | + | parseStl(arrayBufferToString(rep)); | |
mesh.rotation.x = 5; | mesh.rotation.x = 5; | ||
mesh.rotation.z = .25; | mesh.rotation.z = .25; | ||
Line 230: | Line 248: | ||
} | } | ||
- | xhr.open( "GET", 'https://2014.igem.org/Template:Team:Aachen/cuvette.stl?action=raw& | + | xhr.open( "GET", 'https://2014.igem.org/Template:Team:Aachen/cuvette.stl?action=raw&ctype=text/plain', true ); |
+ | |||
xhr.responseType = "arraybuffer"; | xhr.responseType = "arraybuffer"; | ||
//xhr.setRequestHeader("Accept","text/plain"); | //xhr.setRequestHeader("Accept","text/plain"); | ||
Line 242: | Line 261: | ||
document.body.appendChild( renderer.domElement ); | document.body.appendChild( renderer.domElement ); | ||
- | stats = new Stats(); | + | //stats = new Stats(); |
- | stats.domElement.style.position = 'absolute'; | + | //stats.domElement.style.position = 'absolute'; |
- | stats.domElement.style.top = '0px'; | + | //stats.domElement.style.top = '0px'; |
- | document.body.appendChild(stats.domElement); | + | //document.body.appendChild(stats.domElement); |
} | } | ||
Line 253: | Line 272: | ||
requestAnimationFrame( animate ); | requestAnimationFrame( animate ); | ||
render(); | render(); | ||
- | stats.update(); | + | //stats.update(); |
} | } | ||
+ | |||
+ | delta_rot = 0.02; | ||
function render() { | function render() { | ||
Line 262: | Line 283: | ||
if (mesh) { | if (mesh) { | ||
mesh.rotation.z += 0.02; | mesh.rotation.z += 0.02; | ||
+ | mesh.rotation.x += delta_rot; | ||
+ | |||
+ | if (mesh.rotation.x > 6.5) | ||
+ | { | ||
+ | delta_rot = -0.02; | ||
+ | } | ||
+ | |||
+ | if (mesh.rotation.x < 3.5) | ||
+ | { | ||
+ | delta_rot = 0.02; | ||
+ | } | ||
+ | |||
+ | |||
} | } | ||
//light1.position.z -= 1; | //light1.position.z -= 1; |
Latest revision as of 22:47, 20 September 2014
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", 'https://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();
}
delta_rot = 0.02;
function render() {
//mesh.rotation.x += 0.01; if (mesh) { mesh.rotation.z += 0.02; mesh.rotation.x += delta_rot;
if (mesh.rotation.x > 6.5) { delta_rot = -0.02; }
if (mesh.rotation.x < 3.5) { delta_rot = 0.02; }
} //light1.position.z -= 1;
renderer.render( scene, camera );
}