|
|
Line 1: |
Line 1: |
| __NOTOC__ | | __NOTOC__ |
- | {{Team:Aachen/Header}} | + | {{Team:Aachen/HeaderEngineering}} |
| <html> | | <html> |
- | <script type="text/javascript" src="https://2014.igem.org/Template:Team:Aachen/three.js?action=raw&ctype=text/javascript"></script>
| + | |
- | <script type="text/javascript" src="https://2014.igem.org/Template:Team:Aachen/stats.js?action=raw&ctype=text/javascript"></script>
| + | |
- | <script type="text/javascript" src="https://2014.igem.org/Template:Team:Aachen/detector.js?action=raw&ctype=text/javascript"></script>
| + | |
- | </html>
| + | |
- | <html>
| + | |
- | <script> | + | |
- | | + | |
- | 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 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(xhr.responseText);
| + | |
- | 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', 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 );
| + | |
- | | + | |
- | }
| + | |
- | | + | |
- | </script>
| + | |
| </html> | | </html> |
| | | |
| {{Team:Aachen/Footer}} | | {{Team:Aachen/Footer}} |