move fdm print funcs to fdm mode. code style update
This commit is contained in:
parent
8eed635c3f
commit
0dd617feeb
10 changed files with 5055 additions and 5088 deletions
2
app.js
2
app.js
|
|
@ -410,6 +410,7 @@ const script = {
|
|||
"geo/slicer",
|
||||
"geo/mesh",
|
||||
// "moto/broker",
|
||||
"kiri/consts",
|
||||
"kiri/pack",
|
||||
"kiri/utils",
|
||||
"kiri/slice",
|
||||
|
|
@ -459,6 +460,7 @@ const script = {
|
|||
"geo/polygon",
|
||||
"geo/gyroid",
|
||||
"geo/slicer",
|
||||
"kiri/consts",
|
||||
"kiri-mode/fdm/driver",
|
||||
"kiri-mode/fdm/slice",
|
||||
"kiri/utils",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,69 +4,66 @@
|
|||
|
||||
(function() {
|
||||
|
||||
const KIRI = self.kiri,
|
||||
BASE = self.base,
|
||||
UTIL = BASE.util,
|
||||
POLY = BASE.polygons,
|
||||
FDM = KIRI.driver.FDM = {
|
||||
// init, // src/mode/fdm/client.js
|
||||
// slice, // src/mode/fdm/slice.js
|
||||
// prepare, // src/mode/fdm/prepare.js
|
||||
// export, // src/mode/fdm/export.js
|
||||
getRangeParameters
|
||||
};
|
||||
const { kiri } = self;
|
||||
const FDM = kiri.driver.FDM = { getRangeParameters };
|
||||
|
||||
function getRangeParameters(process, index) {
|
||||
if (index === undefined || index === null || index < 0) {
|
||||
return process;
|
||||
}
|
||||
let ranges = process.ranges;
|
||||
if (!(ranges && ranges.length)) {
|
||||
return process;
|
||||
}
|
||||
let params = Object.clone(process);
|
||||
for (let range of ranges) {
|
||||
if (index >= range.lo && index <= range.hi) {
|
||||
for (let [key,value] of Object.entries(range.fields)) {
|
||||
params[key] = value;
|
||||
params._range = true;
|
||||
}
|
||||
// shared by client and worker contexts
|
||||
function getRangeParameters(process, index) {
|
||||
if (index === undefined || index === null || index < 0) {
|
||||
return process;
|
||||
}
|
||||
let ranges = process.ranges;
|
||||
if (!(ranges && ranges.length)) {
|
||||
return process;
|
||||
}
|
||||
let params = Object.clone(process);
|
||||
for (let range of ranges) {
|
||||
if (index >= range.lo && index <= range.hi) {
|
||||
for (let [key, value] of Object.entries(range.fields)) {
|
||||
params[key] = value;
|
||||
params._range = true;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
// defer loading until KIRI.client and KIRI.worker exist
|
||||
KIRI.load(function(API) {
|
||||
// defer loading until client and worker exist
|
||||
kiri.load(function(api) {
|
||||
|
||||
if (KIRI.client)
|
||||
// FDM.support_generate = KIRI.client.fdm_support_generate = function(ondone) {
|
||||
const { client, worker } = kiri;
|
||||
|
||||
if (client) {
|
||||
FDM.support_generate = function(ondone) {
|
||||
KIRI.client.clear();
|
||||
KIRI.client.sync();
|
||||
let settings = API.conf.get();
|
||||
let widgets = API.widgets.map();
|
||||
KIRI.client.send("fdm_support_generate", { settings }, (gen) => {
|
||||
client.clear();
|
||||
client.sync();
|
||||
const settings = api.conf.get();
|
||||
const widgets = api.widgets.map();
|
||||
client.send("fdm_support_generate", { settings }, (gen) => {
|
||||
if (gen && gen.error) {
|
||||
API.show.alert('support generation canceled');
|
||||
api.show.alert('support generation canceled');
|
||||
return ondone([]);
|
||||
}
|
||||
for (let g of gen) g.widget = widgets[g.id];
|
||||
for (let g of gen) {
|
||||
g.widget = widgets[g.id];
|
||||
}
|
||||
ondone(gen);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if (KIRI.worker)
|
||||
KIRI.worker.fdm_support_generate = function(data, send) {
|
||||
if (worker) {
|
||||
worker.fdm_support_generate = function(data, send) {
|
||||
const { settings } = data;
|
||||
const widgets = Object.values(wcache);
|
||||
const fresh = widgets.filter(widget => FDM.supports(settings, widget));
|
||||
send.done(KIRI.codec.encode(fresh.map(widget => { return {
|
||||
send.done(kiri.codec.encode(fresh.map(widget => { return {
|
||||
id: widget.id,
|
||||
supports: widget.supports,
|
||||
} } )));
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,317 +4,317 @@
|
|||
|
||||
(function() {
|
||||
|
||||
if (self.kiri.fill) return;
|
||||
if (self.kiri.fill) return;
|
||||
|
||||
const KIRI = self.kiri,
|
||||
BASE = self.base,
|
||||
UTIL = BASE.util,
|
||||
ROUND = UTIL.round,
|
||||
DEG2RAD = Math.PI / 180,
|
||||
FILL = self.kiri.fill = {
|
||||
hex: fillHexFull,
|
||||
grid: fillGrid,
|
||||
gyroid: fillGyroid,
|
||||
triangle: fillTriangle,
|
||||
linear: fillLinear,
|
||||
cubic: fillCubic
|
||||
},
|
||||
CACHE = self.kiri.fill_fixed = {
|
||||
hex: fillHexFull,
|
||||
grid: fillGrid,
|
||||
triangle: fillTriangle
|
||||
};
|
||||
const KIRI = self.kiri,
|
||||
BASE = self.base,
|
||||
UTIL = BASE.util,
|
||||
ROUND = UTIL.round,
|
||||
DEG2RAD = Math.PI / 180,
|
||||
FILL = self.kiri.fill = {
|
||||
hex: fillHexFull,
|
||||
grid: fillGrid,
|
||||
gyroid: fillGyroid,
|
||||
triangle: fillTriangle,
|
||||
linear: fillLinear,
|
||||
cubic: fillCubic
|
||||
},
|
||||
CACHE = self.kiri.fill_fixed = {
|
||||
hex: fillHexFull,
|
||||
grid: fillGrid,
|
||||
triangle: fillTriangle
|
||||
};
|
||||
|
||||
function fillHexFull(target) {
|
||||
fillHex(target, true);
|
||||
}
|
||||
function fillHexFull(target) {
|
||||
fillHex(target, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* emitter creates a hex infill pattern and sends to target
|
||||
*
|
||||
* @param {Object} target
|
||||
* @param {boolean} full continuous walls
|
||||
*/
|
||||
function fillHex(target, full) {
|
||||
// compute segment lengths (vert/horiz and 45)
|
||||
let spacing = target.offset();
|
||||
// let vhlen = (1 / target.density()) * (target.lineWidth() + spacing);
|
||||
let vhlen = (1 / target.density()) * target.lineWidth() * 0.5;
|
||||
let anxlen = ROUND(Math.cos(30 * DEG2RAD) * vhlen, 7);
|
||||
let anylen = ROUND(Math.sin(30 * DEG2RAD) * vhlen, 7);
|
||||
let bounds = target.bounds();
|
||||
let even = true;
|
||||
let evenZ = target.zIndex() % 2 === 0;
|
||||
let maxy = bounds.max.y + (vhlen + anylen * 2);
|
||||
let x, y;
|
||||
/**
|
||||
* emitter creates a hex infill pattern and sends to target
|
||||
*
|
||||
* @param {Object} target
|
||||
* @param {boolean} full continuous walls
|
||||
*/
|
||||
function fillHex(target, full) {
|
||||
// compute segment lengths (vert/horiz and 45)
|
||||
let spacing = target.offset();
|
||||
// let vhlen = (1 / target.density()) * (target.lineWidth() + spacing);
|
||||
let vhlen = (1 / target.density()) * target.lineWidth() * 0.5;
|
||||
let anxlen = ROUND(Math.cos(30 * DEG2RAD) * vhlen, 7);
|
||||
let anylen = ROUND(Math.sin(30 * DEG2RAD) * vhlen, 7);
|
||||
let bounds = target.bounds();
|
||||
let even = true;
|
||||
let evenZ = target.zIndex() % 2 === 0;
|
||||
let maxy = bounds.max.y + (vhlen + anylen * 2);
|
||||
let x, y;
|
||||
|
||||
if (full || evenZ) {
|
||||
x = bounds.min.x;
|
||||
for (;;) {
|
||||
if (even && x > bounds.max.x) break;
|
||||
if (!even && x > bounds.max.x + anxlen + spacing) break;
|
||||
y = bounds.min.y;
|
||||
target.newline();
|
||||
while (y <= maxy) {
|
||||
target.emit(x,y);
|
||||
y += vhlen;
|
||||
target.emit(x,y);
|
||||
if (even) x += anxlen; else x -= anxlen;
|
||||
y += anylen;
|
||||
target.emit(x,y);
|
||||
y += vhlen;
|
||||
target.emit(x,y);
|
||||
if (even) x -= anxlen; else x += anxlen;
|
||||
y += anylen;
|
||||
}
|
||||
x += spacing;
|
||||
if (even) x += (anxlen * 2);
|
||||
even = !even;
|
||||
target.newline();
|
||||
}
|
||||
} else {
|
||||
y = bounds.min.y + vhlen;
|
||||
for (;;) {
|
||||
if (even && y > bounds.max.y) break;
|
||||
if (!even && y > bounds.max.y + anylen) break;
|
||||
x = bounds.min.x;
|
||||
target.newline();
|
||||
while (x < bounds.max.x) {
|
||||
target.emit(x,y);
|
||||
if (even) y += anylen; else y -= anylen;
|
||||
x += anxlen;
|
||||
target.emit(x,y);
|
||||
x += spacing;
|
||||
target.emit(x,y);
|
||||
if (even) y -= anylen; else y += anylen;
|
||||
x += anxlen;
|
||||
target.emit(x,y);
|
||||
x += spacing;
|
||||
}
|
||||
y += vhlen;
|
||||
if (even) y += (anylen * 2);
|
||||
even = !even;
|
||||
target.newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fillGyroid(target) {
|
||||
let bounds = target.bounds();
|
||||
let height = target.zHeight();
|
||||
let span_x = bounds.max.x - bounds.min.x;
|
||||
let span_y = bounds.max.y - bounds.min.y;
|
||||
let density = target.density();
|
||||
let tile = 1 + (1 - density) * 15;
|
||||
let tile_x = span_x / tile;
|
||||
let tile_y = span_y / tile;
|
||||
let tile_z = 1 / tile;
|
||||
let gyroid = BASE.gyroid.slice(target.zValue() * tile_z, (1 - density) * 500);
|
||||
|
||||
// gyroid.polys.forEach(poly => {
|
||||
// for (let tx=0; tx<=tile_x; tx++) {
|
||||
// for (let ty=0; ty<=tile_y; ty++) {
|
||||
// target.newline();
|
||||
// let bx = tx * tile + bounds.min.x;
|
||||
// let by = ty * tile + bounds.min.y;
|
||||
// poly.forEach(point => {
|
||||
// target.emit(bx + point.x * tile, by + point.y * tile);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
let polys = [];
|
||||
for (let tx=0; tx<=tile_x; tx++) {
|
||||
for (let ty=0; ty<=tile_y; ty++) {
|
||||
for (let poly of gyroid.polys) {
|
||||
target.newline();
|
||||
let points = poly.map(el => {
|
||||
return {
|
||||
x: el.x * tile + tx * tile + bounds.min.x,
|
||||
y: el.y * tile + ty * tile + bounds.min.y,
|
||||
z: 0
|
||||
}
|
||||
});
|
||||
polys.push(BASE.newPolygon().setOpen(true).addObj(points));
|
||||
}
|
||||
}
|
||||
}
|
||||
polys = connectOpenPolys(polys);
|
||||
for (let poly of polys.filter(p => p.perimeter() > 2)) {
|
||||
if (full || evenZ) {
|
||||
x = bounds.min.x;
|
||||
for (;;) {
|
||||
if (even && x > bounds.max.x) break;
|
||||
if (!even && x > bounds.max.x + anxlen + spacing) break;
|
||||
y = bounds.min.y;
|
||||
target.newline();
|
||||
for (let point of poly.points) {
|
||||
target.emit(point.x, point.y);
|
||||
while (y <= maxy) {
|
||||
target.emit(x,y);
|
||||
y += vhlen;
|
||||
target.emit(x,y);
|
||||
if (even) x += anxlen; else x -= anxlen;
|
||||
y += anylen;
|
||||
target.emit(x,y);
|
||||
y += vhlen;
|
||||
target.emit(x,y);
|
||||
if (even) x -= anxlen; else x += anxlen;
|
||||
y += anylen;
|
||||
}
|
||||
x += spacing;
|
||||
if (even) x += (anxlen * 2);
|
||||
even = !even;
|
||||
target.newline();
|
||||
}
|
||||
} else {
|
||||
y = bounds.min.y + vhlen;
|
||||
for (;;) {
|
||||
if (even && y > bounds.max.y) break;
|
||||
if (!even && y > bounds.max.y + anylen) break;
|
||||
x = bounds.min.x;
|
||||
target.newline();
|
||||
while (x < bounds.max.x) {
|
||||
target.emit(x,y);
|
||||
if (even) y += anylen; else y -= anylen;
|
||||
x += anxlen;
|
||||
target.emit(x,y);
|
||||
x += spacing;
|
||||
target.emit(x,y);
|
||||
if (even) y -= anylen; else y += anylen;
|
||||
x += anxlen;
|
||||
target.emit(x,y);
|
||||
x += spacing;
|
||||
}
|
||||
y += vhlen;
|
||||
if (even) y += (anylen * 2);
|
||||
even = !even;
|
||||
target.newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fillGyroid(target) {
|
||||
let bounds = target.bounds();
|
||||
let height = target.zHeight();
|
||||
let span_x = bounds.max.x - bounds.min.x;
|
||||
let span_y = bounds.max.y - bounds.min.y;
|
||||
let density = target.density();
|
||||
let tile = 1 + (1 - density) * 15;
|
||||
let tile_x = span_x / tile;
|
||||
let tile_y = span_y / tile;
|
||||
let tile_z = 1 / tile;
|
||||
let gyroid = BASE.gyroid.slice(target.zValue() * tile_z, (1 - density) * 500);
|
||||
|
||||
// gyroid.polys.forEach(poly => {
|
||||
// for (let tx=0; tx<=tile_x; tx++) {
|
||||
// for (let ty=0; ty<=tile_y; ty++) {
|
||||
// target.newline();
|
||||
// let bx = tx * tile + bounds.min.x;
|
||||
// let by = ty * tile + bounds.min.y;
|
||||
// poly.forEach(point => {
|
||||
// target.emit(bx + point.x * tile, by + point.y * tile);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
let polys = [];
|
||||
for (let tx=0; tx<=tile_x; tx++) {
|
||||
for (let ty=0; ty<=tile_y; ty++) {
|
||||
for (let poly of gyroid.polys) {
|
||||
target.newline();
|
||||
let points = poly.map(el => {
|
||||
return {
|
||||
x: el.x * tile + tx * tile + bounds.min.x,
|
||||
y: el.y * tile + ty * tile + bounds.min.y,
|
||||
z: 0
|
||||
}
|
||||
});
|
||||
polys.push(BASE.newPolygon().setOpen(true).addObj(points));
|
||||
}
|
||||
}
|
||||
}
|
||||
polys = connectOpenPolys(polys);
|
||||
for (let poly of polys.filter(p => p.perimeter() > 2)) {
|
||||
target.newline();
|
||||
for (let point of poly.points) {
|
||||
target.emit(point.x, point.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function connectOpenPolys(noff, dist = 0.1) {
|
||||
if (noff.length <= 1) {
|
||||
return noff;
|
||||
}
|
||||
let heal = 0;
|
||||
// heal/rejoin open segments that have close endpoints
|
||||
outer: for(;; heal++) {
|
||||
let ntmp = noff, tlen = ntmp.length;
|
||||
for (let i=0; i<tlen; i++) {
|
||||
let s1 = ntmp[i];
|
||||
if (!s1 || !s1.open) continue;
|
||||
for (let j=i+1; j<tlen; j++) {
|
||||
let s2 = ntmp[j];
|
||||
if (!s2 || !s2.open) continue;
|
||||
if (s1.last().distTo2D(s2.first()) <= dist) {
|
||||
s1.addPoints(s2.points);
|
||||
ntmp[j] = null;
|
||||
continue outer;
|
||||
}
|
||||
if (s1.first().distTo2D(s2.last()) <= dist) {
|
||||
s2.addPoints(s1.points);
|
||||
ntmp[i] = null;
|
||||
continue outer;
|
||||
}
|
||||
if (s1.first().distTo2D(s2.first()) <= dist) {
|
||||
s1.reverse();
|
||||
s1.addPoints(s2.points);
|
||||
ntmp[j] = null;
|
||||
continue outer;
|
||||
}
|
||||
if (s1.last().distTo2D(s2.last()) <= dist) {
|
||||
s1.addPoints(s2.points.reverse());
|
||||
ntmp[j] = null;
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (heal > 0) {
|
||||
// cull nulls
|
||||
noff = noff.filter(o => o);
|
||||
}
|
||||
function connectOpenPolys(noff, dist = 0.1) {
|
||||
if (noff.length <= 1) {
|
||||
return noff;
|
||||
}
|
||||
|
||||
function fillGrid(target) {
|
||||
let bounds = target.bounds();
|
||||
let height = target.zHeight();
|
||||
let span_x = bounds.max.x - bounds.min.x;
|
||||
let span_y = bounds.max.y - bounds.min.y;
|
||||
let offset = target.offset() / 2;
|
||||
let tile = (1 / target.density()) * target.lineWidth();
|
||||
let tile_x = tile + offset;
|
||||
let tile_xc = span_x / tile_x;
|
||||
let tile_yc = span_y / tile;
|
||||
|
||||
for (let tx=0; tx<=tile_xc; tx++) {
|
||||
target.newline();
|
||||
for (let ty=0; ty<=tile_yc; ty++) {
|
||||
let bx = tx * tile_x + bounds.min.x;
|
||||
let by = ty * tile + bounds.min.y;
|
||||
if ((tx + ty) % 2) {
|
||||
target.emit(bx, by);
|
||||
target.emit(bx + tile_x - offset, by + tile);
|
||||
} else {
|
||||
target.emit(bx + tile_x - offset, by);
|
||||
target.emit(bx, by + tile);
|
||||
let heal = 0;
|
||||
// heal/rejoin open segments that have close endpoints
|
||||
outer: for(;; heal++) {
|
||||
let ntmp = noff, tlen = ntmp.length;
|
||||
for (let i=0; i<tlen; i++) {
|
||||
let s1 = ntmp[i];
|
||||
if (!s1 || !s1.open) continue;
|
||||
for (let j=i+1; j<tlen; j++) {
|
||||
let s2 = ntmp[j];
|
||||
if (!s2 || !s2.open) continue;
|
||||
if (s1.last().distTo2D(s2.first()) <= dist) {
|
||||
s1.addPoints(s2.points);
|
||||
ntmp[j] = null;
|
||||
continue outer;
|
||||
}
|
||||
if (s1.first().distTo2D(s2.last()) <= dist) {
|
||||
s2.addPoints(s1.points);
|
||||
ntmp[i] = null;
|
||||
continue outer;
|
||||
}
|
||||
if (s1.first().distTo2D(s2.first()) <= dist) {
|
||||
s1.reverse();
|
||||
s1.addPoints(s2.points);
|
||||
ntmp[j] = null;
|
||||
continue outer;
|
||||
}
|
||||
if (s1.last().distTo2D(s2.last()) <= dist) {
|
||||
s1.addPoints(s2.points.reverse());
|
||||
ntmp[j] = null;
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
function fillCubic(target) {
|
||||
let bounds = target.bounds();
|
||||
let span = Math.max(
|
||||
bounds.max.x - bounds.min.x,
|
||||
bounds.max.y - bounds.min.y
|
||||
);
|
||||
let steps = Math.floor((span / target.lineWidth()) * target.density());
|
||||
let step = span / steps;
|
||||
let ztype = Math.floor(target.zIndex() / target.repeat()) % 3;
|
||||
if (ztype === 1) {
|
||||
for (let tx=bounds.min.x; tx<=bounds.max.x; tx += step) {
|
||||
target.newline();
|
||||
target.emit(tx, bounds.min.y);
|
||||
target.emit(tx, bounds.max.y);
|
||||
}
|
||||
} else if (ztype === 0) {
|
||||
for (let ty=bounds.min.y; ty<=bounds.max.y; ty += step) {
|
||||
target.newline();
|
||||
target.emit(bounds.min.x, ty);
|
||||
target.emit(bounds.max.x, ty);
|
||||
}
|
||||
} else {
|
||||
step *- Math.sqrt(2);
|
||||
for (let tx=bounds.min.x; tx<=bounds.max.x; tx += step) {
|
||||
target.newline();
|
||||
target.emit(tx, bounds.min.y);
|
||||
target.emit(tx + 1000, bounds.max.y + 1000);
|
||||
}
|
||||
for (let ty=bounds.min.y; ty<=bounds.max.y; ty += step) {
|
||||
target.newline();
|
||||
target.emit(bounds.min.x, ty);
|
||||
target.emit(bounds.min.x + 1000, ty + 1000);
|
||||
}
|
||||
}
|
||||
if (heal > 0) {
|
||||
// cull nulls
|
||||
noff = noff.filter(o => o);
|
||||
}
|
||||
return noff;
|
||||
}
|
||||
|
||||
function fillLinear(target) {
|
||||
let bounds = target.bounds();
|
||||
let span = Math.max(
|
||||
bounds.max.x - bounds.min.x,
|
||||
bounds.max.y - bounds.min.y
|
||||
);
|
||||
let steps = Math.floor((span / target.lineWidth()) * target.density());
|
||||
let step = span / steps;
|
||||
let ztype = Math.floor(target.zIndex() / target.repeat()) % 2;
|
||||
if (ztype === 1) {
|
||||
for (let tx=bounds.min.x; tx<=bounds.max.x; tx += step) {
|
||||
target.newline();
|
||||
target.emit(tx, bounds.min.y);
|
||||
target.emit(tx, bounds.max.y);
|
||||
}
|
||||
} else if (ztype === 0) {
|
||||
for (let ty=bounds.min.y; ty<=bounds.max.y; ty += step) {
|
||||
target.newline();
|
||||
target.emit(bounds.min.x, ty);
|
||||
target.emit(bounds.max.x, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
function fillGrid(target) {
|
||||
let bounds = target.bounds();
|
||||
let height = target.zHeight();
|
||||
let span_x = bounds.max.x - bounds.min.x;
|
||||
let span_y = bounds.max.y - bounds.min.y;
|
||||
let offset = target.offset() / 2;
|
||||
let tile = (1 / target.density()) * target.lineWidth();
|
||||
let tile_x = tile + offset;
|
||||
let tile_xc = span_x / tile_x;
|
||||
let tile_yc = span_y / tile;
|
||||
|
||||
function fillTriangle(target) {
|
||||
let bounds = target.bounds();
|
||||
let span_x = bounds.max.x - bounds.min.x;
|
||||
let span_y = bounds.max.y - bounds.min.y;
|
||||
let offset = target.offset();
|
||||
let line_w = target.lineWidth() / 2;
|
||||
let tile = (1 / target.density()) * (target.lineWidth() * 1.25);
|
||||
let tile_x = tile + offset*2 + line_w;
|
||||
let tile_xc = span_x / tile_x;
|
||||
let tile_yc = span_y / tile;
|
||||
|
||||
for (let tx=0; tx<=tile_xc; tx++) {
|
||||
target.newline();
|
||||
for (let ty=0; ty<=tile_yc; ty++) {
|
||||
let bx = tx * tile_x + bounds.min.x;
|
||||
let by = ty * tile + bounds.min.y;
|
||||
if ((tx + ty) % 2) {
|
||||
target.emit(bx, by);
|
||||
target.emit(bx + tile_x - offset - line_w, by + tile);
|
||||
} else {
|
||||
target.emit(bx + tile_x - offset - line_w, by);
|
||||
target.emit(bx, by + tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let tx=0; tx<=tile_xc; tx++) {
|
||||
for (let tx=0; tx<=tile_xc; tx++) {
|
||||
target.newline();
|
||||
for (let ty=0; ty<=tile_yc; ty++) {
|
||||
let bx = tx * tile_x + bounds.min.x;
|
||||
let xp = bx + tile_x - line_w/2 - offset/2;
|
||||
target.newline();
|
||||
target.emit(xp, bounds.min.y);
|
||||
target.emit(xp, bounds.max.y);
|
||||
let by = ty * tile + bounds.min.y;
|
||||
if ((tx + ty) % 2) {
|
||||
target.emit(bx, by);
|
||||
target.emit(bx + tile_x - offset, by + tile);
|
||||
} else {
|
||||
target.emit(bx + tile_x - offset, by);
|
||||
target.emit(bx, by + tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fillCubic(target) {
|
||||
let bounds = target.bounds();
|
||||
let span = Math.max(
|
||||
bounds.max.x - bounds.min.x,
|
||||
bounds.max.y - bounds.min.y
|
||||
);
|
||||
let steps = Math.floor((span / target.lineWidth()) * target.density());
|
||||
let step = span / steps;
|
||||
let ztype = Math.floor(target.zIndex() / target.repeat()) % 3;
|
||||
if (ztype === 1) {
|
||||
for (let tx=bounds.min.x; tx<=bounds.max.x; tx += step) {
|
||||
target.newline();
|
||||
target.emit(tx, bounds.min.y);
|
||||
target.emit(tx, bounds.max.y);
|
||||
}
|
||||
} else if (ztype === 0) {
|
||||
for (let ty=bounds.min.y; ty<=bounds.max.y; ty += step) {
|
||||
target.newline();
|
||||
target.emit(bounds.min.x, ty);
|
||||
target.emit(bounds.max.x, ty);
|
||||
}
|
||||
} else {
|
||||
step *- Math.sqrt(2);
|
||||
for (let tx=bounds.min.x; tx<=bounds.max.x; tx += step) {
|
||||
target.newline();
|
||||
target.emit(tx, bounds.min.y);
|
||||
target.emit(tx + 1000, bounds.max.y + 1000);
|
||||
}
|
||||
for (let ty=bounds.min.y; ty<=bounds.max.y; ty += step) {
|
||||
target.newline();
|
||||
target.emit(bounds.min.x, ty);
|
||||
target.emit(bounds.min.x + 1000, ty + 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fillLinear(target) {
|
||||
let bounds = target.bounds();
|
||||
let span = Math.max(
|
||||
bounds.max.x - bounds.min.x,
|
||||
bounds.max.y - bounds.min.y
|
||||
);
|
||||
let steps = Math.floor((span / target.lineWidth()) * target.density());
|
||||
let step = span / steps;
|
||||
let ztype = Math.floor(target.zIndex() / target.repeat()) % 2;
|
||||
if (ztype === 1) {
|
||||
for (let tx=bounds.min.x; tx<=bounds.max.x; tx += step) {
|
||||
target.newline();
|
||||
target.emit(tx, bounds.min.y);
|
||||
target.emit(tx, bounds.max.y);
|
||||
}
|
||||
} else if (ztype === 0) {
|
||||
for (let ty=bounds.min.y; ty<=bounds.max.y; ty += step) {
|
||||
target.newline();
|
||||
target.emit(bounds.min.x, ty);
|
||||
target.emit(bounds.max.x, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fillTriangle(target) {
|
||||
let bounds = target.bounds();
|
||||
let span_x = bounds.max.x - bounds.min.x;
|
||||
let span_y = bounds.max.y - bounds.min.y;
|
||||
let offset = target.offset();
|
||||
let line_w = target.lineWidth() / 2;
|
||||
let tile = (1 / target.density()) * (target.lineWidth() * 1.25);
|
||||
let tile_x = tile + offset*2 + line_w;
|
||||
let tile_xc = span_x / tile_x;
|
||||
let tile_yc = span_y / tile;
|
||||
|
||||
for (let tx=0; tx<=tile_xc; tx++) {
|
||||
target.newline();
|
||||
for (let ty=0; ty<=tile_yc; ty++) {
|
||||
let bx = tx * tile_x + bounds.min.x;
|
||||
let by = ty * tile + bounds.min.y;
|
||||
if ((tx + ty) % 2) {
|
||||
target.emit(bx, by);
|
||||
target.emit(bx + tile_x - offset - line_w, by + tile);
|
||||
} else {
|
||||
target.emit(bx + tile_x - offset - line_w, by);
|
||||
target.emit(bx, by + tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let tx=0; tx<=tile_xc; tx++) {
|
||||
let bx = tx * tile_x + bounds.min.x;
|
||||
let xp = bx + tile_x - line_w/2 - offset/2;
|
||||
target.newline();
|
||||
target.emit(xp, bounds.min.y);
|
||||
target.emit(xp, bounds.max.y);
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -131,6 +131,7 @@ kiri.consts = {
|
|||
MODES,
|
||||
VIEWS,
|
||||
SEED,
|
||||
beltfact: Math.cos(Math.PI / 4)
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
const { feature, platform, selection, settings } = api;
|
||||
const { COLOR, MODES, PMODES, VIEWS } = consts;
|
||||
|
||||
const LANG = lang.current,
|
||||
const LANG = lang.current,
|
||||
WIN = self.window,
|
||||
DOC = self.document,
|
||||
LOC = self.location,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
const { base, kiri } = self;
|
||||
const { paths, util, newPoint, Polygon } = base;
|
||||
const { tip2tipEmit } = paths;
|
||||
const { numOrDefault } = util;
|
||||
const { beltfact } = kiri.consts;
|
||||
|
||||
kiri.newPrint = function(settings, widgets, id) {
|
||||
return new Print(settings, widgets, id);
|
||||
|
|
@ -70,7 +72,7 @@ class Print {
|
|||
const { process } = settings;
|
||||
|
||||
let shortDist = process.outputShortDistance,
|
||||
shellMult = pref(options.extrude, process.outputShellMult),
|
||||
shellMult = numOrDefault(options.extrude, process.outputShellMult),
|
||||
printSpeed = options.rate || process.outputFeedrate,
|
||||
moveSpeed = process.outputSeekrate,
|
||||
minSpeed = process.outputMinSpeed,
|
||||
|
|
@ -169,638 +171,6 @@ class Print {
|
|||
}
|
||||
}
|
||||
|
||||
// fdm only
|
||||
slicePrintPath(slice, startPoint, offset, output, opt = {}) {
|
||||
const scope = this;
|
||||
const { settings } = scope;
|
||||
const { device } = settings;
|
||||
|
||||
// console.log({slicePrintPath: slice.index, ext:slice.extruder});
|
||||
let i,
|
||||
preout = [],
|
||||
process = opt.params || settings.process,
|
||||
extruder = slice.extruder || 0,
|
||||
nozzleSize = device.extruders[extruder].extNozzle,
|
||||
firstLayer = opt.first || false,
|
||||
thinWall = nozzleSize * (opt.thinWall || 1.75),
|
||||
retractDist = opt.retractOver || 2,
|
||||
solidWidth = process.sliceFillWidth || 1,
|
||||
fillMult = opt.mult || process.outputFillMult,
|
||||
shellMult = opt.mult || process.outputShellMult || (process.laserSliceHeight >= 0 ? 1 : 0),
|
||||
shellOrder = {"out-in":-1,"in-out":1}[process.sliceShellOrder] || -1,
|
||||
sparseMult = process.outputSparseMult,
|
||||
coastDist = process.outputCoastDist || 0,
|
||||
finishSpeed = opt.speed || process.outputFinishrate,
|
||||
firstShellSpeed = process.firstLayerRate,
|
||||
firstFillSpeed = process.firstLayerFillRate,
|
||||
firstPrintMult = process.firstLayerPrintMult,
|
||||
printSpeed = opt.speed || (firstLayer ? firstShellSpeed : process.outputFeedrate),
|
||||
fillSpeed = opt.speed || opt.fillSpeed || (firstLayer ? firstFillSpeed || firstShellSpeed : process.outputFeedrate),
|
||||
infillSpeed = process.sliceFillRate || opt.infillSpeed || fillSpeed || printSpeed,
|
||||
moveSpeed = process.outputSeekrate,
|
||||
origin = startPoint.add(offset),
|
||||
zhop = process.zHopDistance || 0,
|
||||
antiBacklash = process.antiBacklash,
|
||||
wipeDist = process.outputRetractWipe || 0,
|
||||
isBelt = device.bedBelt,
|
||||
beltFirst = process.outputBeltFirst || false,
|
||||
startClone = startPoint.clone(),
|
||||
seedPoint = opt.seedPoint || startPoint,
|
||||
z = slice.z,
|
||||
lastPoly;
|
||||
|
||||
// apply first layer extrusion multipliers
|
||||
if (firstLayer) {
|
||||
fillMult *= firstPrintMult;
|
||||
shellMult *= firstPrintMult;
|
||||
sparseMult *= firstPrintMult;
|
||||
}
|
||||
|
||||
function retract() {
|
||||
let array = preout.length ? preout : output;
|
||||
if (array.length) {
|
||||
let last = array.last();
|
||||
last.retract = true;
|
||||
if (wipeDist && lastPoly && last.point) {
|
||||
let endpoint = last.point.followTo(lastPoly.center(true), wipeDist);
|
||||
if (endpoint.inPolygon(lastPoly)) {
|
||||
scope.addOutput(array, endpoint);
|
||||
}
|
||||
}
|
||||
} else if (opt.pretract) {
|
||||
opt.pretract(wipeDist);
|
||||
} else {
|
||||
console.log('unable to retract. no preout or output');
|
||||
}
|
||||
}
|
||||
|
||||
function intersectsTop(p1, p2) {
|
||||
if (slice.index < 0) {
|
||||
return false;
|
||||
}
|
||||
let int = false;
|
||||
slice.topPolysFlat().forEach((poly) => {
|
||||
if (!int) poly.forEachSegment((s1, s2) => {
|
||||
if (util.intersect(p1,p2,s1,s2,base.key.SEGINT)) {
|
||||
return int = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
// if intersecting, look for a route around
|
||||
if (int && opt.routeAround) {
|
||||
return !routeAround(p1, p2);
|
||||
}
|
||||
return int;
|
||||
}
|
||||
|
||||
// returns true if routed around or no retract requried
|
||||
function routeAround(p1, p2) {
|
||||
const dbug = false;
|
||||
if (dbug === slice.index) console.log(slice.index, {p1, p2, d: p1.distTo2D(p2)});
|
||||
|
||||
let ints = [];
|
||||
let tops = slice.topRouteFlat();
|
||||
for (let poly of tops) {
|
||||
poly.forEachSegment((s1, s2) => {
|
||||
let ip = util.intersect(p1,p2,s1,s2,base.key.SEGINT);
|
||||
if (ip) {
|
||||
ints.push({ip, poly});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// no intersections
|
||||
if (ints.length === 0) {
|
||||
if (dbug === slice.index) console.log(slice.index, 'no ints');
|
||||
return false;
|
||||
}
|
||||
|
||||
// odd # of intersections ?!? do retraction
|
||||
if (ints.length && ints.length % 2 !== 0) {
|
||||
if (dbug === slice.index) console.log(slice.index, {odd_intersects: ints});
|
||||
return false;
|
||||
}
|
||||
|
||||
// sort by distance
|
||||
ints.sort((a, b) => {
|
||||
return a.ip.dist - b.ip.dist;
|
||||
});
|
||||
|
||||
if (dbug === slice.index) console.log(slice.index, {ints});
|
||||
|
||||
// check pairs. eliminate too close points.
|
||||
// pairs must intersect same poly or retract.
|
||||
for (let i=0; i<ints.length; i += 2) {
|
||||
let i1 = ints[i];
|
||||
let i2 = ints[i+1];
|
||||
// different poly. force retract
|
||||
if (i1.poly !== i2.poly) {
|
||||
if (dbug === slice.index) console.log(slice.index, {int_diff_poly: ints, i});
|
||||
return false;
|
||||
}
|
||||
// mark invalid intersect pairs (low or zero dist, etc)
|
||||
// TODO: only if this is the outer pair and there are closer inner pairs
|
||||
if (i1.ip.distTo2D(i2.ip) < retractDist) {
|
||||
if (dbug === slice.index) console.log(slice.index, {int_dist_too_small: i1.ip.distTo2D(i2.ip), retractDist});
|
||||
ints[i] = undefined;
|
||||
ints[i+1] = undefined;
|
||||
}
|
||||
}
|
||||
// filter out invalid intersection pairs
|
||||
ints = ints.filter(i => i);
|
||||
|
||||
if (ints.length > 2) {
|
||||
if (dbug === slice.index) console.log(slice.index, {complex_route: ints.length});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ints.length === 2) {
|
||||
// can route around intersected top polys
|
||||
for (let i=0; i<ints.length; i += 2) {
|
||||
let i1 = ints[0];
|
||||
let i2 = ints[1];
|
||||
|
||||
// output first point
|
||||
scope.addOutput(preout, i1.ip, 0, moveSpeed, extruder);
|
||||
|
||||
// create two loops around poly
|
||||
// find shortest of two paths and emit poly points
|
||||
let poly = i1.poly;
|
||||
let isCW = poly.isClockwise();
|
||||
let points = poly.points;
|
||||
|
||||
let p1p = isCW ? points : points.slice().reverse(); // CW
|
||||
let p2p = isCW ? points.slice().reverse() : points; // CCW
|
||||
|
||||
let r1s = p1p.indexOf(isCW ? i1.ip.p2 : i1.ip.p1);
|
||||
let r1e = p1p.indexOf(isCW ? i2.ip.p1 : i2.ip.p2);
|
||||
|
||||
let r1 = r1s === r1e ?
|
||||
[ p1p[r1s] ] : r1s < r1e ?
|
||||
[ ...p1p.slice(r1s,r1e+1) ] :
|
||||
[ ...p1p.slice(r1s), ...p1p.slice(0,r1e+1) ];
|
||||
|
||||
let r1d = 0;
|
||||
for (let i=1; i<r1.length; i++) {
|
||||
r1d += r1[i-1].distTo2D(r1[i]);
|
||||
}
|
||||
|
||||
let r2s = p2p.indexOf(isCW ? i1.ip.p1 : i1.ip.p2);
|
||||
let r2e = p2p.indexOf(isCW ? i2.ip.p2 : i2.ip.p1);
|
||||
|
||||
let r2 = r2s === r2e ?
|
||||
[ p2p[r2s] ] : r2s < r2e ?
|
||||
[ ...p2p.slice(r2s,r2e+1) ] :
|
||||
[ ...p2p.slice(r2s), ...p2p.slice(0,r2e+1) ];
|
||||
|
||||
let r2d = 0;
|
||||
for (let i=1; i<r2.length; i++) {
|
||||
r2d += r2[i-1].distTo2D(r2[i]);
|
||||
}
|
||||
|
||||
let route = r1d <= r2d ? r1 : r2;
|
||||
|
||||
if (dbug === slice.index) console.log(slice.index, {
|
||||
ints: ints.map(i=>i.ip.dist),
|
||||
i1, i2, same: i1.poly === i2.poly,
|
||||
route,
|
||||
p1, p2, dist: p1.distTo2D(p2),
|
||||
r1, r1d, r1s, r1e,
|
||||
r2, r2d, r2s, r2e,
|
||||
isCW});
|
||||
|
||||
for (let p of route) {
|
||||
scope.addOutput(preout, p, 0, moveSpeed, extruder);
|
||||
}
|
||||
|
||||
// output last point
|
||||
scope.addOutput(preout, i2.ip, 0, moveSpeed, extruder);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function outputTraces(poly, opt = {}) {
|
||||
if (!poly) return;
|
||||
if (Array.isArray(poly)) {
|
||||
if (opt.sort) {
|
||||
let polys = poly.slice().sort((a,b) => {
|
||||
return (a.perimeter() - b.perimeter()) * opt.sort;
|
||||
});
|
||||
let debug = polys.length > 3;
|
||||
let last;
|
||||
while (polys.length) {
|
||||
let next;
|
||||
for (let p of polys) {
|
||||
if (!last) {
|
||||
next = p;
|
||||
break;
|
||||
}
|
||||
if (opt.sort > 0) {
|
||||
// in-out
|
||||
if (last.isInside(p)) {
|
||||
next = p;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// out-in
|
||||
if (p.isInside(last)) {
|
||||
next = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (next) {
|
||||
last = next;
|
||||
polys.remove(next);
|
||||
outputTraces(next, opt);
|
||||
} else {
|
||||
last = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outputOrderClosest(poly, function(next) {
|
||||
outputTraces(next, opt);
|
||||
}, null);
|
||||
}
|
||||
} else {
|
||||
let finishShell = poly.depth === 0 && !firstLayer;
|
||||
startPoint = scope.polyPrintPath(poly, startPoint, preout, {
|
||||
tool: extruder,
|
||||
rate: finishShell ? finishSpeed : printSpeed,
|
||||
accel: finishShell,
|
||||
wipe: process.outputWipeDistance || 0,
|
||||
coast: firstLayer ? 0 : coastDist,
|
||||
extrude: pref(opt.extrude, shellMult),
|
||||
onfirst: function(firstPoint) {
|
||||
let from = seedPoint || startPoint;
|
||||
if (from.distTo2D(firstPoint) > retractDist) {
|
||||
if (intersectsTop(from, firstPoint)) {
|
||||
retract();
|
||||
}
|
||||
}
|
||||
seedPoint = null;
|
||||
}
|
||||
});
|
||||
lastPoly = slice.lastPoly = poly;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Polygon[]} polys
|
||||
*/
|
||||
function outputSparse(polys, extrude, speed) {
|
||||
if (!polys) return;
|
||||
let proxy = polys.map((poly) => {
|
||||
return {poly: poly, first: poly.first(), last: poly.last()};
|
||||
});
|
||||
let lp = startPoint;
|
||||
startPoint = tip2tipEmit(proxy, startPoint, (el, point, count) => {
|
||||
let poly = el.poly;
|
||||
if (poly.last() === point) {
|
||||
poly.reverse();
|
||||
}
|
||||
poly.forEachPoint((p, i) => {
|
||||
let dist = lp.distTo2D(p);
|
||||
let rdst = dist > retractDist;
|
||||
let itop = rdst && intersectsTop(lp,p);
|
||||
let emit = extrude;
|
||||
// retract if dist trigger and crosses a slice top polygon
|
||||
if (i === 0) {
|
||||
if (itop) {
|
||||
retract();
|
||||
emit = 0;
|
||||
} else if (dist > nozzleSize) {
|
||||
emit = 0;
|
||||
}
|
||||
}
|
||||
// let emit = i === 0 ? 0 : extrude;
|
||||
// handle shallow cloned infill
|
||||
if (poly.z !== undefined) {
|
||||
p = p.clone().setZ(poly.z);
|
||||
}
|
||||
scope.addOutput(preout, p, emit, speed || printSpeed, extruder);
|
||||
lp = p;
|
||||
}, !poly.open);
|
||||
return lp;
|
||||
});
|
||||
}
|
||||
|
||||
function outputThin(lines) {
|
||||
if (!lines) {
|
||||
return;
|
||||
}
|
||||
let points = lines.group(2).map(grp => {
|
||||
let [ p1, p2 ] = grp;
|
||||
return newPoint(
|
||||
(p1.x + p2.x) / 2,
|
||||
(p1.y + p2.y) / 2,
|
||||
(p1.z + p2.z) / 2
|
||||
)
|
||||
});
|
||||
let order = util.orderClosest(points, (p1, p2) => p1.distTo2D(p2));
|
||||
if (order.length === 0) {
|
||||
return;
|
||||
}
|
||||
let first = points[0];
|
||||
let last = first;
|
||||
scope.addOutput(preout, first, 0, moveSpeed, extruder);
|
||||
for (let p of order) {
|
||||
let dist = last ? last.distTo2D(p) : 0;
|
||||
if (dist > thinWall) {
|
||||
retract();
|
||||
scope.addOutput(preout, p, 0, moveSpeed, extruder);
|
||||
}
|
||||
scope.addOutput(preout, p, 1, fillSpeed, extruder);
|
||||
last = p;
|
||||
}
|
||||
// close a circle
|
||||
if (last && last.distTo2D(first) <= thinWall) {
|
||||
scope.addOutput(preout, first, 1, fillSpeed, extruder);
|
||||
}
|
||||
}
|
||||
|
||||
function outputFills(lines, opt = {}) {
|
||||
if (!lines || lines.length === 0) {
|
||||
return;
|
||||
}
|
||||
let p, p1, p2, dist, len, found, group, mindist, t1, t2,
|
||||
marked = 0,
|
||||
start = 0,
|
||||
skip = false,
|
||||
lastIndex = -1,
|
||||
flow = opt.flow || 1,
|
||||
near = opt.near || false,
|
||||
fast = opt.fast || false,
|
||||
fill = (opt.fill >= 0 ? opt.fill : fillMult) * flow,
|
||||
thinDist = near ? thinWall : thinWall;
|
||||
|
||||
while (lines && marked < lines.length) {
|
||||
group = null;
|
||||
found = false;
|
||||
mindist = Infinity;
|
||||
|
||||
// use next nearest line strategy
|
||||
if (near)
|
||||
for (i=0; i<lines.length; i += 2) {
|
||||
t1 = lines[i];
|
||||
if (t1.del) {
|
||||
continue;
|
||||
}
|
||||
t2 = lines[i+1];
|
||||
let d1 = t1.distToSq2D(startPoint);
|
||||
let d2 = t2.distToSq2D(startPoint);
|
||||
if (d1 < mindist || d2 < mindist) {
|
||||
if (d2 < d1) {
|
||||
p2 = t1;
|
||||
p1 = t2;
|
||||
} else {
|
||||
p1 = t1;
|
||||
p2 = t2;
|
||||
}
|
||||
mindist = Math.min(d1, d2);
|
||||
lastIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// use next index line strategy
|
||||
// order all points by distance to last point
|
||||
if (!near)
|
||||
for (i=start; i<lines.length; i += 2) {
|
||||
p = lines[i];
|
||||
if (p.del) {
|
||||
continue;
|
||||
}
|
||||
if (group === null && p.index > lastIndex) {
|
||||
group = p.index;
|
||||
}
|
||||
if (group !== null) {
|
||||
if (p.index !== group) {
|
||||
break;
|
||||
}
|
||||
if (p.index % 2 === 0) {
|
||||
t1 = lines[i];
|
||||
t2 = lines[i+1];
|
||||
} else {
|
||||
t2 = lines[i];
|
||||
t1 = lines[i+1];
|
||||
}
|
||||
dist = Math.min(t1.distTo2D(startPoint), t2.distTo2D(startPoint));
|
||||
if (dist < mindist) {
|
||||
p1 = t1;
|
||||
p2 = t2;
|
||||
mindist = dist;
|
||||
}
|
||||
start = i;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
// go back to start and try again
|
||||
if (!near && !found) {
|
||||
if (start === 0 && lastIndex === -1) {
|
||||
console.log('infinite loop', lines, {
|
||||
marked, i, group, start, lastIndex,
|
||||
points: lines.map(p => p.index).join(', ')
|
||||
});
|
||||
break;
|
||||
}
|
||||
start = 0;
|
||||
lastIndex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
dist = startPoint.distToSq2D(p1);
|
||||
len = p1.distToSq2D(p2);
|
||||
|
||||
// go back to start when dist > retractDist
|
||||
if (!near && !fast && !skip && dist > retractDist) {
|
||||
skip = true;
|
||||
start = 0;
|
||||
lastIndex = -1;
|
||||
continue;
|
||||
}
|
||||
skip = false;
|
||||
|
||||
// mark as used (temporarily)
|
||||
p1.del = true;
|
||||
p2.del = true;
|
||||
marked += 2;
|
||||
lastIndex = p1.index;
|
||||
|
||||
// if dist to new segment is less than thinWall
|
||||
// and segment length is less than thinWall then
|
||||
// just extrude to midpoint of next segment. this is
|
||||
// to avoid shaking the printer to death.
|
||||
if (dist <= thinDist && len <= thinDist) {
|
||||
p2 = p1.midPointTo(p2);
|
||||
// this.addOutput(preout, p2, fill * (dist / thinWall), fillSpeed, extruder);
|
||||
scope.addOutput(preout, p2, fill, fillSpeed, extruder);
|
||||
} else {
|
||||
// retract if dist trigger or crosses a slice top polygon
|
||||
if (!fast && dist > retractDist && (zhop || intersectsTop(startPoint, p1))) {
|
||||
retract();
|
||||
}
|
||||
|
||||
// anti-backlash on longer move
|
||||
if (!fast && antiBacklash && dist > retractDist) {
|
||||
scope.addOutput(preout, p1.add({x:antiBacklash,y:-antiBacklash,z:0}), 0, moveSpeed, extruder);
|
||||
}
|
||||
|
||||
// bridge ends of fill when they're close together
|
||||
if (dist < thinDist) {
|
||||
scope.addOutput(preout, p1, fill, fillSpeed, extruder);
|
||||
} else {
|
||||
scope.addOutput(preout, p1, 0, moveSpeed, extruder);
|
||||
}
|
||||
|
||||
scope.addOutput(preout, p2, fill, fillSpeed, extruder);
|
||||
}
|
||||
|
||||
startPoint = p2;
|
||||
}
|
||||
|
||||
// clear delete marks so we can re-print later
|
||||
if (lines) lines.forEach(p => { p.del = false });
|
||||
}
|
||||
|
||||
/**
|
||||
* given array of polygons, emit them in next closest order with
|
||||
* the special exception that depth is considered into distance
|
||||
* so that inner polygons are emitted first.
|
||||
*
|
||||
* @param {Array} array of Polygons or Polygon wrappers (tops)
|
||||
* @param {Function} fn call to emit next candidate
|
||||
* @param {Function} fnp convert 'next' object into a Polygon for closeness
|
||||
*/
|
||||
function outputOrderClosest(array, fn, fnp) {
|
||||
if (array.length === 1) {
|
||||
return fn(array[0]);
|
||||
}
|
||||
array = array.slice();
|
||||
let closest, find, next, order, poly, lastDepth = 0;
|
||||
for (;;) {
|
||||
order = [];
|
||||
closest = null;
|
||||
for (i=0; i<array.length; i++) {
|
||||
next = array[i];
|
||||
if (!next) continue;
|
||||
poly = fnp ? fnp(next) : next;
|
||||
find = poly.findClosestPointTo(startPoint);
|
||||
order.push({
|
||||
i: i,
|
||||
n: next,
|
||||
d: find.distance - (poly.depth * thinWall),
|
||||
});
|
||||
}
|
||||
if (order.length === 0) {
|
||||
return;
|
||||
}
|
||||
order.sort((a,b) => {
|
||||
return a.d - b.d;
|
||||
});
|
||||
array[order[0].i] = null;
|
||||
fn(order[0].n);
|
||||
}
|
||||
}
|
||||
|
||||
let out = [];
|
||||
if (slice.tops) {
|
||||
out.appendAll(slice.tops);
|
||||
};
|
||||
if (opt.support && slice.supports) {
|
||||
out.appendAll(slice.supports);
|
||||
}
|
||||
|
||||
let lastTop = null;
|
||||
outputOrderClosest(out, function(next) {
|
||||
if (next instanceof Polygon) {
|
||||
scope.setType('support');
|
||||
// support polygon
|
||||
next.setZ(z);
|
||||
outputTraces([next].appendAll(next.inner || []));
|
||||
if (next.fill) {
|
||||
next.fill.forEach(p => { p.z = z });
|
||||
outputFills(next.fill, {fast: true});
|
||||
}
|
||||
} else {
|
||||
scope.setType('shells');
|
||||
if (lastTop && lastTop !== next) {
|
||||
retract();
|
||||
}
|
||||
|
||||
// control of layer start point
|
||||
switch (process.sliceLayerStart) {
|
||||
case "center":
|
||||
startPoint = newPoint(0,0,startPoint.z);
|
||||
break;
|
||||
case "origin":
|
||||
startPoint = origin.clone();
|
||||
break;
|
||||
}
|
||||
|
||||
// optimize start point on belt for tops touching belt
|
||||
// and enforce optimal shell order (outer first)
|
||||
if (isBelt && opt.onBelt) {
|
||||
startPoint = startClone;
|
||||
if (beltFirst) {
|
||||
shellOrder = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// innermost shells
|
||||
let inner = next.innerShells() || [];
|
||||
|
||||
// output inner polygons
|
||||
if (shellOrder === 1) outputTraces(inner, { sort: shellOrder });
|
||||
|
||||
outputTraces(next.shells, { sort: shellOrder });
|
||||
|
||||
// output outer polygons
|
||||
if (shellOrder === -1) outputTraces(inner, { sort: shellOrder });
|
||||
|
||||
// output thin fill
|
||||
scope.setType('thin fill');
|
||||
outputThin(next.thin_fill);
|
||||
|
||||
// then output solid and sparse fill
|
||||
scope.setType('solid fill');
|
||||
outputFills(next.fill_lines, {flow: solidWidth});
|
||||
|
||||
scope.setType('sparse infill');
|
||||
outputSparse(next.fill_sparse, sparseMult, infillSpeed);
|
||||
|
||||
lastTop = next;
|
||||
}
|
||||
}, function(obj) {
|
||||
// for tops
|
||||
return obj instanceof Polygon ? obj : obj.poly;
|
||||
});
|
||||
|
||||
// produce polishing paths when present
|
||||
if (slice.tops.length && slice.tops[0].polish) {
|
||||
let {x,y} = slice.tops[0].polish;
|
||||
if (x) {
|
||||
outputSparse(x, 0, process.polishSpeed);
|
||||
}
|
||||
if (y) {
|
||||
outputSparse(y, 0, process.polishSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
// offset print points
|
||||
for (i=0; i<preout.length; i++) {
|
||||
preout[i].point = preout[i].point.add(offset);
|
||||
}
|
||||
|
||||
// add offset points to total print
|
||||
this.addPrintPoints(preout, output, origin, extruder);
|
||||
|
||||
return startPoint.add(offset);
|
||||
}
|
||||
|
||||
parseSVG(code, offset) {
|
||||
let scope = this,
|
||||
svg = new DOMParser().parseFromString(code, 'text/xml'),
|
||||
|
|
@ -890,7 +260,6 @@ class Print {
|
|||
|
||||
const output = scope.output = [ seq ];
|
||||
const beltaxis = { X: "X", Y: "Z", Z: "Y", E: "E", F: "F" };
|
||||
const beltfact = Math.cos(Math.PI / 4);
|
||||
|
||||
function LOG() {
|
||||
console.log(...[...arguments].map(o => Object.clone(o)));
|
||||
|
|
@ -1181,10 +550,6 @@ class Output {
|
|||
}
|
||||
}
|
||||
|
||||
function pref(a,b) {
|
||||
return a !== undefined ? a : b;
|
||||
}
|
||||
|
||||
kiri.Print = Print;
|
||||
|
||||
})();
|
||||
|
|
|
|||
Loading…
Reference in a new issue