add cam origin selector. fix wasm newpoly

This commit is contained in:
Stewart Allen 2025-07-10 16:54:02 -04:00
commit 5532cf28e4
12 changed files with 277 additions and 132 deletions

90
app.js
View file

@ -72,11 +72,6 @@ function init(mod) {
dversion = debug ? `_${version}` : version;
forceUseCache = ENV.cache ? true : false;
const approot = PATH.join("main","gapp");
const refcache = {};
const callstack = [];
let xxxx = false;
if (!ENV.electron) {
generateDevices();
}
@ -116,8 +111,6 @@ function init(mod) {
});
}
mod.add(rewriteHtmlVersion);
// example of how to use the new middleware
// mod.add(appendContent('/kiri/index.html', '<script>console.log("hello")</script>'));
mod.static("/lib/", "src");
mod.static("/obj/", "web/obj");
mod.static("/font/", "web/font");
@ -126,8 +119,8 @@ function init(mod) {
mod.static("/moto/", "web/moto");
mod.static("/kiri/", "web/kiri");
// module loader
function load_modules(root, force) {
// load modules
lastmod(`${dir}/${root}`) && fs.readdirSync(`${dir}/${root}`).forEach(mdir => {
const modpath = `${root}/${mdir}`;
if (dir.charAt(0) === '.' && !ENV.single) return;
@ -152,7 +145,7 @@ function init(mod) {
// load optional local modules
load_modules('mods');
// run loads injected by modules
// run load functions injected by modules
while (load.length) {
try {
load.shift()();
@ -161,7 +154,7 @@ function init(mod) {
}
}
// minify appends
// minify appends in production mode
if (!debug) {
for (let key of Object.keys(append)) {
append[key] = minify(append[key]);
@ -189,14 +182,14 @@ function initModule(mod, file, dir) {
// express functions added here show up at "/api/" url root
api: api,
adm: {
setver: (ver) => { oversion = ver },
crossOrigin: (bool) => { crossOrigin = bool }
setver(ver) { oversion = ver },
crossOrigin(bool) { crossOrigin = bool }
},
events,
const: {
args: {},
meta: mod.meta,
debug: debug,
debug,
moddir: dir,
rootdir: mod.dir,
version: oversion || version
@ -209,35 +202,21 @@ function initModule(mod, file, dir) {
},
mod: mods,
util: {
guid,
time,
log: logger.log,
time: time,
guid: guid,
logger: log.new,
mkdirs: util.mkdir,
isfile: util.isfile,
confdir: util.confdir,
datadir: util.datadir,
lastmod: lastmod,
obj2string: obj2string,
string2obj: string2obj,
isfile: util.isfile,
getCookieValue: cookieValue,
logger: log.new
},
inject: (code, file, opt = {}) => {
const path = mod.dir + '/' + dir + '/' + file;
try {
const body = fs.readFileSync(path);
// console.log({ inject: code, file, opt });
if (opt.first) {
append[code] = body.toString() + '\n' + append[code];
} else {
append[code] += body.toString() + '\n';
}
} catch (e) {
console.log({ missing_file: path, dir, mod });
}
obj2string(o) { return JSON.stringify(o) },
string2obj(s) { return JSON.parse(s) },
},
path: {
any: arg => { mod.add(arg) },
any(arg) { mod.add(arg) },
code() {
const [ path, file ] = [ ...arguments ];
if (lastmod(file)) {
@ -251,13 +230,13 @@ function initModule(mod, file, dir) {
console.log({ MISSING_CODE: path, file });
}
},
full: arg => { mod.add(fullpath(arg)) },
map: arg => { mod.add(fixedmap(arg)) },
pre: arg => { mod.add(prepath(arg)) },
full(arg) { mod.add(fullpath(arg)) },
map(arg) { mod.add(fixedmap(arg)) },
pre(arg) { mod.add(prepath(arg)) },
redir: redir,
remap: remap,
setup: fn => { setupFn = fn },
static: (root, pre) => {
setup(fn) { setupFn = fn },
static(root, pre) {
mod.static(pre || "/", root);
},
},
@ -271,22 +250,29 @@ function initModule(mod, file, dir) {
ws: {
register: mod.wss
},
onload: (fn) => {
inject(code, file, opt = {}) {
const path = mod.dir + '/' + dir + '/' + file;
try {
const body = fs.readFileSync(path);
// console.log({ inject: code, file, opt });
if (opt.first) {
append[code] = body.toString() + '\n' + append[code];
} else {
append[code] += body.toString() + '\n';
}
} catch (e) {
console.log({ missing_file: path, dir, mod });
}
},
onload(fn) {
load.push(fn);
},
onexit: (fn) => {
onexit(fn) {
mod.on.exit(fn);
}
});
}
// prevent caching of specified modules
const cachever = {};
function promise(resolve, reject) {
return new Promise(resolve, reject);
}
function rval() {
return (Math.round(Math.random()*0xffffffff)).toString(36);
}
@ -299,14 +285,6 @@ function time() {
return Date.now();
}
function obj2string(o) {
return JSON.stringify(o);
}
function string2obj(s) {
return JSON.parse(s);
}
function handleSetup(req, res, next) {
if (setupFn) {
setupFn(req, res, next);

View file

@ -1117,6 +1117,14 @@ export class Polygon {
return this.first().isEqual(this.last());
}
fixClosed() {
if (this.appearsClosed()) {
this.points.pop();
this.open = false;
}
return this;
}
setClockwise() {
if (!this.isClockwise()) this.reverse();
return this;

View file

@ -1,9 +1,9 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { base } from '../geo/base.js';
import { newPolygon } from './polygon.js';
const { config } = base;
const factor = config.clipper;
export const wasm_ctrl = {
@ -54,7 +54,7 @@ function writePoly(view, poly, inner) {
function readPoly(view, z) {
let points = view.readU16(true);
if (points === 0) return;
let poly = base.newPolygon();
let poly = newPolygon();
while (points-- > 0) {
poly.add(view.readI32(true)/factor, view.readI32(true)/factor, z || 0);
}

View file

@ -6,7 +6,7 @@ import STACKS from './stacks.js';
import { broker } from '../../moto/broker.js';
import { client as work } from './client.js';
import { consts, COLOR as color, LISTS as lists, MODES, VIEWS, PATHS } from './consts.js';
import { consts, COLOR as color, LISTS as lists } from './consts.js';
import { device, devices } from './devices.js';
import { catalog, dialog, event, group, help, hide, image } from './main.js';
import { modal, mode, probe, process, show, space, util, view } from './main.js';

View file

@ -2,6 +2,9 @@
import { api } from './api.js';
import { noop } from './utils.js';
import { codec } from './codec.js';
import { Widget } from './widget.js';
import { newPrint } from './print.js';
// this code runs in kiri's main loop
let debug = self.debug === true,
@ -199,7 +202,7 @@ export const client = {
send("rotate", { settings }, reply => {
if (reply.group) {
// collect post-rotation data for slice/preview renders
for (let widget of kiri.Widget.Groups.forid(reply.group)) {
for (let widget of Widget.Groups.forid(reply.group)) {
widget.belt = reply.belt;
}
} else if (callback) {
@ -280,10 +283,10 @@ export const client = {
y: -origin.y,
z: origin.z
};
const output = kiri.newPrint().parseSVG(code, offset);
const output = newPrint().parseSVG(code, offset);
send("parse_svg", output, reply => {
if (reply.parsed) {
done(kiri.codec.decode(reply.parsed));
done(codec.decode(reply.parsed));
}
});
return;
@ -293,7 +296,7 @@ export const client = {
progress(reply.progress);
}
if (reply.parsed) {
done(kiri.codec.decode(reply.parsed), reply.maxSpeed, reply.minSpeed);
done(codec.decode(reply.parsed), reply.maxSpeed, reply.minSpeed);
}
});
},

View file

@ -16,6 +16,7 @@ import { init as initLaser } from '../mode/laser/client.js';
import { init as initSLA } from '../mode/sla/client.js';
import { init as initWEDM } from '../mode/wedm/client.js';
import { init as initWJET } from '../mode/wjet/client.js';
import { menu as menuCAM } from '../mode/cam/init-menu.js';
let { CAM, SLA, FDM, LASER, DRAG, WJET, WEDM } = MODES,
{ client, catalog, platform, selection, stats } = api,
@ -123,11 +124,6 @@ function speedSave() {
api.view.update_speeds();
}
function zAnchorSave() {
api.conf.update();
api.platform.update_top_z();
}
function setThreaded(bool) {
if (bool) {
client.pool.start();
@ -234,6 +230,8 @@ function onBooleanClick(el) {
api.devices.update_laser_state();
}
api.event.on('click.boolean', onBooleanClick);
function onButtonClick(ev) {
let target = ev.target;
while (target && target.tagName !== 'BUTTON') {
@ -242,6 +240,8 @@ function onButtonClick(ev) {
api.event.emit("button.click", target);
}
api.event.on('click.button', onButtonClick);
function inputHasFocus() {
let active = DOC.activeElement;
return active && (active.nodeName === "INPUT" || active.nodeName === "TEXTAREA");
@ -1229,61 +1229,7 @@ function init_one() {
fdmRanges: $('fdm-ranges'),
/** CAM Settings */
_____: newGroup(LANG.ct_menu, $('cam-tabs'), { modes:CAM, marker:true, driven, separator }),
camTabsWidth: newInput(LANG.ct_wdth_s, {title:LANG.ct_wdth_l, convert:toFloat, bound:bound(0.005,100), units}),
camTabsHeight: newInput(LANG.ct_hght_s, {title:LANG.ct_hght_l, convert:toFloat, bound:bound(0.005,100), units}),
camTabsDepth: newInput(LANG.ct_dpth_s, {title:LANG.ct_dpth_l, convert:toFloat, bound:bound(0.005,100), units}),
separator: newBlank({ class:"set-sep", driven }),
camTabsMidline: newBoolean(LANG.ct_midl_s, onBooleanClick, {title:LANG.ct_midl_l}),
separator: newBlank({ class:"set-sep", driven }),
camTabsManual: newRow([
(ui.tabAdd = newButton(undefined, onButtonClick, {icon:'<i class="fas fa-plus"></i>'})),
(ui.tabDun = newButton(undefined, onButtonClick, {icon:'<i class="fas fa-check"></i>'})),
(ui.tabClr = newButton(undefined, onButtonClick, {icon:'<i class="fas fa-trash-alt"></i>'}))
], {class:"ext-buttons f-row"}),
_____: newGroup(LANG.cs_menu, $('cam-stock'), { modes:CAM, driven, separator }),
camStockX: newInput(LANG.cs_wdth_s, {title:LANG.cs_wdth_l, convert:toFloat, bound:bound(0,9999), units}),
camStockY: newInput(LANG.cs_dpth_s, {title:LANG.cs_dpth_l, convert:toFloat, bound:bound(0,9999), units}),
camStockZ: newInput(LANG.cs_hght_s, {title:LANG.cs_hght_l, convert:toFloat, bound:bound(0,9999), units}),
separator: newBlank({ class:"set-sep", driven }),
camStockOffset: newBoolean(LANG.cs_offs_s, onBooleanClick, {title:LANG.cs_offs_l}),
camStockClipTo: newBoolean(LANG.cs_clip_s, onBooleanClick, {title:LANG.cs_clip_l}),
camStockIndexed: newBoolean(LANG.cs_indx_s, onBooleanClick, {title:LANG.cs_indx_l}),
camStockIndexGrid: newBoolean(LANG.cs_ishg_s, onBooleanClick, {title:LANG.cs_ishg_l, show:() => ui.camStockIndexed.checked}),
_____: newGroup(LANG.cc_menu, $('cam-limits'), { modes:CAM, driven, separator }),
camZAnchor: newSelect(LANG.ou_zanc_s, {title: LANG.ou_zanc_l, action:zAnchorSave, show:() => !ui.camStockIndexed.checked}, "zanchor"),
camZOffset: newInput(LANG.ou_ztof_s, {title:LANG.ou_ztof_l, convert:toFloat, units}),
camZTop: newInput(LANG.ou_ztop_s, {title:LANG.ou_ztop_l, convert:toFloat, units, trigger}),
camZBottom: newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:toFloat, units, trigger}),
camZThru: newInput(LANG.ou_ztru_s, {title:LANG.ou_ztru_l, convert:toFloat, bound:bound(0.0,100), units }),
camZClearance: newInput(LANG.ou_zclr_s, {title:LANG.ou_zclr_l, convert:toFloat, bound:bound(0.01,100), units }),
camFastFeedZ: newInput(LANG.cc_rzpd_s, {title:LANG.cc_rzpd_l, convert:toFloat, units}),
camFastFeed: newInput(LANG.cc_rapd_s, {title:LANG.cc_rapd_l, convert:toFloat, units}),
_____: newGroup(LANG.ou_menu, $('cam-output'), { modes:CAM, driven, separator, group:"cam-output" }),
camConventional: newBoolean(LANG.ou_conv_s, onBooleanClick, {title:LANG.ou_conv_l}),
camEaseDown: newBoolean(LANG.cr_ease_s, onBooleanClick, {title:LANG.cr_ease_l}),
camDepthFirst: newBoolean(LANG.ou_depf_s, onBooleanClick, {title:LANG.ou_depf_l}),
camToolInit: newBoolean(LANG.ou_toin_s, onBooleanClick, {title:LANG.ou_toin_l}),
separator: newBlank({ class:"set-sep", driven }),
camFirstZMax: newBoolean(LANG.ou_z1st_s, onBooleanClick, {title:LANG.ou_z1st_l}),
camForceZMax: newBoolean(LANG.ou_forz_s, onBooleanClick, {title:LANG.ou_forz_l}),
separator: newBlank({ class:"set-sep", driven }),
camEaseAngle: newInput(LANG.ou_eang_s, {title:LANG.ou_eang_l, convert:toFloat, bound:bound(0.1,85), show:() => ui.camEaseDown.checked}),
camFullEngage: newInput(LANG.ou_feng_s, {title:LANG.ou_feng_l, convert:toFloat, bound:bound(0.1,1.0)}),
_____: newGroup(LANG.co_menu, $('cam-origin'), { modes:CAM, driven, separator }),
camOriginTop: newBoolean(LANG.or_topp_s, onBooleanClick, {title:LANG.or_topp_l}),
camOriginCenter: newBoolean(LANG.or_cntr_s, onBooleanClick, {title:LANG.or_cntr_l}),
separator: newBlank({ class:"set-sep", driven }),
camOriginOffX: newInput(LANG.co_offx_s, {title:LANG.co_offx_l, convert:toFloat, units}),
camOriginOffY: newInput(LANG.co_offy_s, {title:LANG.co_offy_l, convert:toFloat, units}),
camOriginOffZ: newInput(LANG.co_offz_s, {title:LANG.co_offz_l, convert:toFloat, units}),
_____: newGroup(LANG.op_xprt_s, $('cam-expert'), { group:"cam_expert", modes:CAM, marker: false, driven, separator }),
camExpertFast: newBoolean(LANG.cx_fast_s, onBooleanClick, {title:LANG.cx_fast_l, show: () => !ui.camTrueShadow.checked }),
camTrueShadow: newBoolean(LANG.cx_true_s, onBooleanClick, {title:LANG.cx_true_l, show: () => !ui.camExpertFast.checked }),
separator: newBlank({ class:"set-sep", driven }),
camArcTolerance: newInput(LANG.cx_arct_s, {title:LANG.cx_arct_l, convert:toFloat, units, bound:bound(0,100)}),
camArcResolution: newInput(LANG.cx_arcr_s, {title:LANG.cx_arcr_l, convert:toFloat, bound:bound(0,180), show:() => ui.camArcTolerance.value > 0}),
...menuCAM(),
/** LASER/DRAG/WJET/WEDM cut tool Settings */
@ -1367,6 +1313,8 @@ function init_one() {
});
// run client mode initializations right after UI is bound
// MUST run after main ui menu inits since they rely on passed state
// that createPopOps disrupts (should be refactored)
initCAM();
initDRAG();
initFDM();

View file

@ -95,6 +95,7 @@ export function createPopOp(type, map) {
return op.rec === rec;
},
bind: (ev) => {
console.log({ bind: type, map, op });
api.util.ui2rec(op.rec, op.inputs);
const settings = conf.get();

View file

@ -0,0 +1,114 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { api } from '../../core/api.js';
import { env, clearPops } from './client.js';
import { CAM } from './driver-fe.js';
import { config } from '../../../geo/base.js';
import { addbox, delbox } from '../../core/boxes.js';
export let originSelectOn = false;
let { world } = api.SPACE;
let alert, lastHover, lastPoints;
export function originSelect() {
if (originSelectOn) {
return originSelectDone();
}
clearPops();
alert = api.show.alert("analyzing parts...", 1000);
originSelectOn = true;
api.feature.hover = true;
api.feature.hoverAdds = true;
env.hover = pointHover;
env.hoverUp = pointHoverUp;
CAM.traces((ids) => {
api.hide.alert(alert);
alert = api.show.alert("select origin<br>[esc] to cancel", 1000);
let points = {};
let color = new THREE.Color( 0xff0000 );
api.widgets.for(widget => {
let { pos, tzoff } = widget.track;
let { adds, traces } = widget;
let polys = traces.map(trace => {
return trace.fixClosed().clone().move(pos).move({ x:0, y:0, z: -tzoff });
});
for (let poly of polys) {
if (poly.circularity() >= config.hint_min_circ) {
let center = poly.calcCircleCenter();
if (points[center.key]) {
continue;
}
let box = addbox(center, color, center.key, undefined, { opacity: 1 });
adds.push(box);
world.add(box);
box._origin = center;
points[center.key] = { box, center };
}
}
});
lastPoints = Object.values(points);
});
}
export function originSelectDone() {
if (!originSelectOn) {
return;
}
api.hide.alert(alert);
api.feature.hover = false;
api.feature.hoverAdds = false;
api.widgets.for(widget => {
for (let box of widget.adds) {
world.remove(box);
}
widget.adds.length = 0;
});
originSelectOn = false;
}
function pointHover(data) {
if (lastHover) {
let { color, colorSave } = lastHover.material[0] || lastHover.material;
color.r = colorSave.r;
color.g = colorSave.g;
color.b = colorSave.b;
}
lastHover = null;
if (data.type === 'platform') {
return;
}
if (!data.int.object._origin) {
return;
}
lastHover = data.int.object;
let material = lastHover.material[0] || lastHover.material;
let color = material.color;
material.colorSave = color.clone();
color.setHex(0x00ff00);
}
function pointHoverUp(int, ev) {
if (!int?.object?._origin) return;
let { _origin } = int.object;
let { process, stock } = api.conf.get();
let { x, y, z } = _origin;
let { camOriginTop, camOriginCenter } = process;
if (camOriginTop) {
z = z - stock.z;
}
if (!camOriginCenter) {
x += stock.x / 2;
y += stock.y / 2;
}
process.camOriginOffX = x;
process.camOriginOffY = y;
process.camOriginOffZ = z;
api.settings.update_fields();
api.platform.update_origin();
originSelectDone();
}

View file

@ -1,7 +1,7 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { api } from '../../core/api.js';
import { env, clearPops } from './client.js';
import { env, clearPops, isDark } from './client.js';
import { CAM } from './driver-fe.js';
import { Layers } from '../../core/layers.js';
import { Stack } from '../../core/stack.js';
@ -123,7 +123,7 @@ export function traceHover(data) {
let material = lastTrace.material[0] || lastTrace.material;
let color = material.color;
material.colorSave = color.clone();
color.setHex(env.isDark() ? 0x0066ff : 0x0000ff);
color.setHex(isDark() ? 0x0066ff : 0x0000ff);
}
export function traceHoverUp(int, ev) {
@ -157,7 +157,7 @@ export function traceToggle(obj, skip) {
colorSave = material.colorSave = color.clone();
}
if (obj.selected) {
color.setHex(env.isDark() ? 0xdd0011 : 0xff0033);
color.setHex(isDark() ? 0xdd0011 : 0xff0033);
colorSave.r = color.r;
colorSave.g = color.g;
colorSave.b = color.b;

View file

@ -1,6 +1,6 @@
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { $, h } from '../../../moto/webui.js';
import { $ } from '../../../moto/webui.js';
import { api } from '../../core/api.js';
import { load } from '../../../load/file.js';
import { animate as anim_2d, animate_clear as anim_2d_clear } from './anim-2d-fe.js';
@ -14,13 +14,14 @@ import { tabAdd, tabDone, tabClear, restoreTabs, updateTabs } from './cl-tab.js'
import { traceOn, traceDone, unselectTraces } from './cl-trace.js';
import { holeSelOn, selectHolesDone, clearHolesRec } from './cl-hole.js';
import { surfaceOn, surfaceDone } from './cl-surface.js';
import { originSelectDone } from './cl-origin.js';
const DEG2RAD = Math.PI / 180;
const RAD2DEG = 180 / Math.PI;
const hasSharedArrays = self.SharedArrayBuffer ? true : false;
const { VIEWS, STACKS } = api.const;
const { noop, space } = api;
const { noop } = api;
const { ui: UI, uc: UC } = api;
const { widgets: WIDGETS } = api;
@ -54,10 +55,11 @@ export function isDark() {
export function clearPops() {
if (env.func.unpop) env.func.unpop();
originSelectDone();
selectHolesDone();
surfaceDone();
tabDone();
traceDone();
surfaceDone();
selectHolesDone();
}
function animFn() {

View file

@ -0,0 +1,92 @@
import { api } from '../../core/api.js';
import { originSelect } from './cl-origin.js';
let LANG = api.language.current;
let { CAM } = api.const.MODES,
{ $ } = api.web,
{ uc, ui } = api,
{ bound, toInt, toFloat } = uc,
{ newBlank, newButton, newBoolean, newGroup, newInput } = uc,
{ newSelect, newLabel, newValue, newRow, newGCode, newDiv } = uc,
driven = true,
separator = true,
trigger = true,
units = true
;
function onBooleanClick(el) {
api.event.emit('click.boolean', el);
}
function onButtonClick(el) {
api.event.emit('click.button', el);
}
function zAnchorSave() {
api.conf.update();
api.platform.update_top_z();
}
export function menu() {
return {
_____: newGroup(LANG.ct_menu, $('cam-tabs'), { modes:CAM, marker:true, driven, separator }),
camTabsWidth: newInput(LANG.ct_wdth_s, {title:LANG.ct_wdth_l, convert:toFloat, bound:bound(0.005,100), units}),
camTabsHeight: newInput(LANG.ct_hght_s, {title:LANG.ct_hght_l, convert:toFloat, bound:bound(0.005,100), units}),
camTabsDepth: newInput(LANG.ct_dpth_s, {title:LANG.ct_dpth_l, convert:toFloat, bound:bound(0.005,100), units}),
separator: newBlank({ class:"set-sep", driven }),
camTabsMidline: newBoolean(LANG.ct_midl_s, onBooleanClick, {title:LANG.ct_midl_l}),
separator: newBlank({ class:"set-sep", driven }),
camTabsManual: newRow([
(ui.tabAdd = newButton(undefined, onButtonClick, {icon:'<i class="fas fa-plus"></i>'})),
(ui.tabDun = newButton(undefined, onButtonClick, {icon:'<i class="fas fa-check"></i>'})),
(ui.tabClr = newButton(undefined, onButtonClick, {icon:'<i class="fas fa-trash-alt"></i>'}))
], {class:"ext-buttons f-row"}),
_____: newGroup(LANG.cs_menu, $('cam-stock'), { modes:CAM, driven, separator }),
camStockX: newInput(LANG.cs_wdth_s, {title:LANG.cs_wdth_l, convert:toFloat, bound:bound(0,9999), units}),
camStockY: newInput(LANG.cs_dpth_s, {title:LANG.cs_dpth_l, convert:toFloat, bound:bound(0,9999), units}),
camStockZ: newInput(LANG.cs_hght_s, {title:LANG.cs_hght_l, convert:toFloat, bound:bound(0,9999), units}),
separator: newBlank({ class:"set-sep", driven }),
camStockOffset: newBoolean(LANG.cs_offs_s, onBooleanClick, {title:LANG.cs_offs_l}),
camStockClipTo: newBoolean(LANG.cs_clip_s, onBooleanClick, {title:LANG.cs_clip_l}),
camStockIndexed: newBoolean(LANG.cs_indx_s, onBooleanClick, {title:LANG.cs_indx_l}),
camStockIndexGrid: newBoolean(LANG.cs_ishg_s, onBooleanClick, {title:LANG.cs_ishg_l, show:() => ui.camStockIndexed.checked}),
_____: newGroup(LANG.cc_menu, $('cam-limits'), { modes:CAM, driven, separator }),
camZAnchor: newSelect(LANG.ou_zanc_s, {title: LANG.ou_zanc_l, action:zAnchorSave, show:() => !ui.camStockIndexed.checked}, "zanchor"),
camZOffset: newInput(LANG.ou_ztof_s, {title:LANG.ou_ztof_l, convert:toFloat, units}),
camZTop: newInput(LANG.ou_ztop_s, {title:LANG.ou_ztop_l, convert:toFloat, units, trigger}),
camZBottom: newInput(LANG.ou_zbot_s, {title:LANG.ou_zbot_l, convert:toFloat, units, trigger}),
camZThru: newInput(LANG.ou_ztru_s, {title:LANG.ou_ztru_l, convert:toFloat, bound:bound(0.0,100), units }),
camZClearance: newInput(LANG.ou_zclr_s, {title:LANG.ou_zclr_l, convert:toFloat, bound:bound(0.01,100), units }),
camFastFeedZ: newInput(LANG.cc_rzpd_s, {title:LANG.cc_rzpd_l, convert:toFloat, units}),
camFastFeed: newInput(LANG.cc_rapd_s, {title:LANG.cc_rapd_l, convert:toFloat, units}),
_____: newGroup(LANG.ou_menu, $('cam-output'), { modes:CAM, driven, separator, group:"cam-output" }),
camConventional: newBoolean(LANG.ou_conv_s, onBooleanClick, {title:LANG.ou_conv_l}),
camEaseDown: newBoolean(LANG.cr_ease_s, onBooleanClick, {title:LANG.cr_ease_l}),
camDepthFirst: newBoolean(LANG.ou_depf_s, onBooleanClick, {title:LANG.ou_depf_l}),
camToolInit: newBoolean(LANG.ou_toin_s, onBooleanClick, {title:LANG.ou_toin_l}),
separator: newBlank({ class:"set-sep", driven }),
camFirstZMax: newBoolean(LANG.ou_z1st_s, onBooleanClick, {title:LANG.ou_z1st_l}),
camForceZMax: newBoolean(LANG.ou_forz_s, onBooleanClick, {title:LANG.ou_forz_l}),
separator: newBlank({ class:"set-sep", driven }),
camEaseAngle: newInput(LANG.ou_eang_s, {title:LANG.ou_eang_l, convert:toFloat, bound:bound(0.1,85), show:() => ui.camEaseDown.checked}),
camFullEngage: newInput(LANG.ou_feng_s, {title:LANG.ou_feng_l, convert:toFloat, bound:bound(0.1,1.0)}),
_____: newGroup(LANG.co_menu, $('cam-origin'), { modes:CAM, driven, separator }),
camOriginTop: newBoolean(LANG.or_topp_s, onBooleanClick, {title:LANG.or_topp_l}),
camOriginCenter: newBoolean(LANG.or_cntr_s, onBooleanClick, {title:LANG.or_cntr_l}),
separator: newBlank({ class:"set-sep", driven }),
camOriginOffX: newInput(LANG.co_offx_s, {title:LANG.co_offx_l, convert:toFloat, units}),
camOriginOffY: newInput(LANG.co_offy_s, {title:LANG.co_offy_l, convert:toFloat, units}),
camOriginOffZ: newInput(LANG.co_offz_s, {title:LANG.co_offz_l, convert:toFloat, units}),
separator: newBlank({ class:"set-sep", driven }),
camOriginSelect: newRow([ newButton("select", originSelect)], { class: "ext-buttons f-row" }),
_____: newGroup(LANG.op_xprt_s, $('cam-expert'), { group:"cam_expert", modes:CAM, marker: false, driven, separator }),
camExpertFast: newBoolean(LANG.cx_fast_s, onBooleanClick, {title:LANG.cx_fast_l, show: () => !ui.camTrueShadow.checked }),
camTrueShadow: newBoolean(LANG.cx_true_s, onBooleanClick, {title:LANG.cx_true_l, show: () => !ui.camExpertFast.checked }),
separator: newBlank({ class:"set-sep", driven }),
camArcTolerance: newInput(LANG.cx_arct_s, {title:LANG.cx_arct_l, convert:toFloat, units, bound:bound(0,100)}),
camArcResolution: newInput(LANG.cx_arcr_s, {title:LANG.cx_arcr_l, convert:toFloat, bound:bound(0,180), show:() => ui.camArcTolerance.value > 0}),
};
};

View file

@ -398,7 +398,7 @@ export function addDogbones(poly, dist, reverse) {
}
};
export async function traces(settings, widget, single) {
export async function traces(settings, widget) {
if (widget.traces) {
return false;
}
@ -534,7 +534,6 @@ export async function holes(settings, widget, individual, rec, onProgress) {
// keeps the z bottom relative to the part when z align changes
zBottom = isIndexed ? camZBottom : camZBottom - zbOff;
let slicerOpts = { flatoff: 0.001 }
let slicer = new cam_slicer(widget, slicerOpts);
let zFlats = Object.keys(slicer.zFlat).map(Number).map(z => [z, z - 0.002]).flat()