Merge branch 'rel-4.1'
This commit is contained in:
commit
d8d36b3448
76 changed files with 6431 additions and 1842 deletions
|
|
@ -5,7 +5,6 @@
|
|||
"add/array",
|
||||
"add/class",
|
||||
"ext/three",
|
||||
"ext/three-bgu",
|
||||
"add/three",
|
||||
"ext/clip2",
|
||||
"ext/earcut",
|
||||
|
|
|
|||
72
src/ext/md5.js
Normal file
72
src/ext/md5.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// SOURCE: https://stackoverflow.com/questions/1655769/fastest-md5-implementation-in-javascript
|
||||
gapp.register("ext.md5", [], (root, exports) => {
|
||||
|
||||
exports({ hash });
|
||||
|
||||
function hash(e) {
|
||||
function h(a, b) {
|
||||
var c, d, e, f, g;
|
||||
e = a & 2147483648;
|
||||
f = b & 2147483648;
|
||||
c = a & 1073741824;
|
||||
d = b & 1073741824;
|
||||
g = (a & 1073741823) + (b & 1073741823);
|
||||
return c & d ? g ^ 2147483648 ^ e ^ f : c | d ? g & 1073741824 ? g ^ 3221225472 ^ e ^ f : g ^ 1073741824 ^ e ^ f : g ^ e ^ f
|
||||
}
|
||||
|
||||
function k(a, b, c, d, e, f, g) {
|
||||
a = h(a, h(h(b & c | ~b & d, e), g));
|
||||
return h(a << f | a >>> 32 - f, b)
|
||||
}
|
||||
|
||||
function l(a, b, c, d, e, f, g) {
|
||||
a = h(a, h(h(b & d | c & ~d, e), g));
|
||||
return h(a << f | a >>> 32 - f, b)
|
||||
}
|
||||
|
||||
function m(a, b, d, c, e, f, g) {
|
||||
a = h(a, h(h(b ^ d ^ c, e), g));
|
||||
return h(a << f | a >>> 32 - f, b)
|
||||
}
|
||||
|
||||
function n(a, b, d, c, e, f, g) {
|
||||
a = h(a, h(h(d ^ (b | ~c), e), g));
|
||||
return h(a << f | a >>> 32 - f, b)
|
||||
}
|
||||
|
||||
function p(a) {
|
||||
var b = "",
|
||||
d = "",
|
||||
c;
|
||||
for (c = 0; 3 >= c; c++) d = a >>> 8 * c & 255, d = "0" + d.toString(16), b += d.substr(d.length - 2, 2);
|
||||
return b
|
||||
}
|
||||
var f = [],
|
||||
q, r, s, t, a, b, c, d;
|
||||
e = function(a) {
|
||||
a = a.replace(/\r\n/g, "\n");
|
||||
for (var b = "", d = 0; d < a.length; d++) {
|
||||
var c = a.charCodeAt(d);
|
||||
128 > c ? b += String.fromCharCode(c) : (127 < c && 2048 > c ? b += String.fromCharCode(c >> 6 | 192) : (b += String.fromCharCode(c >> 12 | 224), b += String.fromCharCode(c >> 6 & 63 | 128)), b += String.fromCharCode(c & 63 | 128))
|
||||
}
|
||||
return b
|
||||
}(e);
|
||||
f = function(b) {
|
||||
var a, c = b.length;
|
||||
a = c + 8;
|
||||
for (var d = 16 * ((a - a % 64) / 64 + 1), e = Array(d - 1), f = 0, g = 0; g < c;) a = (g - g % 4) / 4, f = g % 4 * 8, e[a] |= b.charCodeAt(g) << f, g++;
|
||||
a = (g - g % 4) / 4;
|
||||
e[a] |= 128 << g % 4 * 8;
|
||||
e[d - 2] = c << 3;
|
||||
e[d - 1] = c >>> 29;
|
||||
return e
|
||||
}(e);
|
||||
a = 1732584193;
|
||||
b = 4023233417;
|
||||
c = 2562383102;
|
||||
d = 271733878;
|
||||
for (e = 0; e < f.length; e += 16) q = a, r = b, s = c, t = d, a = k(a, b, c, d, f[e + 0], 7, 3614090360), d = k(d, a, b, c, f[e + 1], 12, 3905402710), c = k(c, d, a, b, f[e + 2], 17, 606105819), b = k(b, c, d, a, f[e + 3], 22, 3250441966), a = k(a, b, c, d, f[e + 4], 7, 4118548399), d = k(d, a, b, c, f[e + 5], 12, 1200080426), c = k(c, d, a, b, f[e + 6], 17, 2821735955), b = k(b, c, d, a, f[e + 7], 22, 4249261313), a = k(a, b, c, d, f[e + 8], 7, 1770035416), d = k(d, a, b, c, f[e + 9], 12, 2336552879), c = k(c, d, a, b, f[e + 10], 17, 4294925233), b = k(b, c, d, a, f[e + 11], 22, 2304563134), a = k(a, b, c, d, f[e + 12], 7, 1804603682), d = k(d, a, b, c, f[e + 13], 12, 4254626195), c = k(c, d, a, b, f[e + 14], 17, 2792965006), b = k(b, c, d, a, f[e + 15], 22, 1236535329), a = l(a, b, c, d, f[e + 1], 5, 4129170786), d = l(d, a, b, c, f[e + 6], 9, 3225465664), c = l(c, d, a, b, f[e + 11], 14, 643717713), b = l(b, c, d, a, f[e + 0], 20, 3921069994), a = l(a, b, c, d, f[e + 5], 5, 3593408605), d = l(d, a, b, c, f[e + 10], 9, 38016083), c = l(c, d, a, b, f[e + 15], 14, 3634488961), b = l(b, c, d, a, f[e + 4], 20, 3889429448), a = l(a, b, c, d, f[e + 9], 5, 568446438), d = l(d, a, b, c, f[e + 14], 9, 3275163606), c = l(c, d, a, b, f[e + 3], 14, 4107603335), b = l(b, c, d, a, f[e + 8], 20, 1163531501), a = l(a, b, c, d, f[e + 13], 5, 2850285829), d = l(d, a, b, c, f[e + 2], 9, 4243563512), c = l(c, d, a, b, f[e + 7], 14, 1735328473), b = l(b, c, d, a, f[e + 12], 20, 2368359562), a = m(a, b, c, d, f[e + 5], 4, 4294588738), d = m(d, a, b, c, f[e + 8], 11, 2272392833), c = m(c, d, a, b, f[e + 11], 16, 1839030562), b = m(b, c, d, a, f[e + 14], 23, 4259657740), a = m(a, b, c, d, f[e + 1], 4, 2763975236), d = m(d, a, b, c, f[e + 4], 11, 1272893353), c = m(c, d, a, b, f[e + 7], 16, 4139469664), b = m(b, c, d, a, f[e + 10], 23, 3200236656), a = m(a, b, c, d, f[e + 13], 4, 681279174), d = m(d, a, b, c, f[e + 0], 11, 3936430074), c = m(c, d, a, b, f[e + 3], 16, 3572445317), b = m(b, c, d, a, f[e + 6], 23, 76029189), a = m(a, b, c, d, f[e + 9], 4, 3654602809), d = m(d, a, b, c, f[e + 12], 11, 3873151461), c = m(c, d, a, b, f[e + 15], 16, 530742520), b = m(b, c, d, a, f[e + 2], 23, 3299628645), a = n(a, b, c, d, f[e + 0], 6, 4096336452), d = n(d, a, b, c, f[e + 7], 10, 1126891415), c = n(c, d, a, b, f[e + 14], 15, 2878612391), b = n(b, c, d, a, f[e + 5], 21, 4237533241), a = n(a, b, c, d, f[e + 12], 6, 1700485571), d = n(d, a, b, c, f[e + 3], 10, 2399980690), c = n(c, d, a, b, f[e + 10], 15, 4293915773), b = n(b, c, d, a, f[e + 1], 21, 2240044497), a = n(a, b, c, d, f[e + 8], 6, 1873313359), d = n(d, a, b, c, f[e + 15], 10, 4264355552), c = n(c, d, a, b, f[e + 6], 15, 2734768916), b = n(b, c, d, a, f[e + 13], 21, 1309151649), a = n(a, b, c, d, f[e + 4], 6, 4149444226), d = n(d, a, b, c, f[e + 11], 10, 3174756917), c = n(c, d, a, b, f[e + 2], 15, 718787259), b = n(b, c, d, a, f[e + 9], 21, 3951481745), a = h(a, q), b = h(b, r), c = h(c, s), d = h(d, t);
|
||||
return (p(a) + p(b) + p(c) + p(d)).toLowerCase()
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -160,12 +160,24 @@ function inRange(value, min, max) {
|
|||
}
|
||||
|
||||
function round(v, zeros) {
|
||||
if (typeof v === 'object') {
|
||||
for (let [key,val] of Object.entries(v)) {
|
||||
if (typeof val === 'number') {
|
||||
v[key] = round(val, zeros);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
const prec = zeros !== undefined ? zeros : round_decimal_precision;
|
||||
if (prec === 0) return v | 0;
|
||||
let pow = Math.pow(10, prec);
|
||||
return Math.round(v * pow) / pow;
|
||||
}
|
||||
|
||||
function clamp(val, low, hi) {
|
||||
return Math.max(low, Math.min(hi, val));
|
||||
}
|
||||
|
||||
/**
|
||||
* used by {@link Polygon.trace} and {@link Polygon.intersect}
|
||||
*/
|
||||
|
|
@ -590,6 +602,7 @@ base.util = {
|
|||
sqr,
|
||||
lerp,
|
||||
time,
|
||||
clamp,
|
||||
comma,
|
||||
round,
|
||||
area2,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ function slice(off, res, val) {
|
|||
// or the requested resolution or tip values have changed
|
||||
let now = Date.now();
|
||||
if (res !== lastRes || val !== lastVal || now - lastSlice > 20000) {
|
||||
// console.log({clear_cache: now});
|
||||
cache = {};
|
||||
}
|
||||
lastVal = val;
|
||||
|
|
|
|||
|
|
@ -956,6 +956,7 @@ class Polygon {
|
|||
ln = ar.length,
|
||||
i = 0;
|
||||
while (i < ln) ar[i++].z = z;
|
||||
this.z = z;
|
||||
if (this.inner) this.inner.forEach(c => c.setZ(z));
|
||||
return this;
|
||||
}
|
||||
|
|
@ -964,7 +965,7 @@ class Polygon {
|
|||
* @returns {number} z value of first point
|
||||
*/
|
||||
getZ(i) {
|
||||
return this.z !== undefined ? this.z : this.points[i || 0].z;
|
||||
return this.z !== undefined ? this.z : this.points[i || 0]?.z || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2036,7 +2037,7 @@ class Polygon {
|
|||
tree = new PolyTree(),
|
||||
sp1 = this.toClipper(),
|
||||
sp2 = poly.toClipper(),
|
||||
minarea = min >= 0 ? min : 0.1;
|
||||
minarea = min ?? 0.1;
|
||||
|
||||
clip.AddPaths(sp1, PathSubject, true);
|
||||
clip.AddPaths(sp2, PathClip, true);
|
||||
|
|
|
|||
|
|
@ -345,10 +345,10 @@ function flatten(polys, to, crush) {
|
|||
* @returns {Polygon[]} out
|
||||
*/
|
||||
function subtract(setA, setB, outA, outB, z, minArea, opt = {}) {
|
||||
let min = minArea || 0.1,
|
||||
let min = numOrDefault(minArea, 0.1),
|
||||
out = [];
|
||||
|
||||
function filter(from, to = []) {
|
||||
function filter(from, to = []) {
|
||||
from.forEach(function(poly) {
|
||||
if (poly.area() >= min) {
|
||||
to.push(poly);
|
||||
|
|
@ -431,7 +431,7 @@ function subtract(setA, setB, outA, outB, z, minArea, opt = {}) {
|
|||
let lpre = length(polys);
|
||||
|
||||
if (opt.wasm && geo.wasm) {
|
||||
let min = minarea || 0.01;
|
||||
let min = minarea ?? 0.01;
|
||||
// let deepLength = polys.map(p => p.deepLength).reduce((a,v) => a+v);
|
||||
// if (deepLength < 15000)
|
||||
try {
|
||||
|
|
@ -632,7 +632,7 @@ function offset(polys, dist, opts = {}) {
|
|||
let coff = new ClipperOffset(opts.miter, opts.arc),
|
||||
tree = new PolyTree();
|
||||
|
||||
// setup offset
|
||||
// setup offset
|
||||
for (let poly of polys) {
|
||||
// convert to clipper format
|
||||
poly = poly.toClipper();
|
||||
|
|
|
|||
|
|
@ -10,11 +10,10 @@
|
|||
"gcodePre": [
|
||||
"'UNITS:MM",
|
||||
"'",
|
||||
" \t'Set program to absolute coordinate mode",
|
||||
"CN, 90",
|
||||
"&Tool =1 'Tool number to change to",
|
||||
"CN, 90 'Set program to absolute coordinate mode",
|
||||
"&Tool =1 'Tool number to change to",
|
||||
"C9 'Change tool",
|
||||
"TR,4000 'Set spindle RPM",
|
||||
"TR,4000 'Set spindle RPM",
|
||||
"C6 'Spindle on",
|
||||
"PAUSE 2",
|
||||
"'"
|
||||
|
|
@ -24,9 +23,8 @@
|
|||
"C7",
|
||||
"END",
|
||||
"'",
|
||||
"'",
|
||||
"UNIT_ERROR:",
|
||||
"CN, 91 'Run file explaining unit error",
|
||||
"CN, 91 'Run file explaining unit error",
|
||||
"END"
|
||||
],
|
||||
"gcodeDwell": [
|
||||
|
|
|
|||
824
src/kiri-dev/fdm/Bambu.A1
Normal file
824
src/kiri-dev/fdm/Bambu.A1
Normal file
|
|
@ -0,0 +1,824 @@
|
|||
{
|
||||
"mode": "FDM",
|
||||
"internal": 0,
|
||||
"bedHeight": 2.5,
|
||||
"bedWidth": 256,
|
||||
"bedDepth": 256,
|
||||
"bedRound": false,
|
||||
"maxHeight": 256,
|
||||
"originCenter": false,
|
||||
"gcodeFan": [
|
||||
"M106 P1 S{fan_speed}"
|
||||
],
|
||||
"gcodeTrack": [
|
||||
"M73 P{progress}"
|
||||
],
|
||||
"gcodeLayer": [
|
||||
"; ===== CHANGE_LAYER ==============================",
|
||||
"; layer num/total_layer_count: {layer}/{layers}",
|
||||
"M622.1 S1 ; for prev firware, default turned on",
|
||||
"M1002 judge_flag timelapse_record_flag",
|
||||
"M622 J1",
|
||||
"M971 S11 C10 O0 ; timelapse without wipe tower",
|
||||
"M623",
|
||||
"M73 L{layer}",
|
||||
"M991 S0 P{layer-1} ; notify layer change",
|
||||
";; IF { layer == 0 }",
|
||||
"M204 S500 ; reduce first layer acceleration",
|
||||
";; ELSE",
|
||||
"M204 S5000 ; faster acceleration",
|
||||
";; END"
|
||||
],
|
||||
"gcodePre": [
|
||||
"; total layer number: {layers}",
|
||||
";; PREAMBLE",
|
||||
";; DEFINE BAMBU-AMS 0,1,2,3",
|
||||
"; ===== HEADER ====================================",
|
||||
"M73 P0 R24 ; Initial progress and time remaining",
|
||||
"M201 X12000 Y12000 Z1500 E5000 ; Set max acceleration",
|
||||
"M203 X500 Y500 Z30 E30 ; Set max feed rates",
|
||||
"M204 P12000 R5000 T12000 ; Set acceleration",
|
||||
"M205 X9.00 Y9.00 Z3.00 E2.50 ; Set advanced settings",
|
||||
"M106 S0 ; Set part fan speed to 0",
|
||||
"M106 P2 S0 ; Turn off aux fan",
|
||||
";===== Machine: A1 ================================",
|
||||
"G392 S0 ; Disable clog detection",
|
||||
"M9833.2 ; Custom command (unknown function)",
|
||||
";===== Start Heating ==============================",
|
||||
"M1002 gcode_claim_action : 2",
|
||||
"M1002 set_filament_type:PLA ; Set filament type to PLA",
|
||||
"M104 S140 ; Set nozzle temperature",
|
||||
"M140 S65 ; Set bed temperature",
|
||||
";===== Startup Sound ==============================",
|
||||
"M17 ; Enable steppers",
|
||||
"M400 S1 ; Wait for movements to complete",
|
||||
"M1006 S1 ; Start printer sound",
|
||||
"M1006 A0 B10 L100 C37 D10 M60 E37 F10 N60",
|
||||
"M1006 A0 B10 L100 C41 D10 M60 E41 F10 N60",
|
||||
"M1006 A0 B10 L100 C44 D10 M60 E44 F10 N60",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N60",
|
||||
"M1006 A43 B10 L100 C46 D10 M70 E39 F10 N80",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N80",
|
||||
"M1006 A0 B10 L100 C43 D10 M60 E39 F10 N80",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N80",
|
||||
"M1006 A0 B10 L100 C41 D10 M80 E41 F10 N80",
|
||||
"M1006 A0 B10 L100 C44 D10 M80 E44 F10 N80",
|
||||
"M1006 A0 B10 L100 C49 D10 M80 E49 F10 N80",
|
||||
"M1006 A0 B10 L100 C0 D10 M80 E0 F10 N80",
|
||||
"M1006 A44 B10 L100 C48 D10 M60 E39 F10 N80",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N80",
|
||||
"M1006 A0 B10 L100 C44 D10 M80 E39 F10 N80",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N80",
|
||||
"M1006 A43 B10 L100 C46 D10 M60 E39 F10 N80",
|
||||
"M1006 W ; Play audio",
|
||||
"M18 ; Disable steppers",
|
||||
";===== Avoid End Stop =============================",
|
||||
"G91 ; Set relative positioning",
|
||||
"G380 S2 Z40 F1200 ; Move Z up to 40mm",
|
||||
"G380 S3 Z-15 F1200 ; Move Z down to -15mm",
|
||||
"G90 ; Set absolute positioning",
|
||||
";===== Reset Machine Status =======================",
|
||||
"M204 S6000 ; Set acceleration to 6000 mm/s^2",
|
||||
"M630 S0 P0 ; Custom command (unknown function)",
|
||||
"G91 ; Set relative positioning",
|
||||
"M17 Z0.3 ; Lower Z motor current",
|
||||
"G90 ; Set absolute positioning",
|
||||
"M17 X0.65 Y1.2 Z0.6 ; Reset motor currents",
|
||||
"M960 S5 P1 ; Turn on logo lamp",
|
||||
"G90 ; Set absolute positioning",
|
||||
"M220 S100 ; Reset feedrate",
|
||||
"M221 S100 ; Reset flowrate",
|
||||
"M73.2 R1.0 ; Reset estimated time remaining",
|
||||
";===== Enable Noise Reduction =====================",
|
||||
"M982.2 S1 ; Turn on noise reduction",
|
||||
";===== Home XY & Prepare Print ====================",
|
||||
"M1002 gcode_claim_action : 13",
|
||||
"G28 X ; Home X-axis",
|
||||
"G91 ; Set relative positioning",
|
||||
"G1 Z5 F1200 ; Move Z up by 5mm",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G0 X128 F30000 ; Move X to 128mm",
|
||||
"G0 Y254 F3000 ; Move Y to 254mm",
|
||||
"G91 ; Set relative positioning",
|
||||
"G1 Z-5 F1200 ; Move Z down by 5mm",
|
||||
"M109 S25 H140 ; Set tool preheat temperature",
|
||||
"M17 E0.3 ; Set extruder motor current",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"G1 E10 F1200 ; Extrude 10mm",
|
||||
"G1 E-0.5 F30 ; Retract 0.5mm",
|
||||
"M17 D ; Restore motor current",
|
||||
";===== Home Z with Low Precision ==================",
|
||||
"G28 Z P0 T140 ; Home Z with low precision",
|
||||
"M104 S220 ; Set nozzle temperature",
|
||||
";===== Build Plate Detection ======================",
|
||||
"M1002 judge_flag build_plate_detect_flag",
|
||||
"M622 S1",
|
||||
" G39.4 ; Custom build plate detection command",
|
||||
" G90 ; Set absolute positioning",
|
||||
" G1 Z5 F1200 ; Move Z up by 5mm",
|
||||
"M623",
|
||||
";===== Prepare Print Temperature & Material =======",
|
||||
"M1002 gcode_claim_action : 24",
|
||||
"M400 ; Wait for all movements to complete",
|
||||
"M211 X0 Y0 Z0 ; Turn off soft endstops",
|
||||
"M975 S1 ; Enable tool vibration suppression",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G1 X-28.5 F30000 ; Move X-axis",
|
||||
"G1 X-48.2 F3000 ; Move further on X",
|
||||
"M620 M ; Enable material remap",
|
||||
"M620 S0A ; Switch material if AMS exists",
|
||||
" M1002 gcode_claim_action : 4",
|
||||
" M400 ; Wait for heating",
|
||||
" M1002 set_filament_type:UNKNOWN ; Set filament type as unknown",
|
||||
" M109 S220 ; Set and wait hotend temperature",
|
||||
" M104 S250 ; Set nozzle purge temp",
|
||||
" M400 ; Wait for heating",
|
||||
" T0 ; Select Tool 0",
|
||||
" G1 X-48.2 F3000 ; Move X again",
|
||||
" M400 ; Wait for completion",
|
||||
" M620.1 E F523.843 T240 ; Extrude for purge sequence",
|
||||
" M109 S250 ; Wait for nozzle flush temp",
|
||||
" M106 P1 S0 ; Turn off nozzle cooling fan",
|
||||
" G92 E0 ; Reset extruder position",
|
||||
" G1 E50 F200 ; Extrude 50mm to clear nozzle",
|
||||
" M400 ; Wait for all movements to complete",
|
||||
" M1002 set_filament_type:PLA ; Confirm filament type",
|
||||
"M621 S0A ; Confirm material switch",
|
||||
"M109 S240 H300 ; Set nozzle temp",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"G1 E50 F200 ; Extrude 50mm slowly to prevent clog",
|
||||
"M400 ; Wait for completion",
|
||||
"M106 P1 S178 ; Set nozzle cooling fan speed",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"G1 E5 F200 ; Extrude 5mm slowly",
|
||||
"M104 S220 ; Lower nozzle temperature",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"G1 E-0.5 F300 ; Retract filament slightly",
|
||||
";===== Wipe and Shake Nozzle ======================",
|
||||
"G1 X-28.5 F30000 ; Move X-axis",
|
||||
"M73 P1 R23 ; Update print progress",
|
||||
"G1 X-48.2 F3000 ; Move back on X-axis",
|
||||
"M73 P2 R23 ; Update print progress",
|
||||
"G1 X-28.5 F30000 ; Wipe nozzle",
|
||||
"G1 X-48.2 F3000 ; Move back on X",
|
||||
"G1 X-28.5 F30000 ; Wipe nozzle",
|
||||
"G1 X-48.2 F3000 ; Move back on X",
|
||||
"M400 ; Wait for all movements to complete",
|
||||
"M106 P1 S0 ; Turn off nozzle cooling fan",
|
||||
";===== Auto Extrude Calibration Start =============",
|
||||
"M975 S1 ; Enable extruder calibration",
|
||||
"G90 ; Set absolute positioning",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"T1000 ; Select tool 1000",
|
||||
"G1 X-48.2 Y0 Z10 F10000 ; Move to calibration start position",
|
||||
"M400 ; Wait for all moves to complete",
|
||||
"M1002 set_filament_type:UNKNOWN ; Set filament type to unknown",
|
||||
"M412 S1 ; Enable filament runout detection",
|
||||
"M400 P10 ; Wait for 10ms",
|
||||
"M620.3 W1 ; Enable filament tangle detection",
|
||||
"M400 S2 ; Wait for 2ms",
|
||||
"M1002 set_filament_type:PLA ; Set filament type to PLA",
|
||||
"M1002 judge_flag extrude_cali_flag ; Check extruder calibration flag",
|
||||
"M622 J1",
|
||||
" M1002 gcode_claim_action : 8",
|
||||
" M109 S220 ; Set hotend temperature",
|
||||
" G1 E10 F377.08 ; Extrude 10mm at 377.08 mm/min",
|
||||
" M983 F6.28466 A0.3 H0.4 ; Perform dynamic extrusion compensation",
|
||||
" M106 P1 S255 ; Set nozzle cooling fan to max speed",
|
||||
" M400 S5 ; Wait for 5 seconds",
|
||||
" G1 X-28.5 F18000 ; Move X for wipe",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" G1 X-28.5 F18000 ; Wipe motion",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" M73 P3 R23 ; Update progress",
|
||||
" G1 X-28.5 F12000 ; Wipe and shake",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" M400 ; Wait for all movements to complete",
|
||||
" M106 P1 S0 ; Turn off nozzle cooling fan",
|
||||
" M1002 judge_last_extrude_cali_success",
|
||||
" M622 J0",
|
||||
" M983 F6.28466 A0.3 H0.4 ; Perform dynamic extrusion compensation",
|
||||
" M106 P1 S255 ; Set nozzle cooling fan to max speed",
|
||||
" M400 S5 ; Wait for 5 seconds",
|
||||
" G1 X-28.5 F18000 ; Move X for wipe",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" G1 X-28.5 F18000 ; Wipe motion",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" G1 X-28.5 F12000 ; Wipe and shake",
|
||||
" M400 ; Wait for all movements to complete",
|
||||
" M106 P1 S0 ; Turn off nozzle cooling fan",
|
||||
" M623 ; End of calibration routine",
|
||||
" M73 P4 R23 ; Update progress",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" M400 ; Wait for all movements to complete",
|
||||
" M984 A0.1 E1 S1 F6.28466 H0.4 ; Apply extruder calibration parameters",
|
||||
" M106 P1 S178 ; Set nozzle cooling fan to moderate speed",
|
||||
" M400 S7 ; Wait for 7 seconds",
|
||||
" G1 X-28.5 F18000 ; Move X for wipe",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" G1 X-28.5 F18000 ; Wipe motion",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" G1 X-28.5 F12000 ; Wipe and shake",
|
||||
" G1 X-48.2 F3000 ; Move X back",
|
||||
" M400 ; Wait for all movements to complete",
|
||||
" M106 P1 S0 ; Turn off nozzle cooling fan",
|
||||
"M623 ; End of extruder calibration process",
|
||||
"M104 S170 ; Prepare to wipe nozzle",
|
||||
"M106 S255 ; Turn on fan",
|
||||
";===== Mech Mode Fast Check Start =================",
|
||||
"M1002 gcode_claim_action : 3",
|
||||
"G1 X128 Y128 F20000 ; Move to check position",
|
||||
"G1 Z5 F1200 ; Raise Z-axis",
|
||||
"M400 P200 ; Wait for movements to complete",
|
||||
"M970.3 Q1 A5 K0 O3 ; Execute fast check routine",
|
||||
"M974 Q1 S2 P0 ; Confirm fast check step",
|
||||
"M970.2 Q1 K1 W58 Z0.1 ; Additional fast check",
|
||||
"M974 S2 ; Confirm step",
|
||||
"G1 X128 Y128 F20000 ; Repeat move to check position",
|
||||
"G1 Z5 F1200 ; Raise Z-axis",
|
||||
"M400 P200 ; Wait for movements to complete",
|
||||
"M970.3 Q0 A10 K0 O1 ; Execute another fast check routine",
|
||||
"M974 Q0 S2 P0 ; Confirm step",
|
||||
"M970.2 Q0 K1 W78 Z0.1 ; Another additional check",
|
||||
"M974 S2 ; Confirm step",
|
||||
"M975 S1 ; Confirm vibration suppression",
|
||||
"G1 F30000 ; Set movement speed",
|
||||
"G1 X0 Y5 ; Move to next step",
|
||||
"G28 X ; Re-home XY",
|
||||
"G1 Z4 F1200 ; Lower Z-axis",
|
||||
";===== Wipe Nozzle ================================",
|
||||
"M1002 gcode_claim_action : 14",
|
||||
"M975 S1 ; Enable wipe mode",
|
||||
"M106 S255 ; Turn on fan (G28 turns off fan)",
|
||||
"M211 S ; Push soft endstop status",
|
||||
"M211 X0 Y0 Z0 ; Turn off Z-axis endstop",
|
||||
";===== Remove Waste by Touching Start =============",
|
||||
"M104 S170 ; Set nozzle temp",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"G1 E-1 F500 ; Retract filament",
|
||||
"G90 ; Set absolute positioning",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"M109 S170 ; Set nozzle temperature",
|
||||
"G0 X108 Y-0.5 F30000 ; Move to wipe position",
|
||||
"G380 S3 Z-5 F1200 ; Lower nozzle to wipe",
|
||||
"; Repeat wipe sequence",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X110 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"M73 P22 R18",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X112 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X114 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X116 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X118 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X120 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X122 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X124 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X126 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X128 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X130 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X132 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X134 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X136 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X138 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X140 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X142 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X144 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X146 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z2 F1200",
|
||||
"G1 X148 F10000",
|
||||
"G380 S3 Z-5 F1200",
|
||||
"G1 Z5 F30000 ; Raise Z",
|
||||
";===== Remove Waste by Touching End ===============",
|
||||
"G1 Z10 F1200 ; Lift nozzle",
|
||||
"G0 X118 Y261 F30000 ; Move to safe position",
|
||||
"G1 Z5 F1200 ; Lower Z",
|
||||
"M109 S170 ; Set nozzle temperature",
|
||||
"G28 Z P0 T300 ; Home Z with low precision",
|
||||
"G29.2 S0 ; Turn off ABL",
|
||||
"M104 S140 ; Prepare for auto bed leveling",
|
||||
"G0 Z5 F20000 ; Lift Z",
|
||||
"G0 X128 Y261 F20000 ; Move to exposed steel surface",
|
||||
"G0 Z-1.01 F1200 ; Lower nozzle to stop position",
|
||||
"G91 ; Set relative positioning",
|
||||
"G2 I1 J0 X2 Y0 F2000.1 ; Execute wipe motion",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G1 Z10 F1200 ; Raise Z",
|
||||
";===== Brush Material Wipe Nozzle =================",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G1 Y250 F30000 ; Move to brush position",
|
||||
"G1 X55 ; Move X",
|
||||
"G1 Z1.300 F1200 ; Lower nozzle",
|
||||
"G1 Y262.5 F6000 ; Wipe motion",
|
||||
"G91 ; Set relative positioning",
|
||||
"G1 X-35 F30000 ; Move along brush",
|
||||
"G1 Y-0.5",
|
||||
"G1 X45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X-45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X-45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X45",
|
||||
"G1 Z5.000 F1200 ; Lift nozzle",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G1 X30 Y250.000 F30000 ; Move to brush position",
|
||||
"G1 Z1.300 F1200 ; Lower nozzle",
|
||||
"G1 Y262.5 F6000 ; Wipe motion",
|
||||
"G91 ; Set relative positioning",
|
||||
"G1 X35 F30000 ; Move along brush",
|
||||
"G1 Y-0.5",
|
||||
"G1 X-45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X-45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X45",
|
||||
"G1 Y-0.5",
|
||||
"G1 X-45",
|
||||
"G1 Z10.000 F1200 ; Lift nozzle",
|
||||
";===== Brush Material Wipe Nozzle End ============",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G1 Y250 F30000 ; Move to safe position",
|
||||
"G1 X138",
|
||||
"G1 Y261",
|
||||
"G0 Z-1.01 F1200 ; Stop nozzle",
|
||||
"G91 ; Set relative positioning",
|
||||
"G2 I1 J0 X2 Y0 F2000.1",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"M73 P23 R18",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"G2 I1 J0 X2",
|
||||
"G2 I-0.75 J0 X-1.5",
|
||||
"M109 S140 ; Set nozzle temperature",
|
||||
"M106 S255 ; Turn on fan (G28 turns off fan)",
|
||||
"M211 R ; Restore soft endstop status",
|
||||
";===== Bed Leveling ===============================",
|
||||
"M1002 judge_flag g29_before_print_flag ; Check bed leveling flag",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G1 Z5 F1200 ; Lift nozzle",
|
||||
"G1 X0 Y0 F30000 ; Move to home position",
|
||||
"G29.2 S1 ; Turn on ABL (auto bed level)",
|
||||
"M190 S65 ; Set and wait bed temp",
|
||||
"M109 S140 ; Set and wait nozzle temp",
|
||||
"M106 S0 ; Turn off fan (reduce noise)",
|
||||
"M622 J1",
|
||||
" M1002 gcode_claim_action : 1",
|
||||
" G29 A1 X115.2 Y115.2 I25.6 J25.6 ; Perform bed leveling",
|
||||
" M400 ; Wait for all movements to complete",
|
||||
" M500 ; Save calibration data",
|
||||
"M623 ; End bed leveling",
|
||||
";===== Home After Wipe Mouth ======================",
|
||||
"M1002 judge_flag g29_before_print_flag ; Check if bed leveling was performed",
|
||||
"M622 J0 ; Signal start of sequence",
|
||||
" M1002 gcode_claim_action : 13 ; Claim home action",
|
||||
" G28 ; Home all axes",
|
||||
"M623 ; End sequence",
|
||||
";===== Home After Wipe Mouth End ==================",
|
||||
"G1 X108.000 Y-0.500 F30000 ; Move to start position",
|
||||
"G1 Z0.300 F1200 ; Lower Z for calibration",
|
||||
"M400 ; Wait for moves to complete",
|
||||
"G2814 Z0.32 ; Set Z offset",
|
||||
"M104 S220 ; Set nozzle temperature to 220°C for printing",
|
||||
";===== Nozzle Load Line ===========================",
|
||||
";G90 ; Set absolute positioning",
|
||||
";M83 ; Set extruder to relative mode",
|
||||
";G1 Z5 F1200 ; Raise Z before priming",
|
||||
";G1 X88 Y-0.5 F20000 ; Move to priming position",
|
||||
";G1 Z0.3 F1200 ; Lower nozzle for priming",
|
||||
";M109 S220 ; Wait for nozzle temperature to reach 220°C",
|
||||
";G1 E2 F300 ; Extrude filament",
|
||||
";G1 X168 E4.989 F6000 ; Extrude along the line",
|
||||
";G1 Z1 F1200 ; Lift Z after priming",
|
||||
";===== Extrude Calibration Test ====================",
|
||||
"M400 ; Wait for all commands to complete",
|
||||
"M900 S ; Start calibration",
|
||||
"M900 C ; Start calibration cycle",
|
||||
"G90 ; Set absolute positioning",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"M109 S220 ; Set and wait nozzle temp",
|
||||
"G0 X128 E8 F904.991 ; Extrude calibration test pattern",
|
||||
"G0 X133 E.3742 F1508.32",
|
||||
"G0 X138 E.3742 F6033.27",
|
||||
"G0 X143 E.3742 F1508.32",
|
||||
"G0 X148 E.3742 F6033.27",
|
||||
"G0 X153 E.3742 F1508.32",
|
||||
"G91 ; Set relative positioning",
|
||||
"G1 X1 Z-0.300 ; Lower nozzle slightly",
|
||||
"G1 X4 ",
|
||||
"G1 Z1 F1200 ; Raise back up",
|
||||
"G90 ; Return to absolute positioning",
|
||||
"M400 ; Wait for completion",
|
||||
"M900 R ; Reset calibration",
|
||||
"M1002 judge_flag extrude_cali_flag ; Check calibration status",
|
||||
"M622 J1 ; Signal start of sequence",
|
||||
" G90 ; Set absolute positioning",
|
||||
" G1 X108.000 Y1.000 F30000 ; Move to calibration position",
|
||||
" G91 ; Set relative positioning",
|
||||
" G1 Z-0.700 F1200 ; Lower nozzle slightly",
|
||||
" G90 ; Return to absolute positioning",
|
||||
" M83 ; Set extruder to relative mode",
|
||||
" G0 X128 E10 F904.991 ; Run extrusion test",
|
||||
" G0 X133 E.3742 F1508.32",
|
||||
" G0 X138 E.3742 F6033.27",
|
||||
" G0 X143 E.3742 F1508.32",
|
||||
" G0 X148 E.3742 F6033.27",
|
||||
" G0 X153 E.3742 F1508.32",
|
||||
" G91 ; Set relative positioning",
|
||||
" G1 X1 Z-0.300 ; Lower slightly",
|
||||
" G1 X4",
|
||||
" G1 Z1 F1200 ; Raise back up",
|
||||
" G90 ; Return to absolute positioning",
|
||||
" M400 ; Wait for completion",
|
||||
"M623 ; End sequence",
|
||||
"G1 Z0.2 ; Lower nozzle slightly",
|
||||
"M1002 gcode_claim_action : 0 ; Claim action",
|
||||
"M400 ; Wait for actions to complete",
|
||||
";===== Final Print Prep ===========================",
|
||||
"G29.1 Z-0.02 ; Adjust Z height for PEI plate",
|
||||
"M960 S1 P0 ; Turn off laser",
|
||||
"M960 S2 P0 ; Turn off laser",
|
||||
"M106 S0 ; Turn off fan",
|
||||
"M106 P2 S0 ; Turn off auxiliary fan",
|
||||
"M106 P3 S0 ; Turn off chamber fan",
|
||||
"M975 S1 ; Enable mechanical suppression mode",
|
||||
"G90 ; Set absolute positioning",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"T1000 ; Tool selection",
|
||||
"M211 X0 Y0 Z0 ; Disable soft endstops",
|
||||
"M1007 S1 ; Enable mass estimation",
|
||||
"G29.4 ; Start additional leveling routine",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G21 ; Set units to millimeters",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"M106 P3 S200 ; Set chamber fan speed",
|
||||
"M981 S1 P20000 ; Open spaghetti detector"
|
||||
],
|
||||
"gcodePost": [
|
||||
"; ===== FOOTER ====================================",
|
||||
"M204 S6000 ; Set acceleration to 6000 mm/s^2",
|
||||
"M1003 S0 ; Disable power loss recovery",
|
||||
"M106 S0 ; Turn off part cooling fan",
|
||||
"M106 P2 S0 ; Turn off auxiliary cooling fan",
|
||||
"M981 S0 P20000 ; Close spaghetti detector",
|
||||
"M106 P3 S0 ; Turn off chamber fan",
|
||||
"G392 S0 ; Turn off nozzle clog detection",
|
||||
"M400 ; Wait for buffer to clear",
|
||||
"G92 E0 ; Zero the extruder",
|
||||
"G1 E-0.8 F1800 ; Retract filament by 0.8mm",
|
||||
"G1 Z26.1 F900 ; Raise Z-axis slightly",
|
||||
"G1 X0 Y128 F18000 ; Move to safe position",
|
||||
"G1 X-13.0 F3000 ; Move to another safe position",
|
||||
";===== Timelapse Sequence ========================",
|
||||
"M1002 judge_flag timelapse_record_flag",
|
||||
"M622 J1",
|
||||
" M400 P100",
|
||||
" M971 S11 C11 O0",
|
||||
" M991 S0 P-1 ; End timelapse at safe pos",
|
||||
"M623 ; End conditional block",
|
||||
";===== End of Print ==============================",
|
||||
"M140 S0 ; Turn off heated bed",
|
||||
"M106 S0 ; Turn off all cooling fans",
|
||||
"M106 P2 S0 ; Turn off auxiliary cooling fan",
|
||||
"M106 P3 S0 ; Turn off chamber cooling fan",
|
||||
";===== Pull Back Filament ========================",
|
||||
"M620 S255 ; Retract filament to AMS",
|
||||
"G1 X267 F15000 ; Move to retract position",
|
||||
"T255 ; Select tool 255 (AMS retract)",
|
||||
"G1 X-28.5 F18000",
|
||||
"G1 X-48.2 F3000",
|
||||
"G1 X-28.5 F18000",
|
||||
"G1 X-48.2 F3000",
|
||||
"M621 S255 ; Complete filament unload",
|
||||
"M104 S0 ; Turn off hotend",
|
||||
"M400 ; Wait for all motion to complete",
|
||||
"M17 S ; Enable steppers",
|
||||
"M17 Z0.4 ; Reduce Z stepper motor current",
|
||||
"G1 Z125.6 F600 ; Move Z-axis up",
|
||||
"G1 Z123.6",
|
||||
"M400 P100",
|
||||
"M17 R ; Restore Z motor current",
|
||||
"G90 ; Set absolute positioning",
|
||||
"G1 X-48 Y180 F3600 ; Move to parking position",
|
||||
"M220 S100 ; Reset feedrate to 100%",
|
||||
"M201.2 K1.0 ; Reset acceleration magnitude",
|
||||
"M73.2 R1.0 ; Reset remaining time estimation",
|
||||
"M1002 set_gcode_claim_speed_level : 0",
|
||||
";===== Printer Finish Sound ======================",
|
||||
"M17",
|
||||
"M400 S1",
|
||||
"M1006 S1",
|
||||
"M1006 A0 B20 L100 C37 D20 M40 E42 F20 N60",
|
||||
"M1006 A0 B10 L100 C44 D10 M60 E44 F10 N60",
|
||||
"M1006 A0 B10 L100 C46 D10 M80 E46 F10 N80",
|
||||
"M1006 A44 B20 L100 C39 D20 M60 E48 F20 N60",
|
||||
"M1006 A0 B10 L100 C44 D10 M60 E44 F10 N60",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N60",
|
||||
"M1006 A0 B10 L100 C39 D10 M60 E39 F10 N60",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N60",
|
||||
"M1006 A0 B10 L100 C44 D10 M60 E44 F10 N60",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N60",
|
||||
"M1006 A0 B10 L100 C39 D10 M60 E39 F10 N60",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N60",
|
||||
"M1006 A0 B10 L100 C48 D10 M60 E44 F10 N80",
|
||||
"M1006 A0 B10 L100 C0 D10 M60 E0 F10 N80",
|
||||
"M1006 A44 B20 L100 C49 D20 M80 E41 F20 N80",
|
||||
"M1006 A0 B20 L100 C0 D20 M60 E0 F20 N80",
|
||||
"M1006 A0 B20 L100 C37 D20 M30 E37 F20 N60",
|
||||
"M1006 W",
|
||||
"M400 ; Wait for completion",
|
||||
"M18 X Y Z ; Disable motors",
|
||||
"M73 P100 R0 ; Set progress to 100%"
|
||||
],
|
||||
"gcodeProc": "",
|
||||
"gcodeFExt": "gcode",
|
||||
"extruders": [
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [
|
||||
"; BEGIN tool change from {last_tool} to {tool}",
|
||||
"M620 S{tool}A ; prepare tool change",
|
||||
"M204 S9000 ; Set acceleration to 9000 mm/s^2",
|
||||
"M620.11 S0 ; Reset filament retraction state",
|
||||
"M400 ; wait for moves to complete",
|
||||
"M620.1 E F187 T240 ; set purge rate 187 temp 240",
|
||||
"T{tool} ; initiate tool change",
|
||||
"M620.1 E F374 T240 ; set purge rate 374 temp 240",
|
||||
"M620.11 S0 ; Reset filament retraction state",
|
||||
"G92 E0 ; reset extruder position",
|
||||
"M400 ; wait for moves to complete",
|
||||
" ; -- PURGE --",
|
||||
"M109 S240 ; Set nozzle temperature to 240°C",
|
||||
"G1 E23.7 F187 ; Extrude 23.7mm of filament at flowrate 187",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F187 ; Continue extrusion at flowrate 187",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F374 ; Continue extrusion at flowrate 374",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F374 ; Continue extrusion at flowrate 374",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F374 ; Continue extrusion at flowrate 374",
|
||||
"G1 E-2 F1800 ; Retract filament by 2mm",
|
||||
"G1 E2 F300 ; Recover retraction slowly",
|
||||
"M400 ; Wait for all movements to complete",
|
||||
"M109 S{temp} ; Set nozzle temperature back to print temp",
|
||||
" ; -- SHAKE --",
|
||||
"M106 P1 S255 ; Turn on nozzle cooling fan to full speed",
|
||||
"M400 S3 ; Wait for all movements to complete",
|
||||
"G1 X70 F5000 ; Move to X70",
|
||||
"G1 X90 F3000 ; Move to X90",
|
||||
"G1 Y255 F4000 ; Move to Y255",
|
||||
"G1 X105 F5000 ; Move to X105",
|
||||
"G1 Y265 ; Move to Y265",
|
||||
"G1 X70 F10000 ; Rapid move to X70",
|
||||
"G1 X100 F5000 ; Move to X100",
|
||||
"G1 X70 F10000 ; Rapid move back to X70",
|
||||
"G1 X100 F5000 ; Move to X100",
|
||||
"G1 X70 F10000 ; Shake filament residue",
|
||||
"G1 X80 F15000",
|
||||
"G1 X60",
|
||||
"G1 X80",
|
||||
"G1 X60",
|
||||
"G1 X80 ; Shake to put down garbage",
|
||||
"G1 X100 F5000 ; Move to X100",
|
||||
"G1 X165 F15000 ; Wipe and shake",
|
||||
"G1 Y256 ; Move Y aside to prevent collision",
|
||||
"M400 ; Wait for all movements to complete",
|
||||
"M204 S10000 ; Set acceleration to 10000 mm/s^2",
|
||||
"M621 S{tool}A ; complete tool change",
|
||||
"; END tool change"
|
||||
],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
},
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
},
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
},
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [
|
||||
"T3"
|
||||
],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
}
|
||||
],
|
||||
"new": false,
|
||||
"deviceName": "Bambu A1",
|
||||
"bedBelt": false,
|
||||
"fwRetract": false,
|
||||
"filamentSource": "direct",
|
||||
"extras": {
|
||||
"bbl": {
|
||||
"luke": {
|
||||
"host": "10.20.20.75",
|
||||
"code": "20709223",
|
||||
"serial": "01P09C482401767",
|
||||
"modified": true
|
||||
},
|
||||
"leia": {
|
||||
"host": "10.20.20.76",
|
||||
"code": "35129782",
|
||||
"serial": "01P09C461603301",
|
||||
"modified": true
|
||||
},
|
||||
"vader": {
|
||||
"host": "10.20.20.77",
|
||||
"code": "17711811",
|
||||
"serial": "01P00A413100516",
|
||||
"modified": true
|
||||
},
|
||||
"Scrappy": {
|
||||
"host": "10.10.2.5",
|
||||
"serial": "01S00A292500224",
|
||||
"code": "38373335",
|
||||
"modified": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"imageURL": "",
|
||||
"deviceZMax": 0,
|
||||
"gcodeTime": 1,
|
||||
"gcodeFeature": [],
|
||||
"profiles": [
|
||||
{
|
||||
"processName": "Bambu PLA",
|
||||
"sliceHeight": 0.2,
|
||||
"sliceShells": 2,
|
||||
"sliceShellOrder": "in-out",
|
||||
"sliceLayerStart": "last",
|
||||
"sliceFillAngle": 45,
|
||||
"sliceFillOverlap": 0.35,
|
||||
"sliceFillSparse": 0.1,
|
||||
"sliceFillType": "grid",
|
||||
"sliceAdaptive": false,
|
||||
"sliceMinHeight": 0,
|
||||
"sliceSupportDensity": 0.5,
|
||||
"sliceSupportOffset": 0.4,
|
||||
"sliceSupportGap": 1,
|
||||
"sliceSupportSize": 5,
|
||||
"sliceSupportArea": 0.25,
|
||||
"sliceSupportExtra": 0,
|
||||
"sliceSupportAngle": 60,
|
||||
"sliceSupportNozzle": 0,
|
||||
"sliceSolidMinArea": 0,
|
||||
"sliceBottomLayers": 2,
|
||||
"sliceTopLayers": 3,
|
||||
"firstLayerRate": 20,
|
||||
"firstLayerPrintMult": 1,
|
||||
"firstLayerYOffset": 0,
|
||||
"firstLayerBrim": 0,
|
||||
"firstLayerBeltLead": 0,
|
||||
"firstLayerFanSpeed": 0,
|
||||
"outputTemp": 220,
|
||||
"outputBedTemp": 65,
|
||||
"outputFanSpeed": 255,
|
||||
"outputFeedrate": 120,
|
||||
"outputFinishrate": 90,
|
||||
"outputSeekrate": 200,
|
||||
"outputShellMult": 1.2,
|
||||
"outputFillMult": 1.2,
|
||||
"outputSparseMult": 1.2,
|
||||
"outputRetractDist": 2,
|
||||
"outputRetractSpeed": 80,
|
||||
"outputRetractWipe": 0,
|
||||
"outputRetractDwell": 0,
|
||||
"outputShortPoly": 100,
|
||||
"outputMinSpeed": 5,
|
||||
"outputCoastDist": 0,
|
||||
"outputLayerRetract": false,
|
||||
"zHopDistance": 0,
|
||||
"antiBacklash": 0,
|
||||
"sliceFillWidth": 1,
|
||||
"sliceFillRate": 0,
|
||||
"sliceSupportEnable": false,
|
||||
"firstSliceHeight": 0.3,
|
||||
"firstLayerFillRate": 80,
|
||||
"firstLayerLineMult": 1,
|
||||
"firstLayerNozzleTemp": 210,
|
||||
"firstLayerBedTemp": 60,
|
||||
"firstLayerBrimTrig": 0,
|
||||
"firstLayerBrimGap": 0,
|
||||
"outputRaft": false,
|
||||
"outputRaftSpacing": 0.2,
|
||||
"outputBrimCount": 0,
|
||||
"outputBrimOffset": 2,
|
||||
"outputPurgeTower": 0,
|
||||
"outputInvertX": false,
|
||||
"outputInvertY": false,
|
||||
"arcTolerance": 0,
|
||||
"ranges": [],
|
||||
"sliceLineWidth": 0,
|
||||
"sliceFillRepeat": 2,
|
||||
"firstLayerBrimIn": 0,
|
||||
"firstLayerBeltBump": 0,
|
||||
"outputBeltFirst": false,
|
||||
"outputLoops": 0,
|
||||
"sliceFillGrow": 0,
|
||||
"sliceSolidRate": 0,
|
||||
"sliceSupportSpan": 5,
|
||||
"sliceSupportOutline": true,
|
||||
"firstLayerFlatten": 0,
|
||||
"outputDraftShield": false,
|
||||
"outputAvoidGaps": true,
|
||||
"sliceDetectThin": "off",
|
||||
"outputAlternating": false,
|
||||
"sliceLayerStartX": 0,
|
||||
"sliceLayerStartY": 0,
|
||||
"sliceSupportGrow": 0,
|
||||
"outputFanLayer": 1,
|
||||
"outputNozzle": 0,
|
||||
"sliceAngle": 45,
|
||||
"sliceZInterleave": false
|
||||
}
|
||||
]
|
||||
}
|
||||
508
src/kiri-dev/fdm/Bambu.P1S
Normal file
508
src/kiri-dev/fdm/Bambu.P1S
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
{
|
||||
"mode": "FDM",
|
||||
"internal": 0,
|
||||
"bedHeight": 2.5,
|
||||
"bedWidth": 256,
|
||||
"bedDepth": 256,
|
||||
"bedRound": false,
|
||||
"maxHeight": 256,
|
||||
"originCenter": false,
|
||||
"gcodeFan": [
|
||||
"M106 S{fan_speed}"
|
||||
],
|
||||
"gcodeTrack": [
|
||||
"M73 P{progress}"
|
||||
],
|
||||
"gcodeLayer": [
|
||||
"; CHANGE_LAYER",
|
||||
"; layer num/total_layer_count: {layer}/{layers}",
|
||||
"M622.1 S1 ; for prev firware, default turned on",
|
||||
"M1002 judge_flag timelapse_record_flag",
|
||||
"M622 J1",
|
||||
"M971 S11 C10 O0 ; timelapse without wipe tower",
|
||||
"M623",
|
||||
"M73 L{layer}",
|
||||
"M991 S0 P{layer-1} ; notify layer change",
|
||||
";; IF { layer == 0 }",
|
||||
"M204 S500",
|
||||
";; ELSE",
|
||||
"M204 S5000",
|
||||
";; END"
|
||||
],
|
||||
"gcodePre": [
|
||||
"; total layer number: {layers}",
|
||||
";; PREAMBLE",
|
||||
";; DEFINE BAMBU-AMS 0,1,2,3",
|
||||
"; ===== HEADER ====================================",
|
||||
"M73 P0 R14 ; Initial progress and time remaining",
|
||||
"M201 X20000 Y20000 Z500 E5000 ; Set max acceleration",
|
||||
"M203 X500 Y500 Z20 E30 ; Set max feedrates",
|
||||
"M204 P20000 R5000 T20000 ; Set acceleration",
|
||||
"M205 X9.00 Y9.00 Z3.00 E2.50 ; Set advanced settings",
|
||||
"M106 S0 ; Set part fan speed to 0",
|
||||
"M106 P2 S0 ; Turn off aux fan",
|
||||
";===== machine: P1S ===============================",
|
||||
"M104 S75 ; Set extruder temp to turn on HB fan, prevent filament oozing",
|
||||
"M710 A1 S255 ; Turn on MC fan by default (P1S)",
|
||||
";===== Reset machine status =======================",
|
||||
"M290 X40 Y40 Z2.6666666 ; Set baby stepping offsets",
|
||||
"G91 ; Set to relative positioning",
|
||||
"M17 Z0.4 ; Lower Z-motor current",
|
||||
"G380 S2 Z30 F300 ; Lower hotbed (G380 like G38)",
|
||||
"G380 S2 Z-25 F300 ; Continue to lower bed",
|
||||
"G1 Z5 F300 ; Raise bed by 5mm",
|
||||
"G90 ; Set to absolute positioning",
|
||||
"M17 X1.2 Y1.2 Z0.75 ; Reset motor current to default",
|
||||
"M960 S5 P1 ; Turn on logo lamp",
|
||||
"M220 S100 ; Reset feedrate to 100%",
|
||||
"M221 S100 ; Reset flowrate to 100%",
|
||||
"M73.2 R1.0 ; Reset remaining time magnitude",
|
||||
"M1002 set_gcode_claim_speed_level : 5 ; Set G-code claim speed level",
|
||||
"M221 X0 Y0 Z0 ; Turn off soft endstop to prevent logic issues",
|
||||
"G29.1 Z0 ; Clear Z-trim value",
|
||||
"M204 S10000 ; Initialize acceleration to 10 m/s^2",
|
||||
";===== Heatbed preheat ============================",
|
||||
"M1002 gcode_claim_action : 2 ; Claim action for preheating",
|
||||
"M140 S{bed_temp} ; Set bed temperature to 65°C",
|
||||
"M190 S{bed_temp} ; Wait for bed temperature to reach 65°C",
|
||||
";===== Turn on fans to prevent PLA jamming ========",
|
||||
"M106 P3 S180 ; set chamber fan speed to prevent PLA jamming",
|
||||
"M106 P2 S100 ; Turn on aux fan to cool toolhead",
|
||||
";===== Prepare print temperature and material =====",
|
||||
"M104 S{temp} ; Set extruder temp to 220°C",
|
||||
"G91 ; Set to relative positioning",
|
||||
"G0 Z10 F1200 ; Raise Z by 10mm",
|
||||
"G90 ; Set to absolute positioning",
|
||||
"G28 X ; Home X axis",
|
||||
"M975 S1 ; Turn on feature (guess: vibration suppression)",
|
||||
"M73 P31 R9 ; Update progress and time remaining",
|
||||
"G1 X60 F12000 ; Fast move to X60",
|
||||
"G1 Y245 ; Move to Y245",
|
||||
"G1 Y265 F3000 ; Move to Y265 slowly",
|
||||
"M620 M ; Custom command (guess: material management)",
|
||||
"M620 S{tool}A ; Switch material if AMS present",
|
||||
"M109 S{temp} ; Wait for extruder to reach 220°C",
|
||||
"G1 X120 F12000 ; Fast move to X120",
|
||||
"G1 X20 Y50 F12000 ; Fast move to X20 Y50",
|
||||
"G1 Y-3 ; Move down Y-axis by 3",
|
||||
"T{tool} ; Select starting tool",
|
||||
"G1 X54 F12000 ; Fast move to X54",
|
||||
"G1 Y265 ; Move to Y265",
|
||||
"M400 ; Wait for all moves to finish",
|
||||
"M621 S{tool}A ; Custom command",
|
||||
"M620.1 E F523.843 T240 ; Extrude command with custom parameters",
|
||||
"M412 S1 ; Turn on filament runout detection",
|
||||
"M109 S250 ; Set nozzle to common flush temp",
|
||||
"M106 P1 S0 ; Turn off nozzle fan",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"G1 E50 F200 ; Extrude 50mm of filament",
|
||||
"M400 ; Wait for moves to finish",
|
||||
"M104 S{temp} ; Set nozzle temperature to 220°C",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"G1 E50 F200 ; Extrude 50mm of filament",
|
||||
"M400 ; Wait for moves to finish",
|
||||
"M106 P1 S255 ; Turn on nozzle fan to full speed",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"G1 E5 F300 ; Extrude 5mm of filament",
|
||||
"M109 S200 ; Drop nozzle temperature to 200°C to shrink filament",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"M73 P33 R9 ; Update progress and time remaining",
|
||||
"G1 E-0.5 F300 ; Retract filament by 0.5mm",
|
||||
"M73 P35 R9 ; Update progress and time remaining",
|
||||
"G1 X70 F9000 ; Fast move to X70",
|
||||
"G1 X76 F15000 ; Fast move to X76",
|
||||
"G1 X65 F15000 ; Fast move to X65",
|
||||
"G1 X76 F15000 ; Repeat movements to shake and clean nozzle",
|
||||
"G1 X65 F15000 ; Shake to put down garbage",
|
||||
"G1 X80 F6000 ; Move to X80",
|
||||
"G1 X95 F15000 ; Fast move to X95",
|
||||
"G1 X80 F15000 ; Return to X80",
|
||||
"G1 X165 F15000 ; Wipe and shake",
|
||||
"M400 ; Wait for all moves to finish",
|
||||
"M106 P1 S0 ; Turn off nozzle fan",
|
||||
";===== Wipe nozzle ===============================",
|
||||
"M1002 gcode_claim_action : 14 ; Claim action for nozzle wipe",
|
||||
"M975 S1 ; Turn on feature (guess: vibration suppression)",
|
||||
"M106 S255 ; Turn on part fan to full speed",
|
||||
"G1 X65 Y230 F18000 ; Fast move to start of wipe",
|
||||
"G1 Y264 F6000 ; Wipe along Y-axis",
|
||||
"M109 S200 ; Set nozzle temperature to 200°C",
|
||||
"G1 X100 F18000 ; Wipe first pass",
|
||||
"G0 X135 Y253 F20000 ; Move to exposed steel surface edge",
|
||||
"G28 Z P0 T300 ; Home Z with low precision, permit 300°C temperature",
|
||||
"G29.2 S0 ; Turn off ABL (auto bed leveling)",
|
||||
"G0 Z5 F20000 ; Raise Z by 5mm",
|
||||
"G1 X60 Y265 ; Move to X60 Y265",
|
||||
"G92 E0 ; Reset extruder position",
|
||||
"G1 E-0.5 F300 ; Retract more",
|
||||
"G1 X100 F5000 ; Second wipe pass",
|
||||
"G1 X70 F15000 ; Repeat movements for further wiping",
|
||||
"G1 X100 F5000",
|
||||
"G1 X70 F15000",
|
||||
"G1 X100 F5000",
|
||||
"G1 X70 F15000",
|
||||
"G1 X90 F5000",
|
||||
"G0 X128 Y261 Z-1.5 F20000 ; Move to exposed steel surface, stop nozzle",
|
||||
"M104 S140 ; Set temp down to heatbed acceptable",
|
||||
"M106 S255 ; Turn on part fan (G28 turned off fan)",
|
||||
"M221 S ; Push soft endstop status",
|
||||
"M221 Z0 ; Turn off Z axis endstop",
|
||||
"G0 Z0.5 F20000 ; Raise Z by 0.5mm",
|
||||
"G0 X125 Y259.5 Z-1.01 ; Move to wiping position",
|
||||
"G0 X131 F211",
|
||||
"G0 X124",
|
||||
"G0 Z0.5 F20000",
|
||||
"G0 X125 Y262.5",
|
||||
"G0 Z-1.01",
|
||||
"G0 X131 F211",
|
||||
"G0 X124",
|
||||
"G0 Z0.5 F20000",
|
||||
"G0 X125 Y260.0",
|
||||
"G0 Z-1.01",
|
||||
"G0 X131 F211",
|
||||
"G0 X124",
|
||||
"G0 Z0.5 F20000",
|
||||
"G0 X125 Y262.0",
|
||||
"G0 Z-1.01",
|
||||
"G0 X131 F211",
|
||||
"G0 X124",
|
||||
"G0 Z0.5 F20000",
|
||||
"G0 X125 Y260.5",
|
||||
"G0 Z-1.01",
|
||||
"G0 X131 F211",
|
||||
"G0 X124",
|
||||
"G0 Z0.5 F20000",
|
||||
"G0 X125 Y261.5",
|
||||
"G0 Z-1.01",
|
||||
"G0 X131 F211",
|
||||
"G0 X124",
|
||||
"G0 Z0.5 F20000",
|
||||
"G0 X125 Y261.0",
|
||||
"G0 Z-1.01",
|
||||
"G0 X131 F211",
|
||||
"G0 X124",
|
||||
"G0 X128",
|
||||
"G2 I0.5 J0 F300 ; Arc movements for final cleaning",
|
||||
"M73 P36 R8 ; Update progress and time remaining",
|
||||
"G2 I0.5 J0 F300",
|
||||
"G2 I0.5 J0 F300",
|
||||
"G2 I0.5 J0 F300",
|
||||
"M109 S140 ; Wait for nozzle temp to reach heatbed acceptable temp",
|
||||
"G2 I0.5 J0 F3000 ; More arc movements",
|
||||
"G2 I0.5 J0 F3000",
|
||||
"G2 I0.5 J0 F3000",
|
||||
"G2 I0.5 J0 F3000",
|
||||
"M221 R ; Pop softend status",
|
||||
"G1 Z10 F1200 ; Raise Z by 10mm",
|
||||
"M400 ; Wait for all moves to finish",
|
||||
"G1 Z10 ; Raise Z by 10mm",
|
||||
"G1 F30000 ; Set fast feedrate",
|
||||
"G1 X230 Y15 ; Move to X230 Y15",
|
||||
"G29.2 S1 ; Turn on ABL",
|
||||
"M106 S0 ; Turn off part fan, too noisy",
|
||||
";===== Bed leveling ===============================",
|
||||
"M1002 judge_flag g29_before_print_flag ; Judge flag before leveling",
|
||||
"M622 J1",
|
||||
" M1002 gcode_claim_action : 1 ; Claim action for bed leveling",
|
||||
" G29 A X115.2 Y115.2 I25.6 J25.6 ; Perform bed leveling",
|
||||
" M400 ; Wait for all moves to finish",
|
||||
" M500 ; Save calibration data",
|
||||
"M623",
|
||||
";===== Home after wipe mouth ======================",
|
||||
"M1002 judge_flag g29_before_print_flag ; Judge flag before homing",
|
||||
"M622 J0",
|
||||
" M1002 gcode_claim_action : 13 ; Claim action for homing",
|
||||
" G28 ; Home all axes",
|
||||
"M623",
|
||||
";===== Home after wipe mouth end ==================",
|
||||
"M975 S1 ; Turn on vibration suppression",
|
||||
";===== Turn on fans to prevent PLA jamming ========",
|
||||
"M106 P3 S180 ; set chamber fan speed to Prevent PLA jamming",
|
||||
"M106 P2 S100 ; Turn on aux fan to cool toolhead",
|
||||
"M104 S{temp} ; Set extruder temp to 220°C earlier, reduce wait time",
|
||||
";===== Mech mode fast check =======================",
|
||||
"G1 X128 Y128 Z10 F20000 ; Move to center for check",
|
||||
"M400 P200 ; Wait and perform check",
|
||||
"M970.3 Q1 A7 B30 C80 H15 K0 ; Custom command (mechanical check)",
|
||||
"M974 Q1 S2 P0 ; Custom command",
|
||||
"G1 X128 Y128 Z10 F20000 ; Move again to center for check",
|
||||
"M400 P200 ; Wait and perform another check",
|
||||
"M970.3 Q0 A7 B30 C90 Q0 H15 K0 ; Custom command",
|
||||
"M974 Q0 S2 P0 ; Custom command",
|
||||
"M975 S1 ; Turn on feature (vibration suppression)",
|
||||
"G1 F30000 ; Set fast feedrate",
|
||||
"M73 P37 R8 ; Update progress and time remaining",
|
||||
"G1 X230 Y15 ; Move to X230 Y15",
|
||||
"G28 X ; Re-home X and Y",
|
||||
";===== Nozzle load line ===========================",
|
||||
"M975 S1 ; Turn on vibration suppression",
|
||||
"G90 ; Set to absolute positioning",
|
||||
"M83 ; Set extruder to relative mode",
|
||||
"T1000 ; Custom command",
|
||||
"G1 X18.0 Y1.0 Z0.8 F18000 ; Move to start position",
|
||||
"M109 S{temp} ; Set extruder temp to 220°C",
|
||||
"G1 Z0.2 ; Lower Z to 0.2mm",
|
||||
"G0 E2 F300 ; Extrude 2mm of filament",
|
||||
"G0 X240 E25 F5539.96 ; Move to X240 while extruding",
|
||||
"G0 Y15 E1.166 F1384.99 ; Move along Y while extruding",
|
||||
"G0 X239.5 ; Move to X239.5",
|
||||
"G0 E0.2 ; Extrude 0.2mm of filament",
|
||||
"G0 Y1.5 E1.166 ; Move along Y while extruding",
|
||||
"G0 X18 E25 F5539.96 ; Return to start position while extruding",
|
||||
"M400 ; Wait for all moves to finish",
|
||||
";===== Final Preparations =========================",
|
||||
";G29.1 Z-0.04 ; Adjust Z-offset for textured PEI plate",
|
||||
"M1002 gcode_claim_action : 0 ; Claim action",
|
||||
"M106 S0 ; Turn off part fan",
|
||||
"M106 P2 S0 ; Turn off aux fan",
|
||||
"M106 P3 S0 ; Turn off chamber fan",
|
||||
"M975 S1 ; Turn on mechanical mode suppression",
|
||||
"G90 ; Set to absolute positioning",
|
||||
"G21 ; Set units to millimeters",
|
||||
"M83 ; Use relative distances for extrusion",
|
||||
"M106 P3 S200 ; Set chamber fan speed to 200 (prevents PLA jamming)",
|
||||
"M981 S1 P20000 ; Open spaghetti detector"
|
||||
],
|
||||
"gcodePost": [
|
||||
"; ===== FOOTER =====================================",
|
||||
"M106 S0 ; Turn off part cooling fan",
|
||||
"M106 P2 S0 ; Turn off auxiliary cooling fan",
|
||||
"M981 S0 P20000 ; Close spaghetti detector",
|
||||
"M106 P3 S0 ; Turn off chamber fan",
|
||||
"M400 ; Wait for buffer to clear",
|
||||
"G92 E0 ; Zero the extruder",
|
||||
"G1 E-0.8 F1800 ; Retract filament by 0.8mm",
|
||||
"G91 ; relative moves",
|
||||
"G1 Z5 F900 ; drop bed 5mm",
|
||||
"G90 ; absolute moves",
|
||||
"G1 X65 Y245 F12000 ; Move to safe position X65 Y245",
|
||||
"G1 Y265 F3000 ; Move to Y265 slowly",
|
||||
"G1 X65 Y245 F12000 ; Move back to X65 Y245",
|
||||
"G1 Y265 F3000 ; Move to Y265 slowly again",
|
||||
"M140 S0 ; Turn off heated bed",
|
||||
"M106 S0 ; Turn off part cooling fan",
|
||||
"M106 P2 S0 ; Turn off auxiliary cooling fan",
|
||||
"M106 P3 S0 ; Turn off chamber cooling fan",
|
||||
"G1 X100 F12000 ; Wipe nozzle",
|
||||
"M620 S255 ; Pull back filament to AMS",
|
||||
"G1 X20 Y50 F12000 ; Move to X20 Y50",
|
||||
"G1 Y-3 ; Move down Y-axis by 3",
|
||||
"T255 ; Tool change command (educated guess)",
|
||||
"G1 X65 F12000 ; Move to X65",
|
||||
"G1 Y265 ; Move to Y265",
|
||||
"G1 X100 F12000 ; Wipe nozzle again",
|
||||
"M621 S255 ; Custom command (educated guess)",
|
||||
"M104 S0 ; Turn off hotend",
|
||||
"M622.1 S1 ; Enable feature (default for older firmware)",
|
||||
"M1002 judge_flag timelapse_record_flag ; Check if timelapse recording is needed",
|
||||
"M622 J1 ; Enable timelapse",
|
||||
" M400 ; Wait for all motions to complete",
|
||||
" M991 S0 P-1 ; End smooth timelapse at safe position",
|
||||
" M400 S3 ; Wait for last picture to be taken",
|
||||
"M623 ; End of \"timelapse_record_flag\"",
|
||||
"M400 ; Wait for all motions to complete",
|
||||
"M17 S ; Engage stepper motors",
|
||||
"M17 Z0.4 ; Lower Z motor current to reduce impact if obstruction exists",
|
||||
"G1 Z{z_max} F600 ; Drop bed",
|
||||
"M400 P100 ; Wait for 100ms",
|
||||
"M17 R ; Restore Z motor current",
|
||||
"M220 S100 ; Reset feedrate magnitude to 100%",
|
||||
"M201.2 K1.0 ; Reset acceleration magnitude",
|
||||
"M73.2 R1.0 ; Reset remaining time magnitude",
|
||||
"M1002 set_gcode_claim_speed_level : 0 ; Set G-code claim speed level to 0",
|
||||
"M17 X0.8 Y0.8 Z0.5 ; Lower motor current to 45% power",
|
||||
"M73 P100 R0 ; Set progress to 100% with 0 remaining time"
|
||||
],
|
||||
"gcodeProc": "",
|
||||
"gcodeFExt": "gcode",
|
||||
"extruders": [
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [
|
||||
"; BEGIN tool change from {last_tool} to {tool}",
|
||||
"M620 S{tool}A ; prepare tool change",
|
||||
"M204 S9000 ; Set acceleration to 9000 mm/s^2",
|
||||
"M620.11 S0 ; Reset filament retraction state",
|
||||
"M400 ; wait for moves to complete",
|
||||
"M620.1 E F187 T240 ; set purge rate 187 temp 240",
|
||||
"T{tool} ; initiate tool change",
|
||||
"M620.1 E F374 T240 ; set purge rate 374 temp 240",
|
||||
"M620.11 S0 ; Reset filament retraction state",
|
||||
"G92 E0 ; reset extruder position",
|
||||
"M400 ; wait for moves to complete",
|
||||
" ; -- PURGE --",
|
||||
"M109 S240 ; Set nozzle temperature to 240°C",
|
||||
"G1 E23.7 F187 ; Extrude 23.7mm of filament at flowrate 187",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F187 ; Continue extrusion at flowrate 187",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F374 ; Continue extrusion at flowrate 374",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F374 ; Continue extrusion at flowrate 374",
|
||||
"G1 E0.914611 F50 ; Pulsatile extrusion",
|
||||
"G1 E10.518 F374 ; Continue extrusion at flowrate 374",
|
||||
"G1 E-2 F1800 ; Retract filament by 2mm",
|
||||
"G1 E2 F300 ; Recover retraction slowly",
|
||||
"M400 ; Wait for all movements to complete",
|
||||
"M109 S{temp} ; Set nozzle temperature back to print temp",
|
||||
" ; -- SHAKE --",
|
||||
"M106 P1 S255 ; Turn on nozzle cooling fan to full speed",
|
||||
"M400 S3 ; Wait for all movements to complete",
|
||||
"G1 X70 F5000 ; Move to X70",
|
||||
"G1 X90 F3000 ; Move to X90",
|
||||
"G1 Y255 F4000 ; Move to Y255",
|
||||
"G1 X105 F5000 ; Move to X105",
|
||||
"G1 Y265 ; Move to Y265",
|
||||
"G1 X70 F10000 ; Rapid move to X70",
|
||||
"G1 X100 F5000 ; Move to X100",
|
||||
"G1 X70 F10000 ; Rapid move back to X70",
|
||||
"G1 X100 F5000 ; Move to X100",
|
||||
"G1 X70 F10000 ; Shake filament residue",
|
||||
"G1 X80 F15000",
|
||||
"G1 X60",
|
||||
"G1 X80",
|
||||
"G1 X60",
|
||||
"G1 X80 ; Shake to put down garbage",
|
||||
"G1 X100 F5000 ; Move to X100",
|
||||
"G1 X165 F15000 ; Wipe and shake",
|
||||
"G1 Y256 ; Move Y aside to prevent collision",
|
||||
"M400 ; Wait for all movements to complete",
|
||||
"M204 S10000 ; Set acceleration to 10000 mm/s^2",
|
||||
"M621 S{tool}A ; complete tool change",
|
||||
"; END tool change"
|
||||
],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
},
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
},
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
},
|
||||
{
|
||||
"extFilament": 1.75,
|
||||
"extNozzle": 0.4,
|
||||
"extSelect": [],
|
||||
"extOffsetX": 0,
|
||||
"extOffsetY": 0,
|
||||
"extDeselect": []
|
||||
}
|
||||
],
|
||||
"new": false,
|
||||
"deviceName": "Bambu P1S",
|
||||
"bedBelt": false,
|
||||
"fwRetract": false,
|
||||
"filamentSource": "direct",
|
||||
"extras": {
|
||||
"bbl": {}
|
||||
},
|
||||
"imageURL": "",
|
||||
"deviceZMax": 0,
|
||||
"gcodeTime": 1,
|
||||
"gcodeFeature": [],
|
||||
"profiles": [
|
||||
{
|
||||
"processName": "Bambu PLA",
|
||||
"sliceHeight": 0.2,
|
||||
"sliceShells": 2,
|
||||
"sliceShellOrder": "in-out",
|
||||
"sliceLayerStart": "last",
|
||||
"sliceFillAngle": 45,
|
||||
"sliceFillOverlap": 0.35,
|
||||
"sliceFillSparse": 0.1,
|
||||
"sliceFillType": "hex",
|
||||
"sliceAdaptive": false,
|
||||
"sliceMinHeight": 0,
|
||||
"sliceSupportDensity": 0.2,
|
||||
"sliceSupportOffset": 0.4,
|
||||
"sliceSupportGap": 1,
|
||||
"sliceSupportSize": 5,
|
||||
"sliceSupportArea": 0.25,
|
||||
"sliceSupportExtra": 0,
|
||||
"sliceSupportAngle": 60,
|
||||
"sliceSupportNozzle": 0,
|
||||
"sliceSolidMinArea": 0,
|
||||
"sliceBottomLayers": 2,
|
||||
"sliceTopLayers": 3,
|
||||
"firstLayerRate": 20,
|
||||
"firstLayerPrintMult": 1,
|
||||
"firstLayerYOffset": 0,
|
||||
"firstLayerBrim": 0,
|
||||
"firstLayerBeltLead": 0,
|
||||
"firstLayerFanSpeed": 0,
|
||||
"outputTemp": 210,
|
||||
"outputBedTemp": 60,
|
||||
"outputFanSpeed": 255,
|
||||
"outputFeedrate": 110,
|
||||
"outputFinishrate": 90,
|
||||
"outputSeekrate": 200,
|
||||
"outputShellMult": 1.2,
|
||||
"outputFillMult": 1.2,
|
||||
"outputSparseMult": 1.2,
|
||||
"outputRetractDist": 1,
|
||||
"outputRetractSpeed": 80,
|
||||
"outputRetractWipe": 0,
|
||||
"outputRetractDwell": 0,
|
||||
"outputShortPoly": 50,
|
||||
"outputMinSpeed": 5,
|
||||
"outputCoastDist": 0,
|
||||
"outputLayerRetract": false,
|
||||
"zHopDistance": 0,
|
||||
"antiBacklash": 0,
|
||||
"sliceFillWidth": 1,
|
||||
"sliceFillRate": 0,
|
||||
"sliceSupportEnable": false,
|
||||
"firstSliceHeight": 0.3,
|
||||
"firstLayerFillRate": 80,
|
||||
"firstLayerLineMult": 1,
|
||||
"firstLayerNozzleTemp": 220,
|
||||
"firstLayerBedTemp": 65,
|
||||
"firstLayerBrimTrig": 0,
|
||||
"firstLayerBrimGap": 0,
|
||||
"outputRaft": false,
|
||||
"outputRaftSpacing": 0.2,
|
||||
"outputBrimCount": 0,
|
||||
"outputBrimOffset": 2,
|
||||
"outputPurgeTower": 0,
|
||||
"outputInvertX": false,
|
||||
"outputInvertY": false,
|
||||
"arcTolerance": 0,
|
||||
"ranges": [],
|
||||
"sliceLineWidth": 0,
|
||||
"sliceFillRepeat": 2,
|
||||
"firstLayerBrimIn": 0,
|
||||
"firstLayerBeltBump": 0,
|
||||
"outputBeltFirst": false,
|
||||
"outputLoops": 0,
|
||||
"sliceFillGrow": 0,
|
||||
"sliceSolidRate": 0,
|
||||
"sliceSupportSpan": 5,
|
||||
"sliceSupportOutline": false,
|
||||
"firstLayerFlatten": 0,
|
||||
"outputDraftShield": false,
|
||||
"outputAvoidGaps": true,
|
||||
"sliceDetectThin": "off",
|
||||
"outputAlternating": false,
|
||||
"sliceLayerStartX": 0,
|
||||
"sliceLayerStartY": 0,
|
||||
"sliceSupportGrow": 0,
|
||||
"outputFanLayer": 1,
|
||||
"outputNozzle": 0,
|
||||
"sliceAngle": 45,
|
||||
"sliceZInterleave": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
"G28 W ; home all without mesh bed level",
|
||||
"G92 E0.0",
|
||||
"G1 F{600} ",
|
||||
"M425 X0 Y0 Z0 ; Set backlash to specific values for all axis",
|
||||
"M425 F1 S3 ; Enable backlash compensation at 100% for 3 mm",
|
||||
"M117 ULIO 3D BRIX Printing"
|
||||
],
|
||||
"gcodePost": [
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
"G28 W ; home all without mesh bed level",
|
||||
"G92 E0.0",
|
||||
"G1 F{600} ",
|
||||
"M425 X0 Y0 Z0 ; Set backlash to specific values for all axis",
|
||||
"M425 F1 S3 ; Enable backlash compensation at 100% for 3 mm",
|
||||
"M117 ULIO 3D STEAM Printing"
|
||||
],
|
||||
"gcodePost": [
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
// dep: kiri-mode.cam.driver
|
||||
// use: kiri-mode.cam.animate
|
||||
// use: kiri-mode.cam.animate2
|
||||
// use: kiri-mode.cam.tools
|
||||
// use: load.gbr
|
||||
gapp.register("kiri-mode.cam.client", [], (root, exports) => {
|
||||
|
||||
const { base, kiri } = root;
|
||||
const { newPoint, newPolygon } = base;
|
||||
const { driver } = kiri;
|
||||
const { CAM } = driver;
|
||||
const DEG2RAD = Math.PI / 180;
|
||||
|
|
@ -23,6 +23,7 @@ let isAnimate,
|
|||
isIndexed,
|
||||
isParsed,
|
||||
camStock,
|
||||
camZTop,
|
||||
camZBottom,
|
||||
current,
|
||||
currentIndex,
|
||||
|
|
@ -508,7 +509,7 @@ CAM.init = function(kiri, api) {
|
|||
let clazz = notime ? [ "draggable", "notime" ] : [ "draggable" ];
|
||||
let notable = rec.note ? rec.note.split(' ').filter(v => v.charAt(0) === '#') : undefined;
|
||||
if (clock) { clazz.push('clock'); title = ` title="end of ops chain\ndrag/drop like an op\nops after this are disabled"` }
|
||||
if (notable?.length) label = notable[0].slice(1);
|
||||
if (notable?.length) label += ` (${notable[0].slice(1)})`;
|
||||
html.appendAll([
|
||||
`<div id="${mark+i}" class="${clazz.join(' ')}"${title}>`,
|
||||
`<label class="label">${label}</label>`,
|
||||
|
|
@ -610,6 +611,10 @@ CAM.init = function(kiri, api) {
|
|||
}, 250);
|
||||
}
|
||||
function onDown(ev) {
|
||||
if (!ev.target.rec) {
|
||||
// only trigger on operation buttons bound to recs
|
||||
return;
|
||||
}
|
||||
let mobile = ev.touches;
|
||||
func.surfaceDone();
|
||||
func.traceDone();
|
||||
|
|
@ -930,6 +935,9 @@ CAM.init = function(kiri, api) {
|
|||
// SURFACE FUNCS
|
||||
let surfaceOn = false, lastWidget;
|
||||
func.surfaceAdd = (ev) => {
|
||||
if (surfaceOn) {
|
||||
return func.surfaceDone();
|
||||
}
|
||||
func.clearPops();
|
||||
alert = api.show.alert("analyzing surfaces...", 1000);
|
||||
let surfaces = poppedRec.surfaces;
|
||||
|
|
@ -981,6 +989,9 @@ CAM.init = function(kiri, api) {
|
|||
// TRACE FUNCS
|
||||
let traceOn = false, lastTrace;
|
||||
func.traceAdd = (ev) => {
|
||||
if (traceOn) {
|
||||
return func.traceDone();
|
||||
}
|
||||
func.clearPops();
|
||||
alert = api.show.alert("analyzing parts...", 1000);
|
||||
traceOn = hoveredOp;
|
||||
|
|
@ -1281,6 +1292,10 @@ CAM.init = function(kiri, api) {
|
|||
return current.device.spindleMax > 0;
|
||||
}
|
||||
|
||||
function zTop() {
|
||||
return API.conf.get().process.camZTop > 0;
|
||||
}
|
||||
|
||||
function zBottom() {
|
||||
return API.conf.get().process.camZBottom > 0;
|
||||
}
|
||||
|
|
@ -1318,7 +1333,9 @@ CAM.init = function(kiri, api) {
|
|||
voids: 'camRoughVoid',
|
||||
flats: 'camRoughFlat',
|
||||
inside: 'camRoughIn',
|
||||
top: 'camRoughTop'
|
||||
ov_topz: 0,
|
||||
ov_botz: 0,
|
||||
ov_conv: '~camConventional',
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
|
|
@ -1334,8 +1351,13 @@ CAM.init = function(kiri, api) {
|
|||
all: UC.newBoolean(LANG.cr_clst_s, undefined, {title:LANG.cr_clst_l, show:hasIndexing}),
|
||||
voids: UC.newBoolean(LANG.cr_clrp_s, undefined, {title:LANG.cr_clrp_l}),
|
||||
flats: UC.newBoolean(LANG.cr_clrf_s, undefined, {title:LANG.cr_clrf_l}),
|
||||
top: UC.newBoolean(LANG.cr_clrt_s, undefined, {title:LANG.cr_clrt_l}),
|
||||
inside: UC.newBoolean(LANG.cr_olin_s, undefined, {title:LANG.cr_olin_l})
|
||||
inside: UC.newBoolean(LANG.cr_olin_s, undefined, {title:LANG.cr_olin_l}),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
exp: UC.newExpand("overrides"),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, {title:LANG.ou_ztop_l, convert:UC.toFloat, units:true}),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:UC.toFloat, units:true}),
|
||||
ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, {title:LANG.ou_conv_l}),
|
||||
exp_end: UC.endExpand(),
|
||||
};
|
||||
|
||||
createPopOp('outline', {
|
||||
|
|
@ -1352,7 +1374,10 @@ CAM.init = function(kiri, api) {
|
|||
outside: 'camOutlineOut',
|
||||
inside: 'camOutlineIn',
|
||||
wide: 'camOutlineWide',
|
||||
top: 'camOutlineTop'
|
||||
top: 'camOutlineTop',
|
||||
ov_topz: 0,
|
||||
ov_botz: 0,
|
||||
ov_conv: '~camConventional',
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
|
|
@ -1371,6 +1396,12 @@ CAM.init = function(kiri, api) {
|
|||
omitvoid: UC.newBoolean(LANG.co_omvd_s, undefined, {title:LANG.co_omvd_l, xshow:(op) => { return op.inputs.outside.checked }}),
|
||||
wide: UC.newBoolean(LANG.co_wide_s, undefined, {title:LANG.co_wide_l, show:(op) => { return !op.inputs.inside.checked }}),
|
||||
dogbones: UC.newBoolean(LANG.co_dogb_s, undefined, {title:LANG.co_dogb_l, show:(op) => { return !op.inputs.wide.checked }}),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
exp: UC.newExpand("overrides"),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, {title:LANG.ou_ztop_l, convert:UC.toFloat, units:true}),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:UC.toFloat, units:true}),
|
||||
ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, {title:LANG.ou_conv_l}),
|
||||
exp_end: UC.endExpand(),
|
||||
};
|
||||
|
||||
const contourFilter = gcodeEditor('Layer Filter', 'filter');
|
||||
|
|
@ -1422,7 +1453,7 @@ CAM.init = function(kiri, api) {
|
|||
tolerance: 'camTolerance',
|
||||
filter: 'camContourFilter',
|
||||
leave: 'camContourLeave',
|
||||
axis: 'X'
|
||||
linear: 'camLatheLinear'
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
// axis: UC.newSelect(LANG.cd_axis, {}, "xyaxis"),
|
||||
|
|
@ -1435,6 +1466,8 @@ CAM.init = function(kiri, api) {
|
|||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
tolerance: UC.newInput(LANG.ou_toll_s, {title:LANG.ou_toll_l, convert:UC.toFloat, bound:UC.bound(0,10.0), units:true, round:4}),
|
||||
leave: UC.newInput(LANG.cf_leav_s, {title:LANG.cf_leav_l, convert:UC.toFloat, bound:UC.bound(0,100)}),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
linear: UC.newBoolean(LANG.ci_line_s, undefined, {title:LANG.ci_line_l}),
|
||||
// filter: UC.newRow([ UC.newButton(LANG.filter, contourFilter) ], {class:"ext-buttons f-row"})
|
||||
};
|
||||
|
||||
|
|
@ -1461,11 +1494,14 @@ CAM.init = function(kiri, api) {
|
|||
thru: 'camTraceThru',
|
||||
rate: 'camTraceSpeed',
|
||||
plunge: 'camTracePlunge',
|
||||
bottom: 'camTraceBottom',
|
||||
offover: 'camTraceOffOver',
|
||||
dogbone: 'camTraceDogbone',
|
||||
revbone: 'camTraceDogbone',
|
||||
select: 'camTraceMode'
|
||||
merge: 'camTraceMerge',
|
||||
select: 'camTraceMode',
|
||||
ov_topz: 0,
|
||||
ov_botz: 0,
|
||||
ov_conv: '~camConventional',
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
select: UC.newSelect(LANG.cc_sele_s, {title:LANG.cc_sele_l}, "select"),
|
||||
|
|
@ -1481,14 +1517,17 @@ CAM.init = function(kiri, api) {
|
|||
thru: UC.newInput(LANG.cc_thru_s, {title:LANG.cc_thru_l, convert:UC.toFloat, units:true}),
|
||||
offover: UC.newInput(LANG.cc_offd_s, {title:LANG.cc_offd_l, convert:UC.toFloat, units:true, show:() => poppedRec.offset !== "none"}),
|
||||
sep: UC.newBlank({class:"pop-sep", modes:MCAM, xshow:zDogSep}),
|
||||
bottom: UC.newBoolean(LANG.cf_botm_s, undefined, {title:LANG.cf_botm_l, show:(op,conf) => conf.process.camZBottom}),
|
||||
merge: UC.newBoolean(LANG.co_merg_s, undefined, {title:LANG.co_merg_l, show:() => !popOp.trace.rec.down}),
|
||||
dogbone: UC.newBoolean(LANG.co_dogb_s, undefined, {title:LANG.co_dogb_l, show:canDogBones}),
|
||||
revbone: UC.newBoolean(LANG.co_dogr_s, undefined, {title:LANG.co_dogr_l, show:canDogBonesRev}),
|
||||
exp: UC.newExpand("overrides"),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
menu: UC.newRow([
|
||||
UC.newButton(undefined, func.traceAdd, {icon:'<i class="fas fa-plus"></i>'}),
|
||||
UC.newButton(undefined, func.traceDone, {icon:'<i class="fas fa-check"></i>'}),
|
||||
], {class:"ext-buttons f-row"}),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, {title:LANG.ou_ztop_l, convert:UC.toFloat, units:true}),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:UC.toFloat, units:true}),
|
||||
ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, {title:LANG.ou_conv_l}),
|
||||
exp_end: UC.endExpand(),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
menu: UC.newRow([ UC.newButton("select", func.traceAdd) ], {class:"ext-buttons f-row"}),
|
||||
};
|
||||
|
||||
createPopOp('pocket', {
|
||||
|
|
@ -1505,6 +1544,9 @@ CAM.init = function(kiri, api) {
|
|||
contour: 'camPocketContour',
|
||||
engrave: 'camPocketEngrave',
|
||||
outline: 'camPocketOutline',
|
||||
ov_topz: 0,
|
||||
ov_botz: 0,
|
||||
ov_conv: '~camConventional',
|
||||
tolerance: 'camTolerance',
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
|
|
@ -1525,11 +1567,14 @@ CAM.init = function(kiri, api) {
|
|||
contour: UC.newBoolean(LANG.cp_cont_s, undefined, {title:LANG.cp_cont_s}),
|
||||
outline: UC.newBoolean(LANG.cp_outl_s, undefined, {title:LANG.cp_outl_l, show:() => !poppedRec.contour}),
|
||||
engrave: UC.newBoolean(LANG.cp_engr_s, undefined, {title:LANG.cp_engr_l, show:() => poppedRec.contour}),
|
||||
exp: UC.newExpand("overrides"),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
menu: UC.newRow([
|
||||
UC.newButton(undefined, func.surfaceAdd, {icon:'<i class="fas fa-plus"></i>'}),
|
||||
UC.newButton(undefined, func.surfaceDone, {icon:'<i class="fas fa-check"></i>'}),
|
||||
], {class:"ext-buttons f-row"}),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, {title:LANG.ou_ztop_l, convert:UC.toFloat, units:true}),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:UC.toFloat, units:true}),
|
||||
ov_conv: UC.newBoolean(LANG.ou_conv_s, undefined, {title:LANG.ou_conv_l}),
|
||||
exp_end: UC.endExpand(),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
menu: UC.newRow([ UC.newButton("select", func.surfaceAdd) ], {class:"ext-buttons f-row"}),
|
||||
};
|
||||
|
||||
createPopOp('drill', {
|
||||
|
|
@ -1584,9 +1629,7 @@ CAM.init = function(kiri, api) {
|
|||
sep: UC.newBlank({class:"pop-sep", modes:MCAM, show:zBottom}),
|
||||
invert: UC.newBoolean(LANG.cf_nvrt_s, undefined, {title:LANG.cf_nvrt_l, show:zBottom}),
|
||||
sep: UC.newBlank({class:"pop-sep"}),
|
||||
action: UC.newRow([
|
||||
UC.newButton(LANG.cf_menu, func.opFlip)
|
||||
], {class:"ext-buttons f-row"})
|
||||
action: UC.newRow([ UC.newButton(LANG.cf_menu, func.opFlip) ], {class:"ext-buttons f-row"})
|
||||
};
|
||||
|
||||
createPopOp('gcode', {
|
||||
|
|
@ -1669,8 +1712,16 @@ function createPopOp(type, map) {
|
|||
for (let [key, val] of Object.entries(op.inputs)) {
|
||||
let type = val.type;
|
||||
let from = map[key];
|
||||
if (rec[key] === undefined && type && from) {
|
||||
rec[key] = current.process[from];
|
||||
let rval = rec[key];
|
||||
// fill undef entries older defines
|
||||
if (type && (rval === null || rval === undefined)) {
|
||||
if (typeof(from) === 'string') {
|
||||
rec[key] = current.process[from];
|
||||
} else if (from !== undefined) {
|
||||
rec[key] = from;
|
||||
} else {
|
||||
console.log('error', { key, val, type, from });
|
||||
}
|
||||
}
|
||||
}
|
||||
API.util.rec2ui(rec, op.inputs);
|
||||
|
|
@ -1683,7 +1734,7 @@ function createPopOp(type, map) {
|
|||
API.util.ui2rec(op.rec, op.inputs);
|
||||
for (let [key, val] of Object.entries(op.rec)) {
|
||||
let saveTo = map[key];
|
||||
if (saveTo) {
|
||||
if (saveTo && typeof(key) === 'string' && !key.startsWith("~")) {
|
||||
current.process[saveTo] = val;
|
||||
}
|
||||
}
|
||||
|
|
@ -1692,15 +1743,17 @@ function createPopOp(type, map) {
|
|||
},
|
||||
new: () => {
|
||||
let rec = { type };
|
||||
for (let [key, val] of Object.entries(map)) {
|
||||
rec[key] = current.process[val];
|
||||
for (let [key, src] of Object.entries(map)) {
|
||||
rec[key] = typeof(src) === 'string'
|
||||
? current.process[src.replace('~','')]
|
||||
: src;
|
||||
}
|
||||
return rec;
|
||||
},
|
||||
hideshow: (abc) => {
|
||||
hideshow: () => {
|
||||
for (let inp of Object.values(op.inputs)) {
|
||||
let parent = inp.parentElement;
|
||||
if (parent.setVisible && parent.__opt.show) {
|
||||
if (parent && parent.setVisible && parent.__opt.show) {
|
||||
parent.setVisible(parent.__opt.show(op, API.conf.get()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1872,9 +1925,11 @@ function updateStock() {
|
|||
}
|
||||
|
||||
if (!isCamMode) {
|
||||
SPACE.world.remove(camZTop);
|
||||
SPACE.world.remove(camZBottom);
|
||||
SPACE.world.remove(camStock);
|
||||
camStock = null;
|
||||
camZTop = null;
|
||||
camZBottom = null;
|
||||
return;
|
||||
}
|
||||
|
|
@ -1937,6 +1992,32 @@ function updateStock() {
|
|||
camStock = null;
|
||||
}
|
||||
|
||||
SPACE.world.remove(camZTop);
|
||||
if (process.camZTop && widgets.length) {
|
||||
let max = { x, y, z };
|
||||
for (let w of widgets) {
|
||||
max.x = Math.max(max.x, w.track.box.w);
|
||||
max.y = Math.max(max.y, w.track.box.h);
|
||||
max.z = Math.max(max.z, w.track.box.d);
|
||||
}
|
||||
let geo = new THREE.PlaneGeometry(max.x, max.y);
|
||||
let mat = new THREE.MeshBasicMaterial({
|
||||
color: 0x777777,
|
||||
opacity: 0.55,
|
||||
transparent: true,
|
||||
side:THREE.DoubleSide
|
||||
});
|
||||
camZTop = new THREE.Mesh(geo, mat);
|
||||
camZTop._max = max;
|
||||
camZTop.renderOrder = 1;
|
||||
camZTop.position.x = center.x;
|
||||
camZTop.position.y = center.y;
|
||||
camZTop.position.z = process.camZTop;
|
||||
SPACE.world.add(camZTop);
|
||||
} else {
|
||||
camZTop = undefined;
|
||||
}
|
||||
|
||||
SPACE.world.remove(camZBottom);
|
||||
if (process.camZBottom && widgets.length) {
|
||||
let max = { x, y, z };
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// dep: geo.base
|
||||
// dep: geo.polygons
|
||||
// dep: kiri-mode.cam.driver
|
||||
gapp.register("kiri-mode.cam.export", [], (root, exports) => {
|
||||
gapp.register("kiri-mode.cam.export", (root, exports) => {
|
||||
|
||||
const { base, kiri } = root;
|
||||
const { polygons, util } = base;
|
||||
|
|
@ -70,7 +70,8 @@ CAM.export = function(print, online) {
|
|||
},
|
||||
offset = {
|
||||
x: -origin.x,
|
||||
y: origin.y
|
||||
y: origin.y,
|
||||
z: spro.camOriginTop ? origin.z - zmax : origin.z
|
||||
},
|
||||
scale = {
|
||||
x: 1,
|
||||
|
|
@ -88,7 +89,7 @@ CAM.export = function(print, online) {
|
|||
time_sec: 0,
|
||||
time_ms: 0,
|
||||
time: 0
|
||||
}
|
||||
};
|
||||
|
||||
function section(section) {
|
||||
append();
|
||||
|
|
@ -197,10 +198,14 @@ CAM.export = function(print, online) {
|
|||
}
|
||||
}
|
||||
|
||||
// enforce XY origin at start of print
|
||||
if (points === 0 || changeTool) {
|
||||
pos.x = pos.y = pos.z = 0;
|
||||
}
|
||||
|
||||
// split first move to X,Y then Z for that new location
|
||||
// safety to prevent tool crashing
|
||||
if (points === 0) {
|
||||
pos.x = pos.y = pos.z = 0;
|
||||
if (points === 0 || changeTool) {
|
||||
points++;
|
||||
if (spro.camFirstZMax) {
|
||||
moveTo({
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
// dep: kiri.slice
|
||||
// use: kiri-mode.cam.topo
|
||||
// use: kiri-mode.cam.topo4
|
||||
gapp.register("kiri-mode.cam.ops", [], (root, exports) => {
|
||||
gapp.register("kiri-mode.cam.ops", (root, exports) => {
|
||||
|
||||
const { base, kiri } = root;
|
||||
const { paths, polygons, newPoint, newPolygon, sliceConnect } = base;
|
||||
|
|
@ -155,7 +155,7 @@ class OpLevel extends CamOp {
|
|||
poly.reverse();
|
||||
}
|
||||
poly.forEachPoint((point, pidx) => {
|
||||
camOut(point.clone(), pidx > 0, stepOver);
|
||||
camOut(point.clone(), true, stepOver);
|
||||
}, false);
|
||||
});
|
||||
setPrintPoint(printPoint);
|
||||
|
|
@ -171,9 +171,10 @@ class OpRough extends CamOp {
|
|||
|
||||
async slice(progress) {
|
||||
let { op, state } = this;
|
||||
let { settings, widget, slicer, addSlices, unsafe, color } = state;
|
||||
let { settings, slicer, addSlices, unsafe, color } = state;
|
||||
let { updateToolDiams, thruHoles, tabs, cutTabs, cutPolys } = state;
|
||||
let { tshadow, shadowTop, ztOff, zBottom, zThru, zMax, shadowAt, isIndexed } = state;
|
||||
let { ztOff, zMax, shadowAt, isIndexed} = state;
|
||||
let { workarea } = state;
|
||||
let { process, stock } = settings;
|
||||
|
||||
if (op.down <= 0) {
|
||||
|
|
@ -181,7 +182,6 @@ class OpRough extends CamOp {
|
|||
}
|
||||
|
||||
let roughIn = op.inside;
|
||||
let roughTop = op.top;
|
||||
let roughDown = op.down;
|
||||
let roughLeave = op.leave || 0;
|
||||
let roughLeaveZ = op.leavez || 0;
|
||||
|
|
@ -189,9 +189,11 @@ class OpRough extends CamOp {
|
|||
let toolDiam = new CAM.Tool(settings, op.tool).fluteDiameter();
|
||||
let trueShadow = process.camTrueShadow === true;
|
||||
|
||||
// create facing slices
|
||||
if (roughTop) {
|
||||
let shadow = tshadow.clone();
|
||||
updateToolDiams(toolDiam);
|
||||
|
||||
// clear the stock above the area to be roughed out
|
||||
if (workarea.top_z > workarea.top_part) {
|
||||
let shadow = state.shadow.base.clone();
|
||||
let step = toolDiam * op.step;
|
||||
let inset = roughStock ?
|
||||
POLY.offset([ newPolygon().centerRectangle(stock.center, stock.x, stock.y) ], step) :
|
||||
|
|
@ -210,7 +212,7 @@ class OpRough extends CamOp {
|
|||
let camFaces = this.camFaces = [];
|
||||
let zstart = zMax + ztOff - zstep;
|
||||
for (let z = zstart; zsteps > 0; zsteps--) {
|
||||
let slice = shadowTop.slice.clone(false);
|
||||
let slice = newSlice();
|
||||
slice.z = z;
|
||||
slice.camLines = POLY.setZ(facing.clone(true), slice.z + roughLeaveZ);
|
||||
slice.output()
|
||||
|
|
@ -223,23 +225,24 @@ class OpRough extends CamOp {
|
|||
}
|
||||
|
||||
// create roughing slices
|
||||
updateToolDiams(toolDiam);
|
||||
|
||||
let flats = [];
|
||||
let shadow = [];
|
||||
let slices = [];
|
||||
let indices = slicer.interval(roughDown, {
|
||||
down: true, min: 0, fit: true, off: 0.01
|
||||
});
|
||||
|
||||
// shift out first (top-most) slice
|
||||
indices.shift();
|
||||
|
||||
// find flats and add to indices for slicing
|
||||
if (op.flats) {
|
||||
let flatArea = (Math.PI * (toolDiam/2) * (toolDiam/2)) / 2;
|
||||
let flats = Object.entries(slicer.zFlat)
|
||||
.filter(row => row[1] > flatArea)
|
||||
.map(row => row[0])
|
||||
.map(v => parseFloat(v).round(5))
|
||||
.filter(v => v >= zBottom);
|
||||
.filter(v => v >= workarea.bottom_z);
|
||||
flats.forEach(v => {
|
||||
if (!indices.contains(v)) {
|
||||
indices.push(v);
|
||||
|
|
@ -267,7 +270,7 @@ class OpRough extends CamOp {
|
|||
indices = indices.appendAll(flats).sort((a,b) => b-a);
|
||||
}
|
||||
|
||||
indices = indices.filter(v => v >= zBottom);
|
||||
indices = indices.filter(v => v >= workarea.bottom_z);
|
||||
// console.log('indices', ...indices, {zBottom});
|
||||
|
||||
let cnt = 0;
|
||||
|
|
@ -278,11 +281,11 @@ class OpRough extends CamOp {
|
|||
// exclude flats injected to complete shadow
|
||||
return;
|
||||
}
|
||||
// data.shadow = trueShadow ? CAM.shadowAt(widget, data.z) : shadow.clone(true);
|
||||
if (data.z > workarea.top_z) {
|
||||
return;
|
||||
}
|
||||
data.shadow = trueShadow ? shadowAt(data.z) : shadow.clone(true);
|
||||
data.slice.shadow = data.shadow;
|
||||
// data.slice.tops[0].inner = data.shadow;
|
||||
// data.slice.tops[0].inner = POLY.setZ(tshadow.clone(true), data.z);
|
||||
slices.push(data.slice);
|
||||
progress(0.25 + 0.25 * (++cnt / tot));
|
||||
}, progress: (index, total) => {
|
||||
|
|
@ -291,9 +294,9 @@ class OpRough extends CamOp {
|
|||
} });
|
||||
|
||||
if (trueShadow) {
|
||||
shadow = tshadow.clone(true);
|
||||
shadow = state.shadow.base.clone(true);
|
||||
} else {
|
||||
shadow = POLY.union(shadow.appendAll(shadowTop.tops), 0.01, true);
|
||||
shadow = POLY.union(shadow.appendAll(state.shadow.base), 0.01, true);
|
||||
}
|
||||
|
||||
// inset or eliminate thru holes from shadow
|
||||
|
|
@ -301,10 +304,6 @@ class OpRough extends CamOp {
|
|||
thruHoles.forEach(hole => {
|
||||
shadow = shadow.map(p => {
|
||||
if (p.isEquivalent(hole)) {
|
||||
// eliminate thru holes when roughing voids enabled
|
||||
// if (op.voids) {
|
||||
// return undefined;
|
||||
// }
|
||||
let po = POLY.offset([p], -(toolDiam / 2 + roughLeave + 0.01));
|
||||
return po ? po[0] : undefined;
|
||||
} else {
|
||||
|
|
@ -314,6 +313,7 @@ class OpRough extends CamOp {
|
|||
});
|
||||
shadow = POLY.nest(shadow);
|
||||
if (op.voids) {
|
||||
// eliminate voids from shadow when "clear voids" enables
|
||||
for (let s of shadow) s.inner = undefined;
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +406,9 @@ class OpRough extends CamOp {
|
|||
});
|
||||
|
||||
let last = slices[slices.length-1];
|
||||
for (let zneg of base.util.lerp(0, zThru, op.down)) {
|
||||
|
||||
if (workarea.bottom_z < 0)
|
||||
for (let zneg of base.util.lerp(0, -workarea.bottom_cut, op.down)) {
|
||||
if (!last) continue;
|
||||
let add = last.clone(true);
|
||||
add.z -= zneg;
|
||||
|
|
@ -435,13 +437,14 @@ class OpRough extends CamOp {
|
|||
let { process } = settings;
|
||||
|
||||
let easeDown = process.camEaseDown;
|
||||
let cutdir = process.camConventional;
|
||||
let cutdir = op.ov_conv;
|
||||
let depthFirst = process.camDepthFirst && !state.isIndexed;
|
||||
let depthData = [];
|
||||
|
||||
setTool(op.tool, op.rate, op.plunge);
|
||||
setSpindle(op.spindle);
|
||||
|
||||
// output the clearing of stock above roughing
|
||||
for (let slice of (camFaces || [])) {
|
||||
const level = [];
|
||||
for (let poly of slice.camLines) {
|
||||
|
|
@ -463,6 +466,7 @@ class OpRough extends CamOp {
|
|||
newLayer();
|
||||
}
|
||||
|
||||
// output the roughing passes
|
||||
setPrintPoint(printPoint);
|
||||
sliceOutput(sliceOut, {
|
||||
cutdir,
|
||||
|
|
@ -481,8 +485,8 @@ class OpOutline extends CamOp {
|
|||
async slice(progress) {
|
||||
let { op, state } = this;
|
||||
let { settings, widget, slicer, addSlices, tshadow, thruHoles, unsafe, color } = state;
|
||||
let { updateToolDiams, zThru, zBottom, shadowTop, tabs, cutTabs, cutPolys } = state;
|
||||
let { zMax, ztOff } = state;
|
||||
let { updateToolDiams, tabs, cutTabs, cutPolys, workarea } = state;
|
||||
let { zMax } = state;
|
||||
let { process, stock } = settings;
|
||||
|
||||
if (op.down <= 0) {
|
||||
|
|
@ -494,8 +498,11 @@ class OpOutline extends CamOp {
|
|||
let shadow = [];
|
||||
let slices = [];
|
||||
let intopt = {
|
||||
down: true, min: zBottom, fit: true, off: 0.01,
|
||||
max: op.top ? zMax + ztOff : undefined
|
||||
off: 0.01,
|
||||
fit: true,
|
||||
down: true,
|
||||
min: Math.max(0, workarea.bottom_z),
|
||||
max: workarea.top_z
|
||||
};
|
||||
let indices = slicer.interval(op.down, intopt);
|
||||
let trueShadow = process.camTrueShadow === true;
|
||||
|
|
@ -506,12 +513,11 @@ class OpOutline extends CamOp {
|
|||
.map(v => (parseFloat(v) - 0.01).round(5))
|
||||
.filter(v => v > 0 && indices.indexOf(v) < 0);
|
||||
indices = indices.appendAll(flats).sort((a,b) => b-a);
|
||||
indices = indices.filter(v => v - zBottom >= -0.001);
|
||||
// console.log('indices', ...indices, {zBottom, slicer});
|
||||
|
||||
let cnt = 0;
|
||||
let tot = 0;
|
||||
if (op.outside && !op.inside) {
|
||||
// console.log({outline_bypass: indices, down: op.down});
|
||||
console.log({outline_bypass: indices, down: op.down});
|
||||
indices.forEach((ind,i) => {
|
||||
if (flats.indexOf(ind) >= 0) {
|
||||
// exclude flats
|
||||
|
|
@ -540,13 +546,13 @@ class OpOutline extends CamOp {
|
|||
tot = total;
|
||||
progress((index / total) * 0.5);
|
||||
} });
|
||||
shadow = POLY.union(shadow.appendAll(shadowTop.tops), 0.01, true);
|
||||
shadow = POLY.union(shadow.appendAll(state.shadow.base), 0.01, true);
|
||||
|
||||
// start slices at top of stock when `clear top` enabled
|
||||
if (op.top) {
|
||||
let first = slices[0];
|
||||
let zlist = slices.map(s => s.z);
|
||||
for (let z of indices.filter(v => v >= zMax).reverse()) {
|
||||
for (let z of indices.filter(v => v >= zMax)) {
|
||||
if (zlist.contains(z)) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -559,9 +565,9 @@ class OpOutline extends CamOp {
|
|||
}
|
||||
|
||||
// extend cut thru (only when z bottom is 0)
|
||||
if (zThru) {
|
||||
if (workarea.bottom_z < 0) {
|
||||
let last = slices[slices.length-1];
|
||||
for (let zneg of base.util.lerp(0, zThru, op.down)) {
|
||||
for (let zneg of base.util.lerp(0, -workarea.bottom_cut, op.down)) {
|
||||
if (!last) continue;
|
||||
let add = last.clone(true);
|
||||
add.tops.forEach(top => top.poly.setZ(add.z));
|
||||
|
|
@ -678,7 +684,7 @@ class OpOutline extends CamOp {
|
|||
|
||||
let easeDown = process.camEaseDown;
|
||||
let toolDiam = this.toolDiam;
|
||||
let cutdir = process.camConventional;
|
||||
let cutdir = op.ov_conv;//process.camConventional;
|
||||
let depthFirst = process.camDepthFirst;
|
||||
let depthData = [];
|
||||
|
||||
|
|
@ -948,25 +954,29 @@ class OpTrace extends CamOp {
|
|||
async slice(progress) {
|
||||
let { op, state } = this;
|
||||
let { tool, rate, down, plunge, offset, offover, thru } = op;
|
||||
let { settings, widget, addSlices, zMax, zTop, zThru, tabs } = state;
|
||||
let { ov_conv } = op;
|
||||
let { settings, widget, addSlices, zThru, tabs, workarea } = state;
|
||||
let { updateToolDiams, cutTabs, cutPolys, healPolys, color } = state;
|
||||
let { process, stock } = settings;
|
||||
let { camStockClipTo, camZBottom } = process;
|
||||
let { camStockClipTo } = process;
|
||||
if (state.isIndexed) {
|
||||
throw 'trace op not supported with indexed stock';
|
||||
}
|
||||
// generate tracing offsets from chosen features
|
||||
let zTop = workarea.top_z;
|
||||
let zBottom = workarea.bottom_z;
|
||||
let sliceOut = this.sliceOut = [];
|
||||
let areas = op.areas[widget.id] || [];
|
||||
let camTool = new CAM.Tool(settings, tool);
|
||||
let toolDiam = camTool.fluteDiameter();
|
||||
let toolOver = toolDiam * op.step;
|
||||
let traceOffset = camTool.traceOffset()
|
||||
let cutdir = process.camConventional;
|
||||
let cutdir = ov_conv;
|
||||
let polys = [];
|
||||
let stockRect = stock.center && stock.x && stock.y ?
|
||||
newPolygon().centerRectangle(stock.center, stock.x, stock.y) : undefined;
|
||||
updateToolDiams(toolDiam);
|
||||
|
||||
if (tabs) {
|
||||
tabs.forEach(tab => {
|
||||
tab.off = POLY.expand([tab.poly], toolDiam / 2).flat();
|
||||
|
|
@ -986,6 +996,9 @@ class OpTrace extends CamOp {
|
|||
sliceOut.push(slice);
|
||||
return slice;
|
||||
}
|
||||
function minZ(z) {
|
||||
return zBottom ? Math.max(zBottom, z - thru) : z - thru;
|
||||
}
|
||||
function followZ(poly) {
|
||||
if (op.dogbone) {
|
||||
CAM.addDogbones(poly, toolDiam / 5, !op.revbone);
|
||||
|
|
@ -1002,7 +1015,7 @@ class OpTrace extends CamOp {
|
|||
slice.camLines = cutPolys([stockRect], slice.camLines, z, true);
|
||||
}
|
||||
slice.output()
|
||||
.setLayer("follow", {line: color}, false)
|
||||
.setLayer("trace follow", {line: color}, false)
|
||||
.addPolys(slice.camLines)
|
||||
}
|
||||
function clearZ(polys, z, down) {
|
||||
|
|
@ -1013,7 +1026,8 @@ class OpTrace extends CamOp {
|
|||
let slice = newSliceOut(z);
|
||||
slice.camTrace = { tool, rate, plunge };
|
||||
POLY.offset([ poly ], [ -toolDiam/2, -toolOver ], {
|
||||
count:999, outs: slice.camLines = [], flat:true, z
|
||||
count:999, outs: slice.camLines = [], flat:true, z,
|
||||
minArea: 0
|
||||
});
|
||||
if (tabs) {
|
||||
slice.camLines = cutTabs(tabs, POLY.flatten(slice.camLines, null, true), z);
|
||||
|
|
@ -1022,7 +1036,7 @@ class OpTrace extends CamOp {
|
|||
}
|
||||
POLY.setWinding(slice.camLines, cutdir, false);
|
||||
slice.output()
|
||||
.setLayer("clear", {line: color}, false)
|
||||
.setLayer("trace clear", {line: color}, false)
|
||||
.addPolys(slice.camLines)
|
||||
}
|
||||
}
|
||||
|
|
@ -1089,6 +1103,7 @@ class OpTrace extends CamOp {
|
|||
poly2polyEmit(polys, newPoint(0,0,0), (poly, index, count, spoint) => {
|
||||
routed.push(poly);
|
||||
});
|
||||
let output = [];
|
||||
for (let poly of POLY.nest(routed)) {
|
||||
let offdist = offset !== 'none' ? offover : 0;
|
||||
if (!offdist)
|
||||
|
|
@ -1110,29 +1125,34 @@ class OpTrace extends CamOp {
|
|||
}
|
||||
for (let pi of POLY.flatten(poly, [], true))
|
||||
if (down) {
|
||||
let zto = pi.getZ() - thru;
|
||||
let zto = minZ(pi.getZ());
|
||||
if (zThru && similar(zto,0)) {
|
||||
zto -= zThru;
|
||||
}
|
||||
for (let z of base.util.lerp(zTop, zto, down)) {
|
||||
followZ(pi.clone().setZ(z));
|
||||
output.push(pi.clone().setZ(z));
|
||||
}
|
||||
} else {
|
||||
if (thru) {
|
||||
pi.setZ(pi.getZ() - thru);
|
||||
}
|
||||
followZ(pi);
|
||||
output.push(pi);
|
||||
}
|
||||
if (!down && op.merge) {
|
||||
let nest = POLY.nest(output);
|
||||
let union = POLY.union(nest, 0, true);
|
||||
output = POLY.flatten(union, [], true);
|
||||
}
|
||||
}
|
||||
for (let poly of output) {
|
||||
followZ(poly);
|
||||
}
|
||||
break;
|
||||
case "clear":
|
||||
const zbo = widget.track.top - widget.track.box.d;
|
||||
let zmap = {};
|
||||
for (let poly of polys) {
|
||||
let z = poly.getZ() - thru;
|
||||
if (op.bottom && camZBottom) {
|
||||
z = Math.max(z, camZBottom) - zbo;
|
||||
}
|
||||
let z = minZ(poly.getZ());
|
||||
if (offover) {
|
||||
let pnew = POLY.offset([poly], -offover, { minArea: 0, open: true });
|
||||
if (pnew) {
|
||||
|
|
@ -1174,17 +1194,20 @@ class OpPocket extends CamOp {
|
|||
const debug = false;
|
||||
let { op, state } = this;
|
||||
let { tool, rate, down, plunge, expand, contour, smooth, tolerance } = op;
|
||||
let { settings, widget, addSlices, zTop, zBottom, zThru, tabs, color } = state;
|
||||
let { updateToolDiams, cutTabs, cutPolys, healPolys, shadowAt } = state;
|
||||
let { process, stock } = settings;
|
||||
let { ov_botz, ov_conv } = op;
|
||||
let { settings, widget, addSlices, zBottom, zThru, tabs, color } = state;
|
||||
let { updateToolDiams, cutTabs, healPolys, shadowAt, workarea } = state;
|
||||
let { process } = settings;
|
||||
zBottom = ov_botz ? workarea.bottom_stock + ov_botz : zBottom;
|
||||
// generate tracing offsets from chosen features
|
||||
let sliceOut;
|
||||
let pockets = this.pockets = [];
|
||||
let camTool = new CAM.Tool(settings, tool);
|
||||
let toolDiam = camTool.fluteDiameter();
|
||||
let toolOver = toolDiam * op.step;
|
||||
let cutdir = process.camConventional;
|
||||
let cutdir = ov_conv;
|
||||
let engrave = contour && op.engrave;
|
||||
let zTop = workarea.top_z;
|
||||
if (contour) {
|
||||
down = 0;
|
||||
this.topo = await CAM.Topo({
|
||||
|
|
@ -1219,6 +1242,7 @@ class OpPocket extends CamOp {
|
|||
return slice;
|
||||
}
|
||||
function clearZ(polys, z, down) {
|
||||
// console.log({ clearZ: polys });
|
||||
if (down) {
|
||||
// adjust step down to a value <= down that
|
||||
// ends on the lowest z specified
|
||||
|
|
@ -1250,7 +1274,7 @@ class OpPocket extends CamOp {
|
|||
if (smooth) {
|
||||
shadow = POLY.setZ(POLY.offset(POLY.offset(shadow, smooth), -smooth), z);
|
||||
}
|
||||
POLY.subtract([ poly ], shadow, clip);
|
||||
POLY.subtract([ poly ], shadow, clip, undefined, undefined, 0);
|
||||
}
|
||||
if (clip.length === 0) {
|
||||
continue;
|
||||
|
|
@ -1263,7 +1287,7 @@ class OpPocket extends CamOp {
|
|||
[ expand || (-0.02), -toolOver ] :
|
||||
[ -toolDiam / 2, -toolOver ];
|
||||
POLY.offset(clip, offs, {
|
||||
count, outs: slice.camLines = [], flat:true, z
|
||||
count, outs: slice.camLines = [], flat:true, z, minArea: 0
|
||||
});
|
||||
} else {
|
||||
// when engraving with a 0 width tip
|
||||
|
|
@ -1418,7 +1442,7 @@ class OpPocket extends CamOp {
|
|||
if (min.pocket) {
|
||||
min.pocket.used = true;
|
||||
sliceOutput(min.pocket, {
|
||||
cutdir: process.camConventional,
|
||||
cutdir: op.ov_conv,
|
||||
depthFirst: process.camDepthFirst && !state.isIndexed,
|
||||
easeDown: op.down && process.easeDown ? op.down : 0,
|
||||
progress: (n,m) => progress(n/m, "pocket")
|
||||
|
|
@ -1708,6 +1732,18 @@ class OpXRay extends CamOp {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the Part "shadow" and attaches relevant data to the "state" object
|
||||
*
|
||||
* The part shadow consists of top-cown layers at which the polygon shadow changes
|
||||
* shape. For curved or sloped surfaces, this is approximated and paths that clip
|
||||
* to it should use the next lower layer from current Z to ensure no part collisions.
|
||||
*
|
||||
* The shadow at each layer is computed by top-down unioning the part outline with
|
||||
* the shadow from the layer above.
|
||||
*
|
||||
* This operation is injected at the start of the operation chain before processing.
|
||||
*/
|
||||
class OpShadow extends CamOp {
|
||||
constructor(state, op) {
|
||||
super(state, op);
|
||||
|
|
@ -1726,7 +1762,9 @@ class OpShadow extends CamOp {
|
|||
|
||||
let tslices = [];
|
||||
let tshadow = [];
|
||||
let tzindex = slicer.interval(minStepDown, { fit: true, off: 0.01, down: true, flats: true });
|
||||
let tzindex = slicer.interval(minStepDown, {
|
||||
fit: true, off: 0.01, down: true, flats: true
|
||||
});
|
||||
let skipTerrain = unsafe;
|
||||
|
||||
if (skipTerrain) {
|
||||
|
|
@ -1737,10 +1775,14 @@ class OpShadow extends CamOp {
|
|||
let lsz; // only shadow up to bottom of last shadow for progressive union
|
||||
let cnt = 0;
|
||||
let tot = 0;
|
||||
|
||||
// terrain is the "shadow stack" where index 0 = top of part
|
||||
// thus array.length -1 = bottom of part
|
||||
let terrain = await slicer.slice(tzindex, { each: data => {
|
||||
let shadow = trueShadow ? shadowAt(data.z, lsz) : [];
|
||||
tshadow = POLY.union(tshadow.slice().appendAll(data.tops).appendAll(shadow), 0.01, true);
|
||||
tslices.push(data.slice);
|
||||
// capture current shadow for this slice
|
||||
data.slice.shadow = tshadow;
|
||||
if (false) {
|
||||
const slice = data.slice;
|
||||
|
|
@ -1775,14 +1817,23 @@ class OpShadow extends CamOp {
|
|||
throw `invalid widget shadow`;
|
||||
}
|
||||
|
||||
state.shadowTop = terrain[terrain.length - 1];
|
||||
// TODO: deprecate use of separate shadow vars in state
|
||||
state.center = tshadow[0].bounds.center();
|
||||
state.tshadow = tshadow; // true shadow (bottom of part)
|
||||
state.terrain = terrain; // stack of shadow slices with tops
|
||||
state.tslices = tslices;
|
||||
state.tshadow = tshadow; // true shadow (base of part)
|
||||
state.terrain = terrain; // stack of shadow slices stored in tops
|
||||
state.tslices = tslices; // raw slicer 'data' layer outputs
|
||||
state.skipTerrain = skipTerrain;
|
||||
|
||||
// identify through holes
|
||||
// TODO: refactor ops to use a unified shadow object
|
||||
state.shadow = {
|
||||
base: tshadow, // computed shadow union at base of part
|
||||
stack: terrain, // stack of shadow slices
|
||||
slices: tslices, // raw slicer 'data' objects
|
||||
skip: skipTerrain
|
||||
};
|
||||
|
||||
// identify through holes which are inner/child polygons
|
||||
// on the bottom-most layer of the shadow stack (tshadow, index == 0)
|
||||
state.thruHoles = tshadow.map(p => p.inner || []).flat();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// dep: kiri.render
|
||||
// dep: kiri-mode.cam.driver
|
||||
// use: kiri-mode.cam.ops
|
||||
gapp.register("kiri-mode.cam.prepare", [], (root, exports) => {
|
||||
gapp.register("kiri-mode.cam.prepare", (root, exports) => {
|
||||
|
||||
const { base, kiri } = root;
|
||||
const { paths, polygons, newPoint } = base;
|
||||
|
|
@ -562,7 +562,7 @@ function prepEach(widget, settings, print, firstPoint, update) {
|
|||
opSum += weight;
|
||||
if (tool && lastPoint) {
|
||||
newLayer();
|
||||
layerPush(printPoint = lastPoint.clone().setZ(zmax + zadd), 0, 0, tool);
|
||||
layerPush(printPoint = lastPoint.clone().setZ(zmax_outer), 0, 0, tool);
|
||||
newLayer();
|
||||
}
|
||||
}
|
||||
|
|
@ -606,7 +606,7 @@ function prepEach(widget, settings, print, firstPoint, update) {
|
|||
return start;
|
||||
}
|
||||
let ltops = tops[depth];
|
||||
let fitted = fit ? ltops.filter(poly => poly.isInside(fit, 0.01)) : ltops;
|
||||
let fitted = fit ? ltops.filter(poly => poly.isInside(fit, 0.05)) : ltops;
|
||||
let ftops = fitted.filter(top => !top.level_emit);
|
||||
if (ftops.length > 1) {
|
||||
ftops = POLY.route(ftops, start);
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@
|
|||
// use: kiri-mode.cam.slicer
|
||||
// use: kiri-mode.cam.slicer2
|
||||
// use: kiri-mode.cam.ops
|
||||
gapp.register("kiri-mode.cam.slice", [], (root, exports) => {
|
||||
gapp.register("kiri-mode.cam.slice", (root, exports) => {
|
||||
|
||||
const { base, kiri } = root;
|
||||
const { util } = base;
|
||||
const { driver, newSlice, setSliceTracker } = kiri;
|
||||
const { polygons, newPoint, newPolygon } = base;
|
||||
const { CAM } = driver;
|
||||
|
|
@ -28,14 +29,14 @@ const POLY = polygons;
|
|||
* @param {Function} output
|
||||
*/
|
||||
CAM.slice = async function(settings, widget, onupdate, ondone) {
|
||||
let mesh = widget.mesh,
|
||||
proc = settings.process,
|
||||
let proc = settings.process,
|
||||
stock = settings.stock || {},
|
||||
isIndexed = proc.camStockIndexed,
|
||||
camOps = widget.camops = [],
|
||||
sliceAll = widget.slices = [],
|
||||
bounds = widget.getBoundingBox(),
|
||||
track = widget.track,
|
||||
{ camZTop, camZBottom, camZThru } = proc,
|
||||
// widget top z as defined by setTopz()
|
||||
wztop = track.top,
|
||||
// distance between top of part and top of stock
|
||||
|
|
@ -44,11 +45,11 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
|||
zbOff = isIndexed ? 0 : (wztop - track.box.d),
|
||||
// defined z bottom offset by distance to stock bottom
|
||||
// keeps the z bottom relative to the part when z align changes
|
||||
zBottom = isIndexed ? proc.camZBottom : proc.camZBottom - zbOff,
|
||||
zBottom = isIndexed ? camZBottom : camZBottom - zbOff,
|
||||
// greater of widget bottom and z bottom
|
||||
zMin = isIndexed ? bounds.min.z : Math.max(bounds.min.z, zBottom),
|
||||
zMax = bounds.max.z,
|
||||
zThru = proc.camZBottom ? 0 : (proc.camZThru || 0),
|
||||
zThru = camZThru,
|
||||
zTop = zMax + ztOff,
|
||||
minToolDiam = Infinity,
|
||||
maxToolDiam = -Infinity,
|
||||
|
|
@ -58,7 +59,37 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
|||
unsafe = proc.camExpertFast,
|
||||
units = settings.controller.units === 'in' ? 25.4 : 1,
|
||||
axisRotation,
|
||||
axisIndex;
|
||||
axisIndex,
|
||||
// new work area tracking
|
||||
part_size = bounds.dim,
|
||||
bottom_gap = zbOff,
|
||||
bottom_part = 0,
|
||||
bottom_stock = -bottom_gap,
|
||||
bottom_thru = zThru,
|
||||
bottom_z = Math.max(
|
||||
(camZBottom ? bottom_stock + camZBottom : bottom_part) - bottom_thru,
|
||||
(camZBottom ? bottom_stock + camZBottom : bottom_stock - bottom_thru)
|
||||
),
|
||||
bottom_cut = Math.max(bottom_z, -zThru),
|
||||
top_stock = zTop,
|
||||
top_part = zMax,
|
||||
top_gap = ztOff,
|
||||
top_z = camZTop ? bottom_stock + camZTop : top_stock,
|
||||
workarea = util.round({
|
||||
top_stock,
|
||||
top_part,
|
||||
top_gap,
|
||||
top_z,
|
||||
bottom_stock,
|
||||
bottom_part,
|
||||
bottom_gap,
|
||||
bottom_z,
|
||||
bottom_cut
|
||||
}, 3);
|
||||
|
||||
// console.table({ workarea });
|
||||
// console.table({ part_size });
|
||||
// console.table({ stock });
|
||||
|
||||
if (tabs) {
|
||||
// make tab polygons
|
||||
|
|
@ -66,7 +97,7 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
|||
let zero = newPoint(0,0,0);
|
||||
let point = newPoint(tab.pos.x, tab.pos.y, tab.pos.z);
|
||||
let poly = newPolygon().centerRectangle(zero, tab.dim.x, tab.dim.y);
|
||||
let tslice = newSlice(0);
|
||||
// let tslice = newSlice(0);
|
||||
let m4 = new THREE.Matrix4().makeRotationFromQuaternion(
|
||||
new THREE.Quaternion(tab.rot._x, tab.rot._y, tab.rot._z, tab.rot._w)
|
||||
);
|
||||
|
|
@ -203,7 +234,8 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
|||
zTop,
|
||||
unsafe,
|
||||
color,
|
||||
dark
|
||||
dark,
|
||||
// workarea
|
||||
};
|
||||
|
||||
let opList = [
|
||||
|
|
@ -236,9 +268,19 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
|||
|
||||
// call slice() function on all ops in order
|
||||
let tracker = setSliceTracker({ rotation: 0 });
|
||||
let workarea_orig = structuredClone(workarea);
|
||||
setAxisIndex();
|
||||
for (let op of opList) {
|
||||
let weight = op.weight();
|
||||
// apply operation override vars
|
||||
let workover = structuredClone(workarea_orig);
|
||||
let valz = op.op;
|
||||
if (valz.ov_topz) workover.top_z = bottom_stock + valz.ov_topz;
|
||||
if (valz.ov_botz) {
|
||||
workover.bottom_z = bottom_stock + valz.ov_botz;
|
||||
workover.bottom_cut = Math.max(workover.bottom_z, -zThru);
|
||||
}
|
||||
state.workarea = workover;
|
||||
await op.slice((progress, message) => {
|
||||
onupdate((opSum + (progress * weight)) / opTot, message || op.type());
|
||||
});
|
||||
|
|
@ -280,9 +322,9 @@ CAM.slice = async function(settings, widget, onupdate, ondone) {
|
|||
|
||||
// add shadow perimeter to terrain to catch outside moves off part
|
||||
let tabpoly = tabs ? tabs.map(tab => tab.poly) : [];
|
||||
let allpoly = POLY.union([...state.shadowTop.tops, ...tabpoly, ...state.shadowTop.slice.shadow], 0, true);
|
||||
let allpoly = POLY.union([...state.shadow.base, ...tabpoly], 0, true);
|
||||
let shadowOff = maxToolDiam < 0 ? allpoly :
|
||||
POLY.offset(allpoly, [minToolDiam/2,maxToolDiam/2], { count: 2, flat: true });
|
||||
POLY.offset(allpoly, [minToolDiam/2,maxToolDiam/2], { count: 2, flat: true, minArea: 0 });
|
||||
state.terrain.forEach(level => level.tops.appendAll(shadowOff));
|
||||
|
||||
widget.terrain = state.skipTerrain ? null : state.terrain;
|
||||
|
|
@ -366,7 +408,7 @@ CAM.traces = async function(settings, widget, single) {
|
|||
let trace = traces[i];
|
||||
let dz = Math.abs(z - trace.getZ());
|
||||
// only compare polys farther apart in Z
|
||||
if (dz < 0.01) {
|
||||
if (dz > 0.01) {
|
||||
continue;
|
||||
}
|
||||
// do not add duplicates
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ class Tool {
|
|||
return this.unitScale() * this.tool.taper_tip;
|
||||
}
|
||||
|
||||
maxDiameter() {
|
||||
return Math.max(this.fluteDiameter(), this.tipDiameter(), this.shaftDiameter());
|
||||
}
|
||||
|
||||
traceOffset() {
|
||||
return (this.isTaperMill() ? this.tipDiameter() : this.fluteDiameter()) / 2;
|
||||
}
|
||||
|
|
|
|||
302
src/kiri-mode/cam/tools.js
Normal file
302
src/kiri-mode/cam/tools.js
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
"use strict";
|
||||
|
||||
// dep: kiri.api
|
||||
// dep: kiri.consts
|
||||
// dep: kiri.settings
|
||||
gapp.register("kiri-mode.cam.tools", (root, exports) => {
|
||||
|
||||
let { kiri } = root,
|
||||
{ api, consts } = kiri,
|
||||
{ uc, ui } = api,
|
||||
{ MODES } = consts,
|
||||
DOC = document,
|
||||
selectedTool = null,
|
||||
editTools = null,
|
||||
maxTool = 0;
|
||||
|
||||
api.show.tools = showTools;
|
||||
|
||||
// extend API
|
||||
Object.assign(api.tool, {
|
||||
update: updateTool
|
||||
});
|
||||
|
||||
function settings() {
|
||||
return api.conf.get();
|
||||
}
|
||||
|
||||
function renderTools() {
|
||||
ui.toolSelect.innerHTML = '';
|
||||
maxTool = 0;
|
||||
editTools.forEach(function(tool, index) {
|
||||
maxTool = Math.max(maxTool, tool.number);
|
||||
tool.order = index;
|
||||
let opt = DOC.createElement('option');
|
||||
opt.appendChild(DOC.createTextNode(tool.name));
|
||||
opt.onclick = function() { selectTool(tool) };
|
||||
ui.toolSelect.appendChild(opt);
|
||||
});
|
||||
}
|
||||
|
||||
function selectTool(tool) {
|
||||
selectedTool = tool;
|
||||
ui.toolName.value = tool.name;
|
||||
ui.toolNum.value = tool.number;
|
||||
ui.toolFluteDiam.value = tool.flute_diam;
|
||||
ui.toolFluteLen.value = tool.flute_len;
|
||||
ui.toolShaftDiam.value = tool.shaft_diam;
|
||||
ui.toolShaftLen.value = tool.shaft_len;
|
||||
ui.toolTaperTip.value = tool.taper_tip || 0;
|
||||
ui.toolMetric.checked = tool.metric;
|
||||
ui.toolType.selectedIndex = ['endmill','ballmill','tapermill'].indexOf(tool.type);
|
||||
if (tool.type === 'tapermill') {
|
||||
ui.toolTaperAngle.value = kiri.driver.CAM.calcTaperAngle(
|
||||
(tool.flute_diam - tool.taper_tip) / 2, tool.flute_len
|
||||
).round(1);
|
||||
} else {
|
||||
ui.toolTaperAngle.value = 0;
|
||||
}
|
||||
renderTool(tool);
|
||||
}
|
||||
|
||||
function otag(o) {
|
||||
if (Array.isArray(o)) {
|
||||
let out = []
|
||||
o.forEach(oe => out.push(otag(oe)));
|
||||
return out.join('');
|
||||
}
|
||||
let tags = [];
|
||||
Object.keys(o).forEach(key => {
|
||||
let val = o[key];
|
||||
let att = [];
|
||||
Object.keys(val).forEach(tk => {
|
||||
let tv = val[tk];
|
||||
att.push(`${tk.replace(/_/g,'-')}="${tv}"`);
|
||||
});
|
||||
tags.push(`<${key} ${att.join(' ')}></${key}>`);
|
||||
});
|
||||
return tags.join('');
|
||||
}
|
||||
|
||||
function renderTool(tool) {
|
||||
let type = selectedTool.type;
|
||||
let taper = type === 'tapermill';
|
||||
ui.toolTaperAngle.disabled = taper ? undefined : 'true';
|
||||
ui.toolTaperTip.disabled = taper ? undefined : 'true';
|
||||
$('tool-view').innerHTML = '<svg id="tool-svg" width="100%" height="100%"></svg>';
|
||||
setTimeout(() => {
|
||||
let svg = $('tool-svg');
|
||||
let pad = 10;
|
||||
let dim = { w: svg.clientWidth, h: svg.clientHeight }
|
||||
let max = { w: dim.w - pad * 2, h: dim.h - pad * 2};
|
||||
let off = { x: pad, y: pad };
|
||||
let shaft_fill = "#cccccc";
|
||||
let flute_fill = "#dddddd";
|
||||
let stroke = "#777777";
|
||||
let stroke_width = 3;
|
||||
let stroke_thin = stroke_width / 2;
|
||||
let shaft = tool.shaft_len || 1;
|
||||
let flute = tool.flute_len || 1;
|
||||
let tip_len = type === "ballmill" ? tool.flute_diam / 2 : 0;
|
||||
let total_len = shaft + flute + tip_len;
|
||||
let units = dim.h / total_len;
|
||||
let shaft_len = (shaft / total_len) * max.h;
|
||||
let flute_len = (flute / total_len) * max.h;
|
||||
let total_wid = Math.max(tool.flute_diam, tool.shaft_diam);
|
||||
let shaft_off = (max.w - tool.shaft_diam * units) / 2;
|
||||
let flute_off = (max.w - tool.flute_diam * units) / 2;
|
||||
let taper_off = (max.w - (tool.taper_tip || 0) * units) / 2;
|
||||
let parts = [
|
||||
{ rect: {
|
||||
x:off.x + shaft_off, y:off.y,
|
||||
width:max.w - shaft_off * 2, height:shaft_len,
|
||||
stroke, fill: shaft_fill, stroke_width
|
||||
} }
|
||||
];
|
||||
if (type === "tapermill") {
|
||||
let yoff = off.y + shaft_len;
|
||||
let mid = dim.w / 2;
|
||||
parts.push({path: {stroke_width, stroke, fill:flute_fill, d:[
|
||||
`M ${off.x + flute_off} ${yoff}`,
|
||||
`L ${off.x + taper_off} ${yoff + flute_len}`,
|
||||
`L ${dim.w - off.x - taper_off} ${yoff + flute_len}`,
|
||||
`L ${dim.w - off.x - flute_off} ${yoff}`,
|
||||
`z`
|
||||
].join('\n')}});
|
||||
} else {
|
||||
let x1 = off.x + flute_off;
|
||||
let y1 = off.y + shaft_len;
|
||||
let x2 = x1 + max.w - flute_off * 2;
|
||||
let y2 = y1 + flute_len;
|
||||
parts.push({ rect: {
|
||||
x:off.x + flute_off, y:off.y + shaft_len,
|
||||
width:max.w - flute_off * 2, height:flute_len,
|
||||
stroke, fill: flute_fill, stroke_width
|
||||
} });
|
||||
parts.push({ line: { x1, y1, x2, y2, stroke, stroke_width: stroke_thin } });
|
||||
parts.push({ line: {
|
||||
x1: (x1 + x2) / 2, y1, x2, y2: (y1 + y2) / 2,
|
||||
stroke, stroke_width: stroke_thin
|
||||
} });
|
||||
parts.push({ line: {
|
||||
x1, y1: (y1 + y2) / 2, x2: (x1 + x2) / 2, y2,
|
||||
stroke, stroke_width: stroke_thin
|
||||
} });
|
||||
}
|
||||
if (type === "ballmill") {
|
||||
let rad = (max.w - flute_off * 2) / 2;
|
||||
let xend = dim.w - off.x - flute_off;
|
||||
let yoff = off.y + shaft_len + flute_len + stroke_width/2;
|
||||
parts.push({path: {stroke_width, stroke, fill:flute_fill, d:[
|
||||
`M ${off.x + flute_off} ${yoff}`,
|
||||
`A ${rad} ${rad} 0 0 0 ${xend} ${yoff}`,
|
||||
// `L ${off.x + flute_off} ${yoff}`
|
||||
].join('\n')}})
|
||||
}
|
||||
svg.innerHTML = otag(parts);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function updateTool(ev) {
|
||||
selectedTool.name = ui.toolName.value;
|
||||
selectedTool.number = parseInt(ui.toolNum.value);
|
||||
selectedTool.flute_diam = parseFloat(ui.toolFluteDiam.value);
|
||||
selectedTool.flute_len = parseFloat(ui.toolFluteLen.value);
|
||||
selectedTool.shaft_diam = parseFloat(ui.toolShaftDiam.value);
|
||||
selectedTool.shaft_len = parseFloat(ui.toolShaftLen.value);
|
||||
selectedTool.taper_tip = parseFloat(ui.toolTaperTip.value);
|
||||
selectedTool.metric = ui.toolMetric.checked;
|
||||
selectedTool.type = ['endmill','ballmill','tapermill'][ui.toolType.selectedIndex];
|
||||
if (selectedTool.type === 'tapermill') {
|
||||
const CAM = kiri.driver.CAM;
|
||||
const rad = (selectedTool.flute_diam - selectedTool.taper_tip) / 2;
|
||||
if (ev && ev.target === ui.toolTaperAngle) {
|
||||
const angle = parseFloat(ev.target.value);
|
||||
const len = CAM.calcTaperLength(rad, angle * DEG2RAD);
|
||||
selectedTool.flute_len = len;
|
||||
ui.toolTaperAngle.value = angle.round(1);
|
||||
ui.toolFluteLen.value = selectedTool.flute_len.round(4);
|
||||
} else {
|
||||
ui.toolTaperAngle.value = CAM.calcTaperAngle(rad, selectedTool.flute_len).round(1);
|
||||
}
|
||||
} else {
|
||||
ui.toolTaperAngle.value = 0;
|
||||
}
|
||||
renderTools();
|
||||
ui.toolSelect.selectedIndex = selectedTool.order;
|
||||
setToolChanged(true);
|
||||
renderTool(selectedTool);
|
||||
}
|
||||
|
||||
function setToolChanged(changed) {
|
||||
editTools.changed = changed;
|
||||
ui.toolsSave.disabled = !changed;
|
||||
}
|
||||
|
||||
function showTools() {
|
||||
if (api.mode.get_id() !== MODES.CAM) return;
|
||||
api.settings.sync.get().then(_showTools);
|
||||
}
|
||||
|
||||
function _showTools() {
|
||||
let selectedIndex = null;
|
||||
|
||||
editTools = settings().tools.slice().sort((a,b) => {
|
||||
return a.name > b.name ? 1 : -1;
|
||||
});
|
||||
|
||||
setToolChanged(false);
|
||||
|
||||
ui.toolsClose.onclick = function() {
|
||||
if (editTools.changed && !confirm("abandon changes?")) return;
|
||||
api.dialog.hide();
|
||||
};
|
||||
ui.toolAdd.onclick = function() {
|
||||
let metric = settings().controller.units === 'mm';
|
||||
editTools.push(Object.assign({
|
||||
id: Date.now(),
|
||||
number: maxTool + 1,
|
||||
name: "new tool",
|
||||
type: "endmill",
|
||||
taper_tip: 0,
|
||||
metric
|
||||
}, metric ? {
|
||||
shaft_diam: 2,
|
||||
shaft_len: 15,
|
||||
flute_diam: 2,
|
||||
flute_len: 20,
|
||||
} : {
|
||||
shaft_diam: 0.25,
|
||||
shaft_len: 1.5,
|
||||
flute_diam: 0.25,
|
||||
flute_len: 2,
|
||||
}));
|
||||
setToolChanged(true);
|
||||
renderTools();
|
||||
ui.toolSelect.selectedIndex = editTools.length-1;
|
||||
selectTool(editTools[editTools.length-1]);
|
||||
};
|
||||
ui.toolCopy.onclick = function() {
|
||||
let clone = Object.assign({}, selectedTool);
|
||||
let { name } = clone;
|
||||
let split = name.split(' ');
|
||||
let endv = parseInt(split.pop());
|
||||
if (endv) {
|
||||
name = split.join(' ') + ' ' + (endv + 1);
|
||||
} else {
|
||||
name = `${name} 2`;
|
||||
}
|
||||
clone.id = Date.now();
|
||||
clone.number = maxTool + 1;
|
||||
clone.name = name;
|
||||
editTools.push(clone);
|
||||
setToolChanged(true);
|
||||
renderTools();
|
||||
ui.toolSelect.selectedIndex = editTools.length-1;
|
||||
selectTool(editTools[editTools.length-1]);
|
||||
};
|
||||
ui.toolDelete.onclick = function() {
|
||||
editTools.remove(selectedTool);
|
||||
setToolChanged(true);
|
||||
renderTools();
|
||||
};
|
||||
ui.toolsSave.onclick = function() {
|
||||
if (selectedTool) updateTool();
|
||||
settings().tools = editTools.sort((a,b) => {
|
||||
return a.name < b.name ? -1 : 1;
|
||||
});
|
||||
setToolChanged(false);
|
||||
api.conf.save();
|
||||
api.conf.update_fields();
|
||||
api.event.settings();
|
||||
api.settings.sync.put();
|
||||
};
|
||||
ui.toolsExport.onclick = () => {
|
||||
uc.prompt("Export Tools Filename", "tools").then(name => {
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
const record = {
|
||||
version: kiri.version,
|
||||
tools: api.conf.get().tools,
|
||||
time: Date.now()
|
||||
};
|
||||
api.util.download(api.util.b64enc(record), `${name}.km`);
|
||||
});
|
||||
};
|
||||
|
||||
renderTools();
|
||||
if (editTools.length > 0) {
|
||||
selectTool(editTools[0]);
|
||||
ui.toolSelect.selectedIndex = 0;
|
||||
} else {
|
||||
ui.toolAdd.onclick();
|
||||
}
|
||||
|
||||
api.dialog.show('tools');
|
||||
ui.toolSelect.focus();
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -73,6 +73,7 @@ class Topo4 {
|
|||
this.diam = tool.fluteDiameter();
|
||||
this.zoff = widget.track.top || 0;
|
||||
this.leave = op.leave || 0;
|
||||
this.linear = op.linear || false;
|
||||
this.lineColor = state.settings.controller.dark ? 0xffff00 : 0x555500;
|
||||
|
||||
onupdate(0, "lathe");
|
||||
|
|
@ -363,7 +364,7 @@ class Topo4 {
|
|||
}
|
||||
|
||||
async latheMinions(onupdate) {
|
||||
const { sliced, tool, zoff, leave, maxo, zBottom, step, resolution } = this;
|
||||
const { sliced, tool, zoff, leave, maxo, zBottom, step, resolution, linear } = this;
|
||||
const { putCache, clearCache, queue } = this;
|
||||
|
||||
const rota = this.angle * DEG2RAD;
|
||||
|
|
@ -404,19 +405,34 @@ class Topo4 {
|
|||
await Promise.all(promises);
|
||||
recs.sort((a, b) => { return b.angle - a.angle });
|
||||
|
||||
count = recs[0].heights.length / 3;
|
||||
// let linear = true;
|
||||
|
||||
count = linear ? recs.length : recs[0].heights.length / 3;
|
||||
while (count-- > 0) {
|
||||
let slice = newSlice(count);
|
||||
slice.camLines = [ newPolygon().setOpen() ];
|
||||
paths.push(slice);
|
||||
}
|
||||
|
||||
for (let rec of recs) {
|
||||
const { degrees, heights } = rec;
|
||||
[...heights].group(3).forEach((a,i) => {
|
||||
// progress each path 360 degrees to prevent A rolling backwards
|
||||
paths[i].camLines[0].push( newPoint(a[0], a[1], a[2] + leave).setA(degrees + i * -360) );
|
||||
if (linear) {
|
||||
recs.forEach((rec,i) => {
|
||||
const { degrees, heights } = rec;
|
||||
[...heights].group(3).forEach((a) => {
|
||||
// progress each path 360 degrees to prevent A rolling backwards
|
||||
paths[i].camLines[0].push( newPoint(a[0], a[1], a[2] + leave).setA(degrees + i * -360) );
|
||||
});
|
||||
if (i % 2 === 1) {
|
||||
paths[i].camLines[0].reverse();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
for (let rec of recs) {
|
||||
const { degrees, heights } = rec;
|
||||
[...heights].group(3).forEach((a,i) => {
|
||||
// progress each path 360 degrees to prevent A rolling backwards
|
||||
paths[i].camLines[0].push( newPoint(a[0], a[1], a[2] + leave).setA(degrees + i * -360) );
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (let slice of paths) {
|
||||
|
|
@ -425,9 +441,11 @@ class Topo4 {
|
|||
console.log('empty', slice);
|
||||
continue;
|
||||
}
|
||||
// repeat first point 360 degrees progressed
|
||||
const repeat = poly.points[0];
|
||||
slice.camLines[0].push(repeat.clone().setA(repeat.a - 360));
|
||||
if (!linear) {
|
||||
// repeat first point 360 degrees progressed
|
||||
const repeat = poly.points[0];
|
||||
slice.camLines[0].push(repeat.clone().setA(repeat.a - 360));
|
||||
}
|
||||
slice.output()
|
||||
.setLayer("lathe", { line: this.lineColor })
|
||||
.addPoly(poly.clone().applyRotations().move({ z: -zoff, x:0, y:0 }));
|
||||
|
|
|
|||
|
|
@ -14,14 +14,20 @@ const { getRangeParameters } = FDM;
|
|||
const debug = false;
|
||||
|
||||
FDM.export = function(print, online, ondone, ondebug) {
|
||||
const { settings, belty, tools } = print;
|
||||
const { widgets, settings, belty, tools, firstTool } = print;
|
||||
const { bounds, controller, device, process, filter, mode } = settings;
|
||||
const { extruders, fwRetract } = device;
|
||||
const { bedWidth, bedDepth, bedRound, bedBelt, maxHeight } = device;
|
||||
const { gcodeFan, gcodeLayer, gcodeTrack, gcodePause, gcodeFeature } = device;
|
||||
|
||||
let model_labels = [];
|
||||
for (let widget of widgets) {
|
||||
model_labels.push(widget.track.grid_id);
|
||||
}
|
||||
|
||||
let layers = print.output,
|
||||
extras = device.extras || {},
|
||||
isBambu = extras.bbl,
|
||||
{ extrudeAbs } = device,
|
||||
{ exportThumb } = controller,
|
||||
extused = Object.keys(print.extruders).map(v => parseInt(v)),
|
||||
|
|
@ -72,7 +78,7 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
y: isBelt ? 0 : bedDepth/2,
|
||||
z: 0
|
||||
},
|
||||
tool = 0,
|
||||
tool = firstTool || 0,
|
||||
extruder = extruders[tool],
|
||||
offset_x = extruder.extOffsetX,
|
||||
offset_y = extruder.extOffsetY,
|
||||
|
|
@ -107,8 +113,9 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
z_max: maxHeight,
|
||||
layers: layers.length,
|
||||
progress: 0,
|
||||
nozzle: 0,
|
||||
tool: 0
|
||||
nozzle: tool,
|
||||
tool: tool,
|
||||
model_labels: model_labels.sort().join(',')
|
||||
},
|
||||
pidx, path, out, speedMMM, emitMM, emitPerMM, lastp, laste, dist,
|
||||
lines = 0,
|
||||
|
|
@ -120,15 +127,6 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
minz = { x: Infinity, y: Infinity, z: Infinity },
|
||||
// lenghts of each filament (by nozzle) consumed
|
||||
segments = [],
|
||||
// palette & ping data
|
||||
isPalette = device.filamentSource === 'palette3',
|
||||
paletteInfo = extras.palette || {},
|
||||
palettePingStart = Math.max(paletteInfo.ping, paletteInfo.feed, paletteInfo.push) || 500,
|
||||
palettePingSpace = paletteInfo.ping || 0,
|
||||
// track purges for palette3 pings
|
||||
purgePos,
|
||||
purgeOn = 0,
|
||||
purgeOff = 0,
|
||||
extrudeMM = FDM.extrudeMM,
|
||||
extrudePerMM = FDM.extrudePerMM;
|
||||
|
||||
|
|
@ -138,6 +136,19 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
}
|
||||
subst.tool_count = tools_used.length;
|
||||
|
||||
// encodes an array offset as a single "on" bit in an
|
||||
// 8 byte array, then converts the array to base64 which
|
||||
// is what Bambu's M624 uses to flag an object as currently
|
||||
// being printed. the array is presented at the top of the
|
||||
// gcode as a comment: "; model label id: {model_labels}"
|
||||
function encodeBitOffset(index) {
|
||||
let bytes = new Uint8Array(8);
|
||||
let byteIndex = Math.floor(index / 8);
|
||||
let bitPosition = index % 8;
|
||||
bytes[byteIndex] |= (1 << bitPosition);
|
||||
return btoa(String.fromCharCode(...bytes));
|
||||
}
|
||||
|
||||
function setTempFanSpeed(tempSpeed) {
|
||||
if (tempSpeed > 0) {
|
||||
fanSpeedSave = fanSpeedSave >= 0 ? fanSpeedSave : fanSpeed;
|
||||
|
|
@ -239,7 +250,9 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
// with logic flow IF / ELIF / ELSE / END
|
||||
// IF / IF is valid but will not nest
|
||||
function appendSub(line, pad) {
|
||||
if (line.indexOf(';; IF ') === 0) {
|
||||
if (line.indexOf(';; DEFINE ') === 0) {
|
||||
// ignore var declarations
|
||||
} else if (line.indexOf(';; IF ') === 0) {
|
||||
line = line.substring(6).trim();
|
||||
let evil = print.constReplace(line, subst, 0, 666);
|
||||
subon = evil;
|
||||
|
|
@ -301,15 +314,16 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
append("; --- startup ---");
|
||||
}
|
||||
|
||||
// lookg for ";; PREAMBLE <MODE>" comment
|
||||
// looking for ";; PREAMBLE <MODE>" comment
|
||||
let pre = 0;
|
||||
let gcpre = [];
|
||||
for (let line of device.gcodePre) {
|
||||
line = line.trim();
|
||||
if (line.indexOf(";; PREAMBLE ") === 0) {
|
||||
if (line.indexOf(";; PREAMBLE") === 0) {
|
||||
if (line === ';; PREAMBLE OFF') pre = 1;
|
||||
if (line === ';; PREAMBLE END') pre = 2;
|
||||
} if (line.indexOf(";; AXISMAP ") === 0) {
|
||||
else if (line === ';; PREAMBLE END') pre = 2;
|
||||
else gcpre.push(pre = 123);
|
||||
} else if (line.indexOf(";; AXISMAP ") === 0) {
|
||||
let axmap = JSON.parse(line.substring(11).trim());
|
||||
for (let key in axmap) {
|
||||
axis[key] = ` ${axmap[key]}`;
|
||||
|
|
@ -324,6 +338,10 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
let t0 = false;
|
||||
let t1 = false;
|
||||
for (let line of gcpre) {
|
||||
if (line === pre) {
|
||||
preamble();
|
||||
continue;
|
||||
}
|
||||
if (line.indexOf('T0') === 0) t0 = true; else
|
||||
if (line.indexOf('T1') === 0) t1 = true; else
|
||||
if (line.indexOf('M82') === 0) {
|
||||
|
|
@ -360,15 +378,7 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
}
|
||||
});
|
||||
}
|
||||
if (line.indexOf("{tool}") > 0 && extused.length > 0) {
|
||||
for (let i of extused) {
|
||||
subst.tool = i;
|
||||
appendSubPad(line);
|
||||
}
|
||||
subst.tool = 0;
|
||||
} else {
|
||||
appendSubPad(line);
|
||||
}
|
||||
appendSubPad(line);
|
||||
}
|
||||
|
||||
if (pre === 2) preamble();
|
||||
|
|
@ -441,15 +451,6 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
}
|
||||
|
||||
function moveTo(newpos, rate, comment) {
|
||||
if (pingRemain) {
|
||||
if (newpos.e) {
|
||||
if (pingRemain - newpos.e < -0.4) {
|
||||
// split move if ping over-extrudes? complicates emitted calc.
|
||||
// console.log({over_ping: pingRemain - newpos.e});
|
||||
}
|
||||
pingRemain -= newpos.e;
|
||||
}
|
||||
}
|
||||
let o = [!rate && !newpos.e ? 'G0' : 'G1'];
|
||||
let emit = { x: false, y: false, z: false };
|
||||
if (typeof newpos.x === 'number' && newpos.x !== pos.x) {
|
||||
|
|
@ -527,9 +528,6 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
totaldistance += o1.point.distTo2D(o2.point);
|
||||
}, 1);
|
||||
|
||||
// for palette pings, amount of extrusion left
|
||||
let pingRemain = 0;
|
||||
|
||||
// retract before first move
|
||||
retract();
|
||||
|
||||
|
|
@ -610,44 +608,26 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
moveTo({z:zpos}, seekMMM);
|
||||
}
|
||||
|
||||
let cwidget;
|
||||
// iterate through layer outputs
|
||||
for (pidx=0; pidx<path.length; pidx++) {
|
||||
out = path[pidx];
|
||||
speedMMM = (out.speed || process.outputFeedrate) * 60; // range
|
||||
|
||||
// track purge towers for palette3
|
||||
// do not generate pings before total tube length exhausted
|
||||
// because the palette cannot respond to differences before then
|
||||
if (isPalette && palettePingSpace && emitted >= palettePingStart) {
|
||||
if (purgeOn === 0 && out.point.purgeOn && emitted - purgeOff >= palettePingSpace) {
|
||||
retract();
|
||||
pushPos(out.point.purgeOn);
|
||||
// shorter pause accounts for retract/move
|
||||
dwell(12750);
|
||||
popPos();
|
||||
unretract();
|
||||
purgeOn = emitted;
|
||||
purgePos = out.point.purgeOn;
|
||||
pingRemain = 20;
|
||||
// hint to controller that we're working on a specific object
|
||||
// so that gcode between start/stop comments can be cancelled
|
||||
if (out.widget !== cwidget) {
|
||||
if (cwidget) {
|
||||
append(`; end object id: ${cwidget.track.grid_id}`);
|
||||
isBambu && append('M625');
|
||||
}
|
||||
if (purgeOn && pingRemain <= 0) {
|
||||
retract();
|
||||
pushPos(purgePos);
|
||||
// shorter pause accounts for retract/move
|
||||
dwell(6750);
|
||||
popPos();
|
||||
unretract();
|
||||
if (!print.purges) {
|
||||
print.purges = [];
|
||||
}
|
||||
print.purges.push({
|
||||
length: purgeOn,
|
||||
extrusion: emitted - purgeOn
|
||||
});
|
||||
purgeOff = emitted;
|
||||
purgeOn = 0;
|
||||
pingRemain = 0;
|
||||
if (out.widget) {
|
||||
let off = model_labels.indexOf(out.widget.track.grid_id);
|
||||
let b64 = encodeBitOffset(off);
|
||||
append(`; start object id: ${out.widget.track.grid_id}`);
|
||||
isBambu && append(`M624 ${b64}`);
|
||||
}
|
||||
cwidget = out.widget;
|
||||
}
|
||||
|
||||
// emit comment on output type chage
|
||||
|
|
@ -662,8 +642,11 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
|
||||
// look for extruder change, run scripts, recalc emit factor
|
||||
if (out.tool !== undefined && out.tool != tool) {
|
||||
let macro_deselect = extruder.extDeselect.length ? extruder.extDeselect : extruders[0].extDeselect;
|
||||
let macro_select = extruder.extSelect.length ? extruder.extSelect : extruders[0].extSelect;
|
||||
segments.push({emitted, tool});
|
||||
appendAllSub(extruder.extDeselect);
|
||||
appendAllSub(macro_deselect);
|
||||
subst.last_tool = tool;
|
||||
tool = out.tool;
|
||||
subst.nozzle = subst.tool = tool;
|
||||
extruder = extruders[tool];
|
||||
|
|
@ -674,10 +657,7 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
extruder.extFilament,
|
||||
path.layer === 0 ?
|
||||
(process.firstSliceHeight || process.sliceHeight) : path.height);
|
||||
// do not run extruder swapping code when source is Palette3
|
||||
if (!isPalette) {
|
||||
appendAllSub(extruder.extSelect);
|
||||
}
|
||||
appendAllSub(macro_select);
|
||||
}
|
||||
|
||||
// if no point in output, it's a dwell command
|
||||
|
|
@ -848,6 +828,11 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
laste = out.emit;
|
||||
}
|
||||
layer++;
|
||||
if (cwidget) {
|
||||
append(`; end object id: ${cwidget.track.grid_id}`);
|
||||
isBambu && append('M625');
|
||||
cwidget = undefined;
|
||||
}
|
||||
|
||||
// end open loop when detected
|
||||
while (endloop-- > 0) {
|
||||
|
|
@ -1002,11 +987,11 @@ FDM.export = function(print, online, ondone, ondebug) {
|
|||
// force emit of buffer
|
||||
append();
|
||||
// console.log({segments, emitted, outputLength});
|
||||
print.segments = isPalette ? segments : undefined;
|
||||
print.distance = emitted;
|
||||
print.lines = lines;
|
||||
print.bytes = bytes + lines - 1;
|
||||
print.time = time;
|
||||
print.labels = model_labels;
|
||||
|
||||
if (debug) {
|
||||
console.log('segments', segments);
|
||||
|
|
|
|||
|
|
@ -111,36 +111,42 @@ function fillGyroid(target) {
|
|||
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++) {
|
||||
if (gyroid.dir == 'lr') {
|
||||
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));
|
||||
for (let tx=0; tx<=tile_x; tx++) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
polys = connectOpenPolys(polys);
|
||||
for (let poly of polys.filter(p => p.perimeter() > 2)) {
|
||||
target.newline();
|
||||
for (let point of poly.points) {
|
||||
|
|
@ -180,7 +186,8 @@ function connectOpenPolys(noff, dist = 0.1) {
|
|||
continue outer;
|
||||
}
|
||||
if (s1.last().distTo2D(s2.last()) <= dist) {
|
||||
s1.addPoints(s2.points.reverse());
|
||||
s2.reverse();
|
||||
s1.addPoints(s2.points);
|
||||
ntmp[j] = null;
|
||||
continue outer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ FDM.prepare = async function(widgets, settings, update) {
|
|||
return a.z - b.z;
|
||||
});
|
||||
|
||||
let firstExt;
|
||||
let firstTool;
|
||||
let lastWidget;
|
||||
let lastExt;
|
||||
let lastOut;
|
||||
|
|
@ -516,8 +516,8 @@ FDM.prepare = async function(widgets, settings, update) {
|
|||
return a.dst - b.dst;
|
||||
});
|
||||
let { z, slice, offset } = order[0];
|
||||
if (firstExt === undefined) {
|
||||
firstExt = slice.extruder;
|
||||
if (firstTool === undefined) {
|
||||
firstTool = slice.extruder;
|
||||
}
|
||||
|
||||
// when layers switch between widgets, force retraction
|
||||
|
|
@ -549,6 +549,7 @@ FDM.prepare = async function(widgets, settings, update) {
|
|||
let beltStart = slice.belt && slice.belt.touch;// && (widgets.length === 1);
|
||||
// output seek to start point between mesh slices if previous data
|
||||
print.setType('layer');
|
||||
print.setWidget(lastWidget);
|
||||
printPoint = slicePrintPath(
|
||||
print,
|
||||
slice,
|
||||
|
|
@ -579,6 +580,7 @@ FDM.prepare = async function(widgets, settings, update) {
|
|||
}
|
||||
}
|
||||
);
|
||||
print.setWidget(null);
|
||||
|
||||
lastOut = slice;
|
||||
lastExt = lastOut.extruder;
|
||||
|
|
@ -644,6 +646,7 @@ FDM.prepare = async function(widgets, settings, update) {
|
|||
}
|
||||
|
||||
print.output = output;
|
||||
print.firstTool = firstTool;
|
||||
|
||||
// post-process for base extrusions (touching the bed)
|
||||
if (isBelt) {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,19 @@ FDM.sliceAll = function(settings, onupdate) {
|
|||
.sort((a,b) => {
|
||||
return a.slices[0].z - b.slices[0].z
|
||||
});
|
||||
// assign grid_id which can be embedded in gcode and
|
||||
// used by the controller to cancel objects during print
|
||||
let { bounds } = settings;
|
||||
for (let widget of widgets) {
|
||||
let { pos, box } = widget.track;
|
||||
// calculate top/left coordinate for widget
|
||||
// relative to bounding box for all widgets
|
||||
let tl = {
|
||||
x: Math.round((pos.x - box.w/2 - bounds.min.x) / 10) + 1,
|
||||
y: Math.round((pos.y - box.h/2 - bounds.min.y) / 10) + 1
|
||||
};
|
||||
widget.track.grid_id = tl.x * 100 + tl.y;
|
||||
}
|
||||
// count extruders used
|
||||
let ext = [];
|
||||
for (let w of widgets) {
|
||||
|
|
@ -104,6 +117,7 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
|
|||
let render = settings.render !== false,
|
||||
{ process, device, controller } = settings,
|
||||
isBelt = device.bedBelt,
|
||||
isBrick = controller.devel && process.sliceZInterleave,
|
||||
isSynth = widget.track.synth,
|
||||
isSupport = widget.track.support,
|
||||
useAssembly = controller.assembly,
|
||||
|
|
@ -857,6 +871,52 @@ FDM.slice = function(settings, widget, onupdate, ondone) {
|
|||
profileEnd();
|
||||
}
|
||||
|
||||
if (isBrick) {
|
||||
let indices = slices.map(s => s.index);
|
||||
let first = indices[1];
|
||||
let last = indices[indices.length - 2];
|
||||
let nu = [];
|
||||
for (let slice of slices) {
|
||||
if (slice.index < first || slice.index > last) {
|
||||
continue;
|
||||
}
|
||||
let nuSlice = slice.clone();
|
||||
nuSlice.z -= slice.height / 2;
|
||||
if (slice.index === first) {
|
||||
nuSlice.z = slice.z - slice.height / 4;
|
||||
nuSlice.height = slice.height / 2;
|
||||
} else {
|
||||
nuSlice.height = slice.height;
|
||||
}
|
||||
nu.push(nuSlice);
|
||||
let ti = 0;
|
||||
for (let top of slice.tops) {
|
||||
let nuTop = nuSlice.tops[ti++];
|
||||
nuTop.shells = [];
|
||||
top.shells = top.shells.filter((s,i) => {
|
||||
if (i % 2 === 0) {
|
||||
return true;
|
||||
} else {
|
||||
nuTop.shells.push(s);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (slice.index === last) {
|
||||
let cap = nuSlice.clone();
|
||||
cap.z += (slice.height * 0.75);
|
||||
cap.height = (slice.height / 2);
|
||||
nu.push(cap);
|
||||
cap.tops.forEach((top, i) => {
|
||||
top.shells = nuSlice.tops[i].shells.clone();
|
||||
});
|
||||
}
|
||||
}
|
||||
slices.appendAll(nu);
|
||||
slices.sort((a,b) => a.z - b.z);
|
||||
slices.forEach((s,i) => s.index = i);
|
||||
}
|
||||
|
||||
// render if not explicitly disabled
|
||||
if (render) {
|
||||
forSlices(0.9, 1.0, slice => {
|
||||
|
|
@ -1054,6 +1114,7 @@ function doShells(slice, count, offset1, offsetN, fillOffset, opt = {}) {
|
|||
}
|
||||
|
||||
slice.tops.forEach(function(top) {
|
||||
if (!top.fill_off) return; // missing for inner brick layers
|
||||
let lines = fillArea(top.fill_off, angle, spacing, null);
|
||||
top.fill_lines.appendAll(lines);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -45,14 +45,15 @@ function polyLabel(poly, label) {
|
|||
}
|
||||
|
||||
function sliceEmitObjects(print, slice, groups, opt = { }) {
|
||||
let process = print.settings.process;
|
||||
let stacked = process.ctOutStack;
|
||||
let grouped = stacked || process.ctOutGroup;
|
||||
let label = false && process.outputLaserLabel;
|
||||
let simple = opt.simple || false;
|
||||
let emit = { in: [], out: [], mark: [] };
|
||||
let lastEmit = opt.lastEmit;
|
||||
let zcolor = print.settings.process.ctOutZColor;
|
||||
let process = print.settings.process,
|
||||
marked = process.ctOutMark,
|
||||
stacked = process.ctOutStack,
|
||||
grouped = marked || process.ctOutGroup,
|
||||
label = false && process.outputLaserLabel,
|
||||
simple = opt.simple || false,
|
||||
emit = { in: [], out: [], mark: [] },
|
||||
lastEmit = opt.lastEmit,
|
||||
zcolor = print.settings.process.ctOutZColor;
|
||||
|
||||
function polyOut(poly, group, type, indexed) {
|
||||
if (!poly) {
|
||||
|
|
@ -77,7 +78,7 @@ function sliceEmitObjects(print, slice, groups, opt = { }) {
|
|||
print.PPP(poly, group, pathOpt);
|
||||
// when stacking (top down widget slices), if the last layer is fully contained
|
||||
// by the current layer, then it is "marked" onto the current layer in a different color
|
||||
if (stacked && type === "out" && lastEmit) {
|
||||
if (marked && type === "out" && lastEmit) {
|
||||
for (let out of lastEmit.out) {
|
||||
if (out.isInside(poly)) {
|
||||
polyOut(out, group, "mark");
|
||||
|
|
@ -297,9 +298,12 @@ async function prepare(widgets, settings, update) {
|
|||
// emit objects from each slice into output array
|
||||
let layers = [];
|
||||
for (let widget of widgets) {
|
||||
if (process.ctOutMerged) {
|
||||
// slice stack merging
|
||||
// there is not layout in this mode
|
||||
if (process.ctOutStack) {
|
||||
// 3d stack output, no merging or layout
|
||||
for (let slice of widget.slices) {
|
||||
}
|
||||
} else if (process.ctOutMerged) {
|
||||
// slice stack merging, no layout
|
||||
// there are no inner vs outer polys
|
||||
// merged/same polys "increase" color/weight
|
||||
let merged = [];
|
||||
|
|
@ -557,7 +561,8 @@ function exportGCode(settings, data) {
|
|||
let dev = settings.device;
|
||||
let proc = settings.process;
|
||||
let space = dev.gcodeSpace ? ' ' : '';
|
||||
let power = 255;
|
||||
let max_power = dev.laserMaxPower || 255;
|
||||
let power = max_power;
|
||||
let cut_on = dev.gcodeLaserOn || dev.gcodeWaterOn || dev.gcodeKnifeDn || [];
|
||||
let cut_off = dev.gcodeLaserOff || dev.gcodeWaterOff || dev.gcodeKnifeUp || [];
|
||||
let knifeOn = proc.knifeOn;
|
||||
|
|
@ -567,14 +572,14 @@ function exportGCode(settings, data) {
|
|||
exportElements(
|
||||
settings,
|
||||
data,
|
||||
function(min, max, power, speed) {
|
||||
function(min, max, pct, speed) {
|
||||
let width = (max.x - min.x),
|
||||
height = (max.y - min.y);
|
||||
|
||||
dx = min.x;
|
||||
dy = min.y;
|
||||
feedrate = `${space}F${speed}`;
|
||||
power = (256 * (power / 100)).toFixed(3);
|
||||
power = (max_power * (pct / 100)).toFixed(3);
|
||||
|
||||
(dev.gcodePre || []).forEach(line => {
|
||||
lines.push(line);
|
||||
|
|
@ -640,7 +645,7 @@ function exportGCode(settings, data) {
|
|||
function exportSVG(settings, data, cut_color) {
|
||||
let { process } = settings;
|
||||
let zcolor = process.ctOutZColor ? 1 : 0;
|
||||
let zstack = process.ctOutStack;
|
||||
let zstack = process.ctOutMark;
|
||||
let lines = [], dx = 0, dy = 0, my, z = 0;
|
||||
let colors = [
|
||||
"black",
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ function init(kiri, api) {
|
|||
print_min = print_min.toString().padStart(2,'0');
|
||||
print_hrs = print_hrs.toString().padStart(2,'0');
|
||||
|
||||
$('print-filename').value = filename;
|
||||
$('print-filename-sla').value = filename;
|
||||
$('print-volume').value = (volume/1000).round(2);
|
||||
$('print-layers').value = layers;
|
||||
$('print-time').value = `${print_hrs}:${print_min}:${print_sec}`;
|
||||
|
|
@ -94,7 +94,7 @@ function init(kiri, api) {
|
|||
}
|
||||
|
||||
function saveFile(api, file, ext) {
|
||||
api.util.download(file, $('print-filename').value + ext);
|
||||
api.util.download(file, $('print-filename-sla').value + ext);
|
||||
api.modal.hide();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -494,15 +494,29 @@ kiri.worker = {
|
|||
send.data({debug});
|
||||
});
|
||||
const {
|
||||
bounds, time, lines, bytes, distance,
|
||||
settings, segments, purges
|
||||
bounds,
|
||||
time,
|
||||
lines,
|
||||
bytes,
|
||||
distance,
|
||||
settings,
|
||||
segments,
|
||||
purges,
|
||||
labels
|
||||
} = current.print;
|
||||
|
||||
send.done({
|
||||
done: true,
|
||||
output: output ? output : {
|
||||
bounds, time, lines, bytes, distance,
|
||||
settings, segments, purges
|
||||
bounds,
|
||||
time,
|
||||
lines,
|
||||
bytes,
|
||||
distance,
|
||||
settings,
|
||||
segments,
|
||||
purges,
|
||||
labels
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -67,10 +67,11 @@ function update(clear) {
|
|||
}
|
||||
}
|
||||
|
||||
api.alerts = {
|
||||
// extend API
|
||||
Object.assign(api.alerts, {
|
||||
hide,
|
||||
show,
|
||||
update
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
213
src/kiri/api.js
213
src/kiri/api.js
|
|
@ -6,59 +6,134 @@
|
|||
// dep: data.local
|
||||
// dep: kiri.utils
|
||||
// dep: kiri.consts
|
||||
gapp.register("kiri.api", [], (root, exports) => {
|
||||
gapp.register("kiri.api", (root, exports) => {
|
||||
|
||||
const { data, kiri, noop } = root;
|
||||
const { consts, utils } = kiri;
|
||||
const { areEqual, parseOpt, encodeOpt, ajax, o2js, js2o } = utils;
|
||||
const { LISTS } = consts;
|
||||
|
||||
let isHover = false;
|
||||
|
||||
const feature = {
|
||||
seed: true, // seed profiles on first use
|
||||
meta: true, // show selected widget metadata
|
||||
frame: true, // receive frame events
|
||||
alert_event: false, // emit alerts as events instead of display
|
||||
controls: true, // show or not side menus
|
||||
device_filter: undefined, // function to limit devices shown
|
||||
drop_group: undefined, // optional array to group multi drop
|
||||
drop_layout: true, // layout on new drop
|
||||
hoverAdds: false, // when true only searches widget additions
|
||||
on_key: undefined, // function override default key handlers
|
||||
on_load: undefined, // function override file drop loads
|
||||
on_add_stl: undefined, // legacy override stl drop loads
|
||||
on_mouse_up: undefined, // function intercepts mouse up select
|
||||
on_mouse_down: undefined, // function intercepts mouse down
|
||||
work_alerts: true, // allow disabling work progress alerts
|
||||
modes: [ "fdm", "sla", "cam", "laser" ], // enable device modes
|
||||
pmode: consts.PMODES.SPEED, // preview modes
|
||||
// hover: false, // when true fires mouse hover events
|
||||
get hover() {
|
||||
return isHover;
|
||||
let { data, kiri, moto, noop } = root,
|
||||
{ consts, utils } = kiri,
|
||||
{ ajax, o2js, js2o } = utils,
|
||||
lists = consts.LISTS,
|
||||
clone = Object.clone,
|
||||
isHover = false,
|
||||
feature = {
|
||||
seed: true, // seed profiles on first use
|
||||
meta: true, // show selected widget metadata
|
||||
frame: true, // receive frame events
|
||||
alert_event: false, // emit alerts as events instead of display
|
||||
controls: true, // show or not side menus
|
||||
device_filter: undefined, // function to limit devices shown
|
||||
drop_group: undefined, // optional array to group multi drop
|
||||
drop_layout: true, // layout on new drop
|
||||
hoverAdds: false, // when true only searches widget additions
|
||||
on_key: undefined, // function override default key handlers
|
||||
on_key2: [], // allows for multiple key handlers
|
||||
on_load: undefined, // function override file drop loads
|
||||
on_add_stl: undefined, // legacy override stl drop loads
|
||||
on_mouse_up: undefined, // function intercepts mouse up select
|
||||
on_mouse_down: undefined, // function intercepts mouse down
|
||||
work_alerts: true, // allow disabling work progress alerts
|
||||
pmode: consts.PMODES.SPEED, // preview modes
|
||||
// hover: false, // when true fires mouse hover events
|
||||
get hover() {
|
||||
return isHover;
|
||||
},
|
||||
set hover(b) {
|
||||
isHover = b;
|
||||
moto.broker.publish("feature.hover", b);
|
||||
}
|
||||
},
|
||||
set hover(b) {
|
||||
isHover = b;
|
||||
moto.broker.publish("feature.hover", b);
|
||||
}
|
||||
};
|
||||
onkey = (fn) => {
|
||||
api.feature.on_key2.push(fn);
|
||||
},
|
||||
doit = {
|
||||
undo: noop, // do.js
|
||||
redo: noop // do.js
|
||||
},
|
||||
devel = {
|
||||
xray(layers, raw) {
|
||||
let proc = api.conf.get().process,
|
||||
size = proc.sliceHeight || proc.slaSlice || 1,
|
||||
base = (proc.firstSliceHeight || size);
|
||||
layers = Array.isArray(layers) ? layers : [ layers ];
|
||||
proc.xray = layers.map(l => raw ? l : base + l * size - size / 2);
|
||||
proc.xrayi = layers.slice();
|
||||
api.function.slice();
|
||||
}
|
||||
},
|
||||
local = {
|
||||
get: (key) => localGet(key),
|
||||
getInt: (key) => parseInt(localGet(key)),
|
||||
getFloat: (key) => parseFloat(localGet(key)),
|
||||
getBoolean: (key, def = true) => {
|
||||
let val = localGet(key);
|
||||
return val === true || val === 'true' || val === def;
|
||||
},
|
||||
toggle: (key, val, def) => localSet(key, val ?? !api.local.getBoolean(key, def)),
|
||||
put: (key, val) => localSet(key, val),
|
||||
set: (key, val) => localSet(key, val),
|
||||
},
|
||||
tweak = {
|
||||
line_precision(v) { api.work.config({base:{clipperClean: v}}) },
|
||||
gcode_decimals(v) { api.work.config({base:{gcode_decimals: v}}) }
|
||||
},
|
||||
und = undefined,
|
||||
api = exports({
|
||||
ajax, // via utils
|
||||
alerts: {}, // alerts.js
|
||||
busy: {}, // main.js
|
||||
catalog: und, // main.js
|
||||
clip, // <--
|
||||
clone, // <--
|
||||
color: und, // main.js
|
||||
conf: {}, // settings.js
|
||||
const: {}, // main.js
|
||||
devel, // <--
|
||||
device: {}, // devices.js
|
||||
devices: {}, // devices.js
|
||||
dialog: {}, // main.js
|
||||
doit, // <--
|
||||
event: {}, // main.js
|
||||
feature, // <--
|
||||
function: {}, // function.js
|
||||
group: {}, // main.js
|
||||
help: {}, // main.js
|
||||
hide: {}, // main.js
|
||||
image: {}, // main.js
|
||||
js2o, // via utils
|
||||
language: und, // main.js
|
||||
lists, // <--
|
||||
local, // <--
|
||||
modal: {}, // main.js
|
||||
mode: {}, // main.js
|
||||
o2js, // via utils
|
||||
onkey, // <--
|
||||
platform: {}, // platform.js
|
||||
probe: {}, // main.js
|
||||
process: {}, // main.js
|
||||
sdb: data.local,
|
||||
selection: {}, // selection.js
|
||||
settings: {}, // settings.js
|
||||
show: {}, // main.js
|
||||
space: {}, // main.js
|
||||
tool: {}, // kiri-mode/cam/tools.js
|
||||
tweak, // <--
|
||||
uc: {}, // main.js
|
||||
ui: {}, // main.js
|
||||
util: {}, // main.js
|
||||
var: {
|
||||
layer_lo: 0,
|
||||
layer_hi: 0,
|
||||
layer_max: 0
|
||||
},
|
||||
view: {}, // main.js
|
||||
widgets: {}, // widgets.js
|
||||
work: und, // main.js
|
||||
});
|
||||
|
||||
const devel = {
|
||||
xray: (layers, raw) => {
|
||||
let proc = api.conf.get().process;
|
||||
let size = proc.sliceHeight || proc.slaSlice || 1;
|
||||
let base = (proc.firstSliceHeight || size);
|
||||
layers = Array.isArray(layers) ? layers : [ layers ];
|
||||
proc.xray = layers.map(l => raw ? l : base + l * size - size / 2);
|
||||
proc.xrayi = layers.slice();
|
||||
api.function.slice();
|
||||
}
|
||||
};
|
||||
|
||||
const tweak = {
|
||||
line_precision(v) { api.work.config({base:{clipperClean: v}}) },
|
||||
gcode_decimals(v) { api.work.config({base:{gcode_decimals: v}}) }
|
||||
};
|
||||
function clip(text) {
|
||||
navigator.clipboard
|
||||
.writeText(text)
|
||||
.catch(err => console.error('Clipboard Error:', err));
|
||||
}
|
||||
|
||||
function localGet(key) {
|
||||
let sloc = api.conf.get().local;
|
||||
|
|
@ -71,42 +146,4 @@ function localSet(key, val) {
|
|||
return val;
|
||||
}
|
||||
|
||||
const api = exports({
|
||||
clip: (text) => {
|
||||
navigator.clipboard
|
||||
.writeText(text)
|
||||
.catch(err => console.error('Clipboard Error:', err));
|
||||
},
|
||||
clone: Object.clone,
|
||||
sdb: data.local,
|
||||
ajax: ajax,
|
||||
js2o: js2o,
|
||||
o2js: o2js,
|
||||
lists: LISTS,
|
||||
doit: {
|
||||
undo: noop, // set in do.js
|
||||
redo: noop // set in do.js
|
||||
},
|
||||
var: {
|
||||
layer_lo: 0,
|
||||
layer_hi: 0,
|
||||
layer_max: 0
|
||||
},
|
||||
feature,
|
||||
devel,
|
||||
tweak,
|
||||
local: {
|
||||
get: (key) => localGet(key),
|
||||
getInt: (key) => parseInt(localGet(key)),
|
||||
getFloat: (key) => parseFloat(localGet(key)),
|
||||
getBoolean: (key, def = true) => {
|
||||
let val = localGet(key);
|
||||
return val === true || val === 'true' || val === def;
|
||||
},
|
||||
toggle: (key, val, def) => localSet(key, val ?? !api.local.getBoolean(key, def)),
|
||||
put: (key, val) => localSet(key, val),
|
||||
set: (key, val) => localSet(key, val),
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
// dep: add.array
|
||||
// dep: data.local
|
||||
gapp.register("kiri.conf", [], (root, exports) => {
|
||||
gapp.register("kiri.conf", (root, exports) => {
|
||||
|
||||
const { data } = root;
|
||||
const { local } = data;
|
||||
const { clone } = Object;
|
||||
const CVER = 185;
|
||||
const CVER = 410;
|
||||
|
||||
function genID() {
|
||||
while (true) {
|
||||
|
|
@ -79,21 +79,6 @@ function forValues(o, fn) {
|
|||
Object.values(o).forEach(v => fn(v));
|
||||
}
|
||||
|
||||
function device_v1_to_v2(device) {
|
||||
if (device && device.filamentSize) {
|
||||
device.extruders = [{
|
||||
extFilament: device.filamentSize,
|
||||
extNozzle: device.nozzleSize,
|
||||
extSelect: ["T0"],
|
||||
extDeselect: [],
|
||||
extOffsetX: 0,
|
||||
extOffsetY: 0
|
||||
}];
|
||||
delete device.filamentSize;
|
||||
delete device.nozzleSize;
|
||||
}
|
||||
}
|
||||
|
||||
// convert default filter (from server) into device structure
|
||||
function device_from_code(code,mode) {
|
||||
// presence of internal field indicates already converted
|
||||
|
|
@ -176,18 +161,6 @@ function normalize(settings) {
|
|||
default_dev = defaults[mode].d,
|
||||
default_pro = defaults[mode].p;
|
||||
|
||||
// v1 to v2 changed FDM extruder / nozzle / filament structure
|
||||
if (settings.ver != CVER) {
|
||||
// backup settings before upgrade
|
||||
local.setItem(`ws-settings-${Date.now()}`, JSON.stringify(settings));
|
||||
device_v1_to_v2(settings.device);
|
||||
device_v1_to_v2(settings.cdev.FDM);
|
||||
objectMap(settings.devices, dev => {
|
||||
return dev ? device_from_code(dev) : dev;
|
||||
});
|
||||
settings.ver = CVER;
|
||||
}
|
||||
|
||||
// fixup old/new detail settings
|
||||
let detail = settings.controller.detail;
|
||||
settings.controller.detail = {
|
||||
|
|
@ -292,7 +265,7 @@ const conf = exports({
|
|||
extOffsetY: 0
|
||||
}],
|
||||
profiles: [],
|
||||
// other stored info like palette3 config
|
||||
// other stored config info
|
||||
extras: {}
|
||||
},
|
||||
// process defaults FDM:Process
|
||||
|
|
@ -327,6 +300,7 @@ const conf = exports({
|
|||
sliceSupportNozzle: 0,
|
||||
sliceSupportEnable: false,
|
||||
sliceSupportOutline: true,
|
||||
sliceZInterleave: false,
|
||||
sliceSolidMinArea: 1,
|
||||
sliceBottomLayers: 3,
|
||||
sliceTopLayers: 3,
|
||||
|
|
@ -522,8 +496,11 @@ const conf = exports({
|
|||
camTraceSpeed: 250,
|
||||
camTracePlunge: 200,
|
||||
camTraceOffOver: 0,
|
||||
camTraceDogbone: false,
|
||||
camTraceMerge: true,
|
||||
camTraceLines: false,
|
||||
camTraceBottom: false,
|
||||
camTraceZTop: 0,
|
||||
camTraceZBottom: 0,
|
||||
camPocketSpindle: 1000,
|
||||
camPocketTool: 1000,
|
||||
camPocketOver: 0.25,
|
||||
|
|
@ -537,6 +514,8 @@ const conf = exports({
|
|||
camPocketContour: false,
|
||||
camPocketEngrave: false,
|
||||
camPocketOutline: false,
|
||||
camPocketZTop: 0,
|
||||
camPocketZBottom: 0,
|
||||
camDrillTool: 1000,
|
||||
camDrillSpindle: 1000,
|
||||
camDrillDownSpeed: 250,
|
||||
|
|
@ -573,6 +552,7 @@ const conf = exports({
|
|||
camOriginTop: true,
|
||||
camZAnchor: "middle",
|
||||
camZOffset: 0,
|
||||
camZTop: 0,
|
||||
camZBottom: 0,
|
||||
camZClearance: 1,
|
||||
camZThru: 0,
|
||||
|
|
@ -619,6 +599,7 @@ const conf = exports({
|
|||
bedDepth: 200,
|
||||
bedHeight: 2.5,
|
||||
maxHeight: 100,
|
||||
laserMaxPower: 255,
|
||||
gcodePre: [],
|
||||
gcodePost: [],
|
||||
gcodeFExt: "",
|
||||
|
|
@ -639,6 +620,7 @@ const conf = exports({
|
|||
ctOutGroup: true,
|
||||
ctOutZColor: false,
|
||||
ctOutLayer: false,
|
||||
ctOutMark: false,
|
||||
ctOutStack: false,
|
||||
ctOutMerged: false,
|
||||
ctOriginCenter: true,
|
||||
|
|
@ -682,7 +664,7 @@ const conf = exports({
|
|||
ctOutGroup: true,
|
||||
ctOutZColor: false,
|
||||
ctOutLayer: false,
|
||||
ctOutStack: false,
|
||||
ctOutMark: false,
|
||||
ctOutMerged: false,
|
||||
ctOriginCenter: true,
|
||||
ctOriginBounds: false,
|
||||
|
|
@ -690,7 +672,8 @@ const conf = exports({
|
|||
outputInvertY: false,
|
||||
ctOutKnifeDepth: 1,
|
||||
ctOutKnifePasses: 1,
|
||||
ctOutKnifeTip: 2
|
||||
ctOutKnifeTip: 2,
|
||||
ctOutStack: true,
|
||||
},
|
||||
},
|
||||
wjet: {
|
||||
|
|
@ -725,7 +708,7 @@ const conf = exports({
|
|||
ctOutGroup: true,
|
||||
ctOutZColor: false,
|
||||
ctOutLayer: false,
|
||||
ctOutStack: false,
|
||||
ctOutMark: false,
|
||||
ctOutMerged: false,
|
||||
ctOriginCenter: true,
|
||||
ctOriginBounds: false,
|
||||
|
|
@ -733,7 +716,8 @@ const conf = exports({
|
|||
outputInvertY: false,
|
||||
ctOutKnifeDepth: 1,
|
||||
ctOutKnifePasses: 1,
|
||||
ctOutKnifeTip: 2
|
||||
ctOutKnifeTip: 2,
|
||||
ctOutStack: false,
|
||||
},
|
||||
},
|
||||
wedm: {
|
||||
|
|
@ -767,14 +751,15 @@ const conf = exports({
|
|||
ctOutGroup: true,
|
||||
ctOutZColor: false,
|
||||
ctOutLayer: false,
|
||||
ctOutStack: false,
|
||||
ctOutMark: false,
|
||||
ctOutMerged: false,
|
||||
ctOriginCenter: false,
|
||||
ctOriginBounds: true,
|
||||
ctOriginOffX: 0,
|
||||
ctOriginOffY: 0,
|
||||
outputInvertX: false,
|
||||
outputInvertY: false
|
||||
outputInvertY: false,
|
||||
ctOutStack: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -851,11 +836,11 @@ const conf = exports({
|
|||
taper_tip: 0,
|
||||
}
|
||||
],
|
||||
// currently selected device
|
||||
// currently selected device (current mode)
|
||||
device:{},
|
||||
// currently selected process
|
||||
// currently selected process (current mode)
|
||||
process:{},
|
||||
// current process name by mode
|
||||
// current process (name of last used) by mode
|
||||
cproc:{
|
||||
FDM: "default",
|
||||
SLA: "default",
|
||||
|
|
@ -865,7 +850,7 @@ const conf = exports({
|
|||
WEDM: "default",
|
||||
LASER: "default",
|
||||
},
|
||||
// stored processes by mode
|
||||
// stored process (copy of last used) by mode
|
||||
sproc:{
|
||||
FDM: {},
|
||||
SLA: {},
|
||||
|
|
@ -875,7 +860,7 @@ const conf = exports({
|
|||
WEDM: {},
|
||||
LASER: {},
|
||||
},
|
||||
// current device name by mode
|
||||
// current device (name of last used) by mode
|
||||
filter:{
|
||||
FDM: "Any.Generic.Marlin",
|
||||
SLA: "Anycubic.Photon",
|
||||
|
|
@ -885,7 +870,7 @@ const conf = exports({
|
|||
WEDM: "RackRobo.Betta.Wire.V1",
|
||||
LASER: "Any.Generic.Laser",
|
||||
},
|
||||
// stored device by mode
|
||||
// current (last used) device by mode
|
||||
cdev: {
|
||||
FDM: null,
|
||||
SLA: null,
|
||||
|
|
@ -895,9 +880,7 @@ const conf = exports({
|
|||
},
|
||||
// custom devices by name (all modes)
|
||||
devices:{},
|
||||
// favorited devices (all modes)
|
||||
favorites:{},
|
||||
// map of device to last process setting (name)
|
||||
// map of device name to last process setting name
|
||||
devproc: {},
|
||||
// application ui and control preferences (Q menu)
|
||||
controller:{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
gapp.register("kiri.consts", [], (root, exports) => {
|
||||
gapp.register("kiri.consts", (root, exports) => {
|
||||
|
||||
const COLOR = {
|
||||
wireframe: 0x444444,
|
||||
|
|
@ -62,10 +62,6 @@ const LISTS = {
|
|||
{ name: "flat" },
|
||||
{ name: "line" }
|
||||
],
|
||||
filasrc: [
|
||||
{ name: "direct" },
|
||||
{ name: "palette3" }
|
||||
],
|
||||
animesh: [
|
||||
{ name: "100" },
|
||||
{ name: "200" },
|
||||
|
|
|
|||
395
src/kiri/devices.js
Normal file
395
src/kiri/devices.js
Normal file
|
|
@ -0,0 +1,395 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
"use strict";
|
||||
|
||||
// dep: kiri.api
|
||||
// dep: kiri.settings
|
||||
gapp.register("kiri.devices", (root, exports) => {
|
||||
|
||||
let { kiri } = root,
|
||||
{ api, conf } = kiri;
|
||||
|
||||
// extend API
|
||||
Object.assign(api.show, {
|
||||
devices: showDevices
|
||||
});
|
||||
|
||||
Object.assign(api.device, {
|
||||
clone: cloneDevice,
|
||||
code: currentDeviceCode,
|
||||
get: currentDeviceName,
|
||||
set: selectDevice,
|
||||
isBelt
|
||||
});
|
||||
|
||||
Object.assign(api.devices, {
|
||||
show: showDevices,
|
||||
select: selectDevice,
|
||||
refresh: updateDeviceList,
|
||||
update_laser_state: updateLaserState
|
||||
});
|
||||
|
||||
function isBelt() {
|
||||
return api.conf.get().device.bedBelt;
|
||||
}
|
||||
|
||||
function currentDeviceName() {
|
||||
return api.conf.get().filter[api.mode.get()];
|
||||
}
|
||||
|
||||
function currentDeviceCode() {
|
||||
return api.conf.get().devices[currentDeviceName()];
|
||||
}
|
||||
|
||||
function getModeDevices() {
|
||||
// devices are injected into self scope by
|
||||
// app.js generateDevices()
|
||||
return Object.keys(devices[api.mode.get_lower()]).sort();
|
||||
}
|
||||
|
||||
function showDevices() {
|
||||
api.settings.sync.get().then(_showDevices);
|
||||
}
|
||||
|
||||
function _showDevices() {
|
||||
updateDeviceList();
|
||||
api.modal.show('setup');
|
||||
}
|
||||
|
||||
function updateDeviceList() {
|
||||
renderDevices(getModeDevices());
|
||||
}
|
||||
|
||||
function updateDeviceName(newname) {
|
||||
let selected = api.device.get(),
|
||||
devs = api.conf.get().devices;
|
||||
if (newname !== selected) {
|
||||
devs[newname] = devs[selected];
|
||||
delete devs[selected];
|
||||
selectDevice(newname);
|
||||
updateDeviceList();
|
||||
}
|
||||
}
|
||||
|
||||
function putLocalDevice(devicename, obj) {
|
||||
api.conf.get().devices[devicename] = obj;
|
||||
api.conf.save();
|
||||
}
|
||||
|
||||
function removeLocalDevice(devicename) {
|
||||
delete api.conf.get().devices[devicename];
|
||||
api.conf.save();
|
||||
api.settings.sync.put();
|
||||
}
|
||||
|
||||
function isLocalDevice(devicename) {
|
||||
return api.conf.get().devices[devicename] ? true : false;
|
||||
}
|
||||
|
||||
function getSelectedDevice() {
|
||||
return api.device.get();
|
||||
}
|
||||
|
||||
function selectDevice(devicename) {
|
||||
if (isLocalDevice(devicename)) {
|
||||
setDeviceCode(api.conf.get().devices[devicename], devicename);
|
||||
} else {
|
||||
let code = devices[api.mode.get_lower()][devicename];
|
||||
if (code) {
|
||||
setDeviceCode(code, devicename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only for local filters
|
||||
function cloneDevice() {
|
||||
let name = `${getSelectedDevice().replace(/\./g,' ')}`;
|
||||
let code = api.clone(api.conf.get().device);
|
||||
code.mode = api.mode.get();
|
||||
if (name.toLowerCase().indexOf('my ') >= 0) {
|
||||
name = `${name} copy`;
|
||||
} else {
|
||||
name = `My ${name}`;
|
||||
}
|
||||
putLocalDevice(name, code);
|
||||
setDeviceCode(code, name);
|
||||
api.settings.sync.put();
|
||||
}
|
||||
|
||||
function updateLaserState() {
|
||||
const dev = api.conf.get().device;
|
||||
$('laser-on').style.display = dev.useLaser ? 'flex' : 'none';
|
||||
$('laser-off').style.display = dev.useLaser ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
function setDeviceCode(code, devicename) {
|
||||
api.event.emit('device.select', devicename);
|
||||
try {
|
||||
if (typeof(code) === 'string') code = js2o(code) || {};
|
||||
|
||||
let mode = api.mode.get(),
|
||||
lmode = mode.toLowerCase(),
|
||||
current = api.conf.get(),
|
||||
local = isLocalDevice(devicename),
|
||||
dev = current.device = conf.device_from_code(code,mode),
|
||||
dproc = current.devproc[devicename], // last process name for this device
|
||||
newdev = dproc === undefined, // first time device is selected
|
||||
predev = current.filter[mode], // previous device selection
|
||||
chgdev = predev !== devicename; // device is changing
|
||||
|
||||
// fill missing device fields
|
||||
conf.fill_cull_once(dev, conf.defaults[lmode].d);
|
||||
|
||||
// first time device use, add any print profiles and set to default if present
|
||||
if (code.profiles) {
|
||||
for (let profile of code.profiles) {
|
||||
let profname = profile.processName;
|
||||
// if no saved profile by that name for this mode...
|
||||
if (!current.sproc[mode][profname]) {
|
||||
console.log('adding profile', profname, 'to', mode);
|
||||
current.sproc[mode][profname] = profile;
|
||||
}
|
||||
// if it's a new device, seed the new profile name as last profile
|
||||
if (newdev && !current.devproc[devicename]) {
|
||||
console.log('setting default profile for new device', devicename, 'to', profname);
|
||||
current.devproc[devicename] = dproc = profname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev.new = false;
|
||||
dev.deviceName = devicename;
|
||||
|
||||
let { platform, ui, uc } = api;
|
||||
let { space } = kiri;
|
||||
|
||||
ui.deviceBelt.checked = dev.bedBelt;
|
||||
ui.deviceRound.checked = dev.bedRound;
|
||||
ui.deviceOrigin.checked = dev.ctOriginCenter || dev.originCenter || dev.bedRound;
|
||||
ui.fwRetract.checked = dev.fwRetract;
|
||||
|
||||
// add extruder selection buttons
|
||||
if (dev.extruders) {
|
||||
let ext = api.lists.extruders = [];
|
||||
dev.internal = 0;
|
||||
for (let i=0; i<dev.extruders.length; i++) {
|
||||
ext.push({id:i, name:i});
|
||||
}
|
||||
}
|
||||
|
||||
// disable editing for non-local devices
|
||||
[
|
||||
// ui.deviceName,
|
||||
ui.gcodePre,
|
||||
ui.gcodePost,
|
||||
ui.bedDepth,
|
||||
ui.bedWidth,
|
||||
ui.maxHeight,
|
||||
ui.useLaser,
|
||||
ui.resolutionX,
|
||||
ui.resolutionY,
|
||||
ui.deviceOrigin,
|
||||
ui.deviceRound,
|
||||
ui.deviceBelt,
|
||||
ui.fwRetract,
|
||||
ui.deviceZMax,
|
||||
ui.gcodeTime,
|
||||
ui.gcodeFan,
|
||||
ui.gcodeFeature,
|
||||
ui.gcodeTrack,
|
||||
ui.gcodeLayer,
|
||||
ui.extFilament,
|
||||
ui.extNozzle,
|
||||
ui.spindleMax,
|
||||
ui.gcodeSpindle,
|
||||
ui.gcodeDwell,
|
||||
ui.gcodeChange,
|
||||
ui.gcodeFExt,
|
||||
ui.gcodeSpace,
|
||||
ui.gcodeStrip,
|
||||
ui.gcodeLaserOn,
|
||||
ui.gcodeLaserOff,
|
||||
ui.laserMaxPower,
|
||||
ui.extPrev,
|
||||
ui.extNext,
|
||||
ui.extAdd,
|
||||
ui.extDel,
|
||||
ui.extOffsetX,
|
||||
ui.extOffsetY,
|
||||
ui.extSelect,
|
||||
ui.extDeselect
|
||||
].forEach(function(e) {
|
||||
e.disabled = !local;
|
||||
});
|
||||
|
||||
ui.deviceSave.disabled = !local;
|
||||
ui.deviceDelete.disabled = !local;
|
||||
ui.deviceRename.disabled = !local;
|
||||
ui.deviceExport.disabled = !local;
|
||||
ui.deviceAdd.style.display = mode === 'SLA' ? 'none' : '';
|
||||
|
||||
if (local) {
|
||||
ui.deviceAdd.innerText = "copy";
|
||||
ui.deviceDelete.style.display = '';
|
||||
ui.deviceRename.style.display = '';
|
||||
ui.deviceExport.style.display = '';
|
||||
} else {
|
||||
ui.deviceAdd.innerText = "customize";
|
||||
ui.deviceDelete.style.display = 'none';
|
||||
ui.deviceRename.style.display = 'none';
|
||||
ui.deviceExport.style.display = 'none';
|
||||
}
|
||||
ui.deviceAdd.disabled = dev.noclone;
|
||||
|
||||
api.conf.update_fields();
|
||||
space.platform.setBelt(isBelt());
|
||||
platform.update_size();
|
||||
platform.update_origin();
|
||||
platform.update();
|
||||
updateLaserState();
|
||||
|
||||
// store current device name for this mode
|
||||
current.filter[mode] = devicename;
|
||||
// cache device record for this mode (restored in setMode)
|
||||
current.cdev[mode] = dev;
|
||||
|
||||
if (dproc) {
|
||||
// restore last process associated with this device
|
||||
api.conf.load(null, dproc);
|
||||
} else {
|
||||
api.conf.update();
|
||||
}
|
||||
|
||||
api.conf.save();
|
||||
|
||||
if (isBelt()) {
|
||||
// space.view.setHome(dev.bedBelt ? Math.PI/2 : 0, Math.PI / 2.5);
|
||||
space.view.setHome(0, Math.PI / 2.5);
|
||||
} else {
|
||||
space.view.setHome(0);
|
||||
}
|
||||
// when changing devices, update focus on widgets
|
||||
if (chgdev) {
|
||||
setTimeout(api.space.set_focus, 0);
|
||||
}
|
||||
|
||||
uc.refresh(1);
|
||||
api.event.emit('device.selected', dev);
|
||||
} catch (e) {
|
||||
console.log({error:e, device:code, devicename});
|
||||
api.show.alert(`invalid or deprecated device: "${devicename}"`, 10);
|
||||
api.show.alert(`please select a new device`, 10);
|
||||
throw e;
|
||||
showDevices();
|
||||
}
|
||||
api.function.clear();
|
||||
api.event.settings();
|
||||
}
|
||||
|
||||
function renderDevices(devices) {
|
||||
let selected = api.device.get() || devices[0],
|
||||
features = api.feature,
|
||||
devs = api.conf.get().devices,
|
||||
dfilter = typeof(features.device_filter) === 'function' ? features.device_filter : undefined;
|
||||
|
||||
for (let local in devs) {
|
||||
if (!(devs.hasOwnProperty(local) && devs[local])) {
|
||||
continue;
|
||||
}
|
||||
let dev = devs[local],
|
||||
fdmCode = dev.cmd,
|
||||
fdmMode = (api.mode.get() === 'FDM');
|
||||
if (dev.mode ? (dev.mode === api.mode.get()) : (fdmCode ? fdmMode : !fdmMode)) {
|
||||
devices.push(local);
|
||||
}
|
||||
};
|
||||
|
||||
devices = devices.sort();
|
||||
|
||||
let { event, ui } = api;
|
||||
|
||||
event.emit('devices.render', devices);
|
||||
|
||||
ui.deviceSave.onclick = function() {
|
||||
event.emit('device.save');
|
||||
api.function.clear();
|
||||
api.conf.save();
|
||||
api.settings.sync.put();
|
||||
showDevices();
|
||||
api.modal.hide();
|
||||
};
|
||||
ui.deviceAdd.onclick = function() {
|
||||
api.function.clear();
|
||||
cloneDevice();
|
||||
showDevices();
|
||||
};
|
||||
ui.deviceDelete.onclick = function() {
|
||||
api.function.clear();
|
||||
removeLocalDevice(getSelectedDevice());
|
||||
selectDevice(getModeDevices()[0]);
|
||||
showDevices();
|
||||
};
|
||||
ui.deviceRename.onclick = function() {
|
||||
api.uc.prompt(`Rename "${selected}`, selected).then(newname => {
|
||||
if (newname) {
|
||||
updateDeviceName(newname);
|
||||
api.conf.save();
|
||||
api.settings.sync.put();
|
||||
showDevices();
|
||||
} else {
|
||||
showDevices();
|
||||
}
|
||||
});
|
||||
};
|
||||
ui.deviceExport.onclick = function(event) {
|
||||
const record = {
|
||||
version: kiri.version,
|
||||
device: selected,
|
||||
process: api.process.code(),
|
||||
profiles: event.altKey ? api.settings.prof() : undefined,
|
||||
code: devs[selected],
|
||||
time: Date.now()
|
||||
};
|
||||
let exp = api.util.b64enc(record);
|
||||
api.device.export(exp, selected, { event, record });
|
||||
};
|
||||
|
||||
let dedup = {};
|
||||
let list_cdev = [];
|
||||
let list_mdev = [];
|
||||
devices.forEach(function(device, index) {
|
||||
// prevent device from appearing twice
|
||||
// such as local name = standard device name
|
||||
if (dedup[device]) {
|
||||
return;
|
||||
}
|
||||
dedup[device] = device;
|
||||
let loc = isLocalDevice(device);
|
||||
if (dfilter && dfilter(device) === false) {
|
||||
return;
|
||||
}
|
||||
if (loc) {
|
||||
list_mdev.push(h.option(device));
|
||||
} else {
|
||||
list_cdev.push(h.option(device));
|
||||
}
|
||||
});
|
||||
|
||||
let dev_list = $('dev-list');
|
||||
h.bind(dev_list, [
|
||||
h.option({ _: '-- My Devices --', disabled: true }),
|
||||
...list_mdev,
|
||||
h.option({ _: '-- Stock Devices --', disabled: true }),
|
||||
...list_cdev
|
||||
]);
|
||||
let dev_opts = [...dev_list.options].map(o => o.innerText);
|
||||
dev_list.selectedIndex = dev_opts.indexOf(selected);
|
||||
dev_list.onchange = ev => {
|
||||
const seldev = dev_list.options[dev_list.selectedIndex];
|
||||
selectDevice(seldev.innerText);
|
||||
api.platform.layout();
|
||||
}
|
||||
selectDevice(selected);
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
// dep: ext.md5
|
||||
// dep: geo.base
|
||||
// dep: data.local
|
||||
// dep: kiri.consts
|
||||
|
|
@ -109,36 +110,36 @@ function exportLaserDialog(data, names) {
|
|||
function download_svg() {
|
||||
api.util.download(
|
||||
driver.exportSVG(settings, data),
|
||||
$('print-filename').value + ".svg"
|
||||
$('print-filename-laser').value + ".svg"
|
||||
);
|
||||
}
|
||||
|
||||
function download_dxf() {
|
||||
api.util.download(
|
||||
driver.exportDXF(settings, data),
|
||||
$('print-filename').value + ".dxf"
|
||||
$('print-filename-laser').value + ".dxf"
|
||||
);
|
||||
}
|
||||
|
||||
function download_gcode() {
|
||||
api.util.download(
|
||||
driver.exportGCode(settings, data),
|
||||
$('print-filename').value + ".gcode"
|
||||
$('print-filename-laser').value + ".gcode"
|
||||
);
|
||||
}
|
||||
|
||||
// api.ajax("/kiri/output-laser.html", function(html) {
|
||||
api.modal.show('xlaser');
|
||||
let segments = 0;
|
||||
data.forEach(layer => { segments += layer.length });
|
||||
// ui.print.innerHTML = html;
|
||||
$('print-filename').value = filename;
|
||||
$('print-lines').value = util.comma(segments);
|
||||
$('print-svg').onclick = download_svg;
|
||||
$('print-dxf').onclick = download_dxf;
|
||||
$('print-lg').onclick = download_gcode;
|
||||
// api.modal.show('print');
|
||||
// });
|
||||
api.modal.show('xlaser');
|
||||
|
||||
let segments = 0;
|
||||
data.forEach(layer => { segments += layer.length });
|
||||
|
||||
$('print-filename-laser').value = filename;
|
||||
$('print-lines').value = util.comma(segments);
|
||||
$('print-svg').onclick = download_svg;
|
||||
$('print-dxf').onclick = download_dxf;
|
||||
$('print-lg').onclick = download_gcode;
|
||||
|
||||
console.log('laser export', { fileroot, filename });
|
||||
}
|
||||
|
||||
function bindField(field, varname) {
|
||||
|
|
@ -441,14 +442,15 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
function calcWeight() {
|
||||
try {
|
||||
let density = $('print-density');
|
||||
$('print-weight').value = (
|
||||
info.weight = (
|
||||
(Math.PI * util.sqr(
|
||||
info.settings.device.extruders[0].extFilament / 2
|
||||
)) *
|
||||
info.distance *
|
||||
(parseFloat(density.value) || 1.25) /
|
||||
1000
|
||||
).toFixed(2);
|
||||
).round(2);
|
||||
$('print-weight').value = info.weight.toFixed(2);
|
||||
density.onkeyup = (ev) => {
|
||||
if (ev.key === 'Enter') calcWeight();
|
||||
};
|
||||
|
|
@ -467,8 +469,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
}
|
||||
|
||||
api.modal.show('xany');
|
||||
// fetch("/kiri/output-gcode.html").then(r => r.text()).then(html => {
|
||||
// ui.print.innerHTML = html;
|
||||
let set = api.conf.get();
|
||||
let fdm = MODE === MODES.FDM;
|
||||
let octo = set.controller.exportOcto && MODE !== MODES.CAM;
|
||||
|
|
@ -478,8 +478,7 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
$('code-preview-head').style.display = preview ? '' : 'none';
|
||||
$('code-preview').style.display = preview ? '' : 'none';
|
||||
$('print-download').onclick = download;
|
||||
$('print-filament-head').style.display = fdm ? '' : 'none';
|
||||
$('print-filament-info').style.display = fdm ? '' : 'none';
|
||||
$('print-filament').style.display = fdm ? '' : 'none';
|
||||
$('print-filename').value = filename;
|
||||
$('print-filesize').value = util.comma(info.bytes);
|
||||
$('print-filament').value = Math.round(info.distance);
|
||||
|
|
@ -517,133 +516,176 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
})
|
||||
};
|
||||
|
||||
// in palette mode, show download button
|
||||
let downloadPalette = $('print-palette');
|
||||
downloadPalette.style.display = info.segments ? 'flex' : 'none';
|
||||
// generate MAFX downloadble file
|
||||
if (info.segments) {
|
||||
// todo: reduce segments to eliminate 0 lenghts and transitions before 150mm
|
||||
let { settings, segments } = info;
|
||||
let { device, bounds } = settings;
|
||||
let { min, max } = bounds;
|
||||
let extras = device.extras || {};
|
||||
let pinfo = extras.palette || {};
|
||||
// filter pings to those occuring after all tubes combined
|
||||
let pings = info.purges || [];
|
||||
let driveInfo = {};
|
||||
let volume = {};
|
||||
let length = {};
|
||||
// clean up and round pings
|
||||
pings.forEach(p => {
|
||||
p.length = p.length.round(3);
|
||||
// p.length = (p.length - pinfo.offset).round(2);
|
||||
// p.length = (p.length + pinfo.offset).round(2);
|
||||
p.extrusion = p.extrusion.round(3);
|
||||
});
|
||||
// add length of push filament to the last segment
|
||||
segments.peek().emitted += pinfo.push;
|
||||
let lastEmit = 0;
|
||||
let ratioVolume = (0.4 * 0.4) / (1.75 * 1.75);
|
||||
for (let seg of segments) {
|
||||
let seginfo = driveInfo[seg.tool] = driveInfo[seg.tool] || { length: 0, volume: 0 };
|
||||
seg.emitted += pinfo.offset;
|
||||
seginfo.length += seg.emitted - lastEmit;
|
||||
seginfo.volume = seginfo.length * ratioVolume;
|
||||
volume[seg.tool+1] = seginfo.volume.round(2);
|
||||
length[seg.tool+1] = seginfo.length.round(2);
|
||||
lastEmit = seg.emitted;
|
||||
}
|
||||
let totalLength = Object.values(length).reduce((a,v) => a+v).round(2);
|
||||
let totalVolume = Object.values(volume).reduce((a,v) => a+v).round(2);
|
||||
// console.log({info, device, pinfo, segments, volume, length, totalLength});
|
||||
let meta = {
|
||||
version: "3.2",
|
||||
printerProfile: {
|
||||
id: pinfo.printer,
|
||||
name: device.deviceName || "My Printer"
|
||||
},
|
||||
preheatTemperature: { nozzle: [0], bed: 0 },
|
||||
paletteNozzle: 0,
|
||||
time: info.time.round(1),
|
||||
volume,
|
||||
length,
|
||||
totalLength,
|
||||
totalVolume,
|
||||
inputsUsed: Object.keys(driveInfo).length,
|
||||
splices: segments.length,
|
||||
pings: pings.length,
|
||||
boundingBox: {
|
||||
min: [ min.x, min.y, min.z ],
|
||||
max: [ max.x, max.y, max.z ]
|
||||
},
|
||||
filaments: Object.keys(driveInfo).map(v => { return {
|
||||
name: `Color${v}`,
|
||||
type: "Filament",
|
||||
color: `#${v}0${v}0${v}0`,
|
||||
materialId: parseInt(v) + 1,
|
||||
filamentId: parseInt(v) + 1
|
||||
}}),
|
||||
};
|
||||
let lastDrive;
|
||||
let algokeys = {};
|
||||
let algorithms = [];
|
||||
let defaultSplice = {
|
||||
compression: pinfo.press,
|
||||
cooling: pinfo.cool,
|
||||
heat: pinfo.heat
|
||||
};
|
||||
for (let key of Object.keys(driveInfo)) {
|
||||
key = parseInt(key) + 1;
|
||||
algorithms.push({
|
||||
ingoingId: key,
|
||||
outgoingId: key,
|
||||
...defaultSplice
|
||||
});
|
||||
}
|
||||
let palette = {
|
||||
version: "3.0",
|
||||
drives: [0, 0, 0, 0, 0, 0, 0, 0].map((v,i) => {
|
||||
return driveInfo[i] ? i+1 : 0
|
||||
}),
|
||||
splices: segments.filter(r => {
|
||||
return r.emitted >= 150;
|
||||
}).map(r => {
|
||||
if (lastDrive >= 0 && lastDrive !== r.tool) {
|
||||
let key = `${lastDrive}+${r.tool}`;
|
||||
if (!algokeys[key]) {
|
||||
let rec = algokeys[key] = {
|
||||
ingoingId: lastDrive + 1,
|
||||
outgoingId: r.tool + 1,
|
||||
...defaultSplice
|
||||
};
|
||||
algorithms.push(rec);
|
||||
}
|
||||
}
|
||||
lastDrive = r.tool;
|
||||
return { id: r.tool + 1, length: r.emitted.round(2) }
|
||||
}),
|
||||
pings,
|
||||
algorithms
|
||||
};
|
||||
let png;
|
||||
kiri.client.png({}, data => {
|
||||
png = data.png;
|
||||
});
|
||||
console.log({meta,palette});
|
||||
downloadPalette.onclick = function() {
|
||||
kiri.client.zip([
|
||||
{name:"meta.json", data:JSON.stringify(meta,undefined,4)},
|
||||
{name:"palette.json", data:JSON.stringify(palette,undefined,4)},
|
||||
{name:"thumbnail.png", data:png.buffer}
|
||||
], progress => {
|
||||
api.show.progress(progress.percent/100, "generating palette files");
|
||||
}, output => {
|
||||
api.show.progress(0);
|
||||
api.util.download(output, `${$('print-filename').value}.mafx`);
|
||||
})
|
||||
};
|
||||
// in fdm mode, show 3mf file option
|
||||
let nozzle0 = set.device?.extruders?.[0]?.extNozzle || 0.4;
|
||||
let download3MF = $('print-3mf');
|
||||
download3MF.style.display = fdm ? 'flex' : 'none';
|
||||
download3MF.onclick = function() {
|
||||
gen3mf(zip => api.util.download(zip, `${$('print-filename').value}.3mf`));
|
||||
};
|
||||
|
||||
// present bambu print options when selected device is bambu
|
||||
if (api.bambu) {
|
||||
api.bambu.prep_export(gen3mf, gcode, info, settings);
|
||||
}
|
||||
|
||||
// let wids = api.widgets.all();
|
||||
// let bnds = settings.bounds;
|
||||
// console.log({ wids, bnds });
|
||||
|
||||
function gen3mf(then, ptype = 'unknown', ams = [0]) {
|
||||
let now = new Date();
|
||||
let ymd = [
|
||||
now.getFullYear(),
|
||||
(now.getMonth() + 1).toString().padStart(2,0),
|
||||
now.getDate().toString().padStart(2,0),
|
||||
].join('-');
|
||||
let files = [{
|
||||
name: `[Content_Types].xml`,
|
||||
data: [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">',
|
||||
' <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>',
|
||||
' <Default Extension="model" ContentType="application/vnd.ms-package.3dmanufacturing-3dmodel+xml"/>',
|
||||
' <Default Extension="gcode" ContentType="application/octet-stream"/>',
|
||||
'</Types>'
|
||||
].join('\n')
|
||||
},{
|
||||
name: `_rels/.rels`,
|
||||
data: [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">',
|
||||
' <Relationship Target="/3D/3dmodel.model" Id="rel-1" Type="http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel"/>',
|
||||
'</Relationships>'
|
||||
].join('\n')
|
||||
},{
|
||||
name: `3D/3dmodel.model`,
|
||||
data: [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<model unit="millimeter" xml:lang="en-US" xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02" xmlns:BambuStudio="http://schemas.bambulab.com/package/2021">',
|
||||
' <metadata name="Application">Kiri:Moto</metadata>',
|
||||
' <metadata name="Copyright"></metadata>',
|
||||
` <metadata name="CreationDate">${ymd}</metadata>`,
|
||||
' <metadata name="Description"></metadata>',
|
||||
' <metadata name="Designer"></metadata>',
|
||||
' <metadata name="DesignerCover"></metadata>',
|
||||
' <metadata name="License"></metadata>',
|
||||
` <metadata name="ModificationDate">${ymd}</metadata>`,
|
||||
' <metadata name="Origin"></metadata>',
|
||||
' <metadata name="Title"></metadata>',
|
||||
' <resources>',
|
||||
' </resources>',
|
||||
' <build/>',
|
||||
'</model>'
|
||||
].join('\n')
|
||||
},{
|
||||
name: `Metadata/_rels/model_settings.config.rels`,
|
||||
data: [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">',
|
||||
' <Relationship Target="/Metadata/plate_1.gcode" Id="rel-1" Type="http://schemas.microsoft.com/3dmanufacturing/2013/01/gcode"/>',
|
||||
'</Relationships>'
|
||||
].join('\n')
|
||||
// },{
|
||||
// name: `Metadata/plate_1.json`,
|
||||
// data: JSON.stringify({
|
||||
// "bbox_all": [ 100, 100, 200, 200 ],
|
||||
// "bbox_objects": (info.labels || []).map(label => {
|
||||
// return {
|
||||
// area: 600,
|
||||
// bbox: [ 100, 100, 200, 200 ],
|
||||
// id: label,
|
||||
// layer_height: 0.2,
|
||||
// name: "Object"
|
||||
// }
|
||||
// }),
|
||||
// "bed_type": "textured_plate",
|
||||
// "filament_colors": ["#FFFFFF"],
|
||||
// "filament_ids": ams,
|
||||
// "first_extruder": ams[0],
|
||||
// "is_seq_print": false,
|
||||
// "nozzle_diameter": 0.6,
|
||||
// "version": 2
|
||||
// })
|
||||
},{
|
||||
name: `Metadata/model_settings.config`,
|
||||
data: [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<config>',
|
||||
' <plate>',
|
||||
' <metadata key="plater_id" value="1"/>',
|
||||
' <metadata key="plater_name" value=""/>',
|
||||
' <metadata key="locked" value="false"/>',
|
||||
' <metadata key="gcode_file" value="Metadata/plate_1.gcode"/>',
|
||||
' <metadata key="thumbnail_file" value="Metadata/plate_1.png"/>',
|
||||
' <metadata key="thumbnail_no_light_file" value="Metadata/plate_no_light_1.png"/>',
|
||||
' <metadata key="top_file" value="Metadata/top_1.png"/>',
|
||||
' <metadata key="pick_file" value="Metadata/pick_1.png"/>',
|
||||
' </plate>',
|
||||
'</config>'
|
||||
].join('\n')
|
||||
},{
|
||||
name: `Metadata/slice_info.config`,
|
||||
data: [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<config>',
|
||||
' <header>',
|
||||
' <header_item key="X-BBL-Client-Type" value="slicer"/>',
|
||||
' <header_item key="X-BBL-Client-Version" value="01.10.01.50"/>',
|
||||
' </header>',
|
||||
' <plate>',
|
||||
' <metadata key="index" value="1"/>',
|
||||
// setting this value allows for the printer to error out if
|
||||
// the gcode / 3mf was intended for a different target type.
|
||||
// leaving it blank bypasses the check
|
||||
// ` <metadata key="printer_model_id" value="${ptype}"/>`,
|
||||
` <metadata key="nozzle_diameters" value="${nozzle0}"/>`,
|
||||
' <metadata key="timelapse_type" value="0"/>',
|
||||
` <metadata key="prediction" value="${Math.round(info.time)}"/>`,
|
||||
` <metadata key="weight" value="${info.weight}"/>`,
|
||||
' <metadata key="outside" value="false"/>',
|
||||
' <metadata key="support_used" value="false"/>',
|
||||
' <metadata key="label_object_enabled" value="false"/>',
|
||||
// (info.labels || []).map(label =>
|
||||
// ` <object identify_id="${label}" name="Object" skipped="false" />`),
|
||||
// ' <filament id="1" tray_info_idx="GFL96" type="PLA" color="#FFFFFF" used_m="0.17" used_g="0.50" />',
|
||||
// ' <warning msg="bed_temperature_too_high_than_filament" level="1" error_code ="1000C001" />',
|
||||
' </plate>',
|
||||
'</config>'
|
||||
].filter(v => v).flat().join('\n')
|
||||
},{
|
||||
name: `Metadata/project_settings.config`,
|
||||
data: JSON.stringify({},undefined,4)
|
||||
},{
|
||||
name: `Metadata/plate_1.gcode`,
|
||||
data: gcode
|
||||
},{
|
||||
name: `Metadata/plate_1.gcode.md5`,
|
||||
data: ext.md5.hash(gcode)
|
||||
},{
|
||||
name: `Metadata/plate_1_small.png`,
|
||||
data: api.view.bambu.s128.png
|
||||
},{
|
||||
name: `Metadata/plate_no_light_1.png`,
|
||||
data: api.view.bambu.s512.png
|
||||
},{
|
||||
name: `Metadata/plate_1.png`,
|
||||
data: api.view.bambu.s512.png
|
||||
},{
|
||||
name: `Metadata/pick_1.png`,
|
||||
data: api.view.bambu.s512.png
|
||||
},{
|
||||
name: `Metadata/top_1.png`,
|
||||
data: api.view.bambu.s512.png
|
||||
}];
|
||||
kiri.client.zip(files, progress => {
|
||||
api.show.progress(progress.percent/100, "generating 3mf");
|
||||
}, output => {
|
||||
api.show.progress(0);
|
||||
then(output);
|
||||
})
|
||||
};
|
||||
|
||||
// octoprint setup
|
||||
$('send-to-octohead').style.display = octo ? '' : 'none';
|
||||
$('send-to-octoprint').style.display = octo ? '' : 'none';
|
||||
|
|
@ -696,10 +738,6 @@ function exportGCodeDialog(gcode, sections, info, names) {
|
|||
|
||||
// preview of the generated GCODE (first 64k max)
|
||||
if (preview && gcode) $('code-preview-textarea').value = gcode.substring(0,65535);
|
||||
|
||||
// show dialog
|
||||
// api.modal.show('print');
|
||||
// });
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
// dep: kiri-mode.drag.driver
|
||||
// dep: kiri-mode.wjet.driver
|
||||
// dep: kiri-mode.wedm.driver
|
||||
gapp.register("kiri.function", [], (root, exports) => {
|
||||
gapp.register("kiri.function", (root, exports) => {
|
||||
|
||||
const { kiri } = root;
|
||||
const { api, client, consts, utils } = kiri;
|
||||
|
|
@ -31,7 +31,10 @@ function prepareSlices(callback, scale = 1, offset = 0) {
|
|||
// this can be used later by exports and rendered on some devices
|
||||
let snap = space.screenshot();
|
||||
view.snapshot = snap.substring(snap.indexOf(",") + 1);
|
||||
client.snap(space.screenshot2({width: 640}));
|
||||
client.snap(space.screenshot2({ width: 640 }));
|
||||
let bambu = view.bambu = { };
|
||||
space.screenshot3({ width: 512, out(png) { bambu.s512 = png } });
|
||||
space.screenshot3({ width: 128, out(png) { bambu.s128 = png } });
|
||||
}
|
||||
|
||||
if (mode.is_sla() && !callback) {
|
||||
|
|
@ -439,7 +442,7 @@ function parseCode(code, type) {
|
|||
}
|
||||
|
||||
// extend API (api.function)
|
||||
const functions = api.function = {
|
||||
const functions = Object.assign(api.function, {
|
||||
slice: prepareSlices,
|
||||
print: preparePreview,
|
||||
prepare: preparePreview,
|
||||
|
|
@ -449,6 +452,6 @@ const functions = api.function = {
|
|||
parse: parseCode,
|
||||
clear: client.clear,
|
||||
clear_progress() { complete = {} }
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
975
src/kiri/init.js
975
src/kiri/init.js
File diff suppressed because it is too large
Load diff
175
src/kiri/main.js
175
src/kiri/main.js
|
|
@ -15,6 +15,7 @@
|
|||
// dep: kiri.widget
|
||||
// dep: kiri.stats
|
||||
// dep: kiri.stacks
|
||||
// dep: kiri.devices
|
||||
// dep: kiri.function
|
||||
// dep: kiri.platform
|
||||
// dep: kiri.selection
|
||||
|
|
@ -23,19 +24,17 @@
|
|||
// use: kiri.files
|
||||
// use: kiri.frame
|
||||
// use: moto.ajax
|
||||
gapp.register("kiri.main", [], (root, exports) => {
|
||||
gapp.register("kiri.main", (root, exports) => {
|
||||
|
||||
const { base, data, kiri, moto, noop } = root;
|
||||
const { api, consts, lang, Widget, newWidget, utils, stats } = kiri;
|
||||
const { areEqual, parseOpt, encodeOpt, ajax, o2js, js2o, ls2o } = utils;
|
||||
const { feature, platform, selection, settings } = api;
|
||||
const { COLOR, MODES, PMODES, VIEWS } = consts;
|
||||
|
||||
const LANG = lang.current,
|
||||
let { data, kiri, moto, noop } = root,
|
||||
{ api, consts, lang, Widget, newWidget, utils, stats } = kiri,
|
||||
{ parseOpt, encodeOpt, o2js, js2o, ls2o } = utils,
|
||||
{ platform, selection, settings } = api,
|
||||
{ COLOR, MODES, VIEWS } = consts,
|
||||
LANG = lang.current,
|
||||
WIN = self.window,
|
||||
DOC = self.document,
|
||||
LOC = self.location,
|
||||
HOST = LOC.host.split(':'),
|
||||
SETUP = parseOpt(LOC.search.substring(1)),
|
||||
SECURE = isSecure(LOC.protocol),
|
||||
LOCAL = self.debug && !SETUP.remote,
|
||||
|
|
@ -43,93 +42,73 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
SDB = data.local,
|
||||
SPACE = kiri.space = moto.space,
|
||||
FILES = kiri.catalog = kiri.openFiles(new data.Index(SETUP.d ? SETUP.d[0] : 'kiri')),
|
||||
CONF = kiri.conf,
|
||||
clone = Object.clone;
|
||||
|
||||
let UI = {},
|
||||
clone = Object.clone,
|
||||
UI = {},
|
||||
UC = kiri.ui.prefix('kiri').inputAction(api.conf.update),
|
||||
MODE = MODES.FDM,
|
||||
STACKS = kiri.stacks,
|
||||
DRIVER = undefined,
|
||||
viewMode = VIEWS.ARRANGE,
|
||||
local = SETUP.local,
|
||||
autoSaveTimer = null,
|
||||
busy = 0,
|
||||
showFavorites = SDB.getItem('dev-favorites') === 'true',
|
||||
saveTimer = null,
|
||||
version = kiri.version = gapp.version;
|
||||
{ assign } = Object;
|
||||
|
||||
// add show() to catalog for API
|
||||
FILES.show = showCatalog;
|
||||
|
||||
// patch broker for api backward compatibility
|
||||
EVENT.on = (topic, listener) => {
|
||||
EVENT.subscribe(topic, listener);
|
||||
return EVENT;
|
||||
};
|
||||
|
||||
// augment api
|
||||
Object.assign(api, {
|
||||
ui: UI,
|
||||
uc: UC,
|
||||
// extend API
|
||||
assign(api, {
|
||||
ui: UI = assign(api.ui, UI),
|
||||
uc: UC = assign(api.uc, UC),
|
||||
stats,
|
||||
focus: noop,
|
||||
catalog: FILES,
|
||||
busy: {
|
||||
busy: assign(api.busy, {
|
||||
val() { return busy },
|
||||
inc() { kiri.api.event.emit("busy", ++busy) },
|
||||
dec() { kiri.api.event.emit("busy", --busy) }
|
||||
},
|
||||
}),
|
||||
color: COLOR,
|
||||
const: {
|
||||
const: assign(api.const, {
|
||||
LANG,
|
||||
LOCAL,
|
||||
SETUP,
|
||||
SECURE,
|
||||
STACKS,
|
||||
},
|
||||
device: {
|
||||
code: currentDeviceCode,
|
||||
get: currentDeviceName,
|
||||
set: noop, // set during init
|
||||
clone: noop // set during init
|
||||
},
|
||||
dialog: {
|
||||
}),
|
||||
dialog: assign(api.dialog, {
|
||||
show: showModal,
|
||||
hide: hideModal,
|
||||
update_process_list: updateProcessList
|
||||
},
|
||||
help: {
|
||||
}),
|
||||
help: assign(api.help, {
|
||||
show: showHelp,
|
||||
file: showHelpFile
|
||||
},
|
||||
event: {
|
||||
}),
|
||||
event: assign(api.event, {
|
||||
on(t,l) { return EVENT.on(t,l) },
|
||||
emit(t,m,o) { return EVENT.publish(t,m,o) },
|
||||
bind(t,m,o) { return EVENT.bind(t,m,o) },
|
||||
alerts(clr) { api.alerts.update(clr) },
|
||||
import: loadFile,
|
||||
settings: triggerSettingsEvent
|
||||
},
|
||||
group: {
|
||||
}),
|
||||
group: assign(api.group, {
|
||||
merge: groupMerge,
|
||||
split: groupSplit,
|
||||
},
|
||||
hide: {
|
||||
}),
|
||||
hide: assign(api.hide, {
|
||||
alert(rec, recs) { api.alerts.hide(...arguments) },
|
||||
import: noop,
|
||||
slider: hideSlider
|
||||
},
|
||||
image: {
|
||||
}),
|
||||
image: assign(api.image, {
|
||||
dialog: loadImageDialog,
|
||||
convert: loadImageConvert
|
||||
},
|
||||
}),
|
||||
language: kiri.lang,
|
||||
modal: {
|
||||
modal: assign(api.modal, {
|
||||
show: showModal,
|
||||
hide: hideModal,
|
||||
visible: modalShowing
|
||||
},
|
||||
mode: {
|
||||
}),
|
||||
mode: assign(api.mode, {
|
||||
get_id() { return MODE },
|
||||
get_lower: getModeLower,
|
||||
get: getMode,
|
||||
|
|
@ -149,29 +128,26 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
api.mode.is_wjet() ||
|
||||
api.mode.is_laser()
|
||||
}
|
||||
},
|
||||
probe: {
|
||||
}),
|
||||
probe: assign(api.probe, {
|
||||
live: "https://live.grid.space",
|
||||
grid: noop,
|
||||
local: noop
|
||||
},
|
||||
process: {
|
||||
}),
|
||||
process: assign(api.process, {
|
||||
code: currentProcessCode,
|
||||
get: currentProcessName
|
||||
},
|
||||
show: {
|
||||
}),
|
||||
show: assign(api.show, {
|
||||
alert() { return api.alerts.show(...arguments) },
|
||||
devices: noop, // set during init
|
||||
progress: setProgress,
|
||||
controls: setControlsVisible,
|
||||
favorites: getShowFavorites,
|
||||
slices: showSlices,
|
||||
layer: setVisibleLayer,
|
||||
local: showLocal,
|
||||
tools: noop, // set during init
|
||||
import: function() { UI.import.style.display = '' }
|
||||
},
|
||||
space: {
|
||||
}),
|
||||
space: assign(api.space, {
|
||||
reload,
|
||||
auto_save,
|
||||
restore: restoreWorkspace,
|
||||
|
|
@ -180,16 +156,16 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
set_focus: setFocus,
|
||||
update: SPACE.update,
|
||||
is_dark() { return settings.ctrl().dark }
|
||||
},
|
||||
util: {
|
||||
}),
|
||||
util: assign(api.util, {
|
||||
isSecure,
|
||||
download: downloadBlob,
|
||||
ui2rec() { api.conf.update_from(...arguments) },
|
||||
rec2ui() { api.conf.update_fields(...arguments) },
|
||||
b64enc(obj) { return base64js.fromByteArray(new TextEncoder().encode(JSON.stringify(obj))) },
|
||||
b64dec(obj) { return JSON.parse(new TextDecoder().decode(base64js.toByteArray(obj))) }
|
||||
},
|
||||
view: {
|
||||
}),
|
||||
view: assign(api.view, {
|
||||
get() { return viewMode },
|
||||
set() { setViewMode(...arguments) },
|
||||
set_arrange() { api.view.set(VIEWS.ARRANGE) },
|
||||
|
|
@ -209,10 +185,19 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
edges: setEdges,
|
||||
unit_scale: unitScale,
|
||||
wireframe: setWireframe,
|
||||
},
|
||||
}),
|
||||
work: kiri.client
|
||||
});
|
||||
|
||||
// add show() to catalog for API
|
||||
FILES.show = showCatalog;
|
||||
|
||||
// patch broker for api backward compatibility
|
||||
EVENT.on = (topic, listener) => {
|
||||
EVENT.subscribe(topic, listener);
|
||||
return EVENT;
|
||||
};
|
||||
|
||||
function updateStackLabelState() {
|
||||
const settings = api.conf.get();
|
||||
const { stacks } = kiri;
|
||||
|
|
@ -274,8 +259,8 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
if (!settings.ctrl().autoSave) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(saveTimer);
|
||||
saveTimer = setTimeout(() => {
|
||||
clearTimeout(autoSaveTimer);
|
||||
autoSaveTimer = setTimeout(() => {
|
||||
api.space.save(true);
|
||||
}, 1000);
|
||||
}
|
||||
|
|
@ -284,7 +269,7 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
let inits = parseInt(SDB.getItem('kiri-init') || stats.get('init') || 0) + 1;
|
||||
SDB.setItem('kiri-init', inits);
|
||||
stats.set('init', inits);
|
||||
stats.set('kiri', kiri.version);
|
||||
stats.set('kiri', kiri.version || gapp.version);
|
||||
|
||||
// remove version from url, preserve other settings
|
||||
WIN.history.replaceState({},'','/kiri/' + encodeOpt(SETUP) + LOC.hash);
|
||||
|
|
@ -297,15 +282,6 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
return api.mode.is_cam() && settings.ctrl().units === 'in' ? 25.4 : 1;
|
||||
}
|
||||
|
||||
function getShowFavorites(bool) {
|
||||
if (bool !== undefined) {
|
||||
SDB.setItem('dev-favorites', bool);
|
||||
showFavorites = bool;
|
||||
return bool;
|
||||
}
|
||||
return showFavorites;
|
||||
}
|
||||
|
||||
function triggerSettingsEvent() {
|
||||
api.event.emit('settings', settings.get());
|
||||
}
|
||||
|
|
@ -450,11 +426,6 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
api.var.layer_hi = layer;
|
||||
api.event.emit("slider.label");
|
||||
|
||||
let cam = api.mode.is_cam(),
|
||||
sla = api.mode.is_sla(),
|
||||
hi = cam ? api.var.layer_max - api.var.layer_lo : api.var.layer_hi,
|
||||
lo = cam ? api.var.layer_max - api.var.layer_hi : api.var.layer_lo;
|
||||
|
||||
updateSlider();
|
||||
STACKS.setRange(api.var.layer_lo, api.var.layer_hi);
|
||||
|
||||
|
|
@ -513,7 +484,7 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
}
|
||||
|
||||
function loadImage(image, opt = {}) {
|
||||
const info = Object.assign({settings: settings.get(), png:image}, opt);
|
||||
const info = assign({settings: settings.get(), png:image}, opt);
|
||||
kiri.client.image2mesh(info, progress => {
|
||||
api.show.progress(progress, "converting");
|
||||
}, vertices => {
|
||||
|
|
@ -670,8 +641,9 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
visible = modalShowing(),
|
||||
info = { pct: 0 };
|
||||
|
||||
["help","setup","tools","prefs","saves","files","xany","xlaser","xsla","local","any"].forEach(name => {
|
||||
UI[name].style.display = name === which ? 'flex' : '';
|
||||
// hide all modals befroe showing another
|
||||
Object.keys(UI.modals).forEach(name => {
|
||||
UI.modals[name].style.display = name === which ? 'flex' : '';
|
||||
});
|
||||
|
||||
function ondone() {
|
||||
|
|
@ -702,7 +674,10 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
easing(TWEEN.Easing.Quadratic.InOut).
|
||||
to({pct:0}, 100).
|
||||
onUpdate(() => { style.height = `${info.pct}%` }).
|
||||
onComplete(() => { style.display = '' }).
|
||||
onComplete(() => {
|
||||
style.display = '';
|
||||
api.event.emit('modal.hide');
|
||||
}).
|
||||
start();
|
||||
}
|
||||
|
||||
|
|
@ -868,7 +843,6 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
}
|
||||
|
||||
function setViewMode(mode) {
|
||||
const oldMode = viewMode;
|
||||
const isCAM = settings.mode() === 'CAM';
|
||||
viewMode = mode;
|
||||
platform.deselect();
|
||||
|
|
@ -955,7 +929,7 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
// restore cached device profile for this mode
|
||||
if (current.cdev[mode]) {
|
||||
current.device = clone(current.cdev[mode]);
|
||||
api.event.emit('device.select', currentDeviceName());
|
||||
api.event.emit('device.select', api.device.get());
|
||||
}
|
||||
// hide/show
|
||||
api.uc.setVisible($('set-tools'), mode === 'CAM');
|
||||
|
|
@ -981,14 +955,6 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
}
|
||||
}
|
||||
|
||||
function currentDeviceName() {
|
||||
return settings.get().filter[getMode()];
|
||||
}
|
||||
|
||||
function currentDeviceCode() {
|
||||
return settings.get().devices[currentDeviceName()];
|
||||
}
|
||||
|
||||
function currentProcessName() {
|
||||
return settings.get().cproc[getMode()];
|
||||
}
|
||||
|
|
@ -1012,9 +978,6 @@ gapp.register("kiri.main", [], (root, exports) => {
|
|||
// prevent safari from exiting full screen mode
|
||||
DOC.onkeydown = function (evt) { if (evt.keyCode == 27) evt.preventDefault() }
|
||||
|
||||
// complete module loading
|
||||
// kiri.load_exec();
|
||||
|
||||
// upon restore, seed presets
|
||||
api.event.emit('preset', api.conf.dbo());
|
||||
|
||||
|
|
|
|||
|
|
@ -921,7 +921,7 @@ function fitDeviceToWidgets() {
|
|||
}
|
||||
|
||||
// extend API (api.platform)
|
||||
const platform = api.platform = {
|
||||
const platform = Object.assign(api.platform, {
|
||||
fit: fitDeviceToWidgets,
|
||||
add: platformAdd,
|
||||
changed: platformChanged,
|
||||
|
|
@ -950,6 +950,6 @@ const platform = api.platform = {
|
|||
show_volume: space.platform.showVolume,
|
||||
top_z() { return topZ },
|
||||
clear() { api.space.clear(); api.space.save(true) }
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ class Print {
|
|||
this.nextType = type;
|
||||
}
|
||||
|
||||
// allows for gcode object id annotations enabling
|
||||
// discrete object cancellation during print (bambu)
|
||||
setWidget(widget) {
|
||||
this.widget = widget;
|
||||
}
|
||||
|
||||
addOutput(array, point, emit, speed, tool, type) {
|
||||
let { lastPoint, lastEmit, lastOut } = this;
|
||||
// drop duplicates (usually intruced by FDM bisections)
|
||||
|
|
@ -52,6 +58,7 @@ class Print {
|
|||
if (tool !== undefined) {
|
||||
this.tools[tool] = true;
|
||||
}
|
||||
lastOut.widget = this.widget;
|
||||
array.push(lastOut);
|
||||
this.nextType = undefined;
|
||||
return lastOut;
|
||||
|
|
@ -582,7 +589,7 @@ class Print {
|
|||
scope.belt = belt;
|
||||
|
||||
if (scope.debugE) {
|
||||
console.log({ print_time: time.round(2) });
|
||||
console.log({ bounds, print_time: time.round(2) });
|
||||
}
|
||||
|
||||
done({ output: scope.output });
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
// dep: kiri.api
|
||||
// dep: kiri.consts
|
||||
// dep: kiri.utils
|
||||
gapp.register("kiri.selection", [], (root, exports) => {
|
||||
gapp.register("kiri.selection", (root, exports) => {
|
||||
|
||||
const { kiri, moto, noop } = self;
|
||||
const { api, consts, utils } = kiri;
|
||||
|
|
@ -296,7 +296,7 @@ function setDisabled(bool) {
|
|||
}
|
||||
|
||||
// extend API (api.selection)
|
||||
const selection = api.selection = {
|
||||
const selection = Object.assign(api.selection, {
|
||||
move,
|
||||
merge,
|
||||
scale,
|
||||
|
|
@ -320,6 +320,6 @@ const selection = api.selection = {
|
|||
disable() { setDisabled(true) },
|
||||
opacity() { api.widgets.opacity(...arguments) },
|
||||
meshes() { return selectedMeshes.slice() },
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// dep: data.local
|
||||
// use: kiri.widgets
|
||||
// use: ext.base64
|
||||
gapp.register("kiri.settings", [], (root, exports) => {
|
||||
gapp.register("kiri.settings", (root, exports) => {
|
||||
|
||||
const { data, kiri, moto, noop } = self;
|
||||
const { api, conf, consts, utils } = kiri;
|
||||
|
|
@ -762,7 +762,7 @@ function setEnableWASM(bool) {
|
|||
}
|
||||
|
||||
// extend API (api.conf)
|
||||
api.conf = {
|
||||
Object.assign(api.conf, {
|
||||
dbo: () => { return ls2o('ws-settings') },
|
||||
get: getSettings,
|
||||
put: putSettings,
|
||||
|
|
@ -778,10 +778,10 @@ api.conf = {
|
|||
restore: restoreSettings,
|
||||
export: settingsExport,
|
||||
import: settingsImport,
|
||||
};
|
||||
});
|
||||
|
||||
// extend API (api.settings)
|
||||
api.settings = {
|
||||
Object.assign(api.settings, {
|
||||
get: getSettings,
|
||||
import: settingsImport,
|
||||
import_zip: settingsImportZip,
|
||||
|
|
@ -797,6 +797,6 @@ api.settings = {
|
|||
async put() {},
|
||||
status: false
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// dep: add.three
|
||||
// dep: kiri.api
|
||||
gapp.register("kiri.tools", [], (root, exports) => {
|
||||
gapp.register("kiri.tools", (root, exports) => {
|
||||
|
||||
const { Vector3, Quaternion } = THREE;
|
||||
const { kiri, moto } = root;
|
||||
|
|
|
|||
117
src/kiri/ui.js
117
src/kiri/ui.js
|
|
@ -10,6 +10,7 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
|
||||
let DOC = self.document,
|
||||
inputAction = null,
|
||||
lastAddTo = null,
|
||||
lastGroup = null,
|
||||
lastDiv = null,
|
||||
addTo = null,
|
||||
|
|
@ -46,11 +47,13 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
toFloat,
|
||||
isSticky,
|
||||
setSticky,
|
||||
newElement,
|
||||
newBoolean,
|
||||
newButton,
|
||||
newBlank,
|
||||
newDiv,
|
||||
newElement,
|
||||
newExpand,
|
||||
endExpand,
|
||||
newGCode,
|
||||
newGroup,
|
||||
newLabel,
|
||||
|
|
@ -58,8 +61,6 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
newRange,
|
||||
newRow,
|
||||
newSelect,
|
||||
newTable,
|
||||
newTableRow,
|
||||
newText,
|
||||
setGroup,
|
||||
addUnits,
|
||||
|
|
@ -68,6 +69,13 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
prompt,
|
||||
alert,
|
||||
onBlur,
|
||||
setEnabled(el, bool) {
|
||||
if (bool) {
|
||||
el.removeAttribute('disabled');
|
||||
} else {
|
||||
el.setAttribute('disabled','');
|
||||
}
|
||||
},
|
||||
setVisible(el, bool) {
|
||||
kiri.ui.setClass(el, 'hide', !bool);
|
||||
},
|
||||
|
|
@ -101,19 +109,26 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
}
|
||||
|
||||
function prompt(message, value) {
|
||||
return confirm(message, {ok:true, cancel:false}, value);
|
||||
return confirm(message, {ok:true, cancel:undefined}, value);
|
||||
}
|
||||
|
||||
function confirm(message, buttons, input, opt = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let { api } = kiri;
|
||||
let { feature } = api;
|
||||
let onkey_save = feature.on_key;
|
||||
feature.on_key = key => {
|
||||
// console.log({ eat_key: key });
|
||||
return true;
|
||||
};
|
||||
let dialog = $('dialog');
|
||||
let btns = buttons || {
|
||||
"yes": true,
|
||||
"no": false
|
||||
};
|
||||
let rnd = Date.now().toString(36);
|
||||
let any = $('mod-any');
|
||||
let html = [
|
||||
`<div class="confirm f-col a-stretch">`
|
||||
`<div class="confirm f-col a-stretch" style="padding:5px !important">`
|
||||
];
|
||||
if (message) {
|
||||
html.push(`<label style="user-select:text">${message}</label>`);
|
||||
|
|
@ -122,12 +137,12 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
html = opt.pre.appendAll(html);
|
||||
}
|
||||
let iid;
|
||||
if (typeof(input) === 'string') {
|
||||
iid = `confirm-input-${rnd}`;
|
||||
html.append(`<div><input class="grow" type="text" spellcheck="false" id="${iid}"/></div>`);
|
||||
} else if (Array.isArray(input)) {
|
||||
if (Array.isArray(input)) {
|
||||
iid = `confirm-input-${rnd}`;
|
||||
html.append(`<div><textarea rows="15" cols="40" class="grow" type="text" spellcheck="false" id="${iid}"></textarea></div>`);
|
||||
} else if (input !== undefined) {
|
||||
iid = `confirm-input-${rnd}`;
|
||||
html.append(`<div><input class="grow" type="text" spellcheck="false" id="${iid}"/></div>`);
|
||||
}
|
||||
html.append(`<div class="f-row j-end">`);
|
||||
Object.entries(btns).forEach((row,i) => {
|
||||
|
|
@ -137,10 +152,13 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
if (opt.post) {
|
||||
html.appendAll(opt.post);
|
||||
}
|
||||
$('mod-any').innerHTML = html.join('');
|
||||
dialog.innerHTML = html.join('');
|
||||
function done(value) {
|
||||
kiri.api.modal.hide();
|
||||
setTimeout(() => { resolve(value) }, 150);
|
||||
dialog.close();
|
||||
feature.on_key = onkey_save;
|
||||
if (value !== undefined) {
|
||||
setTimeout(() => { resolve(value) }, 150);
|
||||
}
|
||||
}
|
||||
if (iid) {
|
||||
let array = Array.isArray(input);
|
||||
|
|
@ -162,10 +180,11 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
}
|
||||
});
|
||||
setTimeout(() => {
|
||||
kiri.api.modal.show('any');
|
||||
dialog.showModal();
|
||||
if (iid) {
|
||||
iid.focus();
|
||||
iid.selectionStart = iid.value.length;
|
||||
iid.selectionStart = 0;
|
||||
iid.selectionEnd = iid.value.length;
|
||||
}
|
||||
}, 150);
|
||||
});
|
||||
|
|
@ -267,7 +286,7 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
row,
|
||||
arr,
|
||||
update() {
|
||||
if (hidden[group]) {
|
||||
if (!hidden[group]) {
|
||||
arr.innerHTML = '<i class="fa-solid fa-caret-down"></i>';
|
||||
row.classList.add('hidden');
|
||||
} else {
|
||||
|
|
@ -286,8 +305,8 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
return row;
|
||||
}
|
||||
|
||||
function addCollapsableElement(parent) {
|
||||
let row = newDiv();
|
||||
function addCollapsableElement(parent, options = {}) {
|
||||
let row = newDiv(options);
|
||||
if (parent) parent.appendChild(row);
|
||||
if (lastGroup) lastGroup.push(row);
|
||||
return row;
|
||||
|
|
@ -393,16 +412,42 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
}
|
||||
|
||||
function newDiv(opt = {}) {
|
||||
let div = DOC.createElement('div');
|
||||
let div = DOC.createElement(opt.tag || 'div');
|
||||
addModeControls(div, opt);
|
||||
(opt.addto || addTo).appendChild(div);
|
||||
if (opt.addto) lastDiv = addTo = div;
|
||||
if (opt.addto && opt.class) div.setAttribute('class', opt.class);
|
||||
if (opt.class) div.setAttribute('class', opt.class);
|
||||
lastGroup?.push(div);
|
||||
div._group = groupName;
|
||||
return div;
|
||||
}
|
||||
|
||||
function newExpand(label, opt = {}, opteach = {}) {
|
||||
let div = DOC.createElement('details');
|
||||
div.setAttribute('class', opt.class || 'f-col');
|
||||
addModeControls(div, opt);
|
||||
|
||||
let summary = DOC.createElement('summary');
|
||||
summary.setAttribute('class', opt.class || 'var-row');
|
||||
summary.innerHTML = `<label>${label}</label>`;
|
||||
|
||||
div.appendChild( summary );
|
||||
div.collapse = () => {
|
||||
div.removeAttribute('open');
|
||||
};
|
||||
|
||||
lastAddTo = addTo;
|
||||
addTo.appendChild(div);
|
||||
addTo = div;
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
function endExpand() {
|
||||
addTo = lastAddTo;
|
||||
return addTo;
|
||||
}
|
||||
|
||||
function isSticky() {
|
||||
return groupSticky;
|
||||
}
|
||||
|
|
@ -421,10 +466,11 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
txt.setAttribute("spellcheck", "false");
|
||||
txt.setAttribute("style", "resize: none");
|
||||
txt.onblur = bindTo || inputAction;
|
||||
txt.button = btn;
|
||||
|
||||
btn.setAttribute("class", "basis-50");
|
||||
btn.appendChild(DOC.createTextNode(label));
|
||||
|
||||
btn.setAttribute("title", opt.title || undefined);
|
||||
btn.onclick = function(ev) {
|
||||
ev.stopPropagation();
|
||||
if (ev.target === txt) {
|
||||
|
|
@ -442,9 +488,6 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
rows.forEach(row => {
|
||||
cols = Math.max(cols, row.length);
|
||||
});
|
||||
txt.setAttribute("cols", Math.max(30, cols + 1));
|
||||
txt.setAttribute("rows", 6);
|
||||
|
||||
let showing = btn === lastBtn;
|
||||
if (lastTxt) {
|
||||
lastTxt.classList.remove('txt-sel');
|
||||
|
|
@ -462,11 +505,8 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
addModeControls(btn, opt);
|
||||
if (opt.title) {
|
||||
btn.setAttribute("title", options.title);
|
||||
}
|
||||
txt.button = btn;
|
||||
|
||||
return txt;
|
||||
}
|
||||
|
|
@ -794,25 +834,4 @@ gapp.register("kiri.ui", [], (root, exports) => {
|
|||
return row;
|
||||
}
|
||||
|
||||
function newRowTable(array) {
|
||||
let div = newDiv();
|
||||
div.setAttribute("class", "table-row");
|
||||
array.forEach(function(c) {
|
||||
div.appendChild(c);
|
||||
});
|
||||
return div;
|
||||
}
|
||||
|
||||
function newTableRow(arrayOfArrays, options) {
|
||||
return newRow(newTable(arrayOfArrays), options);
|
||||
}
|
||||
|
||||
function newTable(arrayOfArrays) {
|
||||
let array = [];
|
||||
for (let i=0; i<arrayOfArrays.length; i++) {
|
||||
array.push(newRowTable(arrayOfArrays[i]));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// use: load.file
|
||||
// use: kiri.selection
|
||||
// use: kiri.platform
|
||||
gapp.register("kiri.widgets", [], (root, exports) => {
|
||||
gapp.register("kiri.widgets", (root, exports) => {
|
||||
|
||||
const { data, kiri, moto, noop } = root;
|
||||
const { api, consts, utils, newWidget, Widget } = kiri;
|
||||
|
|
@ -93,7 +93,7 @@ function opacity(value) {
|
|||
}
|
||||
|
||||
// extend API (api.widgets)
|
||||
const widgets = api.widgets = {
|
||||
const widgets = Object.assign(api.widgets, {
|
||||
load: Widget.loadFromCatalog,
|
||||
new: newWidget,
|
||||
map,
|
||||
|
|
@ -110,6 +110,6 @@ const widgets = api.widgets = {
|
|||
each(fn) { WIDGETS.slice().forEach(widget => fn(widget)) },
|
||||
for(fn) { widgets.each(fn) },
|
||||
forid(id) { return WIDGETS.filter(w => w.id === id)[0] }
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ function transform(def, mesh) {
|
|||
return pos.array;
|
||||
}
|
||||
|
||||
/** find matching attribute regardless of namespace */
|
||||
function getLocalAttribute(node, name) {
|
||||
for (let attr of node.attributes) {
|
||||
if (attr.localName === name) {
|
||||
return attr.value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function loadModel(doc) {
|
||||
let items = [];
|
||||
let objects = {};
|
||||
|
|
@ -118,13 +128,16 @@ function loadModel(doc) {
|
|||
query(node, ["components","+component"], (type, node) => {
|
||||
object.components.push({
|
||||
oid: node.getAttribute('objectid'),
|
||||
xform: node.getAttribute('transform')
|
||||
path: getLocalAttribute(node, "path"),
|
||||
xform: node.getAttribute('transform'),
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return resolve({ objects, items });
|
||||
|
||||
// create object mesh from components
|
||||
for (let object of Object.values(objects)) {
|
||||
let { mesh, components } = object;
|
||||
|
|
@ -135,7 +148,9 @@ function loadModel(doc) {
|
|||
for (let component of components) {
|
||||
let { oid, xform } = component;
|
||||
let ref = objects[oid];
|
||||
if (xform) {
|
||||
if (!ref) {
|
||||
console.log({ missing_ref: oid, objects, components, doc });
|
||||
} else if (xform) {
|
||||
mesh.appendAll(transform(xform, ref.mesh));
|
||||
} else {
|
||||
mesh.appendAll(ref.mesh);
|
||||
|
|
@ -160,21 +175,73 @@ function loadModel(doc) {
|
|||
});
|
||||
}
|
||||
|
||||
function extractItems(records) {
|
||||
let outItems = [];
|
||||
let models = Object.values(records);
|
||||
|
||||
// create object mesh from components
|
||||
for (let model of models) {
|
||||
let { objects } = model;
|
||||
for (let object of Object.values(objects)) {
|
||||
let { mesh, components } = object;
|
||||
if (mesh) {
|
||||
continue;
|
||||
}
|
||||
mesh = object.mesh = [];
|
||||
for (let component of components) {
|
||||
let { oid, path, xform } = component;
|
||||
let omap = objects;
|
||||
if (path) {
|
||||
omap = records[path.substring(1)].objects;
|
||||
// console.log({ component_from_ob_path: path, using: omap });
|
||||
}
|
||||
let ref = omap[oid];
|
||||
if (!ref) {
|
||||
console.log({ missing_ref: oid, objects, components });
|
||||
} else if (xform) {
|
||||
mesh.appendAll(transform(xform, ref.mesh));
|
||||
} else {
|
||||
mesh.appendAll(ref.mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create export items from object references
|
||||
for (let model of models) {
|
||||
let { items, objects } = model;
|
||||
for (let item of items || []) {
|
||||
let { oid, xform } = item;
|
||||
let { name, mesh } = objects[oid];
|
||||
item.name = name;
|
||||
if (xform) {
|
||||
item.faces = transform(xform, mesh);
|
||||
} else {
|
||||
item.faces = mesh;
|
||||
}
|
||||
}
|
||||
outItems.push(...items);
|
||||
}
|
||||
|
||||
return outItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} data binary file
|
||||
* @returns {Array} vertex face array
|
||||
*/
|
||||
function parseAsync(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
JSZip.loadAsync(data).then(zip => {
|
||||
for (let [key,value] of Object.entries(zip.files)) {
|
||||
if (key.indexOf(".model") > 0) {
|
||||
value.async("string").then(xml => {
|
||||
resolve(loadModel(new DOMParser().parseFromString(xml, "text/xml")));
|
||||
});
|
||||
}
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let zip = await JSZip.loadAsync(data);
|
||||
let models = {};
|
||||
for (let [key, value] of Object.entries(zip.files)) {
|
||||
if (key.endsWith(".model")) {
|
||||
let xml = await value.async("string");
|
||||
let { objects, items } = await loadModel(new DOMParser().parseFromString(xml, "text/xml"));
|
||||
models[key] = { objects, items };
|
||||
}
|
||||
});
|
||||
}
|
||||
resolve(extractItems(models));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
108
src/load/svg.js
108
src/load/svg.js
|
|
@ -22,11 +22,11 @@ function parse(text, opt = { }) {
|
|||
const rez = (opt.resolution || 1);
|
||||
const dpi = (opt.dpi || 0);
|
||||
const segmin = Math.max(1, opt.segmin || 10);
|
||||
const objs = [];
|
||||
const data = new THREE.SVGLoader().parse(text);
|
||||
const paths = data.paths;
|
||||
const xmlat = data.xml.attributes;
|
||||
const polys = fromSoup ? [] : undefined;
|
||||
const objs = [];
|
||||
const polys = [];
|
||||
const isinch = xmlat.width?.value.endsWith('in');
|
||||
const scale = isinch ? 25.4 : (dpi ? 1 / (dpi / 25.4) : 1);
|
||||
const depth = parseFloat(opt.depth || xmlat['data-km-extrude']?.value
|
||||
|
|
@ -39,76 +39,50 @@ function parse(text, opt = { }) {
|
|||
let type = path.userData?.node?.nodeName;
|
||||
let width = path.userData?.style?.strokeWidth;
|
||||
let miter = path.userData?.style?.strokeMiterLimit;
|
||||
if (fromSoup) {
|
||||
for (let sub of path.subPaths) {
|
||||
let points = sub.curves.map(curve => {
|
||||
let length = curve.getLength();
|
||||
let segs = curve.type === 'LineCurve' ?
|
||||
1 : Math.max(Math.ceil(length * rez), segmin);
|
||||
return curve.getPoints(segs);
|
||||
}).flat();
|
||||
if (points.length < 3) {
|
||||
// console.log({ sub, length, points });
|
||||
continue;
|
||||
}
|
||||
let poly = base.newPolygon().addPoints(points.map(p => base.newPoint(p.x, -p.y, 0)));
|
||||
if (poly.appearsClosed()) poly.points.pop();
|
||||
if (type === 'polyline') poly.setOpen(true);
|
||||
poly._svg = { width, miter };
|
||||
polys.push(poly);
|
||||
if (scale !== 1) {
|
||||
poly.scale({ x: scale, y: scale, z: 1 });
|
||||
}
|
||||
for (let sub of path.subPaths) {
|
||||
let points = sub.curves.map(curve => {
|
||||
let length = curve.getLength();
|
||||
let segs = curve.type === 'LineCurve' ?
|
||||
1 : Math.max(Math.ceil(length * rez), segmin);
|
||||
return curve.getPoints(segs);
|
||||
}).flat();
|
||||
if (points.length < 3) {
|
||||
// console.log({ sub, length, points });
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (justPoly) {
|
||||
continue;
|
||||
}
|
||||
let geom = new THREE.ExtrudeGeometry(shapes, {
|
||||
depth,
|
||||
steps: 1,
|
||||
bevelEnabled: false
|
||||
});
|
||||
let array = geom.attributes.position.array;
|
||||
// invert y
|
||||
for (let i=1; i<array.length; i+=3) {
|
||||
array[i] = -array[i];
|
||||
}
|
||||
// invert vertex order to compensate for inverted y
|
||||
for (let i=0; i<array.length; i+=9) {
|
||||
let tmp = array.slice(i,i+3);
|
||||
for (let j=0; j<3; j++) {
|
||||
array[i+j] = array[i+j+3];
|
||||
array[i+j+3] = tmp[j];
|
||||
let poly = base.newPolygon().addPoints(points.map(p => base.newPoint(p.x, -p.y, 0)));
|
||||
if (poly.appearsClosed()) poly.points.pop();
|
||||
if (type === 'polyline') poly.setOpen(true);
|
||||
poly._svg = { width, miter };
|
||||
polys.push(poly);
|
||||
if (scale !== 1) {
|
||||
poly.scale({ x: scale, y: scale, z: 1 });
|
||||
}
|
||||
}
|
||||
objs.push([ ...array ]);
|
||||
}
|
||||
|
||||
if (fromSoup) {
|
||||
const nest = base.polygons.nest(polys.filter(p => {
|
||||
// filter duplicates
|
||||
for (let pc of polys) {
|
||||
if (pc === p) {
|
||||
return true;
|
||||
} else {
|
||||
return !pc.isEquivalent(p);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
if (justPoly) {
|
||||
return nest;
|
||||
}
|
||||
|
||||
for (let poly of nest) {
|
||||
let obj = poly.extrude(depth);
|
||||
objs.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return justPoly ? polys : objs;
|
||||
const sub = fromSoup ? base.polygons.nest(polys) : polys;
|
||||
const nest = sub.filter(p => {
|
||||
// filter duplicates
|
||||
for (let pc of polys) {
|
||||
if (pc === p) {
|
||||
return true;
|
||||
} else {
|
||||
return !pc.isEquivalent(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (justPoly) {
|
||||
return nest;
|
||||
}
|
||||
|
||||
for (let poly of nest) {
|
||||
let obj = poly.extrude(depth);
|
||||
objs.push(obj);
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ let mods = [];
|
|||
|
||||
gapp.overlay = Object.assign;
|
||||
|
||||
// extract function arguments grouped by type
|
||||
function exargs(args) {
|
||||
return {
|
||||
funcs: args.filter(a => typeof a === 'function'),
|
||||
|
|
@ -70,34 +71,38 @@ function exargs(args) {
|
|||
};
|
||||
}
|
||||
|
||||
// register module without a load function
|
||||
gapp.register = function() {
|
||||
// console.log(1, { mods });
|
||||
const args = exargs([...arguments]);
|
||||
const name = args.strings[0];
|
||||
const fn = args.funcs[0];
|
||||
const mod = { fn, name };
|
||||
// console.log(2, { mods });
|
||||
// console.log('reg', { mod, mods });
|
||||
mods.push(mod);
|
||||
};
|
||||
|
||||
// prevent module load from terminating main/init chain
|
||||
function safeFN(fn, name) {
|
||||
return function() {
|
||||
try {
|
||||
return fn(...arguments);
|
||||
} catch (error) {
|
||||
console.log({ register_fail: name, error });
|
||||
if (error.stack) {
|
||||
console.log(`[${name}]`, error.stack);
|
||||
} else {
|
||||
console.log({ register_fail: name, error });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// register module without a load function
|
||||
gapp.register = function() {
|
||||
const args = exargs([...arguments]);
|
||||
const objs = args.objects || {};
|
||||
const name = objs.name || objs.module || args.strings[0];
|
||||
const fn = objs.exec || args.funcs[0];
|
||||
const mod = { fn, name };
|
||||
mods.push(mod);
|
||||
};
|
||||
|
||||
// perform dependency checks and run module load functions
|
||||
gapp.main = function() {
|
||||
const args = exargs([...arguments]);
|
||||
const app = args.strings[0];
|
||||
const post = args.funcs[0];
|
||||
const pre = args.funcs[1];
|
||||
const objs = args.objects[0] || {};
|
||||
const app = objs.app || args.strings[0];
|
||||
const post = objs.post || args.funcs[0];
|
||||
const pre = objs.pre || args.funcs[1];
|
||||
const root = self;
|
||||
// optional fn to run before loading
|
||||
if (pre) {
|
||||
|
|
@ -129,6 +134,7 @@ gapp.main = function() {
|
|||
}
|
||||
let tmp = path[map] || {};
|
||||
safeFN(fn, name)(root, exports => {
|
||||
// map exports into module namespace when called
|
||||
if (exports) {
|
||||
return path[map] = Object.assign(tmp, exports);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,37 +2,40 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
gapp.main("main.kiri", [], (root) => {
|
||||
gapp.main({
|
||||
app: "kiri",
|
||||
|
||||
const { kiri } = root;
|
||||
const { api } = kiri;
|
||||
pre(root) {
|
||||
let mods = root.kirimod = ( root.kirimod || [] );
|
||||
|
||||
// complete module loading
|
||||
kiri.load_exec();
|
||||
|
||||
}, (root) => {
|
||||
|
||||
const modfns = root.kirimod = ( root.kirimod || [] );
|
||||
|
||||
const kiri = root.kiri = {
|
||||
beta: 0,
|
||||
driver: {}, // driver modules
|
||||
load(fn) {
|
||||
modfns.push(fn);
|
||||
},
|
||||
load_exec(api) {
|
||||
const saferun = (fn) => {
|
||||
try {
|
||||
fn(api || kiri.api);
|
||||
} catch (error) {
|
||||
console.log({ module_error: error });
|
||||
}
|
||||
};
|
||||
// complete module loading
|
||||
modfns.forEach(modfn => saferun(modfn));
|
||||
// rewrite load() to be immediate post-finalize
|
||||
kiri.load = (modfn) => saferun(modfn);
|
||||
}
|
||||
};
|
||||
let kiri = root.kiri = {
|
||||
beta: 4113,
|
||||
driver: {
|
||||
// attached driver modules
|
||||
},
|
||||
load(fn) {
|
||||
// modules register exec() functions
|
||||
mods.push(fn);
|
||||
},
|
||||
load_exec(api) {
|
||||
// process all module exec() functions
|
||||
const saferun = (fn) => {
|
||||
try {
|
||||
fn(api || kiri.api);
|
||||
} catch (error) {
|
||||
console.log({ module_error: error });
|
||||
}
|
||||
};
|
||||
// complete module loading
|
||||
mods.forEach(fn => saferun(fn));
|
||||
// rewrite load() to run immediately post-finalize
|
||||
kiri.load = (fn) => saferun(fn);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
post(root) {
|
||||
// complete module loading
|
||||
root.kiri.load_exec();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -280,6 +280,11 @@ function space_init(data) {
|
|||
},
|
||||
'keydown', evt => {
|
||||
let { shiftKey, metaKey, ctrlKey, code } = evt;
|
||||
let once = keyOnce[code];
|
||||
if (once) {
|
||||
delete keyOnce[code];
|
||||
return once(evt);
|
||||
}
|
||||
let rv = (Math.PI / 12);
|
||||
if (api.modal.showing) {
|
||||
if (code === 'Escape') {
|
||||
|
|
@ -598,6 +603,16 @@ function space_load(data) {
|
|||
}
|
||||
|
||||
let metaCache = {};
|
||||
let keyOnce = {};
|
||||
|
||||
function key_once(data) {
|
||||
const { code, fn } = data;
|
||||
keyOnce[code] = fn;
|
||||
}
|
||||
|
||||
function key_once_cancel(code) {
|
||||
delete keyOnce[code];
|
||||
}
|
||||
|
||||
function store_meta() {
|
||||
mesh.db.admin.put("meta", metaCache);
|
||||
|
|
@ -711,6 +726,8 @@ function set_snap_value(snap) {
|
|||
|
||||
// bind functions to topics
|
||||
broker.listeners({
|
||||
key_once,
|
||||
key_once_cancel,
|
||||
load_files,
|
||||
object_meta,
|
||||
object_destroy,
|
||||
|
|
|
|||
|
|
@ -9,15 +9,19 @@
|
|||
"use strict";
|
||||
|
||||
// dep: moto.space
|
||||
// dep: moto.broker
|
||||
gapp.register("mesh.split", [], (root, exports) => {
|
||||
|
||||
const { broker } = gapp;
|
||||
const { Mesh, MeshPhongMaterial, PlaneGeometry, DoubleSide, Vector3 } = THREE;
|
||||
const { mesh, moto } = root;
|
||||
const { space } = moto;
|
||||
const { api } = mesh;
|
||||
|
||||
let isActive;
|
||||
|
||||
const key_once = broker.bind('key_once');
|
||||
const key_cancel = broker.bind('key_once_cancel');
|
||||
|
||||
// split functions
|
||||
let split = {
|
||||
active() {
|
||||
|
|
@ -29,6 +33,11 @@ let split = {
|
|||
return;
|
||||
}
|
||||
let { api, util } = mesh;
|
||||
let { log } = api;
|
||||
if (api.selection.models().length === 0) {
|
||||
log.emit('no models selected for splitting');
|
||||
return;
|
||||
}
|
||||
// create split plane visual
|
||||
let geo, mat, obj = new Mesh(
|
||||
geo = new PlaneGeometry(1,1),
|
||||
|
|
@ -72,11 +81,36 @@ let split = {
|
|||
obj.position.set(mid.x, y, -mid.y);
|
||||
});
|
||||
isActive = true;
|
||||
key_once({ code: 'KeyS', fn(evt) {
|
||||
split.select();
|
||||
}});
|
||||
key_once({ code: 'KeyV', fn(evt) {
|
||||
evt.preventDefault();
|
||||
let state = split.state;
|
||||
split.end();
|
||||
function doit(z) {
|
||||
state.plane = { z };
|
||||
split.select(state);
|
||||
}
|
||||
api.modal.dialog({
|
||||
title: "split object Z",
|
||||
body: [ h.div({ class: "additem" }, [
|
||||
h.label('Z value'),
|
||||
h.input({ value: 0, size: 5, id: "_value" }),
|
||||
h.button({ _: "split", onclick() {
|
||||
const { _value } = api.modal.bound;
|
||||
doit(parseFloat(_value.value));
|
||||
api.modal.hide();
|
||||
} })
|
||||
]) ]
|
||||
});
|
||||
api.modal.bound._value.focus();
|
||||
} });
|
||||
},
|
||||
|
||||
select() {
|
||||
select(state) {
|
||||
let { log } = mesh.api;
|
||||
let { models, plane } = split.state;
|
||||
let { models, plane } = split.state || state;
|
||||
if (!(models && plane)) {
|
||||
return split.end();
|
||||
}
|
||||
|
|
@ -92,6 +126,8 @@ let split = {
|
|||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
key_cancel('KeyS');
|
||||
key_cancel('KeyV');
|
||||
let space = moto.space;
|
||||
let { obj } = split.state;
|
||||
space.scene.remove(obj);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
let terms = {
|
||||
COPYRIGHT: "Copyright (C) Stewart Allen <sa@grid.space> - All Rights Reserved",
|
||||
LICENSE: "See the license.md file included with the source distribution",
|
||||
VERSION: (is_self ? self : this).debug_version || "4.0.31"
|
||||
VERSION: (is_self ? self : this).debug_version || "4.1.0"
|
||||
};
|
||||
|
||||
if (typeof(module) === 'object') {
|
||||
|
|
|
|||
|
|
@ -1308,10 +1308,39 @@ gapp.register("moto.space", [], (root, exports) => {
|
|||
return {
|
||||
url: ncv.toDataURL(param.format || "image/png", param.options),
|
||||
width: ncv.width,
|
||||
height: ncv.height
|
||||
height: ncv.height,
|
||||
};
|
||||
},
|
||||
|
||||
screenshot3(param = {}) {
|
||||
let oco = renderer.domElement;
|
||||
let oWidth = oco.offsetWidth;
|
||||
let oHeight = oco.offsetHeight;
|
||||
let oRatio = oWidth / oHeight;
|
||||
let width = param.width || 512;
|
||||
let height = param.height || width;
|
||||
let nRatio = width / height;
|
||||
let ncv = document.createElement('canvas');
|
||||
ncv.width = width;
|
||||
ncv.height = height;
|
||||
let nco = ncv.getContext('2d');
|
||||
let ox = 0, oy = 0;
|
||||
if (oRatio > nRatio) {
|
||||
let tmp = oWidth;
|
||||
oWidth = oHeight * nRatio;
|
||||
ox = (tmp - oWidth) / 2;
|
||||
} else {
|
||||
let tmp = oHeight;
|
||||
oHeight = oWidth * nRatio;
|
||||
oy = (tmp - oHeight) / 2;
|
||||
}
|
||||
nco.drawImage(oco, ox, oy, oWidth, oHeight, 0, 0, width, height);
|
||||
if (param.out) {
|
||||
ncv.toBlob(blob => blob.arrayBuffer().then(png => param.out({ png, width, height })));
|
||||
}
|
||||
return ncv;
|
||||
},
|
||||
|
||||
internals: () => {
|
||||
return { renderer, camera, platform };
|
||||
},
|
||||
|
|
|
|||
|
|
@ -33,9 +33,14 @@ function build(data, context) {
|
|||
html.push(`<${type}`);
|
||||
let func = {};
|
||||
for (let [key, val] of Object.entries(attr || {})) {
|
||||
if (val === undefined) {
|
||||
continue;
|
||||
}
|
||||
let tov = typeof val;
|
||||
if (key === '_') {
|
||||
text = val;
|
||||
} else if (key.startsWith('_')) {
|
||||
if (val) html.push(` ${key.substring(1)}`);
|
||||
} else if (key === 'id') {
|
||||
elid = val ? (tov === 'object' ? val.join('_') : val) : undefined;
|
||||
} else if (tov === 'function') {
|
||||
|
|
@ -76,7 +81,12 @@ let h = exports({
|
|||
bind: (el, data, opt = {}) => {
|
||||
let ctx = [];
|
||||
let html = build(data, ctx).join('');
|
||||
if (opt.append) {
|
||||
if (opt.after || opt.before) {
|
||||
let tmpl = document.createElement('template');
|
||||
tmpl.innerHTML = html;
|
||||
opt.before && el.before(tmpl.content);
|
||||
opt.after && el.after(tmpl.content);
|
||||
} else if (opt.append) {
|
||||
el.innerHTML += html;
|
||||
} else {
|
||||
el.innerHTML = html;
|
||||
|
|
@ -149,7 +159,7 @@ gapp.overlay(root, {
|
|||
// add common element types
|
||||
[
|
||||
"a", "i", "hr", "div", "pre", "code", "span", "label", "input",
|
||||
"button", "svg", "textarea", "select", "option"
|
||||
"button", "svg", "textarea", "select", "option", "img", "canvas"
|
||||
].forEach(type => {
|
||||
h[type] = (attr, innr) => {
|
||||
return h.el(type, attr, innr);
|
||||
|
|
|
|||
Loading…
Reference in a new issue