Merge branch 'rel-4.3'

This commit is contained in:
Stewart Allen 2025-10-12 19:26:24 -04:00
commit dbcf85863f
27 changed files with 562 additions and 674 deletions

2
app.js
View file

@ -122,6 +122,7 @@ function init(mod) {
mod.add(serveWasm);
mod.add(serveCode);
mod.add(fullpath({
"/boot" : redir((pre??"") + "/boot/", 301),
"/kiri" : redir((pre??"") + "/kiri/", 301),
"/mesh" : redir((pre??"") + "/mesh/", 301),
"/meta" : redir((pre??"") + "/meta/", 301),
@ -147,6 +148,7 @@ function init(mod) {
mod.static("/mesh/", "web/mesh");
mod.static("/moto/", "web/moto");
mod.static("/kiri/", "web/kiri");
mod.static("/boot/", "web/boot");
// module loader
function load_modules(root, force) {

11
bin/bundle.config.json Normal file
View file

@ -0,0 +1,11 @@
{
"outputs": {
"bundle": "./web/kiri/bundle.bin"
},
"inputs": [
{ "root": "./web", "prefix": "" },
{ "root": "./src", "prefix": "lib" },
{ "root": "./src/wasm", "prefix": "wasm" },
{ "root": "./src/wasm", "prefix": "lib/kiri/wasm" }
]
}

106
bin/bundler.mjs Normal file
View file

@ -0,0 +1,106 @@
import fs from 'fs';
import path from 'path';
import uglify from 'uglify-js';
import { Buffer } from 'buffer';
const cfg = JSON.parse(fs.readFileSync(process.argv[2] || './bundle.config.json', 'utf8'));
const compress = process.env.UGLIFY ? true : false
// --- recursive directory walker (follows symlinks safely) ---
function* walk(dir, seen = new Set()) {
const real = fs.realpathSync(dir);
if (seen.has(real)) {
return;
}
seen.add(real);
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name);
let st;
try { st = fs.statSync(p); } catch { continue; }
if (st.isDirectory()) yield* walk(p, seen);
else yield p;
}
}
// --- collect all files according to config ---
let entries = [];
for (const input of cfg.inputs) {
const root = input.root;
const prefix = input.prefix || '';
for (const file of walk(root)) {
const rel = path.relative(root, file).replace(/\\/g, '/');
const virt = prefix ? `${prefix}/${rel}` : rel;
entries.push({ file, virt });
}
}
// --- build header and data ---
const dataParts = [];
const entryMeta = [];
let offset = 0;
let cache = new Map();
for (const { file, virt } of entries) {
let record = cache.get(file);
if (record) {
// console.log({ dup: file });
entryMeta.push({ ...record, virt });
} else {
let data = fs.readFileSync(file);
if (compress && file.endsWith("js")) {
console.log('compress', file);
data = uglify.minify(data.toString(), {
compress: {
merge_vars: false,
unused: false
}
});
// console.log({ to: typeof(data), data });
if (!data.code) {
console.log({ skip: file });
continue;
}
data = Buffer.from(data.code);
}
record = { virt, offset, length: data.length };
cache.set(file, record);
entryMeta.push(record);
dataParts.push(data);
offset += data.length;
}
}
// temporary header without offsets to measure total size
let tempHeaderParts = [];
for (const { virt, offset, length } of entryMeta) {
const name = Buffer.from(virt, 'utf8');
const nlen = Buffer.alloc(2); nlen.writeUInt16LE(name.length);
const offb = Buffer.alloc(4); offb.writeUInt32LE(0); // placeholder
const lenb = Buffer.alloc(4); lenb.writeUInt32LE(length);
tempHeaderParts.push(nlen, name, offb, lenb);
}
const count = Buffer.alloc(4); count.writeUInt32LE(entries.length);
const tempHeader = Buffer.concat([count, ...tempHeaderParts]);
const headerSize = tempHeader.length; // true data offset base
// now rebuild header with correct absolute offsets
let headerParts = [];
for (const { virt, offset, length } of entryMeta) {
const name = Buffer.from(virt, 'utf8');
const nlen = Buffer.alloc(2); nlen.writeUInt16LE(name.length);
const offb = Buffer.alloc(4); offb.writeUInt32LE(headerSize + offset);
const lenb = Buffer.alloc(4); lenb.writeUInt32LE(length);
headerParts.push(nlen, name, offb, lenb);
// console.log(virt);
}
const header = Buffer.concat([count, ...headerParts]);
const full = Buffer.concat([header, ...dataParts]);
// --- write final bundle ---
const outPath = cfg.outputs.bundle || './bundle.bin';
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, full); // ⚡ write raw binary
console.log(`✅ Bundled ${entries.length} files → ${outPath} (${full.length} bytes)`);

View file

@ -15,6 +15,7 @@
* `P` move all persisted / workspace settings/data to IndexedDB (LS limitations)
* `P` faster ray intersect https://github.com/gkjohnson/three-mesh-bvh/
* `P` try material clipping planes for slice range selection
* `P` switch png lib to https://github.com/photopea/UPNG.js
* `F` edit in Mesh:Tool
* `F` custom device vars for profiles / ranges / gcode

View file

@ -1,6 +1,6 @@
{
"name": "grid-apps",
"version": "4.3.2",
"version": "4.3.3",
"description": "grid.space 3d slicing & modeling tools",
"author": "Stewart Allen <sa@grid.space>",
"license": "MIT",
@ -82,7 +82,8 @@
"webpack-cli": "^5.1.4"
},
"scripts": {
"setup": "npm i && npm run clean && npm run dev -- --dryrun && npm run webpack-ext",
"setup": "npm run setup-mods && npm i && npm run clean && npm run dev -- --dryrun && npm run webpack-ext",
"setup-mods": "cd mods && npm i",
"build": "npm run prebuild && electron-builder",
"build-nopublish": "npm run prebuild && electron-builder --publish never",
"build-debug": "npm run prebuild && DEBUG=electron-builder electron-builder",

View file

@ -168,7 +168,7 @@ SP.init = function(options = {}) {
request = IDB.open(name, this.version);
request.onupgradeneeded = function(event) {
let db = storage.db = request.result;
let db = request.result;
let current = [...db.objectStoreNames];
let stores = storage.stores;
// add missing stores
@ -184,13 +184,12 @@ SP.init = function(options = {}) {
// remove obsolete stores
for (let curr of current) {
if (stores.indexOf(curr) < 0) {
storage.db.deleteObjectStore(curr);
db.deleteObjectStore(curr);
console.log({index_dropped: curr});
}
}
event.target.transaction.oncomplete = function(event) {
storage.runQueue();
};
// allow transactions
storage.db = db;
};
request.onsuccess = function(event) {
@ -217,6 +216,7 @@ SP.runQueue = function() {
let i = 0, q = this.queue, e;
while (i < q.length) {
e = q[i++];
// console.log('runQ', i, ...e);
switch (e.shift()) {
case 'iterate': this.iterate(...e); break;
case 'keys': this.keys(...e); break;
@ -252,7 +252,11 @@ SP.put = function(key, value, callback, store = this.current) {
req.onerror = function(event) { callback(false) };
}
} catch (e) {
console.log(e);
if (e.name === 'InvalidStateError') {
console.log({ putRetry: key });
return this.queue.push(['put', key, value, callback, store]);
}
console.log(e.name, e);
if (callback) callback(false);
}
};
@ -275,6 +279,10 @@ SP.get = function(key, callback, store = this.current) {
req.onerror = function(event) { callback(null) };
}
} catch (e) {
if (e.name === 'InvalidStateError') {
console.log({ getRetry: key });
return this.queue.push(['get', key, callback, store]);
}
console.log(e);
if (callback) callback(null);
}

View file

@ -4,4 +4,4 @@
import './pngjs.js';
// Re-export the PNG object
export const PNG = self.png ? self.png.PNG : null;
export const PNG = globalThis.png ? globalThis.png.PNG : null;

View file

@ -1,4 +1,4 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.png = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function(f){globalThis.png = f();if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.png = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (Buffer){
"use strict";

View file

@ -9,7 +9,7 @@ import { client as work } from './client.js';
import { consts, COLOR as color, LISTS as lists } from './consts.js';
import { device, devices } from './devices.js';
import { catalog, dialog, event, group, help, hide, image } from './main.js';
import { modal, mode, probe, process, show, space, util, view } from './main.js';
import { modal, mode, process, show, space, util, view } from './main.js';
import { local as dataLocal } from '../../data/local.js';
import { noop, ajax, o2js, js2o } from './utils.js';
import { functions } from './function.js';
@ -162,7 +162,6 @@ export const api = {
o2js,
onkey,
platform,
probe,
process,
sdb: dataLocal,
selection,

View file

@ -182,33 +182,33 @@ function normalize(settings) {
// auto field renaming on import
const renamed = {
roughingTool: "camRoughTool",
roughingSpindle: "camRoughSpindle",
roughingDown: "camRoughDown",
roughingOver: "camRoughOver",
roughingSpeed: "camRoughSpeed",
roughingPlunge: "camRoughPlunge",
roughingStock: "camRoughStock",
roughingPocket: "camRoughVoid",
roughingOn: "camRoughOn",
finishingTool: "camOutlineTool",
finishingSpindle: "camOutlineSpindle",
camWideCutout: "camOutlineWide",
drillDown: "camDrillDown",
drillDownSpeed: "camDrillDownSpeed",
drillDwell: "camDrillDwell",
drillingOn: "camDrillingOn",
drillLift: "camDrillLift",
drillSpindle: "camDrillSpindle",
drillTool: "camDrillTool",
finishingDown: "camOutlineDown",
finishingOver: "camContourOver",
finishingSpeed: "camOutlineSpeed",
finishingPlunge: "camOutlinePlunge",
finishingOn: "camOutlineOn",
finishingOver: "camContourOver",
finishingPlunge: "camOutlinePlunge",
finishingSpeed: "camOutlineSpeed",
finishingSpindle: "camOutlineSpindle",
finishingTool: "camOutlineTool",
finishingXOn: "camContourXOn",
finishingYOn: "camContourYOn",
drillTool: "camDrillTool",
drillSpindle: "camDrillSpindle",
drillDownSpeed: "camDrillDownSpeed",
drillDown: "camDrillDown",
drillDwell: "camDrillDwell",
drillLift: "camDrillLift",
drillingOn: "camDrillingOn",
camWideCutout: "camOutlineWide",
outputClockwise: "camConventional"
outputClockwise: "camConventional",
roughingDown: "camRoughDown",
roughingOn: "camRoughOn",
roughingOver: "camRoughOver",
roughingPlunge: "camRoughPlunge",
roughingPocket: "camRoughVoid",
roughingSpeed: "camRoughSpeed",
roughingSpindle: "camRoughSpindle",
roughingStock: "camRoughStock",
roughingTool: "camRoughTool",
};
export const conf = {
@ -258,97 +258,97 @@ export const conf = {
},
// process defaults FDM:Process
p:{
antiBacklash: 0,
arcTolerance: 0,
firstLayerBedTemp: 0,
firstLayerBeltBump: 0,
firstLayerBeltLead: 3,
firstLayerBrim: 0,
firstLayerBrimGap: 0,
firstLayerBrimIn: 0,
firstLayerBrimTrig: 0,
firstLayerFanSpeed: 0,
firstLayerFillRate: 35,
firstLayerFlatten: 0,
firstLayerLineMult: 1.0,
firstLayerNozzleTemp: 0,
firstLayerPrintMult: 1.0,
firstLayerRate: 30,
firstLayerYOffset: 0,
firstSliceHeight: 0.25,
outputAlternating: false,
outputAvoidGaps: true,
outputBedTemp: 60,
outputBeltFirst: false,
outputBrimCount: 2,
outputBrimOffset: 2,
outputCoastDist: 0,
outputDraftShield: false,
outputFanLayer: 1,
outputFanSpeed: 255,
outputFeedrate: 50,
outputFillMult: 1.25,
outputFinishrate: 50,
outputInvertX: false,
outputInvertY: false,
outputLayerRetract: false,
outputLoops: 0,
outputMinLayerTime: 10,
outputMinSpeed: 5.0,
outputPurgeTower: 0,
outputRaft: false,
outputRaftSpacing: 0.2,
outputRetractDist: 1.5,
outputRetractDwell: 20,
outputRetractSpeed: 40,
outputRetractWipe: 0,
outputScarfLength: 5,
outputSeekrate: 80,
outputShellMult: 1.25,
outputShortPoly: 0.0,
outputSparseMult: 1.25,
outputTemp: 200,
processName: "default",
ranges: [],
sliceAdaptive: false,
sliceAngle: 45,
sliceBottomLayers: 3,
sliceCompInner: 0,
sliceCompOuter: 0,
sliceDetectThin: "basic",
sliceFillAngle: 45,
sliceFillGrow: 0,
sliceFillOverlap: 0.35,
sliceFillRate: 0,
sliceFillRepeat: 1,
sliceFillSparse: 0.25,
sliceFillType: "hex",
sliceFillWidth: 1,
sliceHeight: 0.25,
sliceShells: 3,
sliceShellOrder: "in-out",
sliceLayerStart: "last",
sliceLayerStartX: 0,
sliceLayerStartY: 0,
sliceLineWidth: 0,
sliceCompInner: 0,
sliceCompOuter: 0,
sliceFillGrow: 0,
sliceFillAngle: 45,
sliceFillWidth: 1,
sliceFillOverlap: 0.35,
sliceFillSparse: 0.25,
sliceFillRepeat: 1,
sliceFillRate: 0,
sliceSolidRate: 0,
sliceFillType: "hex",
sliceSupportDensity: 0.1,
sliceSupportOffset: 1.0,
sliceSupportGap: 1,
sliceSupportSize: 5,
sliceSupportArea: 0.1,
sliceSupportSpan: 5,
sliceSupportGrow: 0,
sliceSupportExtra: 0,
sliceSupportAngle: 50,
sliceSupportNozzle: 0,
sliceSupportEnable: false,
sliceSupportOutline: true,
sliceZInterleave: false,
sliceSolidMinArea: 1,
sliceBottomLayers: 3,
sliceTopLayers: 3,
firstSliceHeight: 0.25,
firstLayerRate: 30,
firstLayerFillRate: 35,
firstLayerPrintMult: 1.0,
firstLayerLineMult: 1.0,
firstLayerYOffset: 0,
firstLayerNozzleTemp: 0,
firstLayerBedTemp: 0,
firstLayerBrim: 0,
firstLayerBrimIn: 0,
firstLayerBrimTrig: 0,
firstLayerBrimGap: 0,
firstLayerBeltLead: 3,
firstLayerBeltBump: 0,
firstLayerFanSpeed: 0,
firstLayerFlatten: 0,
outputRaft: false,
outputRaftSpacing: 0.2,
outputDraftShield: false,
outputTemp: 200,
outputBedTemp: 60,
outputFeedrate: 50,
outputFinishrate: 50,
outputSeekrate: 80,
outputShellMult: 1.25,
outputFillMult: 1.25,
outputSparseMult: 1.25,
outputFanLayer: 1,
outputFanSpeed: 255,
outputRetractDist: 1.5,
outputRetractSpeed: 40,
outputRetractWipe: 0,
outputRetractDwell: 20,
outputBrimCount: 2,
outputBrimOffset: 2,
outputScarfLength: 0,
outputShortPoly: 100.0,
outputMinSpeed: 10.0,
outputMinLayerTime: 0,
outputCoastDist: 0,
outputPurgeTower: 0,
outputBeltFirst: false,
outputAvoidGaps: true,
outputAlternating: false,
outputLayerRetract: false,
outputLoops: 0,
outputInvertX: false,
outputInvertY: false,
sliceDetectThin: "off",
sliceMinHeight: 0,
sliceAdaptive: false,
sliceShellOrder: "in-out",
sliceShells: 3,
sliceSolidMinArea: 1,
sliceSolidRate: 0,
sliceSupportAngle: 50,
sliceSupportArea: 0.1,
sliceSupportDensity: 0.1,
sliceSupportEnable: false,
sliceSupportExtra: 0,
sliceSupportGap: 1,
sliceSupportGrow: 0,
sliceSupportNozzle: 0,
sliceSupportOffset: 1.0,
sliceSupportOutline: true,
sliceSupportSize: 5,
sliceSupportSpan: 5,
sliceTopLayers: 3,
sliceZInterleave: false,
zHopDistance: 0.2,
arcTolerance: 0,
antiBacklash: 0,
ranges: []
}
},
sla:{
@ -422,186 +422,186 @@ export const conf = {
},
// process defaults CAM:Process
p:{
processName: "default",
camLevelTool: 1000,
camLevelSpindle: 1000,
camLevelOver: 0.75,
camLevelStepZ: 0,
camLevelSpeed: 1000,
camLevelDown: 0,
camLevelInset: 0.5,
camLevelStock: true,
camRoughTool: 1000,
camRoughSpindle: 1000,
camRoughDown: 2,
camRoughOver: 0.4,
camRoughSpeed: 1000,
camRoughPlunge: 250,
camRoughStock: 0,
camRoughStockZ: 0,
camRoughAll: true,
camRoughVoid: false,
camRoughFlat: true,
camRoughTop: true,
camRoughIn: true,
camRoughOn: true,
camRoughOmitThru: false,
camRoughOmitVoid: false,
camOutlineTool: 1000,
camOutlineSpindle: 1000,
camOutlineTop: true,
camOutlineDown: 3,
camOutlineOver: 0.4,
camOutlineOverCount: 1,
camOutlineSpeed: 800,
camOutlinePlunge: 250,
camOutlineWide: false,
camOutlineDogbone: false,
camOutlineOmitThru: false,
camOutlineOmitVoid: false,
camOutlineOut: true,
camOutlineIn: false,
camOutlineOn: true,
camContourTool: 1000,
camContourSpindle: 1000,
camContourOver: 0.5,
camContourSpeed: 1000,
camArcEnabled: false,
camArcResolution: 5,
camArcTolerance: 0.15,
camContourAngle: 85,
camContourLeave: 0,
camContourReduce: 2,
camContourBottom: false,
camContourBridge: 0,
camContourCurves: false,
camContourIn: false,
camContourLeave: 0,
camContourOver: 0.5,
camContourReduce: 2,
camContourSpeed: 1000,
camContourSpindle: 1000,
camContourTool: 1000,
camContourXOn: true,
camContourYOn: true,
camLatheTool: 1000,
camLatheSpindle: 1000,
camLatheOver: 0.1,
camLatheAngle: 1,
camLatheSpeed: 500,
camLatheLinear: true,
camTolerance: 0,
camTraceTool: 1000,
camTraceSpindle: 1000,
camTraceType: "follow",
camTraceOver: 0.5,
camTraceDown: 0,
camTraceThru: 0,
camTraceSpeed: 250,
camTracePlunge: 200,
camTraceOffOver: 0,
camTraceDogbone: false,
camTraceMerge: false,
camTraceLines: false,
camTraceZTop: 0,
camTraceZBottom: 0,
camPocketSpindle: 1000,
camPocketTool: 1000,
camPocketOver: 0.25,
camPocketDown: 1,
camPocketSpeed: 250,
camPocketPlunge: 200,
camPocketExpand: 0,
camPocketSmooth: 0,
camPocketRefine: 20,
camPocketFollow: 5,
camPocketContour: false,
camPocketEngrave: false,
camPocketOutline: false,
camPocketZTop: 0,
camPocketZBottom: 0,
camDrillTool: 1006,
camDrillSpindle: 1000,
camDrillDownSpeed: 250,
camConventional: false, // outputClockwise
camDepthFirst: false,
camDrillDown: 5,
camDrillDownSpeed: 250,
camDrillDwell: 250,
camDrillFromStockTop: false,
camDrillingOn: false,
camDrillLift: 2,
camDrillMark: false,
camDrillFromStockTop: false,
camDrillThru: 5,
camDrillPrecision: 1,
camDrillingOn: false,
camRegisterSpeed: 1000,
camRegisterThru: 5,
camRegisterOffset: 10,
camHelicalTool: 1000,
camHelicalSpindle: 1000,
camHelicalDownSpeed: 250,
camHelicalSpeed: 1000,
camHelicalDown: 5,
camHelicalBottomFinish: true,
camHelicalThru: 0,
camHelicalOffset: "auto",
camHelicalForceStartAngle: false,
camHelicalStartAngle: 0,
camHelicalOffsetOverride: 0,
camHelicalEntry: false,
camHelicalEntryOffset:0,
camHelicalReverse: false,
camHelicalClockwise: true,
camFlipAxis: "X",
camFlipOther: "",
camLaserEnable: ["M321"],
camLaserDisable: ["M322"],
camLaserOn: ["M3"],
camLaserOff: ["M5"],
camLaserSpeed: 100,
camLaserPower: 1,
camLaserAdaptive: false,
camLaserAdaptMod: false,
camLaserFlatten: false,
camLaserFlatZ: 0,
camLaserPowerMin: 0,
camLaserPowerMax: 1,
camLaserZMin: 0,
camLaserZMax: 0,
camTabsWidth: 5,
camTabsHeight: 5,
camTabsDepth: 5,
camTabsMidline: false,
camDepthFirst: false,
camInnerFirst: false,
camEaseDown: false,
camDrillSpindle: 1000,
camDrillThru: 5,
camDrillTool: 1006,
camEaseAngle: 10,
camOriginTop: true,
camZAnchor: "middle",
camZOffset: 0,
camZTop: 0,
camZBottom: 0,
camZClearance: 1,
camZThru: 0,
camEaseDown: false,
camExpertFast: false,
camFastFeed: 6000,
camFastFeedZ: 300,
camTolerance: 0,
camFirstZMax: false,
camFlatness: 0.001,
camContourBridge: 0,
camStockX: 5,
camStockY: 5,
camStockZ: 5,
camStockOffset: true,
camStockClipTo: false,
camStockIndexed: false,
camStockIndexGrid: true,
camIndexAxis: 0,
camFlipAxis: "X",
camFlipOther: "",
camForceZMax: false,
camFullEngage: 0.8,
camHelicalBottomFinish: true,
camHelicalClockwise: true,
camHelicalDown: 5,
camHelicalDownSpeed: 250,
camHelicalEntry: false,
camHelicalEntryOffset:0,
camHelicalForceStartAngle: false,
camHelicalOffset: "auto",
camHelicalOffsetOverride: 0,
camHelicalReverse: false,
camHelicalSpeed: 1000,
camHelicalSpindle: 1000,
camHelicalStartAngle: 0,
camHelicalThru: 0,
camHelicalTool: 1000,
camIndexAbs: true,
camConventional: false, // outputClockwise
camIndexAxis: 0,
camInnerFirst: false,
camLaserAdaptive: false,
camLaserAdaptMod: false,
camLaserDisable: ["M322"],
camLaserEnable: ["M321"],
camLaserFlatten: false,
camLaserFlatZ: 0,
camLaserOff: ["M5"],
camLaserOn: ["M3"],
camLaserPower: 1,
camLaserPowerMax: 1,
camLaserPowerMin: 0,
camLaserSpeed: 100,
camLaserZMax: 0,
camLaserZMin: 0,
camLatheAngle: 1,
camLatheLinear: true,
camLatheOver: 0.1,
camLatheSpeed: 500,
camLatheSpindle: 1000,
camLatheTool: 1000,
camLevelDown: 0,
camLevelInset: 0.5,
camLevelOver: 0.75,
camLevelSpeed: 1000,
camLevelSpindle: 1000,
camLevelStepZ: 0,
camLevelStock: true,
camLevelTool: 1000,
camOriginCenter: false,
camOriginOffX: 0,
camOriginOffY: 0,
camOriginOffZ: 0,
camOriginTop: true,
camOutlineDogbone: false,
camOutlineDown: 3,
camOutlineIn: false,
camOutlineOmitThru: false,
camOutlineOmitVoid: false,
camOutlineOn: true,
camOutlineOut: true,
camOutlineOver: 0.4,
camOutlineOverCount: 1,
camOutlinePlunge: 250,
camOutlineSpeed: 800,
camOutlineSpindle: 1000,
camOutlineTool: 1000,
camOutlineTop: true,
camOutlineWide: false,
camPocketContour: false,
camPocketDown: 1,
camPocketEngrave: false,
camPocketExpand: 0,
camPocketFollow: 5,
camPocketOutline: false,
camPocketOver: 0.25,
camPocketPlunge: 200,
camPocketRefine: 20,
camPocketSmooth: 0,
camPocketSpeed: 250,
camPocketSpindle: 1000,
camPocketTool: 1000,
camPocketZBottom: 0,
camPocketZTop: 0,
camRegisterOffset: 10,
camRegisterSpeed: 1000,
camRegisterThru: 5,
camRoughAll: true,
camRoughDown: 2,
camRoughFlat: true,
camRoughIn: true,
camRoughOmitThru: false,
camRoughOmitVoid: false,
camRoughOn: true,
camRoughOver: 0.4,
camRoughPlunge: 250,
camRoughSpeed: 1000,
camRoughSpindle: 1000,
camRoughStock: 0,
camRoughStockZ: 0,
camRoughTool: 1000,
camRoughTop: true,
camRoughVoid: false,
camStockClipTo: false,
camStockIndexed: false,
camStockIndexGrid: true,
camStockOffset: true,
camStockX: 5,
camStockY: 5,
camStockZ: 5,
camTabsDepth: 5,
camTabsHeight: 5,
camTabsMidline: false,
camTabsWidth: 5,
camTolerance: 0,
camTolerance: 0,
camToolInit: true,
camTraceDogbone: false,
camTraceDown: 0,
camTraceLines: false,
camTraceMerge: false,
camTraceOffOver: 0,
camTraceOver: 0.5,
camTracePlunge: 200,
camTraceSpeed: 250,
camTraceSpindle: 1000,
camTraceThru: 0,
camTraceTool: 1000,
camTraceType: "follow",
camTraceZBottom: 0,
camTraceZTop: 0,
camTrueShadow: false,
camZAnchor: "middle",
camZBottom: 0,
camZClearance: 1,
camZOffset: 0,
camZThru: 0,
camZTop: 0,
op2: [], // flip ops
ops: [], // current ops
outputInvertX: false,
outputInvertY: false,
camExpertFast: false,
camTrueShadow: false,
camArcEnabled: false,
camArcTolerance: 0.15,
camArcResolution: 5,
camForceZMax: false,
camFirstZMax: false,
camToolInit: true,
camFullEngage: 0.8,
ops: [], // current ops
op2: [] // flip ops
processName: "default",
}
},
laser: {
@ -917,37 +917,35 @@ export const conf = {
devproc: {},
// application ui and control preferences (Q menu)
controller:{
view: null,
dark: false,
shiny: false,
drawer: false,
scrolls: true,
zoomSpeed: 1.0,
lineType: "path",
autoSave: true,
animesh: "800",
antiAlias: true,
assembly: false,
autoLayout: true,
autoSave: true,
dark: false,
detail: "50",
devel: false,
drawer: false,
edgeangle: 20,
exportOcto: false,
exportPreview: false,
exportThumb: false,
freeLayout: true,
healMesh: false,
lineType: "path",
ortho: false,
reverseZoom: true,
scrolls: true,
shiny: true,
showOrigin: false,
showRulers: true,
showSpeeds: true,
freeLayout: true,
autoLayout: true,
spaceRandoX: false,
spaceLayout: 1,
edgeangle: 20,
units: "mm",
exportOcto: false,
exportGhost: false,
exportLocal: false,
exportThumb: false,
exportPreview: false,
detail: "50",
animesh: "800",
healMesh: false,
spaceRandoX: false,
threaded: true,
assembly: false,
ortho: false,
devel: false
units: "mm",
view: null,
zoomSpeed: 1.0,
},
// default hidden ui groups
hidden: {

View file

@ -218,207 +218,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
ajax.send(form);
}
function gridhost_tracker(host,key) {
ajax(host+"/api/check?key="+key, function(data) {
data = js2o(data);
console.log(data);
if (!(data.done || data.error)) {
setTimeout(function() { gridhost_tracker(host,key) }, 1000);
}
});
}
function gridlocal_probe(ev, devs) {
if (ev && ev.code !== 'Enter') return;
if (!devs && api.probe.local(gridlocal_probe)) return;
grid_local = devs;
let gdev = localGet('grid-local');
let gloc = $('grid-local');
let html = [];
for (let uuid in devs) {
gdev = gdev || uuid;
let dev = devs[uuid];
let sel = uuid === gdev ? ' selected' : '';
html.push(`<option id="gl-${uuid}" value="${uuid}" ${sel}>${dev.stat.device.name}</option>`);
}
if (html.length) {
gloc.innerHTML = html.join('\n');
gloc.onchange = (ev) => {
localSet('grid-local', gloc.options[gloc.selectedIndex].value);
};
$('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() {
let uuid = $('grid-local').value;
let dev = grid_local[uuid];
if (dev) {
let file = $('print-filename').value;
fetch(
`${api.probe.live}/api/grid_send?uuid=${uuid}&file=${encodeURIComponent(file + "." + fileext)}`,
{method: "POST", body: gcode}
)
.then(t => t.text())
.then(t => {
api.stats.add(`ua_${api.mode.get_lower()}_print_local_ok`);
console.log({grid_spool_said: t});
})
.catch(e => {
api.stats.add(`ua_${api.mode.get_lower()}_print_local_err`);
console.log({grid_local_spool_error: e});
})
.finally(() => {
api.modal.hide();
});
}
}
function admin_gridlocal() {
let dev = grid_local[$('grid-local').value];
if (dev && dev.stat && dev.stat.device) {
let dsd = dev.stat.device;
window.open(`http://${dsd.addr[0]}:${dsd.port || 4080}`, "_grid_admin");
}
}
function gridhost_probe(ev, set_host) {
if (ev && ev.code !== 'Enter') return;
if (!(grid_host && grid_apik)) return;
if (set_host) grid_host.value = set_host;
let xhtr = new XMLHttpRequest(),
host = grid_host.value,
apik = grid_apik.value,
target = grid_target.value;
if (!apik) $('gpapik').style.display = 'none';
if (!host && api.probe.grid(gridhost_probe)) return;
if (!host) return;
xhtr.onreadystatechange = function() {
if (xhtr.readyState === 4) {
if (xhtr.status >= 200 && xhtr.status < 300) {
localSet('grid-host', host);
localSet('grid-apik', apik);
let res = JSON.parse(xhtr.responseText);
let sel = false;
let match = false;
let first = null;
let html = [];
grid_targets = {};
for (let key in res) {
first = first || key;
if (!localGet('grid-target')) {
localSet('grid-target', key);
sel = true;
} else {
sel = localGet('grid-target') === key;
}
match = match || sel;
grid_targets[html.length] = key;
html.push(
"<option id='gpo-'" + key + " value='" +key + "'" +
(sel ? " selected" : "") +
">" +
(res[key].comment || key) +
"</option>"
);
}
if (!match) {
localSet('grid-target', first);
}
grid_target.innerHTML = html.join('\n');
} else if (xhtr.status === 401) {
$('gpapik').style.display = '';
} else {
local.removeItem('grid-host');
local.removeItem('grid-apik');
console.log("invalid grid:host url");
}
}
};
xhtr.open("GET", host + "/api/active?key=" + apik);
xhtr.send();
}
function sendto_gridhost() {
if (!(grid_host && grid_apik)) return;
let xhtr = new XMLHttpRequest(),
host = grid_host.value,
apik = grid_apik.value,
target = localGet('grid-target') || '';
if (target === '') {
api.show.alert('invalid or missing target');
return;
}
if (host.indexOf("http") !== 0) {
api.show.alert("host missing protocol (http:// or https://)");
return;
}
if (host.indexOf("://") < 0) {
api.show.alert("host:port malformed");
return;
}
if (api.const.SECURE && !api.util.isSecure(host)) {
api.show.alert("host must begin with 'https' on a secure site");
return;
}
localSet('grid-host', host.trim());
localSet('grid-apik', apik.trim());
xhtr.onreadystatechange = function() {
if (xhtr.readyState === 4) {
let status = xhtr.status;
api.stats.add(`ua_${api.mode.get_lower()}_print_grid_${status}`);
if (status >= 200 && status < 300) {
let json = js2o(xhtr.responseText);
gridhost_tracker(host,json.key);
api.ajax(host+"/api/wait?key="+json.key, function(data) {
data = js2o(data);
console.log(data);
api.show.alert("print to "+target+": "+data.status, 600);
});
} else {
api.show.alert("grid:host error\nstatus: "+status+"\nmessage: "+xhtr.responseText, 10000);
}
api.show.progress(0);
}
};
xhtr.upload.addEventListener('progress', function(evt) {
api.show.progress(evt.loaded/evt.total, "sending");
});
filename = $('print-filename').value;
xhtr.open("POST",
host + "/api/print?" +
"filename=" + filename +
"&target=" + target +
"&key=" + apik +
"&time=" + Math.round(info.time) +
"&length=" + Math.round(info.distance) +
"&image=" + filename
);
xhtr.setRequestHeader("Content-Type", "text/plain");
let snapshot = api.view.snapshot;
xhtr.send(snapshot ? [gcode,snapshot].join("\0") : gcode);
api.modal.hide();
}
function download() {
filename = $('print-filename').value;
api.util.download(gcode, filename + "." + fileext);
@ -463,8 +262,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
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;
let preview = set.controller.exportPreview;
$('code-preview-head').style.display = preview ? '' : 'none';
$('code-preview').style.display = preview ? '' : 'none';
@ -484,8 +281,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
// persist fields when changed
bindField('octo-host', 'octo-host');
bindField('octo-apik', 'octo-apik');
bindField('grid-host', 'grid-host');
bindField('grid-apik', 'grid-apik');
// in cam mode, show zip file option
let downloadZip = $('print-zip');
@ -699,37 +494,11 @@ function exportGCodeDialog(gcode, sections, info, names) {
$('ophost').style.display = 'none';
$('opapik').style.display = 'none';
$('oph1nt').style.display = 'none';
$('send-to-gridhost').style.display = 'none';
}
octo_host.value = localGet('octo-host') || '';
octo_apik.value = localGet('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) {
localSet('grid-target', grid_targets[grid_target.selectedIndex]);
};
grid_host.value = localGet('grid-host') || '';
grid_apik.value = localGet('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) }
// preview of the generated GCODE (first 64k max)
if (preview && gcode) $('code-preview-textarea').value = gcode.substring(0,65535);
}

View file

@ -155,8 +155,6 @@ function booleanSave() {
control.reverseZoom = ui.reverseZoom.checked;
control.dark = ui.dark.checked;
control.exportOcto = ui.exportOcto.checked;
control.exportGhost = ui.exportGhost.checked;
control.exportLocal = ui.exportLocal.checked;
control.exportThumb = ui.exportThumb.checked;
control.exportPreview = ui.exportPreview.checked;
control.healMesh = ui.healMesh.checked;
@ -904,7 +902,6 @@ function init_one() {
xany: $('mod-x-any'),
xsla: $('mod-x-sla'),
xlaser: $('mod-x-laser'),
local: $('mod-local'),
don8: $('mod-don8'),
any: $('mod-any'),
},
@ -1058,8 +1055,6 @@ function init_one() {
spaceRandoX: newBoolean(LANG.op_spcx_s, booleanSave, {title:LANG.op_spcx_l, show:isBelt}),
spaceLayout: newInput(LANG.op_spcr_s, {title:LANG.op_spcr_l, convert:toFloat, size:3, units}),
_____: newGroup(LANG.xp_menu, $('prefs-xpo'), {inline: true}),
exportLocal: newBoolean(`Grid:Local`, booleanSave, {title:LANG.op_exgl_l}),
exportGhost: newBoolean(`Grid:Host`, booleanSave, {title:LANG.op_exgh_l}),
exportOcto: newBoolean(`OctoPrint`, booleanSave, {title:LANG.op_exop_l}),
exportThumb: newBoolean(`Thumbnail`, booleanSave, {modes:FDM}),
exportPreview: newBoolean(`Code Preview`, booleanSave),

View file

@ -114,12 +114,6 @@ export const mode = {
}
};
export const probe = {
live: "https://live.grid.space",
grid: noop,
local: noop
};
export const process = {
code: currentProcessCode,
get: currentProcessName
@ -784,43 +778,7 @@ function showHelpFile(local,then) {
}
function showLocal() {
showModal('local');
api.probe.local((err,data) => {
let devc = 0;
let bind = [];
let html = ['<table>'];
html.push(`<thead><tr><th>device</th><th>type</th><th>status</th><th></th></tr></thead>`);
html.push(`<tbody>`);
let recs = [];
for (let k in data) {
recs.push(data[k].stat);
}
recs.sort((a,b) => {
return a.device.name < b.device.name ? -1 : 1;
});
for (let r of recs) {
bind.push({uuid: r.device.uuid, host: r.device.addr[0], port: r.device.port});
html.push(`<tr>`);
html.push(`<td>${r.device.name}</td>`);
html.push(`<td>${r.device.mode}</td>`);
html.push(`<td>${r.state}</td>`);
html.push(`<td><button id="${r.device.uuid}">admin</button></td>`);
html.push(`</tr>`);
devc++;
}
html.push(`</tbody>`);
html.push(`</table>`);
if (devc) {
$('mod-local').innerHTML = html.join('');
} else {
$('mod-local').innerHTML = `<br><b>no local devices</b>`;
}
bind.forEach(rec => {
$(rec.uuid).onclick = () => {
window.open(`http://${rec.host}:${rec.port||4080}/`);
};
});
});
// deprecated
}
function setViewMode(mode) {

View file

@ -129,6 +129,7 @@ class Print {
close = !options.open,
scarf = !poly.open ? (options.scarf ?? 0) : false,
tool = options.tool,
zmax = options.zmax,
last = startPoint,
first = true;

View file

@ -10,7 +10,7 @@ import { Layers } from '../../core/layers.js';
import { Stack } from '../../core/stack.js';
import { updateStock } from './cl-stock.js';
import { createPopOps } from './cl-ops.js';
import { tabAdd, tabDone, tabClear, restoreTabs, rotateTabs, updateTabs, clearTabs } from './cl-tab.js';
import { tabAdd, tabDone, tabClear, restoreTabs, rotateTabs, updateTabs, clearTabs, mirrorTabs } from './cl-tab.js';
import { traceOn, traceDone, unselectTraces } from './cl-trace.js';
import { holeSelOn, selectHolesDone, clearHolesRec } from './cl-hole.js';
import { surfaceOn, surfaceDone } from './cl-surface.js';
@ -320,6 +320,7 @@ export function opRender() {
el.classList.add("disabled");
}
bounds.push(el);
let parent = $('camops');
let timer = null;
let inside = true;
let popped = false;
@ -329,14 +330,14 @@ export function opRender() {
}
el.rec = rec;
el.unpop = () => {
let pos = [...el.childNodes].indexOf(poprec.div);
let pos = [...parent.childNodes].indexOf(poprec.div);
if (pos >= 0) {
el.removeChild(poprec.div);
parent.removeChild(poprec.div);
}
popped = false;
};
function onEnter(ev) {
if ((surfaceOn || traceOn) && env.poppedRec != rec) {
if ((clock || surfaceOn || traceOn) && env.poppedRec != rec) {
return;
}
if (popped && env.poppedRec != rec) {
@ -351,22 +352,24 @@ export function opRender() {
popped = true;
poprec.use(rec);
env.hoveredOp = el;
if (!clock) {
// offset Y position of pop div by % of Y screen location of button
el.appendChild(poprec.div);
poprec.addNote();
const { innerHeight } = window;
const brect = ev.target.getBoundingClientRect();
const prect = poprec.div.getBoundingClientRect();
const pcty = (brect.top / innerHeight) * 0.9;
const offpx = -pcty * prect.height;
poprec.div.style.transform = `translateY(${offpx}px)`;
}
// offset Y position of pop div by % of Y screen location of button
parent.appendChild(poprec.div);
poprec.addNote();
const { innerHeight } = window;
const brect = ev.target.getBoundingClientRect();
const prect = parent.getBoundingClientRect();
const Prect = poprec.div.getBoundingClientRect();
const tdiff = prect.top - brect.top;
const botoff = innerHeight - (brect.top + Prect.height);
const offpx = -tdiff + (botoff < 0 ? botoff : -Prect.height/3);
poprec.div.style.transform = `translateY(${offpx}px)`;
poprec.div.onmouseenter = () => { inside = true };
poprec.div.onmouseleave = onLeave;
// option click event appears latent
// and overides the sticky settings
setTimeout(() => {
UC.setSticky(false);
}, 0);
}, 10);
}
function onLeave(ev) {
inside = false;

View file

@ -4,26 +4,70 @@ import { CamOp } from './op.js';
import { Tool } from './tool.js';
import { generate as Topo } from './topo3.js';
import { newPoint } from '../../../geo/point.js';
import { newPolygon } from '../../../geo/polygon.js';
import { tip2tipEmit } from '../../../geo/paths.js';
function createFilter(op) {
function createFilter(op, origin, axis) {
console.log({ origin, axis });
let ok = () => true;
let filter = slices => slices;
let filterString = op.filter?.map(l => l.trim()).join('\n');
if (filterString) {
try {
const obj = eval(`( ${filterString} )`);
let idx = 0;
if (obj && obj.slices) {
const nadd = [];
filter = function (slices) {
for (let slice of slices) {
if (obj.slices(slice, idx++)) {
nadd.push(slice);
let box = obj?.box;
let slice_fn = obj?.slices;
let index = 0;
const accept = [];
filter = function (slices) {
for (let slice of slices) {
if (slice_fn && slice_fn(slice, index++)) {
accept.push(slice);
} else if (box) {
// slice.z = x when axis = y
// slice.z = y when axis = x
let { x, y, z } = box;
x = x ?? [ -Infinity, Infinity ];
y = y ?? [ -Infinity, Infinity ];
z = z ?? [ -Infinity, Infinity ];
let ok = false;
if (axis === 'x') {
let sy = slice.z + origin.y;
if (sy >= y[0] && sy <= y[1]) {
ok = true;
for (let p of slice.camLines) {
p.points = p.points.filter(p =>
p.x - origin.x >= x[0] && p.x - origin.x <= x[1] &&
p.z - origin.z >= z[0] && p.z - origin.z <= z[1]
);
}
}
} else {
let sx = slice.z - origin.x;
if (sx >= x[0] && sx <= x[1]) {
ok = true;
for (let p of slice.camLines) {
p.points = p.points.filter(p =>
p.y + origin.y >= y[0] && p.y + origin.y <= y[1] &&
p.z - origin.z >= z[0] && p.z - origin.z <= z[1]
);
}
}
}
if (ok) {
slice.camLines = slice.camLines.map(p => {
if (p.points.length > 1) {
return newPolygon(p.points).setOpen(true);
} else {
return undefined;
}
}).filter(p => p);
accept.push(slice);
}
}
return nadd;
};
}
}
return accept;
};
} catch (e) {
console.log('filter parse error', e, op.filter);
}
@ -38,8 +82,8 @@ class OpContour extends CamOp {
async slice(progress) {
let { op, state } = this;
let { addSlices, settings, updateToolDiams } = state;
let filter = createFilter(op);
let { color, addSlices, settings, updateToolDiams } = state;
let filter = createFilter(op, settings.origin, op.axis.toLowerCase());
let toolDiam = this.toolDiam = new Tool(settings, op.tool).fluteDiameter();
updateToolDiams(toolDiam);
// we need topo for safe travel moves when roughing and outlining
@ -54,6 +98,11 @@ class OpContour extends CamOp {
slices = filter(slices);
this.sliceOut = slices;
addSlices(slices);
for (let slice of slices) {
slice.output()
.setLayer(`contour ${op.axis}`, { face: color, line: color })
.addPolys(slice.camLines);
}
},
contour: op,
state: state

View file

@ -6,22 +6,23 @@ import { generate as topo4_generate } from './topo4.js';
import { newPoint } from '../../../geo/point.js';
function createFilter(op) {
let ok = () => true;
let filter = slices => slices;
if (op.filter) {
let filterString = op.filter?.map(l => l.trim()).join('\n');
if (filterString) {
try {
const obj = eval(`( ${op.filter.join('\n')} )`);
let idx = 0;
if (obj && obj.slices) {
const nadd = [];
filter = function (slices) {
for (let slice of slices) {
if (obj.slices(slice, idx++)) {
nadd.push(slice);
}
const obj = eval(`( ${filterString} )`);
const accept = [];
let index = 0;
let sl_fn = obj?.slices ?? ok;
filter = function (slices) {
for (let slice of slices) {
if (sl_fn(slice, index++)) {
accept.push(slice);
}
return nadd;
};
}
}
return accept;
};
} catch (e) {
console.log('filter parse error', e, op.filter);
}
@ -38,7 +39,6 @@ class OpLathe extends CamOp {
let { op, state } = this;
let { addSlices } = state;
let filter = createFilter(op);
this.topo = await topo4_generate({
op,
state,

View file

@ -973,8 +973,8 @@ export function prepEach(widget, settings, print, firstPoint, update) {
let arcPoints = arcToPath(from, to, arcPreviewRes, { clockwise, center })
.map(applyWidgetMovement);
.map(applyWidgetMovement);
// console.log({arcPoints})
camOut(from, 1);

View file

@ -16,7 +16,7 @@ export class Topo {
async generate(opt = {}) {
let { state, contour, onupdate, ondone } = opt;
let { widget, settings, tshadow, center, tabs, color } = opt.state;
let { widget, settings, tshadow, tabs } = opt.state;
let { controller, process } = settings,
animesh = parseInt(controller.animesh || 100) * 2500,
@ -177,8 +177,7 @@ export class Topo {
clipTabZ: clipTab ? clipTab.map(t => t.z) : undefined,
tabHeight,
newslices,
leave,
color
leave
}, (i, l, p) => {
onupdate(l / 2 + i / 2, l, p);
});
@ -304,7 +303,7 @@ export class Topo {
const { minX, maxX, minY, maxY, boundsX, boundsY, stepsX, stepsY } = params;
const { gridDelta, resolution, density, partOff, toolStep, contourX, contourY } = params;
const { clipTo, clipTab, clipTabZ, tabHeight, newslices, color, leave } = params;
const { clipTo, clipTab, clipTabZ, tabHeight, newslices, leave } = params;
let stepsTaken = 0,
stepsTotal = 0;
@ -370,11 +369,8 @@ export class Topo {
gridy
}, segments => {
if (segments.length > 0) {
let slice = newSlice(gridx);
let slice = newSlice(x);
slice.camLines = segments;
slice.output()
.setLayer("contour y", { face: color, line: color })
.addPolys(segments);
slicesY.push(slice);
}
onupdate(++stepsTaken, stepsTotal, "contour y");
@ -399,11 +395,8 @@ export class Topo {
gridy
}, segments => {
if (segments.length > 0) {
let slice = newSlice(gridy);
let slice = newSlice(y);
slice.camLines = segments;
slice.output()
.setLayer("contour x", { face: color, line: color })
.addPolys(segments);
slicesX.push(slice);
}
onupdate(++stepsTaken, stepsTotal, "contour x");

View file

@ -613,6 +613,7 @@ export function fdm_export(print, online, ondone, ondebug) {
for (pidx=0; pidx<path.length; pidx++) {
out = path[pidx];
speedMMM = (out.speed || process.outputFeedrate) * 60; // range
fanSpeed = out.fan ?? fanSpeed;
// hint to controller that we're working on a specific object
// so that gcode between start/stop comments can be cancelled
@ -685,13 +686,13 @@ export function fdm_export(print, online, ondone, ondebug) {
}
// in belt mode, fan can change per segment (for base)
if (isBelt) {
// if (isBelt) {
setTempFanSpeed(out.fan);
if (fanSpeed !== lastFanSpeed) {
appendAllSub(gcodeFan);
lastFanSpeed = fanSpeed;
}
}
// }
if (lastp && out.emit) {
if (arcDist) {

View file

@ -46,8 +46,6 @@ export async function fdm_prepare(widgets, settings, update) {
output = [],
layerout = [];
let lastLayerStart = null;
// compute bounds if missing
if (!bounds) {
bounds = new THREE.Box3();
@ -553,12 +551,9 @@ export async function fdm_prepare(widgets, settings, update) {
offset,
layerout,
{
routeAround: process.outputAvoidGaps,
seedPoint: printPoint.sub(offset),
params, // range parameters
first: slice.index === 0,
support: slice.widget.support,
onBelt: beltStart,
params, // range parameters
pretract: (wipeDist) => {
if (!(lastLayer && lastLayer.length)) {
return;
@ -573,7 +568,11 @@ export async function fdm_prepare(widgets, settings, update) {
print.addOutput(lastLayer, endpoint, null, null, lastOut.tool);
}
}
}
},
routeAround: process.outputAvoidGaps,
seedPoint: printPoint.sub(offset),
support: slice.widget.support,
zmax,
}
);
layerout.print_time = printPoint.layer_time;
@ -815,6 +814,7 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
shellOrder = {"out-in":-1,"in-out":1,"alternate":-2}[process.sliceShellOrder] || -1,
sparseMult = process.outputSparseMult,
coastDist = process.outputCoastDist || 0,
fanSpeed = process.outputFanSpeed,
firstShellSpeed = process.firstLayerRate,
firstFillSpeed = process.firstLayerFillRate,
firstPrintMult = process.firstLayerPrintMult,
@ -823,8 +823,10 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
fillSpeed = opt.speed || opt.fillSpeed || (firstLayer ? firstFillSpeed || firstShellSpeed : process.outputFeedrate),
infillSpeed = process.sliceFillRate || opt.infillSpeed || fillSpeed || printSpeed,
moveSpeed = process.outputSeekrate,
minSpeed = process.outputMinSpeed,
origin = startPoint.add(offset),
zhop = process.zHopDistance || 0,
zmax = opt.zmax,
antiBacklash = process.antiBacklash,
wipeDist = process.outputRetractWipe || 0,
isBelt = device.bedBelt,
@ -862,6 +864,7 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
// override: adapt bridge layer speed
if (slice.isBridgeLayer) {
fillSpeed /= 2;
printSpeed /= 2;
}
// apply first layer extrusion multipliers
@ -1100,9 +1103,6 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
coast: firstLayer ? 0 : coastDist,
extrude: numOrDefault(opt.extrude, shellMult),
nozzleSize,
rate: finishShell ? finishSpeed : printSpeed,
scarf,
tool: extruder,
onfirst: (firstPoint, preout) => {
let from = seedPoint || startPoint;
if (from.distTo2D(firstPoint) > retractDist) {
@ -1111,7 +1111,11 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
}
}
seedPoint = null;
}
},
rate: finishShell ? finishSpeed : printSpeed,
scarf,
tool: extruder,
zmax
});
lastPoly = slice.lastPoly = poly;
}
@ -1600,7 +1604,7 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
if (minLayerTime && tt < minLayerTime) {
let fact = tt / minLayerTime;
for (let p of preout) {
if (p.emit) p.speed *= fact;
if (p.emit) p.speed = Math.max(p.speed * fact, minSpeed);
}
}
@ -1612,6 +1616,12 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
// add offset points to total print
print.addPrintPoints(preout, output);
// bridge layer fan change
if (slice.isBridgeLayer) {
preout[0].fan = Math.round(fanSpeed / 3);
preout.peek().fan = fanSpeed;
}
// create next layer start point and annotate
// with print time for previous layer (hack to
// avoid changing return signature rn)

View file

@ -20,6 +20,7 @@ function safeExec(fn) {
function checkReady() {
if (document.readyState === 'complete') {
console.log(`kiri | boot ctrl | ` + (navigator.serviceWorker.controller ? true : false));
kiri.api = run();
self.$ = kiri.api.web.$;
for (let fn of load) {

View file

@ -11,8 +11,9 @@ async function start_service_worker() {
debug('service worker registration');
try {
// const reg = await navigator.serviceWorker.register("/src/moto/service.js?013", { scope: "/" });
const reg = await navigator.serviceWorker.register("/code/service.js?"+version, { scope: "/" });
const reg = await navigator
.serviceWorker
.register(`/code/service.js?${version}`, { scope: "/" });
if (reg.installing) {
debug('service worker installing');
} else if (reg.waiting) {
@ -31,4 +32,6 @@ async function start_service_worker() {
}
}
if (service_worker && self.enable_service) start_service_worker();
if (service_worker && self.enable_service) {
start_service_worker();
}

View file

@ -3,7 +3,7 @@
const terms = {
COPYRIGHT: "Copyright (C) Stewart Allen <sa@grid.space> - All Rights Reserved",
LICENSE: "See the license.md file included with the source distribution",
VERSION: "4.3.2"
VERSION: "4.3.3"
};
export const beta = 0;

View file

@ -1375,10 +1375,16 @@ details[open] summary::after {
}
#camops {
display: flex;
padding: 5px 0 0 0;
padding: 0 0 0 0;
}
#oplist {
max-height: 70vh;
min-height: 0;
overflow-y: auto;
padding-top: 1px;
}
.cam-pop-op {
top: 50%;
top: 0;
right: calc(100% + 4px);
text-align: left;
position: absolute;

View file

@ -420,7 +420,7 @@
<div class="set2-group f-col mode-cam">
<div class="set-header mode-cam"><a>operation list</a></div>
<div id="camops" class="f-col a-stretch grow">
<div id="oplist" class="f-col j-center"></div>
<div id="oplist" class="f-col"></div>
<div id="op-add" class="opdiv">
<i class="fas fa-plus"></i>
<div id="op-add-pop" class="f-col">
@ -612,8 +612,6 @@
</div>
</div>
<!-- grid local list -->
<div id="mod-local" class="mdialog f-col"></div>
<!-- export dialogs -->
<div id="mod-x-any" class="mod-print mdialog f-col">
<div class="f-row gap4">
@ -667,31 +665,6 @@
</div>
<div id="oph1nt"><label class="hint"><a href="http://docs.octoprint.org/en/master/api/general.html?highlight=cors#cross-origin-requests" target="_help">CORS support</a> must be enabled in API settings</label></div>
</div>
<div id="send-to-hosthead" class="header"><label>grid:host</label></div>
<div id="send-to-gridhost" class="f-col box">
<div class="grow f-row">
<div class="f-col grow">
<div><label>host</label><input id="grid-host" size="20" placeholder="http(s)://host:port" /></div>
<div id="gpapik"><label>api key</label><input id="grid-apik" size="20" /></div>
<div><label>target</label><select id="grid-target"></select></div>
</div>
<button id="print-gridhost">send</button>
</div>
<div><label class="hint">setup <a href="https://github.com/GridSpace/grid-host" target="_help">grid:host</a> for your network</label></div>
</div>
<div id="send-to-gridhead" class="header noshow"><label>grid:local</label></div>
<div id="send-to-gridspool" class="f-row box noshow">
<div class="grow f-row">
<div class="grow a-center j-center">
<label>target</label>
<select id="grid-local"></select>
</div>
<div class="f-col">
<button id="print-gridlocal">send</button>
<button id="admin-gridlocal">admin</button>
</div>
</div>
</div>
</div>
<div id="mod-x-sla" class="mod-print mdialog f-col">
<div class="header"><label>export</label></div>

View file

@ -1,5 +1,5 @@
{
"name": "Kiri:Moto 4.3.2",
"name": "Kiri:Moto 4.3.3",
"short_name": "Kiri:Moto",
"description": "Slicer for 3D printers, CNC mills, laser cutters and more",
"start_url": "/kiri/",