generalize path renderer
This commit is contained in:
parent
64a61a177f
commit
0de4445256
5 changed files with 381 additions and 358 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
// dep: geo.paths
|
// dep: geo.paths
|
||||||
// dep: geo.point
|
// dep: geo.point
|
||||||
// dep: geo.polygons
|
// dep: geo.polygons
|
||||||
|
// dep: kiri.render
|
||||||
// dep: kiri-mode.cam.driver
|
// dep: kiri-mode.cam.driver
|
||||||
// use: kiri-mode.cam.ops
|
// use: kiri-mode.cam.ops
|
||||||
gapp.register("kiri-mode.cam.prepare", [], (root, exports) => {
|
gapp.register("kiri-mode.cam.prepare", [], (root, exports) => {
|
||||||
|
|
@ -12,7 +13,7 @@ gapp.register("kiri-mode.cam.prepare", [], (root, exports) => {
|
||||||
const { base, kiri } = root;
|
const { base, kiri } = root;
|
||||||
const { paths, polygons, newPoint } = base;
|
const { paths, polygons, newPoint } = base;
|
||||||
const { tip2tipEmit, poly2polyEmit } = paths;
|
const { tip2tipEmit, poly2polyEmit } = paths;
|
||||||
const { driver } = kiri;
|
const { driver, render } = kiri;
|
||||||
const { CAM } = driver;
|
const { CAM } = driver;
|
||||||
|
|
||||||
const POLY = polygons;
|
const POLY = polygons;
|
||||||
|
|
@ -40,7 +41,7 @@ CAM.prepare = function(widgets, settings, update) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
print.render = kiri.driver.FDM.prepareRender(print.output, (progress, layer) => {
|
print.render = render.path(print.output, (progress, layer) => {
|
||||||
update(0.75 + progress * 0.25, "render", layer);
|
update(0.75 + progress * 0.25, "render", layer);
|
||||||
}, {
|
}, {
|
||||||
thin: true,
|
thin: true,
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,12 @@
|
||||||
// dep: kiri.utils
|
// dep: kiri.utils
|
||||||
// dep: kiri.slice
|
// dep: kiri.slice
|
||||||
// dep: kiri.consts
|
// dep: kiri.consts
|
||||||
|
// dep: kiri.render
|
||||||
// dep: kiri-mode.fdm.driver
|
// dep: kiri-mode.fdm.driver
|
||||||
gapp.register("kiri-mode.fdm.prepare", [], (root, exports) => {
|
gapp.register("kiri-mode.fdm.prepare", [], (root, exports) => {
|
||||||
|
|
||||||
const { base, kiri, noop } = root;
|
const { base, kiri, noop } = root;
|
||||||
const { consts, driver, newSlice, utils } = kiri;
|
const { consts, driver, newSlice, utils, render } = kiri;
|
||||||
const { config, polygons, paths, util, newPoint, newPolygon, Polygon } = base;
|
const { config, polygons, paths, util, newPoint, newPolygon, Polygon } = base;
|
||||||
const { poly2polyEmit, tip2tipEmit } = paths;
|
const { poly2polyEmit, tip2tipEmit } = paths;
|
||||||
const { numOrDefault } = util;
|
const { numOrDefault } = util;
|
||||||
|
|
@ -760,7 +761,7 @@ FDM.prepare = function(widgets, settings, update) {
|
||||||
|
|
||||||
// render if not explicitly disabled
|
// render if not explicitly disabled
|
||||||
if (settings.render !== false) {
|
if (settings.render !== false) {
|
||||||
print.render = FDM.prepareRender(output, (progress, layer) => {
|
print.render = render.path(output, (progress, layer) => {
|
||||||
update(0.5 + progress * 0.5, "render", layer);
|
update(0.5 + progress * 0.5, "render", layer);
|
||||||
}, {
|
}, {
|
||||||
toolMode: settings.pmode === 2,
|
toolMode: settings.pmode === 2,
|
||||||
|
|
@ -1416,354 +1417,4 @@ function slicePrintPath(print, slice, startPoint, offset, output, opt = {}) {
|
||||||
return startPoint.add(offset);
|
return startPoint.add(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
FDM.isDark = function() {
|
|
||||||
return worker.print.settings.controller.dark ? true : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
FDM.rateToColor = function(rate, max) {
|
|
||||||
return FDM.isDark() ?
|
|
||||||
darkColorFunction(rate/max, 1, 0.85) :
|
|
||||||
currentColorFunction(rate/max, 1, 0.85);
|
|
||||||
};
|
|
||||||
|
|
||||||
FDM.prepareRender = function(levels, update, opts = {}) {
|
|
||||||
levels = levels.filter(level => level.length);
|
|
||||||
if (levels.length === 0) {
|
|
||||||
self.worker.print.maxSpeed = 0;
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const dark = FDM.isDark();
|
|
||||||
const tools = opts.tools || {};
|
|
||||||
const flat = opts.flat;
|
|
||||||
const thin = opts.thin && !flat;
|
|
||||||
const ckspeed = opts.speed !== false;
|
|
||||||
const headColor = 0x888888;
|
|
||||||
const moveColor = opts.move >= 0 ? opts.move : 0xaaaaaa;
|
|
||||||
const printColor = opts.print >= 0 ? opts.print : 0x777700;
|
|
||||||
const arrowAll = true;
|
|
||||||
const arrowSize = arrowAll ? 0.2 : 0.4;
|
|
||||||
const layers = [];
|
|
||||||
const toolMode = opts.toolMode;
|
|
||||||
|
|
||||||
const moveOpt = {
|
|
||||||
face: moveColor,
|
|
||||||
line: flat ? 1 : moveColor,
|
|
||||||
opacity: flat ? 0.5 : 1
|
|
||||||
};
|
|
||||||
const printOpt = {
|
|
||||||
face: printColor,
|
|
||||||
line: flat ? 1 : printColor,
|
|
||||||
opacity: flat ? 0.5 : 1
|
|
||||||
};
|
|
||||||
|
|
||||||
let minspd = Infinity;
|
|
||||||
let maxspd = opts.maxspeed || 0;
|
|
||||||
let maxtool = [];
|
|
||||||
|
|
||||||
for (let level of levels) {
|
|
||||||
for (let o of level) {
|
|
||||||
if (o.speed) {
|
|
||||||
minspd = Math.min(minspd, o.speed);
|
|
||||||
maxspd = Math.max(maxspd, o.speed);
|
|
||||||
}
|
|
||||||
if (toolMode && o.tool !== undefined) {
|
|
||||||
if (maxtool.indexOf(o.tool) < 0) {
|
|
||||||
maxtool.push(o.tool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// const maxspd = levels.map(level => {
|
|
||||||
// return level.map(o => o.speed || 0).reduce((a, v) => Math.max(a,v));
|
|
||||||
// }).reduce((a, v) => Math.max(a, v)) + 1;
|
|
||||||
|
|
||||||
// for reporting
|
|
||||||
self.worker.print.minSpeed = minspd;
|
|
||||||
self.worker.print.maxSpeed = maxspd;
|
|
||||||
self.worker.print.thinColor = thin;
|
|
||||||
self.worker.print.flatColor = flat;
|
|
||||||
|
|
||||||
let lastTool = null;
|
|
||||||
let lastEnd = null;
|
|
||||||
let lastOut = null;
|
|
||||||
let current = null;
|
|
||||||
let retracted = false;
|
|
||||||
let retractz = 0;
|
|
||||||
|
|
||||||
function color(point) {
|
|
||||||
if (toolMode) {
|
|
||||||
return FDM.rateToColor(maxtool.indexOf(point.tool), maxtool.length);
|
|
||||||
} else {
|
|
||||||
return FDM.rateToColor(point.speed, maxspd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
levels.forEach((level, index) => {
|
|
||||||
const prints = {};
|
|
||||||
const moves = [];
|
|
||||||
const heads = [];
|
|
||||||
const changes = [];
|
|
||||||
const retracts = [];
|
|
||||||
const engages = [];
|
|
||||||
const output = new kiri.Layers();
|
|
||||||
layers.push(output);
|
|
||||||
|
|
||||||
const pushPrint = (toolid, poly) => {
|
|
||||||
toolid = toolid || 0;
|
|
||||||
const array = prints[toolid] = prints[toolid] || [];
|
|
||||||
const tool = tools[toolid] || {};
|
|
||||||
array.width = (tool.extNozzle || 1) / 2;
|
|
||||||
array.push(poly);
|
|
||||||
emits++;
|
|
||||||
};
|
|
||||||
|
|
||||||
let height = level.height / 2;
|
|
||||||
let width = 1;
|
|
||||||
let emits = 0;
|
|
||||||
|
|
||||||
level.forEach((out,oi) => {
|
|
||||||
if (retracted && out.emit) {
|
|
||||||
retracted = false;
|
|
||||||
engages.push(lastOut.point);
|
|
||||||
}
|
|
||||||
if (out.tool !== lastTool) {
|
|
||||||
lastTool = out.tool;
|
|
||||||
changes.push(out.point);
|
|
||||||
}
|
|
||||||
if (out.retract) {
|
|
||||||
retracts.push(out.point);
|
|
||||||
retracted = true;
|
|
||||||
retractz++;
|
|
||||||
}
|
|
||||||
if (!out.point) {
|
|
||||||
// in cam mode, these are drilling or dwell ops
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastOut) {
|
|
||||||
if (arrowAll || lastOut.emit !== out.emit) {
|
|
||||||
heads.push({p1: lastOut.point, p2: out.point});
|
|
||||||
}
|
|
||||||
const op = out.point, lp = lastOut.point;
|
|
||||||
// const moved = Math.max(
|
|
||||||
// Math.abs(op.x - lp.x),
|
|
||||||
// Math.abs(op.y - lp.y),
|
|
||||||
// Math.abs(op.z - lp.z));
|
|
||||||
// if (moved < 0.0001) return;
|
|
||||||
if (out.emit) {
|
|
||||||
if (!lastOut.emit || (ckspeed && out.speed !== lastOut.speed) || lastEnd) {
|
|
||||||
current = newPolygon().setOpen();
|
|
||||||
current.push(lastOut.point);
|
|
||||||
current.color = color(out);
|
|
||||||
pushPrint(out.tool, current);
|
|
||||||
}
|
|
||||||
current.push(out.point);
|
|
||||||
} else {
|
|
||||||
if (lastOut.emit || lastEnd) {
|
|
||||||
current = newPolygon().setOpen();
|
|
||||||
current.push(lastOut.point);
|
|
||||||
moves.push(current);
|
|
||||||
}
|
|
||||||
current.push(out.point);
|
|
||||||
}
|
|
||||||
lastEnd = null;
|
|
||||||
} else {
|
|
||||||
current = newPolygon().setOpen();
|
|
||||||
current.push(out.point);
|
|
||||||
if (out.emit) {
|
|
||||||
current.color = color(out);
|
|
||||||
pushPrint(out.tool, current);
|
|
||||||
} else {
|
|
||||||
moves.push(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastOut = out;
|
|
||||||
});
|
|
||||||
// all moves with an emit at the very end (common in contouring)
|
|
||||||
if (lastOut.emit && !emits) {
|
|
||||||
pushPrint(lastOut.tool, current)
|
|
||||||
}
|
|
||||||
lastEnd = lastOut;
|
|
||||||
if (changes.length) {
|
|
||||||
output
|
|
||||||
.setLayer('tool', { line: 0x000055, face: 0x0000ff, opacity: 0.5 }, true)
|
|
||||||
.addAreas(changes.map(point => {
|
|
||||||
return newPolygon().centerCircle(point, 0.2, 4).setZ(point.z + 0.03);
|
|
||||||
}), { outline: true });
|
|
||||||
}
|
|
||||||
if (retracts.length) {
|
|
||||||
output
|
|
||||||
.setLayer('retract', { line: 0x550000, face: 0xff0000, opacity: 0.5 }, true)
|
|
||||||
.addAreas(retracts.map(point => {
|
|
||||||
return newPolygon().centerCircle(point, 0.2, 5).setZ(point.z + 0.01);
|
|
||||||
}), { outline: true });
|
|
||||||
}
|
|
||||||
if (engages.length) {
|
|
||||||
output
|
|
||||||
.setLayer('engage', { line: 0x005500, face: 0x00ff00, opacity: 0.5 }, true)
|
|
||||||
.addAreas(engages.map(point => {
|
|
||||||
return newPolygon().centerCircle(point, 0.2, 7).setZ(point.z + 0.02);
|
|
||||||
}), { outline: true });
|
|
||||||
}
|
|
||||||
if (heads.length) {
|
|
||||||
let line = dark ? 0xffffff : 0x112233;
|
|
||||||
output
|
|
||||||
.setLayer('arrows', { face: headColor, line, opacity: 0.75 }, true)
|
|
||||||
.addAreas(heads.map(points => {
|
|
||||||
const {p1, p2} = points;
|
|
||||||
const slope = p2.slopeTo(p1);
|
|
||||||
const s1 = base.newSlopeFromAngle(slope.angle + 20);
|
|
||||||
const s2 = base.newSlopeFromAngle(slope.angle - 20);
|
|
||||||
const p3 = points.p2.projectOnSlope(s1, arrowSize);
|
|
||||||
const p4 = points.p2.projectOnSlope(s2, arrowSize);
|
|
||||||
return newPolygon().addPoints([p2,p3,p4]).setZ(p2.z + 0.01);
|
|
||||||
}), { thin: true, outline: true });
|
|
||||||
}
|
|
||||||
output
|
|
||||||
.setLayer(opts.other || 'move', moveOpt, opts.moves !== true)
|
|
||||||
.addPolys(moves, { thin: true, z: opts.z });
|
|
||||||
// force level when present
|
|
||||||
let pz = level.z ? level.z - height : opts.z;
|
|
||||||
Object.values(prints).forEach(array => {
|
|
||||||
array.forEach(poly => {
|
|
||||||
if (flat && poly.appearsClosed()) {
|
|
||||||
poly.setClosed();
|
|
||||||
poly.points.pop();
|
|
||||||
}
|
|
||||||
output
|
|
||||||
.setLayer(opts.action || 'print', printOpt)
|
|
||||||
.addPolys([ poly ],
|
|
||||||
thin ? { thin, z: opts.z, color: poly.color } :
|
|
||||||
flat ? {
|
|
||||||
flat, z: pz, color: poly.color,
|
|
||||||
outline: true, offset: array.width, open: poly.open } :
|
|
||||||
{
|
|
||||||
offset: array.width, height, z: pz,
|
|
||||||
color: { face: poly.color, line: poly.color }
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
update(index / levels.length, output);
|
|
||||||
});
|
|
||||||
// console.log({retractz});
|
|
||||||
return layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
const colorFunctions = FDM.colorFunctions = {
|
|
||||||
default: hsv2rgb.bind({ seg: 4, fn: color4d }),
|
|
||||||
simple: hsv2rgb.bind({ seg: 3, fn: color4 }),
|
|
||||||
dark: hsv2rgb.bind({ seg: 4, fn: color4d })
|
|
||||||
};
|
|
||||||
|
|
||||||
let currentColorFunction = colorFunctions.default;
|
|
||||||
let darkColorFunction = colorFunctions.dark;
|
|
||||||
|
|
||||||
// hsv values all = 0 to 1
|
|
||||||
function hsv2rgb(h, s, v) {
|
|
||||||
const div = this.seg;
|
|
||||||
const ss = 1 / div;
|
|
||||||
const seg = Math.floor(h / ss);
|
|
||||||
const rem = h - (seg * ss);
|
|
||||||
const inc = (rem / ss);
|
|
||||||
const dec = (1 - inc);
|
|
||||||
const rgb = {r: 0, g: 0, b: 0};
|
|
||||||
this.fn(rgb, inc, seg);
|
|
||||||
rgb.r = ((rgb.r * 255 * v) & 0xff) << 16;
|
|
||||||
rgb.g = ((rgb.g * 255 * v) & 0xff) << 8;
|
|
||||||
rgb.b = ((rgb.b * 255 * v) & 0xff);
|
|
||||||
return rgb.r | rgb.g | rgb.b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function color5(rgb, inc, seg) {
|
|
||||||
const dec = 1 - inc;
|
|
||||||
switch (seg) {
|
|
||||||
case 0:
|
|
||||||
rgb.r = 1;
|
|
||||||
rgb.g = inc;
|
|
||||||
rgb.b = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rgb.r = dec;
|
|
||||||
rgb.g = 1;
|
|
||||||
rgb.b = 0;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rgb.r = 0;
|
|
||||||
rgb.g = dec;
|
|
||||||
rgb.b = inc;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
rgb.r = inc;
|
|
||||||
rgb.g = 0;
|
|
||||||
rgb.b = 1;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
rgb.r = dec;
|
|
||||||
rgb.g = 0;
|
|
||||||
rgb.b = dec;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function color4d(rgb, inc, seg) {
|
|
||||||
const dec = 1 - inc;
|
|
||||||
switch (seg) {
|
|
||||||
case 0:
|
|
||||||
rgb.r = 1;
|
|
||||||
rgb.g = inc;
|
|
||||||
rgb.b = 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rgb.r = dec;
|
|
||||||
rgb.g = 1;
|
|
||||||
rgb.b = 0;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rgb.r = 0;
|
|
||||||
rgb.g = dec;
|
|
||||||
rgb.b = inc;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
rgb.r = inc * 0.85;
|
|
||||||
rgb.g = 0;
|
|
||||||
rgb.b = 1;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
rgb.r = 0.85;
|
|
||||||
rgb.g = 0;
|
|
||||||
rgb.b = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function color4(rgb, inc, seg) {
|
|
||||||
const dec = 1 - inc;
|
|
||||||
switch (seg) {
|
|
||||||
case 0:
|
|
||||||
rgb.r = 0;
|
|
||||||
rgb.g = inc;
|
|
||||||
rgb.b = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rgb.r = inc;
|
|
||||||
rgb.g = 1;
|
|
||||||
rgb.b = 0;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rgb.r = 1;
|
|
||||||
rgb.g = dec;
|
|
||||||
rgb.b = 0;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
rgb.r = dec;
|
|
||||||
rgb.g = 0;
|
|
||||||
rgb.b = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
// dep: geo.point
|
// dep: geo.point
|
||||||
// dep: kiri.slice
|
// dep: kiri.slice
|
||||||
// use: kiri.pack
|
// use: kiri.pack
|
||||||
|
// use: kiri.render
|
||||||
gapp.register("kiri-mode.laser.driver", [], (root, exports) => {
|
gapp.register("kiri-mode.laser.driver", [], (root, exports) => {
|
||||||
|
|
||||||
const { base, kiri } = root;
|
const { base, kiri } = root;
|
||||||
|
|
@ -365,7 +366,7 @@ function prepare(widgets, settings, update) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return print.render = FDM.prepareRender(output, (progress, layer) => {
|
return print.render = kiri.render.path(output, (progress, layer) => {
|
||||||
update(0.5 + progress * 0.5, "render", layer);
|
update(0.5 + progress * 0.5, "render", layer);
|
||||||
}, { thin: true, z: 0, action: "cut", moves: process.knifeOn });
|
}, { thin: true, z: 0, action: "cut", moves: process.knifeOn });
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
// dep: kiri.codec
|
// dep: kiri.codec
|
||||||
// dep: kiri.slice
|
// dep: kiri.slice
|
||||||
// dep: moto.license
|
// dep: moto.license
|
||||||
|
// use: kiri.render
|
||||||
// use: kiri-mode.cam.animate
|
// use: kiri-mode.cam.animate
|
||||||
// use: kiri-mode.cam.slice
|
// use: kiri-mode.cam.slice
|
||||||
// use: kiri-mode.cam.prepare
|
// use: kiri-mode.cam.prepare
|
||||||
|
|
@ -512,7 +513,7 @@ kiri.worker = {
|
||||||
const { colors, max } = data;
|
const { colors, max } = data;
|
||||||
const colorMap = {};
|
const colorMap = {};
|
||||||
colors.forEach(color => {
|
colors.forEach(color => {
|
||||||
colorMap[color] = kiri.driver.FDM.rateToColor(color, max);
|
colorMap[color] = kiri.render.rate_to_color(color, max);
|
||||||
});
|
});
|
||||||
send.done(colorMap);
|
send.done(colorMap);
|
||||||
},
|
},
|
||||||
|
|
@ -536,7 +537,7 @@ kiri.worker = {
|
||||||
}, done => {
|
}, done => {
|
||||||
const minSpeed = print.minSpeed;
|
const minSpeed = print.minSpeed;
|
||||||
const maxSpeed = print.maxSpeed;
|
const maxSpeed = print.maxSpeed;
|
||||||
const layers = kiri.driver.FDM.prepareRender(done.output, progress => {
|
const layers = kiri.render.path(done.output, progress => {
|
||||||
send.data({ progress: 0.25 + progress * 0.75 });
|
send.data({ progress: 0.25 + progress * 0.75 });
|
||||||
}, { thin: thin || print.belt, flat, tools });
|
}, { thin: thin || print.belt, flat, tools });
|
||||||
send.done({parsed: codec.encode(layers), maxSpeed, minSpeed});
|
send.done({parsed: codec.encode(layers), maxSpeed, minSpeed});
|
||||||
|
|
@ -554,7 +555,7 @@ kiri.worker = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const print = current.print = kiri.newPrint(null, Object.values(wcache));
|
const print = current.print = kiri.newPrint(null, Object.values(wcache));
|
||||||
const layers = kiri.driver.FDM.prepareRender(parsed, progress => {
|
const layers = kiri.render.path(parsed, progress => {
|
||||||
send.data({ progress });
|
send.data({ progress });
|
||||||
}, { thin: true });
|
}, { thin: true });
|
||||||
send.done({parsed: codec.encode(layers)});
|
send.done({parsed: codec.encode(layers)});
|
||||||
|
|
|
||||||
369
src/kiri/render.js
Normal file
369
src/kiri/render.js
Normal file
|
|
@ -0,0 +1,369 @@
|
||||||
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// dep: geo.base
|
||||||
|
// dep: geo.point
|
||||||
|
// dep: geo.polygon
|
||||||
|
gapp.register("kiri.render", [], (root, exports) => {
|
||||||
|
|
||||||
|
const { base, kiri } = root;
|
||||||
|
const { config, util, newPolygon } = base;
|
||||||
|
|
||||||
|
exports({
|
||||||
|
path,
|
||||||
|
is_dark,
|
||||||
|
rate_to_color
|
||||||
|
});
|
||||||
|
|
||||||
|
function is_dark() {
|
||||||
|
return root.worker.print.settings.controller.dark ? true : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
function rate_to_color(rate, max) {
|
||||||
|
return is_dark() ?
|
||||||
|
darkColorFunction(rate/max, 1, 0.85) :
|
||||||
|
currentColorFunction(rate/max, 1, 0.85);
|
||||||
|
};
|
||||||
|
|
||||||
|
function path(levels, update, opts = {}) {
|
||||||
|
levels = levels.filter(level => level.length);
|
||||||
|
if (levels.length === 0) {
|
||||||
|
self.worker.print.maxSpeed = 0;
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const dark = is_dark();
|
||||||
|
const tools = opts.tools || {};
|
||||||
|
const flat = opts.flat;
|
||||||
|
const thin = opts.thin && !flat;
|
||||||
|
const ckspeed = opts.speed !== false;
|
||||||
|
const headColor = 0x888888;
|
||||||
|
const moveColor = opts.move >= 0 ? opts.move : (dark ? 0x666666 : 0xaaaaaa);
|
||||||
|
const printColor = opts.print >= 0 ? opts.print : 0x777700;
|
||||||
|
const arrowAll = true;
|
||||||
|
const arrowSize = arrowAll ? 0.2 : 0.4;
|
||||||
|
const layers = [];
|
||||||
|
const toolMode = opts.toolMode;
|
||||||
|
|
||||||
|
const moveOpt = {
|
||||||
|
face: moveColor,
|
||||||
|
line: flat ? 1 : moveColor,
|
||||||
|
opacity: flat ? 0.5 : 1
|
||||||
|
};
|
||||||
|
const printOpt = {
|
||||||
|
face: printColor,
|
||||||
|
line: flat ? 1 : printColor,
|
||||||
|
opacity: flat ? 0.5 : 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let minspd = Infinity;
|
||||||
|
let maxspd = opts.maxspeed || 0;
|
||||||
|
let maxtool = [];
|
||||||
|
|
||||||
|
for (let level of levels) {
|
||||||
|
for (let o of level) {
|
||||||
|
if (o.speed) {
|
||||||
|
minspd = Math.min(minspd, o.speed);
|
||||||
|
maxspd = Math.max(maxspd, o.speed);
|
||||||
|
}
|
||||||
|
if (toolMode && o.tool !== undefined) {
|
||||||
|
if (maxtool.indexOf(o.tool) < 0) {
|
||||||
|
maxtool.push(o.tool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const maxspd = levels.map(level => {
|
||||||
|
// return level.map(o => o.speed || 0).reduce((a, v) => Math.max(a,v));
|
||||||
|
// }).reduce((a, v) => Math.max(a, v)) + 1;
|
||||||
|
|
||||||
|
// for reporting
|
||||||
|
self.worker.print.minSpeed = minspd;
|
||||||
|
self.worker.print.maxSpeed = maxspd;
|
||||||
|
self.worker.print.thinColor = thin;
|
||||||
|
self.worker.print.flatColor = flat;
|
||||||
|
|
||||||
|
let lastTool = null;
|
||||||
|
let lastEnd = null;
|
||||||
|
let lastOut = null;
|
||||||
|
let current = null;
|
||||||
|
let retracted = false;
|
||||||
|
let retractz = 0;
|
||||||
|
|
||||||
|
function color(point) {
|
||||||
|
if (toolMode) {
|
||||||
|
return rate_to_color(maxtool.indexOf(point.tool), maxtool.length);
|
||||||
|
} else {
|
||||||
|
return rate_to_color(point.speed, maxspd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
levels.forEach((level, index) => {
|
||||||
|
const prints = {};
|
||||||
|
const moves = [];
|
||||||
|
const heads = [];
|
||||||
|
const changes = [];
|
||||||
|
const retracts = [];
|
||||||
|
const engages = [];
|
||||||
|
const output = new kiri.Layers();
|
||||||
|
layers.push(output);
|
||||||
|
|
||||||
|
const pushPrint = (toolid, poly) => {
|
||||||
|
toolid = toolid || 0;
|
||||||
|
const array = prints[toolid] = prints[toolid] || [];
|
||||||
|
const tool = tools[toolid] || {};
|
||||||
|
array.width = (tool.extNozzle || 1) / 2;
|
||||||
|
array.push(poly);
|
||||||
|
emits++;
|
||||||
|
};
|
||||||
|
|
||||||
|
let height = level.height / 2;
|
||||||
|
let width = 1;
|
||||||
|
let emits = 0;
|
||||||
|
|
||||||
|
level.forEach((out,oi) => {
|
||||||
|
if (retracted && out.emit) {
|
||||||
|
retracted = false;
|
||||||
|
engages.push(lastOut.point);
|
||||||
|
}
|
||||||
|
if (out.tool !== lastTool) {
|
||||||
|
lastTool = out.tool;
|
||||||
|
changes.push(out.point);
|
||||||
|
}
|
||||||
|
if (out.retract) {
|
||||||
|
retracts.push(out.point);
|
||||||
|
retracted = true;
|
||||||
|
retractz++;
|
||||||
|
}
|
||||||
|
if (!out.point) {
|
||||||
|
// in cam mode, these are drilling or dwell ops
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastOut) {
|
||||||
|
if (arrowAll || lastOut.emit !== out.emit) {
|
||||||
|
heads.push({p1: lastOut.point, p2: out.point});
|
||||||
|
}
|
||||||
|
const op = out.point, lp = lastOut.point;
|
||||||
|
// const moved = Math.max(
|
||||||
|
// Math.abs(op.x - lp.x),
|
||||||
|
// Math.abs(op.y - lp.y),
|
||||||
|
// Math.abs(op.z - lp.z));
|
||||||
|
// if (moved < 0.0001) return;
|
||||||
|
if (out.emit) {
|
||||||
|
if (!lastOut.emit || (ckspeed && out.speed !== lastOut.speed) || lastEnd) {
|
||||||
|
current = newPolygon().setOpen();
|
||||||
|
current.push(lastOut.point);
|
||||||
|
current.color = color(out);
|
||||||
|
pushPrint(out.tool, current);
|
||||||
|
}
|
||||||
|
current.push(out.point);
|
||||||
|
} else {
|
||||||
|
if (lastOut.emit || lastEnd) {
|
||||||
|
current = newPolygon().setOpen();
|
||||||
|
current.push(lastOut.point);
|
||||||
|
moves.push(current);
|
||||||
|
}
|
||||||
|
current.push(out.point);
|
||||||
|
}
|
||||||
|
lastEnd = null;
|
||||||
|
} else {
|
||||||
|
current = newPolygon().setOpen();
|
||||||
|
current.push(out.point);
|
||||||
|
if (out.emit) {
|
||||||
|
current.color = color(out);
|
||||||
|
pushPrint(out.tool, current);
|
||||||
|
} else {
|
||||||
|
moves.push(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastOut = out;
|
||||||
|
});
|
||||||
|
// all moves with an emit at the very end (common in contouring)
|
||||||
|
if (lastOut.emit && !emits) {
|
||||||
|
pushPrint(lastOut.tool, current)
|
||||||
|
}
|
||||||
|
lastEnd = lastOut;
|
||||||
|
if (changes.length) {
|
||||||
|
output
|
||||||
|
.setLayer('tool', { line: 0x000055, face: 0x0000ff, opacity: 0.5 }, true)
|
||||||
|
.addAreas(changes.map(point => {
|
||||||
|
return newPolygon().centerCircle(point, 0.2, 4).setZ(point.z + 0.03);
|
||||||
|
}), { outline: true });
|
||||||
|
}
|
||||||
|
if (retracts.length) {
|
||||||
|
output
|
||||||
|
.setLayer('retract', { line: 0x550000, face: 0xff0000, opacity: 0.5 }, true)
|
||||||
|
.addAreas(retracts.map(point => {
|
||||||
|
return newPolygon().centerCircle(point, 0.2, 5).setZ(point.z + 0.01);
|
||||||
|
}), { outline: true });
|
||||||
|
}
|
||||||
|
if (engages.length) {
|
||||||
|
output
|
||||||
|
.setLayer('engage', { line: 0x005500, face: 0x00ff00, opacity: 0.5 }, true)
|
||||||
|
.addAreas(engages.map(point => {
|
||||||
|
return newPolygon().centerCircle(point, 0.2, 7).setZ(point.z + 0.02);
|
||||||
|
}), { outline: true });
|
||||||
|
}
|
||||||
|
if (heads.length) {
|
||||||
|
let line = dark ? 0xffffff : 0x112233;
|
||||||
|
output
|
||||||
|
.setLayer('arrows', { face: headColor, line, opacity: 0.75 }, true)
|
||||||
|
.addAreas(heads.map(points => {
|
||||||
|
const {p1, p2} = points;
|
||||||
|
const slope = p2.slopeTo(p1);
|
||||||
|
const s1 = base.newSlopeFromAngle(slope.angle + 20);
|
||||||
|
const s2 = base.newSlopeFromAngle(slope.angle - 20);
|
||||||
|
const p3 = points.p2.projectOnSlope(s1, arrowSize);
|
||||||
|
const p4 = points.p2.projectOnSlope(s2, arrowSize);
|
||||||
|
return newPolygon().addPoints([p2,p3,p4]).setZ(p2.z + 0.01);
|
||||||
|
}), { thin: true, outline: true });
|
||||||
|
}
|
||||||
|
output
|
||||||
|
.setLayer(opts.other || 'move', moveOpt, opts.moves !== true)
|
||||||
|
.addPolys(moves, { thin: true, z: opts.z });
|
||||||
|
// force level when present
|
||||||
|
let pz = level.z ? level.z - height : opts.z;
|
||||||
|
Object.values(prints).forEach(array => {
|
||||||
|
array.forEach(poly => {
|
||||||
|
if (flat && poly.appearsClosed()) {
|
||||||
|
poly.setClosed();
|
||||||
|
poly.points.pop();
|
||||||
|
}
|
||||||
|
output
|
||||||
|
.setLayer(opts.action || 'print', printOpt)
|
||||||
|
.addPolys([ poly ],
|
||||||
|
thin ? { thin, z: opts.z, color: poly.color } :
|
||||||
|
flat ? {
|
||||||
|
flat, z: pz, color: poly.color,
|
||||||
|
outline: true, offset: array.width, open: poly.open } :
|
||||||
|
{
|
||||||
|
offset: array.width, height, z: pz,
|
||||||
|
color: { face: poly.color, line: poly.color }
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
update(index / levels.length, output);
|
||||||
|
});
|
||||||
|
// console.log({retractz});
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorFunctions = {
|
||||||
|
default: hsv2rgb.bind({ seg: 4, fn: color4d }),
|
||||||
|
simple: hsv2rgb.bind({ seg: 3, fn: color4 }),
|
||||||
|
dark: hsv2rgb.bind({ seg: 4, fn: color4d })
|
||||||
|
};
|
||||||
|
|
||||||
|
let currentColorFunction = colorFunctions.default;
|
||||||
|
let darkColorFunction = colorFunctions.dark;
|
||||||
|
|
||||||
|
// hsv values all = 0 to 1
|
||||||
|
function hsv2rgb(h, s, v) {
|
||||||
|
const div = this.seg;
|
||||||
|
const ss = 1 / div;
|
||||||
|
const seg = Math.floor(h / ss);
|
||||||
|
const rem = h - (seg * ss);
|
||||||
|
const inc = (rem / ss);
|
||||||
|
const dec = (1 - inc);
|
||||||
|
const rgb = {r: 0, g: 0, b: 0};
|
||||||
|
this.fn(rgb, inc, seg);
|
||||||
|
rgb.r = ((rgb.r * 255 * v) & 0xff) << 16;
|
||||||
|
rgb.g = ((rgb.g * 255 * v) & 0xff) << 8;
|
||||||
|
rgb.b = ((rgb.b * 255 * v) & 0xff);
|
||||||
|
return rgb.r | rgb.g | rgb.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function color5(rgb, inc, seg) {
|
||||||
|
const dec = 1 - inc;
|
||||||
|
switch (seg) {
|
||||||
|
case 0:
|
||||||
|
rgb.r = 1;
|
||||||
|
rgb.g = inc;
|
||||||
|
rgb.b = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rgb.r = dec;
|
||||||
|
rgb.g = 1;
|
||||||
|
rgb.b = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rgb.r = 0;
|
||||||
|
rgb.g = dec;
|
||||||
|
rgb.b = inc;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rgb.r = inc;
|
||||||
|
rgb.g = 0;
|
||||||
|
rgb.b = 1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rgb.r = dec;
|
||||||
|
rgb.g = 0;
|
||||||
|
rgb.b = dec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function color4d(rgb, inc, seg) {
|
||||||
|
const dec = 1 - inc;
|
||||||
|
switch (seg) {
|
||||||
|
case 0:
|
||||||
|
rgb.r = 1;
|
||||||
|
rgb.g = inc;
|
||||||
|
rgb.b = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rgb.r = dec;
|
||||||
|
rgb.g = 1;
|
||||||
|
rgb.b = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rgb.r = 0;
|
||||||
|
rgb.g = dec;
|
||||||
|
rgb.b = inc;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rgb.r = inc * 0.85;
|
||||||
|
rgb.g = 0;
|
||||||
|
rgb.b = 1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rgb.r = 0.85;
|
||||||
|
rgb.g = 0;
|
||||||
|
rgb.b = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function color4(rgb, inc, seg) {
|
||||||
|
const dec = 1 - inc;
|
||||||
|
switch (seg) {
|
||||||
|
case 0:
|
||||||
|
rgb.r = 0;
|
||||||
|
rgb.g = inc;
|
||||||
|
rgb.b = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rgb.r = inc;
|
||||||
|
rgb.g = 1;
|
||||||
|
rgb.b = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rgb.r = 1;
|
||||||
|
rgb.g = dec;
|
||||||
|
rgb.b = 0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rgb.r = dec;
|
||||||
|
rgb.g = 0;
|
||||||
|
rgb.b = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue