add laser merge mode
This commit is contained in:
parent
d53f51a6aa
commit
bc58245fb5
5 changed files with 103 additions and 48 deletions
|
|
@ -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 ---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
widget.slices.forEach(function(slice) {
|
// slice stack merging
|
||||||
sliceEmitObjects(print, slice, output);
|
if (process.outputLaserMerged) {
|
||||||
update(slices++ / totalSlices);
|
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) {
|
||||||
|
sliceEmitObjects(print, slice, output);
|
||||||
|
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,
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue