update code style, use gapp.register() for cam driver

This commit is contained in:
Stewart Allen 2022-02-21 10:01:19 -05:00
commit 836d53aad5
10 changed files with 4881 additions and 4862 deletions

View file

@ -2,12 +2,15 @@
"use strict"; "use strict";
self.kiri.load(function() { // dep: kiri.api
// dep: kiri-mode.cam.driver
gapp.register("kiri-mode.cam.animate", [], (root, exports) => {
let KIRI = self.kiri, const { kiri } = root;
CAM = KIRI.driver.CAM, const { api, driver } = kiri;
API, WORLD, SPACE, const { CAM } = driver;
meshes = {},
let meshes = {},
unitScale = 1, unitScale = 1,
progress, toolPosX, toolPosY, toolPosZ, progress, toolPosX, toolPosY, toolPosZ,
speedValues = [ 25, 12, 6, 3 ], speedValues = [ 25, 12, 6, 3 ],
@ -21,30 +24,31 @@ self.kiri.load(function() {
playButton, playButton,
posOffset = { x:0, y:0, z:0 }; posOffset = { x:0, y:0, z:0 };
// ---( CLIENT FUNCTIONS )--- // ---( CLIENT FUNCTIONS )---
if (KIRI.client) kiri.load(() => {
CAM.animate_clear = function(api) { if (!kiri.client) {
API = api; return;
KIRI.client.animate_cleanup(); }
SPACE = KIRI.space;
WORLD = SPACE.world; const { moto } = root;
const { space } = moto;
const { world } = space;
function animate_clear(api) {
kiri.client.animate_cleanup();
$('layer-animate').innerHTML = ''; $('layer-animate').innerHTML = '';
$('layer-toolpos').innerHTML = ''; $('layer-toolpos').innerHTML = '';
Object.keys(meshes).forEach(id => deleteMesh(id)); Object.keys(meshes).forEach(id => deleteMesh(id));
} }
if (KIRI.client) function animate(api, delay) {
CAM.animate = function(api, delay) { kiri.client.animate_setup(api.conf.get(), data => {
API = api;
SPACE = KIRI.space;
WORLD = SPACE.world;
KIRI.client.animate_setup(API.conf.get(), data => {
checkMeshCommands(data); checkMeshCommands(data);
if (!(data && data.mesh_add)) { if (!(data && data.mesh_add)) {
return; return;
} }
const UC = API.uc; const UC = api.uc;
const layer = $('layer-animate'); const layer = $('layer-animate');
layer.innerHTML = ''; layer.innerHTML = '';
UC.setGroup(layer); UC.setGroup(layer);
@ -70,9 +74,109 @@ self.kiri.load(function() {
toolPosZ = UC.newInput('z', {disabled: true, size: 7}); toolPosZ = UC.newInput('z', {disabled: true, size: 7});
playButton.style.display = ''; playButton.style.display = '';
pauseButton.style.display = 'none'; pauseButton.style.display = 'none';
API.event.emit('animate', 'CAM'); api.event.emit('animate', 'CAM');
}); });
}; }
gapp.overlay(kiri.client, {
animate(data, ondone) {
kiri.client.send("animate", data, ondone);
},
animate_setup(settings, ondone) {
color = settings.controller.dark ? 0x888888 : 0;
unitScale = settings.controller.units === 'in' ? 1/25.4 : 1;
kiri.client.send("animate_setup", {settings}, ondone);
},
animate_cleanup(data, ondone) {
kiri.client.send("animate_cleanup", data, ondone);
}
});
gapp.overlay(CAM, {
animate,
animate_clear
});
function meshAdd(id, ind, pos) {
const geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.BufferAttribute(pos, 3));
geo.setIndex(new THREE.BufferAttribute(new Uint32Array(ind), 1));
const mat = new THREE.LineBasicMaterial({
transparent: true,
opacity: 0.75,
color
});
const mesh = new THREE.LineSegments(geo, mat);
world.add(mesh);
meshes[id] = mesh;
}
function meshUpdates(id, updates) {
const mesh = meshes[id];
if (!mesh) {
return; // animate cancelled
}
const mpos = mesh.geometry.attributes.position;
for (let i=0, il=updates.length; i<il; ) {
const pos = updates[i++];
const val = updates[i++];
mpos.array[pos] = val;
}
mpos.needsUpdate = true;
space.update();
}
function deleteMesh(id) {
world.remove(meshes[id]);
delete meshes[id];
}
function step(opts) {
const { steps } = opts;
updateSpeed();
kiri.client.animate({speed, steps: 1}, handleGridUpdate);
}
function play(opts) {
const { steps } = opts;
updateSpeed();
if (steps !== 1) {
playButton.style.display = 'none';
pauseButton.style.display = '';
}
kiri.client.animate({speed, steps: steps || Infinity}, handleGridUpdate);
}
function fast(opts) {
const { steps } = opts;
updateSpeed(1);
playButton.style.display = 'none';
pauseButton.style.display = '';
kiri.client.animate({speed, steps: steps || Infinity}, handleGridUpdate);
}
function pause() {
playButton.style.display = '';
pauseButton.style.display = 'none';
kiri.client.animate({speed: 0}, handleGridUpdate);
}
function skip() {
api.show.alert('fast fowarding without animation');
playButton.style.display = 'none';
pauseButton.style.display = '';
updateSpeed(Infinity);
kiri.client.animate({speed, steps: Infinity, toend: true}, handleGridUpdate);
}
function handleGridUpdate(data) {
checkMeshCommands(data);
if (data && data.progress) {
progress.value = (data.progress * 100).toFixed(1)
}
}
function updateSpeed(inc = 0) { function updateSpeed(inc = 0) {
if (inc === Infinity) { if (inc === Infinity) {
@ -85,9 +189,9 @@ self.kiri.load(function() {
} }
function replay() { function replay() {
CAM.animate_clear(API); CAM.animate_clear(api);
setTimeout(() => { setTimeout(() => {
CAM.animate(API, 50); CAM.animate(api, 50);
}, 250); }, 250);
} }
@ -112,7 +216,7 @@ self.kiri.load(function() {
mesh.position.x = pos.x; mesh.position.x = pos.x;
mesh.position.y = pos.y; mesh.position.y = pos.y;
mesh.position.z = pos.z; mesh.position.z = pos.z;
SPACE.update(); space.update();
if (id !== 0) { if (id !== 0) {
toolPosX.value = ((pos.x + posOffset.x) * unitScale).toFixed(2); toolPosX.value = ((pos.x + posOffset.x) * unitScale).toFixed(2);
toolPosY.value = ((pos.y + posOffset.y) * unitScale).toFixed(2); toolPosY.value = ((pos.y + posOffset.y) * unitScale).toFixed(2);
@ -125,109 +229,19 @@ self.kiri.load(function() {
} }
} }
function meshAdd(id, ind, pos) { });
const geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.BufferAttribute(pos, 3));
geo.setIndex(new THREE.BufferAttribute(new Uint32Array(ind), 1));
const mat = new THREE.LineBasicMaterial({
transparent: true,
opacity: 0.75,
color
});
const mesh = new THREE.LineSegments(geo, mat);
WORLD.add(mesh);
meshes[id] = mesh;
}
function meshUpdates(id, updates) { // ---( WORKER FUNCTIONS )---
const mesh = meshes[id];
if (!mesh) {
return; // animate cancelled
}
const mpos = mesh.geometry.attributes.position;
for (let i=0, il=updates.length; i<il; ) {
const pos = updates[i++];
const val = updates[i++];
mpos.array[pos] = val;
}
mpos.needsUpdate = true;
SPACE.update();
}
function deleteMesh(id) { kiri.load(() => {
WORLD.remove(meshes[id]); if (!kiri.worker) {
delete meshes[id]; return;
} }
function step(opts) {
const { steps } = opts;
updateSpeed();
KIRI.client.animate({speed, steps: 1}, handleGridUpdate);
}
function play(opts) {
const { steps } = opts;
updateSpeed();
if (steps !== 1) {
playButton.style.display = 'none';
pauseButton.style.display = '';
}
KIRI.client.animate({speed, steps: steps || Infinity}, handleGridUpdate);
}
function fast(opts) {
const { steps } = opts;
updateSpeed(1);
playButton.style.display = 'none';
pauseButton.style.display = '';
KIRI.client.animate({speed, steps: steps || Infinity}, handleGridUpdate);
}
function pause() {
playButton.style.display = '';
pauseButton.style.display = 'none';
KIRI.client.animate({speed: 0}, handleGridUpdate);
}
function skip() {
API.show.alert('fast fowarding without animation');
playButton.style.display = 'none';
pauseButton.style.display = '';
updateSpeed(Infinity);
KIRI.client.animate({speed, steps: Infinity, toend: true}, handleGridUpdate);
}
function handleGridUpdate(data) {
checkMeshCommands(data);
if (data && data.progress) {
progress.value = (data.progress * 100).toFixed(1)
}
}
if (KIRI.client)
KIRI.client.animate_setup = function(settings, ondone) {
color = settings.controller.dark ? 0x888888 : 0;
unitScale = settings.controller.units === 'in' ? 1/25.4 : 1;
KIRI.client.send("animate_setup", {settings}, ondone);
};
if (KIRI.client)
KIRI.client.animate = function(data, ondone) {
KIRI.client.send("animate", data, ondone);
};
if (KIRI.client)
KIRI.client.animate_cleanup = function(data, ondone) {
KIRI.client.send("animate_cleanup", data, ondone);
};
// ---( WORKER FUNCTIONS )---
let stock, center, grid, gridX, gridY, rez; let stock, center, grid, gridX, gridY, rez;
let path, pathIndex, tool, tools, last, toolID = 1; let path, pathIndex, tool, tools, last, toolID = 1;
if (KIRI.worker) kiri.worker.animate_setup = function(data, send) {
KIRI.worker.animate_setup = function(data, send) {
const { settings } = data; const { settings } = data;
const { process } = settings; const { process } = settings;
const print = current.print; const print = current.print;
@ -267,6 +281,31 @@ self.kiri.load(function() {
send.done(); send.done();
}; };
kiri.worker.animate = function(data, send) {
if (data.speed >= 0) {
renderSpeed = data.speed;
}
if (data.steps > 0) {
stepsRemain = data.steps;
}
if (data.toend) {
skipMode = !skipMode;
} else {
skipMode = false;
}
checkStash(send);
if (animating) {
return send.done();
}
renderPath(send);
};
kiri.worker.animate_cleanup = function(data, send) {
if (animating) {
animateClear = true;
}
};
function createGrid(stepsX, stepsY, size, step) { function createGrid(stepsX, stepsY, size, step) {
const gridPoints = stepsX * stepsY; const gridPoints = stepsX * stepsY;
const pos = new Float32Array(gridPoints * 3); const pos = new Float32Array(gridPoints * 3);
@ -300,33 +339,6 @@ self.kiri.load(function() {
return { pos, ind }; return { pos, ind };
} }
if (KIRI.worker)
KIRI.worker.animate = function(data, send) {
if (data.speed >= 0) {
renderSpeed = data.speed;
}
if (data.steps > 0) {
stepsRemain = data.steps;
}
if (data.toend) {
skipMode = !skipMode;
} else {
skipMode = false;
}
checkStash(send);
if (animating) {
return send.done();
}
renderPath(send);
};
if (KIRI.worker)
KIRI.worker.animate_cleanup = function(data, send) {
if (animating) {
animateClear = true;
}
};
let animateClear = false; let animateClear = false;
let animating = false; let animating = false;
let renderSpeed = 25; let renderSpeed = 25;
@ -510,7 +522,7 @@ self.kiri.load(function() {
} }
// load renderer code in worker context only // load renderer code in worker context only
if (KIRI.worker && false) if (kiri.worker && false)
fetch('/wasm/kiri-ani.wasm') fetch('/wasm/kiri-ani.wasm')
.then(response => response.arrayBuffer()) .then(response => response.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, { .then(bytes => WebAssembly.instantiate(bytes, {
@ -535,3 +547,5 @@ self.kiri.load(function() {
}); });
}); });
});

View file

@ -2,14 +2,14 @@
"use strict"; "use strict";
(function() { gapp.register("kiri-mode.cam.client", [], (root, exports) => {
let KIRI = self.kiri, const { base, kiri } = root;
BASE = self.base, const { newPoint, newPolygon } = base;
CAM = KIRI.driver.CAM, const { driver } = kiri;
PRO = CAM.process, const { CAM } = driver;
newPolygon = BASE.newPolygon,
newPoint = BASE.newPoint, let PRO = CAM.process,
isAnimate, isAnimate,
isArrange, isArrange,
isCamMode, isCamMode,
@ -20,7 +20,7 @@
hoveredOp, hoveredOp,
API, FDM, SPACE, STACKS, MODES, VIEWS, UI, UC, LANG; API, FDM, SPACE, STACKS, MODES, VIEWS, UI, UC, LANG;
let zaxis = { x: 0, y: 0, z: 1 }, let zaxis = { x: 0, y: 0, z: 1 },
popOp = {}, popOp = {},
func = { func = {
hover: noop, hover: noop,
@ -28,10 +28,10 @@
}, },
flipping; flipping;
CAM.restoreTabs = restoreTabs; CAM.restoreTabs = restoreTabs;
CAM.init = function(kiri, api) { CAM.init = function(kiri, api) {
FDM = KIRI.driver.FDM; FDM = kiri.driver.FDM;
// console.log({kiri,api}) // console.log({kiri,api})
SPACE = kiri.space; SPACE = kiri.space;
@ -563,8 +563,8 @@
CAM.traces((ids) => { CAM.traces((ids) => {
api.hide.alert(alert); api.hide.alert(alert);
alert = api.show.alert("[esc] cancels trace editing"); alert = api.show.alert("[esc] cancels trace editing");
KIRI.api.widgets.opacity(0.8); kiri.api.widgets.opacity(0.8);
KIRI.api.widgets.for(widget => { kiri.api.widgets.for(widget => {
if (ids.indexOf(widget.id) >= 0) { if (ids.indexOf(widget.id) >= 0) {
unselectTraces(widget, true); unselectTraces(widget, true);
widget.trace_stack = null; widget.trace_stack = null;
@ -575,11 +575,11 @@
return; return;
} }
let areas = (poppedRec.areas[widget.id] || []); let areas = (poppedRec.areas[widget.id] || []);
let stack = new KIRI.Stack(widget.mesh); let stack = new kiri.Stack(widget.mesh);
widget.trace_stack = stack; widget.trace_stack = stack;
widget.traces.forEach(poly => { widget.traces.forEach(poly => {
let match = areas.filter(arr => poly.matches(arr)); let match = areas.filter(arr => poly.matches(arr));
let layers = new KIRI.Layers(); let layers = new kiri.Layers();
layers.setLayer("trace", {line: 0xaaaa55}, false).addPoly(poly); layers.setLayer("trace", {line: 0xaaaa55}, false).addPoly(poly);
stack.addLayers(layers); stack.addLayers(layers);
stack.new_meshes.forEach(mesh => { stack.new_meshes.forEach(mesh => {
@ -595,7 +595,7 @@
}); });
}); });
// ensure appropriate traces are toggled matching current record // ensure appropriate traces are toggled matching current record
KIRI.api.widgets.for(widget => { kiri.api.widgets.for(widget => {
let areas = (poppedRec.areas[widget.id] || []); let areas = (poppedRec.areas[widget.id] || []);
let stack = widget.trace_stack; let stack = widget.trace_stack;
stack.meshes.forEach(mesh => { stack.meshes.forEach(mesh => {
@ -623,11 +623,11 @@
func.unpop(); func.unpop();
traceOn.classList.remove("editing"); traceOn.classList.remove("editing");
traceOn = false; traceOn = false;
KIRI.api.widgets.opacity(1); kiri.api.widgets.opacity(1);
api.hide.alert(alert); api.hide.alert(alert);
api.feature.hover = false; api.feature.hover = false;
api.feature.hoverAdds = false; api.feature.hoverAdds = false;
KIRI.api.widgets.for(widget => { kiri.api.widgets.for(widget => {
if (widget.trace_stack) { if (widget.trace_stack) {
widget.trace_stack.hide(); widget.trace_stack.hide();
widget.adds.removeAll(widget.trace_stack.meshes); widget.adds.removeAll(widget.trace_stack.meshes);
@ -1020,9 +1020,9 @@
UC.newButton(LANG.cc_flip, func.opFlip) UC.newButton(LANG.cc_flip, func.opFlip)
], {class:"ext-buttons f-row"}) ], {class:"ext-buttons f-row"})
}; };
}; };
function createPopOp(type, map) { function createPopOp(type, map) {
let op = popOp[type] = { let op = popOp[type] = {
div: UC.newElement('div', { id:`${type}-op`, class:"cam-pop-op" }), div: UC.newElement('div', { id:`${type}-op`, class:"cam-pop-op" }),
use: (rec) => { use: (rec) => {
@ -1076,9 +1076,9 @@
lastGroup: op.group lastGroup: op.group
}); });
return op; return op;
} }
function createTabBox(iw, ic, n) { function createTabBox(iw, ic, n) {
const { track } = iw; const { track } = iw;
const { stock, bounds, process } = API.conf.get(); const { stock, bounds, process } = API.conf.get();
const { camTabsWidth, camTabsHeight, camTabsDepth, camTabsMidline } = process; const { camTabsWidth, camTabsHeight, camTabsDepth, camTabsMidline } = process;
@ -1093,9 +1093,9 @@
const dim = { x:camTabsDepth, y:camTabsWidth, z:camTabsHeight }; const dim = { x:camTabsDepth, y:camTabsWidth, z:camTabsHeight };
const tab = addbox(pos, 0x0000dd, 'tabb', dim, { rotate: rot }); const tab = addbox(pos, 0x0000dd, 'tabb', dim, { rotate: rot });
return { pos, dim, rot, tab, width: camTabsWidth, height: camTabsHeight }; return { pos, dim, rot, tab, width: camTabsWidth, height: camTabsHeight };
} }
function addWidgetTab(widget, rec) { function addWidgetTab(widget, rec) {
const { pos, dim, rot, id } = rec; const { pos, dim, rot, id } = rec;
const tabs = widget.tabs = (widget.tabs || {}); const tabs = widget.tabs = (widget.tabs || {});
// prevent duplicate restore from repeated settings load calls // prevent duplicate restore from repeated settings load calls
@ -1108,9 +1108,9 @@
widget.adds.push(pos.box); widget.adds.push(pos.box);
tabs[id] = pos; tabs[id] = pos;
} }
} }
function restoreTabs(widgets) { function restoreTabs(widgets) {
widgets.forEach(widget => { widgets.forEach(widget => {
const tabs = API.widgets.annotate(widget.id).tab || []; const tabs = API.widgets.annotate(widget.id).tab || [];
tabs.forEach(rec => { tabs.forEach(rec => {
@ -1119,9 +1119,9 @@
addWidgetTab(widget, rec); addWidgetTab(widget, rec);
}); });
}); });
} }
function clearTabs(widget, skiprec) { function clearTabs(widget, skiprec) {
Object.values(widget.tabs || {}).forEach(rec => { Object.values(widget.tabs || {}).forEach(rec => {
widget.adds.remove(rec.box); widget.adds.remove(rec.box);
widget.mesh.remove(rec.box); widget.mesh.remove(rec.box);
@ -1130,9 +1130,9 @@
if (!skiprec) { if (!skiprec) {
delete API.widgets.annotate(widget.id).tab; delete API.widgets.annotate(widget.id).tab;
} }
} }
function unselectTraces(widget, skip) { function unselectTraces(widget, skip) {
if (widget.trace_stack) { if (widget.trace_stack) {
widget.trace_stack.meshes.forEach(mesh => { widget.trace_stack.meshes.forEach(mesh => {
if (mesh.selected) { if (mesh.selected) {
@ -1140,20 +1140,20 @@
} }
}); });
} }
} }
function addbox() { return FDM.addbox(...arguments)}; function addbox() { return FDM.addbox(...arguments)};
function delbox() { return FDM.delbox(...arguments)}; function delbox() { return FDM.delbox(...arguments)};
function animate() { function animate() {
isAnimate = true; isAnimate = true;
API.widgets.opacity(isParsed ? 0 : 0.75); API.widgets.opacity(isParsed ? 0 : 0.75);
API.hide.slider(); API.hide.slider();
STACKS.clear(); STACKS.clear();
CAM.animate(API); CAM.animate(API);
} }
function updateStock(args, event) { function updateStock(args, event) {
if (isAnimate) { if (isAnimate) {
return; return;
} }
@ -1254,7 +1254,7 @@
const {x, y, z} = stock; const {x, y, z} = stock;
if (x && y && z && !STACKS.getStack('bounds')) { if (x && y && z && !STACKS.getStack('bounds')) {
const render = new KIRI.Layers().setLayer('bounds', { face: 0xaaaaaa, line: 0xaaaaaa }); const render = new kiri.Layers().setLayer('bounds', { face: 0xaaaaaa, line: 0xaaaaaa });
const stack = STACKS.setFreeMem(false).create('bounds', SPACE.world); const stack = STACKS.setFreeMem(false).create('bounds', SPACE.world);
stack.add(render.addPolys([ stack.add(render.addPolys([
newPolygon().centerRectangle({x:csox, y:csoy, z:0}, x, y), newPolygon().centerRectangle({x:csox, y:csoy, z:0}, x, y),
@ -1274,6 +1274,6 @@
API.platform.update_top_z(delta); API.platform.update_top_z(delta);
API.platform.update_origin(); API.platform.update_origin();
SPACE.update(); SPACE.update();
} }
})(); });

View file

@ -2,16 +2,17 @@
"use strict"; "use strict";
(function() { // dep: main.kiri
// use: kiri.api
// use: kiri.widgets
gapp.register("kiri-mode.cam.driver", [], (root, exports) => {
const KIRI = self.kiri, const { kiri } = root;
CAM = KIRI.driver.CAM = { const { driver } = kiri;
// init, // src/mode/cam/client.js
// slice, // src/mode/cam/slice.js const CAM = driver.CAM = {};
// prepare, // src/mode/cam/prepare.js
// export // src/mode/cam/export.js CAM.process = {
},
CPRO = CAM.process = {
LEVEL: 1, LEVEL: 1,
ROUGH: 2, ROUGH: 2,
OUTLINE: 3, OUTLINE: 3,
@ -19,19 +20,19 @@
CONTOUR_Y: 5, CONTOUR_Y: 5,
TRACE: 6, TRACE: 6,
DRILL: 7 DRILL: 7
}; };
// defer loading until KIRI.client and KIRI.worker exist // defer loading until kiri.client and kiri.worker exist
KIRI.load(function(API) { kiri.load(api => {
if (KIRI.client) if (kiri.client)
CAM.traces = function(ondone, single) { CAM.traces = function(ondone, single) {
KIRI.client.sync(); kiri.client.sync();
let settings = API.conf.get(); const settings = api.conf.get();
let widgets = API.widgets.map(); const widgets = api.widgets.map();
KIRI.client.send("cam_traces", { settings, single }, output => { kiri.client.send("cam_traces", { settings, single }, output => {
let ids = []; const ids = [];
KIRI.codec.decode(output).forEach(rec => { kiri.codec.decode(output).forEach(rec => {
ids.push(rec.id); ids.push(rec.id);
widgets[rec.id].traces = rec.traces; widgets[rec.id].traces = rec.traces;
}); });
@ -39,17 +40,17 @@
}); });
}; };
if (KIRI.worker) if (kiri.worker)
KIRI.worker.cam_traces = function(data, send) { kiri.worker.cam_traces = function(data, send) {
const { settings, single } = data; const { settings, single } = data;
const widgets = Object.values(wcache); const widgets = Object.values(wcache);
const fresh = widgets.filter(widget => CAM.traces(settings, widget, single)); const fresh = widgets.filter(widget => CAM.traces(settings, widget, single));
send.done(KIRI.codec.encode(fresh.map(widget => { return { send.done(kiri.codec.encode(fresh.map(widget => { return {
id: widget.id, id: widget.id,
traces: widget.traces, traces: widget.traces,
} } ))); } } )));
}; };
}); });
})(); });

View file

@ -2,22 +2,28 @@
"use strict"; "use strict";
(function() { // dep: geo.base
// dep: geo.polygons
gapp.register("kiri-mode.cam.export", [], (root, exports) => {
let KIRI = self.kiri, const { base, kiri } = root;
BASE = self.base, const { polygons, util } = base;
POLY = BASE.polygons, const { driver } = kiri;
UTIL = BASE.util, const { CAM } = driver;
CAM = KIRI.driver.CAM,
PRO = CAM.process;
/** const POLY = polygons;
const PRO = CAM.process;
/**
* @returns {Array} gcode lines * @returns {Array} gcode lines
*/ */
CAM.export = function(print, online) { CAM.export = function(print, online) {
let widget = print.widgets[0]; const widget = print.widgets[0];
if (!widget) return; if (!widget) return;
const { settings } = print;
const { device, tools } = settings;
let i, let i,
time = 0, time = 0,
lines = 0, lines = 0,
@ -26,22 +32,18 @@
factor = 1, factor = 1,
output = [], output = [],
spindle = 0, spindle = 0,
settings = print.settings,
device = settings.device,
gcodes = settings.device || {},
origin = settings.origin || { x: 0, y: 0, z: 0 }, origin = settings.origin || { x: 0, y: 0, z: 0 },
tools = settings.tools, space = device.gcodeSpace ? ' ' : '',
space = gcodes.gcodeSpace ? ' ' : '',
isRML = device.gcodeFExt.toLowerCase() === 'rml', isRML = device.gcodeFExt.toLowerCase() === 'rml',
stripComments = gcodes.gcodeStrip || false, stripComments = device.gcodeStrip || false,
cmdToolChange = gcodes.gcodeChange || [ "M6 T{tool}" ], cmdToolChange = device.gcodeChange || [ "M6 T{tool}" ],
cmdSpindle = gcodes.gcodeSpindle || [ "M3 S{speed}" ], cmdSpindle = device.gcodeSpindle || [ "M3 S{speed}" ],
cmdDwell = gcodes.gcodeDwell || [ "G4 P{time}" ], cmdDwell = device.gcodeDwell || [ "G4 P{time}" ],
dev = settings.device, dev = settings.device,
spro = settings.process, spro = settings.process,
maxZd = spro.camFastFeedZ, maxZd = spro.camFastFeedZ,
maxXYd = spro.camFastFeed, maxXYd = spro.camFastFeed,
decimals = BASE.config.gcode_decimals || 4, decimals = base.config.gcode_decimals || 4,
pos = { x:null, y:null, z:null, f:null, t:null }, pos = { x:null, y:null, z:null, f:null, t:null },
line, line,
cidx, cidx,
@ -149,9 +151,9 @@
return; return;
} }
newpos.x = UTIL.round(newpos.x, decimals); newpos.x = util.round(newpos.x, decimals);
newpos.y = UTIL.round(newpos.y, decimals); newpos.y = util.round(newpos.y, decimals);
newpos.z = UTIL.round(newpos.z, decimals); newpos.z = util.round(newpos.z, decimals);
// on tool change // on tool change
if (out.tool != pos.t) { if (out.tool != pos.t) {
@ -241,7 +243,7 @@
section('header'); section('header');
if (!stripComments) { if (!stripComments) {
append(`; Generated by Kiri:Moto ${KIRI.version}`); append(`; Generated by Kiri:Moto ${kiri.version}`);
append(`; ${new Date().toString()}`); append(`; ${new Date().toString()}`);
filterEmit(["; Bed left:{left} right:{right} top:{top} bottom:{bottom}"], consts); filterEmit(["; Bed left:{left} right:{right} top:{top} bottom:{bottom}"], consts);
if (hasStock) { if (hasStock) {
@ -290,7 +292,7 @@
} }
// emit gcode preamble // emit gcode preamble
filterEmit(gcodes.gcodePre, consts); filterEmit(device.gcodePre, consts);
// emit all points in layer/point order // emit all points in layer/point order
print.output.forEach(function (layerout) { print.output.forEach(function (layerout) {
@ -320,7 +322,7 @@
// emit gcode post // emit gcode post
section('footer'); section('footer');
filterEmit(gcodes.gcodePost, consts); filterEmit(device.gcodePost, consts);
// flush buffered gcode // flush buffered gcode
append(); append();
@ -329,6 +331,6 @@
print.lines = lines; print.lines = lines;
print.bytes = bytes + lines - 1; print.bytes = bytes + lines - 1;
print.bounds = runbox; print.bounds = runbox;
}; };
})(); });

View file

@ -2,19 +2,22 @@
"use strict"; "use strict";
(function() { // dep: geo.base
// dep: geo.paths
// dep: geo.point
// dep: geo.polygons
// dep: kiri.slice
gapp.register("kiri-mode.cam.ops", [], (root, exports) => {
let KIRI = self.kiri, const { base, kiri } = root;
BASE = self.base, const { paths, polygons, newPoint, newPolygon } = base;
UTIL = BASE.util, const { poly2polyEmit, tip2tipEmit } = paths;
CAM = KIRI.driver.CAM, const { driver, newSlice } = kiri;
PRO = CAM.process, const { CAM } = driver;
POLY = BASE.polygons,
newSlice = KIRI.newSlice,
newPoint = BASE.newPoint,
newPolygon = BASE.newPolygon;
class CamOp { const POLY = polygons;
class CamOp {
constructor(state, op) { constructor(state, op) {
this.state = state; this.state = state;
this.op = op this.op = op
@ -31,9 +34,9 @@
slice() { } slice() { }
prepare() { } prepare() { }
} }
class OpLevel extends CamOp { class OpLevel extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -95,9 +98,9 @@
polyEmit(lines[0]); polyEmit(lines[0]);
newLayer(); newLayer();
} }
} }
class OpRough extends CamOp { class OpRough extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -320,7 +323,7 @@
prepare(ops, progress) { prepare(ops, progress) {
let { op, state, sliceOut, camFaces } = this; let { op, state, sliceOut, camFaces } = this;
let { setTool, setSpindle, setPrintPoint } = ops; let { setTool, setSpindle, setPrintPoint } = ops;
let { polyEmit, poly2polyEmit, depthRoughPath } = ops; let { polyEmit, depthRoughPath } = ops;
let { camOut, newLayer, printPoint } = ops; let { camOut, newLayer, printPoint } = ops;
let { settings, widget } = state; let { settings, widget } = state;
let { process, controller } = settings; let { process, controller } = settings;
@ -403,9 +406,9 @@
setPrintPoint(printPoint); setPrintPoint(printPoint);
} }
} }
class OpOutline extends CamOp { class OpOutline extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -467,7 +470,7 @@
// extend cut thru (only when z bottom is 0) // extend cut thru (only when z bottom is 0)
if (zThru) { if (zThru) {
let last = slices[slices.length-1]; let last = slices[slices.length-1];
for (let zneg of BASE.util.lerp(0, zThru, op.down)) { for (let zneg of base.util.lerp(0, zThru, op.down)) {
let add = last.clone(true); let add = last.clone(true);
add.tops.forEach(top => top.poly.setZ(add.z)); add.tops.forEach(top => top.poly.setZ(add.z));
add.shadow = last.shadow.clone(true); add.shadow = last.shadow.clone(true);
@ -566,7 +569,7 @@
prepare(ops, progress) { prepare(ops, progress) {
let { op, state, sliceOut } = this; let { op, state, sliceOut } = this;
let { setTool, setSpindle, setPrintPoint } = ops; let { setTool, setSpindle, setPrintPoint } = ops;
let { polyEmit, poly2polyEmit, depthOutlinePath } = ops; let { polyEmit, depthOutlinePath } = ops;
let { camOut, newLayer, printPoint } = ops; let { camOut, newLayer, printPoint } = ops;
let { settings, widget } = state; let { settings, widget } = state;
let { process, controller } = settings; let { process, controller } = settings;
@ -630,9 +633,9 @@
setPrintPoint(printPoint); setPrintPoint(printPoint);
} }
} }
class OpContour extends CamOp { class OpContour extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -662,7 +665,7 @@
prepare(ops, progress) { prepare(ops, progress) {
let { op, state, sliceOut } = this; let { op, state, sliceOut } = this;
let { setTolerance, setTool, setSpindle, setPrintPoint } = ops; let { setTolerance, setTool, setSpindle, setPrintPoint } = ops;
let { polyEmit, poly2polyEmit, tip2tipEmit } = ops; let { polyEmit } = ops;
let { camOut, newLayer, printPoint, lastPoint } = ops; let { camOut, newLayer, printPoint, lastPoint } = ops;
let { bounds, zmax } = ops; let { bounds, zmax } = ops;
let { settings, widget } = state; let { settings, widget } = state;
@ -719,9 +722,9 @@
setPrintPoint(printPoint); setPrintPoint(printPoint);
} }
} }
class OpTrace extends CamOp { class OpTrace extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -732,7 +735,6 @@
let { settings, widget, sliceAll, zMax, zTop, zThru, tabs } = state; let { settings, widget, sliceAll, zMax, zTop, zThru, tabs } = state;
let { updateToolDiams, cutTabs, cutPolys, healPolys } = state; let { updateToolDiams, cutTabs, cutPolys, healPolys } = state;
let { process, stock } = settings; let { process, stock } = settings;
let poly2polyEmit = BASE.util.poly2polyEmit;
// generate tracing offsets from chosen features // generate tracing offsets from chosen features
let sliceOut = this.sliceOut = []; let sliceOut = this.sliceOut = [];
let areas = op.areas[widget.id] || []; let areas = op.areas[widget.id] || [];
@ -776,7 +778,7 @@
.addPolys(slice.camLines) .addPolys(slice.camLines)
} }
function clearZ(polys, z, down) { function clearZ(polys, z, down) {
let zs = down ? BASE.util.lerp(zTop, z, down) : [ z ]; let zs = down ? base.util.lerp(zTop, z, down) : [ z ];
let nested = POLY.nest(polys); let nested = POLY.nest(polys);
for (let poly of nested) { for (let poly of nested) {
for (let z of zs) { for (let z of zs) {
@ -881,7 +883,7 @@
if (zThru && similar(zto,0)) { if (zThru && similar(zto,0)) {
zto -= zThru; zto -= zThru;
} }
for (let z of BASE.util.lerp(zTop, zto, down)) { for (let z of base.util.lerp(zTop, zto, down)) {
followZ(pi.clone().setZ(z)); followZ(pi.clone().setZ(z));
} }
} else { } else {
@ -912,9 +914,9 @@
ops.emitTrace(slice); ops.emitTrace(slice);
} }
} }
} }
class OpDrill extends CamOp { class OpDrill extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -1002,9 +1004,9 @@
setSpindle(op.spindle); setSpindle(op.spindle);
emitDrills(this.sliceOut.map(slice => slice.camLines).flat()); emitDrills(this.sliceOut.map(slice => slice.camLines).flat());
} }
} }
class OpRegister extends CamOp { class OpRegister extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -1089,7 +1091,7 @@
tv = -tv; tv = -tv;
} }
} }
for (let z of BASE.util.lerp(z1, z2, op.down)) { for (let z of base.util.lerp(z1, z2, op.down)) {
let slice = newSlice(z); let slice = newSlice(z);
sliceAll.push(slice); sliceAll.push(slice);
sliceOut.push(slice); sliceOut.push(slice);
@ -1154,16 +1156,16 @@
emitDrills(this.sliceOut.map(slice => slice.camLines).flat()); emitDrills(this.sliceOut.map(slice => slice.camLines).flat());
} }
} }
} }
class OpXRay extends CamOp { class OpXRay extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
slice(progress) { slice(progress) {
let { widget, sliceAll } = this.state; let { widget, sliceAll } = this.state;
let slicer = new KIRI.cam_slicer(widget.getPoints(), { let slicer = new kiri.cam_slicer(widget.getPoints(), {
zlist: true, zlist: true,
zline: true zline: true
}); });
@ -1182,9 +1184,9 @@
// xrayopt.over = true; // xrayopt.over = true;
// slicer.slice(xrayind, xrayopt); // slicer.slice(xrayind, xrayopt);
} }
} }
class OpShadow extends CamOp { class OpShadow extends CamOp {
constructor(state, op) { constructor(state, op) {
super(state, op); super(state, op);
} }
@ -1257,9 +1259,9 @@
// identify through holes // identify through holes
state.thruHoles = tshadow.map(p => p.inner || []).flat(); state.thruHoles = tshadow.map(p => p.inner || []).flat();
} }
} }
CAM.shadowAt = function(widget, z, ztop) { CAM.shadowAt = function(widget, z, ztop) {
let geo = widget.cache.geo || new THREE.BufferGeometry() let geo = widget.cache.geo || new THREE.BufferGeometry()
.setAttribute('position', new THREE.BufferAttribute(widget.vertices, 3)); .setAttribute('position', new THREE.BufferAttribute(widget.vertices, 3));
widget.cache.geo = geo; widget.cache.geo = geo;
@ -1329,9 +1331,9 @@
.add(a[2].x,a[2].y,a[2].z); .add(a[2].x,a[2].y,a[2].z);
}); });
return POLY.union(polys, 0.0001, true); return POLY.union(polys, 0.0001, true);
}; };
CAM.OPS = CamOp.MAP = { CAM.OPS = CamOp.MAP = {
"xray": OpXRay, "xray": OpXRay,
"shadow": OpShadow, "shadow": OpShadow,
"level": OpLevel, "level": OpLevel,
@ -1342,6 +1344,6 @@
"drill": OpDrill, "drill": OpDrill,
"register": OpRegister, "register": OpRegister,
"flip": CamOp "flip": CamOp
}; };
})(); });

View file

@ -2,17 +2,20 @@
"use strict"; "use strict";
(function() { // dep: geo.paths
// dep: geo.point
// dep: geo.polygons
gapp.register("kiri-mode.cam.prepare", [], (root, exports) => {
let KIRI = self.kiri, const { base, kiri } = root;
BASE = self.base, const { paths, polygons, newPoint } = base;
POLY = BASE.polygons, const { tip2tipEmit, poly2polyEmit } = paths;
PATH = BASE.paths, const { driver } = kiri;
CAM = KIRI.driver.CAM, const { CAM } = driver;
{ newPoint } = BASE,
{ tip2tipEmit, poly2polyEmit } = PATH;
/** const POLY = polygons;
/**
* DRIVER PRINT CONTRACT * DRIVER PRINT CONTRACT
* *
* @param {Object} print state object * @param {Object} print state object
@ -20,12 +23,12 @@
* @param {Number} [index] into widget array * @param {Number} [index] into widget array
* @param {Object} [firstPoint] starting point * @param {Object} [firstPoint] starting point
*/ */
CAM.prepare = function(widgets, settings, update) { CAM.prepare = function(widgets, settings, update) {
widgets = widgets.filter(w => !w.track.ignore && !w.meta.disabled); widgets = widgets.filter(w => !w.track.ignore && !w.meta.disabled);
const count = widgets.length; const count = widgets.length;
const weight = 1/count; const weight = 1/count;
const print = self.worker.print = KIRI.newPrint(settings, widgets); const print = self.worker.print = kiri.newPrint(settings, widgets);
print.output = []; print.output = [];
let point; let point;
@ -35,7 +38,7 @@
}); });
}); });
print.render = KIRI.driver.FDM.prepareRender(print.output, (progress, layer) => { print.render = kiri.driver.FDM.prepareRender(print.output, (progress, layer) => {
update(0.75 + progress * 0.25, "render", layer); update(0.75 + progress * 0.25, "render", layer);
}, { }, {
thin: true, thin: true,
@ -49,9 +52,9 @@
}); });
return print.render; return print.render;
}; };
function prepEach(widget, settings, print, firstPoint, update) { function prepEach(widget, settings, print, firstPoint, update) {
if (widget.camops.length === 0 || widget.meta.disabled) return; if (widget.camops.length === 0 || widget.meta.disabled) return;
@ -502,12 +505,12 @@
// replace output single flattened layer with all points // replace output single flattened layer with all points
print.output = newOutput; print.output = newOutput;
return printPoint; return printPoint;
}; };
/** /**
* return tool Z clearance height for a line segment movement path * return tool Z clearance height for a line segment movement path
*/ */
function getZClearPath(terrain, x1, y1, x2, y2, z, zadd, off, over) { function getZClearPath(terrain, x1, y1, x2, y2, z, zadd, off, over) {
// when terrain skipped, top + pass used // when terrain skipped, top + pass used
if (terrain > 0) { if (terrain > 0) {
return terrain; return terrain;
@ -549,6 +552,6 @@
} }
} }
return maxz; return maxz;
} }
})(); });

View file

@ -2,27 +2,28 @@
"use strict"; "use strict";
(function() { // dep: geo.point
// dep: geo.polygons
// dep: kiri.slice
gapp.register("kiri-mode.cam.slice", [], (root, exports) => {
let KIRI = self.kiri, const { base, kiri } = root;
BASE = self.base, const { driver, newSlice } = kiri;
UTIL = BASE.util, const { polygons, newPoint, newPolygon } = base;
CAM = KIRI.driver.CAM, const { CAM } = driver;
OPS = CAM.OPS, const { OPS } = CAM;
PRO = CAM.process,
POLY = BASE.polygons,
newSlice = KIRI.newSlice,
newPoint = BASE.newPoint,
newPolygon = BASE.newPolygon;
/** const PRO = CAM.process;
const POLY = polygons;
/**
* DRIVER SLICE CONTRACT * DRIVER SLICE CONTRACT
* *
* @param {Object} settings * @param {Object} settings
* @param {Widget} widget * @param {Widget} widget
* @param {Function} output * @param {Function} output
*/ */
CAM.slice = function(settings, widget, onupdate, ondone) { CAM.slice = function(settings, widget, onupdate, ondone) {
let mesh = widget.mesh, let mesh = widget.mesh,
proc = settings.process, proc = settings.process,
stock = settings.stock || {}, stock = settings.stock || {},
@ -93,7 +94,7 @@
} }
let mark = Date.now(); let mark = Date.now();
let slicer = new KIRI.cam_slicer(widget.getPoints(), { let slicer = new kiri.cam_slicer(widget.getPoints(), {
zlist: true, zlist: true,
zline: true zline: true
}); });
@ -189,9 +190,9 @@
widget.maxToolDiam = maxToolDiam; widget.maxToolDiam = maxToolDiam;
ondone(); ondone();
}; };
CAM.addDogbones = function(poly, dist, reverse) { CAM.addDogbones = function(poly, dist, reverse) {
if (Array.isArray(poly)) { if (Array.isArray(poly)) {
return poly.forEach(p => CAM.addDogbones(p, dist)); return poly.forEach(p => CAM.addDogbones(p, dist));
} }
@ -208,11 +209,11 @@
let adiff = lastsl.angleDiff(nextsl, true); let adiff = lastsl.angleDiff(nextsl, true);
let bdiff = ((adiff < 0 ? (180 - adiff) : (180 + adiff)) / 2) + 180; let bdiff = ((adiff < 0 ? (180 - adiff) : (180 + adiff)) / 2) + 180;
if (isCW && adiff > 45) { if (isCW && adiff > 45) {
let newa = BASE.newSlopeFromAngle(lastsl.angle + bdiff); let newa = base.newSlopeFromAngle(lastsl.angle + bdiff);
newpts.push(lastpt.projectOnSlope(newa, dist)); newpts.push(lastpt.projectOnSlope(newa, dist));
newpts.push(lastpt.clone()); newpts.push(lastpt.clone());
} else if (!isCW && adiff < -45) { } else if (!isCW && adiff < -45) {
let newa = BASE.newSlopeFromAngle(lastsl.angle - bdiff); let newa = base.newSlopeFromAngle(lastsl.angle - bdiff);
newpts.push(lastpt.projectOnSlope(newa, dist)); newpts.push(lastpt.projectOnSlope(newa, dist));
newpts.push(lastpt.clone()); newpts.push(lastpt.clone());
} }
@ -226,14 +227,14 @@
if (poly.inner) { if (poly.inner) {
CAM.addDogbones(poly.inner, dist, true); CAM.addDogbones(poly.inner, dist, true);
} }
}; };
CAM.traces = function(settings, widget, single) { CAM.traces = function(settings, widget, single) {
if (widget.traces && widget.trace_single === single) { if (widget.traces && widget.trace_single === single) {
// do no work if cached // do no work if cached
return false; return false;
} }
let slicer = new KIRI.cam_slicer(widget.getPoints(), { let slicer = new kiri.cam_slicer(widget.getPoints(), {
zlist: true, zlist: true,
zline: true zline: true
}); });
@ -256,7 +257,7 @@
} }
} }
} else } else
BASE.polygons.flatten(data.tops,null,true).forEach(poly => { base.polygons.flatten(data.tops,null,true).forEach(poly => {
poly.inner = null; poly.inner = null;
poly.parent = null; poly.parent = null;
let z = poly.getZ(); let z = poly.getZ();
@ -281,20 +282,20 @@
widget.traces = traces; widget.traces = traces;
widget.trace_single = single; widget.trace_single = single;
return true; return true;
}; };
function cutTabs(tabs, offset, z, inter) { function cutTabs(tabs, offset, z, inter) {
tabs = tabs.filter(tab => z < tab.pos.z + tab.dim.z/2).map(tab => tab.off).flat(); tabs = tabs.filter(tab => z < tab.pos.z + tab.dim.z/2).map(tab => tab.off).flat();
return cutPolys(tabs, offset, z, false); return cutPolys(tabs, offset, z, false);
} }
function cutPolys(polys, offset, z, inter) { function cutPolys(polys, offset, z, inter) {
let noff = []; let noff = [];
offset.forEach(op => noff.appendAll( op.cut(POLY.union(polys, 0, true), inter) )); offset.forEach(op => noff.appendAll( op.cut(POLY.union(polys, 0, true), inter) ));
return healPolys(noff); return healPolys(noff);
} }
function healPolys(noff) { function healPolys(noff) {
if (noff.length > 1) { if (noff.length > 1) {
let heal = 0; let heal = 0;
// heal/rejoin open segments that share endpoints // heal/rejoin open segments that share endpoints
@ -350,6 +351,6 @@
} }
} }
return noff; return noff;
} }
})(); });

View file

@ -5,17 +5,15 @@
/** /**
* Slicing engine used by CAM * Slicing engine used by CAM
*/ */
(function() { gapp.register("kiri-mode.cam.slicer", [], (root, exports) => {
let KIRI = self.kiri, const { base, kiri } = root;
BASE = self.base, const { config, util, polygons, newOrderedLine } = base;
CONF = BASE.config, const { newSlice } = kiri;
UTIL = BASE.util,
POLY = BASE.polygons,
newSlice = KIRI.newSlice,
newOrderedLine = BASE.newOrderedLine;
class Slicer { const POLY = polygons;
class Slicer {
constructor(points, options) { constructor(points, options) {
this.options = {}; this.options = {};
if (points) { if (points) {
@ -92,7 +90,7 @@
if (p1.z === p2.z && p2.z === p3.z) { if (p1.z === p2.z && p2.z === p3.z) {
// detect zFlat faces to avoid slicing directly on them // detect zFlat faces to avoid slicing directly on them
let zkey = p1.z.toFixed(5), let zkey = p1.z.toFixed(5),
area = Math.abs(UTIL.area2(p1,p2,p3)) / 2; area = Math.abs(util.area2(p1,p2,p3)) / 2;
if (!zFlat[zkey]) { if (!zFlat[zkey]) {
zFlat[zkey] = area; zFlat[zkey] = area;
} else { } else {
@ -165,7 +163,7 @@
// if Z is supplied as an array, iterate and collect // if Z is supplied as an array, iterate and collect
if (Array.isArray(z)) { if (Array.isArray(z)) {
const mark = UTIL.time(); const mark = util.time();
const rarr = []; const rarr = [];
z.forEach((zv,zi) => { z.forEach((zv,zi) => {
const data = this.slice(zv, opt, zi, z.length, mark); const data = this.slice(zv, opt, zi, z.length, mark);
@ -177,7 +175,7 @@
} }
let znorm = z.toFixed(5), let znorm = z.toFixed(5),
flatoff = UTIL.numOrDefault(opt.flatoff, 0.01), flatoff = util.numOrDefault(opt.flatoff, 0.01),
onflat = this.zFlat[znorm], onflat = this.zFlat[znorm],
edges = opt.edges || false, edges = opt.edges || false,
over = opt.over || false, over = opt.over || false,
@ -258,7 +256,7 @@
const hastops = !opt.genso || opt.notopok || (retn.tops && retn.tops.length) || edges; const hastops = !opt.genso || opt.notopok || (retn.tops && retn.tops.length) || edges;
if (opt.each && haslines && hastops) { if (opt.each && haslines && hastops) {
opt.each(retn, index, total, UTIL.time() - mark); opt.each(retn, index, total, util.time() - mark);
} }
return haslines && hastops ? retn : null; return haslines && hastops ? retn : null;
@ -399,9 +397,9 @@
array = array.map(v => v.round(5)).filter((e,i,a) => i < 1 || a[i-1] !== a[i]); array = array.map(v => v.round(5)).filter((e,i,a) => i < 1 || a[i-1] !== a[i]);
return array.map(v => Math.abs(parseFloat(v.toFixed(5)))); return array.map(v => Math.abs(parseFloat(v.toFixed(5))));
} }
} }
/** /**
* given a point, append to the correct * given a point, append to the correct
* 'where' objec tarray (on, over or under) * 'where' objec tarray (on, over or under)
* *
@ -409,18 +407,18 @@
* @param {number} z offset * @param {number} z offset
* @param {Obejct} where * @param {Obejct} where
*/ */
function checkOverUnderOn(p, z, where) { function checkOverUnderOn(p, z, where) {
let delta = p.z - z; let delta = p.z - z;
if (Math.abs(delta) < CONF.precision_slice_z) { // on if (Math.abs(delta) < config.precision_slice_z) { // on
where.on.push(p); where.on.push(p);
} else if (delta < 0) { // under } else if (delta < 0) { // under
where.under.push(p); where.under.push(p);
} else { // over } else { // over
where.over.push(p); where.over.push(p);
} }
} }
/** /**
* Given a point over and under a z offset, calculate * Given a point over and under a z offset, calculate
* and return the intersection point on that z plane * and return the intersection point on that z plane
* *
@ -429,7 +427,7 @@
* @param {number} z offset * @param {number} z offset
* @returns {Point} intersection point * @returns {Point} intersection point
*/ */
function intersectPoints(over, under, z) { function intersectPoints(over, under, z) {
let ip = []; let ip = [];
for (let i = 0; i < over.length; i++) { for (let i = 0; i < over.length; i++) {
for (let j = 0; j < under.length; j++) { for (let j = 0; j < under.length; j++) {
@ -437,21 +435,21 @@
} }
} }
return ip; return ip;
} }
/** /**
* Ensure points are unique with a cache/key algorithm * Ensure points are unique with a cache/key algorithm
*/ */
function getCachedPoint(phash, p) { function getCachedPoint(phash, p) {
let cached = phash[p.key]; let cached = phash[p.key];
if (!cached) { if (!cached) {
phash[p.key] = p; phash[p.key] = p;
return p; return p;
} }
return cached; return cached;
} }
/** /**
* Given two points and hints about their edges, * Given two points and hints about their edges,
* return a new Line object with points sorted * return a new Line object with points sorted
* lexicographically by key. This allows for future * lexicographically by key. This allows for future
@ -464,16 +462,16 @@
* @param {boolean} [edge] * @param {boolean} [edge]
* @returns {Line} * @returns {Line}
*/ */
function makeZLine(phash, p1, p2, coplanar, edge) { function makeZLine(phash, p1, p2, coplanar, edge) {
p1 = getCachedPoint(phash, p1); p1 = getCachedPoint(phash, p1);
p2 = getCachedPoint(phash, p2); p2 = getCachedPoint(phash, p2);
let line = newOrderedLine(p1,p2); let line = newOrderedLine(p1,p2);
line.coplanar = coplanar || false; line.coplanar = coplanar || false;
line.edge = edge || false; line.edge = edge || false;
return line; return line;
} }
/** /**
* Given an array of input lines (line soup), find the path through * Given an array of input lines (line soup), find the path through
* joining line ends that encompasses the greatest area without self * joining line ends that encompasses the greatest area without self
* interesection. Eliminate used points and repeat. Unjoined lines * interesection. Eliminate used points and repeat. Unjoined lines
@ -483,16 +481,16 @@
* @param {number} [index] * @param {number} [index]
* @returns {Array} * @returns {Array}
*/ */
function connectLines(input, opt = {}, debug) { function connectLines(input, opt = {}, debug) {
// map points to all other points they're connected to // map points to all other points they're connected to
let CONF = BASE.config, let config = base.config,
pmap = {}, pmap = {},
points = [], points = [],
output = [], output = [],
connect = [], connect = [],
search = 1, search = 1,
nextMod = 1, nextMod = 1,
bridge = CONF.bridgeLineGapDistance, bridge = config.bridgeLineGapDistance,
minPoly = opt.openok ? 2 : 3, minPoly = opt.openok ? 2 : 3,
p1, p2; p1, p2;
@ -611,7 +609,7 @@
// it gets more complicated with multiple possible output paths // it gets more complicated with multiple possible output paths
if (closed > 1 && open === 0) { if (closed > 1 && open === 0) {
// add polygon to path (for area sorting) // add polygon to path (for area sorting)
paths.forEach(function(path) { path.poly = BASE.newPolygon().addPoints(path) }); paths.forEach(function(path) { path.poly = base.newPolygon().addPoints(path) });
// sort descending by area VS (length below -- better in most cases) // sort descending by area VS (length below -- better in most cases)
// paths.sort(function(a,b) { return b.poly.area() - a.poly.area() }); // paths.sort(function(a,b) { return b.poly.area() - a.poly.area() });
@ -633,7 +631,7 @@
if (longest.open) { if (longest.open) {
connect.push(longest); connect.push(longest);
} else { } else {
emit(BASE.newPolygon().addPoints(longest)); emit(base.newPolygon().addPoints(longest));
} }
} }
} }
@ -685,7 +683,7 @@
if (!bridge) { if (!bridge) {
if (opt.openok) { if (opt.openok) {
emit(BASE.newPolygon().addPoints(array).setOpen()); emit(base.newPolygon().addPoints(array).setOpen());
} }
continue; continue;
} }
@ -722,15 +720,15 @@
merged++; merged++;
// tail meets head (closed) // tail meets head (closed)
if (close(array[0], last)) { if (close(array[0], last)) {
emit(BASE.newPolygon().addPoints(array)); emit(base.newPolygon().addPoints(array));
break loop; break loop;
} }
} else { } else {
// no more closest polys (open set) // no more closest polys (open set)
if (opt.openok) { if (opt.openok) {
emit(BASE.newPolygon().addPoints(array).setOpen()); emit(base.newPolygon().addPoints(array).setOpen());
} else { } else {
emit(BASE.newPolygon().addPoints(array)); emit(base.newPolygon().addPoints(array));
} }
break loop; break loop;
} }
@ -738,9 +736,9 @@
} }
return output; return output;
} }
/** /**
* eliminate duplicate lines and interior-only lines (coplanar) * eliminate duplicate lines and interior-only lines (coplanar)
* *
* lines are sorted using lexicographic point keys such that * lines are sorted using lexicographic point keys such that
@ -751,7 +749,7 @@
* @param {Line[]} lines * @param {Line[]} lines
* @returns {Line[]} * @returns {Line[]}
*/ */
function removeDuplicateLines(lines, debug) { function removeDuplicateLines(lines, debug) {
let output = [], let output = [],
tmplines = [], tmplines = [],
points = [], points = [],
@ -804,7 +802,7 @@
// find new endpoints that are not shared point // find new endpoints that are not shared point
let p1 = l1.p1 != point ? l1.p1 : l1.p2, let p1 = l1.p1 != point ? l1.p1 : l1.p2,
p2 = l2.p1 != point ? l2.p1 : l2.p2, p2 = l2.p1 != point ? l2.p1 : l2.p2,
newline = BASE.newOrderedLine(p1,p2); newline = base.newOrderedLine(p1,p2);
// remove deleted lines from associated points // remove deleted lines from associated points
p1.group.remove(l1); p1.group.remove(l1);
p1.group.remove(l2); p1.group.remove(l2);
@ -840,11 +838,11 @@
}); });
return output; return output;
} }
Slicer.checkOverUnderOn = checkOverUnderOn; Slicer.checkOverUnderOn = checkOverUnderOn;
Slicer.intersectPoints = intersectPoints; Slicer.intersectPoints = intersectPoints;
self.kiri.cam_slicer = Slicer; kiri.cam_slicer = Slicer;
})(); });

View file

@ -2,15 +2,15 @@
"use strict"; "use strict";
(function() { gapp.register("kiri-mode.cam.tools", [], (root, exports) => {
let KIRI = self.kiri, const { kiri } = root;
BASE = self.base, const { driver } = kiri;
UTIL = BASE.util, const { CAM } = driver;
HPI = Math.PI/2,
CAM = KIRI.driver.CAM;
class Tool { const HPI = Math.PI/2;
class Tool {
constructor(settings, id, number) { constructor(settings, id, number) {
if (number >= 0) { if (number >= 0) {
this.tool = settings.tools.filter(tool => tool.number == number)[0]; this.tool = settings.tools.filter(tool => tool.number == number)[0];
@ -125,11 +125,12 @@
}; };
return this; return this;
} }
} }
CAM.Tool = Tool; CAM.Tool = Tool;
CAM.getToolDiameter = function(settings, id) {
CAM.getToolDiameter = function(settings, id) {
return new CAM.Tool(settings, id).fluteDiameter(); return new CAM.Tool(settings, id).fluteDiameter();
}; };
})(); });

View file

@ -2,21 +2,18 @@
"use strict"; "use strict";
(function() { gapp.register("kiri-mode.cam.tools", [], (root, exports) => {
let KIRI = self.kiri, const { base, kiri } = root;
BASE = self.base, const { driver, newSlice } = kiri;
CAM = KIRI.driver.CAM, const { CAM } = driver;
PRO = CAM.process, const { polygons, newLine, newSlope, newPoint, newPolygon } = base;
POLY = BASE.polygons,
RAD2DEG = 180 / Math.PI,
newSlice = KIRI.newSlice,
newLine = BASE.newLine,
newSlope = BASE.newSlope,
newPoint = BASE.newPoint,
newPolygon = BASE.newPolygon;
class Topo { const PRO = CAM.process;
const POLY = polygons;
const RAD2DEG = 180 / Math.PI;
class Topo {
constructor(opt = {}) { constructor(opt = {}) {
let { state, contour, onupdate, ondone } = opt; let { state, contour, onupdate, ondone } = opt;
let { widget, settings, tshadow, center, tabs, color } = opt.state; let { widget, settings, tshadow, center, tabs, color } = opt.state;
@ -384,7 +381,7 @@
ondone(newslices); ondone(newslices);
} }
let slicer = new KIRI.cam_slicer(widget.getPoints(), { let slicer = new kiri.cam_slicer(widget.getPoints(), {
swapX: true, emptyok: true, notopok: true swapX: true, emptyok: true, notopok: true
}); });
let sindex = slicer.interval(resolution); let sindex = slicer.interval(resolution);
@ -398,8 +395,8 @@
processSlices(slices.filter(s => s.lines).map(data => data.slice)); processSlices(slices.filter(s => s.lines).map(data => data.slice));
} }
} }
CAM.Topo = Topo; CAM.Topo = Topo;
})(); });