diff --git a/web/app/3d/io.js b/web/app/3d/io.js new file mode 100644 index 00000000..55d7e3a1 --- /dev/null +++ b/web/app/3d/io.js @@ -0,0 +1,23 @@ +import {ParseStl} from './stl/stl-reader' + +export function LoadSTLFromURL(url, solidsConsumer) { + const xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function(){ + if (this.readyState == 4){ + //console.log(this.response, typeof this.response); + if (this.status == 200) { + const reader = new FileReader(); + reader.addEventListener("loadend", () => { + let solids = ParseStl(reader.result); + solidsConsumer(solids) + }); + reader.readAsArrayBuffer(this.response); + } else { + solidsConsumer(null, this.status); + } + } + }; + xhr.open('GET', url); + xhr.responseType = 'blob'; + xhr.send(); +} \ No newline at end of file diff --git a/web/app/3d/stl/stl-ascii-reader.js b/web/app/3d/stl/stl-ascii-reader.js index c040b1a1..2cc242b7 100644 --- a/web/app/3d/stl/stl-ascii-reader.js +++ b/web/app/3d/stl/stl-ascii-reader.js @@ -1,15 +1,15 @@ +import {StlSolid, StlFace} from './stl-data-structure' + export function parse(buf) { - var solid = { - name: null, - faces: [] - }; - var solids = []; - var triangle = []; - var normal = null; - var reader = new LinesReader(buf); + let solid = new StlSolid(''); + let face = new StlFace(null); + let solids = []; + let reader = new LinesReader(buf); + let lineNumber = 0; while (reader.hasNextLine()) { - let line = reader.nextLine(); + let line = reader.nextLine(); + lineNumber ++; var parts = line .trim() .split(' ') @@ -18,10 +18,7 @@ export function parse(buf) { }); switch(parts[0]) { case 'solid': - solid = { - name: parts.slice(1).join(' '), - faces: [] - }; + solid = new StlSolid(parts.slice(1).join(' ')); break; case 'endsolid': solids.push(solid); @@ -29,22 +26,22 @@ export function parse(buf) { case 'facet': var noramlParts = parts.slice(2); if (noramlParts.length == 3) { - normal = noramlParts.map(Number); + face.normal = noramlParts.map(Number); + } else { + console.warn('bad normal definition at line ' + lineNumber); } break; case 'vertex': - var position = parts.slice(1).map(Number); - triangle.push(position); + const position = parts.slice(1).map(Number); + face.vertices.push(position); break; case 'endfacet': - if (triangle.length == 3) { - solid.faces.push({ - vertices: triangle, - normal: normal - }); + if (face.normal != null && face.vertices.length == 3) { + solid.faces.push(face); + } else { + console.warn('bad stl face at line ' + lineNumber); } - triangle = []; - normal = null; + face = new StlFace(null); default: // skip } diff --git a/web/app/3d/stl/stl-data-structure.js b/web/app/3d/stl/stl-data-structure.js new file mode 100644 index 00000000..60b804a9 --- /dev/null +++ b/web/app/3d/stl/stl-data-structure.js @@ -0,0 +1,9 @@ +export function StlSolid(name) { + this.name = name; + this.faces = []; +} + +export function StlFace(normal) { + this.normal = normal; + this.vertices = []; +} \ No newline at end of file diff --git a/web/app/3d/stl/stl-reader.js b/web/app/3d/stl/stl-reader.js index 5ba78543..c406e086 100644 --- a/web/app/3d/stl/stl-reader.js +++ b/web/app/3d/stl/stl-reader.js @@ -5,13 +5,18 @@ export function ParseStl(buf) { if(typeof buf === 'string') { return ParseASCII(buf); } + + // The other way is to check if file starts with 'solid' then it's ascii + // WIKI: A binary STL file has an 80-character header (which is generally ignored, but should never begin with "solid" + // because that will lead most software to assume that this is an ASCII STL file - //var triangleCount = buf.readUInt32LE(80); - //var expectedSize = 80 + 4 + triangleCount * ((4 * 3) * 4 + 2); - // - //if(expectedSize === buf.length) { - // return parseBinary(buf); - //} + const dataView = new DataView(buf); + const triangleCount = dataView.getUint32(80, true); + const expectedSize = 80 + 4 + triangleCount * ((4 * 3) * 4 + 2); + + if(expectedSize === buf.byteLength) { + return [ParseBinary(dataView)]; + } return ParseASCII(buf); }