|
// 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; |
|
|
|
})(); |