|
|
@@ -0,0 +1,187 @@ |
|
|
+// namespace
|
|
|
+var MeshesJS = MeshesJS || {};
|
|
|
+
|
|
|
+;(function() {
|
|
|
+
|
|
|
+ // Constructor
|
|
|
+ function STLLoader(dropTarget) {
|
|
|
+ this.dropTarget = dropTarget || null;
|
|
|
+ this.addDropListener();
|
|
|
+ }
|
|
|
+
|
|
|
+ // methods
|
|
|
+ STLLoader.prototype.onDragLeave = function(e) {
|
|
|
+ e.stopPropagation();
|
|
|
+ e.preventDefault();
|
|
|
+ }
|
|
|
+
|
|
|
+ STLLoader.prototype.onDrop = function(e) {
|
|
|
+ this.onDragLeave(e);
|
|
|
+ this.loadFile((e.target.files || e.dataTransfer.files)[0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ STLLoader.prototype.addDropListener = function(dropTarget) {
|
|
|
+ var dropTarget = dropTarget || this.dropTarget;
|
|
|
+ if (dropTarget) {
|
|
|
+ var self = this;
|
|
|
+ dropTarget.addEventListener('drop' , function(e) { self.onDrop(e); } , false);
|
|
|
+ dropTarget.addEventListener('dragover' , function(e) { self.onDragLeave(e); }, false);
|
|
|
+ dropTarget.addEventListener('dragleave', function(e) { self.onDragLeave(e); }, false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ STLLoader.prototype.removeDropListener = function(dropTarget) {
|
|
|
+ var dropTarget = dropTarget || this.dropTarget;
|
|
|
+ if (dropTarget) {
|
|
|
+ var self = this;
|
|
|
+ dropTarget.removeEventListener('drop' , function(e) { self.onDrop(e); } , false);
|
|
|
+ dropTarget.removeEventListener('dragover' , function(e) { self.onDragLeave(e); }, false);
|
|
|
+ dropTarget.removeEventListener('dragleave', function(e) { self.onDragLeave(e); }, false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ STLLoader.prototype.onGeometry = function(geometry) {};
|
|
|
+ STLLoader.prototype.onError = function(error) {};
|
|
|
+
|
|
|
+ STLLoader.prototype.loadFile = function(file) {
|
|
|
+ // self alias
|
|
|
+ var self = this;
|
|
|
+
|
|
|
+ // file reader instance
|
|
|
+ var reader = new FileReader();
|
|
|
+
|
|
|
+ // on file loaded
|
|
|
+ reader.onloadend = function(event) {
|
|
|
+ // if error/abort
|
|
|
+ if (this.error) {
|
|
|
+ self.onError(this.error);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Parse ASCII STL
|
|
|
+ if (typeof this.result === 'string' ) {
|
|
|
+ self.loadString(this.result);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // buffer reader
|
|
|
+ var view = new DataView(this.result);
|
|
|
+
|
|
|
+ // get faces number
|
|
|
+ try {
|
|
|
+ var faces = view.getUint32(80, true);
|
|
|
+ }
|
|
|
+ catch(error) {
|
|
|
+ self.onError(error);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // is binary ?
|
|
|
+ var binary = view.byteLength == (80 + 4 + 50 * faces);
|
|
|
+
|
|
|
+ if (! binary) {
|
|
|
+ // get the file contents as string
|
|
|
+ // (faster than convert array buffer)
|
|
|
+ reader.readAsText(file);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // parse binary STL
|
|
|
+ self.loadBinaryData(view, faces);
|
|
|
+ };
|
|
|
+
|
|
|
+ // start reading file as array buffer
|
|
|
+ reader.readAsArrayBuffer(file);
|
|
|
+ };
|
|
|
+
|
|
|
+ STLLoader.prototype.loadString = function(data) {
|
|
|
+ var length, normal, patternNormal, patternVertex, result, text;
|
|
|
+ var geometry = new THREE.Geometry();
|
|
|
+ var patternFace = /facet([\s\S]*?)endfacet/g;
|
|
|
+
|
|
|
+ while((result = patternFace.exec(data)) !== null) {
|
|
|
+ text = result[0];
|
|
|
+
|
|
|
+ patternNormal = /normal[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;
|
|
|
+ patternVertex = /vertex[\s]+([\-+]?[0-9]+\.?[0-9]*([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+[\s]+([\-+]?[0-9]*\.?[0-9]+([eE][\-+]?[0-9]+)?)+/g;
|
|
|
+
|
|
|
+ while((result = patternNormal.exec(text)) !== null) {
|
|
|
+ normal = new THREE.Vector3(
|
|
|
+ parseFloat(result[1]),
|
|
|
+ parseFloat(result[3]),
|
|
|
+ parseFloat(result[5])
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ while((result = patternVertex.exec(text)) !== null) {
|
|
|
+ geometry.vertices.push(new THREE.Vector3(
|
|
|
+ parseFloat(result[1]),
|
|
|
+ parseFloat(result[3]),
|
|
|
+ parseFloat(result[5])
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ length = geometry.vertices.length;
|
|
|
+
|
|
|
+ geometry.faces.push(new THREE.Face3(length-3, length-2, length-1, normal));
|
|
|
+ }
|
|
|
+
|
|
|
+ geometry.computeBoundingBox();
|
|
|
+ geometry.computeBoundingSphere();
|
|
|
+
|
|
|
+ this.onGeometry(geometry);
|
|
|
+ };
|
|
|
+
|
|
|
+ STLLoader.prototype.loadBinaryData = function(view, faces) {
|
|
|
+ if (! view instanceof DataView) {
|
|
|
+ var view = new DataView(view);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (! faces) {
|
|
|
+ try {
|
|
|
+ var faces = view.getUint32(80, true);
|
|
|
+ }
|
|
|
+ catch(error) {
|
|
|
+ this.onError(error);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var dataOffset = 84;
|
|
|
+ var faceLength = 12 * 4 + 2;
|
|
|
+ var offset = 0;
|
|
|
+ var geometry = new THREE.BufferGeometry();
|
|
|
+ var vertices = new Float32Array( faces * 3 * 3 );
|
|
|
+ var normals = new Float32Array( faces * 3 * 3 );
|
|
|
+
|
|
|
+ for ( var face = 0; face < faces; face ++ ) {
|
|
|
+ var start = dataOffset + face * faceLength;
|
|
|
+ var normalX = view.getFloat32( start, true );
|
|
|
+ var normalY = view.getFloat32( start + 4, true );
|
|
|
+ var normalZ = view.getFloat32( start + 8, true );
|
|
|
+
|
|
|
+ for (var i = 1; i <= 3; i ++) {
|
|
|
+ var vertexstart = start + i * 12;
|
|
|
+
|
|
|
+ normals[ offset ] = normalX;
|
|
|
+ normals[ offset + 1 ] = normalY;
|
|
|
+ normals[ offset + 2 ] = normalZ;
|
|
|
+
|
|
|
+ vertices[ offset ] = view.getFloat32( vertexstart, true );
|
|
|
+ vertices[ offset + 1 ] = view.getFloat32( vertexstart + 4, true );
|
|
|
+ vertices[ offset + 2 ] = view.getFloat32( vertexstart + 8, true );
|
|
|
+
|
|
|
+ offset += 3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
|
|
|
+ geometry.addAttribute('normal', new THREE.BufferAttribute(normals, 3));
|
|
|
+
|
|
|
+ this.onGeometry(geometry);
|
|
|
+ };
|
|
|
+
|
|
|
+ // export module
|
|
|
+ MeshesJS.STLLoader = STLLoader;
|
|
|
+
|
|
|
+})();
|
0 comments on commit
49eab4c