add load_url to platform api which handles STL, OBJ, 3MF
This commit is contained in:
parent
655b92e2a0
commit
7fb36b91a6
6 changed files with 123 additions and 8 deletions
1
app.js
1
app.js
|
|
@ -248,6 +248,7 @@ const script = {
|
||||||
"moto/load-3mf",
|
"moto/load-3mf",
|
||||||
"moto/load-obj",
|
"moto/load-obj",
|
||||||
"moto/load-stl",
|
"moto/load-stl",
|
||||||
|
"moto/load-url",
|
||||||
"moto/db",
|
"moto/db",
|
||||||
"kiri/ui",
|
"kiri/ui",
|
||||||
"kiri/lang",
|
"kiri/lang",
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
layout: platformLayout,
|
layout: platformLayout,
|
||||||
load: platformLoad,
|
load: platformLoad,
|
||||||
load_stl: platformLoadSTL,
|
load_stl: platformLoadSTL,
|
||||||
|
load_url: platformLoadURL,
|
||||||
deselect: platformDeselect,
|
deselect: platformDeselect,
|
||||||
select: platformSelect,
|
select: platformSelect,
|
||||||
select_all: platformSelectAll,
|
select_all: platformSelectAll,
|
||||||
|
|
@ -1874,6 +1875,20 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
}, formdata, scale);
|
}, formdata, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function platformLoadURL(url, group) {
|
||||||
|
platform.group();
|
||||||
|
MOTO.URL.load(url).then((objects) => {
|
||||||
|
for (let object of objects) {
|
||||||
|
let widget = newWidget(undefined, group).loadVertices(object.mesh);
|
||||||
|
widget.meta.file = object.file;
|
||||||
|
platform.add(widget);
|
||||||
|
}
|
||||||
|
platform.group_done();
|
||||||
|
}).catch(error => {
|
||||||
|
API.show.alert(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function platformComputeMaxZ() {
|
function platformComputeMaxZ() {
|
||||||
topZ = 0;
|
topZ = 0;
|
||||||
forAllWidgets(function(widget) {
|
forAllWidgets(function(widget) {
|
||||||
|
|
@ -2501,7 +2516,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is3mf) {
|
else if (is3mf) {
|
||||||
MOTO.TMF.parse(e.target.result).then(models => {
|
MOTO.TMF.parseAsync(e.target.result).then(models => {
|
||||||
console.log({models});
|
console.log({models});
|
||||||
for (let model of models) {
|
for (let model of models) {
|
||||||
let name = e.target.file.name;
|
let name = e.target.file.name;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
if (self.moto.OBJ) return;
|
if (self.moto.OBJ) return;
|
||||||
|
|
||||||
self.moto.TMF = {
|
self.moto.TMF = {
|
||||||
parse : parse
|
parseAsync
|
||||||
};
|
};
|
||||||
|
|
||||||
function query(node, path, fn) {
|
function query(node, path, fn) {
|
||||||
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
function loadModel(doc) {
|
function loadModel(doc) {
|
||||||
let models = [];
|
let models = [];
|
||||||
|
|
||||||
function emitModel(model, faces) {
|
function emitModel(model, faces) {
|
||||||
if (faces && faces.length) {
|
if (faces && faces.length) {
|
||||||
models.push({name: model, faces});
|
models.push({name: model, faces});
|
||||||
|
|
@ -82,7 +81,7 @@
|
||||||
* @param {Object} data binary file
|
* @param {Object} data binary file
|
||||||
* @returns {Array} vertex face array
|
* @returns {Array} vertex face array
|
||||||
*/
|
*/
|
||||||
function parse(data) {
|
function parseAsync(data) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
JSZip.loadAsync(data).then(zip => {
|
JSZip.loadAsync(data).then(zip => {
|
||||||
for (let [key,value] of Object.entries(zip.files)) {
|
for (let [key,value] of Object.entries(zip.files)) {
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,27 @@
|
||||||
if (self.moto.OBJ) return;
|
if (self.moto.OBJ) return;
|
||||||
|
|
||||||
self.moto.OBJ = {
|
self.moto.OBJ = {
|
||||||
parse : parse
|
parse,
|
||||||
|
parseAsync
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} text
|
* @param {String} text
|
||||||
* @returns {Array} vertex face array
|
* @returns {Array} vertex face array
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
function parseAsync(text) {
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
resolve(parse(text));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function parse(text) {
|
function parse(text) {
|
||||||
|
|
||||||
let lines = text.split('\n').map(l => l.trim());
|
let lines = text.split('\n').map(l => l.trim());
|
||||||
let verts = [];
|
let verts = [];
|
||||||
let faces = [];
|
let faces = [];
|
||||||
let obj = [ faces ];
|
let objs = [ faces ];
|
||||||
|
|
||||||
for (let line of lines) {
|
for (let line of lines) {
|
||||||
let toks = line.split(' ');
|
let toks = line.split(' ');
|
||||||
|
|
@ -35,7 +43,7 @@
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
if (faces.length) {
|
if (faces.length) {
|
||||||
obj.push(faces = []);
|
objs.push(faces = []);
|
||||||
}
|
}
|
||||||
if (toks[0]) {
|
if (toks[0]) {
|
||||||
faces.name = toks[0];
|
faces.name = toks[0];
|
||||||
|
|
@ -44,7 +52,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return objs;
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,11 @@
|
||||||
return bin;
|
return bin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} data
|
||||||
|
* @param {number} scale
|
||||||
|
* @returns vertex array
|
||||||
|
*/
|
||||||
SP.parse = function(data, scale) {
|
SP.parse = function(data, scale) {
|
||||||
let binData = this.convertToBinary(data);
|
let binData = this.convertToBinary(data);
|
||||||
|
|
||||||
|
|
@ -124,6 +129,12 @@
|
||||||
: this.parseASCII(this.convertToString(data), scale);
|
: 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) {
|
SP.parseBinary = function(data, scale = 1) {
|
||||||
let reader = new DataView(data),
|
let reader = new DataView(data),
|
||||||
faces = reader.getUint32 (80, true),
|
faces = reader.getUint32 (80, true),
|
||||||
|
|
|
||||||
81
src/moto/load-url.js
Normal file
81
src/moto/load-url.js
Normal 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
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
||||||
Loading…
Reference in a new issue