splitting cam client into modules
This commit is contained in:
parent
f4957698c0
commit
37e081ed8e
8 changed files with 1493 additions and 1432 deletions
82
src2/kiri-mode/cam/cl-flip.js
Normal file
82
src2/kiri-mode/cam/cl-flip.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { api } from '../../kiri/api.js';
|
||||
import { env } from './client.js';
|
||||
import { CAM } from './driver-fe.js';
|
||||
|
||||
export function opFlip() {
|
||||
api.view.set_arrange();
|
||||
let widgets = api.widgets.all();
|
||||
let { process } = env.current;
|
||||
let { ops, op2 } = process;
|
||||
// add flip singleton to b-side
|
||||
let add2 = op2.length === 0;
|
||||
let axis = env.poppedRec.axis;
|
||||
env.flipping = true;
|
||||
process.camZAnchor = {
|
||||
top: "bottom",
|
||||
bottom: "top",
|
||||
middle: "middle"
|
||||
}[process.camZAnchor];
|
||||
// flip tabs
|
||||
for (let widget of widgets) {
|
||||
let anno = api.widgets.annotate(widget.id).tab || [];
|
||||
let wbm = widget.bounds.max.z;
|
||||
for (let tab of anno) {
|
||||
let box = widget.tabs[tab.id].box;s
|
||||
let bpo = box.position;
|
||||
let xr = 0, yr = 0;
|
||||
let flz = wbm - bpo.z;
|
||||
if (axis === 'X') {
|
||||
tab.pos.y = -tab.pos.y;
|
||||
bpo.y = -bpo.y;
|
||||
xr = Math.PI / 2;
|
||||
}
|
||||
if (axis === 'Y') {
|
||||
tab.pos.x = -tab.pos.x;
|
||||
bpo.x = -bpo.x;
|
||||
yr = Math.PI / 2;
|
||||
}
|
||||
tab.pos.z = bpo.z = flz;
|
||||
let [rx, ry, rz, rw] = tab.rot;
|
||||
let qat = new THREE.Quaternion(rx, ry, rz, rw);
|
||||
let eul = new THREE.Euler().setFromQuaternion(qat);
|
||||
eul._z = -eul._z;
|
||||
tab.rot = new THREE.Quaternion().setFromEuler(eul);
|
||||
}
|
||||
clearTabs(widget, true);
|
||||
restoreTabs([widget]);
|
||||
}
|
||||
// flip widget
|
||||
if (axis === 'X') {
|
||||
api.selection.rotate(Math.PI, 0, 0);
|
||||
}
|
||||
if (axis === 'Y') {
|
||||
api.selection.rotate(0, Math.PI, 0);
|
||||
}
|
||||
// clear traces cache
|
||||
CAM.traces_clear();
|
||||
api.client.clear();
|
||||
env.flipping = false;
|
||||
process.ops = op2;
|
||||
process.op2 = ops;
|
||||
// flip camZBottom
|
||||
if (env.poppedRec.invert && process.camZBottom && env.camZBottom) {
|
||||
const maxZ = env.camZBottom._max.z
|
||||
process.camZBottom = maxZ - process.camZBottom;
|
||||
api.util.rec2ui(process);
|
||||
updateStock();
|
||||
}
|
||||
// keep flip operations in sync
|
||||
for (let op of op2) {
|
||||
if (op.type === 'flip') {
|
||||
op.axis = env.poppedRec.axis;
|
||||
op.invert = env.poppedRec.invert;
|
||||
}
|
||||
}
|
||||
if (add2) {
|
||||
opAdd(env.poppedRec);
|
||||
} else {
|
||||
opRender();
|
||||
}
|
||||
}
|
||||
216
src2/kiri-mode/cam/cl-hole.js
Normal file
216
src2/kiri-mode/cam/cl-hole.js
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { api } from '../../kiri/api.js';
|
||||
import { env } from './client.js';
|
||||
import { lastTrace, setLastTrace } from './cl-trace.js';
|
||||
|
||||
export let holeSelOn = false, lastSelHoles;
|
||||
|
||||
/**
|
||||
* Client side function to select holes in widgets for CAM operations.
|
||||
* If holes have already been analyzed, they are displayed immediately.
|
||||
* Otherwise, the CAM server is queried and the results are cached.
|
||||
* @param {boolean} individual - select all holes, false to only select
|
||||
* holes of tool diameter.
|
||||
*/
|
||||
export async function selectHoles(individual) {
|
||||
// console.log("client individual selected",individual)
|
||||
if (holeSelOn) {
|
||||
return selectHolesDone();
|
||||
}
|
||||
env.clearPops();
|
||||
let alert = api.show.alert("analyzing parts...");
|
||||
holeSelOn = env.hoveredOp;
|
||||
holeSelOn.classList.add("editing");
|
||||
api.feature.hover = true;
|
||||
api.feature.hoverAdds = true;
|
||||
env.hover = selectHolesHover;
|
||||
env.hoverUp = selectHolesHoverUp;
|
||||
|
||||
const widgets = api.widgets.all()
|
||||
/**
|
||||
* creates a mesh for a hole and adds it to a widget
|
||||
* @param {Object3D} widget - widget to add the hole mesh to
|
||||
* @param {Object} drill - {depth,selected} object of the hole
|
||||
* @returns {Mesh} the created mesh
|
||||
*/
|
||||
function createHoleMesh(widget, drill) {
|
||||
let { depth, selected, diam } = drill
|
||||
let color = selected ? 0xFF0000 : 0x39e366
|
||||
let geo = new THREE.CylinderGeometry(diam / 2, diam / 2, depth, 20);
|
||||
const material = new THREE.MeshPhongMaterial({ color });
|
||||
let mesh = new THREE.Mesh(geo, material);
|
||||
mesh.position.copy(drill)
|
||||
mesh.position.z -= depth / 2
|
||||
mesh.rotation.x = Math.PI / 2
|
||||
drill.widgetID = widget.id
|
||||
drill.meshId = mesh.id; // add pointers to both objects
|
||||
mesh.hole = drill;
|
||||
mesh.parent = widget.mesh;
|
||||
widget.mesh.add(mesh);
|
||||
widget.adds.push(mesh); // for click detection
|
||||
return mesh
|
||||
}
|
||||
let meshesCached = widgets.every(widget => env.poppedRec.drills[widget.id] != undefined)
|
||||
if (individual && meshesCached) {
|
||||
// if any widget already has cached holes
|
||||
// console.log("already has cached holes",env.poppedRec.drills)
|
||||
api.hide.alert(alert);
|
||||
api.widgets.for(widget => {
|
||||
if (widget.adds) {
|
||||
let drills = env.poppedRec.drills[widget.id];
|
||||
let ids = drills.map(hole => hole.meshId);
|
||||
if (false && widget.adds.includes(mesh)) {
|
||||
// mesh in the old code was a dead artifact
|
||||
// so this code branch never actually ran
|
||||
widget.adds.forEach(add => {
|
||||
if (ids.includes(add.id)) {
|
||||
add.visible = true;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
drills.forEach(drill => {
|
||||
createHoleMesh(widget, drill);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// if no widget has cached holes
|
||||
let alert2 = api.show.alert("");
|
||||
let found = await CAM.holes(
|
||||
individual,
|
||||
env.poppedRec,
|
||||
(progress, msg) => {
|
||||
alert2[0] = msg;
|
||||
api.show.progress(progress, msg);
|
||||
api.alerts.update();
|
||||
},
|
||||
async centers => {
|
||||
api.show.progress(0);
|
||||
if (!Array.isArray(centers)) {
|
||||
console.log("worker returned a malformed drills response");
|
||||
return;
|
||||
}
|
||||
if (centers.length === 0) {
|
||||
console.log("no drill holes found");
|
||||
return;
|
||||
}
|
||||
let shadow = centers.some(c => c.shadowed);
|
||||
api.hide.alert(alert2);
|
||||
if (shadow) {
|
||||
alert2 = api.show.alert("Some holes are shadowed by part and are not shown.");
|
||||
}
|
||||
centers = centers ?? [];
|
||||
// list of all hole centers and if they are selected
|
||||
api.widgets.for(widget => {
|
||||
const { holes } = centers.find(center => center.id == widget.id);
|
||||
// console.log(holes)
|
||||
if (!holes.length) unselectHoles(holes);
|
||||
holes.forEach(hole => {
|
||||
createHoleMesh(widget, hole);
|
||||
});
|
||||
//add hole data to record
|
||||
env.poppedRec.drills = env.poppedRec.drills ?? {};
|
||||
env.poppedRec.drills[widget.id] = holes;
|
||||
//give widget access to an array of drill records that refrence it
|
||||
//so that it can be cleared when widget is rotated or mirrored etc.
|
||||
if (!widget.drills) { widget.drills = [] };
|
||||
widget.drills.push(holes);
|
||||
})
|
||||
}
|
||||
);
|
||||
if (!found || found.length === 0) {
|
||||
api.hide.alert(alert);
|
||||
api.hide.alert(alert2);
|
||||
api.show.alert("no drill holes found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
//hide the alert once hole meshes are calculated on the worker, and then added to the scene
|
||||
// api.hide.alert(alert);
|
||||
let escAlert = api.show.alert("[esc] cancels drill editing", 1000);
|
||||
setTimeout(() => {
|
||||
api.hide.alert(escAlert);
|
||||
}, 5000);
|
||||
api.widgets.opacity(0.8);
|
||||
}
|
||||
|
||||
export function selectHolesHover(data) {
|
||||
//not used right now. may be useful in the future
|
||||
if (lastTrace) {
|
||||
let { color, colorSave } = lastTrace.material[0] || lastTrace.material;
|
||||
color.r = colorSave.r;
|
||||
color.g = colorSave.g;
|
||||
color.b = colorSave.b;
|
||||
lastTrace.position.z -= 0.01;
|
||||
}
|
||||
if (data.type === 'platform') {
|
||||
setLastTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export function selectHolesHoverUp(int, ev) {
|
||||
if (!int) return; //if not a hole mesh return
|
||||
let { object } = int;
|
||||
selectHoleToggle(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the selection of a hole mesh and update its color
|
||||
* @param {Object3D} mesh - the hole mesh to toggle
|
||||
*/
|
||||
export function selectHoleToggle(mesh) {
|
||||
let { hole } = mesh
|
||||
if (!hole) return
|
||||
hole.selected = !hole.selected;
|
||||
mesh.material.color.setHex(hole.selected ? 0xFF0000 : 0x39e366);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the recorded holes in the widget (widget.drills array)
|
||||
* and also clears the widget.adds array.
|
||||
* @param {Object} widget - the widget with the drills array to clear
|
||||
*/
|
||||
export function clearHolesRec(widget) {
|
||||
if (widget.drills) {
|
||||
widget.drills.forEach(rec => {
|
||||
})
|
||||
}
|
||||
if (widget.adds) {
|
||||
widget.adds.length = 0 //clear adds array
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup function for selectHoles.
|
||||
* Removes all adds from the scene, hides the alert, and resets the opacity of the widgets.
|
||||
* Also resets the hover features and the editing class on the holeSelOn html element.
|
||||
*/
|
||||
export function selectHolesDone() {
|
||||
if (!holeSelOn) {
|
||||
return;
|
||||
}
|
||||
env.func.unpop();
|
||||
holeSelOn.classList.remove("editing");
|
||||
holeSelOn = false;
|
||||
api.widgets.opacity(1);
|
||||
api.hide.alert(alert);
|
||||
api.feature.hover = false;
|
||||
api.feature.hoverAdds = false;
|
||||
|
||||
api.widgets.for(widget => {
|
||||
for (let add of widget.adds) {
|
||||
add.visible = false
|
||||
widget.mesh.remove(add);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function unselectHoles(widget) {
|
||||
if (!widget.holes) return
|
||||
widget.holes.forEach(hole => {
|
||||
hole.selected = false
|
||||
})
|
||||
}
|
||||
598
src2/kiri-mode/cam/cl-ops.js
Normal file
598
src2/kiri-mode/cam/cl-ops.js
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { $, h } from '../../moto/webui.js';
|
||||
import { api } from '../../kiri/api.js';
|
||||
import { env } from './client.js';
|
||||
import { Tool } from './tool.js';
|
||||
import { opFlip } from './cl-flip.js';
|
||||
import { selectHoles } from './cl-hole.js';
|
||||
import { surfaceAdd } from './cl-surface.js';
|
||||
import { traceAdd } from './cl-trace.js';
|
||||
|
||||
const { MODES } = api.const;
|
||||
const { uc: UC } = api;
|
||||
const { alerts, conf } = api;
|
||||
const { current: LANG } = api.language;
|
||||
|
||||
let seed = Date.now();
|
||||
|
||||
function hasIndexing() {
|
||||
return env.isIndexed;
|
||||
}
|
||||
|
||||
function hasSpindle() {
|
||||
return env.current.device.spindleMax > 0;
|
||||
}
|
||||
|
||||
function zTop() {
|
||||
return api.conf.get().process.camZTop > 0;
|
||||
}
|
||||
|
||||
function zBottom() {
|
||||
return api.conf.get().process.camZBottom > 0;
|
||||
}
|
||||
|
||||
// create custom gcode editor function
|
||||
function gcodeEditor(label, field) {
|
||||
return function () {
|
||||
opGCode(label, field);
|
||||
}
|
||||
}
|
||||
|
||||
function opGCode(label, field = 'gcode') {
|
||||
api.dialog.show('any');
|
||||
const { c_gcode } = h.bind(
|
||||
$('mod-any'), h.div({ id: "camop_dialog" }, [
|
||||
h.label(label || 'custom gcode operation'),
|
||||
h.textarea({ id: "c_gcode", rows: 15, cols: 50 }),
|
||||
h.button({
|
||||
_: 'done', onclick: () => {
|
||||
api.dialog.hide();
|
||||
api.conf.save();
|
||||
}
|
||||
})
|
||||
])
|
||||
);
|
||||
let av = env.poppedRec[field] || [];
|
||||
c_gcode.value = typeof (av) === 'string' ? av : av.join('\n');
|
||||
c_gcode.onkeyup = (el) => {
|
||||
env.poppedRec[field] = c_gcode.value.trim().split('\n');
|
||||
};
|
||||
c_gcode.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new popup operation (popOp) for a given type.
|
||||
* @param {string} type - the name of the popOp to create
|
||||
* @param {object} map - an object mapping popOp keys to either a string
|
||||
* (representing a key in current.process) or a value (to be used as the default).
|
||||
* @returns {object} the newly created popOp.
|
||||
*/
|
||||
export function createPopOp(type, map) {
|
||||
let op = env.popOp[type] = {
|
||||
div: UC.newElement('div', { id: `${type}-op`, class: "cam-pop-op" }),
|
||||
use: (rec) => {
|
||||
op.rec = rec;
|
||||
for (let [key, val] of Object.entries(op.inputs)) {
|
||||
let type = val.type;
|
||||
let from = map[key];
|
||||
let rval = rec[key];
|
||||
// fill undef entries older defines
|
||||
if (type && (rval === null || rval === undefined)) {
|
||||
if (typeof (from) === 'string') {
|
||||
rec[key] = env.current.process[from];
|
||||
} else if (from !== undefined) {
|
||||
rec[key] = from;
|
||||
} else {
|
||||
console.log('error', { key, val, type, from });
|
||||
}
|
||||
}
|
||||
}
|
||||
api.util.rec2ui(rec, op.inputs);
|
||||
op.hideshow();
|
||||
},
|
||||
using: (rec) => {
|
||||
return op.rec === rec;
|
||||
},
|
||||
bind: (ev) => {
|
||||
api.util.ui2rec(op.rec, op.inputs);
|
||||
|
||||
const settings = conf.get();
|
||||
const { tool } = new Tool(settings, op.rec.tool); //get tool by id
|
||||
const opType = op.rec.type
|
||||
const drillOrRegister = opType == "drill" || opType == "register"
|
||||
|
||||
if (!drillOrRegister && tool.type == "drill") {
|
||||
alerts.show(`Warning: Drills should not be used for ${opType} operations.`)
|
||||
}
|
||||
else if (drillOrRegister && tool.type != "drill") {
|
||||
alerts.show(`Warning: Only drills should be used for drilling operations.`)
|
||||
}
|
||||
|
||||
for (let [key, val] of Object.entries(op.rec)) {
|
||||
let saveTo = map[key];
|
||||
if (saveTo && typeof (key) === 'string' && !key.startsWith("~")) {
|
||||
env.current.process[saveTo] = val;
|
||||
}
|
||||
}
|
||||
api.conf.save();
|
||||
op.hideshow();
|
||||
},
|
||||
new: () => {
|
||||
let rec = { type };
|
||||
for (let [key, src] of Object.entries(map)) {
|
||||
rec[key] = typeof (src) === 'string'
|
||||
? env.current.process[src.replace('~', '')]
|
||||
: src;
|
||||
}
|
||||
return rec;
|
||||
},
|
||||
hideshow: () => {
|
||||
for (let inp of Object.values(op.inputs)) {
|
||||
let parent = inp.parentElement;
|
||||
if (parent && parent.setVisible && parent.__opt.show) {
|
||||
parent.setVisible(parent.__opt.show(op, api.conf.get()));
|
||||
}
|
||||
}
|
||||
},
|
||||
addNote: () => {
|
||||
if (!op.note && type !== 'flip') {
|
||||
const divid = `div-${++seed}`;
|
||||
const noteid = `note-${++seed}`;
|
||||
const div = document.createElement('div');
|
||||
div.setAttribute('id', divid);
|
||||
div.classList.add('pop-tics')
|
||||
op.div.appendChild(div);
|
||||
div.innerHTML = h.build(
|
||||
h.div([h.label({ id: noteid })])
|
||||
);
|
||||
op.note = { divid, noteid };
|
||||
}
|
||||
if (op.note) {
|
||||
const { divid, noteid } = op.note;
|
||||
const div = $(divid);
|
||||
if (div) div.onclick = () => {
|
||||
api.uc.prompt('Edit Note for Operation', env.poppedRec.note || '').then(note => {
|
||||
if (note !== undefined && note !== null) {
|
||||
env.poppedRec.note = op.x = note;
|
||||
api.conf.save();
|
||||
}
|
||||
opRender();
|
||||
});
|
||||
};
|
||||
const note = $(noteid);
|
||||
if (note) note.innerText = env.poppedRec.note || '';
|
||||
}
|
||||
},
|
||||
group: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* @function createRecordGetter
|
||||
* @description Creates a getter function for the current record.
|
||||
* The getter will bind the current record to the op before returning it.
|
||||
* This is useful for passing a record to a pre-slice function
|
||||
* @returns {function} A getter function for the current record.
|
||||
*/
|
||||
op.createRecordGetter = () => {
|
||||
return () => {
|
||||
op.bind();
|
||||
return op.rec;
|
||||
}
|
||||
}
|
||||
|
||||
UC.restore({
|
||||
addTo: op.div,
|
||||
bindTo: op.bind,
|
||||
lastDiv: op.div,
|
||||
lastGroup: op.group
|
||||
});
|
||||
return op;
|
||||
}
|
||||
|
||||
export function createPopOps() {
|
||||
createPopOp('level', {
|
||||
tool: 'camLevelTool',
|
||||
spindle: 'camLevelSpindle',
|
||||
step: 'camLevelOver',
|
||||
rate: 'camLevelSpeed',
|
||||
down: 'camLevelDown',
|
||||
over: 'camLevelOver',
|
||||
stock: 'camLevelStock'
|
||||
}).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) }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }),
|
||||
down: UC.newInput(LANG.cc_loff_s, { title: LANG.cc_loff_l, convert: UC.toFloat, units: true }),
|
||||
over: UC.newInput(LANG.cc_lxyo_s, { title: LANG.cc_lxyo_l, convert: UC.toFloat, units: true }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
stock: UC.newBoolean(LANG.cc_lsto_s, undefined, { title: LANG.cc_lsto_l }),
|
||||
};
|
||||
|
||||
createPopOp('rough', {
|
||||
tool: 'camRoughTool',
|
||||
spindle: 'camRoughSpindle',
|
||||
down: 'camRoughDown',
|
||||
step: 'camRoughOver',
|
||||
rate: 'camRoughSpeed',
|
||||
plunge: 'camRoughPlunge',
|
||||
leave: 'camRoughStock',
|
||||
leavez: 'camRoughStockZ',
|
||||
all: 'camRoughAll',
|
||||
voids: 'camRoughVoid',
|
||||
flats: 'camRoughFlat',
|
||||
inside: 'camRoughIn',
|
||||
ov_topz: 0,
|
||||
ov_botz: 0,
|
||||
ov_conv: '~camConventional',
|
||||
}).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 }),
|
||||
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" }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 1.0) }),
|
||||
leave: UC.newInput(LANG.cr_lsto_s, { title: LANG.cr_lsto_l, convert: UC.toFloat, units: true }),
|
||||
leavez: UC.newInput(LANG.cr_lstz_s, { title: LANG.cr_lstz_l, convert: UC.toFloat, bound: UC.bound(0, 10), units: true }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
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 }),
|
||||
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', {
|
||||
tool: 'camOutlineTool',
|
||||
spindle: 'camOutlineSpindle',
|
||||
step: 'camOutlineOver',
|
||||
steps: 'camOutlineOverCount',
|
||||
down: 'camOutlineDown',
|
||||
rate: 'camOutlineSpeed',
|
||||
plunge: 'camOutlinePlunge',
|
||||
dogbones: 'camOutlineDogbone',
|
||||
omitvoid: 'camOutlineOmitVoid',
|
||||
omitthru: 'camOutlineOmitThru',
|
||||
outside: 'camOutlineOut',
|
||||
inside: 'camOutlineIn',
|
||||
wide: 'camOutlineWide',
|
||||
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" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }),
|
||||
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 }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.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: UC.toInt, bound: UC.bound(1, 5), show: () => env.popOp.outline.rec.wide }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
top: UC.newBoolean(LANG.co_clrt_s, undefined, { title: LANG.co_clrt_l }),
|
||||
inside: UC.newBoolean(LANG.co_olin_s, undefined, { title: LANG.co_olin_l, show: (op) => { return !op.inputs.outside.checked } }),
|
||||
outside: UC.newBoolean(LANG.co_olot_s, undefined, { title: LANG.co_olot_l, show: (op) => { return !op.inputs.inside.checked } }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
omitthru: UC.newBoolean(LANG.co_omit_s, undefined, { title: LANG.co_omit_l, xshow: (op) => { return op.inputs.outside.checked } }),
|
||||
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');
|
||||
|
||||
createPopOp('contour', {
|
||||
tool: 'camContourTool',
|
||||
spindle: 'camContourSpindle',
|
||||
step: 'camContourOver',
|
||||
rate: 'camContourSpeed',
|
||||
angle: 'camContourAngle',
|
||||
leave: 'camContourLeave',
|
||||
tolerance: 'camTolerance',
|
||||
flatness: 'camFlatness',
|
||||
reduction: 'camContourReduce',
|
||||
bridging: 'camContourBridge',
|
||||
bottom: 'camContourBottom',
|
||||
curves: 'camContourCurves',
|
||||
inside: 'camContourIn',
|
||||
filter: 'camContourFilter',
|
||||
axis: 'X'
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
axis: UC.newSelect(LANG.cd_axis, {}, "xyaxis"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 10.0) }),
|
||||
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" }),
|
||||
angle: UC.newInput(LANG.cf_angl_s, { title: LANG.cf_angl_l, convert: UC.toFloat, bound: UC.bound(45, 90), show: (op) => op.inputs.curves.checked }),
|
||||
flatness: UC.newInput(LANG.ou_flat_s, { title: LANG.ou_flat_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), units: false, round: 4 }),
|
||||
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 }),
|
||||
reduction: UC.newInput(LANG.ou_redu_s, { title: LANG.ou_redu_l, convert: UC.toInt, bound: UC.bound(0, 10), units: false }),
|
||||
// bridging: UC.newInput(LANG.ou_brdg_s, {title:LANG.ou_brdg_l, convert:UC.toFloat, bound:UC.bound(0,1000.0), units:true, round:4, show:(op) => op.inputs.curves.checked}),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
curves: UC.newBoolean(LANG.cf_curv_s, undefined, { title: LANG.cf_curv_l }),
|
||||
inside: UC.newBoolean(LANG.cf_olin_s, undefined, { title: LANG.cf_olin_l }),
|
||||
bottom: UC.newBoolean(LANG.cf_botm_s, undefined, { title: LANG.cf_botm_l, show: (op, conf) => conf ? conf.process.camZBottom : 0 }),
|
||||
filter: UC.newRow([UC.newButton(LANG.filter, contourFilter)], { class: "ext-buttons f-row" })
|
||||
};
|
||||
|
||||
createPopOp('lathe', {
|
||||
tool: 'camLatheTool',
|
||||
spindle: 'camLatheSpindle',
|
||||
step: 'camLatheOver',
|
||||
angle: 'camLatheAngle',
|
||||
rate: 'camLatheSpeed',
|
||||
tolerance: 'camTolerance',
|
||||
filter: 'camContourFilter',
|
||||
leave: 'camContourLeave',
|
||||
linear: 'camLatheLinear'
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
// axis: UC.newSelect(LANG.cd_axis, {}, "xyaxis"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.toFloat, bound: UC.bound(0.01, 100.0) }),
|
||||
angle: UC.newInput(LANG.cc_sang_s, { title: LANG.cc_sang_l, convert: UC.toFloat, bound: UC.bound(0.01, 180.0) }),
|
||||
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"})
|
||||
};
|
||||
|
||||
function canDogBones() {
|
||||
if (!env.poppedRec) return false;
|
||||
return env.poppedRec.mode === 'follow';// && env.poppedRec.offset && env.poppedRec.offset !== 'none';
|
||||
}
|
||||
|
||||
function canDogBonesRev() {
|
||||
return canDogBones() && env.poppedRec.dogbone;
|
||||
}
|
||||
|
||||
function zDogSep() {
|
||||
return canDogBones() || zBottom();
|
||||
}
|
||||
|
||||
createPopOp('trace', {
|
||||
mode: 'camTraceType',
|
||||
offset: 'camTraceOffset',
|
||||
spindle: 'camTraceSpindle',
|
||||
tool: 'camTraceTool',
|
||||
step: 'camTraceOver',
|
||||
down: 'camTraceDown',
|
||||
thru: 'camTraceThru',
|
||||
rate: 'camTraceSpeed',
|
||||
plunge: 'camTracePlunge',
|
||||
offover: 'camTraceOffOver',
|
||||
dogbone: 'camTraceDogbone',
|
||||
revbone: 'camTraceDogbone',
|
||||
merge: 'camTraceMerge',
|
||||
ov_topz: 0,
|
||||
ov_botz: 0,
|
||||
ov_conv: '~camConventional',
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
mode: UC.newSelect(LANG.cu_type_s, { title: LANG.cu_type_l }, "trace"),
|
||||
offset: UC.newSelect(LANG.cc_offs_s, { title: LANG.cc_offs_l, show: () => (env.poppedRec.mode === 'follow') }, "traceoff"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }),
|
||||
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" }),
|
||||
step: UC.newInput(LANG.cc_sovr_s, { title: LANG.cc_sovr_l, convert: UC.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: UC.toFloat, units: true }),
|
||||
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: () => env.poppedRec.offset !== "none" || env.poppedRec.mode === "clear" }),
|
||||
sep: UC.newBlank({ class: "pop-sep", modes: MODES.CAM, xshow: zDogSep }),
|
||||
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"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
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", traceAdd)], { class: "ext-buttons f-row" }),
|
||||
};
|
||||
|
||||
createPopOp('pocket', {
|
||||
spindle: 'camPocketSpindle',
|
||||
tool: 'camPocketTool',
|
||||
step: 'camPocketOver',
|
||||
down: 'camPocketDown',
|
||||
rate: 'camPocketSpeed',
|
||||
plunge: 'camPocketPlunge',
|
||||
expand: 'camPocketExpand',
|
||||
smooth: 'camPocketSmooth',
|
||||
refine: 'camPocketRefine',
|
||||
follow: 'camPocketFollow',
|
||||
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"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }),
|
||||
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" }),
|
||||
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, show: () => !env.poppedRec.contour }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
expand: UC.newInput(LANG.cp_xpnd_s, { title: LANG.cp_xpnd_l, convert: UC.toFloat, units: true, xshow: () => !env.poppedRec.contour }),
|
||||
refine: UC.newInput(LANG.cp_refi_s, { title: LANG.cp_refi_l, convert: UC.toInt, show: () => env.poppedRec.contour }),
|
||||
smooth: UC.newInput(LANG.cp_smoo_s, { title: LANG.cp_smoo_l, convert: UC.toInt }),
|
||||
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, show: () => env.poppedRec.contour }),
|
||||
follow: UC.newInput(LANG.cp_foll_s, { title: LANG.cp_foll_l, convert: UC.toFloat }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
contour: UC.newBoolean(LANG.cp_cont_s, undefined, { title: LANG.cp_cont_s }),
|
||||
engrave: UC.newBoolean(LANG.cp_engr_s, undefined, { title: LANG.cp_engr_l, show: () => env.poppedRec.contour }),
|
||||
outline: UC.newBoolean(LANG.cp_outl_s, undefined, { title: LANG.cp_outl_l }),
|
||||
exp: UC.newExpand("overrides"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
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", surfaceAdd)], { class: "ext-buttons f-row" }),
|
||||
};
|
||||
|
||||
createPopOp('drill', {
|
||||
tool: 'camDrillTool',
|
||||
spindle: 'camDrillSpindle',
|
||||
down: 'camDrillDown',
|
||||
rate: 'camDrillDownSpeed',
|
||||
dwell: 'camDrillDwell',
|
||||
lift: 'camDrillLift',
|
||||
mark: 'camDrillMark',
|
||||
precision: 'camDrillPrecision',
|
||||
thru: 'camDrillThru',
|
||||
fromTop: 'camDrillFromStockTop',
|
||||
}).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 }),
|
||||
rate: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: UC.toInt, units: true }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }),
|
||||
dwell: UC.newInput(LANG.cd_dwll_s, { title: LANG.cd_dwll_l, convert: UC.toFloat }),
|
||||
lift: UC.newInput(LANG.cd_lift_s, { title: LANG.cd_lift_l, convert: UC.toFloat, units: true, show: () => !env.poppedRec.mark }),
|
||||
mark: UC.newBoolean(LANG.cd_mark_s, undefined, { title: LANG.cd_mark_l, show: () => !env.poppedRec.fromTop }),
|
||||
fromTop: UC.newBoolean(LANG.cd_ftop_s, undefined, { title: LANG.cd_ftop_l, show: () => !env.poppedRec.mark }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
thru: UC.newInput(LANG.cd_dtru_s, { title: LANG.cd_dtru_l, convert: UC.toFloat, units: true, show: () => !env.poppedRec.mark }),
|
||||
precision: UC.newInput(LANG.cd_prcn_s, { title: LANG.cd_prcn_l, convert: UC.toFloat, units: true, show: () => !env.poppedRec.mark }),
|
||||
sep: UC.newBlank({ class: "pop-sep", }),
|
||||
actions: UC.newRow([
|
||||
UC.newButton(LANG.select, () => selectHoles(true), { title: LANG.cd_seli_l }),
|
||||
UC.newButton(LANG.cd_sela_s, () => selectHoles(false), { title: LANG.cd_sela_l })
|
||||
], { class: "ext-buttons f-col" })
|
||||
};
|
||||
|
||||
createPopOp('register', {
|
||||
tool: 'camDrillTool',
|
||||
spindle: 'camDrillSpindle',
|
||||
down: 'camDrillDown',
|
||||
rate: 'camDrillDownSpeed',
|
||||
dwell: 'camDrillDwell',
|
||||
lift: 'camDrillLift',
|
||||
feed: 'camRegisterSpeed',
|
||||
thru: 'camRegisterThru'
|
||||
}).inputs = {
|
||||
tool: UC.newSelect(LANG.cc_tool, {}, "tools"),
|
||||
axis: UC.newSelect(LANG.cd_axis, {}, "regaxis"),
|
||||
points: UC.newSelect(LANG.cd_points, { show: () => env.poppedRec.axis !== '-' }, "regpoints"),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
spindle: UC.newInput(LANG.cc_spnd_s, { title: LANG.cc_spnd_l, convert: UC.toInt, show: hasSpindle }),
|
||||
rate: UC.newInput(LANG.cc_plng_s, { title: LANG.cc_plng_l, convert: UC.toInt, units: true }),
|
||||
feed: UC.newInput(LANG.cc_feed_s, { title: LANG.cc_feed_l, convert: UC.toInt, units: true, show: () => env.poppedRec.axis === '-' }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
down: UC.newInput(LANG.cc_sdwn_s, { title: LANG.cc_sdwn_l, convert: UC.toFloat, units: true }),
|
||||
dwell: UC.newInput(LANG.cd_dwll_s, { title: LANG.cd_dwll_l, convert: UC.toFloat, show: () => env.poppedRec.axis !== '-' }),
|
||||
lift: UC.newInput(LANG.cd_lift_s, { title: LANG.cd_lift_l, convert: UC.toFloat, units: true, show: () => env.poppedRec.axis !== '-' }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
thru: UC.newInput(LANG.cd_thru_s, { title: LANG.cd_thru_l, convert: UC.toFloat, units: true }),
|
||||
};
|
||||
|
||||
createPopOp('flip', {
|
||||
axis: 'camFlipAxis',
|
||||
invert: 'camFlipInvert'
|
||||
}).inputs = {
|
||||
axis: UC.newSelect(LANG.cd_axis, {}, "regaxis"),
|
||||
sep: UC.newBlank({ class: "pop-sep", modes: MODES.CAM, 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, opFlip)], { class: "ext-buttons f-row" })
|
||||
};
|
||||
|
||||
createPopOp('gcode', {
|
||||
gcode: 'camCustomGcode',
|
||||
}).inputs = {
|
||||
action: UC.newRow([UC.newButton(LANG.edit, gcodeEditor())], { class: "ext-buttons f-row" })
|
||||
};
|
||||
|
||||
function angleTowardZUp() {
|
||||
api.event.emit('tool.mesh.face-up');
|
||||
}
|
||||
|
||||
createPopOp('index', {
|
||||
degrees: 'camIndexAxis',
|
||||
absolute: 'camIndexAbs'
|
||||
}).inputs = {
|
||||
degrees: UC.newInput(LANG.ci_degr_s, { title: LANG.ci_degr_l, convert: UC.toFloat, bound: UC.bound(-360, 360.0) }),
|
||||
absolute: UC.newBoolean(LANG.ci_abso_s, undefined, { title: LANG.ci_abso_l }),
|
||||
select: UC.newRow([UC.newButton(LANG.ci_face_s, angleTowardZUp)], { class: "ext-buttons f-row" })
|
||||
};
|
||||
|
||||
const editEnable = gcodeEditor('Laser Enable Script', 'enable');
|
||||
const editOn = gcodeEditor('Laser On Script', 'on');
|
||||
const editOff = gcodeEditor('Laser Off Script', 'off');
|
||||
|
||||
createPopOp('laser on', {
|
||||
enable: 'camLaserEnable',
|
||||
on: 'camLaserOn',
|
||||
off: 'camLaserOff',
|
||||
power: 'camLaserPower',
|
||||
adapt: 'camLaserAdaptive',
|
||||
adaptrp: 'camLaserAdaptMod',
|
||||
flat: 'camLaserFlatten',
|
||||
flatz: 'camLaserFlatZ',
|
||||
minp: 'camLaserPowerMin',
|
||||
maxp: 'camLaserPowerMax',
|
||||
minz: 'camLaserZMin',
|
||||
maxz: 'camLaserZMax',
|
||||
}).inputs = {
|
||||
enable: UC.newRow([UC.newButton(LANG.enable, editEnable)], { class: "ext-buttons f-row" }),
|
||||
on: UC.newRow([UC.newButton(LANG.on, editOn)], { class: "ext-buttons f-row" }),
|
||||
off: UC.newRow([UC.newButton(LANG.off, editOff)], { class: "ext-buttons f-row" }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
power: UC.newInput(LANG.cl_powr_s, { title: LANG.cl_powr_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), show: () => !env.poppedRec.adapt }),
|
||||
maxp: UC.newInput(LANG.cl_maxp_s, { title: LANG.cl_maxp_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), show: () => env.poppedRec.adapt }),
|
||||
minp: UC.newInput(LANG.cl_minp_s, { title: LANG.cl_minp_l, convert: UC.toFloat, bound: UC.bound(0, 1.0), show: () => env.poppedRec.adapt }),
|
||||
maxz: UC.newInput(LANG.cl_maxz_s, { title: LANG.cl_maxz_l, convert: UC.toFloat, show: () => env.poppedRec.adapt }),
|
||||
minz: UC.newInput(LANG.cl_minz_s, { title: LANG.cl_minz_l, convert: UC.toFloat, show: () => env.poppedRec.adapt }),
|
||||
flatz: UC.newInput(LANG.cl_flaz_s, { title: LANG.cl_flaz_l, convert: UC.toFloat, show: () => env.poppedRec.flat }),
|
||||
sep: UC.newBlank({ class: "pop-sep" }),
|
||||
adapt: UC.newBoolean(LANG.cl_adap_s, undefined, { title: LANG.cl_adap_l }),
|
||||
adaptrp: UC.newBoolean(LANG.cl_adrp_s, undefined, { title: LANG.cl_adrp_l, show: () => env.poppedRec.adapt }),
|
||||
flat: UC.newBoolean(LANG.cl_flat_s, undefined, { title: LANG.cl_flat_l }),
|
||||
};
|
||||
|
||||
const editDisable = gcodeEditor('Laser Disable Script', 'disable');
|
||||
|
||||
createPopOp('laser off', {
|
||||
disable: 'camLaserDisable',
|
||||
}).inputs = {
|
||||
disable: UC.newRow([UC.newButton(LANG.disable, editDisable)], { class: "ext-buttons f-row" }),
|
||||
};
|
||||
|
||||
createPopOp('|', {}).inputs = {};
|
||||
}
|
||||
141
src2/kiri-mode/cam/cl-stock.js
Normal file
141
src2/kiri-mode/cam/cl-stock.js
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { api } from '../../kiri/api.js';
|
||||
import { env } from './client.js';
|
||||
import { space as SPACE } from '../../moto/space.js';
|
||||
|
||||
const { ui: UI } = api;
|
||||
|
||||
export function updateStock() {
|
||||
if (env.isAnimate) {
|
||||
if (env.isIndexed) {
|
||||
SPACE.world.remove(env.camStock);
|
||||
env.camStock = undefined;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!env.isCamMode) {
|
||||
SPACE.world.remove(env.camZTop);
|
||||
SPACE.world.remove(env.camZBottom);
|
||||
SPACE.world.remove(env.camStock);
|
||||
env.camStock = null;
|
||||
env.camZTop = null;
|
||||
env.camZBottom = null;
|
||||
return;
|
||||
}
|
||||
|
||||
api.platform.update_bounds();
|
||||
|
||||
const settings = api.conf.get();
|
||||
const widgets = api.widgets.all();
|
||||
|
||||
const { stock, process } = settings;
|
||||
const { x, y, z, center } = stock;
|
||||
|
||||
UI.func.animate.classList.add('disabled');
|
||||
if (env.camStock) {
|
||||
SPACE.world.remove(env.camStock);
|
||||
env.camStock = null;
|
||||
}
|
||||
if (x && y && z) {
|
||||
UI.func.animate.classList.remove('disabled');
|
||||
{
|
||||
let geo = new THREE.BoxGeometry(1, 1, 1);
|
||||
let mat = new THREE.MeshBasicMaterial({
|
||||
color: 0x777777,
|
||||
opacity: 0.05,
|
||||
transparent: true,
|
||||
side: THREE.DoubleSide
|
||||
});
|
||||
env.camStock = new THREE.Mesh(geo, mat);
|
||||
env.camStock.renderOrder = 2;
|
||||
|
||||
let lo = 0.5;
|
||||
let lidat = [
|
||||
lo, lo, lo, lo, lo, -lo,
|
||||
lo, lo, lo, lo, -lo, lo,
|
||||
lo, lo, lo, -lo, lo, lo,
|
||||
-lo, -lo, -lo, -lo, -lo, lo,
|
||||
-lo, -lo, -lo, -lo, lo, -lo,
|
||||
-lo, -lo, -lo, lo, -lo, -lo,
|
||||
lo, lo, -lo, -lo, lo, -lo,
|
||||
lo, lo, -lo, lo, -lo, -lo,
|
||||
lo, -lo, -lo, lo, -lo, lo,
|
||||
lo, -lo, lo, -lo, -lo, lo,
|
||||
-lo, -lo, lo, -lo, lo, lo,
|
||||
-lo, lo, lo, -lo, lo, -lo
|
||||
];
|
||||
let ligeo = new THREE.BufferGeometry();
|
||||
ligeo.setAttribute('position', new THREE.BufferAttribute(lidat.toFloat32(), 3));
|
||||
let limat = new THREE.LineBasicMaterial({ color: 0xaaaaaa });
|
||||
let lines = new THREE.LineSegments(ligeo, limat);
|
||||
env.camStock.lines = lines;
|
||||
env.camStock.add(lines);
|
||||
SPACE.world.add(env.camStock);
|
||||
}
|
||||
// fight z fighting in threejs
|
||||
const { scale, position, lines } = env.camStock;
|
||||
scale.x = x + 0.005;
|
||||
scale.y = y + 0.005;
|
||||
scale.z = z + 0.005;
|
||||
position.x = center.x;
|
||||
position.y = center.y;
|
||||
position.z = center.z;
|
||||
lines.material.color = new THREE.Color(env.isDark() ? 0x555555 : 0xaaaaaa);
|
||||
}
|
||||
|
||||
SPACE.world.remove(env.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
|
||||
});
|
||||
const camZTop = env.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 {
|
||||
env.camZTop = undefined;
|
||||
}
|
||||
|
||||
SPACE.world.remove(env.camZBottom);
|
||||
if (process.camZBottom && 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
|
||||
});
|
||||
const camZBottom = env.camZBottom = new THREE.Mesh(geo, mat);
|
||||
camZBottom._max = max;
|
||||
camZBottom.renderOrder = 1;
|
||||
camZBottom.position.x = center.x;
|
||||
camZBottom.position.y = center.y;
|
||||
camZBottom.position.z = process.camZBottom;
|
||||
SPACE.world.add(camZBottom);
|
||||
} else {
|
||||
env.camZBottom = undefined;
|
||||
}
|
||||
|
||||
SPACE.update();
|
||||
}
|
||||
65
src2/kiri-mode/cam/cl-surface.js
Normal file
65
src2/kiri-mode/cam/cl-surface.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { api } from '../../kiri/api.js';
|
||||
import { env } from './client.js';
|
||||
import { CAM } from './driver-fe.js';
|
||||
|
||||
const DEG2RAD = Math.PI / 180;
|
||||
const RAD2DEG = 180 / Math.PI;
|
||||
|
||||
export let surfaceOn = false;
|
||||
|
||||
let alert, lastWidget;
|
||||
|
||||
export function surfaceAdd(ev) {
|
||||
if (surfaceOn) {
|
||||
return surfaceDone();
|
||||
}
|
||||
env.clearPops();
|
||||
alert = api.show.alert("analyzing surfaces...", 1000);
|
||||
let surfaces = env.poppedRec.surfaces;
|
||||
let radians = env.poppedRec.follow * DEG2RAD;
|
||||
CAM.surface_prep(env.currentIndex * RAD2DEG, () => {
|
||||
api.hide.alert(alert);
|
||||
alert = api.show.alert("[esc] cancels surface selection");
|
||||
for (let [wid, arr] of Object.entries(surfaces)) {
|
||||
let widget = api.widgets.forid(wid);
|
||||
if (widget && arr.length)
|
||||
for (let faceid of arr) {
|
||||
CAM.surface_toggle(widget, faceid, radians, faceids => {
|
||||
// surfaces[widget.id] = faceids;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
surfaceOn = env.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 faceid = min / 3;
|
||||
let widget = lastWidget = obj.object.widget;
|
||||
CAM.surface_toggle(widget, faceid, radians, faceids => {
|
||||
surfaces[widget.id] = faceids;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function surfaceDone() {
|
||||
if (!(surfaceOn && env.poppedRec && env.poppedRec.surfaces)) {
|
||||
return;
|
||||
}
|
||||
let surfaces = env.poppedRec.surfaces;
|
||||
for (let wid of Object.keys(surfaces)) {
|
||||
let widget = api.widgets.forid(wid);
|
||||
if (widget) {
|
||||
CAM.surface_clear(widget);
|
||||
} else {
|
||||
delete surfaces[wid];
|
||||
}
|
||||
}
|
||||
api.hide.alert(alert);
|
||||
api.feature.on_mouse_up = undefined;
|
||||
surfaceOn.classList.remove("editing");
|
||||
surfaceOn = false;
|
||||
}
|
||||
0
src2/kiri-mode/cam/cl-tab.js
Normal file
0
src2/kiri-mode/cam/cl-tab.js
Normal file
181
src2/kiri-mode/cam/cl-trace.js
Normal file
181
src2/kiri-mode/cam/cl-trace.js
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
import { api } from '../../kiri/api.js';
|
||||
import { env } from './client.js';
|
||||
import { CAM } from './driver-fe.js';
|
||||
import { Layers } from '../../kiri/layers.js';
|
||||
import { Stack } from '../../kiri/stack.js';
|
||||
|
||||
export let traceOn = false;
|
||||
export let lastTrace;
|
||||
|
||||
export function setLastTrace(trace) {
|
||||
lastTrace = trace;
|
||||
}
|
||||
|
||||
export function traceAdd(ev) {
|
||||
if (traceOn) {
|
||||
return traceDone();
|
||||
}
|
||||
env.clearPops();
|
||||
alert = api.show.alert("analyzing parts...", 1000);
|
||||
traceOn = env.hoveredOp;
|
||||
traceOn.classList.add("editing");
|
||||
api.feature.hover = true;
|
||||
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');
|
||||
}
|
||||
|
||||
export function traceDone() {
|
||||
if (!traceOn) {
|
||||
return;
|
||||
}
|
||||
env.func.unpop();
|
||||
traceOn.classList.remove("editing");
|
||||
traceOn = false;
|
||||
api.widgets.opacity(1);
|
||||
api.hide.alert(alert);
|
||||
api.feature.hover = false;
|
||||
api.feature.hoverAdds = false;
|
||||
api.widgets.for(widget => {
|
||||
widget.restoreVisualState();
|
||||
if (widget.trace_stack) {
|
||||
widget.trace_stack.hide();
|
||||
widget.adds.removeAll(widget.trace_stack.meshes);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function traceHover(data) {
|
||||
if (lastTrace) {
|
||||
let { color, colorSave } = lastTrace.material[0] || lastTrace.material;
|
||||
color.r = colorSave.r;
|
||||
color.g = colorSave.g;
|
||||
color.b = colorSave.b;
|
||||
}
|
||||
lastTrace = null;
|
||||
if (data.type === 'platform') {
|
||||
return;
|
||||
}
|
||||
if (!data.int.object.trace) {
|
||||
return;
|
||||
}
|
||||
lastTrace = data.int.object;
|
||||
if (lastTrace.selected) {
|
||||
let event = data.event;
|
||||
let target = event.target;
|
||||
let { clientX, clientY } = event;
|
||||
let { offsetWidth, offsetHeight } = target;
|
||||
}
|
||||
let material = lastTrace.material[0] || lastTrace.material;
|
||||
let color = material.color;
|
||||
material.colorSave = color.clone();
|
||||
color.setHex(env.isDark() ? 0x0066ff : 0x0000ff);
|
||||
}
|
||||
|
||||
export function traceHoverUp(int, ev) {
|
||||
if (!int) return;
|
||||
let { object } = int;
|
||||
traceToggle(object);
|
||||
if (ev.metaKey || ev.ctrlKey) {
|
||||
let { selected } = object;
|
||||
let { widget, poly } = object.trace;
|
||||
let avgZ = poly.avgZ();
|
||||
for (let add of widget.adds) {
|
||||
if (add.trace && add.selected !== selected && add.trace.poly.onZ(avgZ)) {
|
||||
traceToggle(add);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function traceToggle(obj, skip) {
|
||||
let material = obj.material[0] || obj.material;
|
||||
if (!material) return;
|
||||
let { color, colorSave } = material;
|
||||
let { widget, poly } = obj.trace;
|
||||
let areas = env.poppedRec.areas;
|
||||
if (!areas) {
|
||||
return;
|
||||
}
|
||||
let wlist = areas[widget.id] = areas[widget.id] || [];
|
||||
obj.selected = !obj.selected;
|
||||
if (!colorSave) {
|
||||
colorSave = material.colorSave = color.clone();
|
||||
}
|
||||
if (obj.selected) {
|
||||
color.setHex(env.isDark() ? 0xdd0011 : 0xff0033);
|
||||
colorSave.r = color.r;
|
||||
colorSave.g = color.g;
|
||||
colorSave.b = color.b;
|
||||
if (!skip) wlist.push(poly._trace);
|
||||
} else {
|
||||
color.setHex(0xaaaa55);
|
||||
colorSave.setHex(0xaaaa55);
|
||||
if (!skip) wlist.remove(poly._trace);
|
||||
}
|
||||
api.conf.save();
|
||||
}
|
||||
|
||||
export function unselectTraces(widget, skip) {
|
||||
if (widget.trace_stack) {
|
||||
widget.trace_stack.meshes.forEach(mesh => {
|
||||
if (mesh.selected) {
|
||||
traceToggle(mesh, skip);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue