implement svg trace path loading
This commit is contained in:
parent
ecef9c4479
commit
6ec01bbdbc
5 changed files with 150 additions and 79 deletions
|
|
@ -1034,7 +1034,11 @@ function newButton(label, action, opt = {}) {
|
|||
*/
|
||||
function newRow(children, options) {
|
||||
let row = addCollapsableElement((options && options.noadd) ? null : addTo);
|
||||
if (children) children.forEach(function (c) { row.appendChild(c) });
|
||||
if (children) {
|
||||
children.forEach((c) => {
|
||||
row.appendChild(c);
|
||||
});
|
||||
};
|
||||
addModeControls(row, options);
|
||||
if (options && options.class) {
|
||||
options.class.split(' ').forEach(ce => {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { opFlip } from './cl-flip.js';
|
|||
import { selectHoles } from './cl-hole.js';
|
||||
import { selectHelical } from './cl-helical.js';
|
||||
import { surfaceAdd } from './cl-surface.js';
|
||||
import { traceAdd } from './cl-trace.js';
|
||||
import { traceAdd, traceClear, traceLoad } from './cl-trace.js';
|
||||
import { startFaceUp } from '../../app/face-tool.js';
|
||||
import { showZBottom, showZTop, updateStock } from './cl-stock.js';
|
||||
|
||||
|
|
@ -137,14 +137,21 @@ export function createPopOp(type, map) {
|
|||
return rec;
|
||||
},
|
||||
hideshow: () => {
|
||||
let conf = api.conf.get();
|
||||
for (let inp of Object.values(op.inputs)) {
|
||||
let parent = inp.parentElement;
|
||||
if (parent && parent.setVisible && parent.__opt.show) {
|
||||
// for normal inputs
|
||||
parent.setVisible(parent.__opt.show(op, api.conf.get()));
|
||||
parent.setVisible(parent.__opt.show(op, conf));
|
||||
} else if (inp.__opt?.show) {
|
||||
// for blanks
|
||||
inp.setVisible(inp.__opt.show(op, api.conf.get()));
|
||||
inp.setVisible(inp.__opt.show(op, conf));
|
||||
} else if (inp.children) {
|
||||
for (let c of inp.children) {
|
||||
if (c.__opt?.show) {
|
||||
c.setVisible(c.__opt.show(op, conf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -322,10 +329,6 @@ export function createPopOps() {
|
|||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0) }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }),
|
||||
leave: UC.newInput(LANG.cr_lsto_s, { title: LANG.cr_lsto_l, convert: toFloat, units }),
|
||||
|
|
@ -336,7 +339,12 @@ export function createPopOps() {
|
|||
inside: UC.newBoolean(LANG.cr_olin_s, undefined, { title: LANG.cr_olin_l, show: () => !env.poppedRec.all || env.poppedRec.inside }),
|
||||
omitthru: UC.newBoolean(LANG.co_omit_s, undefined, { title: LANG.co_omit_l }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
exp: UC.newExpand("overrides", ov_hover),
|
||||
exp: UC.newExpand("feeds & speeds", { }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
exp_end: UC.endExpand(),
|
||||
exp: UC.newExpand("top & bottom", ov_hover),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz),
|
||||
exp_end: UC.endExpand(),
|
||||
|
|
@ -364,9 +372,6 @@ export function createPopOps() {
|
|||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0), show: () => env.popOp.outline.rec.wide }),
|
||||
steps: UC.newInput(LANG.cc_sovc_s, { title: LANG.cc_sovc_l, convert: toInt, bound: UC.bound(1, 500), show: () => env.popOp.outline.rec.wide }),
|
||||
|
|
@ -380,7 +385,12 @@ export function createPopOps() {
|
|||
dogbones: UC.newBoolean(LANG.co_dogb_s, undefined, { title: LANG.co_dogb_l, show: (op) => { return !op.inputs.wide.checked } }),
|
||||
revbones: UC.newBoolean(LANG.co_dogr_s, undefined, { title: LANG.co_dogr_l, show: () => env.poppedRec.dogbones }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
exp: UC.newExpand("overrides", ov_hover),
|
||||
exp: UC.newExpand("feeds & speeds", { }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
exp_end: UC.endExpand(),
|
||||
exp: UC.newExpand("top & bottom", ov_hover),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz),
|
||||
exp_end: UC.endExpand(),
|
||||
|
|
@ -487,10 +497,6 @@ export function createPopOps() {
|
|||
offset: UC.newSelect(LANG.cc_offs_s, { title: LANG.cc_offs_l, show: () => (env.poppedRec.mode === 'follow') }, "traceoff"),
|
||||
direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0), show: (op) => env.popOp.trace.rec.mode === "clear" }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units }),
|
||||
offover: UC.newInput(LANG.cc_offd_s, { title: LANG.cc_offd_l, convert: toFloat, units, show: () => env.poppedRec.offset !== "none" || env.poppedRec.mode === "clear" }),
|
||||
|
|
@ -499,13 +505,22 @@ export function createPopOps() {
|
|||
merge: UC.newBoolean(LANG.co_merg_s, undefined, { title: LANG.co_merg_l, show: () => !env.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", ov_hover),
|
||||
exp: UC.newExpand("feeds & speeds", { }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
exp_end: UC.endExpand(),
|
||||
exp: UC.newExpand("top & bottom", ov_hover),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz),
|
||||
exp_end: UC.endExpand(),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
menu: UC.newRow([UC.newButton("select", traceAdd)], { class: "ext-buttons f-row" }),
|
||||
menu: UC.newRow([
|
||||
UC.newButton("select", traceAdd),
|
||||
// UC.newButton("load", traceLoad, { show: () => env.poppedRec.mode === "follow" }),
|
||||
// UC.newButton("", traceClear, { icon: '<i class="fa fa-trash"></i>' }),
|
||||
], { class: "ext-buttons f-row", row: true }),
|
||||
};
|
||||
|
||||
createPopOp('pocket', {
|
||||
|
|
@ -530,10 +545,6 @@ export function createPopOps() {
|
|||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
direction: UC.newSelect(LANG.ou_dire_s, { title: LANG.ou_dire_l }, "direction"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: toFloat, bound: UC.bound(0.01, 1.0) }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: toFloat, units, show: () => !env.poppedRec.contour }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
|
|
@ -545,7 +556,12 @@ export function createPopOps() {
|
|||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
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 }),
|
||||
exp: UC.newExpand("overrides", ov_hover),
|
||||
exp: UC.newExpand("feeds & speeds", { }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: toInt, units }),
|
||||
plunge: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: toInt, units }),
|
||||
exp_end: UC.endExpand(),
|
||||
exp: UC.newExpand("top & bottom", ov_hover),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
ov_topz: UC.newInput(LANG.ou_ztop_s, ov_topz),
|
||||
ov_botz: UC.newInput(LANG.ou_zbot_s, ov_botz),
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
import { api } from '../../app/api.js';
|
||||
import { env, clearPops, isDark } from './init-ui.js';
|
||||
import { parse } from '../../../load/svg.js';
|
||||
import { CAM } from './driver-fe.js';
|
||||
import { Layers } from '../../app/layers.js';
|
||||
import { Stack } from '../../app/stack.js';
|
||||
import { newPolygon } from '../../../geo/polygon.js';
|
||||
|
||||
export let traceOn = false;
|
||||
export let lastTrace;
|
||||
|
|
@ -13,6 +15,95 @@ export function setLastTrace(trace) {
|
|||
lastTrace = trace;
|
||||
}
|
||||
|
||||
export function traceLoad(ev) {
|
||||
let widget = api.widgets.all()[0];
|
||||
if (!widget) return;
|
||||
window.showOpenFilePicker({
|
||||
types: [{
|
||||
description: 'SVG Files',
|
||||
accept: { 'text/svg': ['.svg'] }
|
||||
}],
|
||||
multiple: false
|
||||
}).then(async fileHandle => {
|
||||
const file = await fileHandle[0].getFile()
|
||||
const text = await file.text(); // string
|
||||
// const buf = await file.arrayBuffer(); // binary
|
||||
// const blob = await file.slice();
|
||||
const polys = parse(text, { flat: true, soup: true });
|
||||
const rec = env.poppedRec;
|
||||
rec.areas[widget.id] = polys.map(p => p.toArray());
|
||||
rec.svg = true;
|
||||
traceAdd();
|
||||
}).catch(error => {
|
||||
console.log('no file load', error);
|
||||
});
|
||||
}
|
||||
|
||||
export function traceClear(ev) {
|
||||
return;
|
||||
api.widgets.for(widget => {
|
||||
unselectTraces(widget, true);
|
||||
widget.traces = [];
|
||||
widget.adds = [];
|
||||
});
|
||||
env.poppedRec.areas = [];
|
||||
env.poppedRec.svg = false;
|
||||
traceDone();
|
||||
}
|
||||
|
||||
function startTraceAdd(ids) {
|
||||
api.hide.alert(alert);
|
||||
alert = api.show.alert("[esc] cancels trace editing");
|
||||
api.widgets.for(widget => {
|
||||
if (ids.indexOf(widget.id) >= 0) {
|
||||
unselectTraces(widget, true);
|
||||
widget.trace_stack = null;
|
||||
}
|
||||
if (widget.trace_stack) {
|
||||
widget.adds.appendAll(widget.trace_stack.meshes);
|
||||
widget.trace_stack.show();
|
||||
return;
|
||||
}
|
||||
let areas = (env.poppedRec.areas[widget.id] || []);
|
||||
let stack = new Stack(widget.mesh);
|
||||
widget.trace_stack = stack;
|
||||
widget.traces?.forEach(poly => {
|
||||
let match = areas.filter(arr => poly.matches(arr));
|
||||
let layers = new Layers();
|
||||
layers.setLayer("trace", { line: 0xaaaa55, fat: 4, order: -10 }, false).addPoly(poly);
|
||||
stack.addLayers(layers);
|
||||
stack.new_meshes.forEach(mesh => {
|
||||
mesh.trace = { widget, poly };
|
||||
// ensure trace poly singleton from matches
|
||||
if (match.length > 0) {
|
||||
poly._trace = match[0];
|
||||
} else {
|
||||
poly._trace = poly.toArray();
|
||||
}
|
||||
});
|
||||
widget.adds.appendAll(stack.new_meshes);
|
||||
// console.log(widget)
|
||||
});
|
||||
});
|
||||
// ensure appropriate traces are toggled matching current record
|
||||
api.widgets.for(widget => {
|
||||
widget.setVisualState({ opacity: 0.25 });
|
||||
let areas = (env.poppedRec.areas[widget.id] || []);
|
||||
let stack = widget.trace_stack;
|
||||
stack.meshes.forEach(mesh => {
|
||||
let { poly } = mesh.trace;
|
||||
let match = areas.filter(arr => poly.matches(arr));
|
||||
if (match.length > 0) {
|
||||
if (!mesh.selected) {
|
||||
traceToggle(mesh, true);
|
||||
}
|
||||
} else if (mesh.selected) {
|
||||
traceToggle(mesh, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function traceAdd(ev) {
|
||||
if (traceOn) {
|
||||
return traceDone();
|
||||
|
|
@ -25,58 +116,16 @@ export function traceAdd(ev) {
|
|||
api.feature.hoverAdds = true;
|
||||
env.hover = traceHover;
|
||||
env.hoverUp = traceHoverUp;
|
||||
CAM.traces((ids) => {
|
||||
api.hide.alert(alert);
|
||||
alert = api.show.alert("[esc] cancels trace editing");
|
||||
api.widgets.for(widget => {
|
||||
if (ids.indexOf(widget.id) >= 0) {
|
||||
unselectTraces(widget, true);
|
||||
widget.trace_stack = null;
|
||||
}
|
||||
if (widget.trace_stack) {
|
||||
widget.adds.appendAll(widget.trace_stack.meshes);
|
||||
widget.trace_stack.show();
|
||||
return;
|
||||
}
|
||||
let areas = (env.poppedRec.areas[widget.id] || []);
|
||||
let stack = new Stack(widget.mesh);
|
||||
widget.trace_stack = stack;
|
||||
widget.traces?.forEach(poly => {
|
||||
let match = areas.filter(arr => poly.matches(arr));
|
||||
let layers = new Layers();
|
||||
layers.setLayer("trace", { line: 0xaaaa55, fat: 4, order: -10 }, false).addPoly(poly);
|
||||
stack.addLayers(layers);
|
||||
stack.new_meshes.forEach(mesh => {
|
||||
mesh.trace = { widget, poly };
|
||||
// ensure trace poly singleton from matches
|
||||
if (match.length > 0) {
|
||||
poly._trace = match[0];
|
||||
} else {
|
||||
poly._trace = poly.toArray();
|
||||
}
|
||||
});
|
||||
widget.adds.appendAll(stack.new_meshes);
|
||||
// console.log(widget)
|
||||
});
|
||||
});
|
||||
// ensure appropriate traces are toggled matching current record
|
||||
api.widgets.for(widget => {
|
||||
widget.setVisualState({ opacity: 0.25 });
|
||||
let areas = (env.poppedRec.areas[widget.id] || []);
|
||||
let stack = widget.trace_stack;
|
||||
stack.meshes.forEach(mesh => {
|
||||
let { poly } = mesh.trace;
|
||||
let match = areas.filter(arr => poly.matches(arr));
|
||||
if (match.length > 0) {
|
||||
if (!mesh.selected) {
|
||||
traceToggle(mesh, true);
|
||||
}
|
||||
} else if (mesh.selected) {
|
||||
traceToggle(mesh, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, env.poppedRec.select === 'lines');
|
||||
if (env.poppedRec.svg === true) {
|
||||
let widgets = api.widgets.all();
|
||||
for (let [ id, areas ] of Object.entries(env.poppedRec.areas)) {
|
||||
let widget = widgets.filter(w => w.id === id)[0];
|
||||
widget.traces = areas.map(arr => newPolygon().fromArray(arr));
|
||||
}
|
||||
startTraceAdd(Object.keys(env.poppedRec.areas));
|
||||
} else {
|
||||
CAM.traces(startTraceAdd, env.poppedRec.select === 'lines');
|
||||
}
|
||||
}
|
||||
|
||||
export function traceDone() {
|
||||
|
|
|
|||
|
|
@ -1346,10 +1346,12 @@ details[open] summary::after {
|
|||
cursor: pointer;
|
||||
}
|
||||
.ext-buttons button {
|
||||
display: inline-flex;
|
||||
line-height: 1;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
flex-grow: 1;
|
||||
flex: 1 1 0; /* equal width */
|
||||
margin-top: 3px;
|
||||
height: 75%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@
|
|||
<div id="file-import">
|
||||
<label lk="import">import</label>
|
||||
<span><i class="fas fa-file-upload"></i></span>
|
||||
<!-- required file input loader -->
|
||||
<input id="load-file" type="file" name="loadme" style="display:none"></input>
|
||||
<!-- required file input loaders -->
|
||||
<input id="load-file" type="file" name="loadme" style="display:none" accept=".km,.kmz,.stl,.obj,.svg,.png,.jpg,.jpeg,.gcode,.nc"></input>
|
||||
</div>
|
||||
<hr>
|
||||
<div id="app-export">
|
||||
|
|
|
|||
Loading…
Reference in a new issue