add load_url to platform api which handles STL, OBJ, 3MF

This commit is contained in:
Stewart Allen 2021-09-03 17:58:02 -04:00
commit 7fb36b91a6
6 changed files with 123 additions and 8 deletions

View file

@ -6,7 +6,7 @@
if (self.moto.OBJ) return;
self.moto.TMF = {
parse : parse
parseAsync
};
function query(node, path, fn) {
@ -30,7 +30,6 @@
function loadModel(doc) {
let models = [];
function emitModel(model, faces) {
if (faces && faces.length) {
models.push({name: model, faces});
@ -82,7 +81,7 @@
* @param {Object} data binary file
* @returns {Array} vertex face array
*/
function parse(data) {
function parseAsync(data) {
return new Promise((resolve, reject) => {
JSZip.loadAsync(data).then(zip => {
for (let [key,value] of Object.entries(zip.files)) {

View file

@ -6,19 +6,27 @@
if (self.moto.OBJ) return;
self.moto.OBJ = {
parse : parse
parse,
parseAsync
};
/**
* @param {String} text
* @returns {Array} vertex face array
*/
function parseAsync(text) {
return new Promise((resolve,reject) => {
resolve(parse(text));
});
}
function parse(text) {
let lines = text.split('\n').map(l => l.trim());
let verts = [];
let faces = [];
let obj = [ faces ];
let objs = [ faces ];
for (let line of lines) {
let toks = line.split(' ');
@ -35,7 +43,7 @@
break;
case 'g':
if (faces.length) {
obj.push(faces = []);
objs.push(faces = []);
}
if (toks[0]) {
faces.name = toks[0];
@ -44,7 +52,7 @@
}
}
return obj;
return objs;
}
})();

View file

@ -107,6 +107,11 @@
return bin;
};
/**
* @param {ArrayBuffer} data
* @param {number} scale
* @returns vertex array
*/
SP.parse = function(data, scale) {
let binData = this.convertToBinary(data);
@ -124,6 +129,12 @@
: this.parseASCII(this.convertToString(data), scale);
};
SP.parseAsync = function(data, scale) {
return new Promise((resolve, reject) => {
resolve(this.parse(data, scale));
});
};
SP.parseBinary = function(data, scale = 1) {
let reader = new DataView(data),
faces = reader.getUint32 (80, true),

81
src/moto/load-url.js Normal file
View file

@ -0,0 +1,81 @@
'use strict';
(function() {
if (!self.moto) self.moto = {};
if (self.moto.URL) return;
const CDH = 'Content-Disposition';
function load(url, options = {}) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
let file = (((url.split('?')[0]).split('#')[0]).split('/')).pop();
let ext = file.split('.').pop().toLowerCase();
let deftype = ext === "obj" ? "text" : "arraybuffer";
let datatype = options.datatype || deftype;
let formdata = options.formdata;
function onloaded(event) {
if (event.target.status === 200 || event.target.status === 0) {
if (xhr.getAllResponseHeaders().indexOf(CDH) > 0) {
// attempt to extract filename from content disposition
let fname = xhr.getResponseHeader(CDH)
.split(';').map(v => v.trim()).filter(v => {
return v.indexOf('filename=') === 0;
}).map(v => {
return v.substring(10,v.length-1);
})[0];
if (fname) {
file = fname;
ext = file.split('.').pop().toLowerCase();
}
}
let data = event.target.response || event.target.responseText;
// return raw data if indicated
if (options.parse === false) {
return resolve(data, ext);
}
switch (ext) {
case "stl":
resolve([{
mesh: new moto.STL().parse(data), file
}]);
break;
case "obj":
resolve(moto.OBJ.parse(data).map(m => { return {mesh: m.toFloat32(), file} }));
break;
case "3mf":
moto.TMF.parseAsync(data).then((meshes) => {
resolve(meshes.map(m => {
return { mesh: m.faces.toFloat32(), file }
}));
});
break;
default:
reject(`unknown file type: "${ext}" from ${url}`);
break;
}
} else {
reject(event.target.statusText);
}
}
xhr.addEventListener('load', onloaded, false);
xhr.addEventListener('progress', function (event) { }, false);
xhr.addEventListener('error', function () { }, false);
if (xhr.overrideMimeType) {
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
xhr.open(formdata ? 'POST' : 'GET', url, true);
xhr.responseType = datatype;
xhr.send(formdata);
});
};
self.moto.URL = {
load
};
})();