stub in cam pocket op with surface selection

This commit is contained in:
Stewart Allen 2022-04-04 21:37:15 -04:00
commit 50dfba4e84
9 changed files with 182 additions and 40 deletions

View file

@ -177,6 +177,7 @@ CAM.init = function(kiri, api) {
case "register": return func.opAddRegister('X', 2); case "register": return func.opAddRegister('X', 2);
case "drill": return func.opAddDrill(); case "drill": return func.opAddDrill();
case "trace": return func.opAddTrace(); case "trace": return func.opAddTrace();
case "pocket": return func.opAddPocket();
case "flip": case "flip":
// only one flip op permitted // only one flip op permitted
for (let op of current.process.ops) { for (let op of current.process.ops) {
@ -200,6 +201,10 @@ CAM.init = function(kiri, api) {
func.opAdd(popOp.outline.new()); func.opAdd(popOp.outline.new());
}; };
func.opAddPocket = () => {
func.opAdd(popOp.pocket.new());
};
func.opAddContour = (axis) => { func.opAddContour = (axis) => {
let rec = popOp.contour.new(); let rec = popOp.contour.new();
rec.axis = axis.toUpperCase(); rec.axis = axis.toUpperCase();
@ -553,15 +558,55 @@ CAM.init = function(kiri, api) {
iw.saveState(); iw.saveState();
}; };
// SURFACE FUNCS
let surfaceOn = false, lastWidget;
func.surfaceAdd = (ev) => {
func.unpop();
func.tabDone();
func.traceDone();
func.surfaceDone();
alert = api.show.alert("analyzing surfaces...", 1000);
CAM.surfaces(data => {
api.hide.alert(alert);
alert = api.show.alert("[esc] cancels surface editing");
});
surfaceOn = hoveredOp;
surfaceOn.classList.add("editing");
api.feature.on_mouse_up = (obj, ev) => {
let { face } = obj;
let min = Math.min(face.a, face.b, face.c);
let widget = lastWidget = obj.object.widget;
CAM.surface_find(widget.id, min / 3, faces => {
if (faces && faces.length) {
widget.selectFaces(faces);
}
});
};
};
func.surfaceDone = () => {
if (!surfaceOn) {
return;
}
lastWidget.selectFaces([]);
api.feature.on_mouse_up = undefined;
surfaceOn.classList.remove("editing");
surfaceOn = false;
};
// TRACE FUNCS // TRACE FUNCS
let traceOn = false, lastTrace; let traceOn = false, lastTrace;
func.traceAdd = (ev) => { func.traceAdd = (ev) => {
func.unpop(); func.unpop();
func.tabDone(); func.tabDone();
func.traceDone(); func.traceDone();
func.surfaceDone();
alert = api.show.alert("analyzing parts...", 1000); alert = api.show.alert("analyzing parts...", 1000);
traceOn = hoveredOp; traceOn = hoveredOp;
traceOn.classList.add("editing"); traceOn.classList.add("editing");
api.feature.hover = true;
api.feature.hoverAdds = true;
func.hover = func.traceHover;
func.hoverUp = func.traceHoverUp;
CAM.traces((ids) => { CAM.traces((ids) => {
api.hide.alert(alert); api.hide.alert(alert);
alert = api.show.alert("[esc] cancels trace editing"); alert = api.show.alert("[esc] cancels trace editing");
@ -613,10 +658,6 @@ CAM.init = function(kiri, api) {
}); });
}); });
}, poppedRec.select === 'lines'); }, poppedRec.select === 'lines');
api.feature.hover = true;
api.feature.hoverAdds = true;
func.hover = func.traceHover;
func.hoverUp = func.traceHoverUp;
}; };
func.traceDone = () => { func.traceDone = () => {
if (!traceOn) { if (!traceOn) {
@ -726,12 +767,14 @@ CAM.init = function(kiri, api) {
if (isCamMode) { if (isCamMode) {
func.tabDone(); func.tabDone();
func.traceDone(); func.traceDone();
func.surfaceDone();
} }
}); });
api.event.on("key.esc", () => { api.event.on("key.esc", () => {
if (isCamMode) { if (isCamMode) {
func.tabDone(); func.tabDone();
func.traceDone(); func.traceDone();
func.surfaceDone();
} }
}); });
api.event.on("selection.scale", () => { api.event.on("selection.scale", () => {
@ -954,7 +997,6 @@ CAM.init = function(kiri, api) {
down: 'camTraceDown', down: 'camTraceDown',
rate: 'camTraceSpeed', rate: 'camTraceSpeed',
plunge: 'camTracePlunge', plunge: 'camTracePlunge',
// single: 'camTraceLines',
select: 'camTraceMode' select: 'camTraceMode'
}).inputs = { }).inputs = {
tool: UC.newSelect(LANG.cc_tool, {}, "tools"), tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
@ -967,7 +1009,6 @@ CAM.init = function(kiri, api) {
rate: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:UC.toInt, units:true}), rate: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:UC.toInt, units:true}),
plunge: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:UC.toInt, units:true}), plunge: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:UC.toInt, units:true}),
sep: UC.newBlank({class:"pop-sep"}), sep: UC.newBlank({class:"pop-sep"}),
// single: UC.newBoolean(LANG.cc_sngl_s, undefined, {title:LANG.cc_sngl_l}),
select: UC.newSelect(LANG.cc_sele_s, {title:LANG.cc_sele_l}, "select"), select: UC.newSelect(LANG.cc_sele_s, {title:LANG.cc_sele_l}, "select"),
menu: UC.newRow([ menu: UC.newRow([
UC.newButton(undefined, func.traceAdd, {icon:'<i class="fas fa-plus"></i>'}), UC.newButton(undefined, func.traceAdd, {icon:'<i class="fas fa-plus"></i>'}),
@ -975,6 +1016,28 @@ CAM.init = function(kiri, api) {
], {class:"ext-buttons f-row"}), ], {class:"ext-buttons f-row"}),
}; };
createPopOp('pocket', {
spindle: 'camPocketSpindle',
tool: 'camPocketTool',
step: 'camPocketOver',
down: 'camPocketDown',
rate: 'camPocketSpeed',
plunge: 'camPocketPlunge',
}).inputs = {
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
sep: UC.newBlank({class:"pop-sep"}),
spindle: UC.newInput(LANG.cc_spnd_s, {title:LANG.cc_spnd_l, convert:UC.toInt, show:hasSpindle}),
step: UC.newInput(LANG.cc_sovr_s, {title:LANG.cc_sovr_l, convert:UC.toFloat, bound:UC.bound(0.01,1.0)}),
down: UC.newInput(LANG.cc_sdwn_s, {title:LANG.cc_sdwn_l, convert:UC.toFloat, units:true}),
rate: UC.newInput(LANG.cc_feed_s, {title:LANG.cc_feed_l, convert:UC.toInt, units:true}),
plunge: UC.newInput(LANG.cc_plng_s, {title:LANG.cc_plng_l, convert:UC.toInt, units:true}),
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"}),
};
createPopOp('drill', { createPopOp('drill', {
tool: 'camDrillTool', tool: 'camDrillTool',
spindle: 'camDrillSpindle', spindle: 'camDrillSpindle',

View file

@ -4,6 +4,7 @@
// dep: main.kiri // dep: main.kiri
// use: kiri.codec // use: kiri.codec
// use: mesh.tool
gapp.register("kiri-mode.cam.driver", [], (root, exports) => { gapp.register("kiri-mode.cam.driver", [], (root, exports) => {
const { kiri } = root; const { kiri } = root;
@ -49,6 +50,42 @@ kiri.load(api => {
} } ))); } } )));
}; };
if (kiri.client)
CAM.surfaces = function(ondone) {
kiri.client.sync();
const settings = api.conf.get();
kiri.client.send("cam_surfaces", { settings }, output => {
ondone(output);
});
};
if (kiri.worker)
kiri.worker.cam_surfaces = function(data, send) {
const { settings } = data;
const widgets = Object.values(kiri.worker.cache);
for (let widget of widgets) {
if (!widget.tool) {
let tool = widget.tool = new mesh.tool();
tool.generateFaceMap(widget.getVertices().array);
}
}
send.done({});
};
if (kiri.client)
CAM.surface_find = function(id, face, ondone) {
kiri.client.send("cam_surface_find", { id, face }, faces => {
ondone(faces);
});
};
if (kiri.worker)
kiri.worker.cam_surface_find = function(data, send) {
const { id, face } = data;
const widget = kiri.worker.cache[id];
const faces = widget.tool.findConnectedSurface([face], 0.1, 0.001);
send.done(faces);
};
}); });
}); });

View file

@ -28,6 +28,8 @@ const feature = {
on_key: undefined, // function override default key handlers on_key: undefined, // function override default key handlers
on_load: undefined, // function override file drop loads on_load: undefined, // function override file drop loads
on_add_stl: undefined, // legacy override stl 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 work_alerts: true, // allow disabling work progress alerts
modes: [ "fdm", "sla", "cam", "laser" ], // enable device modes modes: [ "fdm", "sla", "cam", "laser" ], // enable device modes
pmode: consts.PMODES.SPEED, // preview modes pmode: consts.PMODES.SPEED, // preview modes

View file

@ -492,6 +492,12 @@ const conf = exports({
camTraceSpeed: 250, camTraceSpeed: 250,
camTracePlunge: 200, camTracePlunge: 200,
camTraceLines: false, camTraceLines: false,
camPocketSpindle: 1000,
camPocketTool: 1000,
camPocketOver: 0.5,
camPocketDown: 1,
camPocketSpeed: 250,
camPocketPlunge: 200,
camDrillTool: 1000, camDrillTool: 1000,
camDrillSpindle: 1000, camDrillSpindle: 1000,
camDrillDownSpeed: 250, camDrillDownSpeed: 250,

View file

@ -2423,13 +2423,19 @@ gapp.register("kiri.init", [], (root, exports) => {
} }
}); });
space.mouse.downSelect((int,event) => { space.mouse.downSelect((int, event) => {
if (api.feature.hover) { if (api.feature.on_mouse_down) {
if (int) { if (int) {
api.event.emit('mouse.hover.down', {int, point: int.point}); api.feature.on_mouse_down(int, event);
return; return;
} }
return; }
if (api.feature.hover) {
if (int) {
return api.event.emit('mouse.hover.down', {int, point: int.point});
} else {
return api.selection.meshes();
}
} }
// lay flat with meta or ctrl clicking a selected face // lay flat with meta or ctrl clicking a selected face
if (int && (event.ctrlKey || event.metaKey || api.feature.on_face_select)) { if (int && (event.ctrlKey || event.metaKey || api.feature.on_face_select)) {
@ -2447,7 +2453,14 @@ gapp.register("kiri.init", [], (root, exports) => {
} }
}); });
space.mouse.upSelect(function(object, event) { space.mouse.upSelect((object, event) => {
if (api.feature.on_mouse_up) {
if (event && object) {
return api.feature.on_mouse_up(object, event);
} else {
return api.widgets.meshes();
}
}
if (event && api.feature.hover) { if (event && api.feature.hover) {
api.event.emit('mouse.hover.up', { object, event }); api.event.emit('mouse.hover.up', { object, event });
return; return;

View file

@ -9,16 +9,16 @@
// dep: geo.polygons // dep: geo.polygons
// dep: kiri.utils // dep: kiri.utils
// use: kiri.codec // use: kiri.codec
// use: mesh.util
gapp.register("kiri.widget", [], (root, exports) => { gapp.register("kiri.widget", [], (root, exports) => {
const { base, kiri } = root; const { base, kiri } = root;
const { api, driver, utils } = kiri; const { api, driver, utils } = kiri;
const { config, util, polygons } = base; const { util, polygons } = base;
const { Mesh, newPoint, verticesToPoints } = base; const { Mesh, newPoint, verticesToPoints } = base;
const { inRange, time } = util; const { inRange, time } = util;
const { rgb, avgc } = utils; const { avgc } = utils;
const POLY = polygons;
const solid_opacity = 1.0; const solid_opacity = 1.0;
const groups = []; const groups = [];
@ -299,15 +299,22 @@ class Widget {
*/ */
loadGeometry(geometry) { loadGeometry(geometry) {
const mesh = new THREE.Mesh( const mesh = new THREE.Mesh(
geometry, geometry, [
[ new THREE.MeshPhongMaterial({ new THREE.MeshPhongMaterial({
color: 0xffff00, color: 0xffff00,
specular: 0x202020, specular: 0x202020,
shininess: 125, shininess: 125,
transparent: true, transparent: true,
opacity: solid_opacity opacity: solid_opacity
}) ] }),
); new THREE.MeshPhongMaterial({
color: 0x0088ee,
specular: 0x202020,
shininess: 100,
transparent: true,
opacity: solid_opacity
}),
]);
mesh.renderOrder = 1; mesh.renderOrder = 1;
geometry.computeVertexNormals(); geometry.computeVertexNormals();
geometry.addGroup(0, Infinity, 0); geometry.addGroup(0, Infinity, 0);
@ -377,6 +384,15 @@ class Widget {
return this.getMaterial().visible; return this.getMaterial().visible;
} }
selectFaces(faces) {
let groups = mesh.util.facesToGroups(faces || []);
let geo = this.mesh.geometry;
geo.clearGroups();
for (let group of groups) {
geo.addGroup(group.start*3, group.count*3, group.mat || 0);
}
}
/** /**
* @param {number} value * @param {number} value
*/ */

View file

@ -519,28 +519,7 @@ mesh.model = class MeshModel extends mesh.object {
} }
updateSelections() { updateSelections() {
let faces = this.sel.faces; let groups = mesh.util.facesToGroups(this.sel.faces);
let groups = [];
if (faces && faces.length) {
faces = faces.sort((a,b) => a - b).slice();
let first = faces.shift();
if (first > 0) {
groups.push({ start: 0, count: first, mat: 0 });
}
let range = { start: first, count: 1, mat: 1 };
groups.push(range);
for (let face of faces) {
if (face === range.start + range.count) {
range.count++;
} else {
groups.push(range = { start: range.start + range.count, count: face - range.start - range.count });
groups.push(range = { start: face, count: 1, mat: 1 });
}
}
groups.push({ start: range.start + range.count, count: Infinity });
} else {
groups.push({ start: 0, count: Infinity });
}
let geo = this.mesh.geometry; let geo = this.mesh.geometry;
geo.clearGroups(); geo.clearGroups();
for (let group of groups) { for (let group of groups) {

View file

@ -270,6 +270,31 @@ const util = exports({
} }
return new VertexNormalsHelper(mesh); return new VertexNormalsHelper(mesh);
},
facesToGroups(faces) {
let groups = [];
if (faces && faces.length) {
faces = faces.sort((a,b) => a - b).slice();
let first = faces.shift();
if (first > 0) {
groups.push({ start: 0, count: first, mat: 0 });
}
let range = { start: first, count: 1, mat: 1 };
groups.push(range);
for (let face of faces) {
if (face === range.start + range.count) {
range.count++;
} else {
groups.push(range = { start: range.start + range.count, count: face - range.start - range.count });
groups.push(range = { start: face, count: 1, mat: 1 });
}
}
groups.push({ start: range.start + range.count, count: Infinity });
} else {
groups.push({ start: 0, count: Infinity });
}
return groups;
} }
}); });

View file

@ -477,6 +477,7 @@
<div title="remove an area of material&#13;inside a defined boundary&#13;sometimes called pocketing">rough</div> <div title="remove an area of material&#13;inside a defined boundary&#13;sometimes called pocketing">rough</div>
<div title="clean up after roughing&#13;or perform a part cutout">outline</div> <div title="clean up after roughing&#13;or perform a part cutout">outline</div>
<div title="2.5D tracing along X or Y axis&#13;used for complex part features">contour</div> <div title="2.5D tracing along X or Y axis&#13;used for complex part features">contour</div>
<div title="clear areas above&#13;selected surfaces">pocket</div>
<div title="follow selected features with&#13;a specified tool. often used&#13;for lettering and engraving">trace</div> <div title="follow selected features with&#13;a specified tool. often used&#13;for lettering and engraving">trace</div>
<div title="drill any holes matching&#13;selected tool diameter">drill</div> <div title="drill any holes matching&#13;selected tool diameter">drill</div>
<hr width="100%"> <hr width="100%">