improve thin wall detection
This commit is contained in:
parent
8dae3e7617
commit
8a4e5a053f
7 changed files with 51 additions and 40 deletions
|
|
@ -447,7 +447,6 @@ var gs_base_polygons = exports;
|
||||||
* @param {Polygon[]} polys
|
* @param {Polygon[]} polys
|
||||||
* @param {number} dist1 first offset distance
|
* @param {number} dist1 first offset distance
|
||||||
* @param {number} dist2 2nd thru last offset distance
|
* @param {number} dist2 2nd thru last offset distance
|
||||||
* @param {number} over additional offset over then under
|
|
||||||
* @param {Polygon[]} out optional collector
|
* @param {Polygon[]} out optional collector
|
||||||
* @param {number} count offset passes (0 == until no space left)
|
* @param {number} count offset passes (0 == until no space left)
|
||||||
* @param {Function} collector receives output of each pass
|
* @param {Function} collector receives output of each pass
|
||||||
|
|
@ -455,7 +454,7 @@ var gs_base_polygons = exports;
|
||||||
* @param {number} [z] defaults to 0
|
* @param {number} [z] defaults to 0
|
||||||
* @returns {Polygon[]} last offset
|
* @returns {Polygon[]} last offset
|
||||||
*/
|
*/
|
||||||
function expand2(polys, dist1, dist2, over, out, count, collector, thins, z) {
|
function expand2(polys, dist1, dist2, out, count, collector, thins, z) {
|
||||||
// prepare alignments for clipper lib
|
// prepare alignments for clipper lib
|
||||||
alignWindings(polys);
|
alignWindings(polys);
|
||||||
polys.forEach(function(poly) {
|
polys.forEach(function(poly) {
|
||||||
|
|
@ -470,7 +469,8 @@ var gs_base_polygons = exports;
|
||||||
cety = clib.EndType,
|
cety = clib.EndType,
|
||||||
coff = new clib.ClipperOffset(),
|
coff = new clib.ClipperOffset(),
|
||||||
ctre = new clib.PolyTree(),
|
ctre = new clib.PolyTree(),
|
||||||
orig = polys;
|
orig = polys,
|
||||||
|
over = dist1 * 0.45;
|
||||||
|
|
||||||
// inset
|
// inset
|
||||||
polys.forEach(function(poly) {
|
polys.forEach(function(poly) {
|
||||||
|
|
@ -489,7 +489,7 @@ var gs_base_polygons = exports;
|
||||||
var simple = clip.SimplifyPolygons(clean, cpft.pftNonZero);
|
var simple = clip.SimplifyPolygons(clean, cpft.pftNonZero);
|
||||||
coff.AddPaths(simple, cjnt.jtMiter, cety.etClosedPolygon);
|
coff.AddPaths(simple, cjnt.jtMiter, cety.etClosedPolygon);
|
||||||
});
|
});
|
||||||
coff.Execute(ctre, (-over) * fact);
|
coff.Execute(ctre, -over * fact);
|
||||||
polys = fromClipperTree(ctre, z);
|
polys = fromClipperTree(ctre, z);
|
||||||
|
|
||||||
// detect possible thin walls
|
// detect possible thin walls
|
||||||
|
|
@ -499,7 +499,7 @@ var gs_base_polygons = exports;
|
||||||
diff = Math.abs(1 - (circ1 / circ2));
|
diff = Math.abs(1 - (circ1 / circ2));
|
||||||
|
|
||||||
if (diff > 0.2) {
|
if (diff > 0.2) {
|
||||||
thins(orig, polys, diff);
|
thins(orig, out.length ? polys : null, diff, -over);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,7 +507,7 @@ var gs_base_polygons = exports;
|
||||||
if (out) out.appendAll(polys);
|
if (out) out.appendAll(polys);
|
||||||
if (collector) collector(polys, count);
|
if (collector) collector(polys, count);
|
||||||
if ((count === 0 || count > 1) && polys.length > 0) {
|
if ((count === 0 || count > 1) && polys.length > 0) {
|
||||||
expand2(polys, dist2 || dist1, dist2, over, out, count > 0 ? count-1 : 0, collector, thins, z);
|
expand2(polys, dist2 || dist1, dist2, out, count > 0 ? count-1 : 0, collector, thins, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
return polys;
|
return polys;
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ var gs_kiri_codec = exports;
|
||||||
poly: encode(this.poly, state),
|
poly: encode(this.poly, state),
|
||||||
traces: encode(this.traces, state),
|
traces: encode(this.traces, state),
|
||||||
inner: encode(this.inner, state),
|
inner: encode(this.inner, state),
|
||||||
|
// thinner: encode(this.thinner, state),
|
||||||
solids: encode(this.solids, state),
|
solids: encode(this.solids, state),
|
||||||
fill_lines: encodePointArray(this.fill_lines),
|
fill_lines: encodePointArray(this.fill_lines),
|
||||||
fill_sparse: encode(this.fill_sparse, state)
|
fill_sparse: encode(this.fill_sparse, state)
|
||||||
|
|
@ -131,6 +132,7 @@ var gs_kiri_codec = exports;
|
||||||
|
|
||||||
top.traces = decode(v.traces, state);
|
top.traces = decode(v.traces, state);
|
||||||
top.inner = decode(v.inner, state);
|
top.inner = decode(v.inner, state);
|
||||||
|
// top.thinner = decode(v.thinner, state);
|
||||||
top.solids = decode(v.solids, state);
|
top.solids = decode(v.solids, state);
|
||||||
top.fill_lines = decodePointArray(v.fill_lines,state);
|
top.fill_lines = decodePointArray(v.fill_lines,state);
|
||||||
top.fill_sparse = decode(v.fill_sparse, state);
|
top.fill_sparse = decode(v.fill_sparse, state);
|
||||||
|
|
|
||||||
|
|
@ -216,11 +216,14 @@ var gs_kiri_fdm = exports;
|
||||||
polys = [],
|
polys = [],
|
||||||
preout = [];
|
preout = [];
|
||||||
|
|
||||||
|
// compute first brim
|
||||||
widgets.forEach(function(widget) {
|
widgets.forEach(function(widget) {
|
||||||
var tops = [];
|
var tops = [];
|
||||||
|
// collect top outer polygons
|
||||||
widget.slices[0].tops.forEach(function(top) {
|
widget.slices[0].tops.forEach(function(top) {
|
||||||
tops.push(top.poly.clone());
|
tops.push(top.poly.clone());
|
||||||
});
|
});
|
||||||
|
// nest and offset tops
|
||||||
POLY.nest(tops).forEach(function(poly) {
|
POLY.nest(tops).forEach(function(poly) {
|
||||||
poly.offset(-process.outputBrimOffset + device.nozzleSize/2).forEach(function(brim) {
|
poly.offset(-process.outputBrimOffset + device.nozzleSize/2).forEach(function(brim) {
|
||||||
brim.move(widget.mesh.position);
|
brim.move(widget.mesh.position);
|
||||||
|
|
@ -229,6 +232,11 @@ var gs_kiri_fdm = exports;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// if brim is offset, the expand and shrink to cause brims to merge
|
||||||
|
if (process.outputBrimOffset && brims.length) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
POLY.union(brims).forEach(function(brim) {
|
POLY.union(brims).forEach(function(brim) {
|
||||||
POLY.trace2count(brim, polys, -device.nozzleSize, process.outputBrimCount, 0);
|
POLY.trace2count(brim, polys, -device.nozzleSize, process.outputBrimCount, 0);
|
||||||
});
|
});
|
||||||
|
|
@ -329,7 +337,7 @@ var gs_kiri_fdm = exports;
|
||||||
seekMMM = process.outputSeekrate * 60,
|
seekMMM = process.outputSeekrate * 60,
|
||||||
retDist = process.outputRetractDist,
|
retDist = process.outputRetractDist,
|
||||||
retSpeed = process.outputRetractSpeed * 60,
|
retSpeed = process.outputRetractSpeed * 60,
|
||||||
retDwell = Math.round((process.outputRetractDwell || 0) * 1000),
|
retDwell = process.outputRetractDwell || 0,
|
||||||
// ratio of nozzle area to filament area times
|
// ratio of nozzle area to filament area times
|
||||||
// ratio of slice height to filament max noodle height
|
// ratio of slice height to filament max noodle height
|
||||||
emitPerMM = print.extrudePerMM(device.nozzleSize, device.filamentSize, process.sliceHeight),
|
emitPerMM = print.extrudePerMM(device.nozzleSize, device.filamentSize, process.sliceHeight),
|
||||||
|
|
|
||||||
|
|
@ -634,7 +634,7 @@ var gs_kiri_print = exports;
|
||||||
// if dist to new segment is less than thinWall
|
// if dist to new segment is less than thinWall
|
||||||
// and segment length is less than thinWall then
|
// and segment length is less than thinWall then
|
||||||
// just extrude to midpoint of next segment. this is
|
// just extrude to midpoint of next segment. this is
|
||||||
// to avoid shaking printer to death.
|
// to avoid shaking the printer to death.
|
||||||
if (find.d <= thinWall && len <= thinWall) {
|
if (find.d <= thinWall && len <= thinWall) {
|
||||||
p2 = p1.midPointTo(p2);
|
p2 = p1.midPointTo(p2);
|
||||||
addOutput(preout, p2, fillMult * (find.d / thinWall), printSpeed);
|
addOutput(preout, p2, fillMult * (find.d / thinWall), printSpeed);
|
||||||
|
|
@ -646,7 +646,7 @@ var gs_kiri_print = exports;
|
||||||
checkBisect(startPoint, p1, bounds);
|
checkBisect(startPoint, p1, bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bridge ends of fill if they're close together
|
// bridge ends of fill when they're close together
|
||||||
if (dist < thinWall) {
|
if (dist < thinWall) {
|
||||||
addOutput(preout, p1, fillMult, printSpeed);
|
addOutput(preout, p1, fillMult, printSpeed);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,7 @@ var gs_kiri_slice = exports;
|
||||||
tops.forEach(function(top) {
|
tops.forEach(function(top) {
|
||||||
layer.poly(top.poly, colors[0], true, open);
|
layer.poly(top.poly, colors[0], true, open);
|
||||||
if (top.inner) layer.poly(top.inner, 0x999999, true, null);
|
if (top.inner) layer.poly(top.inner, 0x999999, true, null);
|
||||||
|
// if (top.thinner) layer.poly(top.thinner, 0x559999, true, null);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -357,18 +358,13 @@ var gs_kiri_slice = exports;
|
||||||
*/
|
*/
|
||||||
function cullIntersections(r1, r2) {
|
function cullIntersections(r1, r2) {
|
||||||
if (!(r1 && r2 && r1.length && r2.length)) return;
|
if (!(r1 && r2 && r1.length && r2.length)) return;
|
||||||
if (r2.length > r1.length) {
|
var valid = r2.slice();
|
||||||
var r3 = r1;
|
outer: for (var i=0; i<r1.length; i += 2) {
|
||||||
r1 = r2;
|
for (var j=0; j<r2.length; j += 2) {
|
||||||
r2 = r3;
|
if (UTIL.intersect(r1[i], r1[i+1], r2[j], r2[j+1], BASE.key.SEGINT)) continue outer;
|
||||||
}
|
}
|
||||||
var valid = r1.slice();
|
valid.push(r1[i]);
|
||||||
outer: for (var i=0; i<r2.length; i += 2) {
|
valid.push(r1[i+1]);
|
||||||
for (var j=0; j<r1.length; j += 2) {
|
|
||||||
if (UTIL.intersect(r1[j], r1[j+1], r2[i], r2[i+1])) continue outer;
|
|
||||||
}
|
|
||||||
valid.push(r2[i]);
|
|
||||||
valid.push(r2[i+1]);
|
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
@ -392,6 +388,7 @@ var gs_kiri_slice = exports;
|
||||||
|
|
||||||
slice.tops.forEach(function(top) {
|
slice.tops.forEach(function(top) {
|
||||||
if (opt.vase) top.poly = top.poly.clone(false);
|
if (opt.vase) top.poly = top.poly.clone(false);
|
||||||
|
// top.thinner = [];
|
||||||
top.traces = [];
|
top.traces = [];
|
||||||
top.inner = [];
|
top.inner = [];
|
||||||
var last = [],
|
var last = [],
|
||||||
|
|
@ -412,7 +409,6 @@ var gs_kiri_slice = exports;
|
||||||
[top.poly],
|
[top.poly],
|
||||||
-offset1,
|
-offset1,
|
||||||
-offsetN,
|
-offsetN,
|
||||||
-offset1,
|
|
||||||
top.traces,
|
top.traces,
|
||||||
count,
|
count,
|
||||||
// on each new offset trace ...
|
// on each new offset trace ...
|
||||||
|
|
@ -428,12 +424,17 @@ var gs_kiri_slice = exports;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// thin wall probe
|
// thin wall probe
|
||||||
function(p1, p2) {
|
function(p1, p2, diff, dist) {
|
||||||
var pall = POLY.nest([].appendAll(p1).appendAll(p2).clone(true)),
|
var pall = POLY.nest(POLY.flatten([].appendAll(p1).appendAll(p2)).clone()),
|
||||||
pnew = POLY.expand(pall, -offset1, z, null, 1),
|
pnew1 = POLY.expand(pall, -dist, z, null, 1),
|
||||||
r1 = fillArea(pnew, 45, offsetN, [], 0, offsetN * 2),
|
r1 = fillArea(pnew1, 45, offsetN, [], 0, offset1),
|
||||||
r2 = fillArea(pnew, 135, offsetN, [], 0, offsetN * 2),
|
r2 = fillArea(pnew1, 135, offsetN, [], 0, offset1),
|
||||||
|
rall = top.thin_fill.appendAll(cullIntersections(r1, r2)),
|
||||||
|
pnew2 = POLY.expand(pnew1, -dist, z, null, 1),
|
||||||
|
r1 = fillArea(pnew2, 45, offsetN, [], 0, offset1),
|
||||||
|
r2 = fillArea(pnew2, 135, offsetN, [], 0, offset1),
|
||||||
rall = top.thin_fill.appendAll(cullIntersections(r1, r2));
|
rall = top.thin_fill.appendAll(cullIntersections(r1, r2));
|
||||||
|
// top.thinner.appendAll(pnew1).appendAll(pnew2);
|
||||||
},
|
},
|
||||||
z);
|
z);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
22
js/kiri.js
22
js/kiri.js
|
|
@ -255,9 +255,9 @@ self.kiri.license = exports.LICENSE;
|
||||||
|
|
||||||
sliceHeight: 0.25,
|
sliceHeight: 0.25,
|
||||||
sliceShells: 2,
|
sliceShells: 2,
|
||||||
sliceShellSpacing: 0.9,
|
sliceShellSpacing: 1,
|
||||||
sliceFillAngle: 45,
|
sliceFillAngle: 45,
|
||||||
sliceFillOverlap: 0.5,
|
sliceFillOverlap: 0.3,
|
||||||
sliceFillSpacing: 1.0,
|
sliceFillSpacing: 1.0,
|
||||||
sliceFillSparse: 0.5,
|
sliceFillSparse: 0.5,
|
||||||
|
|
||||||
|
|
@ -278,20 +278,20 @@ self.kiri.license = exports.LICENSE;
|
||||||
firstSliceHeight: 0.25,
|
firstSliceHeight: 0.25,
|
||||||
firstLayerRate: 30,
|
firstLayerRate: 30,
|
||||||
|
|
||||||
outputTemp: 230,
|
outputTemp: 220,
|
||||||
outputFanMax: 255,
|
outputFanMax: 255,
|
||||||
outputBedTemp: 0,
|
outputBedTemp: 0,
|
||||||
outputFeedrate: 100,
|
outputFeedrate: 100,
|
||||||
outputFinishrate: 60,
|
outputFinishrate: 60,
|
||||||
outputSeekrate: 150,
|
outputSeekrate: 150,
|
||||||
outputShellMult: 1.0,
|
outputShellMult: 1.1,
|
||||||
outputFillMult: 1.25,
|
outputFillMult: 1.2,
|
||||||
outputSparseMult: 1.5,
|
outputSparseMult: 1.3,
|
||||||
outputRetractOver: 5.0,
|
outputRetractOver: 5.0,
|
||||||
outputRetractDist: 0.5,
|
outputRetractDist: 0.5,
|
||||||
outputRetractSpeed: 20,
|
outputRetractSpeed: 20,
|
||||||
outputRetractDwell: 0.2,
|
outputRetractDwell: 50,
|
||||||
outputWipeSpeed: 20,
|
outputWipeSpeed: 50,
|
||||||
outputWipeDistance: 0,
|
outputWipeDistance: 0,
|
||||||
outputBrimCount: 2,
|
outputBrimCount: 2,
|
||||||
outputBrimOffset: 3,
|
outputBrimOffset: 3,
|
||||||
|
|
@ -1011,6 +1011,7 @@ self.kiri.license = exports.LICENSE;
|
||||||
ajax.onreadystatechange = function() {
|
ajax.onreadystatechange = function() {
|
||||||
if (ajax.readyState === 4) {
|
if (ajax.readyState === 4) {
|
||||||
var status = ajax.status;
|
var status = ajax.status;
|
||||||
|
STATS.add('op-'+status);
|
||||||
if (status >= 200 && status < 300) {
|
if (status >= 200 && status < 300) {
|
||||||
hideModal();
|
hideModal();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1062,6 +1063,7 @@ self.kiri.license = exports.LICENSE;
|
||||||
xhtr.onreadystatechange = function() {
|
xhtr.onreadystatechange = function() {
|
||||||
if (xhtr.readyState === 4) {
|
if (xhtr.readyState === 4) {
|
||||||
var status = xhtr.status;
|
var status = xhtr.status;
|
||||||
|
STATS.add('gp-'+status);
|
||||||
if (status >= 200 && status < 300) {
|
if (status >= 200 && status < 300) {
|
||||||
var json = js2o(xhtr.responseText);
|
var json = js2o(xhtr.responseText);
|
||||||
gridprint_tracker(host,json.key);
|
gridprint_tracker(host,json.key);
|
||||||
|
|
@ -1435,7 +1437,7 @@ self.kiri.license = exports.LICENSE;
|
||||||
function layoutPlatform(event, space) {
|
function layoutPlatform(event, space) {
|
||||||
var layout = (viewMode === VIEWS.ARRANGE),
|
var layout = (viewMode === VIEWS.ARRANGE),
|
||||||
modified = false,
|
modified = false,
|
||||||
gap = space || 1,
|
gap = space || (1 + settings.process.sliceSupportExtra),
|
||||||
topZ = MODE === MODES.CAM ? camTopZ : 0;
|
topZ = MODE === MODES.CAM ? camTopZ : 0;
|
||||||
|
|
||||||
setViewMode(VIEWS.ARRANGE);
|
setViewMode(VIEWS.ARRANGE);
|
||||||
|
|
@ -2402,7 +2404,7 @@ self.kiri.license = exports.LICENSE;
|
||||||
// outputRetractOver: UC.newInput("retract over", {title:"move threshold that\ntriggers retraction\n0 to disable", convert:UC.toFloat, modes:FDM}),
|
// outputRetractOver: UC.newInput("retract over", {title:"move threshold that\ntriggers retraction\n0 to disable", convert:UC.toFloat, modes:FDM}),
|
||||||
outputRetractDist: UC.newInput("retract dist", {title:"amount to retract filament", convert:UC.toFloat, modes:FDM}),
|
outputRetractDist: UC.newInput("retract dist", {title:"amount to retract filament", convert:UC.toFloat, modes:FDM}),
|
||||||
outputRetractSpeed: UC.newInput("retract rate", {title:"speed of filament\nretraction in mm/s", convert:UC.toInt, modes:FDM}),
|
outputRetractSpeed: UC.newInput("retract rate", {title:"speed of filament\nretraction in mm/s", convert:UC.toInt, modes:FDM}),
|
||||||
outputRetractDwell: UC.newInput("retract dwell", {title:"time between re-engaging\nfilament and movement\nin seconds", convert:UC.toFloat, modes:FDM}),
|
outputRetractDwell: UC.newInput("retract dwell", {title:"time between re-engaging\nfilament and movement\nin milliseconds", convert:UC.toInt, modes:FDM}),
|
||||||
outputWipeSpeed: UC.newInput("wipe speed", {title:"speed while wiping\nnozzle in mm/s", convert:UC.toInt, modes:FDM}),
|
outputWipeSpeed: UC.newInput("wipe speed", {title:"speed while wiping\nnozzle in mm/s", convert:UC.toInt, modes:FDM}),
|
||||||
outputWipeDistance: UC.newInput("wipe distance", {title:"distance to wipe nozzle after\neach enclosed island completes\nin millimeters. 0 to disable", convert:UC.toInt, modes:FDM}),
|
outputWipeDistance: UC.newInput("wipe distance", {title:"distance to wipe nozzle after\neach enclosed island completes\nin millimeters. 0 to disable", convert:UC.toInt, modes:FDM}),
|
||||||
outputShortPoly: UC.newInput("short outline", {title:"poly perimeter length\ntriggers short slowdown\nin millimeters", bound:UC.bound(0,200), convert:UC.toFloat, modes:FDM}),
|
outputShortPoly: UC.newInput("short outline", {title:"poly perimeter length\ntriggers short slowdown\nin millimeters", bound:UC.bound(0,200), convert:UC.toFloat, modes:FDM}),
|
||||||
|
|
|
||||||
4
notes.md
4
notes.md
|
|
@ -59,10 +59,8 @@
|
||||||
|
|
||||||
# FDM todo
|
# FDM todo
|
||||||
|
|
||||||
* fix thin wall support fill artifacts with complex nested polys
|
|
||||||
* post re-engage dwell (on first layer?)
|
|
||||||
* add support expand value to multi-part spacing (which defaults to 1mm)
|
|
||||||
* add lay-flat auto-rotation or from selected face
|
* add lay-flat auto-rotation or from selected face
|
||||||
|
* determine start point from gcode preamble
|
||||||
* add rafts, manual supports
|
* add rafts, manual supports
|
||||||
* check for support / brim intersections on first layer
|
* check for support / brim intersections on first layer
|
||||||
* solid fill every other line, two passes. minimize heat/sag. better fill between
|
* solid fill every other line, two passes. minimize heat/sag. better fill between
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue