diff --git a/app.js b/app.js index f3c8b131..647485f6 100644 --- a/app.js +++ b/app.js @@ -221,6 +221,7 @@ const script = { "kiri", "ext/three", "ext/three-bgu", + "ext/jszip", "license", "ext/clip2", // work.test "ext/tween", @@ -244,6 +245,7 @@ const script = { "moto/ctrl", "moto/pack", "moto/space", + "moto/load-3mf", "moto/load-obj", "moto/load-stl", "moto/db", diff --git a/package.json b/package.json index 28cb21fd..0b8c45f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grid-apps", - "version": "3.0.17D", + "version": "3.0.18D", "description": "grid.space 3d slice & modeling tools", "author": "Stewart Allen ", "license": "MIT", diff --git a/src/kiri.js b/src/kiri.js index f24ce91f..aa9914b0 100644 --- a/src/kiri.js +++ b/src/kiri.js @@ -6,7 +6,7 @@ if (!self.kiri) { self.kiri = { - beta: 3017, + beta: 3018, driver: {}, // driver modules loader: [] // module loading: array of functions }; diff --git a/src/kiri/main.js b/src/kiri/main.js index 711b4172..79cd1b9c 100644 --- a/src/kiri/main.js +++ b/src/kiri/main.js @@ -2433,6 +2433,7 @@ console.log/** Copyright Stewart Allen -- All Rights Reserved */ israw = lower.indexOf(".raw") > 0 || lower.indexOf('.') < 0, isstl = lower.indexOf(".stl") > 0, isobj = lower.indexOf(".obj") > 0, + is3mf = lower.indexOf(".3mf") > 0, issvg = lower.indexOf(".svg") > 0, ispng = lower.indexOf(".png") > 0, isjpg = lower.indexOf(".jpg") > 0, @@ -2454,7 +2455,8 @@ console.log/** Copyright Stewart Allen -- All Rights Reserved */ .saveToCatalog(e.target.file.name) ); } - } else if (isobj) { + } + else if (isobj) { let objs = MOTO.OBJ.parse(e.target.result); let odon = function() { for (let obj of objs) { @@ -2480,6 +2482,18 @@ console.log/** Copyright Stewart Allen -- All Rights Reserved */ odon(); } } + else if (is3mf) { + MOTO.TMF.parse(e.target.result).then(models => { + console.log({models}); + for (let model of models) { + platform.add( + newWidget(undefined,group) + .loadVertices(model.faces.toFloat32()) + .saveToCatalog(name) + ); + } + }); + } else if (isgcode) loadCode(e.target.result, 'gcode'); else if (issvg) loadCode(e.target.result, 'svg'); else if (isset) settingsImport(e.target.result, true); diff --git a/src/license.js b/src/license.js index 92979836..f509b46f 100644 --- a/src/license.js +++ b/src/license.js @@ -3,7 +3,7 @@ let terms = { COPYRIGHT: "Copyright (C) Stewart Allen - All Rights Reserved", LICENSE: "See the license.md file included with the source distribution", - VERSION: "3.0.D17" + VERSION: "3.0.D18" }; if (typeof(module) === 'object') { diff --git a/src/moto/load-3mf.js b/src/moto/load-3mf.js new file mode 100644 index 00000000..9ddda4ae --- /dev/null +++ b/src/moto/load-3mf.js @@ -0,0 +1,99 @@ +'use strict'; + +(function() { + + if (!self.moto) self.moto = {}; + if (self.moto.OBJ) return; + + self.moto.TMF = { + parse : parse + }; + + function query(node, path, fn) { + let collect = false; + let match = path[0]; + if (match[0] === '+') { + match = match.slice(1); + collect = true; + } + for (let child of [...node.childNodes]) { + if (child.tagName === match) { + if (collect) { + fn(match, child); + } + if (path.length > 1) { + query(child, path.slice(1), fn); + } + } + } + } + + function loadModel(doc) { + let models = []; + + function emitModel(model, faces) { + models.push({model, faces}); + } + + return new Promise((resolve, reject) => { + let model; + let faces; + + query(doc, ["+model","resources","object","+mesh"], (type, node) => { + console.log({type, node}); + switch (type) { + case "model": + if (model) { + emitModel(mode, faces); + } + model = node; + faces = []; + break; + case "mesh": + let vertices = []; + query(node, ["vertices","+vertex"], (type, vertex) => { + vertices.push([ + parseFloat(vertex.getAttribute("x")), + parseFloat(vertex.getAttribute("y")), + parseFloat(vertex.getAttribute("z")) + ]); + }); + query(node, ["triangles","+triangle"], (type, triangle) => { + let v1 = parseInt(triangle.getAttribute("v1")); + let v2 = parseInt(triangle.getAttribute("v2")); + let v3 = parseInt(triangle.getAttribute("v3")); + faces.appendAll(vertices[v1]); + faces.appendAll(vertices[v2]); + faces.appendAll(vertices[v3]); + }); + break; + } + }); + + if (model) { + emitModel(model, faces); + } + + resolve(models); + }); + } + + /** + * @param {Object} data binary file + * @returns {Array} vertex face array + */ + function parse(data) { + return new Promise((resolve, reject) => { + JSZip.loadAsync(data).then(zip => { + for (let [key,value] of Object.entries(zip.files)) { + if (key.indexOf(".model") > 0) { + value.async("string").then(xml => { + resolve(loadModel(new DOMParser().parseFromString(xml, "text/xml"))); + }); + } + } + }); + }); + } + +})();