add laser merge mode

This commit is contained in:
Stewart Allen 2020-03-12 19:23:09 -04:00
commit bc58245fb5
5 changed files with 103 additions and 48 deletions

View file

@ -205,6 +205,7 @@ var gs_kiri_conf = exports;
outputLaserPower: 1, outputLaserPower: 1,
outputLaserSpeed: 1, outputLaserSpeed: 1,
outputLaserGroup: 1, outputLaserGroup: 1,
outputLaserMerged: 1,
outputOriginBounds: 1, outputOriginBounds: 1,
outputOriginCenter: 1, outputOriginCenter: 1,
outputInvertX: 1, outputInvertX: 1,
@ -371,6 +372,7 @@ var gs_kiri_conf = exports;
outputLaserPower: 100, outputLaserPower: 100,
outputLaserSpeed: 1000, outputLaserSpeed: 1000,
outputLaserGroup: true, outputLaserGroup: true,
outputLaserMerged: false,
// --- CAM --- // --- CAM ---

View file

@ -2,7 +2,7 @@
"use strict"; "use strict";
var gs_kiri_laser = exports; let gs_kiri_laser = exports;
(function() { (function() {
@ -10,9 +10,10 @@ var gs_kiri_laser = exports;
if (!self.kiri.driver) self.kiri.driver = { }; if (!self.kiri.driver) self.kiri.driver = { };
if (self.kiri.driver.LASER) return; if (self.kiri.driver.LASER) return;
var KIRI = self.kiri, let KIRI = self.kiri,
BASE = self.base, BASE = self.base,
UTIL = BASE.util, UTIL = BASE.util,
POLY = BASE.polygons,
DBUG = BASE.debug, DBUG = BASE.debug,
LASER = KIRI.driver.LASER = { LASER = KIRI.driver.LASER = {
slice, slice,
@ -33,7 +34,7 @@ var gs_kiri_laser = exports;
* @param {Function} ondone (called when complete with an array of Slice objects) * @param {Function} ondone (called when complete with an array of Slice objects)
*/ */
function slice(settings, widget, onupdate, ondone) { function slice(settings, widget, onupdate, ondone) {
var proc = settings.process; let proc = settings.process;
if (proc.laserSliceHeight < 0) { if (proc.laserSliceHeight < 0) {
return ondone("invalid slice height"); return ondone("invalid slice height");
@ -51,34 +52,39 @@ var gs_kiri_laser = exports;
}); });
}; };
function sliceEmitObjects(print, slice, objects) { /**
var start = newPoint(0,0,0); *
*/
function sliceEmitObjects(print, slice, groups) {
let start = newPoint(0,0,0);
let process = print.settings.process;
let grouped = process.outputLaserGroup;
let group = [];
function laserOut(poly, object) { function laserOut(poly, group) {
if (!poly) return; if (!poly) {
return;
}
if (Array.isArray(poly)) { if (Array.isArray(poly)) {
poly.forEach(function(pi) { poly.forEach(function(pi) {
laserOut(pi, object); laserOut(pi, group);
}); });
} else { } else {
print.polyPrintPath(poly, start, object, {extrude: 1}); print.polyPrintPath(poly, start, group, {extrude: 1});
} }
} }
var breakout = !print.settings.process.outputLaserGroup;
var object = [];
slice.tops.forEach(function(top) { slice.tops.forEach(function(top) {
laserOut(top.traces, object); laserOut(top.traces, group);
laserOut(top.innerTraces(), object); laserOut(top.innerTraces(), group);
if (breakout) { if (!grouped) {
objects.push(object); groups.push(group);
object = []; group = [];
} }
}); });
if (!breakout) { if (grouped) {
objects.push(object); groups.push(group);
} }
}; };
@ -89,11 +95,10 @@ var gs_kiri_laser = exports;
* @param {Function} update incremental callback * @param {Function} update incremental callback
*/ */
function printSetup(print, update) { function printSetup(print, update) {
var widgets = print.widgets, let widgets = print.widgets,
settings = print.settings, settings = print.settings,
device = settings.device, device = settings.device,
process = settings.process, process = settings.process,
mode = settings.mode,
output = print.output, output = print.output,
totalSlices = 0, totalSlices = 0,
slices = 0; slices = 0;
@ -105,15 +110,49 @@ var gs_kiri_laser = exports;
// emit objects from each slice into output array // emit objects from each slice into output array
widgets.forEach(function(widget) { widgets.forEach(function(widget) {
// slice stack merging
if (process.outputLaserMerged) {
let merged = [];
widget.slices.forEach(function(slice) {
let polys = [];
slice.gatherTopPolys([]).forEach(p => p.flattenTo(polys));
polys.forEach(p => {
let match = false;
for (let i=0; i<merged.length; i++) {
let mp = merged[i];
if (p.isEquivalent(mp)) {
// increase weight
match = true;
mp.depth++;
}
}
if (!match) {
p.depth = 1;
merged.push(p);
}
});
update(slices++ / totalSlices);
});
let start = newPoint(0,0,0);
let gather = [];
merged.forEach(poly => {
print.polyPrintPath(poly, start, gather, {
extrude: poly.depth,
rate: poly.depth * 10
});
});
output.push(gather);
} else {
widget.slices.forEach(function(slice) { widget.slices.forEach(function(slice) {
sliceEmitObjects(print, slice, output); sliceEmitObjects(print, slice, output);
update(slices++ / totalSlices); update(slices++ / totalSlices);
}); });
}
}); });
// compute tile width / height // compute tile width / height
output.forEach(function(layerout) { output.forEach(function(layerout) {
var min = {w:Infinity, h:Infinity}, max = {w:-Infinity, h:-Infinity}, p; let min = {w:Infinity, h:Infinity}, max = {w:-Infinity, h:-Infinity}, p;
layerout.forEach(function(out) { layerout.forEach(function(out) {
p = out.point; p = out.point;
out.point = p.clone(); // b/c first/last point are often shared out.point = p.clone(); // b/c first/last point are often shared
@ -133,10 +172,8 @@ var gs_kiri_laser = exports;
}); });
// do object layout packing // do object layout packing
var i, m, e, let i, m, e,
MOTO = self.moto, MOTO = self.moto,
device = settings.device,
process = settings.process,
mp = [device.bedWidth, device.bedDepth], mp = [device.bedWidth, device.bedDepth],
ms = [mp[0] / 2, mp[1] / 2], ms = [mp[0] / 2, mp[1] / 2],
mi = mp[0] > mp[1] ? [(mp[0] / mp[1]) * 10, 10] : [10, (mp[1] / mp[1]) * 10], mi = mp[0] > mp[1] ? [(mp[0] / mp[1]) * 10, 10] : [10, (mp[1] / mp[1]) * 10],
@ -170,7 +207,7 @@ var gs_kiri_laser = exports;
*/ */
function exportElements(print, onpre, onpoly, onpost, onpoint) { function exportElements(print, onpre, onpoly, onpost, onpoint) {
var process = print.settings.process, let process = print.settings.process,
output = print.output, output = print.output,
last, last,
point, point,
@ -191,7 +228,7 @@ var gs_kiri_laser = exports;
max.y = Math.max(max.y, point.y); max.y = Math.max(max.y, point.y);
}); });
}); });
console.log(print.settings)
if (!process.outputOriginCenter) { if (!process.outputOriginCenter) {
// normalize against origin lower left // normalize against origin lower left
output.forEach(function(layer) { output.forEach(function(layer) {
@ -225,19 +262,23 @@ var gs_kiri_laser = exports;
onpre(min, max, process.outputLaserPower, process.outputLaserSpeed); onpre(min, max, process.outputLaserPower, process.outputLaserSpeed);
output.forEach(function(layer) { output.forEach(function(layer) {
let color = 0;
layer.forEach(function(out) { layer.forEach(function(out) {
point = out.point; point = out.point;
if (out.emit) { if (out.emit) {
if (last && poly.length === 0) poly.push(onpoint(last)); color = out.emit;
if (last && poly.length === 0) {
poly.push(onpoint(last));
}
poly.push(onpoint(point)); poly.push(onpoint(point));
} else if (poly.length > 0) { } else if (poly.length > 0) {
onpoly(poly); onpoly(poly, color);
poly = []; poly = [];
} }
last = point; last = point;
}); });
if (poly.length > 0) { if (poly.length > 0) {
onpoly(poly); onpoly(poly, color);
poly = []; poly = [];
} }
}); });
@ -249,12 +290,12 @@ var gs_kiri_laser = exports;
* *
*/ */
function exportGCode(print) { function exportGCode(print) {
var lines = [], dx = 0, dy = 0, feedrate, laser_on; let lines = [], dx = 0, dy = 0, feedrate, laser_on;
exportElements( exportElements(
print, print,
function(min, max, power, speed) { function(min, max, power, speed) {
var width = (max.x - min.x), let width = (max.x - min.x),
height = (max.y - min.y); height = (max.y - min.y);
dx = min.x; dx = min.x;
dy = min.y; dy = min.y;
@ -262,7 +303,7 @@ var gs_kiri_laser = exports;
laser_on = "M106 S" + UTIL.round(256 * (power / 100), 3); laser_on = "M106 S" + UTIL.round(256 * (power / 100), 3);
// pre // pre
}, },
function(poly) { function(poly, color) {
poly.forEach(function(point, index) { poly.forEach(function(point, index) {
if (index === 0) { if (index === 0) {
lines.push("G0 " + point); lines.push("G0 " + point);
@ -290,23 +331,34 @@ var gs_kiri_laser = exports;
* *
*/ */
function exportSVG(print, cut_color) { function exportSVG(print, cut_color) {
var lines = [], dx = 0, dy = 0, my; let lines = [], dx = 0, dy = 0, my;
var color = cut_color || "blue"; let colors = [
"purple",
"blue",
"red",
"orange",
"yellow",
"green",
"brown",
"gray",
"black"
];
exportElements( exportElements(
print, print,
function(min, max) { function(min, max) {
var width = (max.x - min.x), let width = (max.x - min.x),
height = (max.y - min.y); height = (max.y - min.y);
dx = min.x; dx = min.x;
dy = min.y; dy = min.y;
my = max.y; my = max.y;
lines.push('<?xml version="1.0" standalone="no"?>'); lines.push('<?xml version="1.0" standalone="no"?>');
lines.push('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'); lines.push('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">');
lines.push('<svg width="'+width+'mm" height="'+height+'mm" viewBox="0 0 '+width+' '+height+'" xmlns="http://www.w3.org/2000/svg" version="1.1">'); lines.push(`<svg width="${width}mm" height="${height}mm" viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg" version="1.1">`);
}, },
function(poly) { function(poly, color) {
lines.push('<polyline points="'+poly.join(' ')+'" fill="none" stroke="' + color + '" stroke-width="0.01mm" />'); let cout = colors[((color-1) % colors.length)];
lines.push(`<polyline points="${poly.join(' ')}" fill="none" stroke="${cout}" stroke-width="0.1mm" />`);
}, },
function() { function() {
lines.push("</svg>"); lines.push("</svg>");
@ -323,7 +375,7 @@ var gs_kiri_laser = exports;
* *
*/ */
function exportDXF(print) { function exportDXF(print) {
var lines = []; let lines = [];
exportElements( exportElements(
print, print,

View file

@ -52,7 +52,7 @@ let gs_kiri_export = exports;
function download_svg() { function download_svg() {
saveAs(new Blob( saveAs(new Blob(
[currentPrint.exportSVG($('print-color').value)], [currentPrint.exportSVG()],
{type:"application/octet-stream"}), {type:"application/octet-stream"}),
$('print-filename').value + ".svg"); $('print-filename').value + ".svg");
} }

View file

@ -380,7 +380,8 @@ var gs_kiri_init = exports;
outputTileScaling: UC.newInput("scaling", {title:"multiplier (0.1 to 100)", convert:UC.toInt, bound:UC.bound(0.1,100), modes:LASER}), outputTileScaling: UC.newInput("scaling", {title:"multiplier (0.1 to 100)", convert:UC.toInt, bound:UC.bound(0.1,100), modes:LASER}),
outputLaserPower: UC.newInput("power", {title:"0 - 100 %", convert:UC.toInt, bound:UC.bound(1,100), modes:LASER}), outputLaserPower: UC.newInput("power", {title:"0 - 100 %", convert:UC.toInt, bound:UC.bound(1,100), modes:LASER}),
outputLaserSpeed: UC.newInput("speed", {title:"millimeters / minute", convert:UC.toInt, modes:LASER}), outputLaserSpeed: UC.newInput("speed", {title:"millimeters / minute", convert:UC.toInt, modes:LASER}),
outputLaserGroup: UC.newBoolean("layer group", onBooleanClick, {title:"retain layer as\nsingle grouped object", modes:LASER}), outputLaserMerged: UC.newBoolean("merged", onBooleanClick, {title:"merge all layers using\ncolor coding to denote\nstacking depth", modes:LASER}),
outputLaserGroup: UC.newBoolean("grouped", onBooleanClick, {title:"retain each layer as\na unified grouping\ninstead of separated\npolygons", modes:LASER}),
outputTemp: UC.newInput("nozzle temp", {title:"degrees celsius", convert:UC.toInt, modes:FDM}), outputTemp: UC.newInput("nozzle temp", {title:"degrees celsius", convert:UC.toInt, modes:FDM}),
outputBedTemp: UC.newInput("bed temp", {title:"degrees celsius", convert:UC.toInt, modes:FDM}), outputBedTemp: UC.newInput("bed temp", {title:"degrees celsius", convert:UC.toInt, modes:FDM}),
@ -454,6 +455,7 @@ var gs_kiri_init = exports;
function onBooleanClick() { function onBooleanClick() {
API.conf.update(); API.conf.update();
DOC.activeElement.blur();
} }
function inputHasFocus() { function inputHasFocus() {

View file

@ -6,7 +6,6 @@
<table id="print-info"> <table id="print-info">
<tr><th>file name</th><td><input id="print-filename" size="30" spellcheck="false" /></td></tr> <tr><th>file name</th><td><input id="print-filename" size="30" spellcheck="false" /></td></tr>
<tr><th>segments</th><td><input id="print-lines" size="10" disabled="true" /></td></tr> <tr><th>segments</th><td><input id="print-lines" size="10" disabled="true" /></td></tr>
<tr><th>svg cut color</th><td><input id="print-color" size="10" value="blue" title="must be a valid SVG color" /></td></tr>
</table> </table>
</div> </div>