diff --git a/app.js b/app.js index aa9d86a4..7d635928 100644 --- a/app.js +++ b/app.js @@ -10,7 +10,7 @@ const fs = require('fs'); const uglify = require('uglify-es'); const moment = require('moment'); const agent = require('express-useragent'); -const license = require_fresh('./js/license.js'); +const license = require_fresh('./src/license.js'); const version = license.VERSION || "rogue"; const fileCache = {}; @@ -18,12 +18,8 @@ const code_src = {}; const code = {}; const mods = {}; const load = []; -const device = { - fdm: [], - sla: [], - cam: [], - laser: [] -}; +const synth = {}; +const api = {}; let level; let cacheDir; @@ -72,7 +68,7 @@ function init(mod) { ])); mod.add(fixedmap("/api/", api)); if (debug) { - mod.static("/js/", "js"); + mod.static("/src/", "src"); mod.static("/mod/", "mod"); mod.sync("/reload", () => { mod.reload(); @@ -130,6 +126,7 @@ function initModule(mod, file, dir) { }, const: { args: {}, + meta: mod.meta, debug: debug, script: script, moddir: dir, @@ -210,139 +207,118 @@ function initModule(mod, file, dir) { }); } -const api = { - "filters-fdm": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(JSON.stringify(device.fdm)); - }, - - "filters-sla": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(JSON.stringify(device.sla)); - }, - - "filters-cam": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(JSON.stringify(device.cam)); - }, - - "filters-laser": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(JSON.stringify(device.laser)); - } -}; - const script = { kiri : [ - "ext-three", - "license", - "ext-clip2", - "ext-tween", - "ext-fsave", - "ext-earcut", - "add-array", - "add-three", - "geo", - "geo-debug", - "geo-render", - "geo-point", - "geo-slope", - "geo-line", - "geo-bounds", - "geo-polygon", - "geo-polygons", - "geo-gyroid", - "moto-kv", - "moto-ajax", - "moto-ctrl", - "moto-space", - "moto-load-stl", - "moto-db", - "moto-ui", - "kiri-icons", - "kiri-lang", - "kiri-lang-en", - "kiri-fill", - "kiri-db", - "kiri-slice", - "kiri-slicer", - "kiri-driver-fdm", - "kiri-driver-sla", - "kiri-driver-cam", - "kiri-driver-laser", - "kiri-pack", - "kiri-layer", - "kiri-widget", - "kiri-print", - "kiri-codec", - "kiri-work", - "kiri-conf", "kiri", - "kiri-init", - "kiri-export" - ].map(p => `js/${p}.js`), - work : [ - "ext-three", - "ext-pngjs", + "ext/three", "license", - "ext-clip2", - "add-array", - "add-three", - "add-class", - "geo", - // "geo-wasm", - "geo-debug", - "geo-point", - "geo-slope", - "geo-line", - "geo-bounds", - "geo-polygon", - "geo-polygons", - "geo-gyroid", - "kiri-fill", - "kiri-slice", - "kiri-slicer", - "kiri-driver-fdm", - "kiri-driver-sla", - "kiri-driver-cam", - "kiri-driver-laser", - "kiri-pack", - "kiri-widget", - "kiri-print", - "kiri-codec" - ].map(p => `js/${p}.js`), + "ext/clip2", + "ext/tween", + "ext/fsave", + "ext/earcut", + "add/array", + "add/three", + "geo/base", + "geo/debug", + "geo/render", + "geo/point", + "geo/slope", + "geo/line", + "geo/bounds", + "geo/polygon", + "geo/polygons", + "geo/gyroid", + "moto/kv", + "moto/ajax", + "moto/ctrl", + "moto/pack", + "moto/space", + "moto/load-stl", + "moto/db", + "kiri/ui", + "kiri/lang", + "kiri/lang-en", + "kiri/fill", + "kiri/db", + "kiri/slice", + "kiri/slicer", + "mode/fdm/driver", + "mode/sla/driver", + "mode/cam/driver", + "mode/laser/driver", + "kiri/layer", + "kiri/widget", + "kiri/print", + "kiri/codec", + "kiri/work", + "kiri/conf", + "kiri/main", + "kiri/init", + "kiri/export", + "@devices", + "@icons" + ].map(p => p.charAt(0) !== '@' ? `src/${p}.js` : p), worker : [ - "kiri-worker" - ].map(p => `js/${p}.js`), - meta : [ - "ext-three", + "kiri", + "ext/three", + "ext/pngjs", "license", - "ext-tween", - "ext-fsave", - "ext-earcut", - "add-array", - "add-three", - "geo", - "geo-debug", - "geo-render", - "geo-point", - "geo-slope", - "geo-line", - "geo-bounds", - "geo-polygon", - "geo-polygons", - "geo-gyroid", - "kiri-layer", - "moto-kv", - "moto-ajax", - "moto-ctrl", - "moto-space", - "moto-load-stl", - "moto-db", - "moto-ui", - "kiri-db", + "ext/clip2", + "add/array", + "add/three", + "add/class", + "geo/base", + // "geo/wasm", + "geo/debug", + "geo/point", + "geo/slope", + "geo/line", + "geo/bounds", + "geo/polygon", + "geo/polygons", + "geo/gyroid", + "moto/pack", + "kiri/fill", + "kiri/slice", + "kiri/slicer", + "mode/fdm/driver", + "mode/sla/driver", + "mode/cam/driver", + "mode/laser/driver", + "kiri/widget", + "kiri/print", + "kiri/codec", + "kiri/worker" + ].map(p => `src/${p}.js`), + meta : [ + "ext/three", + "license", + "ext/tween", + "ext/fsave", + "ext/earcut", + "add/array", + "add/three", + "geo/base", + "geo/debug", + "geo/render", + "geo/point", + "geo/slope", + "geo/line", + "geo/bounds", + "geo/polygon", + "geo/polygons", + "geo/gyroid", + "kiri/layer", + "moto/kv", + "moto/ajax", + "moto/ctrl", + "moto/space", + "moto/load-stl", + "moto/db", + "moto/ui", + "kiri/db", "meta" - ].map(p => `js/${p}.js`) + ].map(p => `src/${p}.js`) }; const db = { @@ -531,8 +507,13 @@ function handleData(req, res, next) { dbVersion = parseInt(version || "0") + 1; checkDone(); }); - } else { + + return; + + } else { + next(); + } } @@ -611,36 +592,46 @@ function serveCode(req, res, code) { res.end(code.code); } +function generateIcons() { + let root = `${dir}/src/ico`; + let icos = {}; + fs.readdirSync(root).forEach(file => { + let name = file.split(".")[0] ; + icos[name] = fs.readFileSync(`${root}/${file}`).toString(); + }); + synth.icons = `self.icons = ${JSON.stringify(icos)};`; +} + +function generateDevices() { + let root = `${dir}/src/dev`; + let devs = {}; + fs.readdirSync(root).forEach(type => { + let map = devs[type] = devs[type] || {}; + fs.readdirSync(`${root}/${type}`).forEach(device => { + map[device] = JSON.parse(fs.readFileSync(`${root}/${type}/${device}`)); + }); + }); + synth.devices = `self.devices = ${JSON.stringify(devs)};`; +} + function prepareScripts() { + generateIcons(); + generateDevices(); code.meta = concatCode(script.meta); code.kiri = concatCode(script.kiri); - code.work = concatCode(script.work); code.worker = concatCode(script.worker); - fs.readdir(dir + "/web/kiri/filter/FDM", function(err, files) { - device.fdm = files || device.fdm; - }); - fs.readdir(dir + "/web/kiri/filter/SLA", function(err, files) { - device.sla = files || device.sla; - }); - fs.readdir(dir + "/web/kiri/filter/CAM", function(err, files) { - device.cam = files || device.cam; - }); - fs.readdir(dir + "/web/kiri/filter/LASER", function(err, files) { - device.laser = files || device.laser; - }); } function concatCode(array) { let code = []; + let direct = array.filter(f => f.charAt(0) !== '@'); + let inject = array.filter(f => f.charAt(0) === '@').map(f => f.substring(1)); // in debug mode, the script should load dependent // scripts instead of serving a complete bundle if (debug) { - let code = [ `(function() { let load = [ `]; - array.forEach(file => { - // if (file.indexOf(":\\") > 0) { - // file = `/${file}`; - // } + let code = [ '(function() { let load = [ ' ]; + direct.forEach(file => { code.push(`"/${file.replace(/\\/g,'/')}?${version}",`); }); code.push([ @@ -653,19 +644,26 @@ function concatCode(array) { 's.src = file;', 's.onload = load_next;', 'document.head.appendChild(s);', - '}; load_next(); })();', + '} load_next(); })();', 'self.debug=true;' ].join('\n')); + inject.forEach(key => { + code.push(synth[key]); + }); return code.join('\n'); } - array.forEach(file => { + direct.forEach(file => { let cached = getCachedFile(file, function(path) { return minify(`${dir}/${file}`); }); code.push(cached); }); + inject.forEach(key => { + code.push(synth[key]); + }); + return code.join(''); } diff --git a/js/ext-earcut.js b/js/ext-earcut.js deleted file mode 120000 index d0216466..00000000 --- a/js/ext-earcut.js +++ /dev/null @@ -1 +0,0 @@ -../node_modules/earcut/src/earcut.js \ No newline at end of file diff --git a/js/ext-three.js b/js/ext-three.js deleted file mode 120000 index a779ba04..00000000 --- a/js/ext-three.js +++ /dev/null @@ -1 +0,0 @@ -../node_modules/three/build/three.min.js \ No newline at end of file diff --git a/js/ext-tween.js b/js/ext-tween.js deleted file mode 120000 index 641b1dea..00000000 --- a/js/ext-tween.js +++ /dev/null @@ -1 +0,0 @@ -../node_modules/tween.js/index.js \ No newline at end of file diff --git a/js/kiri-icons.js b/js/kiri-icons.js deleted file mode 100644 index 715de671..00000000 --- a/js/kiri-icons.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; - -let gs_kiri_ico = exports; - -(function() { - - if (!self.kiri) self.kiri = { }; - if (!self.kiri.icon) self.kiri.icons = { - - fdm:atob('PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0IiB2aWV3Qm94PSIwIDAgMTcwIDE3MCIgd2lkdGg9Ijc1cHgiIGhlaWdodD0iNzVweCI+PGRlZnM+PHBhdGggZD0iTTE1IDM4LjMzQzE1IDM4LjMzIDE1IDM4LjMzIDE1IDM4LjMzQzE1IDI1LjQ1IDI1LjQ1IDE1IDM4LjMzIDE1QzQ0LjU2IDE1IDc1LjY3IDE1IDEzMS42NyAxNUMxMzEuNjcgMTUgMTMxLjY3IDE1IDEzMS42NyAxNUMxMzcuODUgMTUgMTQzLjc5IDE3LjQ2IDE0OC4xNyAyMS44M0MxNTIuNTQgMjYuMjEgMTU1IDMyLjE1IDE1NSAzOC4zM0MxNTUgNDcuNjcgMTU1IDEyMi4zMyAxNTUgMTMxLjY3QzE1NSAxNDQuNTUgMTQ0LjU1IDE1NSAxMzEuNjcgMTU1QzEyMi4zMyAxNTUgNDcuNjcgMTU1IDM4LjMzIDE1NUMyNS40NSAxNTUgMTUgMTQ0LjU1IDE1IDEzMS42N0MxNSAxMTkuMjIgMTUgODguMTEgMTUgMzguMzNaIiBpZD0iYTE0R2FsdjlVRiI+PC9wYXRoPjxwYXRoIGQ9Ik00NSAxNUwxMjUgMTVMMTI1IDc1TDQ1IDc1TDQ1IDE1WiIgaWQ9ImMzcTgzOUxVMyI+PC9wYXRoPjxwYXRoIGQ9Ik0zNSAxNDEuNDhDNTMuMTEgMTQxLjQ4IDY0LjQzIDE0MS40OCA2OC45NiAxNDEuNDhDNzcuODIgMTQxLjQ4IDg1IDEzNC4zIDg1IDEyNS40NUM4NSAxMjUuNDUgODUgMTI1LjQ1IDg1IDEyNS40NSIgaWQ9ImNoRTB0MXhmTCI+PC9wYXRoPjxwYXRoIGQ9Ik0xMDUgOTVMODUgMTE1TDY1IDk1TDEwNSA5NVoiIGlkPSJhNks5OThGM0dUIj48L3BhdGg+PHBhdGggZD0iTTc1IDc1TDk1IDc1TDk1IDk1TDc1IDk1TDc1IDc1WiIgaWQ9ImUxaWlNRVJxQWgiPjwvcGF0aD48L2RlZnM+PGc+PGc+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjYTE0R2FsdjlVRiIgb3BhY2l0eT0iMSIgZmlsbD0iIzAwMDAwMCIgZmlsbC1vcGFjaXR5PSIwIj48L3VzZT48Zz48dXNlIHhsaW5rOmhyZWY9IiNhMTRHYWx2OVVGIiBvcGFjaXR5PSIxIiBmaWxsLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzc3Nzc3NyIgc3Ryb2tlLXdpZHRoPSI4IiBzdHJva2Utb3BhY2l0eT0iMSI+PC91c2U+PC9nPjwvZz48Zz48dXNlIHhsaW5rOmhyZWY9IiNjM3E4MzlMVTMiIG9wYWNpdHk9IjEiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMCI+PC91c2U+PGc+PHVzZSB4bGluazpocmVmPSIjYzNxODM5TFUzIiBvcGFjaXR5PSIxIiBmaWxsLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzc3Nzc3NyIgc3Ryb2tlLXdpZHRoPSI4IiBzdHJva2Utb3BhY2l0eT0iMSI+PC91c2U+PC9nPjwvZz48Zz48Zz48dXNlIHhsaW5rOmhyZWY9IiNjaEUwdDF4ZkwiIG9wYWNpdHk9IjEiIGZpbGwtb3BhY2l0eT0iMCIgc3Ryb2tlPSIjNzc3Nzc3IiBzdHJva2Utd2lkdGg9IjguMDEiIHN0cm9rZS1vcGFjaXR5PSIxIj48L3VzZT48L2c+PC9nPjxnPjxnPjx1c2UgeGxpbms6aHJlZj0iI2E2Szk5OEYzR1QiIG9wYWNpdHk9IjEiIGZpbGwtb3BhY2l0eT0iMCIgc3Ryb2tlPSIjNzc3Nzc3IiBzdHJva2Utd2lkdGg9IjguMDEiIHN0cm9rZS1vcGFjaXR5PSIxIj48L3VzZT48L2c+PC9nPjxnPjx1c2UgeGxpbms6aHJlZj0iI2UxaWlNRVJxQWgiIG9wYWNpdHk9IjEiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMCI+PC91c2U+PGc+PHVzZSB4bGluazpocmVmPSIjZTFpaU1FUnFBaCIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PC9nPjwvZz48L2c+PC9zdmc+Cg=='), - - cam:atob('PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0IiB2aWV3Qm94PSIwIDAgMTcwIDE3MCIgd2lkdGg9Ijc1cHgiIGhlaWdodD0iNzVweCI+PGRlZnM+PHBhdGggZD0iTTE1IDM4LjMzQzE1IDM4LjMzIDE1IDM4LjMzIDE1IDM4LjMzQzE1IDI1LjQ1IDI1LjQ1IDE1IDM4LjMzIDE1QzQ0LjU2IDE1IDc1LjY3IDE1IDEzMS42NyAxNUMxMzEuNjcgMTUgMTMxLjY3IDE1IDEzMS42NyAxNUMxMzcuODUgMTUgMTQzLjc5IDE3LjQ2IDE0OC4xNyAyMS44M0MxNTIuNTQgMjYuMjEgMTU1IDMyLjE1IDE1NSAzOC4zM0MxNTUgNDcuNjcgMTU1IDEyMi4zMyAxNTUgMTMxLjY3QzE1NSAxNDQuNTUgMTQ0LjU1IDE1NSAxMzEuNjcgMTU1QzEyMi4zMyAxNTUgNDcuNjcgMTU1IDM4LjMzIDE1NUMyNS40NSAxNTUgMTUgMTQ0LjU1IDE1IDEzMS42N0MxNSAxMTkuMjIgMTUgODguMTEgMTUgMzguMzNaIiBpZD0iZTNpckhhWHI0Ij48L3BhdGg+PHBhdGggZD0iTTY1IDE1TDEwNSAxNUwxMDUgMTI1TDY1IDEyNUw2NSAxNVoiIGlkPSJjMVlrTG9sMTBkIj48L3BhdGg+PHBhdGggZD0iTTEwNSAyNUw2NSA1NSIgaWQ9ImI0aHhqQ0sxenkiPjwvcGF0aD48cGF0aCBkPSJNMTA1IDU1TDY1IDg1IiBpZD0iYXBVYVY4bVp1Ij48L3BhdGg+PHBhdGggZD0iTTEwNSA4NUw2NSAxMTUiIGlkPSJiazIxZElxT3EiPjwvcGF0aD48L2RlZnM+PGc+PGc+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZTNpckhhWHI0IiBvcGFjaXR5PSIxIiBmaWxsPSIjMDAwMDAwIiBmaWxsLW9wYWNpdHk9IjAiPjwvdXNlPjxnPjx1c2UgeGxpbms6aHJlZj0iI2UzaXJIYVhyNCIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjYzFZa0xvbDEwZCIgb3BhY2l0eT0iMSIgZmlsbD0iIzAwMDAwMCIgZmlsbC1vcGFjaXR5PSIwIj48L3VzZT48Zz48dXNlIHhsaW5rOmhyZWY9IiNjMVlrTG9sMTBkIiBvcGFjaXR5PSIxIiBmaWxsLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzc3Nzc3NyIgc3Ryb2tlLXdpZHRoPSI4IiBzdHJva2Utb3BhY2l0eT0iMSI+PC91c2U+PC9nPjwvZz48Zz48Zz48dXNlIHhsaW5rOmhyZWY9IiNiNGh4akNLMXp5IiBvcGFjaXR5PSIxIiBmaWxsLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzc3Nzc3NyIgc3Ryb2tlLXdpZHRoPSI4LjAxIiBzdHJva2Utb3BhY2l0eT0iMSI+PC91c2U+PC9nPjwvZz48Zz48Zz48dXNlIHhsaW5rOmhyZWY9IiNhcFVhVjhtWnUiIG9wYWNpdHk9IjEiIGZpbGwtb3BhY2l0eT0iMCIgc3Ryb2tlPSIjNzc3Nzc3IiBzdHJva2Utd2lkdGg9IjguMDEiIHN0cm9rZS1vcGFjaXR5PSIxIj48L3VzZT48L2c+PC9nPjxnPjxnPjx1c2UgeGxpbms6aHJlZj0iI2JrMjFkSXFPcSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOC4wMSIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PC9nPjwvZz48L2c+PC9zdmc+Cg=='), - - laser:atob('PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0IiB2aWV3Qm94PSIwIDAgMTcwIDE3MCIgd2lkdGg9Ijc1cHgiIGhlaWdodD0iNzVweCI+PGRlZnM+PHBhdGggZD0iTTE1IDM4LjMzQzE1IDM4LjMzIDE1IDM4LjMzIDE1IDM4LjMzQzE1IDI1LjQ1IDI1LjQ1IDE1IDM4LjMzIDE1QzQ0LjU2IDE1IDc1LjY3IDE1IDEzMS42NyAxNUMxMzEuNjcgMTUgMTMxLjY3IDE1IDEzMS42NyAxNUMxMzcuODUgMTUgMTQzLjc5IDE3LjQ2IDE0OC4xNyAyMS44M0MxNTIuNTQgMjYuMjEgMTU1IDMyLjE1IDE1NSAzOC4zM0MxNTUgNDcuNjcgMTU1IDEyMi4zMyAxNTUgMTMxLjY3QzE1NSAxNDQuNTUgMTQ0LjU1IDE1NSAxMzEuNjcgMTU1QzEyMi4zMyAxNTUgNDcuNjcgMTU1IDM4LjMzIDE1NUMyNS40NSAxNTUgMTUgMTQ0LjU1IDE1IDEzMS42N0MxNSAxMTkuMjIgMTUgODguMTEgMTUgMzguMzNaIiBpZD0iYTRsMDBtbkVueSI+PC9wYXRoPjxwYXRoIGQ9Ik02NSAxNUwxMDUgMTVMMTA1IDU1TDY1IDU1TDY1IDE1WiIgaWQ9ImJxOG9CV3JmRyI+PC9wYXRoPjxwYXRoIGQ9Ik04NSAxMjVMODUgNjUiIGlkPSJhWHpIdEdic0QiPjwvcGF0aD48cGF0aCBkPSJNNTUgMTA1TDc1IDEzNSIgaWQ9ImFrU3poMFFLeCI+PC9wYXRoPjxwYXRoIGQ9Ik0xMTUgMTA1TDk1IDEzNSIgaWQ9ImJsb0FzOWdpWiI+PC9wYXRoPjxwYXRoIGQ9Ik0zNSAxMjVMNzUgMTQ1IiBpZD0iZ2s2b2hqMEpMIj48L3BhdGg+PHBhdGggZD0iTTEzNSAxMjMuOTZMOTUgMTQ1IiBpZD0iZTQwNGVvajdMIj48L3BhdGg+PC9kZWZzPjxnPjxnPjxnPjxnPjx1c2UgeGxpbms6aHJlZj0iI2E0bDAwbW5FbnkiIG9wYWNpdHk9IjEiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMCI+PC91c2U+PGc+PHVzZSB4bGluazpocmVmPSIjYTRsMDBtbkVueSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjYnE4b0JXcmZHIiBvcGFjaXR5PSIxIiBmaWxsPSIjMDAwMDAwIiBmaWxsLW9wYWNpdHk9IjAiPjwvdXNlPjxnPjx1c2UgeGxpbms6aHJlZj0iI2JxOG9CV3JmRyIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjYVh6SHRHYnNEIiBvcGFjaXR5PSIxIiBmaWxsLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzc3Nzc3NyIgc3Ryb2tlLXdpZHRoPSI4LjAxIiBzdHJva2Utb3BhY2l0eT0iMSI+PC91c2U+PC9nPjwvZz48Zz48Zz48dXNlIHhsaW5rOmhyZWY9IiNha1N6aDBRS3giIG9wYWNpdHk9IjEiIGZpbGwtb3BhY2l0eT0iMCIgc3Ryb2tlPSIjNzc3Nzc3IiBzdHJva2Utd2lkdGg9IjguMDEiIHN0cm9rZS1vcGFjaXR5PSIxIj48L3VzZT48L2c+PC9nPjxnPjxnPjx1c2UgeGxpbms6aHJlZj0iI2Jsb0FzOWdpWiIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOC4wMSIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZ2s2b2hqMEpMIiBvcGFjaXR5PSIxIiBmaWxsLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzc3Nzc3NyIgc3Ryb2tlLXdpZHRoPSI4LjAxIiBzdHJva2Utb3BhY2l0eT0iMSI+PC91c2U+PC9nPjwvZz48Zz48Zz48dXNlIHhsaW5rOmhyZWY9IiNlNDA0ZW9qN0wiIG9wYWNpdHk9IjEiIGZpbGwtb3BhY2l0eT0iMCIgc3Ryb2tlPSIjNzc3Nzc3IiBzdHJva2Utd2lkdGg9IjguMDEiIHN0cm9rZS1vcGFjaXR5PSIxIj48L3VzZT48L2c+PC9nPjwvZz48L2c+PC9nPjwvc3ZnPgo='), - - sla:atob('PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCBtZWV0IiB2aWV3Qm94PSIwIDAgMTcwIDE3MCIgd2lkdGg9Ijc1cHgiIGhlaWdodD0iNzVweCI+PGRlZnM+PHBhdGggZD0iTTE1IDM4LjMzQzE1IDM4LjMzIDE1IDM4LjMzIDE1IDM4LjMzQzE1IDI1LjQ1IDI1LjQ1IDE1IDM4LjMzIDE1QzQ0LjU2IDE1IDc1LjY3IDE1IDEzMS42NyAxNUMxMzEuNjcgMTUgMTMxLjY3IDE1IDEzMS42NyAxNUMxMzcuODUgMTUgMTQzLjc5IDE3LjQ2IDE0OC4xNyAyMS44M0MxNTIuNTQgMjYuMjEgMTU1IDMyLjE1IDE1NSAzOC4zM0MxNTUgNDcuNjcgMTU1IDEyMi4zMyAxNTUgMTMxLjY3QzE1NSAxNDQuNTUgMTQ0LjU1IDE1NSAxMzEuNjcgMTU1QzEyMi4zMyAxNTUgNDcuNjcgMTU1IDM4LjMzIDE1NUMyNS40NSAxNTUgMTUgMTQ0LjU1IDE1IDEzMS42N0MxNSAxMTkuMjIgMTUgODguMTEgMTUgMzguMzNaIiBpZD0iYjNUUk5IeWJ4WCI+PC9wYXRoPjxwYXRoIGQ9Ik0zMS44OCA0Mi41TDEzOC4xMiA0Mi41TDEzOC4xMiA0Ny44MUwzMS44OCA0Ny44MUwzMS44OCA0Mi41WiIgaWQ9ImFOTWt6THdiIj48L3BhdGg+PHBhdGggZD0iTTc1IDIxLjg3TDk1IDIxLjg3TDk1IDQxLjg4TDc1IDQxLjg4TDc1IDIxLjg3WiIgaWQ9ImQxZktLZzJKcnUiPjwvcGF0aD48cGF0aCBkPSJNMTE1LjkzIDEwNy4xOUMxMTUuOTMgMTI0LjI3IDEwMi4wNyAxMzguMTMgODUgMTM4LjEzQzY3LjkzIDEzOC4xMyA1NC4wNyAxMjQuMjcgNTQuMDcgMTA3LjE5QzU0LjA3IDkwLjEyIDY3LjkzIDc2LjI2IDg1IDc2LjI2QzEwMi4wNyA3Ni4yNiAxMTUuOTMgOTAuMTIgMTE1LjkzIDEwNy4xOVoiIGlkPSJjbnlyY1RRTWciPjwvcGF0aD48cGF0aCBkPSJNNTMuODcgNDcuODFMNTMuODcgMTA3LjA4IiBpZD0iYTRHOVJyNlZRTCI+PC9wYXRoPjxwYXRoIGQ9Ik0xMTUuNzYgNTEuMjdMMTE1Ljc2IDExMC41MyIgaWQ9ImQ0aHl0eVNReFoiPjwvcGF0aD48cGF0aCBkPSJNNjkuMDYgNzkuNjlMNjkuMDYgNDcuODEiIGlkPSJiMVdRODNFTEFBIj48L3BhdGg+PHBhdGggZD0iTTEwMC45NCA3OS42OUwxMDAuOTQgNDcuODEiIGlkPSJmMmtOSHNsYUxhIj48L3BhdGg+PHBhdGggZD0iTTY5LjA2IDU4LjQ0TDUzLjEzIDc0LjM4IiBpZD0iZzY3dkZKd0FGeSI+PC9wYXRoPjxwYXRoIGQ9Ik0xMTQuNjggNTguNDRMMTAwLjk0IDY5LjA2IiBpZD0iYUFjcDN6NUt2Ij48L3BhdGg+PC9kZWZzPjxnPjxnPjxnPjx1c2UgeGxpbms6aHJlZj0iI2IzVFJOSHlieFgiIG9wYWNpdHk9IjEiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMCI+PC91c2U+PGc+PHVzZSB4bGluazpocmVmPSIjYjNUUk5IeWJ4WCIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjYU5Na3pMd2IiIG9wYWNpdHk9IjEiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMCI+PC91c2U+PGc+PHVzZSB4bGluazpocmVmPSIjYU5Na3pMd2IiIG9wYWNpdHk9IjEiIGZpbGwtb3BhY2l0eT0iMCIgc3Ryb2tlPSIjNzc3Nzc3IiBzdHJva2Utd2lkdGg9IjgiIHN0cm9rZS1vcGFjaXR5PSIxIj48L3VzZT48L2c+PC9nPjxnPjx1c2UgeGxpbms6aHJlZj0iI2QxZktLZzJKcnUiIG9wYWNpdHk9IjEiIGZpbGw9IiMwMDAwMDAiIGZpbGwtb3BhY2l0eT0iMCI+PC91c2U+PGc+PHVzZSB4bGluazpocmVmPSIjZDFmS0tnMkpydSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PHVzZSB4bGluazpocmVmPSIjY255cmNUUU1nIiBvcGFjaXR5PSIxIiBmaWxsPSIjMWVhNWU2IiBmaWxsLW9wYWNpdHk9IjAiPjwvdXNlPjxnPjx1c2UgeGxpbms6aHJlZj0iI2NueXJjVFFNZyIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjYTRHOVJyNlZRTCIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZDRoeXR5U1F4WiIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjYjFXUTgzRUxBQSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZjJrTkhzbGFMYSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iOCIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjZzY3dkZKd0FGeSIgb3BhY2l0eT0iMSIgZmlsbC1vcGFjaXR5PSIwIiBzdHJva2U9IiM3Nzc3NzciIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLW9wYWNpdHk9IjEiPjwvdXNlPjwvZz48L2c+PGc+PGc+PHVzZSB4bGluazpocmVmPSIjYUFjcDN6NUt2IiBvcGFjaXR5PSIxIiBmaWxsLW9wYWNpdHk9IjAiIHN0cm9rZT0iIzc3Nzc3NyIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2Utb3BhY2l0eT0iMSI+PC91c2U+PC9nPjwvZz48L2c+PC9nPjwvc3ZnPgo=') - - }; - -})(); diff --git a/js/kiri-lang-en.js b/js/kiri-lang-en.js deleted file mode 120000 index ec53fb5d..00000000 --- a/js/kiri-lang-en.js +++ /dev/null @@ -1 +0,0 @@ -../web/kiri/lang/en.js \ No newline at end of file diff --git a/js/license.js b/js/license.js deleted file mode 100644 index f5dd8e9e..00000000 --- a/js/license.js +++ /dev/null @@ -1,7 +0,0 @@ -var exports = { - COPYRIGHT:"Copyright (C) Stewart Allen - All Rights Reserved", - LICENSE:"See the license.md file included with the source distribution", - VERSION:"2.0.5" -}; -if (!module) var module = {}; -module.exports = exports; diff --git a/js/web-server.js b/js/web-server.js deleted file mode 100644 index 51796600..00000000 --- a/js/web-server.js +++ /dev/null @@ -1,1432 +0,0 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ - -Array.prototype.contains = function(v) { - return this.indexOf(v) >= 0; -}; - -Array.prototype.appendAll = function(a) { - this.push.apply(this,a); - return this; -}; - -const helper = { - log: function() { - console.log( - moment().format('YYMMDD.HHmmss'), - [...arguments] - .map(v => util.inspect(v, { - maxArrayLength: null, - breakLength: Infinity, - colors: debug, - compact: true, - sorted: true, - depth: null - })) - .join(' ') - ); - } -}; - -function log(o) { - helper.log(o); -} - -function promise(resolve, reject) { - return new Promise(resolve, reject); -} - -function rval() { - return (Math.round(Math.random()*0xffffffff)).toString(36); -} - -function guid() { - return time().toString(36)+rval()+rval()+rval(); -} - -function time() { - return Date.now(); -} - -/** - * @param {String[]} path - */ -function mkdirs(path) { - let root = ""; - path.forEach(seg => { - if (root) { - root = root + "/" + seg; - } else { - root = seg; - } - lastmod(root) || fs.mkdirSync(root); - }); -} - -/** - * @param {String} o - */ -function obj2string(o) { - return JSON.stringify(o); -} - -function string2obj(s) { - return JSON.parse(s); -} - -/** - * sync return mtime for file or 0 for no such file - * @param {String} path - * @returns {number} - */ -function lastmod(path) { - try { - return fs.statSync(path).mtime.getTime(); - } catch (e) { - return 0; - } -} - -/** - * @param {String} filePath - * @param {Function} fn - * @returns {*} - */ -function getCachedFile(filePath, cpath, fn) { - let cachePath = ".cache/" + cpath - .replace(/\//g,'_') - .replace(/\\/g,'_') - .replace(/:/g,'_'), - cached = fileCache[filePath], - now = time(); - - if (cached) { - if (now - cached.lastcheck > 60000) { - let smod = lastmod(filePath), - cmod = cached.mtime; - - if (!smod) throw "missing source file"; - if (smod > cmod) cached = null; - - cached.lastcheck = now; - } - } - - if (!cached) { - let smod = lastmod(filePath), - cmod = lastmod(cachePath), - cacheData; - - if (cmod >= smod) { - cacheData = fs.readFileSync(cachePath); - } else { - helper.log({update_cache:filePath}); - cacheData = fn(filePath); - fs.writeFileSync(cachePath, cacheData); - } - - cached = { - data: cacheData, - mtime: cmod || now, - lastcheck: now - }; - - fileCache[filePath] = cached; - } - - return cached.data; -} - -/** - * mangle, cache and concatenate scripts - */ -function prepareScripts() { - code.kiri = concatCode(script.kiri); - code.meta = concatCode(script.meta); - code.work = concatCode(script.work); - code.worker = concatCode(script.worker); - fs.readdir("./web/kiri/filter/FDM", function(err, files) { - filters_fdm = files || filters_fdm; - }); - fs.readdir("./web/kiri/filter/SLA", function(err, files) { - filters_sla = files || filters_sla; - }); - fs.readdir("./web/kiri/filter/CAM", function(err, files) { - filters_cam = files || filters_cam; - }); - fs.readdir("./web/kiri/filter/LASER", function(err, files) { - filters_laser = files || filters_laser; - }); -} - -/** - * @param {Array} array - * @returns {String} - */ -function concatCode(array) { - let code = [], - cached, - cachepath, - filepath; - - // in debug mode, the script should load dependent - // scripts instead of serving a complete bundle - if (debug) { - let code = [ `(function() { let load = [ `]; - array.forEach(file => { - if (file.indexOf(".js") < 0) { - file = `/js/${file}.js?${ver.VERSION}`; - } - if (file.indexOf(":\\") > 0) { - file = `/${file}`; - } - code.push(`"${file.replace(/\\/g,'/')}",`); - }); - code.push([ - ']; function load_next() {', - 'let file = load.shift();', - 'if (!file) return;', - 'if (!self.document) { importScripts(file); return load_next() }', - 'let s = document.createElement("script");', - 's.type = "text/javascript";', - 's.src = file;', - 's.onload = load_next;', - 'document.head.appendChild(s);', - '}; load_next(); })();', - 'self.debug=true;' - ].join('\n')); - return code.join('\n'); - } - - array.forEach((file, index) => { - if (file.charAt(0) === "/" || file.indexOf("\\") > 0) { - filepath = file; - cachepath = "js_mod" + file - .replace(/\//g,'_') - .replace(/\\/g,'_') - .replace(/:/g,'_'), - array[index] = cachepath.substring(3).replace('.js',''); - fileMap[cachepath.replace("js_","js/")] = filepath; - } else { - filepath = codePrefix + file + ".js"; - cachepath = filepath; - } - cached = getCachedFile(filepath, cachepath, function(path) { - return minify(filepath); - }); - code.push(cached); - }); - - return code.join(''); -} - -/** - * @param {String} cookie - * @param {String} [key] - * @returns {String | null} - */ -function getCookieValue(cookie,key) { - if (!cookie) return null; - key = (key || "key") + "="; - let kpos = cookie.lastIndexOf(key); - if (kpos >= 0) { - return cookie.substring(kpos+key.length).split(';')[0]; - } else { - return null; - } -} - -/** - * @param {String} ip - */ -function isNotLocal(ip) { - return ipLocal.contains(ip) ? null : ip; -} - -/** - * @param {Object} req - * @returns {String} - */ -function remoteIP(req) { - let fwd = req.headers['x-forwarded-for'], - sra = req.socket.remoteAddress, - cra = req.connection.remoteAddress, - ip = isNotLocal(fwd) || sra || cra || '', - ipa = ip.split(','); - if (ip === '' || ipa.length > 1) { - helper.log({remote:ipa, fwd, sra, cra}); - } - return ipa[0]; -} - -/** - * @param {Object} res - * @param {number} code - * @param {String} msg - */ -function quickReply(res, code, msg) { - res.writeHead(code); - res.end(msg+"\n"); -} - -/** - * @param {Object} req - * @param {Object} res - */ -function reply404(req, res) { - logger.emit([ - '404', - req.url, - req.socket.remoteAddress, - req.headers - ]); - res.writeHead(404); - res.end("[404]"); -} - -/** - * @param {Object} res - * @param {String} url - */ -function redirect(res, url) { - res.writeHead(302, { "Location": url }); - res.end(); -} - -/** - * @param {Array} array - * @param {number} length - * @param {number} timespan - * @returns {number} - */ -function limit(array, length, timespan, inc) { - let now = time(), - add = inc || 1, - limit = 0; - // age out entries older than timespan - while (array.length > 0 && now-array[0] > timespan) { - array.shift(); - } - // count elements over the limit - while (array.length > length) { - limit += add; - array.shift(); - } - return limit; -} - -function rewrite(req, res, next) { - if (req.url.indexOf(".html") > 0) { - let real_write = res.write; - let real_end = res.end; - - res.write = function() { - arguments[0] = arguments[0].toString().replace(/{{version}}/g,ver.VERSION); - real_write.apply(res, arguments); - }; - res.end = function() { - if (arguments[0]) { - arguments[0] = arguments[0].toString().replace(/{{version}}/g,ver.VERSION); - } - real_end.apply(res, arguments); - }; - } - - next(); -} - -/** - * @param {Object} req - * @param {Object} res - * @param {Function} next - */ -function setup(req, res, next) { - let host = req.headers['host'] || '', - beta = getCookieValue(req.headers['cookie'],'beta'); - - if (beta === 'true' && req.url.indexOf('?prod') > 0) { - res.setHeader('Set-Cookie', 'beta=false; path=/;'); - beta = 'false'; - } else if (beta !== 'true' && req.url.indexOf('?beta') > 0) { - res.setHeader('Set-Cookie', 'beta=true; path=/;'); - beta = 'true'; - } - - if (beta === 'true' && host.indexOf('beta.') !== 0) { - return redirect(res, `//beta.${host}${req.url}`); - } - - let parsed = url.parse(req.url, true), - ipaddr = remoteIP(req), - dbikey = db.key(["ip",ipaddr]), - path = parsed.pathname, - time = new Date().getTime(), - rec = ipCache[ipaddr] || { - saved : 0, - first: time, - last: [], - hits: 0, - api: [], - ip: ipaddr, - }, - ua = 'unknown'; - - try { - ua = agent.parse(req.headers['user-agent'] || ''); - } catch (e) { - helper.log("ua parse error on : "+req.headers['user-agent']); - } - - // cache it - if (rec.saved === 0) { - ipCache[ipaddr] = rec; - if (!rec.host) { - // prevent overlapping lookups for the same address - rec.host = 'unknown'; - try { - dns.reverse(ipaddr, (err,addr) => { - rec.host = addr; - }); - } catch (e) { - helper.log({dns_err: ipaddr}) - } - } - } - - // grid.space request state - req.gs = { - ua: ua, - ip: ipaddr, - iprec: rec, - local: ipLocal.contains(ipaddr), - port: req.socket.address().port, - url: parsed, - path: parsed.pathname, - query: parsed.query, - }; - - // fixup local addrs - if (req.gs.local) req.gs.ip = "::1"; - - // track clients & show first instance of IP - rec.last.push(time); - rec.hits++; - - // log request - logger.emit([ - req.method, - req.headers['host'] || '', - req.url, - req.socket.remoteAddress, - req.headers['origin'] || '', - req.headers['user-agent'] || '' - // m: req.method, - // u: req.url, - // i: ipaddr, - // h: req.headers['host'], - // o: req.headers['origin'], - // a: req.headers['user-agent'] - ]); - - // update db ip record - if (time - rec.saved > ipSaveDelay) db.get(dbikey) - .then(dbrec => { - // only on the first pull from disk - if (dbrec && rec.saved === 0) { - rec.first = dbrec.first; - rec.hits += dbrec.hits; - rec.last = dbrec.last.appendAll(rec.last); - rec.api = dbrec.api.appendAll(rec.api); - } - rec.saved = time; - return rec; - }) - .then(dbrec => { - if (rec.putTO) clearTimeout(rec.putTO); - rec.putTO = setTimeout(() => { - rec.putTO = null; - db.put(dbikey, dbrec); - }, ipSaveDelay); - }) - .catch(error => { - helper.log({dbikey, error}); - }); - - // absolute limit on client requests per minute - let rateinc = req.headers.host ? 1 : 50; - if (limit(rec.last, 300, 60000, rateinc) && !req.gs.local) { - res.writeHead(503); - res.end("rate limited"); - return log({rate_limit:ipaddr, len:rec.last.length}); - } - - if (req.method === 'OPTIONS') { - addCorsHeaders(req, res); - res.end(); - } else { - next(); - } -} - -function addCorsHeaders(req, res) { - res.setHeader('Access-Control-Allow-Credentials', 'true'); - res.setHeader('Access-Control-Allow-Headers', 'X-Moto-Ajax, Content-Type'); - res.setHeader("Access-Control-Allow-Origin", req.headers['origin'] || '*'); - res.setHeader("Allow", "GET,POST,OPTIONS"); -} - -/** - * in debug mode only, serve ANY file path beginning with / that exists - */ -function handleDebug(req, res, next) { - if (debug) { - let ext = req.url.split('.').pop(); - let type = { - 'html': 'text/html', - 'js': 'application/javascript' - }[ext] || 'application/unknown'; - if (lastmod(req.url)) { - res.setHeader('Content-Type',type); - return res.end(fs.readFileSync(req.url)); - } else if (lastmod(req.url.substring(1))) { - res.setHeader('Content-Type','application/javascript'); - return res.end(fs.readFileSync(req.url.substring(1))); - } - } - return next(); -} - -/** - * meta:moto data storage and retrieval url - * - * @param {Object} req - * @param {Object} res - * @param {Function} next - */ -function handleData(req, res, next) { - addCorsHeaders(req, res); - res.setHeader('Cache-Control', 'private, no-cache, max-age=0'); - - let tok = req.gs.url.path.split('/'), - muid = req.headers['x-moto-ajax'], - space = tok[2] || null, - version = tok[3], - valid = space && space.length >= 4 && space.length <= 8; - - function genKey() { - while (true) { - let k = Math.round(Math.random() * 9999999999).toString(36); - if (k.length >= 4 && k.length <= 8) return k; - } - } - - function countKey(space) { - return db.key(['meta/counter',space]); - } - - function ownerKey(space) { - return db.key(['meta/owner',muid,'space',space]); - } - - function recordKey(space, version) { - return db.key(["meta/space",space,version]); - } - - // retrieve latest space data - if (valid && req.method === 'GET' && valid) { - function send(rec, version) { - if (rec) { - res.write(obj2string({space:space,ver:version,rec:rec})); - res.end(); - } else { - res.end(); - } - } - - function retrieve(version) { - return db.get(recordKey(space,version)) - .then(record => { - send(record || null, version); - }) - } - - if (version) { - retrieve(version) - } else { - db.get(countKey(space)).then(version => retrieve(version)); - } - - return; - - } else if (valid && req.method === 'POST') { - - let dbOwner = null, - dbVersion = null, - postBody = null, - iprec = req.gs.iprec, - spacein = space, - version = 0, - body = ''; - - function checkDone() { - if (!(dbVersion && postBody)) return; - // if not owner, assign new space id - if (dbVersion > 1) { - if (!dbOwner) { - space = genKey(); - version = 1; - log({forked:space,from:spacein,by:muid}); - } - } - // log what we have - log({ - space: space, - ver: dbVersion, - uid: muid, - ip: iprec.ip, - hits: iprec.hits, - size: postBody.length - }); - if (muid && muid.length > 0) { - level.put(recordKey(space, dbVersion), body); - level.put(ownerKey(space), {ip: iprec.ip, time: time(), ver: dbVersion}); - level.put(countKey(space), dbVersion); - } - res.end(obj2string({space: space, ver: dbVersion})); - } - - // accumulate post body - req.on('data', data => { body += data }); - req.on('end', () => { - postBody = body; - checkDone(); - }); - - // fetch owner and version information - db.get(ownerKey(space)) - .then(owner => { - dbOwner = owner; - return db.get(countKey(space)); - }) - .then(version => { - dbVersion = parseInt(version || "0") + 1; - checkDone(); - }); - - return; - } -} - -function minify(path) { - let code = fs.readFileSync(path); - if (skip_minify.indexOf(path) >= 0) { - return code; - } - let mini = uglify.minify(code.toString()); - if (mini.error) { - console.trace(mini.error); - throw mini.error; - } - return mini.code; -} - -const clearok = [ - 'js/add-three.js', - 'js/ext-three.js', - 'js/ext-tween.js', - 'js/moto-load-stl.js', -]; - -/** - * @param {Object} req - * @param {Object} res - * @param {Function} next - */ -function handleJS(req, res, next) { - let spath = req.gs.path.substring(1), - jspos = spath.indexOf(".js"), - fpath = jspos > 0 ? spath.substring(0,jspos+3) : spath, - cached = fileCache[fpath]; - - if (!(req.gs.local || debug || clearok.indexOf(fpath) >= 0)) { - return reply404(req, res); - } - - if (fileMap[fpath]) { - fpath = fileMap[fpath]; - } - - fs.stat(fpath, (err, f) => { - if (err || !f) { - return reply404(req, res); - } - - let mtime = f.mtime.getTime(); - - if (!cached || cached.mtime != mtime) { - if (debug) { - fs.readFile(fpath, null, function(err, code) { - if (err) { - return reply404(req,res); - } - serveCode(req, res, fileCache[fpath] = { - clear: true, - mtime: mtime, - code: code - }); - }); - return; - } else { - let start = new Date().getTime(), - code = minify(fpath), - end = new Date().getTime(); - - log({minify:fpath, in:f.size, out:code.length, time:(end-start)}); - - cached = fileCache[fpath] = { - clear: false, - mtime: mtime, - code: code - }; - } - } - - serveCode(req, res, cached); - }); -} - -/** - * @param {Object} req - * @param {Object} res - * @param {Function} next - * - * expects paths in the format "/code/[token]/the/rest/is/ignored" - */ -function handleCode(req, res, next) { - let key = req.gs.path.split('/')[2].split('.')[0], - ck = code_src[key], - js = code[key]; - - if (!js) { - return reply404(req, res); - } - - if (ck) { - let mod = lastmod(ck.path); - if (mod > ck.mod) { - if (debug) { - js = code[ck.endpoint] = fs.readFileSync(ck.path); - } else { - js = code[ck.endpoint] = minify(ck.path); - } - ck.mod = mod; - } - } - - addCorsHeaders(req, res); - serveCode(req, res, { - code: js, - mtime: startTime - }); -} - -function handleWasm(req, res, next) { - let [root, file] = req.gs.path.split('/').slice(1); - let ext = (file || '').split('.')[1]; - let path = `wasm/${file}`; - let mod = lastmod(path); - - if (root === 'wasm' && ext === 'wasm' && mod) { - let imd = ifModifiedDate(req); - if (imd && mod <= imd) { - res.writeHead(304, "Not Modified"); - return res.end(); - } - res.writeHead(200, { - 'Content-Type': 'application/wasm', - 'Cache-Control': 'public, max-age=600', - 'Last-Modified': new Date(mod).toGMTString(), - }); - res.end(fs.readFileSync(path)); - } else { - next(); - } -} - -function ifModifiedDate(req) { - let ims = req.headers['if-modified-since']; - if (ims) { - // because sys time has a higher resolution than - // seconds converted from IMS header. so give it - // an extra second - return new Date(ims).getTime() + 1000; - } - return 0; -} - -/** - * @param {Object} req - * @param {Object} res - * @param {Obejct} code - */ -function serveCode(req, res, code) { - if (code.deny) { - return reply404(req, res); - } - - let imd = ifModifiedDate(req); - if (imd && code.mtime <= imd && !code.nocache) { - res.writeHead(304, "Not Modified"); - res.end(); - return; - } - - let cacheControl = code.nocache ? - 'private, max-age=0' : - 'public, max-age=600'; - - res.writeHead(200, { - 'Content-Type': 'application/javascript', - 'Cache-Control': cacheControl, - 'Last-Modified': new Date(code.mtime).toGMTString(), - }); - res.end(code.code); -} - -/* ********************************************* - * Setup / Global - ********************************************* */ - -let debug = false, - nolocal = false, - procexit = false, - port = 8080, - args = process.argv.slice(2); - -args.forEach((arg, index) => { - switch (arg) { - case 'nolocal': nolocal = true; break; - case 'debug': debug = true; break; - case 'port': port = process.argv[index+3]; break; - } -}); - -let ver = require('../js/license.js'), - fs = require('fs'), - url = require('url'), - dns = require('dns'), - util = require('util'), - path = require('path'), - valid = require('validator'), - agent = require('express-useragent'), - spawn = require('child_process').spawn, - level = require('level')('./persist', {valueEncoding:"json"}), - https = require('https'), - moment = require('moment'), - uglify = require('uglify-es'), - connect = require('connect'), - serveStatic = require('serve-static'), - compression = require('compression')(), - querystring = require('querystring'), - ipLocal = nolocal ? [] : ["127.0.0.1", "::1", "::ffff:127.0.0.1"], - currentDir = process.cwd(), - ipSaveDelay = 2000, - startTime = time(), - codePrefix = "js/", - fileCache = {}, - fileMap = {}, - filters_fdm = [], - filters_sla = [], - filters_cam = [], - filters_laser = [], - modPaths = [], - ipCache = {}, - skip_minify = [ - "js/ext-three.js" - ], - script = { - kiri : [ - "ext-three", - "license", - "ext-clip2", - "ext-tween", - "ext-fsave", - "ext-earcut", - "add-array", - "add-three", - "geo", - "geo-debug", - "geo-render", - "geo-point", - "geo-slope", - "geo-line", - "geo-bounds", - "geo-polygon", - "geo-polygons", - "geo-gyroid", - "moto-kv", - "moto-ajax", - "moto-ctrl", - "moto-space", - "moto-load-stl", - "moto-db", - "moto-ui", - "kiri-icons", - "kiri-lang", - "kiri-lang-en", - "kiri-fill", - "kiri-db", - "kiri-slice", - "kiri-slicer", - "kiri-driver-fdm", - "kiri-driver-sla", - "kiri-driver-cam", - "kiri-driver-laser", - "kiri-pack", - "kiri-layer", - "kiri-widget", - "kiri-print", - "kiri-codec", - "kiri-work", - "kiri-conf", - "kiri", - "kiri-init", - "kiri-export" - ], - meta : [ - "ext-three", - "license", - "ext-tween", - "ext-fsave", - "ext-earcut", - "add-array", - "add-three", - "geo", - "geo-debug", - "geo-render", - "geo-point", - "geo-slope", - "geo-line", - "geo-bounds", - "geo-polygon", - "geo-polygons", - "geo-gyroid", - "kiri-layer", - "moto-kv", - "moto-ajax", - "moto-ctrl", - "moto-space", - "moto-load-stl", - "moto-db", - "moto-ui", - "kiri-db", - "meta" - ], - work : [ - "ext-three", - "ext-pngjs", - "license", - "ext-clip2", - "add-array", - "add-three", - "add-class", - "geo", - // "geo-wasm", - "geo-debug", - "geo-point", - "geo-slope", - "geo-line", - "geo-bounds", - "geo-polygon", - "geo-polygons", - "geo-gyroid", - "kiri-fill", - "kiri-slice", - "kiri-slicer", - "kiri-driver-fdm", - "kiri-driver-sla", - "kiri-driver-cam", - "kiri-driver-laser", - "kiri-pack", - "kiri-widget", - "kiri-print", - "kiri-codec" - ], - worker : [ - "kiri-worker" - ] - }, - code_src = {}, - code = {}, - WS = require('ws'), - wss = new WS.Server({ noServer: true }), - wss_roots = {}, - loads = [], - exits = [], - mods = {}, - logger = open_logger({dir: ".log-main"}) - ; - -/* ********************************************* - * Promises-based leveldb interface - ********************************************* */ -const db = { - // -------- - key: arr => arr.join("/"), - // -------- - get: key => { - if (Array.isArray(key)) key = db.key(key); - return promise((resolve,reject) => { - level.get(key,(err,record) => { - resolve(record,err); - }); - }); - }, - - // -------- - put: (key, value) => { - if (Array.isArray(key)) key = db.key(key); - return promise((resolve,reject) => { - level.put(key,value,(err) => { - if (err) reject(err); - else resolve(); - }); - }); - }, - // -------- - del: key => { - return promise((resolve,reject) => { - level.del(key, (err) => { - if (err) reject(err); - else resolve(); - }); - }); - } -}; - -/* ********************************************* - * REST API (extensible in modules) - ********************************************* */ -const api = { - - rateLimit: (req, res, next) => { - req.gs.iprec.api.push(time()); - - // allow 60 calls in 60 seconds - if (limit(req.gs.iprec.api, 60, 60000) && !req.gs.local) { - quickReply(res, 503, "rate limited"); - try { log({rate_limit_api: req.gs.ip, url: req.gs.url}); } catch (e) { helper.log(e) } - } else { - next(); - } - }, - - "filters-fdm": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(obj2string(filters_fdm)); - }, - - "filters-sla": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(obj2string(filters_sla)); - }, - - "filters-cam": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(obj2string(filters_cam)); - }, - - "filters-laser": (req, res, next) => { - res.setHeader("Content-Type", "application/javascript"); - res.end(obj2string(filters_laser)); - } - -}; - -/* ********************************************* - * Dispatch Helpers - ********************************************* */ - -// dispatch for path prefixs -function prepath(pre) { - - function handle(req, res, next) { - pre.uid = pre.uid || guid(); - req.ppi = req.ppi || {}; - - let path = req.gs.path, - key, fn, i = req.ppi[pre.uid] || 0; - - while (i < pre.length) { - key = pre[i][0]; - fn = pre[i++][1]; - if (path.indexOf(key) === 0) { - return fn(req, res, () => { - req.ppi[pre.uid] = i; - handle(req, res, next); - }); - } - } - - next(); - } - - return handle; -} - -// dispatch full fixed paths -function fullpath(map) { - return (req, res, next) => { - let fn = map[req.gs.path]; - if (fn) fn(req, res, next); - else next(); - }; -} - -// dispatch full paths based on a prefix and a function map -function fixedmap(prefix, map) { - return (req, res, next) => { - let path = req.gs.path; - if (path.indexOf(prefix) != 0) return next(); - let fn = map[path.substring(prefix.length)]; - if (fn) fn(req, res, next); - else next(); - }; -} - -// HTTP 302 redirect -function redir(path) { - return (req, res, next) => redirect(res, path); -} - -// mangle request path -function remap(path) { - return (req, res, next) => { - req.url = req.gs.path = path; - next(); - } -} - -// load module and call returned function with helper object -function initModule(file, dir) { - helper.log({module:file}); - require(file)({ - api: api, - adm: { - reload: prepareScripts - }, - const: { - args: args, - debug: debug, - script: script, - moddir: dir, - rootdir: currentDir, - version: ver.VERSION - }, - pkg: { - agent, - moment - }, - mod: mods, - util: { - log: helper.log, - time: time, - guid: guid, - mkdirs: mkdirs, - lastmod: lastmod, - obj2string: obj2string, - string2obj: string2obj, - getCookieValue: getCookieValue, - logger: open_logger, - datadir: (dst) => { - let ddir = `./.data-${dst}`; - mkdirs([ddir]); - return ddir; - } - }, - db: { - api: db, - level: level - }, - inject: (code, file, options) => { - let opt = options || {}; - if (opt.end) { - script[code].push(dir + "/" + file); - } else { - script[code].splice(0, 0, dir + "/" + file); - } - }, - path: { - any: arg => { modPaths.push(arg) }, - pre: arg => { modPaths.push(prepath(arg)) }, - map: arg => { modPaths.push(fixedmap(arg)) }, - full: arg => { modPaths.push(fullpath(arg)) }, - static: (root, pre) => { modPaths.push(handleStatic(root, pre)) }, - code: (endpoint, path) => { - if (debug) { - code[endpoint] = fs.readFileSync(path); - } else { - code[endpoint] = minify(path); - } - code_src[endpoint] = { - endpoint, - path, - mod: lastmod(path) - }; - }, - redir: redir, - remap: remap - }, - handler: { - addCORS: addCorsHeaders, - static: handleStatic, - redirect: redirect, - reply404: reply404, - reply: quickReply - }, - ws: { - register: ws_register_root - }, - onload: (fn) => { - loads.push(fn); - }, - onexit: (fn) => { - exits.push(fn) - } - }); -} - -function handleStatic(root, pre) { - let statServe = serveStatic(root); - return function(req, res, next) { - if (pre) { - if (req.url.indexOf(pre) === 0) { - if (req.url === pre) { - req.url = "/"; - } else { - req.url = req.url.substring(pre.length); - } - return statServe(req, res, next); - } - return next(); - } - statServe(req, res, next); - }; -} - -// add static assets to be served -function addStatic(dir, pre) { - helper.log({static:dir}); - modPaths.push(handleStatic(dir, pre)); -} - -// either add module assets to path or require(init.js) -function loadModule(dir) { - if (dir.indexOf('node_modules') >= 0) { - return; - } - if (lastmod(dir + "/.ignore")) { - return; - } - const modjs = dir + "/init.js"; - lastmod(modjs) ? initModule(modjs, dir) : addStatic(dir); -} - -function ws_delete_root(path) { - ws_register_root(path); -} - -function ws_register_root(path, handler) { - if (handler) { - wss_roots[path] = handler; - } else { - delete wss_roots[path]; - } -} - -function open_logger(options) { - let opt = options || { - dir: "logs" - } - let exiting = false; - let logfile = null; - let logstream = null; - let pattern = opt.pattern || 'YY-MM-DD-HH'; - let last_pattern; - let count_min = opt.min || 1000; - let count = 0; - - try { - fs.mkdirSync(opt.dir); - } catch (e) { } - - // create file write stream - function open_file_stream() { - close_file_stream(); - logfile = path.join(opt.dir, last_pattern = moment().format(pattern)); - logstream = fs.createWriteStream(logfile, {flags: 'a'}); - let cur = path.join(opt.dir, "current"); - try { fs.unlinkSync(cur) } catch (e) { } - try { fs.symlinkSync(last_pattern, cur) } catch (e) { } - count = 0; - } - - function close_file_stream() { - if (logstream) { - logstream.end(); - logstream = null; - } - } - - function emit_log(obj) { - helper.log(obj); - emit(obj); - } - - function emit(obj) { - if (exiting) { - // console.log({dir: opt.dir, exiting_skip_log: obj}) - return; - } - let next_pattern = moment().format(pattern); - if (++count > count_min && next_pattern !== last_pattern) { - open_file_stream(); - } - let output = [moment().format('YYMMDD-HHmmss'),' ',JSON.stringify(obj),'\n'].join(''); - logstream.write(output); - } - - function exit() { - exiting = true; - close_file_stream(); - } - - open_file_stream(); - - exits.push(exit); - - return { emit, log: emit_log, close: close_file_stream }; -} - -function processLoad() { - while (loads.length) { - try { - loads.shift()(); - } catch (e) { - log({on_load_fail: e}); - } - } -} - -function processExit(code) { - if (procexit) { - return; - } - procexit = true; - logger.log({proc_exit: code, registered: exits.length, uptime: time() - startTime}); - while (exits.length) { - try { - exits.shift()(code); - } catch (e) { - log({on_exit_fail: e}); - } - } - setTimeout(() => { - process.exit(); - }, 500); -} - -/* ********************************************* - * Start it up - ********************************************* */ - -// load modules -lastmod("mod") && fs.readdirSync(currentDir + "/mod").forEach(dir => { - const fullpath = currentDir + "/mod/" + dir; - if (dir.charAt(0) === '.') return; - const stats = fs.lstatSync(fullpath); - if (!(stats.isDirectory() || stats.isSymbolicLink())) return; - loadModule(fullpath); -}); - -// create cache dir if missing -lastmod(".cache") || mkdirs([".cache"]); - -// precache responses -prepareScripts(); - -// create web handler chain -let handler = connect().use(setup); - -// add path handlers registered by modules -modPaths.forEach(fn => { - handler = handler.use(fn); -}); - -// add the rest of the handler chain -handler.use(fullpath({ - "/kiri/index.html" : redir("/kiri/"), - "/kiri" : redir("/kiri/"), - "/kiri/" : remap("/kiri/index.html"), - "/meta/index.html" : redir("/meta/"), - "/meta" : redir("/meta/"), - "/meta/" : remap("/meta/index.html") - })) - .use(prepath([ - [ "/space", redir("/meta/")], - [ "/api/", api.rateLimit ], - [ "/data/", handleData ], - [ "/code/", handleCode ], - [ "/wasm/", handleWasm ], - [ "/js/", handleJS ] - ])) - .use(handleDebug) - .use(fixedmap("/api/", api)) - .use(compression) - .use(rewrite) - .use(handleStatic(currentDir + "/web/")) - .use(reply404) - .listen(port) - .on('upgrade', (request, socket, head) => { - let handler = wss_roots[request.url]; - if (handler) { - wss.handleUpgrade(request, socket, head, ws => { - try { - handler(ws, request); - } catch (err) { - log({wss_handler_error: err}); - ws_delete_root(request.url); - socket.destroy(); - } - }); - } else { - socket.destroy(); - } - }); - -helper.log("------------------------------------------"); -helper.log({port, debug, nolocal, version: ver.VERSION}); -logger.emit({port, debug, nolocal, version: ver.VERSION}); - -process.on('beforeExit', processExit); - -process.on('exit', processExit); - -process.on('SIGINT', function(sig, code) { - logger.log({exit: code, signal: sig}); - processExit(code); -}); - -process.on('SIGHUP', function(sig, code) { - logger.log({exit: code, signal: sig}); - processExit(code); -}); - -process.on('unhandledRejection', (reason, p) => { - logger.log({unhandled_rejection: reason, promise: p}); -}); - -process.on('uncaughtException', (err) => { - logger.log({uncaught_exception: err}); -}); - -processLoad(); diff --git a/notes.md b/notes.md index 36ed0fdc..73b5babc 100644 --- a/notes.md +++ b/notes.md @@ -2,6 +2,7 @@ ## `C` cosmetic, `F` functional, `P` performance, `B` bug fix +* `C` hover mode to see device / settings selections * `F` implement an in-app bug reporting system * `F` extend mesh object to store raw + annotations (rot,scale,pos) * share raw data w/ dups, encode/decode @@ -15,6 +16,8 @@ # FDM +* `B` fix adaptive slicing with multi-extruder +* `B` fix supports with grouped parts * `F` control for size of purge block (with 0=disabled) * `F` add separate fill speed control * `F` manual support addition / control @@ -29,6 +32,7 @@ * `F` determine start point from gcode preamble * `F` trim support offset from layer below * `F` option to support interior bridges when 0% infill +* `F` calculate filament use per extruder per print * `P` refactor thin fill to use outline and inside poly normal dist to self * `P` segment large polygons for extremely large parts / infill * `P` implement infill clipping in wasm @@ -44,7 +48,6 @@ * `B` linear finishing should extend beyond part boundaries by tool radius * `B` outside cutting direction in roughing mode inverted * `F` z bounded slices (extension of z bottom offset feature) -* `F` do not mill out thru-pockets. cut outline only. * `F` use arcs to connect hard angles * `F` do not rough areas that go all the way through the part https://github.com/GridSpace/grid-apps/issues/20 diff --git a/package.json b/package.json index f3fa17dc..6f3c3516 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grid-apps", - "version": "1.1.3", + "version": "3.0.0-dev", "description": "grid.space 3d slice & modeling tools", "author": "Stewart Allen ", "license": "MIT", diff --git a/js/add-array.js b/src/add/array.js similarity index 100% rename from js/add-array.js rename to src/add/array.js diff --git a/js/add-class.js b/src/add/class.js similarity index 100% rename from js/add-class.js rename to src/add/class.js diff --git a/js/add-three.js b/src/add/three.js similarity index 100% rename from js/add-three.js rename to src/add/three.js diff --git a/web/kiri/filter/CAM/Any.Generic.Grbl b/src/dev/cam/Any.Generic.Grbl similarity index 69% rename from web/kiri/filter/CAM/Any.Generic.Grbl rename to src/dev/cam/Any.Generic.Grbl index 439356cf..5341c0ef 100644 --- a/web/kiri/filter/CAM/Any.Generic.Grbl +++ b/src/dev/cam/Any.Generic.Grbl @@ -12,11 +12,11 @@ "tool-change":[ "M6 T{tool} ; change tool to '{tool_name}'" ], - "dwell":[ - "G4 P{time} ; dwell for {time}ms" - ], - "settings": { - "bed_width": 400, - "bed_depth": 400 - } + "dwell":[ + "G4 P{time} ; dwell for {time}ms" + ], + "settings": { + "bed_width": 400, + "bed_depth": 400 + } } diff --git a/web/kiri/filter/CAM/Any.Generic.LinuxCNC b/src/dev/cam/Any.Generic.LinuxCNC similarity index 61% rename from web/kiri/filter/CAM/Any.Generic.LinuxCNC rename to src/dev/cam/Any.Generic.LinuxCNC index 7ff81803..e7ad43f9 100644 --- a/web/kiri/filter/CAM/Any.Generic.LinuxCNC +++ b/src/dev/cam/Any.Generic.LinuxCNC @@ -5,20 +5,20 @@ "pre":[ "G21 ; set units to MM (required)", "G90 ; absolute position mode (required)", - "M03 S20000 ; spindle on" + "M03 S20000 ; spindle on" ], "post":[ - "M05 ; spindle off", + "M05 ; spindle off", "M30 ; program end" ], "tool-change":[ "M6 T{tool} ; change tool to '{tool_name}'" ], - "dwell":[ - "G4 P{time} ; dwell for {time}ms" - ], - "settings": { - "bed_width": 400, - "bed_depth": 400 - } + "dwell":[ + "G4 P{time} ; dwell for {time}ms" + ], + "settings": { + "bed_width": 400, + "bed_depth": 400 + } } diff --git a/web/kiri/filter/CAM/Any.Generic.TinyG b/src/dev/cam/Any.Generic.TinyG similarity index 100% rename from web/kiri/filter/CAM/Any.Generic.TinyG rename to src/dev/cam/Any.Generic.TinyG diff --git a/web/kiri/filter/CAM/Carbide3D.Nomad.883Pro b/src/dev/cam/Carbide3D.Nomad.883Pro similarity index 71% rename from web/kiri/filter/CAM/Carbide3D.Nomad.883Pro rename to src/dev/cam/Carbide3D.Nomad.883Pro index 4bd60a1a..fd8f0378 100644 --- a/web/kiri/filter/CAM/Carbide3D.Nomad.883Pro +++ b/src/dev/cam/Carbide3D.Nomad.883Pro @@ -12,11 +12,11 @@ "tool-change":[ "M6 T{tool} ; change tool to '{tool_name}'" ], - "dwell":[ - "G4 P{time} ; dwell for {time}ms" - ], - "settings": { - "bed_width": 200, - "bed_depth": 200 - } + "dwell":[ + "G4 P{time} ; dwell for {time}ms" + ], + "settings": { + "bed_width": 200, + "bed_depth": 200 + } } diff --git a/web/kiri/filter/CAM/Carbide3D.Shapeoko.3 b/src/dev/cam/Carbide3D.Shapeoko.3 similarity index 100% rename from web/kiri/filter/CAM/Carbide3D.Shapeoko.3 rename to src/dev/cam/Carbide3D.Shapeoko.3 diff --git a/web/kiri/filter/CAM/Carbide3D.Shapeoko.XL b/src/dev/cam/Carbide3D.Shapeoko.XL similarity index 100% rename from web/kiri/filter/CAM/Carbide3D.Shapeoko.XL rename to src/dev/cam/Carbide3D.Shapeoko.XL diff --git a/web/kiri/filter/CAM/Carbide3D.Shapeoko.XXL b/src/dev/cam/Carbide3D.Shapeoko.XXL similarity index 100% rename from web/kiri/filter/CAM/Carbide3D.Shapeoko.XXL rename to src/dev/cam/Carbide3D.Shapeoko.XXL diff --git a/web/kiri/filter/CAM/Inventables.Carvey.Any b/src/dev/cam/Inventables.Carvey.Any similarity index 100% rename from web/kiri/filter/CAM/Inventables.Carvey.Any rename to src/dev/cam/Inventables.Carvey.Any diff --git a/web/kiri/filter/CAM/Inventables.XCarve.1000mm b/src/dev/cam/Inventables.XCarve.1000mm similarity index 100% rename from web/kiri/filter/CAM/Inventables.XCarve.1000mm rename to src/dev/cam/Inventables.XCarve.1000mm diff --git a/web/kiri/filter/CAM/Inventables.XCarve.500mm b/src/dev/cam/Inventables.XCarve.500mm similarity index 100% rename from web/kiri/filter/CAM/Inventables.XCarve.500mm rename to src/dev/cam/Inventables.XCarve.500mm diff --git a/web/kiri/filter/CAM/Sienci.LongMill b/src/dev/cam/Sienci.LongMill similarity index 100% rename from web/kiri/filter/CAM/Sienci.LongMill rename to src/dev/cam/Sienci.LongMill diff --git a/web/kiri/filter/CAM/Sienci.Mill.One b/src/dev/cam/Sienci.Mill.One similarity index 100% rename from web/kiri/filter/CAM/Sienci.Mill.One rename to src/dev/cam/Sienci.Mill.One diff --git a/web/kiri/filter/CAM/Techno.Davinci.CNC b/src/dev/cam/Techno.Davinci.CNC similarity index 100% rename from web/kiri/filter/CAM/Techno.Davinci.CNC rename to src/dev/cam/Techno.Davinci.CNC diff --git a/web/kiri/filter/FDM/Any.Generic.Marlin b/src/dev/fdm/Any.Generic.Marlin similarity index 100% rename from web/kiri/filter/FDM/Any.Generic.Marlin rename to src/dev/fdm/Any.Generic.Marlin diff --git a/web/kiri/filter/FDM/Any.Generic.Sailfish b/src/dev/fdm/Any.Generic.Sailfish similarity index 100% rename from web/kiri/filter/FDM/Any.Generic.Sailfish rename to src/dev/fdm/Any.Generic.Sailfish diff --git a/web/kiri/filter/FDM/Anycubic.i3.Mega b/src/dev/fdm/Anycubic.i3.Mega similarity index 100% rename from web/kiri/filter/FDM/Anycubic.i3.Mega rename to src/dev/fdm/Anycubic.i3.Mega diff --git a/web/kiri/filter/FDM/Atom.v2 b/src/dev/fdm/Atom.v2 similarity index 100% rename from web/kiri/filter/FDM/Atom.v2 rename to src/dev/fdm/Atom.v2 diff --git a/web/kiri/filter/FDM/Creality.Ender.3 b/src/dev/fdm/Creality.Ender.3 similarity index 100% rename from web/kiri/filter/FDM/Creality.Ender.3 rename to src/dev/fdm/Creality.Ender.3 diff --git a/web/kiri/filter/FDM/Creality.Ender.5 b/src/dev/fdm/Creality.Ender.5 similarity index 100% rename from web/kiri/filter/FDM/Creality.Ender.5 rename to src/dev/fdm/Creality.Ender.5 diff --git a/web/kiri/filter/FDM/Cubicon.Single+ b/src/dev/fdm/Cubicon.Single+ similarity index 100% rename from web/kiri/filter/FDM/Cubicon.Single+ rename to src/dev/fdm/Cubicon.Single+ diff --git a/web/kiri/filter/FDM/Cubicon.Style b/src/dev/fdm/Cubicon.Style similarity index 100% rename from web/kiri/filter/FDM/Cubicon.Style rename to src/dev/fdm/Cubicon.Style diff --git a/web/kiri/filter/FDM/DeltaMaker.2T b/src/dev/fdm/DeltaMaker.2T similarity index 100% rename from web/kiri/filter/FDM/DeltaMaker.2T rename to src/dev/fdm/DeltaMaker.2T diff --git a/web/kiri/filter/FDM/DeltaMaker.Original b/src/dev/fdm/DeltaMaker.Original similarity index 100% rename from web/kiri/filter/FDM/DeltaMaker.Original rename to src/dev/fdm/DeltaMaker.Original diff --git a/web/kiri/filter/FDM/Flashforge.Finder b/src/dev/fdm/Flashforge.Finder similarity index 100% rename from web/kiri/filter/FDM/Flashforge.Finder rename to src/dev/fdm/Flashforge.Finder diff --git a/web/kiri/filter/FDM/Flashforge.Guider.II b/src/dev/fdm/Flashforge.Guider.II similarity index 100% rename from web/kiri/filter/FDM/Flashforge.Guider.II rename to src/dev/fdm/Flashforge.Guider.II diff --git a/web/kiri/filter/FDM/FolgerTech.FT5 b/src/dev/fdm/FolgerTech.FT5 similarity index 100% rename from web/kiri/filter/FDM/FolgerTech.FT5 rename to src/dev/fdm/FolgerTech.FT5 diff --git a/web/kiri/filter/FDM/GridBot.One b/src/dev/fdm/GridBot.One similarity index 100% rename from web/kiri/filter/FDM/GridBot.One rename to src/dev/fdm/GridBot.One diff --git a/web/kiri/filter/FDM/GridBot.Two b/src/dev/fdm/GridBot.Two similarity index 100% rename from web/kiri/filter/FDM/GridBot.Two rename to src/dev/fdm/GridBot.Two diff --git a/web/kiri/filter/FDM/IMADE3D.JellyBOX.Original b/src/dev/fdm/IMADE3D.JellyBOX.Original similarity index 100% rename from web/kiri/filter/FDM/IMADE3D.JellyBOX.Original rename to src/dev/fdm/IMADE3D.JellyBOX.Original diff --git a/web/kiri/filter/FDM/IMADE3D.JellyBOX2 b/src/dev/fdm/IMADE3D.JellyBOX2 similarity index 100% rename from web/kiri/filter/FDM/IMADE3D.JellyBOX2 rename to src/dev/fdm/IMADE3D.JellyBOX2 diff --git a/web/kiri/filter/FDM/Leapfrog.CreatrHS b/src/dev/fdm/Leapfrog.CreatrHS similarity index 100% rename from web/kiri/filter/FDM/Leapfrog.CreatrHS rename to src/dev/fdm/Leapfrog.CreatrHS diff --git a/web/kiri/filter/FDM/MakerGear.M2 b/src/dev/fdm/MakerGear.M2 similarity index 100% rename from web/kiri/filter/FDM/MakerGear.M2 rename to src/dev/fdm/MakerGear.M2 diff --git a/web/kiri/filter/FDM/Makerbot.Replicator2 b/src/dev/fdm/Makerbot.Replicator2 similarity index 100% rename from web/kiri/filter/FDM/Makerbot.Replicator2 rename to src/dev/fdm/Makerbot.Replicator2 diff --git a/web/kiri/filter/FDM/Prusa.i3.MK2S b/src/dev/fdm/Prusa.i3.MK2S similarity index 100% rename from web/kiri/filter/FDM/Prusa.i3.MK2S rename to src/dev/fdm/Prusa.i3.MK2S diff --git a/web/kiri/filter/FDM/Raise3D.N2 b/src/dev/fdm/Raise3D.N2 similarity index 100% rename from web/kiri/filter/FDM/Raise3D.N2 rename to src/dev/fdm/Raise3D.N2 diff --git a/web/kiri/filter/FDM/TypeA.Series1 b/src/dev/fdm/TypeA.Series1 similarity index 100% rename from web/kiri/filter/FDM/TypeA.Series1 rename to src/dev/fdm/TypeA.Series1 diff --git a/web/kiri/filter/FDM/TypeA.Series1Pro b/src/dev/fdm/TypeA.Series1Pro similarity index 100% rename from web/kiri/filter/FDM/TypeA.Series1Pro rename to src/dev/fdm/TypeA.Series1Pro diff --git a/web/kiri/filter/FDM/Ulio3D b/src/dev/fdm/Ulio3D similarity index 100% rename from web/kiri/filter/FDM/Ulio3D rename to src/dev/fdm/Ulio3D diff --git a/web/kiri/filter/FDM/Ultimaker.Ultimaker2 b/src/dev/fdm/Ultimaker.Ultimaker2 similarity index 100% rename from web/kiri/filter/FDM/Ultimaker.Ultimaker2 rename to src/dev/fdm/Ultimaker.Ultimaker2 diff --git a/web/kiri/filter/FDM/Wanhao.Duplicator_4s b/src/dev/fdm/Wanhao.Duplicator_4s similarity index 100% rename from web/kiri/filter/FDM/Wanhao.Duplicator_4s rename to src/dev/fdm/Wanhao.Duplicator_4s diff --git a/web/kiri/filter/FDM/Wanhao.Duplicator_5s b/src/dev/fdm/Wanhao.Duplicator_5s similarity index 100% rename from web/kiri/filter/FDM/Wanhao.Duplicator_5s rename to src/dev/fdm/Wanhao.Duplicator_5s diff --git a/web/kiri/filter/FDM/Wanhao.Duplicator_6 b/src/dev/fdm/Wanhao.Duplicator_6 similarity index 100% rename from web/kiri/filter/FDM/Wanhao.Duplicator_6 rename to src/dev/fdm/Wanhao.Duplicator_6 diff --git a/web/kiri/filter/FDM/Wanhao.Duplicator_i3 b/src/dev/fdm/Wanhao.Duplicator_i3 similarity index 100% rename from web/kiri/filter/FDM/Wanhao.Duplicator_i3 rename to src/dev/fdm/Wanhao.Duplicator_i3 diff --git a/web/kiri/filter/FDM/XYZ.daVinci.Jr.Pro b/src/dev/fdm/XYZ.daVinci.Jr.Pro similarity index 100% rename from web/kiri/filter/FDM/XYZ.daVinci.Jr.Pro rename to src/dev/fdm/XYZ.daVinci.Jr.Pro diff --git a/web/kiri/filter/FDM/XYZ.daVinci.Mini.w b/src/dev/fdm/XYZ.daVinci.Mini.w similarity index 100% rename from web/kiri/filter/FDM/XYZ.daVinci.Mini.w rename to src/dev/fdm/XYZ.daVinci.Mini.w diff --git a/web/kiri/filter/LASER/Any.Generic.Laser b/src/dev/laser/Any.Generic.Laser similarity index 100% rename from web/kiri/filter/LASER/Any.Generic.Laser rename to src/dev/laser/Any.Generic.Laser diff --git a/web/kiri/filter/LASER/Glowforge b/src/dev/laser/Glowforge similarity index 100% rename from web/kiri/filter/LASER/Glowforge rename to src/dev/laser/Glowforge diff --git a/web/kiri/filter/SLA/Anycubic.Photon b/src/dev/sla/Anycubic.Photon similarity index 100% rename from web/kiri/filter/SLA/Anycubic.Photon rename to src/dev/sla/Anycubic.Photon diff --git a/web/kiri/filter/SLA/Anycubic.Photon.S b/src/dev/sla/Anycubic.Photon.S similarity index 100% rename from web/kiri/filter/SLA/Anycubic.Photon.S rename to src/dev/sla/Anycubic.Photon.S diff --git a/js/ext-clip.js b/src/ext/clip.js similarity index 100% rename from js/ext-clip.js rename to src/ext/clip.js diff --git a/js/ext-clip2.js b/src/ext/clip2.js similarity index 100% rename from js/ext-clip2.js rename to src/ext/clip2.js diff --git a/src/ext/earcut.js b/src/ext/earcut.js new file mode 120000 index 00000000..980715ff --- /dev/null +++ b/src/ext/earcut.js @@ -0,0 +1 @@ +../../node_modules/earcut/src/earcut.js \ No newline at end of file diff --git a/js/ext-fsave.js b/src/ext/fsave.js similarity index 100% rename from js/ext-fsave.js rename to src/ext/fsave.js diff --git a/js/ext-pngjs.js b/src/ext/pngjs.js similarity index 100% rename from js/ext-pngjs.js rename to src/ext/pngjs.js diff --git a/src/ext/three.js b/src/ext/three.js new file mode 120000 index 00000000..5f15cbdf --- /dev/null +++ b/src/ext/three.js @@ -0,0 +1 @@ +../../node_modules/three/build/three.min.js \ No newline at end of file diff --git a/src/ext/tween.js b/src/ext/tween.js new file mode 120000 index 00000000..15b834b0 --- /dev/null +++ b/src/ext/tween.js @@ -0,0 +1 @@ +../../node_modules/tween.js/index.js \ No newline at end of file diff --git a/js/geo.js b/src/geo/base.js similarity index 94% rename from js/geo.js rename to src/geo/base.js index f2444522..16db1b62 100644 --- a/js/geo.js +++ b/src/geo/base.js @@ -1,22 +1,19 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_base = exports; - (function() { - if (!self.base) self.base = {}; - if (self.base.util) return; + if (self.base) return; - var BASE = self.base, + const BASE = self.base = {}, round_decimal_precision = 8; /** ****************************************************************** * Utility Functions ******************************************************************* */ - function time() { return new Date().getTime() } + function time() { return Date.now() } /** * call function with all combinations of a1, a2 @@ -29,7 +26,7 @@ var gs_base = exports; * @returns {Object} */ function doCombinations(a1, a2, arg, fn) { - var i, j; + let i, j; for (i = 0; i < a1.length; i++) { for (j = (a1 === a2 ? i + 1 : 0); j < a2.length; j++) { fn(a1[i], a2[j], arg); @@ -151,7 +148,7 @@ var gs_base = exports; * @returns {boolean} */ function inRange(value, min, max) { - var val = parseFloat(value); + let val = parseFloat(value); return val >= min && val <= max; } @@ -162,7 +159,7 @@ var gs_base = exports; * @returns {number} */ function round(v, zeros) { - var pow = Math.pow(10,zeros || round_decimal_precision); + let pow = Math.pow(10,zeros || round_decimal_precision); return Math.round(v * pow) / pow; } @@ -178,7 +175,7 @@ var gs_base = exports; * @returns {?Point | String} */ function intersect(p1, p2, p3, p4, test, parallelok) { - var keys = BASE.key, + let keys = BASE.key, p1x = p1.x, p1y = p1.y, p2x = p2.x, @@ -199,7 +196,7 @@ var gs_base = exports; return test && !parallelok ? null : keys.PARALLEL; } - var a = p1y - p3y, // origin dy + let a = p1y - p3y, // origin dy b = p1x - p3x, // origin dx n1 = (d2x * a) - (d2y * b), n2 = (d1x * a) - (d1y * b); @@ -207,7 +204,7 @@ var gs_base = exports; a = n1 / d; // roughly distance from l1 origin to l2 intersection b = n2 / d; // roughly distance from l2 origin to l1 intersection - var ia = a >= -0.0001 && a <= 1.0001, + let ia = a >= -0.0001 && a <= 1.0001, ib = b >= -0.0001 && b <= 1.0001, segint = (ia && ib), rayint = (a >= 0 && b >= 0); @@ -215,7 +212,7 @@ var gs_base = exports; if (test === keys.SEGINT && !segint) return null; if (test === keys.RAYINT && !rayint) return null; - var ip = BASE.newPoint( + let ip = BASE.newPoint( p1x + (a * d1x), // x p1y + (a * d1y), // y p3.z || p4.z, // z @@ -240,7 +237,7 @@ var gs_base = exports; * @returns {?Point} */ function intersectRayLine(ro, s1, p1, p2, infinite) { - var keys = BASE.key, + let keys = BASE.key, p1x = ro.x, p1y = ro.y, s1x = s1.dx, @@ -253,7 +250,7 @@ var gs_base = exports; s2y = p4y - p3y, d = (s2y * s1x) - (s2x * s1y); - var a = p1y - p3y, + let a = p1y - p3y, b = p1x - p3x, n1 = (s2x * a) - (s2y * b), n2 = (s1x * a) - (s1y * b); @@ -267,7 +264,7 @@ var gs_base = exports; b = n2 / d; if (infinite || (inCloseRange(b,0,1) && a >= 0)) { - var ip = BASE.newPoint( + let ip = BASE.newPoint( p1x + (a * s1x), p1y + (a * s1y), p2.z || ro.z, @@ -289,7 +286,7 @@ var gs_base = exports; * @returns {number} */ function determinant(p1, p2, p3, p4) { - var d1x = (p2.x - p1.x), + let d1x = (p2.x - p1.x), d1y = (p2.y - p1.y), d2x = (p4.x - p3.x), d2y = (p4.y - p3.y); diff --git a/js/geo-bounds.js b/src/geo/bounds.js similarity index 81% rename from js/geo-bounds.js rename to src/geo/bounds.js index 739ec3ee..9b6b6744 100644 --- a/js/geo-bounds.js +++ b/src/geo/bounds.js @@ -2,11 +2,8 @@ "use strict"; -var gs_base_bounds = exports; - (function() { - if (!self.base) self.base = {}; if (self.base.Bounds) return; /** @@ -21,12 +18,9 @@ var gs_base_bounds = exports; this.leftMost = null; } - var BASE = self.base, + const BASE = self.base, UTIL = BASE.util, CONF = BASE.config, - ABS = Math.abs, - MIN = Math.min, - MAX = Math.max, PRO = Bounds.prototype; BASE.Bounds = Bounds; @@ -40,7 +34,7 @@ var gs_base_bounds = exports; * @returns {Bounds} */ PRO.clone = function() { - var b = new Bounds(); + let b = new Bounds(); b.minx = this.minx; b.miny = this.miny; b.maxx = this.maxx; @@ -60,20 +54,20 @@ var gs_base_bounds = exports; * @param {Bounds} b */ PRO.merge = function(b) { - this.minx = MIN(this.minx, b.minx); - this.maxx = MAX(this.maxx, b.maxx); - this.miny = MIN(this.miny, b.miny); - this.maxy = MAX(this.maxy, b.maxy); + this.minx = Math.min(this.minx, b.minx); + this.maxx = Math.max(this.maxx, b.maxx); + this.miny = Math.min(this.miny, b.miny); + this.maxy = Math.max(this.maxy, b.maxy); }; /** * @param {Point} p */ PRO.update = function(p) { - this.minx = MIN(this.minx, p.x); - this.maxx = MAX(this.maxx, p.x); - this.miny = MIN(this.miny, p.y); - this.maxy = MAX(this.maxy, p.y); + this.minx = Math.min(this.minx, p.x); + this.maxx = Math.max(this.maxx, p.x); + this.miny = Math.min(this.miny, p.y); + this.maxy = Math.max(this.maxy, p.y); if (this.minx === p.x) this.leftMost = p; }; @@ -109,8 +103,8 @@ var gs_base_bounds = exports; */ PRO.overlaps = function(b, precision) { return ( - ABS(this.centerx() - b.centerx()) * 2 - precision < this.width() + b.width() && - ABS(this.centery() - b.centery()) * 2 - precision < this.height() + b.height() + Math.abs(this.centerx() - b.centerx()) * 2 - precision < this.width() + b.width() && + Math.abs(this.centery() - b.centery()) * 2 - precision < this.height() + b.height() ); }; diff --git a/js/geo-debug.js b/src/geo/debug.js similarity index 94% rename from js/geo-debug.js rename to src/geo/debug.js index 4bd0b103..bbb156c7 100644 --- a/js/geo-debug.js +++ b/src/geo/debug.js @@ -2,21 +2,19 @@ "use strict"; -var gs_base_debug = exports; - (function() { - if (!self.base) self.base = {}; if (self.base.debug) return; - var base = self.base, - enabled = false, + const base = self.base, flags = {}, stash = [], - size = 20, - next_debug_color = 0, debug_colors = [0xff0000, 0x00ff00, 0x0000ff, 0x00ffff, 0xff00ff, 0xffff00]; + let size = 20, + enabled = false, + next_debug_color = 0; + /** ****************************************************************** * Debug Functions ******************************************************************* */ @@ -69,7 +67,7 @@ var gs_base_debug = exports; function set(f, value) { if (Array.isArray(f)) { - for (var i=0; i -- All Rights Reserved */ "use strict"; -var gs_base_line = exports; - (function() { - if (!self.base) self.base = {}; if (self.base.Line) return; + const BASE = self.base, PRO = Line.prototype; + + BASE.Line = Line; + BASE.newLine = newLine; + BASE.newOrderedLine = newOrderedLine; + /** * * @param {Point} p1 @@ -26,13 +29,6 @@ var gs_base_line = exports; this.del = false; } - var BASE = self.base, - PRO = Line.prototype; - - BASE.Line = Line; - BASE.newLine = newLine; - BASE.newOrderedLine = newOrderedLine; - /** ****************************************************************** * Line Prototype Functions ******************************************************************* */ @@ -62,7 +58,7 @@ var gs_base_line = exports; * @returns {Line} */ PRO.reverse = function() { - var t = this.p1; + let t = this.p1; this.p1 = this.p2; this.p2 = t; return this; @@ -80,7 +76,7 @@ var gs_base_line = exports; * @returns {boolean} */ PRO.isCollinear = function(line) { - var p1 = this.p1, + let p1 = this.p1, p2 = this.p2, p3 = line.p1, p4 = line.p2, diff --git a/js/geo-point.js b/src/geo/point.js similarity index 93% rename from js/geo-point.js rename to src/geo/point.js index 8c686014..5da90311 100644 --- a/js/geo-point.js +++ b/src/geo/point.js @@ -1,14 +1,21 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_base_point = exports; - (function() { - if (!self.base) self.base = {}; if (self.base.Point) return; + const BASE = self.base, + UTIL = BASE.util, + CONF = BASE.config, + KEYS = BASE.key, + ROUND = UTIL.round, + PRO = Point.prototype; + + BASE.Point = Point; + BASE.newPoint = newPoint; + /** * * @param {number} x @@ -44,16 +51,6 @@ var gs_base_point = exports; this.group = null; // for grouping in slice intersect, offset lines in trace } - var BASE = self.base, - UTIL = BASE.util, - CONF = BASE.config, - KEYS = BASE.key, - ROUND = UTIL.round, - PRO = Point.prototype; - - BASE.Point = Point; - BASE.newPoint = newPoint; - /** ****************************************************************** * Point Prototype Functions ******************************************************************* */ @@ -64,14 +61,14 @@ var gs_base_point = exports; } PRO.swapXZ = function() { - var p = this, + let p = this, t = p.x; p.x = p.z; p.z = t; }; PRO.swapYZ = function() { - var p = this, + let p = this, t = p.y; p.y = p.z; p.z = t; @@ -163,10 +160,10 @@ var gs_base_point = exports; * @returns {number} */ PRO.distToLineSq = function(p1, p2) { - var p = this, + let p = this, d = UTIL.distSq(p1, p2); - var t = ((p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y) * (p2.y - p1.y)) / d; + let t = ((p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y) * (p2.y - p1.y)) / d; if (t < 0) return UTIL.distSq(p, p1); if (t > 1) return UTIL.distSq(p, p2); @@ -189,16 +186,16 @@ var gs_base_point = exports; } function p2l(p, l1, l2) { - var v = {x: l2.x - l1.x, y: l2.y - l1.y}; - var w = {x: p.x - l1.x, y: p.y - l1.y}; - var c1 = dot(w, v); - var c2 = dot(v, v); - var b = c1 / c2; + let v = {x: l2.x - l1.x, y: l2.y - l1.y}; + let w = {x: p.x - l1.x, y: p.y - l1.y}; + let c1 = dot(w, v); + let c2 = dot(v, v); + let b = c1 / c2; if (isNaN(b)) { // console.log('nan', {p, l1, l2, v, w, c1, c2}); b = 0; } - var pb = {x: l1.x + b * v.x, y: l1.y + b * v.y}; + let pb = {x: l1.x + b * v.x, y: l1.y + b * v.y}; return d(p, pb); } @@ -212,7 +209,7 @@ var gs_base_point = exports; * @returns {boolean} */ PRO.withinDist2 = function(p1, p2, dist2) { - var ll2 = p1.distToSq2D(p2), + let ll2 = p1.distToSq2D(p2), dp1 = this.distToSq2D(p1), dp2 = this.distToSq2D(p2); // if the line segment described is less than dist2 @@ -277,7 +274,7 @@ var gs_base_point = exports; * @param dist */ PRO.offsetPointFrom = function(p2, dist) { - var p1 = this, + let p1 = this, dx = p2.x - p1.x, dy = p2.y - p1.y, ls = dist / Math.sqrt(dx * dx + dy * dy), @@ -313,7 +310,7 @@ var gs_base_point = exports; * @returns {Line} */ PRO.offsetLineTo = function(p2, offset) { - var p1 = this, + let p1 = this, dx = p2.x - p1.x, dy = p2.y - p1.y, ls = offset / Math.sqrt(dx * dx + dy * dy), @@ -340,7 +337,7 @@ var gs_base_point = exports; PRO.inPolygon = function(poly) { if (!poly.bounds.containsXY(this.x, this.y)) return false; - var p = poly.points, pl = p.length, p1, p2, i, inside = false; + let p = poly.points, pl = p.length, p1, p2, i, inside = false; for (i=0; i 0; if ((c.x - a.x) * as_y - (c.y - a.y) * as_x > 0 == s_ab) return false; diff --git a/js/geo-polygon.js b/src/geo/polygon.js similarity index 94% rename from js/geo-polygon.js rename to src/geo/polygon.js index 3f984619..740fe42f 100644 --- a/js/geo-polygon.js +++ b/src/geo/polygon.js @@ -1,15 +1,12 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_base_polygon = exports; - (function() { - if (!self.base) self.base = {}; if (self.base.Polygon) return; - var BASE = self.base, + const BASE = self.base, CONF = BASE.config, UTIL = BASE.util, DBUG = BASE.debug, @@ -21,12 +18,11 @@ var gs_base_polygon = exports; MAX = Math.max, PI = Math.PI, DEG2RAD = PI / 180, - Bounds = BASE.Bounds, newPoint = BASE.newPoint, - PRO = Polygon.prototype, - nest_test_slope = BASE.newSlope(newPoint(0,0,0,KEYS.NONE), newPoint(1,0,0,KEYS.NONE)), - min_area_mult = 2.0, - seqid = 1; + Bounds = BASE.Bounds, + PRO = Polygon.prototype; + + let seqid = 1; BASE.Polygon = Polygon; BASE.newPolygon = newPolygon; @@ -97,9 +93,9 @@ var gs_base_polygon = exports; Polygon.filterChain = function(filters) { return function() { - var f = filters; + let f = filters; return function(p) { - var len = f.length, + let len = f.length, idx = 0; while (idx < len && (p = f[idx++](p))) ; @@ -213,8 +209,8 @@ var gs_base_polygon = exports; PRO.createConvexHull = function(points) { function removeMiddle(a, b, c) { - var cross = (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x); - var dot = (a.x - b.x) * (c.x - b.x) + (a.y - b.y) * (c.y - b.y); + let cross = (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x); + let dot = (a.x - b.x) * (c.x - b.x) + (a.y - b.y) * (c.y - b.y); return cross < 0 || cross == 0 && dot <= 0; } @@ -222,11 +218,11 @@ var gs_base_polygon = exports; return a.x != b.x ? a.x - b.x : a.y - b.y; }); - var n = points.length; - var hull = []; + let n = points.length; + let hull = []; - for (var i = 0; i < 2 * n; i++) { - var j = i < n ? i : 2 * n - 1 - i; + for (let i = 0; i < 2 * n; i++) { + let j = i < n ? i : 2 * n - 1 - i; while (hull.length >= 2 && removeMiddle(hull[hull.length - 2], hull[hull.length - 1], points[j])) hull.pop(); hull.push(points[j]); @@ -239,7 +235,7 @@ var gs_base_polygon = exports; }; PRO.stepsFromRoot = function() { - var p = this.parent, steps = 0; + let p = this.parent, steps = 0; while (p) { if (p.inner && p.inner.length > 1) steps++; p = p.parent; @@ -256,11 +252,11 @@ var gs_base_polygon = exports; }; PRO.swap = function(x,y) { - var poly = this, + let poly = this, points = poly.points, length = points.length; poly.bounds = new Bounds(); - for (var i=0; i 0) { this.push(newPoint( @@ -406,7 +402,7 @@ var gs_base_polygon = exports; * @returns {Polygon} */ PRO.move = function(offset) { - var scope = this, + let scope = this, bounds = scope.bounds = new Bounds(); scope.points.forEach(function(p) { p.move(offset); @@ -417,7 +413,7 @@ var gs_base_polygon = exports; }; PRO.scale = function(scale, round) { - var scope = this, + let scope = this, bounds = scope.bounds = new Bounds(); scope.points.forEach(function(p) { p.x *= scale; @@ -437,7 +433,7 @@ var gs_base_polygon = exports; * hint fill angle hinting from longest segment */ PRO.hintFillAngle = function() { - var index = 0, + let index = 0, points = this.points, length = points.length, prev, @@ -471,7 +467,7 @@ var gs_base_polygon = exports; * @returns {Polygon} */ PRO.clone = function(deep) { - var np = newPolygon(), + let np = newPolygon(), ln = this.length, i = 0; @@ -495,7 +491,7 @@ var gs_base_polygon = exports; * @returns {Polygon} this */ PRO.setZ = function(z) { - var ar = this.points, + let ar = this.points, ln = ar.length, i = 0; while (i < ln) ar[i++].z = z; @@ -545,7 +541,7 @@ var gs_base_polygon = exports; * @returns {Polygon} */ PRO.addPoints = function(points) { - var poly = this, + let poly = this, length = points.length, i = 0; while (i < length) { @@ -667,7 +663,7 @@ var gs_base_polygon = exports; */ PRO.isNested = function(parent) { if (parent.bounds.contains(this.bounds)) { - //var int = POLY().rayIntersect(this.bounds.leftMost, nest_test_slope, [parent], false); + //let int = POLY().rayIntersect(this.bounds.leftMost, nest_test_slope, [parent], false); //return int.length % 2 === 1 || this.isInside(parent, CONF.precision_nested_sq); return this.isInside(parent, CONF.precision_nested_sq); } @@ -675,7 +671,7 @@ var gs_base_polygon = exports; }; PRO.forEachPointEaseDown = function(fn, fromPoint) { - var index = this.findClosestPointTo(fromPoint).index, + let index = this.findClosestPointTo(fromPoint).index, fromZ = fromPoint.z, offset = 0, points = this.points, @@ -690,7 +686,7 @@ var gs_base_polygon = exports; while (true) { next = points[index % length]; if (last && next.z < fromZ) { - var deltaZ = fromZ - next.z; + let deltaZ = fromZ - next.z; dist2next = last.distTo2D(next); if (dist2next > deltaZ * 2) { // too long: synth intermediate @@ -716,7 +712,7 @@ var gs_base_polygon = exports; }; PRO.forEachPoint = function(fn, close, start) { - var index = start || 0, + let index = start || 0, points = this.points, length = points.length, count = close ? length + 1 : length, @@ -731,7 +727,7 @@ var gs_base_polygon = exports; }; PRO.forEachSegment = function(fn, open, start) { - var index = start || 0, + let index = start || 0, points = this.points, length = points.length, count = open ? length - 1 : length, @@ -749,9 +745,9 @@ var gs_base_polygon = exports; * returns intersections sorted by closest to lp1 */ PRO.intersections = function(lp1, lp2) { - var list = []; + let list = []; this.forEachSegment(function(pp1, pp2, ip1, ip2) { - var int = UTIL.intersect(lp1, lp2, pp1, pp2, BASE.key.SEGINT, false); + let int = UTIL.intersect(lp1, lp2, pp1, pp2, BASE.key.SEGINT, false); if (int) { list.push(int); pp1.pos = ip1; @@ -771,9 +767,9 @@ var gs_base_polygon = exports; PRO.bisect = function(p1, p2) { if (this.isOpen()) return null; - var copy = this.clone().setClockwise(); + let copy = this.clone().setClockwise(); - var int = copy.intersections(p1, p2); + let int = copy.intersections(p1, p2); if (!int || int.length !== 2) return null; return [ copy.emitSegment(int[0], int[1]), copy.emitSegment(int[1], int[0]).reverse() ]; @@ -784,7 +780,7 @@ var gs_base_polygon = exports; * used in cam tabs and fdm output perimeter traces on infill */ PRO.emitSegment = function(i1, i2) { - var poly = newPolygon(), + let poly = newPolygon(), start = i1.p2.pos, end = i2.p1.pos; poly.setOpen(); @@ -805,7 +801,7 @@ var gs_base_polygon = exports; PRO.hasPointsInside = function(poly, tolerance) { if (!poly.overlaps(this)) return false; - var mid, exit = false; + let mid, exit = false; this.forEachSegment(function(prev, next) { // check midpoint on long lines @@ -837,7 +833,7 @@ var gs_base_polygon = exports; this.bounds.isNested(poly.bounds) )) return false; - var mid, + let mid, midcheck, exit = true; @@ -875,7 +871,7 @@ var gs_base_polygon = exports; */ PRO.containedBySet = function(polys) { if (!polys) return false; - for (var i=0; i poly.area() ? this.fillang : poly.fillang, + let fillang = this.fillang && this.area() > poly.area() ? this.fillang : poly.fillang, clib = self.ClipperLib, ctyp = clib.ClipType, ptyp = clib.PolyType, @@ -1222,7 +1218,7 @@ var gs_base_polygon = exports; * @returns {?Polygon[]} */ PRO.mask = function(poly) { - var fillang = this.fillang && this.area() > poly.area() ? this.fillang : poly.fillang, + let fillang = this.fillang && this.area() > poly.area() ? this.fillang : poly.fillang, clib = self.ClipperLib, ctyp = clib.ClipType, ptyp = clib.PolyType, @@ -1287,7 +1283,7 @@ var gs_base_polygon = exports; PRO.union = function(poly, min) { if (!this.overlaps(poly)) return null; - var fillang = this.fillang && this.area() > poly.area() ? this.fillang : poly.fillang, + let fillang = this.fillang && this.area() > poly.area() ? this.fillang : poly.fillang, clib = self.ClipperLib, ctyp = clib.ClipType, ptyp = clib.PolyType, @@ -1318,7 +1314,7 @@ var gs_base_polygon = exports; * furthest apart and lowest when there is a tie breaker */ PRO.spread = function() { - var poly = this, + let poly = this, points = poly.points, plen = points.length, i, pp, np, p, mdelta, newmax, max, shift, maxd; diff --git a/js/geo-polygons.js b/src/geo/polygons.js similarity index 90% rename from js/geo-polygons.js rename to src/geo/polygons.js index 2ea4ac83..32bf07b6 100644 --- a/js/geo-polygons.js +++ b/src/geo/polygons.js @@ -1,15 +1,13 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_base_polygons = exports; - (function() { if (!self.base) self.base = {}; if (self.base.polygons) return; - var BASE = self.base, + const BASE = self.base, UTIL = BASE.util, CONF = BASE.config, DEG2RAD = Math.PI / 180, @@ -30,6 +28,7 @@ var gs_base_polygons = exports; trimTo : trimTo, expand2 : expand2, expand : expand, + expand_lines: expand_lines, union : union, nest : nest, diff : doDiff, @@ -48,13 +47,13 @@ var gs_base_polygons = exports; ******************************************************************* */ function toClipper(polys,debug) { - var out = []; + let out = []; polys.forEach(function(poly) { poly.toClipper(out,debug) }); return out; } function fromClipperNode(tnode, z) { - var poly = BASE.newPolygon(); + let poly = BASE.newPolygon(); tnode.m_polygon.forEach(function(p) { poly.push(newPoint(null, null, z, null, p)); }); @@ -63,7 +62,7 @@ var gs_base_polygons = exports; }; function fromClipperTree(tnode, z, tops, parent, minarea) { - var polys = tops || [], + let polys = tops || [], poly, min = minarea || 0.1; @@ -108,7 +107,7 @@ var gs_base_polygons = exports; }; function cleanClipperTree(tree) { - var clib = self.ClipperLib, + let clib = self.ClipperLib, clip = clib.Clipper; if (tree.m_Childs) tree.m_Childs.forEach(function(child) { @@ -151,7 +150,7 @@ var gs_base_polygons = exports; polygons.sort(function (a, b) { return a.area() - b.area(); }); - var i, poly; + let i, poly; // clear parent/child links if they exist for (i = 0; i < polygons.length; i++) { poly = polygons[i]; @@ -162,8 +161,8 @@ var gs_base_polygons = exports; for (i = 0; i < polygons.length - 1; i++) { poly = polygons[i]; // find the smallest suitable parent - for (var j = i + 1; j < polygons.length; j++) { - var parent = polygons[j]; + for (let j = i + 1; j < polygons.length; j++) { + let parent = polygons[j]; // prevent open polys from having inners if (opentop && parent.isOpen()) continue; if (poly.isNested(parent)) { @@ -173,7 +172,7 @@ var gs_base_polygons = exports; } } // tops have an even # depth - var tops = [], + let tops = [], p; // assign a depth level to each group for (i = 0; i < polygons.length; i++) { @@ -207,7 +206,7 @@ var gs_base_polygons = exports; */ function setWinding(array, CW, recurse) { if (!array) return; - var poly, i = 0; + let poly, i = 0; while (i < array.length) { poly = array[i++]; if (poly.isClockwise() !== CW) poly.reverse(); @@ -223,7 +222,7 @@ var gs_base_polygons = exports; * @return {boolean} true if aligned clockwise */ function alignWindings(polys) { - var len = polys.length, + let len = polys.length, fwd = 0, pts = 0, i = 0, @@ -244,7 +243,7 @@ var gs_base_polygons = exports; } function setContains(setA, poly) { - for (var i=0; i 0) { @@ -596,7 +614,7 @@ var gs_base_polygons = exports; function fillArea(polys, angle, spacing, output, minLen, maxLen) { if (polys.length === 0) return; - var i = 1, + let i = 1, p0 = polys[0], zpos = p0.getZ(), bounds = p0.bounds.clone(), @@ -616,7 +634,7 @@ var gs_base_polygons = exports; while (i < polys.length) bounds.merge(polys[i++].bounds); // ray stepping is an axis from the line perpendicular to the ray - var rayint = output || [], + let rayint = output || [], stepX = -raySlope.dy, stepY = raySlope.dx, iterX = ABS(ABS(stepX) > 0 ? bounds.width() / stepX : 0), @@ -639,7 +657,7 @@ var gs_base_polygons = exports; rayint.origin = newPoint(start.x, start.y, start.z); for (i = 0; i < steps; i++) { - var p1 = newPoint(start.x - raySlope.dx * 1000, start.y - raySlope.dy * 1000, zpos, NOKEY), + let p1 = newPoint(start.x - raySlope.dx * 1000, start.y - raySlope.dy * 1000, zpos, NOKEY), p2 = newPoint(start.x + raySlope.dx * 1000, start.y + raySlope.dy * 1000, zpos, NOKEY); lines.push([p1,p2]); @@ -655,13 +673,13 @@ var gs_base_polygons = exports; if (clip.Execute(ctyp.ctIntersection, ctre, cfil.pftNonZero, cfil.pftEvenOdd)) { ctre.m_AllPolys.forEach(function(poly) { if (minlen || maxlen) { - var plen = clib.JS.PerimeterOfPath(poly.m_polygon, false, 1); + let plen = clib.JS.PerimeterOfPath(poly.m_polygon, false, 1); if (minlen && plen < minlen) return; if (maxlen && plen > maxlen) return; } - var p1 = newPoint(null,null,zpos,null,poly.m_polygon[0]); - var p2 = newPoint(null,null,zpos,null,poly.m_polygon[1]); - var od = rayint.origin.distToLineNew(p1,p2) / spacing; + let p1 = newPoint(null,null,zpos,null,poly.m_polygon[0]); + let p2 = newPoint(null,null,zpos,null,poly.m_polygon[1]); + let od = rayint.origin.distToLineNew(p1,p2) / spacing; lines.push([p1, p2, od]); }); } @@ -671,7 +689,7 @@ var gs_base_polygons = exports; }) lines.forEach(function(line) { - var dist = Math.round(line[2]); + let dist = Math.round(line[2]); line[0].index = dist; line[1].index = dist; rayint.push(line[0]); @@ -692,7 +710,7 @@ var gs_base_polygons = exports; * @returns {Point[]} */ function rayIntersect(start, slope, polygons, for_fill) { - var i = 0, + let i = 0, flat = [], points = [], conf = BASE.config, @@ -703,13 +721,13 @@ var gs_base_polygons = exports; }); polygons = flat; while (i < polygons.length) { - var polygon = polygons[i++], + let polygon = polygons[i++], pp = polygon.points, pl = pp.length, dbug = BASE.debug, debug = false; - for (var j = 0; j < pl; j++) { - var j2 = (j + 1) % pl, + for (let j = 0; j < pl; j++) { + let j2 = (j + 1) % pl, ip = UTIL.intersectRayLine(start, slope, pp[j], pp[j2]); if (ip) { // add group object to point for cull detection @@ -732,12 +750,12 @@ var gs_base_polygons = exports; } } if (points.length > 0) { - var del = false; + let del = false; // sort on distance from ray origin points.sort(function (p1, p2) { // handle passing through line-common end points if (!(p1.del || p2.del) && p1.isNear(p2, merge_dist)) { - var line = []; + let line = []; if (!p1.isNear(p1.p1, merge_dist)) line.push(p1.p1); if (!p1.isNear(p1.p2, merge_dist)) line.push(p1.p2); if (!p2.isNear(p2.p1, merge_dist)) line.push(p2.p1); @@ -780,7 +798,7 @@ var gs_base_polygons = exports; * ok = diff level (even-odd) */ if (for_fill) { - var p1, p2; + let p1, p2; i = 0; pl = points.length; while (i < pl) { @@ -789,7 +807,7 @@ var gs_base_polygons = exports; p2 = points[i++]; while (p2 && p2.del && i < pl) p2 = points[i++]; if (p1 && p2 && p1.group && p1.group) { - var p1g = p1.group, + let p1g = p1.group, p2g = p2.group, even = (p1g.depth % 2 === 0), // point is on an even depth group same = (p1g === p2g); // points intersect same group @@ -803,7 +821,7 @@ var gs_base_polygons = exports; //} // check cull co-linear with group edge if (same && p1.mod && p2.mod) { - var diff = ABS(p1.pos - p2.pos); + let diff = ABS(p1.pos - p2.pos); if (diff === 1 || diff === p1.mod - 1) { p1.del = true; p2.del = true; @@ -817,9 +835,9 @@ var gs_base_polygons = exports; } // handle deletions, if found if (del) { - var np = []; + let np = []; for (i = 0; i < points.length; i++) { - var p = points[i]; + let p = points[i]; if (!p.del) { np.push(p); } diff --git a/js/geo-render.js b/src/geo/render.js similarity index 86% rename from js/geo-render.js rename to src/geo/render.js index b21bd943..866fcc1b 100644 --- a/js/geo-render.js +++ b/src/geo/render.js @@ -1,17 +1,15 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_base_render = exports; - (function() { if (!self.base) self.base = {}; if (self.base.render) return; - var BASE = self.base, - line_width = 1, - materialCache = {}; + const BASE = self.base, + materialCache = {}, + line_width = 1; BASE.render = { wireframe : wireframe @@ -32,11 +30,11 @@ var gs_base_render = exports; */ function wireframe(group, points, color) { if (points.length % 3 != 0) throw "invalid line : "+points.length; - var lines = new THREE.Geometry(), + let lines = new THREE.Geometry(), hash = {}, added = 0; - for (var i = 0; i < points.length; i += 3) { - var p1 = points[i], + for (let i = 0; i < points.length; i += 3) { + let p1 = points[i], p2 = points[i + 1], p3 = points[i + 2], l1 = newOrderedLine(p1, p2), @@ -59,7 +57,7 @@ var gs_base_render = exports; } } lines.verticesNeedUpdate = true; - var mesh = new THREE.LineSegments(lines, getMaterial(color)); + let mesh = new THREE.LineSegments(lines, getMaterial(color)); group.add(mesh); return mesh; } @@ -73,7 +71,7 @@ var gs_base_render = exports; * @returns {THREE.LineBasicMaterial} */ function getMaterial(color) { - var material = materialCache[color]; + let material = materialCache[color]; if (!material) { material = new THREE.LineBasicMaterial({ fog:false, diff --git a/js/geo-slope.js b/src/geo/slope.js similarity index 91% rename from js/geo-slope.js rename to src/geo/slope.js index 565a698c..93f747d1 100644 --- a/js/geo-slope.js +++ b/src/geo/slope.js @@ -1,14 +1,27 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_base_slope = exports; - (function() { - if (!self.base) self.base = {}; if (self.base.Slope) return; + const BASE = self.base, + CONF = BASE.config, + ABS = Math.abs, + PRO = Slope.prototype, + DEG2RAD = Math.PI / 180, + RAD2DEG = 180 / Math.PI; + + BASE.Slope = Slope; + BASE.newSlope = newSlope; + BASE.newSlopeFromAngle = function(angle) { + return newSlope(0,0, + Math.cos(angle * DEG2RAD), + Math.sin(angle * DEG2RAD) + ); + }; + /** * * @param p1 @@ -23,23 +36,6 @@ var gs_base_slope = exports; this.angle = Math.atan2(this.dy, this.dx) * RAD2DEG; } - var BASE = self.base, - CONF = BASE.config, - ABS = Math.abs, - PRO = Slope.prototype, - DEG2RAD = Math.PI / 180, - RAD2DEG = 180 / Math.PI; - - BASE.Slope = Slope; - BASE.newSlope = newSlope; - - BASE.newSlopeFromAngle = function(angle) { - return newSlope(0,0, - Math.cos(angle * DEG2RAD), - Math.sin(angle * DEG2RAD) - ); - }; - /** ****************************************************************** * Slope Prototype Functions ******************************************************************* */ @@ -57,7 +53,7 @@ var gs_base_slope = exports; if (ABS(this.dx) <= CONF.precision_merge && ABS(s.dx) <= CONF.precision_merge) return true; if (ABS(this.dy) <= CONF.precision_merge && ABS(s.dy) <= CONF.precision_merge) return true; // check angle within a range - var prec = Math.min(1/Math.sqrt(this.dx * this.dx + this.dy * this.dy), CONF.precision_slope_merge); + let prec = Math.min(1/Math.sqrt(this.dx * this.dx + this.dy * this.dy), CONF.precision_slope_merge); return angleWithinDelta(this.angle, s.angle, prec || CONF.precision_slope); }; @@ -67,7 +63,7 @@ var gs_base_slope = exports; * @returns {Slope} */ PRO.normal = function() { - var t = this.dx; + let t = this.dx; this.dx = -this.dy; this.dy = t; this.angle = Math.atan2(this.dy, this.dx) * RAD2DEG; @@ -75,7 +71,7 @@ var gs_base_slope = exports; }; PRO.toUnit = function() { - var max = Math.max(ABS(this.dx), ABS(this.dy)); + let max = Math.max(ABS(this.dx), ABS(this.dy)); this.dx = this.dx / max; this.dy = this.dy / max; return this; diff --git a/js/geo-wasm.js b/src/geo/wasm.js similarity index 97% rename from js/geo-wasm.js rename to src/geo/wasm.js index 0f75c0df..5a9cc260 100644 --- a/js/geo-wasm.js +++ b/src/geo/wasm.js @@ -1,10 +1,9 @@ +/** Copyright Stewart Allen -- All Rights Reserved */ + "use strict"; -var gs_wasm = exports; - // only active in workers -if (!self.window) -(function() { +if (!self.window) (function() { if (!self.geo) self.geo = {}; diff --git a/src/ico/cnc.svg b/src/ico/cnc.svg new file mode 100644 index 00000000..857b7dca --- /dev/null +++ b/src/ico/cnc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ico/fdm.svg b/src/ico/fdm.svg new file mode 100644 index 00000000..07acde06 --- /dev/null +++ b/src/ico/fdm.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ico/laser.svg b/src/ico/laser.svg new file mode 100644 index 00000000..f7dd21bf --- /dev/null +++ b/src/ico/laser.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/ico/sla.svg b/src/ico/sla.svg new file mode 100644 index 00000000..53268e1e --- /dev/null +++ b/src/ico/sla.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/kiri.js b/src/kiri.js new file mode 100644 index 00000000..83708208 --- /dev/null +++ b/src/kiri.js @@ -0,0 +1,11 @@ +/** Copyright Stewart Allen -- All Rights Reserved */ + +"use strict"; + +(function () { + + if (self.kiri) return; + + self.kiri = { }; + +})(); diff --git a/js/kiri-codec.js b/src/kiri/codec.js similarity index 85% rename from js/kiri-codec.js rename to src/kiri/codec.js index f0488ec2..bdb1977a 100644 --- a/js/kiri-codec.js +++ b/src/kiri/codec.js @@ -1,19 +1,14 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_kiri_codec = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.codec) return; - var base = self.base, - kiri = self.kiri, - handlers = {}; + const BASE = self.base, KIRI = self.kiri, handlers = {}; - kiri.codec = { + KIRI.codec = { encode: encode, decode: decode, registerDecoder: registerDecoder @@ -24,7 +19,7 @@ var gs_kiri_codec = exports; if (o === null) return null; if (o === undefined) return undefined; if (Array.isArray(o)) { - var arr = new Array(o.length), i=0; + let arr = new Array(o.length), i=0; while (i < o.length) arr[i] = encode(o[i++], state); return arr; } @@ -44,7 +39,7 @@ var gs_kiri_codec = exports; if (o === null) return null; if (o === undefined) return undefined; if (Array.isArray(o)) { - for (var i=0; i < o.length; i++) o[i] = decode(o[i],state); + for (let i=0; i < o.length; i++) o[i] = decode(o[i],state); return o; } switch (typeof(o)) { @@ -64,8 +59,8 @@ var gs_kiri_codec = exports; function genOEncode(o, state) { if (o instanceof Float32Array) return o; - var out = {}; - for (var k in o) { + let out = {}; + for (let k in o) { if (o.hasOwnProperty(k)) out[k] = encode(o[k], state); } return out; @@ -73,8 +68,8 @@ var gs_kiri_codec = exports; function genODecode(o, state) { if (o instanceof Float32Array) return o; - var out = {}; - for (var k in o) { + let out = {}; + for (let k in o) { if (o.hasOwnProperty(k)) out[k] = decode(o[k], state); } return out; @@ -84,7 +79,7 @@ var gs_kiri_codec = exports; * Object CODEC Functions ******************************************************************* */ - kiri.Slice.prototype.encode = function(state) { + KIRI.Slice.prototype.encode = function(state) { return { type: 'slice', z: this.z, @@ -100,7 +95,7 @@ var gs_kiri_codec = exports; }; registerDecoder('slice', function(v, state) { - var slice = kiri.newSlice(v.z, state.mesh ? state.mesh.newGroup() : null); + let slice = KIRI.newSlice(v.z, state.mesh ? state.mesh.newGroup() : null); slice.index = v.index; slice.camMode = v.camMode; @@ -114,7 +109,7 @@ var gs_kiri_codec = exports; return slice; }); - kiri.Top.prototype.encode = function(state) { + KIRI.Top.prototype.encode = function(state) { return { type: 'top', poly: encode(this.poly, state), @@ -129,7 +124,7 @@ var gs_kiri_codec = exports; }; registerDecoder('top', function(v, state) { - var top = kiri.newTop(decode(v.poly, state)); + let top = KIRI.newTop(decode(v.poly, state)); top.traces = decode(v.traces, state); top.inner = decode(v.inner, state); @@ -145,7 +140,7 @@ var gs_kiri_codec = exports; function encodePointArray(points, state) { if (!points) return null; - var array = new Float32Array(points.length * 3), + let array = new Float32Array(points.length * 3), pos = 0; points.forEach(function(point) { @@ -174,21 +169,21 @@ var gs_kiri_codec = exports; function decodePointArray(array) { if (!array) return null; - var vid = 0, + let vid = 0, pid = 0, points = new Array(array.length/3); while (vid < array.length) { - points[pid++] = base.newPoint(array[vid++], array[vid++], array[vid++]); + points[pid++] = BASE.newPoint(array[vid++], array[vid++], array[vid++]); } return points; } - base.Polygon.prototype.encode = function(state) { + BASE.Polygon.prototype.encode = function(state) { if (!state.poly) state.poly = {}; - var cached = state.poly[this.id]; + let cached = state.poly[this.id]; if (cached) { return { @@ -216,11 +211,11 @@ var gs_kiri_codec = exports; if (v.ref) return state.poly[v.ref]; - var poly = base.newPolygon(), + let poly = BASE.newPolygon(), vid = 0; while (vid < v.array.length) { - poly.push(base.newPoint(v.array[vid++], v.array[vid++], v.array[vid++])); + poly.push(BASE.newPoint(v.array[vid++], v.array[vid++], v.array[vid++])); } poly.id = v.id; diff --git a/js/kiri-conf.js b/src/kiri/conf.js similarity index 98% rename from js/kiri-conf.js rename to src/kiri/conf.js index b3bb2859..e65ba093 100644 --- a/js/kiri-conf.js +++ b/src/kiri/conf.js @@ -1,17 +1,12 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_conf = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.conf) return; - let KIRI = self.kiri, - CVER = 185, - clone = Object.clone; + const KIRI = self.kiri, CVER = 185, clone = Object.clone; function genID() { while (true) { @@ -352,6 +347,7 @@ let gs_kiri_conf = exports; p:{ processName: "default", camFastFeed: 6000, + camFastFeedZ: 300, roughingTool: 1000, roughingSpindle: 1000, roughingDown: 2, @@ -542,14 +538,17 @@ let gs_kiri_conf = exports; view: null, dark: false, expert: false, - compact: false, zoomSpeed: 1.0, + thinRender: false, reverseZoom: true, showOrigin: false, freeLayout: true, autoLayout: true, alignTop: true, - units: "mm" + units: "mm", + exportOcto: true, + exportGhost: false, + exportLocal: false }, // for passing temporary slice hints (topo currently) synth: {}, diff --git a/js/kiri-db.js b/src/kiri/db.js similarity index 72% rename from js/kiri-db.js rename to src/kiri/db.js index 74948c18..532ba7de 100644 --- a/js/kiri-db.js +++ b/src/kiri/db.js @@ -1,18 +1,16 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_kiri_db = exports; - (function() { - if (!self.kiri) self.kiri = { }; + const KIRI = self.kiri, DP = Catalog.prototype; /** * @constructor */ function Catalog(motodb, decimate) { - var store = this; + let store = this; store.db = motodb; store.files = {}; store.listeners = []; @@ -21,15 +19,12 @@ var gs_kiri_db = exports; store.refresh(); } - var kiri = self.kiri, - DP = Catalog.prototype; - - kiri.openCatalog = function(motodb,decimate) { + KIRI.openCatalog = function(motodb,decimate) { return new Catalog(motodb,decimate); }; DP.refresh = function() { - var store = this; + let store = this; store.db.get('files', function(files) { if (files) { store.files = files; @@ -39,7 +34,7 @@ var gs_kiri_db = exports; }; DP.wipe = function() { - var key, files = this.files; + let key, files = this.files; for (key in files) { if (files.hasOwnProperty(key)) this.deleteFile(key); } @@ -66,14 +61,14 @@ var gs_kiri_db = exports; } function notifyFileListeners(store) { - for (var i=0; i { + if (!vertices) return complete(false, 'no decimation'); + store.db.put(`fdec-${newname}`, vertices, complete); + }); + store.db.get(`file-${name}`, (vertices) => { + if (!vertices) return complete(false, 'no raw file'); + store.db.put(`file-${newname}`, vertices, complete); + }); + }; + /** * @param {String} name * @param {Function} callback */ DP.getFile = function(name, callback) { - var store = this, + let store = this, rec = store.files[name]; if (rec && rec.deferred) { if (store.deferredHandler) return store.deferredHandler(rec.deferred, name, callback); @@ -152,7 +174,7 @@ var gs_kiri_db = exports; * @param {Function} callback */ DP.deleteFile = function(name, callback) { - var store = this; + let store = this; if (store.files[name]) { delete store.files[name]; store.db.remove('fdec-'+name); diff --git a/js/kiri-export.js b/src/kiri/export.js similarity index 80% rename from js/kiri-export.js rename to src/kiri/export.js index f89b23c8..4de30651 100644 --- a/js/kiri-export.js +++ b/src/kiri/export.js @@ -1,26 +1,24 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_export = exports; - (function() { - if (!self.kiri) self.kiri = { }; if (self.kiri.export) return; - let KIRI = self.kiri, + const KIRI = self.kiri, BASE = self.base, UTIL = BASE.util, API = KIRI.api, SDB = API.sdb, UI = API.ui, STATS = API.stats, - MODES = API.const.MODES, - printSeq = parseInt(SDB['kiri-print-seq'] || SDB['print-seq'] || "0") + 1; + MODES = API.const.MODES; KIRI.export = exportPrint; + let printSeq = parseInt(SDB['kiri-print-seq'] || SDB['print-seq'] || "0") + 1; + function exportPrint() { let currentPrint = API.print.get(); if (currentPrint) { @@ -56,8 +54,12 @@ let gs_kiri_export = exports; } segment = line.message; } - if (line.progress) API.show.progress(line.progress, "exporting"); - if (line.data) lines.push(line.data); + if (line.progress) { + API.show.progress(line.progress, "exporting"); + } + if (line.data) { + lines.push(line.data); + } }, function(done) { currentPrint.exported = true; times[`${seq++}_${segment}`] = Date.now() - mark; @@ -115,7 +117,6 @@ let gs_kiri_export = exports; UI.print.innerHTML = html; $('print-filename').value = filename; $('print-lines').value = UTIL.comma(segments); - $('print-close').onclick = API.modal.hide; $('print-svg').onclick = download_svg; $('print-dxf').onclick = download_dxf; $('print-lg').onclick = download_gcode; @@ -183,6 +184,7 @@ let gs_kiri_export = exports; } else { API.show.alert("octoprint error\nstatus: "+status+"\nmessage: "+ajax.responseText); } + API.show.progress(0); } API.show.progress(0); }; @@ -216,7 +218,15 @@ let gs_kiri_export = exports; let dev = devs[uuid]; html.push(``); } - $('grid-local').innerHTML = html.join('\n'); + + if (html.length) { + $('grid-local').innerHTML = html.join('\n'); + $('send-to-gridhead').style.display = 'flex'; + $('send-to-gridspool').style.display = 'flex'; + } else { + $('send-to-gridhead').style.display = ''; + $('send-to-gridspool').style.display = ''; + } } function sendto_gridlocal() { @@ -415,54 +425,78 @@ let gs_kiri_export = exports; mins = floor(newtime / 60), secs = newtime - mins * 60; - $('mill-time').value = $('print-time').value = [pad(hours),pad(mins),pad(secs)].join(':'); + $('output-time').value = [pad(hours),pad(mins),pad(secs)].join(':'); } - API.ajax("/kiri/output-gcode.html", function(html) { + fetch("/kiri/output-gcode.html").then(r => r.text()).then(html => { UI.print.innerHTML = html; - $('print-close').onclick = API.modal.hide; + let set = API.conf.get(); + let fdm = MODE === MODES.FDM; + let octo = set.controller.exportOcto && MODE !== MODES.CAM; + let ghost = set.controller.exportGhost; + let local = set.controller.exportLocal; $('print-download').onclick = download; - $('print-octoprint').onclick = sendto_octoprint; - $('print-gridhost').onclick = sendto_gridhost; - $('print-gridlocal').onclick = sendto_gridlocal; - $('admin-gridlocal').onclick = admin_gridlocal; - $('print-filament-row').style.display = MODE === MODES.FDM ? '' : 'none'; - $('mill-info').style.display = MODE === MODES.CAM ? '' : 'none'; + $('print-filament-head').style.display = fdm ? '' : 'none'; + $('print-filament-info').style.display = fdm ? '' : 'none'; $('print-filename').value = filename; $('print-filesize').value = UTIL.comma(currentPrint.bytes); $('print-filament').value = Math.round(currentPrint.distance); - $('grid-host').onkeyup = gridhost_probe; - $('grid-apik').onkeyup = gridhost_probe; calcTime(); - if (MODE === MODES.FDM) { + if (fdm) { calcWeight(); } - octo_host = $('octo-host'); - octo_apik = $('octo-apik'); - if (MODE === MODES.CAM) { - $('send-to-octoprint').style.display = 'none'; - } else { - $('send-to-octoprint').style.display = ''; - } - // hide octoprint when hard-coded in the url - if (API.const.OCTO) { - $('ophost').style.display = 'none'; - $('opapik').style.display = 'none'; - $('ophint').style.display = 'none'; - $('send-to-gridhost').style.display = 'none'; - } - octo_host.value = SDB['octo-host'] || ''; - octo_apik.value = SDB['octo-apik'] || ''; - grid_host = $('grid-host'); - grid_apik = $('grid-apik'); - grid_target = $('grid-target'); - grid_target.onchange = function(ev) { - SDB['grid-target'] = grid_targets[grid_target.selectedIndex]; - }; - grid_host.value = SDB['grid-host'] || ''; - grid_apik.value = SDB['grid-apik'] || ''; - gridhost_probe(); - gridlocal_probe(); + + // octoprint setup + $('send-to-octohead').style.display = octo ? '' : 'none'; + $('send-to-octoprint').style.display = octo ? '' : 'none'; + if (octo) try { + $('print-octoprint').onclick = sendto_octoprint; + octo_host = $('octo-host'); + octo_apik = $('octo-apik'); + if (MODE === MODES.CAM) { + $('send-to-octohead').style.display = 'none'; + $('send-to-octoprint').style.display = 'none'; + } else { + $('send-to-octohead').style.display = ''; + $('send-to-octoprint').style.display = ''; + } + // hide octoprint when hard-coded in the url + if (API.const.OCTO) { + $('ophost').style.display = 'none'; + $('opapik').style.display = 'none'; + $('ophint').style.display = 'none'; + $('send-to-gridhost').style.display = 'none'; + } + octo_host.value = SDB['octo-host'] || ''; + octo_apik.value = SDB['octo-apik'] || ''; + } catch (e) { console.log(e) } + + // grid:host setup + $('send-to-hosthead').style.display = ghost ? '' : 'none'; + $('send-to-gridhost').style.display = ghost ? '' : 'none'; + if (ghost) try { + $('print-gridhost').onclick = sendto_gridhost; + $('grid-host').onkeyup = gridhost_probe; + $('grid-apik').onkeyup = gridhost_probe; + grid_host = $('grid-host'); + grid_apik = $('grid-apik'); + grid_target = $('grid-target'); + grid_target.onchange = function(ev) { + SDB['grid-target'] = grid_targets[grid_target.selectedIndex]; + }; + grid_host.value = SDB['grid-host'] || ''; + grid_apik.value = SDB['grid-apik'] || ''; + gridhost_probe(); + } catch (e) { console.log(e) } + + // grid:local setup + if (local) try { + gridlocal_probe(); + $('print-gridlocal').onclick = sendto_gridlocal; + $('admin-gridlocal').onclick = admin_gridlocal; + } catch (e) { console.log(e) } + + // show dialog API.modal.show('print'); }); } diff --git a/js/kiri-fill.js b/src/kiri/fill.js similarity index 98% rename from js/kiri-fill.js rename to src/kiri/fill.js index 6e1572dc..daf825d4 100644 --- a/js/kiri-fill.js +++ b/src/kiri/fill.js @@ -1,15 +1,12 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_kiri_fill = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.fill) return; - let KIRI = self.kiri, + const KIRI = self.kiri, BASE = self.base, UTIL = BASE.util, ROUND = UTIL.round, diff --git a/js/kiri-init.js b/src/kiri/init.js similarity index 81% rename from js/kiri-init.js rename to src/kiri/init.js index d1454aea..8075a050 100644 --- a/js/kiri-init.js +++ b/src/kiri/init.js @@ -1,15 +1,13 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_kiri_init = exports; - (function() { - if (!self.kiri) self.kiri = { }; if (self.kiri.init) return; - let KIRI = self.kiri, + const KIRI = self.kiri, + BASE = self.base, MOTO = self.moto, CONF = KIRI.conf, WIN = self.window, @@ -42,11 +40,12 @@ var gs_kiri_init = exports; GCODE = [MODES.FDM, MODES.LASER, MODES.CAM], LASER = [MODES.LASER], CATALOG = API.catalog, - platform = API.platform, - selection = API.selection, - deviceLock = false, js2o = API.js2o, o2js = API.o2js, + platform = API.platform, + selection = API.selection; + + let deviceLock = false, selectedTool = null, editTools = null, maxTool = 0, @@ -81,7 +80,6 @@ var gs_kiri_init = exports; function booleanSave() { let control = settings().controller; - let isCompact = control.compact; let isDark = control.dark; let isReload = false; control.expert = UI.expert.checked; @@ -90,17 +88,15 @@ var gs_kiri_init = exports; control.freeLayout = UI.freeLayout.checked; control.alignTop = UI.alignTop.checked; control.reverseZoom = UI.reverseZoom.checked; - control.compact = UI.compact.checked; + control.thinRender = UI.thinRender.checked; control.dark = UI.dark.checked; + control.exportOcto = UI.exportOcto.checked; + control.exportGhost = UI.exportGhost.checked; + control.exportLocal = UI.exportLocal.checked; SPACE.view.setZoom(control.reverseZoom, control.zoomSpeed); platform.layout(); platform.update_stock(); API.conf.save(); - // if compact mode changed, reload UI - if (isCompact !== control.compact) { - UC.setDefaults(isCompact); - isReload = true; - } // if dark mode changed, reload UI if (isDark !== control.dark) { isReload = true; @@ -163,7 +159,7 @@ var gs_kiri_init = exports; // kill any poppers in compact mode UC.hidePoppers(); // hide layers menu - UI.layers.style.display = 'none'; + // UI.layers.style.display = 'none'; break; } return false; @@ -296,17 +292,8 @@ var gs_kiri_init = exports; case cca('C'): // refresh catalog CATALOG.refresh(); break; - case cca('i'): // single settings edit - let v = prompt('edit "'+current.process.processName+'"', JSON.stringify(current.process)); - if (v) { - try { - current.process = JSON.parse(v); - API.view.update_fields(); - } catch (e) { - console.log(e); - API.show.alert("invalid settings format"); - } - } + case cca('i'): // file import + API.event.import(); break; case cca('U'): // full settings url storeSettingsToServer(true); @@ -326,13 +313,22 @@ var gs_kiri_init = exports; case cca('P'): // position widget positionSelection(); break; + case cca('r'): // recent files + API.modal.show('files'); + break; case cca('R'): // position widget rotateInputSelection(); break; case cca('x'): // export print API.function.export(); break; - case cca('e'): // devices + case cca('q'): // preferences + API.modal.show('prefs'); + break; + case cca('l'): // device + settingsLoad(); + break; + case cca('e'): // device showDevices(); break; case cca('o'): // tools @@ -342,7 +338,11 @@ var gs_kiri_init = exports; API.show.local(); break; case cca('v'): // toggle single slice view mode - UI.layerRange.checked = !UI.layerRange.checked; + if (API.var.layer_hi == API.var.layer_lo) { + API.var.layer_lo = 0; + } else { + API.var.layer_lo = API.var.layer_hi; + } API.show.slices(); break; case cca('d'): // duplicate object @@ -400,7 +400,7 @@ var gs_kiri_init = exports; API.show.alert("select object to rotate"); return; } - let coord = prompt("Enter X,Y,Z degrees of rotation").split(','), + let coord = (prompt("Enter X,Y,Z degrees of rotation") || '').split(','), prod = Math.PI / 180, x = parseFloat(coord[0] || 0.0) * prod, y = parseFloat(coord[1] || 0.0) * prod, @@ -519,7 +519,7 @@ var gs_kiri_init = exports; } function getSelectedDevice() { - return UI.deviceSelect.options[UI.deviceSelect.selectedIndex].text; + return UI.deviceList.options[UI.deviceList.selectedIndex].text; } function selectDevice(devicename, lock) { @@ -528,11 +528,10 @@ var gs_kiri_init = exports; if (isLocalDevice(devicename)) { setDeviceCode(settings().devices[devicename], devicename); } else { - API.ajax("/kiri/filter/"+API.mode.get()+"/"+devicename, function(code) { - setDeviceCode(code, devicename); - }); + let code = devices[API.mode.get_lower()][devicename]; + setDeviceCode(code, devicename); } - $('selected-device').innerHTML = devicename; + // $('selected-device').innerHTML = devicename; } // only for local filters @@ -568,19 +567,20 @@ var gs_kiri_init = exports; if (dev.extruders) { let ext = API.lists.extruders = []; dev.internal = 0; - let selext = $('sel-ext'); + let selext = $('pop-nozzle'); selext.innerHTML = ''; - for (let i=dev.extruders.length-1; i>=0; i--) { - let b = DOC.createElement('button'); - b.appendChild(DOC.createTextNode(i)); - b.setAttribute('id', `sel-ext-${i}`); - b.onclick = function() { + for (let i=0; i { current.widget[w.id] = {extruder: i}; }); API.platform.update_selected(); }; - selext.appendChild(b); + selext.appendChild(d); ext.push({id:i, name:i}); } } @@ -626,17 +626,7 @@ var gs_kiri_init = exports; e.disabled = !local; }); - // hide spindle fields when device doens't support it - UI.extrudeAbs.style.display = mode === 'CAM' ? 'none' : 'block'; - if (mode === 'CAM') { - [ UI.roughingSpindle, - UI.finishingSpindle, - UI.drillSpindle - ].forEach(function(e) { - e.parentNode.style.display = dev.spindleMax > 0 ? 'block' : 'none'; - }); - } - + UI.extrudeAbs.style.display = mode === 'CAM' ? 'none' : 'flex'; UI.deviceSave.disabled = !local; UI.deviceDelete.disabled = !local; UI.deviceAdd.disabled = dev.noclone; @@ -675,9 +665,6 @@ var gs_kiri_init = exports; } function renderDevices(devices) { - UI.devices.onclick = UC.hidePop; - UC.hidePop(); - let selectedIndex = -1, selected = API.device.get(), devs = settings().devices; @@ -697,7 +684,6 @@ var gs_kiri_init = exports; devices = devices.sort(); - UI.deviceClose.onclick = API.dialog.hide; UI.deviceSave.onclick = function() { API.function.clear(); API.conf.save(); @@ -723,7 +709,7 @@ var gs_kiri_init = exports; showDevices(); }; - UI.deviceSelect.innerHTML = ''; + UI.deviceList.innerHTML = ''; let incr = 0; let faves = API.show.favorites(); let found = false; @@ -761,7 +747,7 @@ var gs_kiri_init = exports; }; if (loc) opt.setAttribute("local", 1); if (loc || fav) opt.setAttribute("favorite", 1); - UI.deviceSelect.appendChild(opt); + UI.deviceList.appendChild(opt); if (device === selected) { selectedIndex = incr; found = true; @@ -770,17 +756,12 @@ var gs_kiri_init = exports; }); if (selectedIndex >= 0) { - UI.deviceSelect.selectedIndex = selectedIndex; + UI.deviceList.selectedIndex = selectedIndex; selectDevice(selected); } else { - UI.deviceSelect.selectedIndex = 0; + UI.deviceList.selectedIndex = 0; selectDevice(first); } - - API.dialog.show('devices', true); - API.dialog.update(); - - UI.deviceSelect.focus(); } function renderTools() { @@ -978,13 +959,15 @@ var gs_kiri_init = exports; UI.toolSelect.focus(); } + function updateDeviceList() { + renderDevices(Object.keys(devices[API.mode.get_lower()]).sort()); + } + function showDevices() { if (deviceLock) return; - API.modal.hide(); - API.ajax("/api/filters-"+API.mode.get_lower(), function(flvalue) { - if (!flvalue) return; - renderDevices(js2o(flvalue)); - }); + updateDeviceList(); + API.modal.show('setup'); + UI.deviceList.focus(); } function dragOverHandler(evt) { @@ -1035,28 +1018,50 @@ var gs_kiri_init = exports; }); for (let i=0; i { + let newname = prompt(`rename file`, short); + if (newname && newname !== short) { + CATALOG.rename(name, `${newname}${ext}`, then => { + CATALOG.refresh(); + }); + } + }; load.setAttribute('load', name); - load.setAttribute('title', 'file: '+name+'\nvertices: '+file.v); + load.setAttribute('title', `file: ${name}\nvertices: ${file.v}\ndate: ${date}`); load.onclick = loadCatalogFile; - load.appendChild(DOC.createTextNode(name.split('.')[0])); + load.appendChild(DOC.createTextNode(short)); del.setAttribute('del', name); del.setAttribute('title', "remove '"+name+"'"); del.onclick = deleteCatalogFile; del.appendChild(DOC.createTextNode('x')); - row.setAttribute("class", "flow-row"); + size.setAttribute("disabled", true); + size.setAttribute("class", "label"); + size.appendChild(DOC.createTextNode(BASE.util.comma(file.v))); + + row.setAttribute("class", "row a-center"); + row.appendChild(renm); row.appendChild(load); + row.appendChild(size); row.appendChild(del); table.appendChild(row); } - // fix layer scroll size - API.dialog.update(); } // MAIN INITIALIZATION FUNCTION @@ -1067,15 +1072,25 @@ var gs_kiri_init = exports; // ensure we have settings from last session API.conf.restore(); - let assets = $('assets'), - control = $('control'), - container = $('container'), + let container = $('container'), welcome = $('welcome'), + gcode = $('dev-gcode'), + tracker = $('tracker'), controller = settings().controller, - compact = SETUP.compact || controller.compact, dark = controller.dark; - WIN.addEventListener("resize", API.dialog.update); + WIN.addEventListener("resize", () => { + API.event.emit('resize'); + }); + + API.event.on('resize', () => { + if (WIN.innerHeight < 800) { + UI.modalBox.classList.add('mh85'); + } else { + UI.modalBox.classList.remove('mh85'); + } + API.view.update_slider(); + }); SPACE.showSkyGrid(false); SPACE.setSkyColor(dark ? 0 : 0xffffff); @@ -1090,35 +1105,49 @@ var gs_kiri_init = exports; SPACE.platform.setRound(true); SPACE.useDefaultKeys(API.feature.on_key === undefined || API.feature.on_key_defaults); - UC.setCompact(compact); - Object.assign(UI, { - // from static HTML alert: { dialog: $('alert-area'), text: $('alert-text') }, + + act: { + slice: $('act-slice'), + preview: $('act-preview'), + export: $('act-export') + }, + + load: $('load-file'), + focuser: $('focuser'), + container: container, - assets: assets, - control: control, - ctrlLeft: $('control-left'), - ctrlRight: $('control-right'), - layerView: $('layer-view'), - layerSlider: $('layer-slider'), - modelOpacity: $('opacity'), + menusep: $('lt-sep'), + rotate: $('lt-rotate'), + scale: $('lt-scale'), + nozzle: $('lt-nozzle'), + modal: $('modal'), - print: $('print'), - local: $('local'), - help: $('help'), + modalBox: $('modal-box'), + help: $('mod-help'), + setup: $('mod-setup'), + tools: $('mod-tools'), + prefs: $('mod-prefs'), + files: $('mod-files'), + saves: $('mod-saves'), + print: $('mod-print'), + local: $('mod-local'), + + catalogBody: $('catalogBody'), + catalogList: $('catalogList'), + devices: $('devices'), + deviceList: $('device-list'), deviceAdd: $('device-add'), deviceDelete: $('device-del'), deviceSave: $('device-save'), - deviceClose: $('device-close'), - deviceSelect: $('device-select'), deviceFavorites: $('device-favorites'), deviceAll: $('device-all'), - tools: $('tools'), + toolsSave: $('tools-save'), toolsClose: $('tools-close'), toolSelect: $('tool-select'), @@ -1134,18 +1163,25 @@ var gs_kiri_init = exports; // toolTaperAngle: $('tool-tangle'), toolTaperTip: $('tool-ttip'), toolMetric: $('tool-metric'), - catalog: $('catalog'), - catalogBody: $('catalogBody'), - catalogList: $('catalogList'), + + setMenu: $('set-menu'), settings: $('settings'), settingsBody: $('settingsBody'), settingsList: $('settingsList'), - layerID: $('layer-id'), - layerSpan: $('layer-span'), - layerRange: $('layer-range'), - loading: $('loading').style, - progress: $('progress').style, - prostatus: $('prostatus'), + + slider: $('slider'), + sliderMax: $('slider-max'), + sliderMin: $('slider-zero'), + sliderLo: $('slider-lo'), + sliderMid: $('slider-mid'), + sliderHi: $('slider-hi'), + sliderHold: $('slider-hold'), + sliderRange: $('slider-center'), + + loading: $('progress').style, + progress: $('progbar').style, + prostatus: $('progtxt'), + selection: $('selection'), sizeX: $('size_x'), sizeY: $('size_y'), @@ -1161,151 +1197,68 @@ var gs_kiri_init = exports; stockDepth: $('stock-width'), stockHeight: $('stock-width'), - device: UC.newGroup(LANG.dv_gr_dev, $('device'), {group:"ddev", nocompact:true}), + device: UC.newGroup(LANG.dv_gr_dev, $('device'), {group:"ddev", inline:true}), deviceName: UC.newInput(LANG.dv_name_s, {title:LANG.dv_name_l, size:"60%", text:true, action:updateDeviceName}), bedWidth: UC.newInput(LANG.dv_bedw_s, {title:LANG.dv_bedw_l, convert:UC.toFloat, size:6}), bedDepth: UC.newInput(LANG.dv_bedd_s, {title:LANG.dv_bedd_l, convert:UC.toFloat, size:6}), maxHeight: UC.newInput(LANG.dv_bedh_s, {title:LANG.dv_bedh_l, convert:UC.toFloat, size:6, modes:FDM_SLA}), +<<<<<<< HEAD:js/kiri-init.js spindleMax: UC.newInput(LANG.dv_spmx_s, {title:LANG.dv_spmx_l, convert:UC.toInt, modes:CAM}), +======= + spindleMax: UC.newInput(LANG.dv_spmx_s, {title:LANG.dv_spmx_l, convert:UC.toInt, size: 6, modes:CAM}), +>>>>>>> dev-3.0:src/kiri/init.js deviceOrigin: UC.newBoolean(LANG.dv_orgc_s, onBooleanClick, {title:LANG.dv_orgc_l, modes:GCODE}), deviceOriginTop: UC.newBoolean(LANG.dv_orgt_s, onBooleanClick, {title:LANG.dv_orgt_l, modes:CAM}), deviceRound: UC.newBoolean(LANG.dv_bedc_s, onBooleanClick, {title:LANG.dv_bedc_l, modes:FDM}), - extruder: UC.newGroup(LANG.dv_gr_ext, $('device'), {group:"dext", nocompact:true, modes:FDM}), + extruder: UC.newGroup(LANG.dv_gr_ext, $('device'), {group:"dext", inline:true, modes:FDM}), extFilament: UC.newInput(LANG.dv_fila_s, {title:LANG.dv_fila_l, convert:UC.toFloat, modes:FDM}), extNozzle: UC.newInput(LANG.dv_nozl_s, {title:LANG.dv_nozl_l, convert:UC.toFloat, modes:FDM}), extOffsetX: UC.newInput(LANG.dv_exox_s, {title:LANG.dv_exox_l, convert:UC.toFloat, modes:FDM, expert:true}), extOffsetY: UC.newInput(LANG.dv_exoy_s, {title:LANG.dv_exoy_l, convert:UC.toFloat, modes:FDM, expert:true}), - extSelect: UC.newText(LANG.dv_exts_s, {title:LANG.dv_exts_l, modes:FDM, size:14, height:3, modes:FDM, expert:true}), + extSelect: UC.newText(LANG.dv_exts_s, {title:LANG.dv_exts_l, modes:FDM, size:14, height:3, modes:FDM, expert:true, area:gcode}), extrudeAbs: UC.newBoolean(LANG.dv_xtab_s, onBooleanClick, {title:LANG.dv_xtab_l, modes:FDM}), - extActions: UC.newTableRow([[ - UI.extPrev = UC.newButton("<"), - UI.extAdd = UC.newButton("+"), - UI.extDel = UC.newButton("-"), - UI.extNext = UC.newButton(">") - ]], {modes:FDM, expert:true}), + extActions: UC.newRow([ + UI.extPrev = UC.newButton(undefined, undefined, {icon:''}), + UI.extAdd = UC.newButton(undefined, undefined, {icon:''}), + UI.extDel = UC.newButton(undefined, undefined, {icon:''}), + UI.extNext = UC.newButton(undefined, undefined, {icon:''}) + ], {modes:FDM, expert:true, class:"ext-buttons"}), - gcode: UC.newGroup(LANG.dv_gr_gco, $('device'), {group:"dgco", nocompact:true, modes:GCODE}), + gcode: UC.newGroup(LANG.dv_gr_gco, $('device'), {group:"dgco", inline:true, modes:GCODE}), gcodeFan: UC.newInput(LANG.dv_fanp_s, {title:LANG.dv_fanp_l, modes:FDM, size:"40%", text:true}), gcodeTrack: UC.newInput(LANG.dv_prog_s, {title:LANG.dv_prog_l, modes:FDM, size:"40%", text:true}), - gcodeLayer: UC.newText(LANG.dv_layr_s, {title:LANG.dv_layr_l, modes:FDM, size:14, height: 2}), + gcodeLayer: UC.newText(LANG.dv_layr_s, {title:LANG.dv_layr_l, modes:FDM, size:14, height: 2, area:gcode}), gcodeSpace: UC.newBoolean(LANG.dv_tksp_s, onBooleanClick, {title:LANG.dv_tksp_l, modes:CAM_LASER}), gcodeStrip: UC.newBoolean(LANG.dv_strc_s, onBooleanClick, {title:LANG.dv_strc_l, modes:CAM}), gcodeFExt: UC.newInput(LANG.dv_fext_s, {title:LANG.dv_fext_l, modes:CAM_LASER, size:7, text:true}), - gcodeDwell: UC.newText(LANG.dv_dwll_s, {title:LANG.dv_dwll_l, modes:CAM, size:14, height:2}), - gcodeChange: UC.newText(LANG.dv_tool_s, {title:LANG.dv_tool_l, modes:CAM, size:14, height:2}), - gcodeSpindle: UC.newText(LANG.dv_sspd_s, {title:LANG.dv_sspd_l, modes:CAM, size:14, height:2}), - gcodePause: UC.newText(LANG.dv_paus_s, {title:LANG.dv_paus_l, modes:FDM, size:14, height:3}), - gcodeLaserOn: UC.newText(LANG.dv_lzon_s, {title:LANG.dv_lzon_l, modes:LASER, size:14, height:3}), - gcodeLaserOff: UC.newText(LANG.dv_lzof_s, {title:LANG.dv_lzof_l, modes:LASER, size:14, height:3}), - gcodePre: UC.newText(LANG.dv_head_s, {title:LANG.dv_head_l, modes:GCODE, size:14, height:3}), - gcodePost: UC.newText(LANG.dv_foot_s, {title:LANG.dv_foot_l, modes:GCODE, size:14, height:3}), + gcodeDwell: UC.newText(LANG.dv_dwll_s, {title:LANG.dv_dwll_l, modes:CAM, size:14, height:2, area:gcode}), + gcodeChange: UC.newText(LANG.dv_tool_s, {title:LANG.dv_tool_l, modes:CAM, size:14, height:2, area:gcode}), + gcodeSpindle: UC.newText(LANG.dv_sspd_s, {title:LANG.dv_sspd_l, modes:CAM, size:14, height:2, area:gcode}), + gcodePause: UC.newText(LANG.dv_paus_s, {title:LANG.dv_paus_l, modes:FDM, size:14, height:3, area:gcode}), + gcodeLaserOn: UC.newText(LANG.dv_lzon_s, {title:LANG.dv_lzon_l, modes:LASER, size:14, height:3, area:gcode}), + gcodeLaserOff: UC.newText(LANG.dv_lzof_s, {title:LANG.dv_lzof_l, modes:LASER, size:14, height:3, area:gcode}), + gcodePre: UC.newText(LANG.dv_head_s, {title:LANG.dv_head_l, modes:GCODE, size:14, height:3, area:gcode}), + gcodePost: UC.newText(LANG.dv_foot_s, {title:LANG.dv_foot_l, modes:GCODE, size:14, height:3, area:gcode}), - mode: UC.newGroup(LANG.mo_menu, assets, {region:"left", poprow:false}), - modeTable: UC.newTableRow([ - [ - UI.modeFDM = - UC.newButton(LANG.mo_fdmp, function() { API.mode.set('FDM',null,platform.update_size) }, {icon: KIRI.icons.fdm}), - ],[ - UI.modeSLA = - UC.newButton(LANG.mo_slap, function() { API.mode.set('SLA',null,platform.update_size) }, {icon: KIRI.icons.sla}), - ],[ - UI.modeLASER = - UC.newButton(LANG.mo_lazr, function() { API.mode.set('LASER',null,platform.update_size) }, {icon: KIRI.icons.laser}), - ],[ - UI.modeCAM = - UC.newButton(LANG.mo_cncm, function() { API.mode.set('CAM',null,platform.update_size) }, {icon: KIRI.icons.cam, id:"modeCAM"}), - ] - ]), - system: UC.newGroup(LANG.su_menu), - sysTable: UC.newTableRow([ - [ - UI.setupDevices = - UC.newButton(LANG.su_devi, showDevices) - ],[ - UI.setupTools = - UC.newButton(LANG.su_tool, showTools, {modes:CAM}) - ],[ - UI.setupExport = - UC.newButton(LANG.su_xprt, settingsExport, {modes:ALL, expert:true}) - ],[ - UI.localButton = - UC.newButton(LANG.su_locl, API.show.local, {modes:FDM_CAM, expert:true}) - ],[ - UI.helpButton = - UC.newButton(LANG.su_help, API.help.show) - ] - ]), - wsFunc: UC.newGroup(LANG.fn_menu), - wsFuncTable: UC.newTableRow([ - [ - UI.load = - UC.newButton(LANG.fn_impo, function() { API.event.import() }, {class:"asym"}), - UI.import = - UC.newButton("+", undefined, {class:"asym"}) - ],[ - UI.modeArrange = - UC.newButton(LANG.fn_arra, platform.layout), - ],[ - UI.modeSlice = - UC.newButton(LANG.fn_slic, API.function.slice) - ],[ - UI.modePreview = - UC.newButton(LANG.fn_prev, API.function.print), - ],[ - UI.modeExport = - UC.newButton(LANG.fn_expo, API.function.export) - ] - ]), - camera: UC.newGroup(LANG.vu_menu), - camTable: UC.newTableRow([ - [ - UC.newButton(LANG.vu_home, SPACE.view.home), - UC.newButton(LANG.vu_rset, SPACE.view.reset) - ],[ - UC.newButton(LANG.vu_sptp, SPACE.view.top), - UC.newButton(LANG.vu_spfr, SPACE.view.front), - ],[ - UC.newButton(LANG.vu_splt, SPACE.view.left), - UC.newButton(LANG.vu_sprt, SPACE.view.right) - ] - ]), + layout: UC.newGroup(LANG.op_menu, $('prefs-gen'), {inline: true}), + expert: UC.newBoolean(LANG.op_xprt_s, booleanSave, {title:LANG.op_xprt_l}), + dark: UC.newBoolean(LANG.op_dark_s, booleanSave, {title:LANG.op_dark_l}), + showOrigin: UC.newBoolean(LANG.op_show_s, booleanSave, {title:LANG.op_show_l, modes:GCODE}), + alignTop: UC.newBoolean(LANG.op_alig_s, booleanSave, {title:LANG.op_alig_l, modes:CAM}), + autoLayout: UC.newBoolean(LANG.op_auto_s, booleanSave, {title:LANG.op_auto_l}), + freeLayout: UC.newBoolean(LANG.op_free_s, booleanSave, {title:LANG.op_free_l, modes:ALL}), + reverseZoom: UC.newBoolean(LANG.op_invr_s, booleanSave, {title:LANG.op_invr_l, modes:ALL}), + thinRender: UC.newBoolean(LANG.op_thin_s, booleanSave, {title:LANG.op_thin_l, modes:ALL}), + units: UC.newSelect(LANG.op_unit_s, {title: LANG.op_unit_l, modes:CAM}, "units"), + prefadd: UC.checkpoint(), - workspace: UC.newGroup(LANG.ws_menu, undefined, {modes:ALL, expert:true}), - wsTable: UC.newTableRow([ - [ - UI.saveButton = - UC.newButton(LANG.ws_save, API.space.save), - ],[ - UC.newButton(LANG.ws_cler, API.space.clear) - ] - ], {modes:ALL, expert:true}), + export: UC.newGroup(LANG.xp_menu, $('prefs-out'), {inline: true}), + exportOcto: UC.newBoolean(`OctoPrint`, booleanSave), + exportGhost: UC.newBoolean(`Grid:Host`, booleanSave), + exportLocal: UC.newBoolean(`Grid:Local`, booleanSave), - layout: UC.newGroup(LANG.op_menu), - expert: UC.newBoolean(LANG.op_xprt_s, booleanSave, {title:LANG.op_xprt_l}), - compact: UC.newBoolean(LANG.op_comp_s, booleanSave, {title:LANG.op_comp_l}), - dark: UC.newBoolean(LANG.op_dark_s, booleanSave, {title:LANG.op_dark_l}), - showOrigin: UC.newBoolean(LANG.op_show_s, booleanSave, {title:LANG.op_show_l, modes:GCODE}), - alignTop: UC.newBoolean(LANG.op_alig_s, booleanSave, {title:LANG.op_alig_l, modes:CAM}), - autoLayout: UC.newBoolean(LANG.op_auto_s, booleanSave, {title:LANG.op_auto_l}), - freeLayout: UC.newBoolean(LANG.op_free_s, booleanSave, {title:LANG.op_free_l, modes:ALL, expert:true}), - reverseZoom: UC.newBoolean(LANG.op_invr_s, booleanSave, {title:LANG.op_invr_l, modes:ALL, expert:true}), - units: UC.newSelect(LANG.op_unit_s, {title: LANG.op_unit_l, modes:CAM}, "units"), - - // allow modules to insert new items at the bottom of the left menu - appendLeft: UC.checkpoint(), - - settingsGroup: UC.newGroup(LANG.se_menu, control, {region:"right"}), - settingsTable: UC.newTableRow([ - [ - UI.settingsLoad = - UC.newButton(LANG.se_load, settingsLoad), - UI.settingsSave = - UC.newButton(LANG.se_save, settingsSave) - ] - ]), - - process: UC.newGroup(LANG.sl_menu, control, {modes:FDM_LASER}), + process: UC.newGroup(LANG.sl_menu, $('settings'), {modes:FDM_LASER}), sliceHeight: UC.newInput(LANG.sl_lahi_s, {title:LANG.sl_lahi_l, convert:UC.toFloat, modes:FDM}), sliceShells: UC.newInput(LANG.sl_shel_s, {title:LANG.sl_shel_l, convert:UC.toInt, modes:FDM}), sliceTopLayers: UC.newInput(LANG.sl_ltop_s, {title:LANG.sl_ltop_l, convert:UC.toInt, modes:FDM}), @@ -1316,7 +1269,7 @@ var gs_kiri_init = exports; laserSliceHeight: UC.newInput(LANG.ls_lahi_s, {title:LANG.ls_lahi_l, convert:UC.toFloat, modes:LASER}), laserSliceSingle: UC.newBoolean(LANG.ls_sngl_s, onBooleanClick, {title:LANG.ls_sngl_l, modes:LASER}), - process: UC.newGroup(LANG.fi_menu, control, {modes:FDM}), + process: UC.newGroup(LANG.fi_menu, $('settings'), {modes:FDM}), sliceFillType: UC.newSelect(LANG.fi_type, {modes:FDM}, "infill"), sliceFillSparse: UC.newInput(LANG.fi_pcnt_s, {title:LANG.fi_pcnt_l, convert:UC.toFloat, bound:UC.bound(0.0,1.0), modes:FDM}), sliceFillAngle: UC.newInput(LANG.fi_angl_s, {title:LANG.fi_angl_l, convert:UC.toFloat, modes:FDM, expert:true}), @@ -1343,9 +1296,6 @@ var gs_kiri_init = exports; sliceSupportNozzle: UC.newSelect(LANG.sp_nozl_s, {title:LANG.sp_nozl_l, modes:FDM, expert:true}, "extruders"), sliceSupportEnable: UC.newBoolean(LANG.enable, onBooleanClick, {modes:FDM}), - camCommon: UC.newGroup(LANG.cc_menu, null, {modes:CAM}), - camFastFeed: UC.newInput(LANG.cc_rapd_s, {title:LANG.cc_rapd_l, convert:UC.toInt, modes:CAM}), - roughing: UC.newGroup(LANG.cr_menu, null, {modes:CAM}), roughingTool: UC.newSelect(LANG.cc_tool, {modes:CAM}), roughingSpindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, modes:CAM}), @@ -1381,13 +1331,6 @@ var gs_kiri_init = exports; drillLift: UC.newInput(LANG.cd_lift_s, {title:LANG.cd_lift_l, convert:UC.toFloat, modes:CAM}), drillingOn: UC.newBoolean(LANG.enable, onBooleanClick, {modes:CAM}), - camTabs: UC.newGroup(LANG.ct_menu, null, {modes:CAM}), - camTabsAngle: UC.newInput(LANG.ct_angl_s, {title:LANG.ct_angl_l, convert:UC.toInt, bound:UC.bound(0,360), modes:CAM}), - camTabsCount: UC.newInput(LANG.ct_numb_s, {title:LANG.ct_numb_l, convert:UC.toInt, bound:UC.bound(1,20), modes:CAM}), - camTabsWidth: UC.newInput(LANG.ct_wdth_s, {title:LANG.ct_wdth_l, convert:UC.toFloat, bound:UC.bound(0.1,100), modes:CAM}), - camTabsHeight: UC.newInput(LANG.ct_hght_s, {title:LANG.ct_hght_l, convert:UC.toFloat, bound:UC.bound(0.1,100), modes:CAM}), - camTabsOn: UC.newBoolean(LANG.enable, onBooleanClick, {title:LANG.ct_nabl_l, modes:CAM}), - output: UC.newGroup(LANG.fr_menu, null, {modes:FDM}), outputRaftSpacing: UC.newInput(LANG.fr_spac_s, {title:LANG.fr_spac_l, convert:UC.toFloat, bound:UC.bound(0.0,3.0), modes:FDM}), outputRaft: UC.newBoolean(LANG.enable, onBooleanClick, {title:LANG.fr_nabl_l, modes:FDM}), @@ -1408,13 +1351,20 @@ var gs_kiri_init = exports; outputFillMult: UC.newInput(LANG.ou_flml_s, {title:LANG.ou_exml_l, convert:UC.toFloat, bound:UC.bound(0.0,2.0), modes:FDM}), outputSparseMult: UC.newInput(LANG.ou_spml_s, {title:LANG.ou_exml_l, convert:UC.toFloat, bound:UC.bound(0.0,2.0), modes:FDM}), outputFanLayer: UC.newInput(LANG.ou_fanl_s, {title:LANG.ou_fanl_l, convert:UC.toInt, bound:UC.bound(0,100), modes:FDM, expert:true}), - camTolerance: UC.newInput(LANG.ou_toll_s, {title:LANG.ou_toll_l, convert:UC.toFloat, bound:UC.bound(0.001,1.0), modes:CAM}), - camZTopOffset: UC.newInput(LANG.ou_ztof_s, {title:LANG.ou_ztof_l, convert:UC.toFloat, modes:CAM}), - camZBottom: UC.newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:UC.toFloat, modes:CAM}), - camZClearance: UC.newInput(LANG.ou_zclr_s, {title:LANG.ou_zclr_l, convert:UC.toFloat, bound:UC.bound(0.01,100), modes:CAM}), + outputClockwise: UC.newBoolean(LANG.ou_conv_s, onBooleanClick, {title:LANG.ou_conv_l, modes:CAM}), camEaseDown: UC.newBoolean(LANG.cr_ease_s, onBooleanClick, {title:LANG.cr_ease_l, modes:CAM}), camDepthFirst: UC.newBoolean(LANG.ou_depf_s, onBooleanClick, {title:LANG.ou_depf_l, modes:CAM}), + camZTopOffset: UC.newInput(LANG.ou_ztof_s, {title:LANG.ou_ztof_l, convert:UC.toFloat, modes:CAM}), + camZBottom: UC.newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:UC.toFloat, modes:CAM}), + camZClearance: UC.newInput(LANG.ou_zclr_s, {title:LANG.ou_zclr_l, convert:UC.toFloat, bound:UC.bound(0.01,100), modes:CAM}), + + camTabs: UC.newGroup(LANG.ct_menu, null, {modes:CAM}), + camTabsAngle: UC.newInput(LANG.ct_angl_s, {title:LANG.ct_angl_l, convert:UC.toInt, bound:UC.bound(0,360), modes:CAM}), + camTabsCount: UC.newInput(LANG.ct_numb_s, {title:LANG.ct_numb_l, convert:UC.toInt, bound:UC.bound(1,20), modes:CAM}), + camTabsWidth: UC.newInput(LANG.ct_wdth_s, {title:LANG.ct_wdth_l, convert:UC.toFloat, bound:UC.bound(0.1,100), modes:CAM}), + camTabsHeight: UC.newInput(LANG.ct_hght_s, {title:LANG.ct_hght_l, convert:UC.toFloat, bound:UC.bound(0.1,100), modes:CAM}), + camTabsOn: UC.newBoolean(LANG.enable, onBooleanClick, {title:LANG.ct_nabl_l, modes:CAM}), camStock: UC.newGroup(LANG.cs_menu, null, {modes:CAM}), camStockX: UC.newInput(LANG.cs_wdth_s, {title:LANG.cs_wdth_l, convert:UC.toFloat, bound:UC.bound(0,9999), modes:CAM}), @@ -1422,6 +1372,11 @@ var gs_kiri_init = exports; camStockZ: UC.newInput(LANG.cs_hght_s, {title:LANG.cs_hght_l, convert:UC.toFloat, bound:UC.bound(0,9999), modes:CAM}), camStockOffset: UC.newBoolean(LANG.cs_offs_s, onBooleanClick, {title:LANG.cs_offs_l, modes:CAM}), + camCommon: UC.newGroup(LANG.cc_menu, null, {modes:CAM}), + camFastFeedZ: UC.newInput(LANG.cc_rzpd_s, {title:LANG.cc_rzpd_l, convert:UC.toInt, modes:CAM}), + camFastFeed: UC.newInput(LANG.cc_rapd_s, {title:LANG.cc_rapd_l, convert:UC.toInt, modes:CAM}), + camTolerance: UC.newInput(LANG.ou_toll_s, {title:LANG.ou_toll_l, convert:UC.toFloat, bound:UC.bound(0.001,1.0), modes:CAM}), + outputOriginBounds: UC.newBoolean(LANG.or_bnds_s, onBooleanClick, {title:LANG.or_bnds_l, modes:LASER}), outputOriginCenter: UC.newBoolean(LANG.or_cntr_s, onBooleanClick, {title:LANG.or_cntr_l, modes:CAM_LASER}), camOriginTop: UC.newBoolean(LANG.or_topp_s, onBooleanClick, {title:LANG.or_topp_l, modes:CAM}), @@ -1481,46 +1436,150 @@ var gs_kiri_init = exports; slaFirstOffset: UC.newInput(LANG.sa_opzo_s, {title:LANG.sa_opzo_l, convert:UC.toFloat, bound:UC.bound(0,1), modes:SLA, expert:true}), slaAntiAlias: UC.newSelect(LANG.sa_opaa_s, {title:LANG.sa_opaa_l, modes:SLA}, "antialias"), + settingsGroup: UC.newGroup(LANG.se_menu, $('settings')), + settingsTable: UC.newTableRow([ + [ + UI.settingsLoad = + UC.newButton(LANG.se_load, settingsLoad), + UI.settingsSave = + UC.newButton(LANG.se_save, settingsSave) + ] + ]), + layers: UC.setGroup($("layers")), - layerOutline: UC.newBoolean(LANG.la_olin, onLayerToggle, {modes:LOCAL ? ALL : FDM_LASER}), layerTrace: UC.newBoolean(LANG.la_trce, onLayerToggle, {modes:FDM_LASER}), layerFacing: UC.newBoolean(LANG.la_face, onLayerToggle, {modes:[]}), // see sliceRender() in CAM layerRough: UC.newBoolean(LANG.la_ruff, onLayerToggle, {modes:CAM}), layerFinish: UC.newBoolean(LANG.la_fini, onLayerToggle, {modes:CAM}), layerFinishX: UC.newBoolean(LANG.la_finx, onLayerToggle, {modes:CAM}), layerFinishY: UC.newBoolean(LANG.la_finy, onLayerToggle, {modes:CAM}), - layerDelta: UC.newBoolean(LANG.la_dlta, onLayerToggle, {modes:FDM_SLA}), - layerSolid: UC.newBoolean(LANG.la_slds, onLayerToggle, {modes:FDM_SLA}), layerFill: UC.newBoolean(LANG.la_fill, onLayerToggle, {modes:FDM}), layerSparse: UC.newBoolean(LANG.la_sprs, onLayerToggle, {modes:FDM}), layerSupport: UC.newBoolean(LANG.la_sprt, onLayerToggle, {modes:FDM_SLA}), + layerOutline: UC.newBoolean(LANG.la_olin, onLayerToggle, {modes:ALL}), + layerDelta: UC.newBoolean(LANG.la_dlta, onLayerToggle, {modes:FDM_SLA}), + layerSolid: UC.newBoolean(LANG.la_slds, onLayerToggle, {modes:FDM_SLA}), layerPrint: UC.newBoolean(LANG.la_prnt, onLayerToggle), layerMoves: UC.newBoolean(LANG.la_move, onLayerToggle, {modes:GCODE}) }); - if (!lang_set) { - // for english only, add underlined labels for hotkeys - UI.setupDevices.innerHTML = "Devices"; - UI.setupTools.innerHTML = "Tools"; - UI.modeArrange.innerHTML = "Arrange"; - UI.modeSlice.innerHTML = "Slice"; - UI.modePreview.innerHTML = "Preview"; - UI.modeExport.innerHTML = "Export"; + // slider setup + const slider = UI.sliderRange; + const drag = { }; + + function pxToInt(txt) { + return txt ? parseInt(txt.substring(0,txt.length-2)) : 0; } - // populate language drop-down - let lp = $('langpop'); - let elp = DOC.createElement("div"); - let dlp = DOC.createElement("div"); - elp.appendChild(DOC.createTextNode('english')); - dlp.appendChild(DOC.createTextNode('danish')); - lp.appendChild(elp); - lp.appendChild(dlp); - elp.onclick = function() { + function sliderUpdate() { + let start = drag.top / drag.maxval; + let end = (drag.top + drag.mid - 20) / drag.maxval; + API.event.emit('slider.pos', { start, end }); + API.var.layer_hi = Math.round((1 - start) * API.var.layer_max); + API.var.layer_lo = Math.round((1 - end) * API.var.layer_max); + API.show.layer(); + } + + function dragit(el, delta) { + el.onmousedown = (ev) => { + tracker.style.display = 'block'; + ev.stopPropagation(); + drag.height = slider.clientHeight; + drag.maxval = drag.height - 40; + drag.start = ev.screenY; + drag.hiat = drag.top = pxToInt(UI.sliderHold.style.marginTop); + drag.mdat = drag.mid = UI.sliderMid.clientHeight; + drag.mdmax = drag.height - 20 - drag.hiat; + drag.himax = drag.height - 20 - drag.mdat; + let cancel_drag = tracker.onmouseup = (ev) => { + if (ev) { + ev.stopPropagation(); + ev.preventDefault(); + } + slider.onmousemove = undefined; + tracker.style.display = 'none'; + }; + tracker.onmousemove = (ev) => { + ev.stopPropagation(); + ev.preventDefault(); + if (ev.buttons === 0) { + return cancel_drag(); + } + if (delta) delta(ev.screenY - drag.start); + }; + }; + } + + dragit(UI.sliderHi, (delta) => { + let midval = drag.mdat - delta; + let topval = drag.hiat + delta; + if (midval < 20 || topval < 0) { + return; + } + UI.sliderHold.style.marginTop = `${topval}px`; + UI.sliderMid.style.height = `${midval}px`; + drag.top = topval; + drag.mid = midval; + sliderUpdate(); + }); + dragit(UI.sliderMid, (delta) => { + let topoff = Math.max(0, Math.min(drag.himax, drag.hiat + delta)); + UI.sliderHold.style.marginTop = `${topoff}px`; + drag.top = topoff; + sliderUpdate(); + }); + dragit(UI.sliderLo, (delta) => { + let midlen = Math.max(20, Math.min(drag.mdmax, drag.mdat + delta)); + UI.sliderMid.style.height = `${midlen}px`; + drag.mid = midlen; + sliderUpdate(); + }); + + UI.sliderMin.onclick = () => { + API.show.layer(0,0); + } + + UI.sliderMax.onclick = () => { + API.show.layer(API.var.layer_max,0); + } + + UI.slider.onmouseover = (ev) => { + API.event.emit('slider.label'); + }; + + UI.slider.onmouseleave = (ev) => { + if (!ev.buttons) API.event.emit('slider.unlabel'); + }; + + API.event.on('slider.unlabel', (values) => { + $('slider-hi-val').style.display = 'none'; + $('slider-lo-val').style.display = 'none'; + }); + + API.event.on('slider.label', (values) => { + $('slider-hi-val').style.display = 'flex'; + $('slider-lo-val').style.display = 'flex'; + $('slider-hi-val').innerText = API.var.layer_hi; + $('slider-lo-val').innerText = API.var.layer_lo; + }); + + API.event.on('slider.set', (values) => { + let height = slider.clientHeight; + let maxval = height - 40; + let start = Math.max(0, Math.min(1, values.start)); + let end = Math.max(start, Math.min(1, values.end)); + let topval = start * maxval; + let midval = ((end - start) * maxval) + 20; + UI.sliderHold.style.marginTop = `${topval}px`; + UI.sliderMid.style.height = `${midval}px`; + }); + + // bind language choices + $('lset-en').onclick = function() { SDB.setItem('kiri-lang', 'en-us'); API.space.reload(); }; - dlp.onclick = function() { + $('lset-da').onclick = function() { SDB.setItem('kiri-lang', 'da-dk'); API.space.reload(); }; @@ -1577,8 +1636,8 @@ var gs_kiri_init = exports; } SPACE.onEnterKey([ - UI.layerSpan, function() { API.show.slices() }, - UI.layerID, function() { API.show.layer(UI.layerID.value) }, + // UI.layerSpan, function() { API.show.slices() }, + // UI.layerID, function() { API.show.layer(UI.layerID.value) }, UI.scaleX, selectionScale, UI.scaleY, selectionScale, UI.scaleZ, selectionScale, @@ -1597,54 +1656,19 @@ var gs_kiri_init = exports; $('rot_z'), selectionRotate ]); - UI.layerID.convert = UC.toFloat.bind(UI.layerID); - UI.layerSpan.convert = UC.toFloat.bind(UI.layerSpan); - UI.layerRange.onclick = function() { - UI.layerRange.checked = !(UI.layerRange.checked || false); - API.show.slices(); - }; - - $('layer-toggle').onclick = function(ev) { - let ls = UI.layers.style; - ls.display = ls.display !== 'block' ? 'block' : 'none'; - UI.layers.style.left = ev.target.getBoundingClientRect().left + 'px'; - }; - - UI.modelOpacity.onchange = UI.modelOpacity.onclick = function(ev) { - API.widgets.opacity(parseInt(UI.modelOpacity.value)/100); - }; - - UI.layerSlider.ondblclick = function() { - UI.layerRange.checked = !UI.layerRange.checked; - API.show.slices(); - }; - - UI.layerSlider.onmousedown = function(ev) { - if (ev.shiftKey) UI.layerRange.checked = !UI.layerRange.checked; - }; - - UI.layerSlider.onclick = function() { - API.show.layer(UI.layerSlider.value); - }; - - UI.layerSlider.onmousemove = UI.layerSlider.onchange = function() { - API.show.layer(UI.layerSlider.value); - }; - - UI.layerSlider.onmouseup = function() { API.focus() }; - - UI.import.setAttribute("import","1"); - UI.import.onclick = function() { - UC.hidePoppers(); - API.dialog.show("catalog"); - }; - - $('cache-close').onclick = API.dialog.hide; - UI.toolMetric.onclick = updateTool; UI.toolType.onchange = updateTool; - $('apphelp').onclick = API.help.show; + function mksvg(src) { + let svg = DOC.createElement('svg'); + svg.innerHTML = src; + return svg; + } + + $('mode-fdm').appendChild(mksvg(icons.fdm)); + $('mode-sla').appendChild(mksvg(icons.sla)); + $('mode-cam').appendChild(mksvg(icons.cnc)); + $('mode-laser').appendChild(mksvg(icons.laser)); SPACE.platform.setSize( settings().device.bedWidth, @@ -1652,10 +1676,6 @@ var gs_kiri_init = exports; settings().device.bedHeight ); - if (compact) { - UI.selection.classList.add('compact'); - } - if (dark) { SPACE.platform.setGrid(25, 5, 0x999999, 0x333333); SPACE.platform.opacity(0.8); @@ -1688,22 +1708,6 @@ var gs_kiri_init = exports; } }); - // SPACE.mouse.onHover(function(d,me) { - // if (d) { - // // console.log(d,d.object.widget.id,d.face.materialIndex) - // // d.object.material.vertexColors = true; - // // d.object.material.needsUpdate = true; - // // d.face.vertexColors = [ - // // new THREE.Color(0xffaa88), - // // new THREE.Color(0xffaa88), - // // new THREE.Color(0xffaa88) - // // ]; - // // d.face.materialIndex = 1; - // } else { - // return API.widgets.meshes(); - // } - // }); - SPACE.mouse.onDrag(function(delta) { if (delta && UI.freeLayout.checked) { let set = settings(); @@ -1734,11 +1738,18 @@ var gs_kiri_init = exports; function init_two() { API.event.emit('init.two'); + // call driver initializations, if present + Object.values(KIRI.driver).forEach(driver => { + if (driver.init) try { + driver.init(KIRI, API); + } catch (error) { + console.log({driver_init_fail: driver, error}) + } + }); + let current = settings(), control = current.controller; - SPACE.scene.freeze(true); - platform.deselect(); CATALOG.addFileListener(updateCatalog); SPACE.view.setZoom(control.reverseZoom, control.zoomSpeed); @@ -1750,13 +1761,12 @@ var gs_kiri_init = exports; UI.autoLayout.checked = control.autoLayout; UI.alignTop.checked = control.alignTop; UI.reverseZoom.checked = control.reverseZoom; - UI.compact.checked = control.compact; // load script extensions if (SETUP.s) SETUP.s.forEach(function(lib) { let scr = DOC.createElement('script'); scr.setAttribute('defer',true); - scr.setAttribute('src','/code/'+lib+'.js'); + scr.setAttribute('src',`/code/${lib}.js?${KIRI.version}`); DOC.body.appendChild(scr); STATS.add('load_'+lib); API.event.emit('load.lib', lib); @@ -1768,7 +1778,7 @@ var gs_kiri_init = exports; let ss = DOC.createElement('link'); ss.setAttribute("type", "text/css"); ss.setAttribute("rel", "stylesheet"); - ss.setAttribute("href", `${style}.css`); + ss.setAttribute("href", `${style}.css?${KIRI.version}`); DOC.body.appendChild(ss); }); @@ -1804,15 +1814,15 @@ var gs_kiri_init = exports; // ensure hot keys work even in iframes API.focus(); - // place version number a couple of places to help users - UI.helpButton.title = `${LANG.version} ` + KIRI.version; - // restore expert setting preference - UC.setExpert(control.expert); + API.mode.set_expert(control.expert); // setup tab visibility watcher // DOC.addEventListener('visibilitychange', function() { document.title = document.hidden }); + // fill device list + updateDeviceList(); + // ensure settings has gcode selectDevice(DEVNAME || API.device.get(), DEVNAME); @@ -1836,18 +1846,48 @@ var gs_kiri_init = exports; // add ability to override API.show.controls(API.feature.controls); - // set initial layer slider size - API.dialog.update(); - - // show version on startup - API.show.alert(`${LANG.version} ${KIRI.version}`); + // enable modal hiding + $('mod-x').onclick = API.modal.hide; if (!SETUP.s) console.log(`kiri | init main | ${KIRI.version}`); // send init-done event API.event.emit('init-done', STATS); - SPACE.scene.freeze(false); + // lift curtain + $('curtain').style.display = 'none'; + + function showSetup() { + API.modal.show('setup'); + } + + // bind interface action elements + $('app-name').onclick = API.help.show; + $('app-mode').onclick = (ev) => { ev.stopPropagation(); showSetup() }; + $('set-device').onclick = (ev) => { ev.stopPropagation(); showSetup() }; + $('set-tools').onclick = (ev) => { ev.stopPropagation(); showTools() }; + $('set-prefs').onclick = (ev) => { ev.stopPropagation(); API.modal.show('prefs') }; + $('set-help').onclick = (ev) => { ev.stopPropagation(); API.help.show() }; + $('acct-help').onclick = (ev) => { ev.stopPropagation(); API.help.show() }; + $('file-recent').onclick = () => { API.modal.show('files') }; + $('file-import').onclick = () => { API.event.import() }; + $('lt-back').onclick = API.platform.layout; + $('lt-action').onclick = API.platform.layout; + UI.act.slice.onclick = (ev) => { ev.stopPropagation(); API.function.slice() }; + UI.act.preview.onclick = (ev) => { ev.stopPropagation(); API.function.print() }; + UI.act.export.onclick = (ev) => { ev.stopPropagation(); API.function.export() }; + $('view-arrange').onclick = API.platform.layout; + $('view-top').onclick = SPACE.view.top; + $('view-home').onclick = SPACE.view.home; + $('mode-fdm').onclick = () => { API.mode.set('FDM') }; + $('mode-sla').onclick = () => { API.mode.set('SLA') }; + $('mode-cam').onclick = () => { API.mode.set('CAM') }; + $('mode-laser').onclick = () => { API.mode.set('LASER') }; + + // add app name hover info + $('app-info').innerText = KIRI.version; + // show topline separator when iframed + // try { if (WIN.self !== WIN.top) $('top-sep').style.display = 'flex' } catch (e) { } } // if a language needs to load, the script is injected and loaded diff --git a/src/kiri/lang-en.js b/src/kiri/lang-en.js new file mode 120000 index 00000000..92cc3a27 --- /dev/null +++ b/src/kiri/lang-en.js @@ -0,0 +1 @@ +../../web/kiri/lang/en.js \ No newline at end of file diff --git a/js/kiri-lang.js b/src/kiri/lang.js similarity index 85% rename from js/kiri-lang.js rename to src/kiri/lang.js index d130eec3..d5fe584c 100644 --- a/js/kiri-lang.js +++ b/src/kiri/lang.js @@ -1,17 +1,14 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_lang = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.lang) return; - let KIRI = self.kiri, - LANG = self.kiri.lang = { current: {} }, - lset = navigator.language.toLocaleLowerCase(); + const KIRI = self.kiri, LANG = self.kiri.lang = { current: {} }; + + let lset = navigator.language.toLocaleLowerCase(); LANG.get = function() { return lset; diff --git a/js/kiri-layer.js b/src/kiri/layer.js similarity index 83% rename from js/kiri-layer.js rename to src/kiri/layer.js index 68a24552..06b44c2a 100644 --- a/js/kiri-layer.js +++ b/src/kiri/layer.js @@ -1,15 +1,12 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_layer = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.Layer) return; - let KIRI = self.kiri, + const KIRI = self.kiri, POLY = self.base.polygons, LP = Layer.prototype, mcache = {}; @@ -82,30 +79,35 @@ let gs_kiri_layer = exports; this.view = view; this.bycolor = {}; this.opacity = 0.15, - this.specular = 0x181818, - this.shininess = 100, + this.specular = 0x181818; + this.shininess = 100; this.transparent = true; }; LP.setOpacity = function(v) { this.opacity = v; + return this; }; LP.setSpecular = function(v) { this.specular = v; + return this; }; LP.setShininess = function(v) { this.shininess = v; + return this; }; LP.setTransparent = function(b) { this.transparent = b; + return this; }; LP.setVisible = function(vis) { if (this.group) this.group.visible = vis; if (this.solids) this.solids.visible = vis; + return this; }; LP.clear = function() { @@ -117,6 +119,7 @@ let gs_kiri_layer = exports; let ca = this.bycolor[color]; if (!ca) ca = this.bycolor[color] = []; ca.push(obj); + return this; }; LP.poly = function(poly, color, deep, open) { @@ -127,14 +130,17 @@ let gs_kiri_layer = exports; this.add(color, {poly:poly, deep:deep, open:open}); this.changed = true; } + return this; }; LP.solid = function(poly, color) { this.add(color, {solid: poly}); this.changed = true; + return this; }; LP.noodle = function(poly, offset, color, traceColor, open) { + if (!poly) return; if (Array.isArray(poly)) { poly = POLY.flatten(poly, [], true); } else { @@ -148,11 +154,38 @@ let gs_kiri_layer = exports; POLY.expand([p], -offset, z-0.01, exp, 1); POLY.nest(exp).forEach((p,i) => { this.add(color, {solid: p}); - p = p.clone(true).setZ(z + 0.01); - this.add(traceColor, {poly: p, deep: true, open}); + this.add(traceColor, {poly: p.clone(true).setZ(z + 0.01), deep: true, open}); }); }) this.changed = true; + return this; + }; + + LP.noodle_open = function(poly, offset, color, traceColor, z) { + poly = POLY.expand_lines(poly, offset, z); + poly.forEach(p => { + this.add(color, {solid: p}); + this.add(traceColor, {poly: p.clone().setZ(z + 0.01), deep: false, open: false}); + }) + this.changed = true; + return this; + }; + + LP.noodle_lines = function(points, offset, color, traceColor, z) { + if (!(points && points.length)) return; + for (let i=0; i -- All Rights Reserved */ -self.kiri = (self.kiri || {}); -self.kiri.version = exports.VERSION; -self.kiri.license = exports.LICENSE; -self.kiri.copyright = exports.COPYRIGHT; +"use strict"; (function () { @@ -43,8 +39,9 @@ self.kiri.copyright = exports.COPYRIGHT; newWidget = kiri.newWidget, // --------------- UI = {}, - UC = MOTO.ui.prefix('kiri').inputAction(updateSettings).hideAction(updateDialogLeft), + UC = KIRI.ui.prefix('kiri').inputAction(updateSettings).hideAction(updateDialogLeft), MODE = MODES.FDM, + DRIVER = undefined, onEvent = {}, currentPrint = null, selectedMeshes = [], @@ -180,18 +177,17 @@ self.kiri.copyright = exports.COPYRIGHT; SECURE }, var: { - layer_at: Infinity, - layer_max: 0, - layer_range: 0 + layer_lo: 0, + layer_hi: 0, + layer_max: 0 }, device: { get: currentDeviceName, set: undefined // set during init }, dialog: { - show: showDialog, - hide: hideDialog, - update: updateDialogLeft + show: showModal, + hide: hideModal }, help: { show: showHelp, @@ -212,7 +208,7 @@ self.kiri.copyright = exports.COPYRIGHT; clear: clearWidgetCache }, hide: { - import: function() { UI.import.style.display = 'none' } + import: function() { } }, language: KIRI.lang, lists, @@ -262,6 +258,7 @@ self.kiri.copyright = exports.COPYRIGHT; view: { get: function() { return viewMode }, set: setViewMode, + update_slider: updateSlider, update_fields: updateFields, wireframe: toggleWireframe, snapshot: null @@ -466,8 +463,21 @@ self.kiri.copyright = exports.COPYRIGHT; return Math.max(min,Math.min(max,v)); } - function setVisibleLayer(v) { - showSlices(API.var.layer_at = bound(v, 0, API.var.layer_max)); + function updateSlider() { + API.event.emit("slider.set", { + start: 1 - (API.var.layer_hi / API.var.layer_max), + end: 1 - (API.var.layer_lo / API.var.layer_max) + }); + } + + function setVisibleLayer(h, l) { + h = h >= 0 ? h : API.var.layer_hi; + l = l >= 0 ? l : API.var.layer_lo; + API.var.layer_hi = bound(h, 0, API.var.layer_max); + API.var.layer_lo = bound(l, 0, h); + API.event.emit("slider.label"); + updateSlider(); + showSlices(); } function meshArray() { @@ -494,9 +504,11 @@ self.kiri.copyright = exports.COPYRIGHT; }); } - function forSelectedWidgets(f) { + function forSelectedWidgets(f,noauto) { let m = selectedMeshes; - if (m.length === 0 && WIDGETS.length === 1) m = [ WIDGETS[0].mesh ]; + if (m.length === 0 && WIDGETS.length === 1) { + m = noauto ? [] : [ WIDGETS[0].mesh ]; + } m.slice().forEach(function (mesh) { f(mesh.widget) }); } @@ -520,16 +532,11 @@ self.kiri.copyright = exports.COPYRIGHT; }); } max = Math.max(0, max - 1); - API.var.layer_max = max; - if (UI.layerID.convert() > max || API.var.layer_at > max) { - API.var.layer_at = max; - UI.layerID.value = max; - UI.layerSlider.value = API.var.layer_max; - } - UI.layerSlider.max = max; - if (set) { - API.var.layer_at = API.var.layer_max; - UI.layerSlider.value = API.var.layer_max; + API.var.layer_max = UI.sliderMax.innerText = max; + if (set || max < API.var.layer_hi) { + API.var.layer_hi = API.var.layer_max; + API.event.emit("slider.label"); + updateSlider(); } } @@ -544,85 +551,69 @@ self.kiri.copyright = exports.COPYRIGHT; return showing; } - function showSlice(index, range, layer) { - if (range) { - return index <= layer && index > layer-range; - } else { - return index <= layer; - } - } - /** * hide or show slice-layers and their sub-elements * * @param {number} [layer] */ function showSlices(layer) { + if (viewMode === VIEWS.ARRANGE) { + return; + } + + showSlider(); + if (typeof(layer) === 'string' || typeof(layer) === 'number') { layer = parseInt(layer); } else { - layer = API.var.layer_at; + layer = API.var.layer_hi; } layer = bound(layer, 0, API.var.layer_max); + API.var.layer_hi = layer; + API.event.emit("slider.label"); - UI.layerID.value = layer; - UI.layerSlider.value = layer; + let print = UI.layerPrint.checked, + moves = UI.layerMoves.checked, + cam = MODE === MODES.CAM, + hi = cam ? API.var.layer_max - API.var.layer_lo : API.var.layer_hi, + lo = cam ? API.var.layer_max - API.var.layer_hi : API.var.layer_lo; - let j, - slice, - slices, - layers, - range = UI.layerRange.checked ? UI.layerSpan.convert() || 1 : 0, - print = UI.layerPrint.checked, - moves = UI.layerMoves.checked; - - if (MODE === MODES.CAM && API.var.layer_range !== range && range && layer === API.var.layer_max) { - layer = 0; - } - - API.var.layer_range = range; - API.var.layer_at = layer; + updateSlider(); forAllWidgets(function(widget) { if (print) return widget.hideSlices(); - slices = widget.slices; + let slices = widget.slices; if (!slices) return; - for (j = 0; j < slices.length; j++) { - slice = slices[j]; - slice.view.visible = showSlice(j, range, layer); - layers = slice.layers; - layers.outline.setVisible( - MODE === MODES.CAM ? - UI.layerOutline.checked && LOCAL : - UI.layerOutline.checked + for (let j = 0; j < slices.length; j++) { + let slice = slices[j]; + slice.view.visible = j >= lo && j <= hi; + let layers = slice.layers; + layers.outline.setVisible(cam ? + UI.layerOutline.checked : + UI.layerOutline.checked ); - layers.trace.setVisible( - MODE === MODES.CAM ? - UI.layerRough.checked : - UI.layerTrace.checked + layers.trace.setVisible(cam ? + UI.layerRough.checked : + UI.layerTrace.checked ); - layers.bridge.setVisible( - MODE === MODES.CAM ? - UI.layerFinishX.checked : - UI.layerDelta.checked + layers.bridge.setVisible(cam ? + UI.layerFinishX.checked : + UI.layerDelta.checked ); - layers.flat.setVisible( - MODE === MODES.CAM ? - UI.layerFinishY.checked : - UI.layerDelta.checked + layers.flat.setVisible(cam ? + UI.layerFinishY.checked : + UI.layerDelta.checked ); - layers.solid.setVisible( - MODE === MODES.CAM ? - UI.layerFinish.checked : - UI.layerSolid.checked + layers.solid.setVisible(cam ? + UI.layerFinish.checked : + UI.layerSolid.checked ); - layers.fill.setVisible( - MODE === MODES.CAM ? - UI.layerFacing.checked : - UI.layerFill.checked + layers.fill.setVisible(cam ? + UI.layerFacing.checked : + UI.layerFill.checked ); layers.sparse.setVisible(UI.layerSparse.checked); layers.support.setVisible(UI.layerSupport.checked); @@ -631,10 +622,11 @@ self.kiri.copyright = exports.COPYRIGHT; if (currentPrint) { let len = currentPrint.getLayerCount(); - for (j = 0; j < len; j++) { - currentPrint.showLayer(j, print && showSlice(j, range, layer), moves); + for (let j = 0; j < len; j++) { + currentPrint.showLayer(j, print && j >= lo && j <= hi, moves); } } + UI.layerPrint.parentNode.style.display = currentPrint ? '' : 'none'; UI.layerMoves.parentNode.style.display = currentPrint ? '' : 'none'; @@ -671,6 +663,7 @@ self.kiri.copyright = exports.COPYRIGHT; function preparePrint(callback) { if (viewMode === VIEWS.PREVIEW) return; + hideSlider(true); // kick off slicing it hasn't been done already for (let i=0; i < WIDGETS.length; i++) { @@ -746,6 +739,18 @@ self.kiri.copyright = exports.COPYRIGHT; }); } + function showSlider() { + UI.layers.style.display = 'flex'; + UI.slider.style.display = 'flex'; + UI.setMenu.style.display = 'none'; + } + + function hideSlider(andmenu) { + UI.layers.style.display = 'none'; + UI.slider.style.display = 'none'; + UI.setMenu.style.display = andmenu ? 'none' : 'flex'; + } + /** * incrementally slice all meshes then incrementally update them * @@ -757,7 +762,11 @@ self.kiri.copyright = exports.COPYRIGHT; API.view.snapshot = snap.substring(snap.indexOf(",")+1); KIRI.work.snap(API.view.snapshot); } + if (MODE === MODES.SLA && !callback) { + callback = preparePrint; + } + hideSlider(true); clearPrint(); platform.deselect(); setViewMode(VIEWS.SLICE); @@ -766,7 +775,7 @@ self.kiri.copyright = exports.COPYRIGHT; let firstMesh = true, countdown = WIDGETS.length, preserveMax = API.var.layer_max, - preserveLayer = API.var.layer_at, + preserveLayer = API.var.layer_hi, totalProgress, track = {}, now = UTIL.time(); @@ -789,7 +798,7 @@ self.kiri.copyright = exports.COPYRIGHT; widget.slice(settings, function(sliced, error) { let mark = UTIL.time(); // on done - widget.render(renderMode, MODE === MODES.CAM); + widget.render(); // clear wireframe widget.setWireframe(false, color.wireframe, color.wireframe_opacity); widget.setOpacity(settings.mode === 'CAM' ? color.cam_sliced_opacity : color.sliced_opacity); @@ -816,8 +825,6 @@ self.kiri.copyright = exports.COPYRIGHT; callback(); } } - // update slider window - API.dialog.update(); // handle slicing errors if (error && !errored) { errored = true; @@ -880,7 +887,7 @@ self.kiri.copyright = exports.COPYRIGHT; function setOpacity(value) { forAllWidgets(function (w) { w.setOpacity(value) }); - UI.modelOpacity.value = value * 100; + // UI.modelOpacity.value = value * 100; SPACE.update(); } @@ -998,7 +1005,9 @@ self.kiri.copyright = exports.COPYRIGHT; } function platformSelect(widget, shift) { - if (viewMode !== VIEWS.ARRANGE) return; + if (viewMode !== VIEWS.ARRANGE) { + return; + } let mesh = widget.mesh, sel = (selectedMeshes.indexOf(mesh) >= 0); if (sel) { @@ -1026,19 +1035,24 @@ self.kiri.copyright = exports.COPYRIGHT; } function platformUpdateSelected() { - UI.selection.style.display = platform.selected_count() ? 'inline' : 'none'; - $('ext-sel').style.display = (MODE === MODES.FDM) ? 'inline-block' : 'none'; let extruders = settings.device.extruders; + let menu_show = platform.selected_count() ? 'flex': ''; + let ext_show = platform.selected_count() && MODE === 'FDM' ? 'flex': ''; + UI.scale.style.display = menu_show; + UI.rotate.style.display = menu_show; + UI.nozzle.style.display = extruders && extruders.length > 1 ? menu_show : ''; + UI.menusep.style.display = menu_show; if (extruders) { for (let i=0; i { + w.setColor(color.selected, settings); let ext = (settings.widget[w.id] || {}).extruder || 0; let b = $(`sel-ext-${ext}`); - if (b) b.classList.add('buton'); - }); + if (b) b.classList.add('pop-sel'); + }, true); } } @@ -1233,7 +1247,7 @@ self.kiri.copyright = exports.COPYRIGHT; camTopZ = topZ; // create/inject cam stock if stock size other than default if (MODE === MODES.CAM && stockSet && WIDGETS.length) { - UI.stock.style.display = offset ? 'inline-block' : 'none'; + // UI.stock.style.display = offset ? 'inline-block' : 'none'; let csx = sd.camStockX * scale; let csy = sd.camStockY * scale; let csz = sd.camStockZ * scale; @@ -1261,9 +1275,9 @@ self.kiri.copyright = exports.COPYRIGHT; csz += max.z - min.z; csox = min.x + ((max.x - min.x) / 2); csoy = min.y + ((max.y - min.y) / 2); - $('stock-width').innerText = (csx/scale).toFixed(2); - $('stock-depth').innerText = (csy/scale).toFixed(2); - $('stock-height').innerText = (csz/scale).toFixed(2); + // $('stock-width').innerText = (csx/scale).toFixed(2); + // $('stock-depth').innerText = (csy/scale).toFixed(2); + // $('stock-height').innerText = (csz/scale).toFixed(2); } if (!camStock) { let geo = new THREE.BoxGeometry(1, 1, 1); @@ -1286,7 +1300,7 @@ self.kiri.copyright = exports.COPYRIGHT; camStock.material.visible = settings.mode === 'CAM'; camTopZ = csz; } else if (camStock) { - UI.stock.style.display = 'none'; + // UI.stock.style.display = 'none'; SPACE.platform.remove(camStock); camStock = null; camTopZ = topZ; @@ -1435,6 +1449,8 @@ self.kiri.copyright = exports.COPYRIGHT; } API.conf.save(); platform.update_stock(); + $('mode-device').innerText = settings.device.deviceName; + $('mode-profile').innerText = settings.process.processName; } function saveSettings() { @@ -1626,36 +1642,53 @@ self.kiri.copyright = exports.COPYRIGHT; } function modalShowing() { - let showing = $('modal').style.display !== 'none'; - return showing || UC.isPopped(); + return UI.modal.style.display === 'flex'; } function showModal(which) { - UI.modal.style.display = 'block'; - ["print","help","local"].forEach(function(modal) { - UI[modal].style.display = (modal === which ? 'block' : 'none'); + let mod = UI.modal, + style = mod.style, + visible = modalShowing(), + info = { pct: 0 }; + + ["help","setup","tools","prefs","saves","files","print","local"].forEach(function(name) { + UI[name].style.display = name === which ? 'flex' : ''; }); - if (which) API.event.emit('modal.show', which); + + function ondone() { + API.event.emit('modal.show', which); + } + + if (visible) { + return ondone(); + } + + style.height = '0'; + style.display = 'flex'; + + new TWEEN.Tween(info). + easing(TWEEN.Easing.Quadratic.InOut). + to({ pct: 100 }, 100). + onUpdate(() => { style.height = `${info.pct}%` }). + onComplete(ondone). + start(); } - function hideDialog() { - showDialog(null); - } - - function showDialog(which, force) { - if (UC.isPopped()) { - UC.hidePop(); + function hideModal() { + if (!modalShowing()) { return; } - ["catalog","devices","tools","settings"].forEach(function(dialog) { - let style = UI[dialog].style; - style.display = (dialog === which && (force || style.display !== 'flex') ? 'flex' : 'none'); - }); - if (which) API.event.emit('dialog.show', which); + let mod = UI.modal, style = mod.style, info={pct:100}; + new TWEEN.Tween(info). + easing(TWEEN.Easing.Quadratic.InOut). + to({pct:0}, 100). + onUpdate(() => { style.height = `${info.pct}%` }). + onComplete(() => { style.display = '' }). + start(); } function showCatalog() { - showDialog("catalog"); + showModal("files"); } function getSettings() { @@ -1691,7 +1724,6 @@ self.kiri.copyright = exports.COPYRIGHT; let mode = getMode(), name = e ? e.target.getAttribute("load") : named || settings.cproc[mode], load = settings.sproc[mode][name]; - if (!load) return; settings.process = clone(load); @@ -1701,20 +1733,11 @@ self.kiri.copyright = exports.COPYRIGHT; // associate named process with the current device settings.devproc[currentDeviceName()] = name; - // update selection display - $('selected-mode').innerHTML = API.mode.get(); - $('selected-device').innerHTML = API.device.get(); - $('selected-process').innerHTML = name; - // FDM process settings overridden by device if (mode == "FDM") { settings.process.outputOriginCenter = (settings.device.originCenter || false); } - if (!named) { - hideDialog(); - } - updateFields(); API.conf.update(); if (e) triggerSettingsEvent(); @@ -1742,7 +1765,10 @@ self.kiri.copyright = exports.COPYRIGHT; name = sk; load.setAttribute('load', sk); - load.onclick = API.conf.load; + load.onclick = (ev) => { + API.conf.load(undefined, sk); + updateSettingsList(); + } load.appendChild(DOC.createTextNode(sk)); if (sk == settings.process.processName) { load.setAttribute('class', 'selected') @@ -1764,15 +1790,15 @@ self.kiri.copyright = exports.COPYRIGHT; row.appendChild(del); table.appendChild(row); }); - API.dialog.update(); } function showSettings() { updateSettingsList(); - showDialog("settings"); + showModal("saves"); } function updateDialogLeft() { + return console.log('TODO updateDialogLeft'); let left = UI.ctrlLeft.getBoundingClientRect(); let right = UI.ctrlRight.getBoundingClientRect(); UI.catalog.style.left = (left.width + 5) + 'px'; @@ -1781,35 +1807,31 @@ self.kiri.copyright = exports.COPYRIGHT; UI.settings.style.right = (right.width + 5) + 'px'; } - function hideModal() { - UI.modal.style.display = 'none'; - } - function showHelp() { showHelpFile(`/kiri/lang/${KIRI.lang.get()}-help.html?${KIRI.version}`); } function showHelpFile(local) { - hideDialog(); if (!local) { WIN.open("//wiki.grid.space/wiki/Kiri:Moto", "_help"); return; } ajax(local, function(html) { UI.help.innerHTML = html; - try { $('help-close').onclick = hideModal; } catch (e) { console.log(e, html) } - try { $('kiri-version').innerHTML = `${LANG.version} ${KIRI.version}`; } catch (e) { } + try { + $('kiri-version').innerHTML = `${LANG.version} ${KIRI.version}`; + } catch (e) { } showModal('help'); }); API.event.emit('help.show', local); } function showLocal() { - $('local-close').onclick = hideModal; showModal('local'); fetch("/api/grid_local") .then(r => r.json()) .then(j => { + let devc = 0; let bind = []; let html = ['']; html.push(``); @@ -1823,10 +1845,15 @@ self.kiri.copyright = exports.COPYRIGHT; html.push(``); html.push(``); html.push(``); + devc++; } html.push(``); html.push(`
devicetypestatus
${r.state}
`); - $('local-dev').innerHTML = html.join(''); + if (devc) { + $('mod-local').innerHTML = html.join(''); + } else { + $('mod-local').innerHTML = `
no local devices`; + } bind.forEach(rec => { $(rec.uuid).onclick = () => { window.open(`http://${rec.host}:${rec.port||4080}/`); @@ -1836,7 +1863,7 @@ self.kiri.copyright = exports.COPYRIGHT; } function setFocus(el) { - el = [ el || UI.load, UI.import, UI.ctrlLeft, UI.container, UI.assets, UI.control, UI.modeFDM, UI.reverseZoom, UI.modelOpacity, DOC.body ]; + el = [ el || UI.focuser, UI.load, UI.sizeX, DOC.body ]; for (let es, i=0; i { + let cl = $(`mode-${dev}`).classList; + if (dev === mode.toLowerCase()) { + cl.add("dev-sel"); + } else { + cl.remove("dev-sel"); + } + }); // restore cached device profile for this mode if (settings.cdev[mode]) { settings.device = clone(settings.cdev[mode]); API.event.emit('device.set', currentDeviceName()); } - if (MODE === MODES.CAM) { - SPACE.platform.setColor(0xeeeeee); - } else { - SPACE.platform.setColor(0xcccccc); - } - MODE = MODES[mode]; - // updates right-hand menu by enabling/disabling fields - setViewMode(VIEWS.ARRANGE); - UC.setMode(MODE); - API.conf.load(); - API.conf.save(); - clearWidgetCache(); - SPACE.update(); - UI.modeFDM.setAttribute('class', MODE === MODES.FDM ? 'buton' : ''); - UI.modeSLA.setAttribute('class', MODE === MODES.SLA ? 'buton' : ''); - UI.modeCAM.setAttribute('class', MODE === MODES.CAM ? 'buton' : ''); - UI.modeLASER.setAttribute('class', MODE === MODES.LASER ? 'buton' : ''); - UI.mode.style.display = lock ? 'none' : ''; - UI.modeTable.style.display = lock ? 'none' : ''; - UI.modelOpacity.style.display = MODE === MODES.SLA ? 'none' : ''; - UI.modePreview.style.display = MODE === MODES.SLA ? 'none' : ''; + // really belongs in CAM driver (lots of work / abstraction needed) if (camStock) { camStock.material.visible = settings.mode === 'CAM'; } - API.space.restore(null, true); - if (then) then(); + // updates right-hand menu by enabling/disabling fields + setViewMode(VIEWS.ARRANGE); + UC.setMode(MODE); + // sanitize and persist settings + API.conf.load(); + API.conf.save(); + // other housekeeping + clearWidgetCache(); triggerSettingsEvent(); platformUpdateSelected(); updateFields(); - if (settings.device.new) { + // because device dialog, if showing, needs to be updated + if (modalShowing()) { API.show.devices(); } + API.space.restore(null, true); API.event.emit("mode.set", mode); + if (then) { + then(); + } } function currentDeviceName() { @@ -1958,8 +1974,8 @@ self.kiri.copyright = exports.COPYRIGHT; } function setControlsVisible(show) { - UI.ctrlLeft.style.display = show ? 'block' : 'none'; - UI.ctrlRight.style.display = show ? 'block' : 'none'; + $('mid-lcol').style.display = show ? 'flex' : 'none'; + $('mid-rcol').style.display = show ? 'flex' : 'none'; } // prevent safari from exiting full screen mode diff --git a/js/kiri-print.js b/src/kiri/print.js similarity index 92% rename from js/kiri-print.js rename to src/kiri/print.js index 5e2e5dae..18ca7445 100644 --- a/js/kiri-print.js +++ b/src/kiri/print.js @@ -1,14 +1,12 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_print = exports; - (function() { - if (!self.kiri) self.kiri = {}; + if (self.kiri.newPrint) return; - let KIRI = self.kiri, + const KIRI = self.kiri, DRIVERS = KIRI.driver, LASER = DRIVERS.LASER, CAM = DRIVERS.CAM, @@ -22,8 +20,9 @@ let gs_kiri_print = exports; PI = Math.PI, PRO = Print.prototype, Polygon = BASE.Polygon, - newPoint = BASE.newPoint, - lastPoint = null, + newPoint = BASE.newPoint; + + let lastPoint = null, lastEmit = null; KIRI.newPrint = function(settings, widgets, id) { @@ -51,6 +50,8 @@ let gs_kiri_print = exports; this.distance = 0; this.bounds = null; this.imported = null; + + this.hsv2rgb = hsv2rgb; } PRO.addOutput = addOutput; @@ -228,6 +229,8 @@ let gs_kiri_print = exports; } else { // executed from kiri-worker.js + // uses encodeOutput in this class to produce scope.output above + // this encoding could be made vastly more efficient let driver = KIRI.driver[mode]; if (driver) driver.printSetup(scope, onupdate); else console.log({missing_print_driver: mode}); @@ -317,7 +320,8 @@ let gs_kiri_print = exports; emit: out.emit, speed: out.speed * 60, retract: out.retract, - point: {x: out.point.x, y: out.point.y, z: out.point.z} + point: {x: out.point.x, y: out.point.y, z: out.point.z}, + tool: out.tool }); } }); @@ -327,25 +331,17 @@ let gs_kiri_print = exports; }; PRO.render = function() { - let scope = this, - settings = scope.settings, - process = settings.process, + let settings = this.settings, origin = settings.origin, mode = settings.mode, + tools = [], driver = KIRI.driver[mode]; - switch (mode) { - case 'SLA': - driver.printRender(scope); - break; - case 'CAM': - case 'FDM': - scope.renderMoves(true, 0x888888); - break; - case 'LASER': - scope.renderMoves(false, 0x0088aa); - break; + if (mode === 'FDM') { + tools = settings.device.extruders || []; } + + driver.printRender(this, {tools}); }; function pref(a,b) { @@ -425,69 +421,6 @@ let gs_kiri_print = exports; return out; } - PRO.renderMoves = function(showMoves, moveColor, firstPoint) { - let debug = KIRI.api.const.LOCAL; - let scope = this, emits, moves, last = firstPoint; - // render layered output - scope.lines = 0; - scope.output.forEach(function(layerout) { - let move = [], print = {}, z; - layerout.forEach(function(out, index) { - let point = out.point; - if (last) { - if (UTIL.distSq(last, point) < 0.001 && point.z === last.z) { - return; - } - if (out.emit > 0) { - let spd = out.speed || 4000; - let arr = print[spd] || []; - print[spd] = arr; - arr.push(last); - arr.push(point); - } else { - move.push(last); - move.push(point); - } - if (debug && showMoves && last.z == point.z) { - let rs = BASE.newSlope( - {x: point.x, y: point.y}, - {x: last.x, y: last.y} - ); - let ao1 = BASE.newSlopeFromAngle(rs.angle + 25); - let ao2 = BASE.newSlopeFromAngle(rs.angle - 25); - let sp = BASE.newPoint(point.x, point.y, point.z); - move.push(sp); - move.push(sp.projectOnSlope(ao1, 0.5)); - move.push(sp); - move.push(sp.projectOnSlope(ao2, 0.5)); - } - } else { - z = point.z; - } - last = point; - }); - emits = KIRI.newLayer(scope.group); - scope.printView.push(emits); - if (showMoves) { - moves = KIRI.newLayer(scope.group); - moves.lines(move, moveColor); - scope.movesView.push(moves); - moves.render(); - } - for (let speed in print) { - let sint = Math.min(6000, parseInt(speed)); - let rgb = hsv2rgb({h:sint/6000, s:1, v:0.6}); - emits.lines(print[speed], - ((rgb.r * 0xff) << 16) | - ((rgb.g * 0xff) << 8) | - ((rgb.b * 0xff) << 0) - ); - } - emits.render(); - scope.lines += print.length; - }); - } - PRO.getLayerCount = function() { return this.output.length; } diff --git a/js/kiri-slice.js b/src/kiri/slice.js similarity index 99% rename from js/kiri-slice.js rename to src/kiri/slice.js index 2a19eac3..c38e1394 100644 --- a/js/kiri-slice.js +++ b/src/kiri/slice.js @@ -1,26 +1,21 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_slice = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.Slice) return; - let KIRI = self.kiri, + const KIRI = self.kiri, FILL = KIRI.fill, FILLFIXED = KIRI.fill_fixed, + PRO = Slice.prototype, BASE = self.base, UTIL = BASE.util, POLY = BASE.polygons, - PRO = Slice.prototype, + NOKEY = BASE.key.NONE, fillArea = POLY.fillArea, newPoint = BASE.newPoint, - MIN = Math.min, - MAX = Math.max, - NOKEY = BASE.key.NONE, outline_colors = [ 0xeeee00, 0xeebb00, diff --git a/js/kiri-slicer.js b/src/kiri/slicer.js similarity index 99% rename from js/kiri-slicer.js rename to src/kiri/slicer.js index 108e6301..f61c2306 100644 --- a/js/kiri-slicer.js +++ b/src/kiri/slicer.js @@ -1,15 +1,12 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_slicer = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.slicer) return; - let slicer = self.kiri.slicer = { + self.kiri.slicer = { slice: slice, sliceWidget: sliceWidget, connectLines: connectLines @@ -271,6 +268,7 @@ let gs_kiri_slicer = exports; // copy to store original z zHeights = zIndexes.slice(); } else if (zIncMin) { + // console.log('adaptive slicing', zIncMin, ':', zInc, 'from', zMin, 'to', zMax); // FDM adaptive slicing let zPos = zMin + zIncFirst, zOI = 0, @@ -311,6 +309,7 @@ let gs_kiri_slicer = exports; } } } else { + // console.log('fixed slicing', zInc, 'from', zMin, 'to', zMax); // FDM fixed slicing if (options.firstHeight) { zIndexes.push(options.firstHeight / 2); @@ -322,6 +321,7 @@ let gs_kiri_slicer = exports; zHeights.push(zInc); } } + // create a Slice for each z offset in the zIndexes array for (let i = 0; i < zIndexes.length; i++) { let ik = zIndexes[i].toFixed(5), diff --git a/src/kiri/ui.js b/src/kiri/ui.js new file mode 100644 index 00000000..01e35d80 --- /dev/null +++ b/src/kiri/ui.js @@ -0,0 +1,586 @@ +/** Copyright Stewart Allen -- All Rights Reserved */ + +"use strict"; + +(function() { + + if (kiri.ui) return; + + let SELF = self, + KIRI = self.kiri, + lastGroup = null, + lastDiv = null, + addTo = null, + hideAction = null, + inputAction = null, + groups = {}, + groupShow = {}, + groupName = undefined, + poppable = {}, + hasModes = [], + isExpert = [], + letMode = null, + letExpert = false, + DOC = SELF.document, + state = {}, + prefix = "tab", + NOMODE = "nomode", + exitimer = undefined; + + SELF.$ = (SELF.$ || function (id) { return DOC.getElementById(id) } ); + + KIRI.ui = { + prefix: function(pre) { prefix = pre; return kiri.ui }, + hideAction: function(fn) { hideAction = fn; return kiri.ui }, + inputAction: function(fn) { inputAction = fn; return kiri.ui }, + setMode: setMode, + setExpert: setExpert, + bound: bound, + toInt: toInt, + toFloat: toFloat, + hidePop: hidePop, + isPopped: isPopped, + newText: newTextArea, + newLabel: newLabel, + newRange: newRange, + newInput: newInputField, + newButton: newButton, + newBoolean: newBooleanField, + newSelect: newSelect, + newTable: newTables, + newTableRow: newTableRow, + newRow: newRow, + newBlank: newBlank, + newGroup: newGroup, + setGroup: setGroup, + hidePoppers: hidePoppers, + checkpoint, + restore + }; + + function setMode(mode) { + Object.keys(groupShow).forEach(group => { + updateGroupShow(group); + }); + letMode = mode; + hasModes.forEach(function(div) { + div.setMode(div._group && !groupShow[div._group] ? NOMODE : mode); + }); + hidePoppers(); + } + + function setExpert(bool) { + letExpert = bool; + setMode(letMode); + } + + function checkpoint() { + return { addTo, lastDiv, lastGroup, groupName }; + } + + function restore(opt) { + if (opt) { + addTo = opt.addTo; + lastDiv = opt.lastDiv; + lastGroup = opt.lastGroup; + groupName = opt.groupName; + } + } + + // at present only used by the layers popup menu + function setGroup(div) { + addTo = lastDiv = div; + groupName = undefined; + lastGroup = []; + return div; + } + + function newGroup(label, div, options) { + lastDiv = div || lastDiv; + return addCollapsableGroup(label, lastDiv, options); + } + + function addCollapsableGroup(label, div, options) { + let opt = options || {}; + let group = opt.group || label; + poppable[group] = opt.inline === true ? false : true; + + let row = DOC.createElement('div'), + a = DOC.createElement('a'), + dbkey = `beta-${prefix}-show-${group}`, + popper = !opt.inline; + + if (popper) { + let pop = DOC.createElement('div'); + pop.classList.add('set-pop'); + row.appendChild(pop); + row.setAttribute("class", "set-group noselect"); + addTo = pop; + } else { + row.setAttribute("class", "set-header col"); + addTo = lastDiv; + } + + div.appendChild(row); + row.appendChild(a); + a.appendChild(DOC.createTextNode(label)); + addModeControls(row, opt); + lastGroup = groups[group] = []; + lastGroup.key = dbkey; + groupName = group; + groupShow[group] = popper ? state[dbkey] === 'true' : state[dbkey] !== 'false'; + row.onclick = function(ev) { + if (ev.target !== a && ev.target !== row) { + return; + } + toggleGroup(group, dbkey); + }; + if (popper) { + row.onmouseenter = function(ev) { + if (ev.target !== a && ev.target !== row) { + return; + } + clearTimeout(exitimer); + showGroup(group); + }; + row.onmouseleave = function(ev) { + if (ev.target !== a && ev.target !== row) { + return; + } + clearTimeout(exitimer); + exitimer = setTimeout(showGroup, 1000); + }; + addTo._group = group; + addModeControls(addTo, opt); + lastGroup.push(addTo); + } + + return row; + } + + function hidePoppers() { + showGroup(undefined); + } + + function showGroup(groupname) { + Object.keys(groups).forEach(name => { + let group = groups[name]; + groupShow[name] = state[group.key] = (groupname === name); + updateGroupShow(name); + }); + } + + function toggleGroup(groupname, dbkey) { + let show = state[dbkey] === 'false'; + groupShow[groupname] = poppable[groupname] ? state[dbkey] = show : true; + updateGroupShow(groupname); + } + + function updateGroupShow(groupname) { + let show = groupShow[groupname] || !poppable[groupname]; + let group = groups[groupname]; + group.forEach(div => { + if (show) div.setMode(letMode); + else div.setMode(NOMODE); + }); + } + + function toInt() { + let nv = this.value !== '' ? parseInt(this.value) : null; + if (isNaN(nv)) nv = 0; + if (nv !== null && this.bound) nv = this.bound(nv); + this.value = nv; + return nv; + } + + function toFloat() { + let nv = this.value !== '' ? parseFloat(this.value) : null; + if (nv !== null && this.bound) nv = this.bound(nv); + this.value = nv; + return nv; + } + + function bound(low,high) { + return function(v) { + if (isNaN(v)) return low; + return v < low ? low : v > high ? high : v; + }; + } + + function raw() { + return this.value !== '' ? this.value : null; + } + + function newLabel(text) { + let label = DOC.createElement('label'); + label.appendChild(DOC.createTextNode(text)); + label.setAttribute("class", "noselect"); + return label; + } + + function addId(el, options) { + if (options && options.id) { + el.setAttribute("id", options.id); + } + } + + function addModeControls(el, options) { + options = options || {}; + el.__show = true; + el.__modeSave = null; + el.showMe = function() { + if (el.__show) return; + el.style.display = el.__modeSave; + el.__show = true; + el.__modeSave = null; + }; + el.hideMe = function() { + if (!el.__show) return; + el.__show = false; + el.__modeSave = el.style.display; + el.style.display = 'none'; + }; + el.setVisible = function(show) { + if (show) el.showMe(); + else el.hideMe(); + }; + el.setMode = function(mode) { + let show = options.expert === undefined || (options.expert === letExpert); + el.setVisible(el.hasMode(mode) && show); + } + el.hasMode = function(mode) { + if (mode === NOMODE) return false; + if (!el.modes) return true; + return el.modes.contains(mode); + } + if (options.modes) { + el.modes = options.modes; + hasModes.push(el); + } + } + + function newDiv(options) { + let div = DOC.createElement('div'); + addModeControls(div, options); + addTo.appendChild(div); + lastGroup.push(div); + div._group = groupName; + return div; + } + + let lastTxt = null; + let lastPop = null; + let savePop = null; + + function hidePop() { + if (lastPop) { + lastPop.style.display = "none"; + } + if (savePop) { + savePop(); + savePop = null; + } + lastPop = null; + } + + function isPopped() { + return lastPop !== null; + } + + function newTextArea(label, options) { + let opt = options || {}, + row = newDiv(options), + btn = DOC.createElement("button"), + pop = DOC.createElement("div"), + txt = DOC.createElement("textarea"), + area = opt.area; + + txt.setAttribute("wrap", "off"); + txt.setAttribute("spellcheck", "false"); + txt.setAttribute("style", "resize: none"); + txt.onblur = inputAction; + + btn.appendChild(DOC.createTextNode("edit")); + + btn.onclick = function(ev) { + ev.stopPropagation(); + if (ev.target === txt) { + // drop clicks on TextArea + ev.target.focus(); + } else { + let fc = area.firstChild; + if (fc) area.removeChild(fc); + area.appendChild(txt); + // first time, button click / show + btn.parentNode.onclick = btn.onclick; + txt.scrollTop = 0; + txt.scrollLeft = 0; + txt.selectionEnd = 0; + let rows = txt.value.split('\n'); + let cols = 0; + rows.forEach(row => { + cols = Math.max(cols, row.length); + }); + txt.setAttribute("cols", Math.max(30, cols + 1)); + txt.setAttribute("rows", Math.max(10, rows.length + 1)); + + let showing = pop === lastPop; + hidePop(); + if (!showing) { + if (lastTxt) { + lastTxt.classList.remove('txt-sel'); + } + row.classList.add('txt-sel'); + savePop = inputAction; + pop.style.display = "flex"; + lastPop = pop; + lastTxt = row; + txt.focus(); + } else { + inputAction(); + } + } + }; + + addModeControls(btn, opt); + addId(btn, opt); + + row.appendChild(newLabel(label)); + row.appendChild(btn); + row.setAttribute("class", "var-row"); + if (opt.title) row.setAttribute("title", options.title); + btn.setVisible = row.setVisible; + + return txt; + } + + function newInputField(label, options) { + let opt = options || {}, + row = newDiv(opt), + hide = opt && opt.hide, + size = opt ? opt.size || 5 : 5, + height = opt ? opt.height : 0, + ip = height > 1 ? DOC.createElement('textarea') : DOC.createElement('input'), + action = opt.action || inputAction; + + row.appendChild(newLabel(label)); + row.appendChild(ip); + row.setAttribute("class", "var-row"); + if (height > 1) { + ip.setAttribute("cols", size); + ip.setAttribute("rows", height); + ip.setAttribute("wrap", "off"); + } else { + if (Number.isInteger(size)) { + ip.setAttribute("size", size); + } else { + ip.setAttribute("style", `width:${size}`); + } + } + ip.setAttribute("type", "text"); + ip.setAttribute("spellcheck", "false"); + row.style.display = hide ? 'none' : ''; + if (opt) { + if (opt.disabled) ip.setAttribute("disabled", "true"); + if (opt.title) row.setAttribute("title", opt.title); + if (opt.convert) ip.convert = opt.convert.bind(ip); + if (opt.bound) ip.bound = opt.bound; + if (opt.action) action = opt.action; + } + ip.addEventListener('focus', function(event) { + hidePop(); + }); + if (action) { + ip.addEventListener('keydown', function(event) { + let key = event.key; + if ( + opt.text || + (key >= '0' && key <= '9') || + key === '.' || + key === '-' || + key === 'Backspace' || + key === 'Delete' || + key === 'ArrowLeft' || + key === 'ArrowRight' || + key === 'Tab' || + event.metaKey || + event.ctrlKey || + (key === ',' && options.comma) + ) { + return; + } + event.preventDefault(); + event.stopPropagation(); + }); + ip.addEventListener('keyup', function(event) { + if (event.keyCode === 13) { + // action(event); + ip.blur(); + } + }); + ip.addEventListener('blur', function(event) { + action(event); + }); + } + if (!ip.convert) ip.convert = raw.bind(ip); + ip.setVisible = row.setVisible; + + return ip; + } + + function newRange(label, options) { + let row = newDiv(options), + ip = DOC.createElement('input'), + hide = options && options.hide, + action = inputAction; + + if (label) row.appendChild(newLabel(label)); + row.appendChild(ip); + row.setAttribute("class", "var-row"); + ip.setAttribute("type", "range"); + ip.setAttribute("min", (options && options.min ? options.min : 0)); + ip.setAttribute("max", (options && options.max ? options.max : 100)); + ip.setAttribute("value", 0); + row.style.display = hide ? 'none' : ''; + if (options) { + if (options.title) { + ip.setAttribute("title", options.title); + row.setAttribute("title", options.title); + } + if (options.action) action = options.action; + } + ip.setVisible = row.setVisible; + + return ip; + } + + function newSelect(label, options, source) { + let row = newDiv(options), + ip = DOC.createElement('select'), + hide = options && options.hide, + action = inputAction; + + row.appendChild(newLabel(label)); + row.appendChild(ip); + row.setAttribute("source", source || "tools"); + row.setAttribute("class", "var-row"); + row.style.display = hide ? 'none' : ''; + if (options) { + if (options.convert) ip.convert = options.convert.bind(ip); + if (options.disabled) ip.setAttribute("disabled", "true"); + if (options.title) row.setAttribute("title", options.title); + if (options.action) action = options.action; + } + ip.onchange = function() { action() }; + ip.setVisible = row.setVisible; + + return ip; + } + + function newBooleanField(label, action, options) { + let row = newDiv(options), + ip = DOC.createElement('input'), + hide = options && options.hide; + + if (label) { + row.appendChild(newLabel(label)); + } + row.appendChild(ip); + row.setAttribute("class", "var-row"); + row.style.display = hide ? 'none' : ''; + ip.setAttribute("type", "checkbox"); + ip.checked = false; + if (options) { + if (options.disabled) ip.setAttribute("disabled", "true"); + if (options.title) { + ip.setAttribute("title", options.title); + row.setAttribute("title", options.title); + } + } + if (action) ip.onclick = function() { action() }; + ip.setVisible = row.setVisible; + + return ip; + } + + function newBlank(options) { + let row = newDiv(options), + hide = options && options.hide; + + row.setAttribute("class", "var-row"); + row.style.display = hide ? 'none' : ''; + ip.setVisible = row.setVisible; + + return ip; + } + + function newButton(label, action, options) { + let opt = options || {}, + b = DOC.createElement('button'); + + b.onclick = function() { + hidePoppers(); + if (action) action(); + }; + + if (opt.class) { + opt.class.split(' ').forEach(ce => { + b.classList.add(ce); + }); + } + if (opt.icon) { + let d = DOC.createElement('div'); + d.innerHTML = opt.icon; + b.appendChild(d); + } + if (label) { + b.appendChild(DOC.createTextNode(label)); + } + + addModeControls(b, options); + addId(b, options); + + return b; + } + + function newTableRow(arrayOfArrays, options) { + return newRow(newTables(arrayOfArrays), options); + } + + function newTables(arrayOfArrays) { + let array = []; + for (let i=0; i { + row.classList.add(ce); + }); + } + return row; + } + + function addCollapsableElement(parent) { + let row = newDiv(); + if (parent) parent.appendChild(row); + if (lastGroup) lastGroup.push(row); + return row; + } + +})(); diff --git a/js/kiri-widget.js b/src/kiri/widget.js similarity index 94% rename from js/kiri-widget.js rename to src/kiri/widget.js index da3a36a0..6827a9df 100644 --- a/js/kiri-widget.js +++ b/src/kiri/widget.js @@ -1,15 +1,12 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_widget = exports; - (function() { - if (!self.kiri) self.kiri = {}; if (self.kiri.Widget) return; - let KIRI = self.kiri, + const KIRI = self.kiri, DRIVERS = KIRI.driver, BASE = self.base, CONF = BASE.config, @@ -20,8 +17,9 @@ let gs_kiri_widget = exports; SQRT = MATH.sqrt, PRO = Widget.prototype, time = UTIL.time, - solid_opacity = 1.0, - nextId = 0, + solid_opacity = 1.0; + + let nextId = 0, groups = []; KIRI.Widget = Widget; @@ -713,34 +711,9 @@ let gs_kiri_widget = exports; /** * render all slice and processed data - * @param {number} renderMode - * @param {boolean} cam mode */ - PRO.render = function(renderMode, cam) { - let slices = this.slices; - if (!slices) return; - - let settings = this.settings, - driver = DRIVERS[settings.mode.toUpperCase()]; - - // allow driver to override widget slice rendering (new in SLA) - if (driver.sliceRender) return driver.sliceRender(this); - - let extruder = this.getExtruder(settings); - // render outline - slices.forEach(function(s) { s.renderOutline(renderMode,extruder) }); - // render shells - slices.forEach(function(s) { s.renderShells(renderMode) }); - // render diff - if (!cam) slices.forEach(function(s) { s.renderDiff() }); - // render solid fill (include solid flats/bridges) - slices.forEach(function(s) { s.renderSolidFill() }); - // render solid fill outlines - if (!cam) slices.forEach(function(s) { s.renderSolidOutlines() }); - // render sparse fill - if (!cam) slices.forEach(function(s) { s.renderSparseFill() }); - // render supports - if (!cam) slices.forEach(function(s) { s.renderSupport() }); + PRO.render = function() { + DRIVERS[this.settings.mode.toUpperCase()].sliceRender(this); }; PRO.hideSlices = function() { diff --git a/js/kiri-work.js b/src/kiri/work.js similarity index 97% rename from js/kiri-work.js rename to src/kiri/work.js index 5ff1ee77..ee8e2e1a 100644 --- a/js/kiri-work.js +++ b/src/kiri/work.js @@ -1,4 +1,5 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ + "use strict"; // this code runs in kiri's main loop @@ -49,7 +50,7 @@ KIRI.work = { slicing = {}; running = {}; - worker = new Worker(`/code/worker.js?${exports.VERSION}`); + worker = new Worker(`/code/worker.js?${self.kiri.version}`); worker.onmessage = function(e) { let now = time(), diff --git a/js/kiri-worker.js b/src/kiri/worker.js similarity index 96% rename from js/kiri-worker.js rename to src/kiri/worker.js index 481538f9..dd8b8006 100644 --- a/js/kiri-worker.js +++ b/src/kiri/worker.js @@ -1,16 +1,15 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ + "use strict"; -importScripts(`/code/work.js${location.search}`); - -let ver = exports.VERSION, - base = self.base, - moto = self.moto, +const base = self.base, util = base.util, time = util.time, kiri = self.kiri, - Widget = kiri.Widget, - currentPrint, + ver = kiri.version, + Widget = kiri.Widget; + +let currentPrint, currentSnap, cache = {}; diff --git a/src/license.js b/src/license.js new file mode 100644 index 00000000..ddb37960 --- /dev/null +++ b/src/license.js @@ -0,0 +1,19 @@ +(function() { + + let terms = { + COPYRIGHT: "Copyright (C) Stewart Allen - All Rights Reserved", + LICENSE: "See the license.md file included with the source distribution", + VERSION: "3.0.0-dev" + }; + + if (typeof(module) === 'object') { + module.exports = terms; + } else if (self.kiri) { + // self.exports = terms; + self.kiri.license = terms.LICENSE; + self.kiri.version = terms.VERSION; + self.kiri.copyright = terms.COPYRIGHT; + self.module = { exports: terms }; + } + +})(); diff --git a/js/meta.js b/src/meta.js similarity index 99% rename from js/meta.js rename to src/meta.js index 06d7caf9..fa6de9e6 100644 --- a/js/meta.js +++ b/src/meta.js @@ -22,12 +22,9 @@ "use strict"; -let gs_meta = exports; -let gs_meta_debug = false; // 'line', 'poly', or 'cut' - THREE.Material.prototype.motoSetup = function() { this.fog = false; - this.transparent = gs_meta_debug ? true : false; + this.transparent = false; let hidden = this.clone(); hidden.visible = false; @@ -271,7 +268,7 @@ THREE.Face3.prototype.mVisible = function(show) { let debugGroup = new THREE.Group(), debugAdded = false, debugLayer = new Layer(debugGroup), - debugExport = gs_meta_debug; + debugExport = false; /** ****************************************************************** * LETS_GET_THIS_PARTY_STARTED() @@ -431,7 +428,7 @@ THREE.Face3.prototype.mVisible = function(show) { markTypeButtons[MARK.SLIDE] = mtypStop; markTypeButtons[MARK.CLEAR] = mtypClear; - UC.newGroup('workspace', assets); + UC.newGroup('workspace', assets, {region:"left"}); UC.newTableRow([[ UC.newButton('new', newWorkspace), UC.newButton('fork', forkWorkspace), @@ -492,25 +489,22 @@ THREE.Face3.prototype.mVisible = function(show) { ]); UC.newGroup('export').setAttribute("title","send selection to target"); UC.newTableRow([ - [ - UC.newButton('library', selectionToLibrary ), - UC.newButton('kiri', selectionToKiri ) - ],[ - UC.newButton('download', downloadSelection ) - ] + [ UC.newButton('to library', selectionToLibrary ) ], + [ UC.newButton('to kiri', selectionToKiri ) ], + [ UC.newButton('download', downloadSelection ) ] ]); UC.newGroup('options'); UI.invert = UC.newBoolean('invert zoom', setZoom); - UC.newGroup('space', control); + UC.newGroup('space', control, {region:"right", nocompact: true}); UI.name = UC.newInput('name', {size:10}); UI.units = UC.newInput('units'); UI.grid = UC.newInput('grid'); UI.version = UC.newInput('version', {disabled:true}); UC.newTableRow([[ verDown, verUp ]]); - UC.newGroup('selection'); + UC.newGroup('selection', undefined, {nocompact: true}); UI.sel_x = UC.newInput('width', {disabled:true}); UI.sel_y = UC.newInput('depth', {disabled:true}); UI.sel_z = UC.newInput('height', {disabled:true}); @@ -519,7 +513,7 @@ THREE.Face3.prototype.mVisible = function(show) { UC.newGroup('spaces'); UI.models = UC.newRow(); - UC.newGroup('import mesh'); + UC.newGroup('import', undefined, {nocompact: true}); UI.libdrop = UC.newButton('(drop mesh here)'); UI.libdrop.id = "dropbutton"; UC.newRow([UI.libdrop]); @@ -541,6 +535,8 @@ THREE.Face3.prototype.mVisible = function(show) { UI.units, function(ev) { setSpaceUnits(UI.units.value) } ]); + UC.hidePoppers(); + /** prevent mouse hover, click in control panels from affecting space */ function killev(ev) { ev.stopImmediatePropagation(); return false } diff --git a/js/kiri-driver-cam.js b/src/mode/cam/driver.js similarity index 94% rename from js/kiri-driver-cam.js rename to src/mode/cam/driver.js index 2510e914..830f5436 100644 --- a/js/kiri-driver-cam.js +++ b/src/mode/cam/driver.js @@ -1,26 +1,25 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_kiri_cam = exports; - (function() { - if (!self.kiri) self.kiri = { }; if (!self.kiri.driver) self.kiri.driver = { }; if (self.kiri.driver.CAM) return; - let KIRI = self.kiri, + const KIRI = self.kiri, BASE = self.base, UTIL = BASE.util, POLY = BASE.polygons, CAM = KIRI.driver.CAM = { + init, slice, sliceRender, printSetup, printExport, + printRender, getToolById, - getToolDiameter + getToolDiameter, }, CPRO = CAM.process = { ROUGH: 1, @@ -49,6 +48,14 @@ var gs_kiri_cam = exports; newPolygon = BASE.newPolygon, time = UTIL.time; + function init(kiri, api) { + api.event.on("mode.set", (mode) => { + let isCAM = mode === 'CAM'; + $('set-tools').style.display = isCAM ? '' : 'none'; + kiri.space.platform.setColor(isCAM ? 0xeeeeee : 0xcccccc); + }); + } + function getToolById(settings, id) { for (let i=0, t=settings.tools; i toolDiam || (deltaZ > toolDiam && deltaXY > tolerance)) && (isMove || absDeltaZ >= tolerance)) { - let maxz = toolProfile ? MAX( - getTopoZPathMax( - widget, - toolProfile, - lastPoint.x - wmx, - lastPoint.y - wmy, - point.x - wmx, - point.y - wmy) + zadd, - point.z, - lastPoint.z) : zmax, - mustGoUp = MAX(maxz - point.z, maxz - lastPoint.z) >= tolerance, - clearz = maxz; - // up if any point between higher than start/finish - if (mustGoUp) { - clearz = maxz + zclear; - layerPush(lastPoint.clone().setZ(clearz), 0, 0, tool.number); - } - // over to point above where we descend to - if (mustGoUp || point.z < maxz) { - layerPush(point.clone().setZ(clearz), 0, 0, tool.number); - // new pos for plunge calc - deltaXY = 0; - } - } - // synth new plunge rate - if (deltaZ <= -tolerance) { - let threshold = MIN(deltaXY / 2, absDeltaZ), - modifier = threshold / absDeltaZ; - if (threshold && modifier && deltaXY > tolerance) { - // use modifier to speed up long XY move plunge rates - rate = Math.round(plungeRate + ((feedRate - plungeRate) * modifier)); - } else { - rate = plungeRate; - } - // console.log({deltaZ: deltaZ, deltaXY: deltaXY, threshold:threshold, modifier:modifier, rate:rate, plungeRate:plungeRate}); - } - } else { - // before first point, move cutting head to point above it - layerPush(point.clone().setZ(zmax), 0, 0, tool.number); + let deltaXY = lastPoint.distTo2D(point), + deltaZ = point.z - lastPoint.z, + absDeltaZ = Math.abs(deltaZ), + isMove = !cut; + // drop points too close together + if (deltaXY < 0.001 && point.z === lastPoint.z) { + console.trace(["drop dup",lastPoint,point]); + return; } + if (isMove && deltaXY <= toolDiamMove) { + // convert short planar moves to cuts + if (absDeltaZ <= tolerance) { + cut = 1; + isMove = false; + } else if (deltaZ <= -tolerance) { + // move over before descending + layerPush(point.clone().setZ(lastPoint.z), 0, 0, tool.number); + // new pos for plunge calc + deltaXY = 0; + } + } //else (TODO verify no else here b/c above could change isMove) + // move over things + if ((deltaXY > toolDiam || (deltaZ > toolDiam && deltaXY > tolerance)) && (isMove || absDeltaZ >= tolerance)) { + let maxz = toolProfile ? MAX( + getTopoZPathMax( + widget, + toolProfile, + lastPoint.x - wmx, + lastPoint.y - wmy, + point.x - wmx, + point.y - wmy) + zadd, + point.z, + lastPoint.z) : zmax, + mustGoUp = MAX(maxz - point.z, maxz - lastPoint.z) >= tolerance, + clearz = maxz; + // up if any point between higher than start/finish + if (mustGoUp) { + clearz = maxz + zclear; + layerPush(lastPoint.clone().setZ(clearz), 0, 0, tool.number); + } + // over to point above where we descend to + if (mustGoUp || point.z < maxz) { + layerPush(point.clone().setZ(clearz), 0, 0, tool.number); + // new pos for plunge calc + deltaXY = 0; + } + } + // synth new plunge rate + if (deltaZ <= -tolerance) { + let threshold = MIN(deltaXY / 2, absDeltaZ), + modifier = threshold / absDeltaZ; + if (threshold && modifier && deltaXY > tolerance) { + // use modifier to speed up long XY move plunge rates + rate = Math.round(plungeRate + ((feedRate - plungeRate) * modifier)); + } else { + rate = plungeRate; + } + // console.log({deltaZ: deltaZ, deltaXY: deltaXY, threshold:threshold, modifier:modifier, rate:rate, plungeRate:plungeRate}); + } + // todo synthesize move speed from feed / plunge accordingly layerPush( point, @@ -1781,12 +1785,6 @@ var gs_kiri_cam = exports; function moveTo(out) { let newpos = out.point; - // first point out sets the current position (but not Z) - if (points === 0) { - pos.x = newpos.x; - pos.y = newpos.y; - } - // no point == dwell // out.speed = time to dwell in ms if (!newpos) { @@ -1810,13 +1808,32 @@ var gs_kiri_cam = exports; filterEmit(cmdToolChange, consts); } + // first point out sets the current position (but not Z) + // hacky AF way to split initial x,y,z into z then x,y + if (points === 0) { + pos.x = pos.y = pos.z = 0; + points++; + moveTo({ + tool: out.tool, + point: { x: 0, y: 0, z: newpos.z }, + speed: spro.camFastFeedZ + }); + moveTo({ + tool: out.tool, + point: { x: newpos.x, y: newpos.y, z: newpos.z }, + speed: spro.camFastFeed + }); + points--; + return; + } + let speed = out.speed, - feed = speed || spro.camFastFeed, nl = [speed ? 'G1' : 'G0'], dx = newpos.x - pos.x, dy = newpos.y - pos.y, dz = newpos.z - pos.z, - dist = Math.sqrt(dx * dx + dy * dy + dz * dz); + dist = Math.sqrt(dx * dx + dy * dy + dz * dz), + feed = Math.min(speed || spro.camFastFeed, dz ? spro.camFastFeedZ : spro.camFastFeed); // drop dup points (all deltas are 0) if (!(dx || dy || dz)) { @@ -1859,7 +1876,7 @@ var gs_kiri_cam = exports; } if (!stripComments) { - append(`; Generated by Kiri:Moto ${exports.VERSION}`); + append(`; Generated by Kiri:Moto ${KIRI.VERSION}`); append(`; ${new Date().toString()}`); filterEmit(["; Bed left:{left} right:{right} top:{top} bottom:{bottom}"], consts); append(`; Target: ${settings.filter[settings.mode]}`); @@ -1925,4 +1942,8 @@ var gs_kiri_cam = exports; return online ? null : output.join("\n"); }; + function printRender(print) { + return KIRI.driver.FDM.printRender(print, {aslines: true}); + } + })(); diff --git a/js/kiri-driver-fdm.js b/src/mode/fdm/driver.js similarity index 83% rename from js/kiri-driver-fdm.js rename to src/mode/fdm/driver.js index 4fbe5140..72cd2234 100644 --- a/js/kiri-driver-fdm.js +++ b/src/mode/fdm/driver.js @@ -1,16 +1,13 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_fdm = exports; - (function() { - if (!self.kiri) self.kiri = { }; if (!self.kiri.driver) self.kiri.driver = { }; if (self.kiri.driver.FDM) return; - let KIRI = self.kiri, + const KIRI = self.kiri, BASE = self.base, DBUG = BASE.debug, UTIL = BASE.util, @@ -18,8 +15,10 @@ let gs_kiri_fdm = exports; POLY = BASE.polygons, FDM = KIRI.driver.FDM = { slice, + sliceRender, printSetup, - printExport + printExport, + printRender }, SLICER = KIRI.slicer, newPoint = BASE.newPoint; @@ -399,6 +398,140 @@ let gs_kiri_fdm = exports; }; + /** + * DRIVER SLICE RENDER CONTRACT + * + * @param {Object} widget to render + * @param {number} mode to use to select colors + */ + function sliceRender(widget) { + let slices = widget.slices; + let settings = widget.settings; + let extnum = widget.getExtruder(settings); + let extarr = settings.device.extruders || []; + let extinfo = extarr[extnum || 0]; + let extoff = (extinfo.extNozzle || 0.4) / 2; + let thin = settings.controller.thinRender && settings.mode === 'FDM'; + + if (!slices) return; + + // render outline + slices.forEach(function(s) { + let layers = s.layers; + let tops = s.tops; + let outline = layers.outline; + let shells = layers.trace; + let solids = layers.fill; + let sparse = layers.sparse; + let support = layers.support; + let outsolid = layers.solid; + let outbridge = layers.bridge; + let outflat = layers.flat; + + outline.clear(); + shells.clear(); + solids.clear(); + sparse.clear(); + support.clear(); + outsolid.clear(); + outbridge.clear(); + outflat.clear(); + + outline.setTransparent(true); + shells.setTransparent(false); + solids.setTransparent(false); + sparse.setTransparent(false); + support.setTransparent(false); + outsolid.setTransparent(true); + outbridge.setTransparent(true); + outflat.setTransparent(true); + + tops.forEach(function(top) { + // outline + outline.poly(top.poly, 0xdddddd, true, false); + outline.solid(top.poly, thin ? 0xdddddd : 0xcccccc); + if (top.inner) outline.poly(top.inner, 0xdddddd, true); + // if (top.thinner) outline.poly(top.thinner, 0x559999, true, null); + + // shells + if (thin) { + shells.poly(top.traces, 0x77bbcc, true); + } else { + shells.noodle(top.traces, extoff, 0x88aadd, 0x77bbcc); + } + if (top.polish) { + shells.poly(top.polish.x, 0x880000, true); + shells.poly(top.polish.y, 0x880000, true); + } + + // solid fill + if (thin) { + solids.lines(top.fill_lines, 0x77bbcc); + } else { + solids.noodle_lines(top.fill_lines, extoff, 0x88aadd, 0x77bbcc, s.z); + } + + // sparse fill + if (top.fill_sparse) { + top.fill_sparse.forEach(function(poly) { + if (thin) { + // todo cull polys with single point before this + if (poly.length > 1) poly.render(sparse, 0x0, false, true); + } else { + sparse.noodle_open(poly, extoff, 0x88aadd, 0x77bbcc, s.z); + } + }); + } + + // support + if (s.supports) { + if (thin) { + s.supports.forEach(function(poly) { + support.poly(poly, 0x88aadd, true); + support.lines(poly.fills, 0x88aadd); + }); + } else { + support.noodle(s.supports, extoff, 0x88aadd, 0x77bbcc); + s.supports.forEach(function(poly) { + support.noodle_lines(poly.fills, extoff, 0x88aadd, 0x77bbcc, s.z); + }); + } + } + }); + + // solid outlines + let trimmed = s.solids.trimmed; + if (trimmed) trimmed.forEach(function(poly) { + poly.setZ(s.z + 0.025); + outsolid.poly(poly, 0x00cc00, true, false); + outsolid.solid(poly, 0x00dd00); + }); + + // diff bridges + if (s.bridges) s.bridges.forEach(function (poly) { + poly.setZ(s.z + 0.05); + outbridge.poly(poly, 0x0099ee, true, false); + outbridge.solid(poly, 0x00aaff); + }); + + // diff flats + if (s.flats) s.flats.forEach(function (poly) { + poly.setZ(s.z + 0.05); + outflat.poly(poly, 0xee0099, true, false); + outflat.solid(poly, 0xff00aa); + }); + + outline.renderAll(); + shells.renderAll(); + solids.renderAll(); + sparse.renderAll(); + support.renderAll(); + outsolid.renderAll(); + outbridge.renderAll(); + outflat.renderAll(); + }); + } + /** * DRIVER PRINT CONTRACT * @@ -861,7 +994,7 @@ let gs_kiri_fdm = exports; arr.forEach(function(line) { appendSub(line) }); } - append(`; Generated by Kiri:Moto ${exports.VERSION}`); + append(`; Generated by Kiri:Moto ${KIRI.VERSION}`); append(`; ${new Date().toString()}`); appendSub("; Bed left:{left} right:{right} top:{top} bottom:{bottom}"); append(`; Target: ${settings.filter[settings.mode]}`); @@ -1124,4 +1257,95 @@ let gs_kiri_fdm = exports; return online ? null : output.join("\n"); }; + function toPoint(obj) { + return base.newPoint(obj.x, obj.y, obj.z); + } + + function printRender(print, options) { + let debug = KIRI.api.const.LOCAL; + let scope = print, emits, last, + moves, moving = true, + opt = options || {}, + tools = opt.tools || [], + showmoves = !opt.nomoves; + // render layered output + scope.lines = 0; + scope.output.forEach(function(layerout) { + let move = [], print = [], cprint; + layerout.forEach(function(out, index) { + let point = toPoint(out.point); + if (last) { + // drop short segments + // if (point.emit === last.emit && UTIL.distSq(last, point) < 0.001 && point.z === last.z) { + // return; + // } + if (out.emit > 0) { + if (moving || !cprint) { + cprint = base.newPolygon().setOpen(true).append(last); + print.push({ + poly: cprint, + speed: out.speed || 4000, + tool:tools[out.tool] + }); + } + try { + cprint.append(point); + } catch (e) { + console.log(e, {cprint}); + } + moving = false; + } else { + cprint = null; + move.push(last); + move.push(point); + moving = true; + } + // move direction arrow heads + if (debug && last.z == point.z) { + let rs = BASE.newSlope( + {x: point.x, y: point.y}, + {x: last.x, y: last.y} + ); + let ao1 = BASE.newSlopeFromAngle(rs.angle + 25); + let ao2 = BASE.newSlopeFromAngle(rs.angle - 25); + let sp = BASE.newPoint(point.x, point.y, point.z); + move.push(sp); + move.push(sp.projectOnSlope(ao1, 0.5)); + move.push(sp); + move.push(sp.projectOnSlope(ao2, 0.5)); + } + } + last = point; + }); + emits = KIRI.newLayer(scope.group); + if (showmoves) { + moves = KIRI.newLayer(scope.group); + moves.lines(move, 0x888888); + } + emits.setTransparent(false); + // emit printing shapes + print.forEach(segment => { + let {poly, speed, tool} = segment; + let off = tool ? (tool.extNozzle || 0.4) / 2 : 0.2; + let sint = Math.min(9000, parseInt(speed)); + let rgb = scope.hsv2rgb({h:sint/9000, s:1, v:1}); + let color = ((rgb.r * 0xff) << 16) | + ((rgb.g * 0xff) << 8) | + ((rgb.b * 0xff) << 0); + if (opt.aslines) { + emits.poly(poly, color, false, true); + } else { + emits.noodle_open(poly, off - 0.02, color, 0x0, poly.getZ()); + } + }); + emits.renderAll(); + if (showmoves) { + moves.render(); + scope.movesView.push(moves); + } + scope.printView.push(emits); + scope.lines += print.length; + }); + } + })(); diff --git a/js/kiri-driver-laser.js b/src/mode/laser/driver.js similarity index 97% rename from js/kiri-driver-laser.js rename to src/mode/laser/driver.js index 5f18be6d..b64e3d9e 100644 --- a/js/kiri-driver-laser.js +++ b/src/mode/laser/driver.js @@ -1,23 +1,22 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_laser = exports; - (function() { - if (!self.kiri) self.kiri = { }; if (!self.kiri.driver) self.kiri.driver = { }; if (self.kiri.driver.LASER) return; - let KIRI = self.kiri, + const KIRI = self.kiri, BASE = self.base, UTIL = BASE.util, POLY = BASE.polygons, DBUG = BASE.debug, LASER = KIRI.driver.LASER = { slice, + sliceRender, printSetup, + printRender, exportGCode, exportSVG, exportDXF @@ -54,9 +53,10 @@ let gs_kiri_laser = exports; }); }; - /** - * - */ + function sliceRender(widget) { + return KIRI.driver.CAM.sliceRender(widget); + } + function sliceEmitObjects(print, slice, groups) { let start = newPoint(0,0,0); let process = print.settings.process; @@ -458,4 +458,8 @@ let gs_kiri_laser = exports; return lines.join('\n'); }; + function printRender(print) { + return KIRI.driver.FDM.printRender(print, {aslines: true, nomoves: true}); + } + })(); diff --git a/js/kiri-driver-sla.js b/src/mode/sla/driver.js similarity index 98% rename from js/kiri-driver-sla.js rename to src/mode/sla/driver.js index d60fc48d..c06ef9a1 100644 --- a/js/kiri-driver-sla.js +++ b/src/mode/sla/driver.js @@ -1,22 +1,20 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_kiri_sla = exports; - (function() { - if (!self.kiri) self.kiri = { }; if (!self.kiri.driver) self.kiri.driver = { }; if (self.kiri.driver.SLA) return; - let KIRI = self.kiri, + const KIRI = self.kiri, BASE = self.base, DBUG = BASE.debug, UTIL = BASE.util, CONF = BASE.config, POLY = BASE.polygons, SLA = KIRI.driver.SLA = { + init, slice, sliceRender, printSetup, @@ -28,8 +26,9 @@ let gs_kiri_sla = exports; newTop = KIRI.newTop, newSlice = KIRI.newSlice, newPoint = BASE.newPoint, - newPolygon = BASE.newPolygon, - preview, + newPolygon = BASE.newPolygon; + + let preview, previewSmall, previewLarge, fill_cache, @@ -37,6 +36,16 @@ let gs_kiri_sla = exports; if (legacy) console.log("SLA Driver in Legacy Mode"); + function init(kiri, api) { + api.event.on("mode.set", (mode) => { + if (mode === 'SLA') { + api.ui.act.preview.classList.add('hide'); + } else { + api.ui.act.preview.classList.remove('hide'); + } + }); + } + /** * DRIVER SLICE CONTRACT - runs in worker * @@ -674,6 +683,9 @@ let gs_kiri_sla = exports; // runs in browser main function sliceRender(widget) { + // legacy debug + return; + widget.slices.forEach(slice => { let layers = slice.layers, outline = layers.outline, @@ -745,7 +757,7 @@ let gs_kiri_sla = exports; if (count === 0) { // TODO fix with contract for exposing layer count // hack uses expected gcode output array in print object - // print.output = print.printView; + print.output = print.printView; return; } @@ -797,7 +809,6 @@ let gs_kiri_sla = exports; $('print-filename').value = filename; $('print-layers').value = lines.length; $('print-time').value = `${print_hrs}:${print_min}:${print_sec}`; - $('print-close').onclick = API.modal.hide; switch (device.deviceName) { case 'Anycubic.Photon': diff --git a/js/moto-ajax.js b/src/moto/ajax.js similarity index 90% rename from js/moto-ajax.js rename to src/moto/ajax.js index 03586d81..c414669a 100644 --- a/js/moto-ajax.js +++ b/src/moto/ajax.js @@ -1,15 +1,13 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_moto_ajax = exports; - (function() { - let MOTO = self.moto; - if (!MOTO) MOTO = self.moto = {}; + if (!self.moto) self.moto = {}; + if (self.moto.Ajax) return; - if (MOTO.Ajax) return; + const MOTO = self.moto; MOTO.Ajax = Ajax; @@ -17,7 +15,7 @@ let gs_moto_ajax = exports; new Ajax(handler).request(url); }; - let AP = Ajax.prototype, + const AP = Ajax.prototype, KV = moto.KV, KEY = "moto-ajax", TIME = function() { return new Date().getTime() }, @@ -30,7 +28,7 @@ let gs_moto_ajax = exports; KV.setItem(KEY, MOKEY); - let STATES = [ + const STATES = [ "request not initialized", // 0 "server connection established", // 1 "request recieved", // 2 diff --git a/js/moto-ctrl.js b/src/moto/ctrl.js similarity index 99% rename from js/moto-ctrl.js rename to src/moto/ctrl.js index 29d5d7d7..068695f9 100644 --- a/js/moto-ctrl.js +++ b/src/moto/ctrl.js @@ -1,9 +1,8 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -let gs_moto_ctrl = exports; -var MOTO = window.moto = window.moto || {}; +let MOTO = self.moto = self.moto || {}; /** * Adapted from THREE.OrbitControls diff --git a/js/moto-db.js b/src/moto/db.js similarity index 91% rename from js/moto-db.js rename to src/moto/db.js index 82848f92..20a708d0 100644 --- a/js/moto-db.js +++ b/src/moto/db.js @@ -1,9 +1,7 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_moto_db = exports; - (function() { if (!self.moto) self.moto = {}; @@ -13,7 +11,7 @@ var gs_moto_db = exports; // https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API - var IDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB, + let IDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB, IRR = self.IDBKeyRange, local = null; @@ -34,14 +32,14 @@ var gs_moto_db = exports; IDB.deleteDatabase(dbname); }; - var SP = Storage.prototype; + let SP = Storage.prototype; /** ****************************************************************** * indexedDB implementation ******************************************************************* */ SP.keys = function(callback, lower, upper) { - var out = []; + let out = []; this.iterate(function(k,v) { if (k === null) { callback(out); @@ -56,12 +54,12 @@ var gs_moto_db = exports; this.init(); return this.queue.push(["iterate", callback, lower, upper]); } - var range = lower && upper ? IRR.bound(lower,upper) : + let range = lower && upper ? IRR.bound(lower,upper) : lower ? IRR.lowerBound(lower) : upper ? IRR.upperBound(upper) : undefined; // iterate over all db values for debugging this.db.transaction(this.name).objectStore(this.name).openCursor(range).onsuccess = function(event) { - var cursor = event.target.result; + let cursor = event.target.result; if (cursor) { callback(cursor.key,cursor.value); cursor.continue(); @@ -80,7 +78,7 @@ var gs_moto_db = exports; SP.init = function(deleteOS) { if (this.initCalled) return; - var storage = this, + let storage = this, name = this.name, request = null; @@ -125,7 +123,7 @@ var gs_moto_db = exports; SP.runQueue = function() { if (this.queue.length > 0) { - var i = 0, q = this.queue, e; + let i = 0, q = this.queue, e; while (i < q.length) { e = q[i++]; switch (e[0]) { @@ -151,7 +149,7 @@ var gs_moto_db = exports; return this.queue.push(['put', key, value, callback]); } try { - var req = this.db.transaction(this.name, "readwrite").objectStore(this.name).put(value, key); + let req = this.db.transaction(this.name, "readwrite").objectStore(this.name).put(value, key); if (callback) { req.onsuccess = function(event) { callback(true) }; req.onerror = function(event) { callback(false) }; @@ -172,7 +170,7 @@ var gs_moto_db = exports; return this.queue.push(['get', key, callback]); } try { - var req = this.db.transaction(this.name).objectStore(this.name).get(key); + let req = this.db.transaction(this.name).objectStore(this.name).get(key); if (callback) { req.onsuccess = function(event) { callback(req.result) }; req.onerror = function(event) { callback(null) }; @@ -194,7 +192,7 @@ var gs_moto_db = exports; return this.queue.push(['remove', key, callback]); } try { - var req = this.db.transaction(this.name, "readwrite").objectStore(this.name).delete(key); + let req = this.db.transaction(this.name, "readwrite").objectStore(this.name).delete(key); if (callback) { req.onsuccess = function(event) { callback(true) }; req.onerror = function(event) { callback(false) }; diff --git a/js/moto-kv.js b/src/moto/kv.js similarity index 92% rename from js/moto-kv.js rename to src/moto/kv.js index 6131bed4..719d64c8 100644 --- a/js/moto-kv.js +++ b/src/moto/kv.js @@ -1,9 +1,7 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_moto_kv = exports; - (function() { if (!self.moto) self.moto = {}; diff --git a/js/moto-load-obj.js b/src/moto/load-obj.js similarity index 94% rename from js/moto-load-obj.js rename to src/moto/load-obj.js index f570cb5f..1e8f508c 100644 --- a/js/moto-load-obj.js +++ b/src/moto/load-obj.js @@ -3,11 +3,13 @@ * * https://en.wikipedia.org/wiki/Wavefront_.obj_file */ + 'use strict'; (function() { if (!self.moto) self.moto = {}; + if (self.moto.OBJ) return; self.moto.OBJ = { parse : parse @@ -19,23 +21,23 @@ */ function parse(text) { - var object, + let object, objects = [], geometry, material; function parseVertexIndex(value) { - var index = parseInt(value); + let index = parseInt(value); return (index >= 0 ? index - 1 : index + vertices.length / 3) * 3; } function parseNormalIndex(value) { - var index = parseInt(value); + let index = parseInt(value); return (index >= 0 ? index - 1 : index + normals.length / 3) * 3; } function parseUVIndex(value) { - var index = parseInt(value); + let index = parseInt(value); return (index >= 0 ? index - 1 : index + uvs.length / 2) * 2; } @@ -65,10 +67,10 @@ function addFace(a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd) { - var ia = parseVertexIndex(a); - var ib = parseVertexIndex(b); - var ic = parseVertexIndex(c); - var id; + let ia = parseVertexIndex(a); + let ib = parseVertexIndex(b); + let ic = parseVertexIndex(c); + let id; if (d === undefined) { addVertex(ia, ib, ic); @@ -124,7 +126,7 @@ objects.push(object); } - var vertices = [], + let vertices = [], normals = [], uvs = [], // v float float float @@ -144,12 +146,12 @@ // split text into lines lines = text.split('\n'); - for (var i = 0; i < lines.length; i++) { + for (let i = 0; i < lines.length; i++) { - var line = lines[i]; + let line = lines[i]; line = line.trim(); - var result; + let result; if (line.length === 0 || line.charAt(0) === '#') { continue; diff --git a/js/moto-load-stl.js b/src/moto/load-stl.js similarity index 87% rename from js/moto-load-stl.js rename to src/moto/load-stl.js index 539e666a..49fe09bf 100644 --- a/js/moto-load-stl.js +++ b/src/moto/load-stl.js @@ -3,10 +3,18 @@ * * https://en.wikipedia.org/wiki/STL_(file_format) */ + 'use strict'; (function() { + if (!self.moto) self.moto = {}; + if (self.moto.STL) return; + + const SP = STL.prototype; + + self.moto.STL = STL; + /** * @constructor */ @@ -16,14 +24,9 @@ this.colors = null; } - var SP = STL.prototype; - - if (!self.moto) self.moto = {}; - - self.moto.STL = STL; SP.load = function(url, callback) { - var stl = this, + let stl = this, xhr = new XMLHttpRequest(); function onloaded (event) { @@ -51,7 +54,7 @@ SP.encode = function(vertices, normals) { if (!(vertices && vertices.length % 3 === 0)) throw "invalid vertices"; - var vc = vertices.length / 3, + let vc = vertices.length / 3, bs = (vc * 16) + (vc * (2/3)) + 84, bin = new ArrayBuffer(bs), writer = new DataView(bin), @@ -95,10 +98,10 @@ }; SP.parse = function(data) { - var binData = this.convertToBinary(data); + let binData = this.convertToBinary(data); - var isBinary = function () { - var expect, face_size, n_faces, reader; + let isBinary = function () { + let expect, face_size, n_faces, reader; reader = new DataView(binData); face_size = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8); n_faces = reader.getUint32(80,true); @@ -112,13 +115,13 @@ }; SP.parseBinary = function(data) { - var reader = new DataView(data), + let reader = new DataView(data), faces = reader.getUint32 (80, true), r, g, b, hasColors = false, colors, defaultR, defaultG, defaultB, alpha; // check for default color in STL header ("COLOR=rgba" sequence). - for (var index = 0; index < 80 - 10; index++) { + for (let index = 0; index < 80 - 10; index++) { if ((reader.getUint32(index, false) == 0x434F4C4F /*COLO*/) && (reader.getUint8(index + 4) == 0x52 /*'R'*/) && (reader.getUint8(index + 5) == 0x3D /*'='*/)) { @@ -131,22 +134,23 @@ } } - var offset = 0, + let offset = 0, dataOffset = 84, faceLength = 12 * 4 + 2, vertices = new Float32Array(faces * 3 * 3), - normals = new Float32Array(faces * 3 * 3), - colors = hasColors ? new Uint16Array(faces * 3 * 3) : null; + normals = new Float32Array(faces * 3 * 3); - for (var face = 0; face < faces; face ++) { + colors = hasColors ? new Uint16Array(faces * 3 * 3) : null; - var start = dataOffset + face * faceLength, + for (let face = 0; face < faces; face ++) { + + let start = dataOffset + face * faceLength, normalX = reader.getFloat32(start, true), normalY = reader.getFloat32(start + 4, true), normalZ = reader.getFloat32(start + 8, true); if (hasColors) { - var packedColor = reader.getUint16(start + 48, true); + let packedColor = reader.getUint16(start + 48, true); if ((packedColor & 0x8000) === 0) { // facet has its own unique color r = (packedColor & 0x1F) / 31; g = ((packedColor >> 5) & 0x1F) / 31; @@ -158,7 +162,7 @@ } } - var i = 1, vertexstart; + let i = 1, vertexstart; while (i <= 3) { vertexstart = start + (i++) * 12; @@ -185,7 +189,7 @@ }; SP.parseASCII = function(data) { - var result, + let result, resultText, patternNormal, patternVertex, @@ -209,7 +213,7 @@ } } - var vToFloat32 = new Float32Array(vertices.length), + let vToFloat32 = new Float32Array(vertices.length), nToFloat32 = new Float32Array(normals.length), i; @@ -224,9 +228,9 @@ SP.convertToString = function (buf) { if (typeof buf !== "string") { - var array_buffer = new Uint8Array(buf); - var str = ''; - for (var i = 0; i < buf.byteLength; i++) { + let array_buffer = new Uint8Array(buf); + let str = ''; + for (let i = 0; i < buf.byteLength; i++) { str += String.fromCharCode(array_buffer[i]); } return str; @@ -237,8 +241,8 @@ SP.convertToBinary = function (buf) { if (typeof buf === "string") { - var array_buffer = new Uint8Array(buf.length); - for (var i = 0; i < buf.length; i++) { + let array_buffer = new Uint8Array(buf.length); + for (let i = 0; i < buf.length; i++) { array_buffer[i] = buf.charCodeAt(i) & 0xff; } return array_buffer.buffer || array_buffer; diff --git a/js/kiri-pack.js b/src/moto/pack.js similarity index 92% rename from js/kiri-pack.js rename to src/moto/pack.js index 10b73bb2..233238d6 100644 --- a/js/kiri-pack.js +++ b/src/moto/pack.js @@ -1,9 +1,7 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_kiri_pack = exports; - /** * adapted from * http://codeincomplete.com/posts/2011/5/7/bin_packing/ @@ -11,6 +9,11 @@ var gs_kiri_pack = exports; (function (){ + if (!self.moto) self.moto = {}; + if (self.moto.Pack) return; + + self.moto.Pack = Packer; + function Packer (w, h, spacing) { this.root = { x: 0, y: 0, w: w, h: h }; this.max = { w: 0, h: 0 }; @@ -22,7 +25,7 @@ var gs_kiri_pack = exports; Packer.prototype = { fit: function (blocks) { - var n = 0, node, block, w, h; + let n = 0, node, block, w, h; while (n < blocks.length) { block = blocks[n++]; w = block.w + this.spacing; @@ -58,7 +61,4 @@ var gs_kiri_pack = exports; }; - if (!self.moto) self.moto = {}; - self.moto.Pack = Packer; - })(); diff --git a/js/moto-space.js b/src/moto/space.js similarity index 98% rename from js/moto-space.js rename to src/moto/space.js index 66e2a1e8..f6de9a90 100644 --- a/js/moto-space.js +++ b/src/moto/space.js @@ -1,12 +1,13 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ -"use strict"; +/** Copyright Stewart Allen -- All Rights Reserved */ -let gs_moto_space = exports; -var MOTO = window.moto = window.moto || {}; +"use strict"; (function() { - let WIN = window, + if (!self.moto) self.moto = {}; + + let MOTO = self.moto, + WIN = window, DOC = document, SCENE = new THREE.Scene(), WORLD = new THREE.Group(), @@ -387,21 +388,9 @@ var MOTO = window.moto = window.moto || {}; case cca('h'): Space.view.home(); break; - case cca('f'): - Space.view.front(); - break; - case cca('l'): - Space.view.left(); - break; - case cca('r'): - Space.view.right(); - break; case cca('t'): Space.view.top(); break; - case cca('b'): - Space.view.back(); - break; default: handled = false; break; diff --git a/js/moto-ui.js b/src/moto/ui.js similarity index 94% rename from js/moto-ui.js rename to src/moto/ui.js index f325b7e2..bbf95327 100644 --- a/js/moto-ui.js +++ b/src/moto/ui.js @@ -1,12 +1,10 @@ -/** Copyright 2014-2019 Stewart Allen -- All Rights Reserved */ +/** Copyright Stewart Allen -- All Rights Reserved */ "use strict"; -var gs_moto_ui = exports; - (function() { - var moto = self.moto = self.moto || {}; + if (!self.moto) self.moto = {}; if (moto.ui) return; let SELF = self, @@ -28,7 +26,6 @@ var gs_moto_ui = exports; DOC = SELF.document, prefix = "tab", NOMODE = "nomode", - compact = false, exitimer = undefined; SELF.$ = (SELF.$ || function (id) { return DOC.getElementById(id) } ); @@ -57,35 +54,17 @@ var gs_moto_ui = exports; newBlank: newBlank, newGroup: newGroup, setGroup: setGroup, - setCompact: setCompact, - setDefaults: setDefaults, hidePoppers: hidePoppers, checkpoint, restore }; - function setDefaults(bool) { - Object.keys(localStorage).forEach(name => { - let namepre = `${prefix}-show-`; - if (name.indexOf(namepre) === 0) { - localStorage[name] = bool; - } - }); - } - - function setCompact(bool) { - compact = bool; - return this; - } - function setMode(mode) { - if (compact) { - $('control-left').classList.add('compact'); - $('control-right').classList.add('compact'); - Object.keys(groupShow).forEach(group => { - updateGroupShow(group); - }); - } + $('control-left').classList.add('compact'); + $('control-right').classList.add('compact'); + Object.keys(groupShow).forEach(group => { + updateGroupShow(group); + }); letMode = mode; hasModes.forEach(function(div) { div.setMode(div._group && !groupShow[div._group] ? NOMODE : mode); @@ -132,8 +111,8 @@ var gs_moto_ui = exports; let row = DOC.createElement('div'), a = DOC.createElement('a'), - dbkey = `${prefix}-show-${group}`, - popper = compact && !opt.nocompact; + dbkey = `beta-${prefix}-show-${group}`, + popper = !opt.nocompact; if (popper) { let pop = DOC.createElement('div'); @@ -185,9 +164,7 @@ var gs_moto_ui = exports; } function hidePoppers() { - if (compact) { - showGroup(undefined); - } + showGroup(undefined); } function showGroup(groupname) { @@ -543,13 +520,13 @@ var gs_moto_ui = exports; t = DOC.createTextNode(label); b.onclick = function() { - if (compact) hidePoppers(); + hidePoppers(); if (action) action(); }; if (options) { if (options.class) b.classList.add(options.class); - if (compact && options.icon) { + if (options.icon) { let d = DOC.createElement('div'); d.innerHTML = options.icon; b.appendChild(d); diff --git a/web/kiri/index.css b/web/kiri/index.css new file mode 100644 index 00000000..b0741bff --- /dev/null +++ b/web/kiri/index.css @@ -0,0 +1,915 @@ +:root { + --fg-gray: #495057; + --bg-gray: rgba(0,0,0,0.25); + --gradbar: linear-gradient(to right, #ddd, #666, #ddd); + --holdbar: linear-gradient(to right, rgba(255,255,255,0), rgba(255,255,255,1), rgba(255,255,255,0)); +} +a, a:hover, a:visited { + border: none; + color: inherit; + text-decoration: none; +} +body { + position: fixed; + overflow: hidden; + font-weight: normal; + font-family: sans-serif; + font-size: larger; + top: 0; + left: 0; + right: 0; + bottom: 0; +} +body,div { + display: flex; + padding: 0px; + border: 0px; + margin: 0px; +} +div { + position: relative; +} +button { + display: flex; + border: 1px solid #ccc; + border-radius: 3px; + background-color: #eee; + padding: 2px 7px 3px 7px; + margin: 1px; + margin-bottom: 2px; +} +button:hover { + background-color: #aaa; + color: black; +} +button[load] { + width: 100%; + text-align: left; +} +button[del] { + margin-left: 5px; +} +input { + background-color: #eee; + margin-bottom: 1px; + text-align: right; + border: 1px solid #bbb; + padding-top: 0; + padding-bottom: 0; + margin-top: 1px; + margin-bottom: 1px; +} +input:focus { + background-color: #fec; +} +input[disabled] { + background-color: #ddd; + color: #000; + border-width: 1px; +} +input[type="range"] { + width: 85px; + background-color: transparent; +} +input[type=range]::-moz-focus-outer { + border: 0; +} +select, textarea, button, input, a { + outline: none; +} +select { + border: 1px solid #bbb; + background-color: rgba(255,255,255,0.5); + border-radius: 3px; +} +select option[local="1"] { + color: #55d; +} +select option[favorite="1"] { + font-weight: bold; +} +th, tr, td, span, div, label, button { + user-select: none; +} +th, tr, td { + white-space: nowrap; +} +.noselect { + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.hide { + display: none !important; +} +.noshow { + display: none; +} +.row { + flex-direction: row; +} +.col { + flex-direction: column; +} +.auto { + flex-basis: auto; +} +.grow { + flex-grow: 1; +} +.a-start { + align-items: flex-start; +} +.a-center { + align-items: center; +} +.a-end { + align-items: flex-end; +} +.a-stretch { + align-items: stretch; +} +.j-start { + justify-content: flex-start; +} +.j-center { + justify-content: center; +} +.j-end { + justify-content: flex-end; +} +.space-between { + justify-content: space-between; +} +.center { + text-align: center; +} +.russo { + font-family: 'Russo One', sans-serif; +} +.overy { + overflow-y: auto; +} +.mh0 { + min-height: 0; +} +.mh85 { + max-height: 85%; +} + +:-moz-any() { + overflow-x: hidden !important; + overflow-y: hidden !important; +} +:-moz-any() { + overflow-x: scroll !important; + overflow-y: scroll !important; + margin-right: -14px !important; + margin-bottom: -14px !important; +} + +#curtain { + top: 0; + left: 0; + right: 0; + bottom: 0; + position: fixed; + background-color: #fff; + font-family: 'Russo One', sans-serif; + z-index: 11; +} + +#tracker { + top: 0; + left: 0; + right: 0; + bottom: 0; + position: absolute; + display: none; + z-index: 101; +} + +#container { + position: fixed; + z-index: -1; + width: 100%; + height: 100%; +} +#container canvas { + width: 100%; + height: 100%; + overflow: hidden; +} + +#top { + font-family: 'Russo One', sans-serif; + background-color: rgba(255,255,255,0.75); + padding: 3px; + z-index: 15; +} +#top > div { + margin: 0 5px 0 5px; +} + +#app-mode, #app-acct { + width: 125px; +} +#app-mode:hover #mode-info { + display: flex; +} +#mode-info { + display: none; + position: absolute; + white-space: nowrap; + font-size: smaller; + font-family: sans-serif; + margin-top: 5px; + padding: 5px; + left: -6px; + top: 100%; + color: var(--fg-gray); + border-radius: 3px; + border: 1px solid #ddd; + background-color: white; +} +#mode-info > div { + padding: 2px 0 2px 0; +} +#mode-info label { + font-weight: bold; + padding-right: 5px; +} + +#app-name:hover #app-info { + display: flex; +} +#app-info { + display: none; + position: absolute; + white-space: nowrap; + font-size: smaller; + font-family: sans-serif; + margin-top: 5px; + padding: 5px; + top: 100%; + color: var(--fg-gray); + border-radius: 3px; + border: 1px solid #ddd; + background-color: white; +} + +#app-acct { + align-items: center; + justify-content: flex-end; +} +#app-acct:hover #acct-pop { + display: flex; +} +#acct-pop { + display: none; + color: var(--fg-gray); + font-family: sans-serif; + position: absolute; + right: -6px; + top: 100%; +} +#acct-pop > div { + margin-top: 5px; + align-items: stretch; + background-color: white; + border: 1px solid #ddd; + border-radius: 3px; + padding: 0; +} +#acct-pop > div > div { + padding: 5px; +} +#acct-pop > div > div:hover { + color: #000; + background-color: #f4f4f4; +} +#acct-lang:hover #lang-pop { + display: flex; +} +#lang-pop { + display: none; + position: absolute; + right: 100%; + top: -1px; + align-items: stretch; + text-align: right; + border-radius: 3px; + border: 1px solid #ddd; + background-color: white; +} +#lang-pop > div { + padding: 5px 7px 5px 7px; +} +#lang-pop > div:hover { + color: #000; + background-color: #f4f4f4; +} + +#mid { + pointer-events: none; +} + +#mid-lcol, #mid-rcol, #modal { + pointer-events: visible; +} + +#top-sep { + display: none; +} +#top-sep, #mid-sep { + z-index: 14; + height: 1px; + background-image: var(--gradbar); +} + +#lt-top { + height: 10px; + border-top-right-radius: 10px; + background-color: var(--bg-gray); + left: -5px; +} + +#lt-back { + position: absolute; + display: none; + top: 0; +} +#lt-sep, #lt-sep-help { + background-color: var(--bg-gray); + height: 10px; + left: -5px; +} + +#lt-end { + height: 10px; + border-bottom-right-radius: 10px; + background-color: var(--bg-gray); + left: -5px; +} + +.pop-lcol { + position: absolute; + display: none; + top: -3px; + left: 100%; + z-index: 10; +} +.pop-lcol > div { + flex-direction: column; + align-items: center; + margin: 2px; + padding: 5px; + background-color: rgba(255,255,255,0.75); + border: 1px solid rgba(0,0,0,0); + border-radius: 3px; + width: 60px; + color: var(--fg-gray); +} +.pop-lcol > div:hover { + background-color: #eee; + border: 1px solid #aaa; + color: #000; +} +.pop-sel { + background-color: #ddd !important; +} + +.lt-menu { + flex-direction: column; + align-items: center; + margin: 2px 0 2px 0; + padding: 5px 5px 5px 10px; + border: 1px solid rgba(0,0,0,0); + border-radius: 3px; + color: var(--fg-gray); + left: -5px; + background-color: rgba(255,255,255,0.75); +} +.lt-menu svg { + font-size: 40px; + text-align: center; +} +.lt-menu label { + font-size: smaller; +} +.lt-menu:hover { + background-color: #eee; + border: 1px solid #aaa; + color: #000; +} +.lt-menu:hover .pop-lcol { + display: flex; +} + +.ext-buttons button { + justify-content: center; + align-items: center; + text-align: center; + flex-grow: 1; + margin-top: 3px; +} +.txt-sel { + background-color: #eee; +} +.txt-sel button { + background-color: #ccc; +} + +#end { + left: 0; + right: 0; + bottom: 0; + position: fixed; + text-align: center; + font-size: smaller; + height: 25px; +} + +#progress { + display: none; + position: absolute; + top: 0px; + left: 10%; + right: 10%; + text-align: center; + background-color: rgba(0,0,0,0.15); + border-radius: 3px; +} +#progbar { + width: 100%; + text-align: left; + position: relative; + background-color: rgba(255,0,0,0.65); + border-radius: 3px; +} +#progtxt { + color: white; + margin: 0 5px 0 5px; + padding: 0 5px 2px 5px; + white-space: nowrap; + flex-direction: row; + align-items: center; + vertical-align: middle; +} + +#modal { + display: none; + position: fixed; + z-index: 20; + top: 50%; + left: 0px; + right: 0px; + bottom: 0px; + height: 300px; + transform: translateY(-50%); + background-color: var(--bg-gray); + border-bottom: 1px solid black; + border-top: 1px solid black; + overflow: hidden; +} +#modal > div { + position: absolute; + transform: translateX(50%) translateY(-50%); + right: 50%; + top: 50%; +} +.mdialog { + display: none; + padding: 10px; + min-height: 20px; + font-size: smaller; + background-color: rgba(255,255,255,0.75); +} + +.mod-top { + height: 10px; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + background-color: var(--bg-gray); +} +#mod-x { + position: absolute; + z-index: 30; + bottom: -20px; + right: 5px; +} +#mod-print { + background-color: rgba(255,255,255,0.85); +} +#mod-print .grow button { + margin-left: 5px; +} +#mod-print .hint { + color: #345; + font-size: 12px; + font-style: italic; + text-align: center; + font-weight: normal; + padding-top: 5px; +} +#mod-print .box { + background-color: rgba(255,255,255,0.5); + border: 1px solid #bbb; + border-radius: 3px; + padding: 20px 10px 10px 10px; +} +#mod-print .box select { + min-width: 10em; +} +#mod-print .header { + flex-direction: column; + justify-content: center; + align-items: center; + transform: translateY(50%); + z-index: 10; +} +#mod-print .header label { + background-color: white; + padding: 0 10px 0 10px; + border-radius: 5px; + border-right: 1px solid #bbb; + border-left: 1px solid #bbb; +} +#mod-print a { + text-decoration: underline; +} +#mod-print a:hover { + color: #567; + background-color: #ddd; +} +#mod-print label { + flex-grow: 1; + font-weight: bold; + padding-right: 10px; +} +#mod-print button { + flex-direction: column; + justify-content: center; + align-items: center; + min-height: 2em; +} +#print-canvas { + width: 180px; + height: 320px; + border: 1px solid #ccc; + background-color: #f5f5f5; + transform: scale(-1, 1); +} +#print-layer { + font-family: 'Russo One', sans-serif; + font-size: small; + width: 5em; + padding: 0 !important; + text-align: right; +} +#print-download { + min-height: 4em !important; +} +.mod-end { + height: 10px; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + background-color: var(--bg-gray); +} +#settingsList button.selected { + font-weight: bold; + background-color: #ccc; +} +#settingsList button.selected:hover { + background-color: #aaa; +} + +#help p { + margin: 2px; +} +#help a { + font-weight: bold; + text-decoration: underline; +} +#help #kiri-version { + font-weight: bold; +} +#help .header { + background-color: rgba(0,0,0,0.1); + justify-content: center; + white-space: nowrap; + text-align: center; + border-radius: 5px; + margin-bottom: 5px; + padding: 1px 0 2px 0; + font-family: monospace; +} +#help .title { + justify-content: center; + flex-direction: column; + text-align: center; + font-size: larger; + font-weight: bold; + padding: 10px; +} +#help .content { + white-space: nowrap; + flex-direction: column; + font-family: monospace; + margin: 3px 0 8px 0; +} +#help .footer { + font-family: monospace; + align-items: center; + white-space: nowrap; + flex-direction: column; + padding: 8px 0 3px 0; + border-top: 1px dashed #aaa; +} +#help th, #help td { + font-family: monospace; +} +#help td label { + font-weight: bold; +} +#help-left { + padding-right: 5px; + border-right: 1px dashed #aaa; +} +#help-left .title { + margin-bottom: 2px; +} +#help-right { + padding-left: 3px; +} + +.dev-type { + font-family: 'Russo One', sans-serif; + flex-direction: column; + align-items: center; + background-color: rgba(255,255,255,0.75); + border-radius: 5px; + width: 100px; + margin: 5px; +} +.dev-sel { + color: #033; + background-color: #bbb; +} + +.t-head { + text-align: center; + font-weight: bold; + padding-bottom: 5px; +} +.t-33 { + width: 33%; +} +.fillh { + top: 0; + bottom: 0; +} +.t-group { + background-image: var(--gradbar); + white-space: nowrap; + text-align: center; + justify-content: center; + border-radius: 2px; + padding: 1px 0 2px 0; + margin: 5px 0 5px 0; + color: white; +} +.t-body { + background-color: rgba(255,255,255,0.5); + border: 1px solid #bbb; + border-radius: 3px; +} +.t-inset { + padding: 3px; +} +.t-pad { + width: 5px; +} +.t-pad2 { + width: 10px; +} + +#devices { + width: 200px; +} +#device { + width: 200px; +} +#gcode-edit { + width: 200px; +} +#dev-gcode textarea { + font-family: monospace; + width: 100%; +} +#device-action, #tool-action { + margin-top: 5px; +} +#device-action button, #tool-action button { + flex-direction: column; + justify-content: center; +} +#catalogList { + min-width: 150px; + height: 350px; + overflow-y: scroll; +} +#catalogList .label { + width: 10em; + justify-content: flex-end; +} +#catalogList .rename { + font-style: italic; + color: #335; +} + +#slider { + display: none; + position: absolute; + font-size: smaller; + top: 10px; + right: 3px; + bottom: 10px; + width: 50px; +} +#slider-hi-val, #slider-lo-val { + display: none; + position: absolute; + font-family: monospace; + transform: translateY(-50%); + background-color: rgba(255,255,255,0.5); + border: 1px solid #ddd; + border-radius: 3px; + right: 110%; + top: 50%; +} +#slider > div { + flex-direction: column; + align-items: center; +} +#slider-max { + background-color: #ccc; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + margin-bottom: 3px; +} +#slider-center { + background-image: var(--holdbar); +} +#slider-zero { + z-index: 10; + margin-top: 3px; + background-color: #ccc; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; +} +#slider-hold { + background-color: rgba(0,0,0,0.15); + position: absolute; + right: 0; + left: 0; + top: 0; +} +#slider-hold .handle { + width: 100%; + height: 10px; + border-radius: 3px; + background-color: var(--bg-gray); +} +#slider-mid { + height: 20px; +} + +#alert-area { + display: none; + justify-content: center; + align-items: center; + position: absolute; + bottom: 40px; + left: 0; + right: 0; +} +#alert-border { + display: flex; + justify-content: center; + align-items: center; + max-width: 50%; + background-color: rgba(255,255,255,0.5); + border: 3px solid var(--bg-gray); + border-radius: 5px; +} +#alert-border:hover { + background-color: rgba(0,0,0,0.1); +} +#alert-text { + display: flex; + text-align: left; + font-weight: bold; + flex-direction: column; + margin: 3px 5px 3px 5px; + color: black; +} +#alert-text p { + margin: 5px; + text-align: center; +} + +#settings { + align-items: stretch; +} +#set-top { + color: black; + padding: 1px 10px 2px 2px; + border-top-left-radius: 10px; + border-bottom-left-radius: 0; + background-color: var(--bg-gray); +} +#set-end { + color: black; + padding: 1px 10px 2px 2px; + border-top-left-radius: 0; + border-bottom-left-radius: 10px; + background-color: var(--bg-gray); + height: 10px; +} +.set-header { + background-color: rgba(0,0,0,0.1); + text-align: center; + white-space: nowrap; + justify-content: center; + border-radius: 2px; + padding: 1px 0 2px 0; + margin: 5px 0 5px 0; +} +.set-group { + align-items: center; + flex-direction: column; + background-color: rgba(255,255,255,0.75); + border: 1px solid rgba(0,0,0,0); + border-radius: 3px; + margin: 2px 0 2px 4px; + padding: 8px 10px 8px 5px; + color: var(--fg-gray); + right: -5px; +} +.set-group:hover { + background-color: #eee; + border: 1px solid #aaa; + color: #000; +} +.set-pop { + top: 50%; + right: 100%; + position: absolute; + white-space: nowrap; + flex-direction: column; + transform: translateY(-50%); + background-color: rgba(255,255,255,0.5); + border: 1px solid #aaa; + border-radius: 5px; + margin-right: 5px; + padding: 5px; +} +#layers .var-row { + border-radius: 10px; + background-color: #ddd; + padding: 2px 5px 2px 5px; + margin: 0 2px 0 2px; +} +.var-row { + white-space: nowrap; + align-items: center; +} +.var-row label { + padding: 2px 4px 2px 0; + flex-grow: 1; + font-size: smaller; +} +.var-row input { + margin-right: 0; + margin-bottom: 1px; + padding-bottom: 1px; + padding-top: 1px; +} +.var-row button { + margin-right: 0; + margin-bottom: 1px; +} +.table-row { + flex-direction: row; + align-items: stretch; +} + +#focuser { + position: fixed; + z-index: -100; + left: -100%; + top: -100%; +} diff --git a/web/kiri/index.html b/web/kiri/index.html index 1e3daeaf..cf28d1c3 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -2,10 +2,10 @@ + + - - @@ -14,211 +14,319 @@ Kiri:Moto - - + + + + - - -
- A
- Kiri:Moto Slicer - ? -
- -
- -
- -
- mode -   :   - device -   :   - settings -
- - - + + +
loading...
- -
status
- -
-
- -
-
-
- -
-
- -
-
-
- -
-
-
- - -
-
-
- -
-
-
-
-
-
-
-
-
- - - - - - - - +
+
+
+
+
+
+
123
+
456
-
- -
-
-
- - - -
-
-
- -
-
-
- +
+
+
Kiri:Moto
+
version
+
+
+
+ +
+
+
+ +
+
english
+
danish
+
+
+
+
-
-
-
-
shaft
-
-
-
flute
-
-
-
taper
- -
-
-
-
- - - - -
- -
-
- - -
- - - - - - - - - - - - - - - - - - - - -
+
+
+
loading
+
+
+ +
+
+
+ + +
+
+ + +
+
+ +
+
+ +
- - - -
-
- - -
- - -
- - -
+
+
+ + +
+
+ + +
+
+ +
- - - -
-
- - - x - x - - +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
∞
+
+
+
+
 
+
+
+
+
0
+
- -
- -
- - - - - -
- -
-
-
+
+
+
+
+
+
+
alerts
alerts
alerts
+
diff --git a/web/kiri/lang/en-help.html b/web/kiri/lang/en-help.html index 72c56e63..df334860 100644 --- a/web/kiri/lang/en-help.html +++ b/web/kiri/lang/en-help.html @@ -1,114 +1,98 @@ - +
-
+
+
Kiri:Moto
-
- -

Quick Help

- -
- Kiri:Moto - is an open-source slicer for -
- Laser cutting, 3D printing, CNC milling -
- -
Loading Objects
- -
- Drag and drop a file onto the grid -
- or import from your computer -
- -
Workflow
- -
- Select operating mode
- Select target device
- Slice, Preview, then Export GCode -
- -
Integrations
- -
- Kiri:Moto is also available through
- Onshape and - Thingiverse as apps -
- -
Resources
- -
- Watch a tutorial on YouTube -
- Follow Grid.Space on Twitter -
- Join the user group on Facebook -
- Visit the Wiki on Github -

... or ...

-

Choose another version of Kiri:Moto

-
- -

- -
- -
-

Keyboard & Mouse Controls
-

-

- - - - - - - - - - - - - - - - - - - - - - -
Mode
Arrange
Slice
Preview
Export
View
Home
Top
Left
Right
Back
Reset
Layer
wheelChange Layer
dragPan
right-dragPan
left-dragRotate
mouse-wheelZoom
middle-dragZoom
- - - - - - - - - - - - - - - - - - - -
Config
This Help Window
Device Selection
CAM Tool Selection
Grid Local Devices
Object
Duplicate
Mirror
Wireframe
Delete
Rotate 90°
Rotate 5°
Move 5mm
Align face to bed
of selected object
+
About
+
+

Kiri:Moto is an open-source slicer for

+

Laser cutting, 3D printing, CNC milling

-
-

Kiri:Moto is entirely open source!

-

Please contribute to the project with code,
- ideas, or localizations for your preferred language.

-

<ESC> key closes any dialog in Kiri

+
File Loading
+
+

Drag and drop a file onto the grid

+

or import from your computer

+
+ +
Integrations
+
+

Kiri:Moto is also available through

+

Onshape and + Thingiverse as apps

+
+ +
Resources
+
+

Watch a tutorial on YouTube

+

Follow Grid.Space on Twitter

+

Join the user group on Facebook

+

Visit the Wiki on Github

+

... also ...

+

Choose another version of Kiri:Moto

+
+ +
+ +
+ +
+
Keyboard & Mouse Controls
+ +
+ + + + + + + + + + + + + + + + + + + + + +
Mode
Arrange
Slice
Preview
Export
View
Top
Home
Layer
wheelChange Layer
dragPan
Pan
Rotate
Zoom
Zoom
Help
This Window
Reset View
+ + + + + + + + + + + + + + + + + + + + + +
Config
Device Selection
CAM Tool Selection
Grid Local Devices
Preference panel
Object
Duplicate
Mirror
Wireframe
Delete
Rotate 90°
Rotate 5°
Move 5mm
Align face to bed
of selected object
File
Import
Recent
+
+ +
+
diff --git a/web/kiri/lang/en.js b/web/kiri/lang/en.js index 356ebc2c..2b1376b6 100644 --- a/web/kiri/lang/en.js +++ b/web/kiri/lang/en.js @@ -85,9 +85,13 @@ kiri.lang['en-us'] = { su_xprt: "Export", su_help: "Help", - // FUNCTION - fn_menu: "function", + // LOAD + fe_menu: "file", + fn_recn: "Recent", fn_impo: "Import", + + // FUNCTION + fn_menu: "action", fn_arra: "Arrange", fn_slic: "Slice", fn_prev: "Preview", @@ -95,20 +99,20 @@ kiri.lang['en-us'] = { // VIEW vu_menu: "view", - vu_home: "home", - vu_rset: "reset", - vu_sptp: "top", - vu_spfr: "front", - vu_splt: "left", - vu_sprt: "right", + vu_home: "Home", + vu_rset: "Reset", + vu_sptp: "Top", + vu_spfr: "Front", + vu_splt: "Left", + vu_sprt: "Right", // WORKSPACE - ws_menu: "workspace", + ws_menu: "view", ws_save: "Save", ws_cler: "Clear", // OPTIONS - op_menu: "options", + op_menu: "preferences", op_xprt_s: "expert", op_xprt_l: "enable expert options", op_dark_s: "dark mode", @@ -125,13 +129,17 @@ kiri.lang['en-us'] = { op_free_l: "permit dragable layout", op_invr_s: "invert zoom", op_invr_l: "invert mouse wheel\nscroll zoom", + op_thin_s: "thin lines", + op_thin_l: "faster part visualization\nsacrificing visual quality", op_unit_s: "units", op_unit_l: "workspace units affects\nspeeds and distances", + xp_menu: "export", + // LAYERS pop-menu la_menu: "layers", la_olin: "outline", - la_trce: "trace", + la_trce: "shells", la_face: "facing", la_ruff: "roughing", la_fini: "finishing", @@ -140,13 +148,13 @@ kiri.lang['en-us'] = { la_dlta: "delta", la_slds: "solids", la_fill: "solid fill", - la_sprs: "sparse", - la_sprt: "support", + la_sprs: "infill", + la_sprt: "supports", la_prnt: "print", la_move: "moves", // SETTINGS - se_menu: "settings", + se_menu: "library", se_load: "load", se_save: "save", @@ -164,7 +172,7 @@ kiri.lang['en-us'] = { sl_lbot_l: "number of solid layers\nto enforce at the\nbottom of the print", // FDM FILL - fi_menu: "fill", + fi_menu: "infill", fi_type: "type", fi_pcnt_s: "percentage", fi_pcnt_l: "fill density values\n0.0 - 1.0", @@ -174,7 +182,7 @@ kiri.lang['en-us'] = { fi_over_l: "overlap with shell and fill\nas % of nozzle width\nhigher bonds better\n0.0 - 1.0", // FDM FIRST LAYER - fl_menu: "first layer", + fl_menu: "1st layer", fl_lahi_s: "layer height", fl_lahi_l: "height of each slice\nin millimeters\nshould be >= slice height", fl_rate_s: "shell speed", @@ -235,9 +243,11 @@ kiri.lang['en-us'] = { cc_pock_l: "constrain cuts to\npart boundaries", // CNC COMMON - cc_menu: "common", - cc_rapd_s: "rapid feed", - cc_rapd_l: "rapid moves feedrate\nin workspace units / minute", + cc_menu: "limits", + cc_rapd_s: "xy feed", + cc_rapd_l: "max xy moves feedrate\nin workspace units / minute", + cc_rzpd_s: "z feed", + cc_rzpd_l: "max z moves feedrate\nin workspace units / minute", // CNC ROUGHING cr_menu: "roughing", @@ -271,7 +281,7 @@ kiri.lang['en-us'] = { cd_lift_l: "lift between plunges\nafter dwell period\nin workspace units\n0 to disable", // CNC CUTOUT TABS - ct_menu: "cutout tabs", + ct_menu: "tabs", ct_angl_s: "angle", ct_angl_l: "starting angle for tab spacing\nin degrees (0-360)", ct_numb_s: "count", @@ -325,7 +335,7 @@ kiri.lang['en-us'] = { // OUTPUT CAM ou_toll_s: "tolerance", - ou_toll_l: "surface precision\nin workspace units", + ou_toll_l: "surface precision\nin workspace units\nlower is slower and\nuses more memory", ou_ztof_s: "z top offset", ou_ztof_l: "offset from stock surface\nto top face of part\nin workspace units", ou_zbot_s: "z bottom", @@ -357,7 +367,7 @@ kiri.lang['en-us'] = { or_topp_l: "origin is references from the top of objects", // FDM ADVANCED - ad_menu: "advanced", + ad_menu: "expert", ad_rdst_s: "retract dist", ad_rdst_l: "amount to retract filament\nfor long moves. in millimeters", ad_rrat_s: "retract rate", diff --git a/web/kiri/output-gcode.html b/web/kiri/output-gcode.html index 038b914c..649c7a0d 100644 --- a/web/kiri/output-gcode.html +++ b/web/kiri/output-gcode.html @@ -1,68 +1,57 @@ - - -output options - -
- - - - - +
+ -