grid-apps-cmms/src/mode/cam/client.js

877 lines
32 KiB
JavaScript
Raw Normal View History

2020-11-05 18:29:04 -05:00
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
"use strict";
(function() {
let KIRI = self.kiri,
BASE = self.base,
2020-11-05 18:29:04 -05:00
CAM = KIRI.driver.CAM,
PRO = CAM.process,
newPolygon = BASE.newPolygon,
2020-11-14 11:12:12 -05:00
newPoint = BASE.newPoint,
2020-12-01 19:54:54 -05:00
toolInfo,
2020-11-24 11:01:29 -05:00
isAnimate,
2020-11-14 11:12:12 -05:00
isArrange,
isCamMode,
isParsed,
2020-11-14 11:12:12 -05:00
camStock,
2020-12-01 18:19:28 -05:00
current,
API, FDM, SPACE, STACKS, MODES, VIEWS, UI, UC, LANG;
2020-11-05 18:29:04 -05:00
let traceOp = { type: "trace" },
zaxis = { x: 0, y: 0, z: 1 },
2020-11-25 16:46:51 -05:00
func = {};
CAM.restoreTabs = restoreTabs;
2020-11-05 18:29:04 -05:00
CAM.init = function(kiri, api) {
2020-11-25 15:26:24 -05:00
FDM = KIRI.driver.FDM;
2020-11-14 11:12:12 -05:00
// console.log({kiri,api})
STACKS = api.const.STACKS;
2020-11-14 11:12:12 -05:00
SPACE = api.const.SPACE;
MODES = api.const.MODES;
VIEWS = api.const.VIEWS;
LANG = api.const.LANG;
2020-11-14 11:12:12 -05:00
UI = api.ui;
UC = api.uc;
API = api;
2020-12-01 19:54:54 -05:00
toolInfo = $('tool-info');
// wire up animate button in ui
api.function.animate = () => {
api.function.prepare(() => {
if (isCamMode && camStock) {
animate();
}
});
};
2020-11-05 18:29:04 -05:00
api.event.on("mode.set", (mode) => {
2020-11-14 11:12:12 -05:00
isCamMode = mode === 'CAM';
$('set-tools').style.display = isCamMode ? '' : 'none';
$('set-label').innerText = isCamMode ? "" : LANG.settings;
2020-11-14 11:12:12 -05:00
kiri.space.platform.setColor(isCamMode ? 0xeeeeee : 0xcccccc);
updateStock(undefined, 'internal');
2020-12-01 00:35:25 -05:00
if (!isCamMode) {
func.tabClear();
func.traceDone();
UI.func.animate.style.display = 'none';
UI.label.slice.innerText = 'slice';
UI.label.preview.innerText = 'preview';
UI.label.export.innerText = 'export';
} else {
UI.label.slice.innerText = 'start';
checkOutlineSettings(api.conf.get());
2020-12-01 00:35:25 -05:00
}
2020-12-01 18:19:28 -05:00
// do not persist traces across page reloads
func.traceClear();
func.opRender();
2020-11-14 11:12:12 -05:00
});
api.event.on("view.set", (mode) => {
isArrange = (mode === VIEWS.ARRANGE);
2020-11-24 11:01:29 -05:00
isAnimate = false;
CAM.animate_clear(api);
2020-12-01 00:35:25 -05:00
func.tabDone();
func.traceDone();
func.opRender();
2020-11-05 18:29:04 -05:00
});
2020-11-14 11:12:12 -05:00
function checkOutlineSettings(settings) {
let ui = api.ui, proc = settings.process;
// fix invalid in/out enabled condition
if (ui.camOutlineIn.checked && ui.camOutlineOut.checked) {
proc.camOutlineIn = proc.camOutlineOut = false;
ui.camOutlineIn.checked = ui.camOutlineOut.checked = false;
api.uc.refresh();
}
}
2020-11-05 18:29:04 -05:00
api.event.on("settings.saved", (settings) => {
2020-12-01 18:19:28 -05:00
current = settings;
let proc = settings.process;
2020-11-30 12:58:13 -05:00
let hasTabs = false;
let hasTraces = false;
// ensure trace op is a singleton for now
for (let i=0; i<proc.ops.length; i++) {
if (proc.ops[i].type === "trace") {
proc.ops[i] = traceOp;
}
}
2020-11-30 12:58:13 -05:00
// for any tabs or traces to set markers
Object.keys(settings.widget).forEach(wid => {
let wannot = settings.widget[wid];
if (wannot.tab && wannot.tab.length) hasTabs = true;
if (wannot.trace && wannot.trace.length) hasTraces = true;
});
checkOutlineSettings(settings);
2020-11-14 11:12:12 -05:00
// show/hide dots in enabled process pop buttons
2020-11-30 12:58:13 -05:00
api.ui.camTabs.marker.style.display = hasTabs ? 'flex' : 'none';
api.ui.camStock.marker.style.display = proc.camStockOn ? 'flex' : 'none';
2020-11-14 11:12:12 -05:00
updateStock(settings, 'settings.saved.internal');
2020-11-05 18:29:04 -05:00
});
2020-11-25 16:46:51 -05:00
api.event.on("settings.load", (settings) => {
func.opRender();
2020-11-25 16:46:51 -05:00
if (!isCamMode) return;
restoreTabs(api.widgets.all());
});
2020-11-14 11:12:12 -05:00
api.event.on([
"init-done",
// update stock when modes change?
"slice.end",
"preview.end",
// update stock when preferences change
// "boolean.click",
"boolean.update",
// update stock when objects move
"platform.layout",
"selection.drag",
"selection.move",
// force bounds update, too
"selection.scale",
"selection.rotate"
], updateStock);
api.event.on("preview.end", () => {
isParsed = false;
2020-11-25 15:26:24 -05:00
if (isCamMode && camStock) {
STACKS.getStack("bounds").button("animate", animate);
}
});
api.event.on("code.loaded", (info) => {
if (isCamMode && camStock) {
isParsed = true;
STACKS.getStack("parse", SPACE.platform.world).button("animate", animate);
}
});
2020-11-25 15:26:24 -05:00
2020-12-01 00:02:34 -05:00
// TAB/TRACE BUTTON HANDLERS
2020-11-25 15:26:24 -05:00
api.event.on("button.click", target => {
let settings = API.conf.get();
let { process, device } = settings;
let drill;
2020-11-25 15:26:24 -05:00
switch (target) {
case api.ui.tabAdd:
2020-11-30 12:58:13 -05:00
return func.tabAdd();
2020-11-25 15:26:24 -05:00
case api.ui.tabDun:
2020-11-30 12:58:13 -05:00
return func.tabDone();
2020-11-25 15:26:24 -05:00
case api.ui.tabClr:
api.uc.confirm("clear tabs?").then(ok => {
2020-11-30 12:58:13 -05:00
if (ok) func.tabClear();
});
break;
case api.ui.traceAdd:
return func.traceAdd();
case api.ui.traceDun:
return func.traceDone();
case api.ui.traceClr:
api.uc.confirm("clear traces?").then(ok => {
if (ok) func.traceClear();
2020-11-25 15:26:24 -05:00
});
break;
case api.ui.crAdd:
func.opAdd({
type: "rough",
tool: process.camRoughTool,
spindle: process.camRoughSpindle,
step: process.camRoughOver,
down: process.camRoughDown,
rate: process.camRoughSpeed,
plunge: process.camRoughPlunge,
leave: process.camRoughStock,
voids: process.camRoughVoid,
flats: process.camRoughFlat,
inside: process.camRoughIn,
top: process.camRoughTop
});
break;
case api.ui.coAdd:
func.opAdd({
type: "outline",
tool: process.camOutlineTool,
spindle: process.camOutlineSpindle,
down: process.camOutlineDown,
rate: process.camOutlineSpeed,
plunge: process.camOutlinePlunge,
dogbones: process.camOutlineDogbone,
outside: process.camOutlineOut,
inside: process.camOutlineIn,
wide: process.camOutlineWide
});
break;
case api.ui.ccxAdd:
func.opAdd({
type: "contour x",
tool: process.camContourTool,
spindle: process.camContourSpindle,
step: process.camContourOver,
rate: process.camContourSpeed,
angle: process.camContourAngle,
tolerance: process.camTolerance,
curves: process.camContourCurves,
inside: process.camContourIn
});
break;
case api.ui.ccyAdd:
func.opAdd({
type: "contour y",
tool: process.camContourTool,
spindle: process.camContourSpindle,
step: process.camContourOver,
rate: process.camContourSpeed,
angle: process.camContourAngle,
tolerance: process.camTolerance,
curves: process.camContourCurves,
inside: process.camContourIn
});
break;
case api.ui.drAdd:
func.opAdd({
type: "drill",
tool: process.camDrillTool,
spindle: process.camDrillSpindle,
down: process.camDrillDown,
rate: process.camDrillDownSpeed,
dwell: process.camDrillDwell,
lift: process.camDrillLift
});
break;
case api.ui.drX2Add:
drill = { axis: "x", points: 2 };
break;
case api.ui.drX3Add:
drill = { axis: "x", points: 3 };
break;
case api.ui.drY2Add:
drill = { axis: "y", points: 2 };
break;
case api.ui.drY3Add:
drill = { axis: "y", points: 3 };
break;
}
if (drill) {
func.opAdd({
type: "register",
tool: process.camDrillTool,
spindle: process.camDrillSpindle,
down: process.camDrillDown,
rate: process.camDrillDownSpeed,
dwell: process.camDrillDwell,
lift: process.camDrillLift,
points: drill.points,
axis: drill.axis
});
}
});
// OPS FUNCS
api.event.on("cam.op.add", func.opAdd = (rec) => {
let oplist = current.process.ops;
if (oplist.indexOf(rec) < 0) {
oplist.push(rec);
API.conf.save();
func.opRender();
}
});
api.event.on("cam.op.del", func.opDel = (rec) => {
let oplist = current.process.ops;
let pos = oplist.indexOf(rec);
if (pos >= 0) {
oplist.splice(pos,1);
API.conf.save();
func.opRender();
}
});
api.event.on("cam.op.render", func.opRender = () => {
$('camops').style.display = isCamMode && isArrange ? 'flex' : '';
if (!isCamMode) return;
let mark = Date.now();
let html = [];
let ops = current.process.ops;
let oplist = ops.length > 0 ? ops : [{
type: "use right menu to add milling operations ... drag & drop to re-order"
}];
let bind = {};
oplist.forEach((rec,i) => {
let title = Object.entries(rec).filter((v,i) => {
return v[0] !== 'type'
}).map(v => v.join(": ")).join("\n");
html.appendAll([
`<div id="${mark+i}">`,
title.length ? `<div class="opop">${title}</div>` : '',
`<label class="label">${rec.type}</label>`,
`<label id="${mark+i}-x" class="del"><i class="fas fa-times"></i></label>`,
`</div>`
]);
bind[mark+i] = rec;
});
let listel = $('oplist');
listel.innerHTML = html.join('');
let bounds = [];
for (let [id, rec] of Object.entries(bind)) {
$(`${id}-x`).onmousedown = (ev) => {
ev.stopPropagation();
ev.preventDefault();
};
$(`${id}-x`).onclick = (ev) => {
oplist.splice(oplist.indexOf(rec), 1);
API.conf.save();
func.opRender();
};
let el = $(id);
bounds.push(el);
el.rec = rec;
el.onmousedown = (ev) => {
let target = ev.target;
target.classList.add("drag");
ev.stopPropagation();
ev.preventDefault();
let tracker = UI.tracker;
tracker.style.display = 'block';
let cancel = tracker.onmouseup = (ev) => {
target.classList.remove("drag");
tracker.style.display = 'none';
if (ev) {
ev.stopPropagation();
ev.preventDefault();
}
ops.length = 0;
for (let child of listel.childNodes) {
ops.push(child.rec);
}
API.conf.save();
func.opRender();
};
tracker.onmousemove = (ev) => {
ev.stopPropagation();
ev.preventDefault();
if (ev.buttons === 0) {
return cancel();
}
for (let el of bounds) {
if (el === target) continue;
let rect = el.getBoundingClientRect();
let left = rect.left;
let right = rect.left + rect.width;
if (ev.pageX >= left && ev.pageX <= right) {
let mid = (left + right) / 2;
try { listel.removeChild(target); } catch (e) { }
el.insertAdjacentElement(ev.pageX < mid ? "beforebegin" : "afterend", target);
}
}
};
};
2020-11-25 15:26:24 -05:00
}
});
2020-12-01 00:02:34 -05:00
// TAB FUNCS
2020-11-30 18:46:56 -05:00
let showTab, lastTab, tab, iw, ic;
2020-11-30 12:58:13 -05:00
api.event.on("cam.tabs.add", func.tabAdd = () => {
2020-11-30 18:46:56 -05:00
func.traceDone();
2020-12-01 18:19:28 -05:00
alert = api.show.alert("[esc] key cancels tab editing");
2020-11-25 15:26:24 -05:00
api.feature.hover = true;
2020-11-30 18:46:56 -05:00
func.hover = func.tabHover;
func.hoverUp = func.tabHoverUp;
2020-11-25 15:26:24 -05:00
});
2020-11-30 12:58:13 -05:00
api.event.on("cam.tabs.done", func.tabDone = () => {
delbox('tabb');
2020-11-25 15:26:24 -05:00
api.hide.alert(alert);
api.feature.hover = false;
2020-12-01 00:35:25 -05:00
if (lastTab) {
lastTab.box.material.color.r = 0;
lastTab = null;
}
2020-11-25 15:26:24 -05:00
});
2020-11-30 12:58:13 -05:00
api.event.on("cam.tabs.clear", func.tabClear = () => {
func.tabDone();
API.widgets.all().forEach(widget => {
clearTabs(widget);
});
API.conf.save();
2020-11-25 15:26:24 -05:00
});
2020-11-30 18:46:56 -05:00
func.tabHover = function(data) {
delbox('tabb');
const { int, type, point } = data;
const object = int ? int.object : null;
const tab = int ? object.tab : null;
if (lastTab) {
lastTab.box.material.color.r = 0;
lastTab = null;
}
if (tab) {
tab.box.material.color.r = 0.5;
lastTab = tab;
return;
}
if (type !== 'widget') {
iw = null;
return;
}
let n = int.face.normal;
iw = int.object.widget;
ic = int.point;
// only near vertical faces
if (Math.abs(n.z) > 0.1) {
return;
}
showTab = createTabBox(iw, ic, n);
};
func.tabHoverUp = function(int) {
delbox('tabb');
if (lastTab) {
const {widget, box, id} = lastTab;
widget.adds.remove(box);
widget.mesh.remove(box);
delete widget.tabs[id];
let ta = API.widgets.annotate(widget.id).tab;
let ix = 0;
ta.forEach((rec,i) => {
if (rec.id === id) {
ix = i;
}
});
ta.splice(ix,1);
API.conf.save();
return;
}
if (!iw) return;
let ip = iw.track.pos;
let wa = api.widgets.annotate(iw.id);
let wt = (wa.tab = wa.tab || []);
let pos = {
x: showTab.pos.x - ip.x,
y: -showTab.pos.z - ip.y,
z: showTab.pos.y + ip.z,
}
let id = Date.now();
let { dim, rot } = showTab;
let rec = { pos, dim, rot, id };
wt.push(Object.clone(rec));
addWidgetTab(iw, rec);
API.conf.save();
};
2020-11-30 12:58:13 -05:00
2020-12-01 00:02:34 -05:00
// TRACE FUNCS
let traceOn = false, lastTrace;
2020-11-30 12:58:13 -05:00
api.event.on("cam.trace.add", func.traceAdd = () => {
2020-12-01 00:02:34 -05:00
if (traceOn) {
return;
}
2020-11-30 18:46:56 -05:00
func.tabDone();
alert = api.show.alert("analyzing parts...", 1000);
2020-12-01 00:02:34 -05:00
traceOn = true;
CAM.traces((ids) => {
2020-12-01 18:19:28 -05:00
api.hide.alert(alert);
alert = api.show.alert("[esc] key cancels trace editing");
2020-11-30 18:46:56 -05:00
KIRI.api.widgets.opacity(0.5);
2020-12-01 00:02:34 -05:00
KIRI.api.widgets.for(widget => {
2020-12-01 20:56:10 -05:00
if (ids.indexOf(widget.id) >= 0) {
clearTraces(widget);
widget.trace_stack = null;
}
2020-12-01 19:54:54 -05:00
if (widget.trace_stack) {
widget.adds.appendAll(widget.trace_stack.meshes);
widget.trace_stack.show();
return;
}
2020-12-01 00:02:34 -05:00
let stack = new KIRI.Stack(widget.mesh);
widget.trace_stack = stack;
2020-12-01 12:31:38 -05:00
widget.traces.forEach(poly => {
let layers = new KIRI.Layers();
layers.setLayer("trace", {line: 0x88aa55}, false).addPoly(poly);
stack.addLayers(layers);
2020-12-01 19:54:54 -05:00
stack.new_meshes.forEach(mesh => {
2020-12-01 18:19:28 -05:00
mesh.trace = {widget, poly};
});
2020-12-01 19:54:54 -05:00
widget.adds.appendAll(stack.new_meshes);
2020-11-30 18:46:56 -05:00
});
2020-12-01 14:22:19 -05:00
// for (let [key, val] of Object.entries(widget.sindex)) {
// console.log('sindex', {key, val});
// let layers = new KIRI.Layers();
// layers.setLayer("sindex", {line: 0x55aa88}, false).addPolys(val);
// stack.addLayers(layers);
// }
2020-11-30 18:46:56 -05:00
});
});
2020-11-30 12:58:13 -05:00
api.feature.hover = true;
2020-12-01 00:02:34 -05:00
api.feature.hoverAdds = true;
2020-11-30 18:46:56 -05:00
func.hover = func.traceHover;
func.hoverUp = func.traceHoverUp;
2020-11-30 12:58:13 -05:00
});
api.event.on("cam.trace.done", func.traceDone = () => {
2020-12-01 00:02:34 -05:00
if (!traceOn) {
return;
}
traceOn = false;
2020-11-30 18:46:56 -05:00
KIRI.api.widgets.opacity(1);
2020-11-30 12:58:13 -05:00
api.hide.alert(alert);
api.feature.hover = false;
2020-12-01 00:02:34 -05:00
api.feature.hoverAdds = false;
KIRI.api.widgets.for(widget => {
2020-12-01 18:19:28 -05:00
if (widget.trace_stack) {
2020-12-01 19:54:54 -05:00
widget.trace_stack.hide();
2020-12-01 18:19:28 -05:00
widget.adds.removeAll(widget.trace_stack.meshes);
}
2020-12-01 00:02:34 -05:00
});
toolInfo.style.display = '';
2020-11-30 12:58:13 -05:00
});
api.event.on("cam.trace.clear", func.traceClear = () => {
func.traceDone();
API.widgets.all().forEach(widget => {
clearTraces(widget);
});
API.conf.save();
});
2020-12-01 00:02:34 -05:00
func.traceHover = function(data) {
if (lastTrace) {
let { color, colorSave } = lastTrace.material[0];
color.r = colorSave.r;
color.g = colorSave.g;
color.b = colorSave.b;
}
if (data.type === 'platform') {
lastTrace = null;
return;
}
if (!data.int.object.trace) {
return;
}
2020-12-01 00:02:34 -05:00
lastTrace = data.int.object;
2020-12-01 19:54:54 -05:00
if (lastTrace.selected) {
let event = data.event;
let target = event.target;
let { clientX, clientY } = event;
let { offsetWidth, offsetHeight } = target;
toolInfo.style.right = `${offsetWidth - clientX + 5}px`;
toolInfo.style.bottom = `${offsetHeight - clientY + 5}px`;
2020-12-01 19:54:54 -05:00
let traceInfo = lastTrace.trace.poly.traceInfo;
let tool = new CAM.Tool(current, traceInfo.tool);
toolInfo.innerText = [
` tool: ${tool.getName()}`,
` feed: ${traceInfo.speed}`,
`plunge: ${traceInfo.plunge}`
].join('\n');
toolInfo.style.display = 'flex';
} else {
toolInfo.style.display = '';
}
2020-12-01 00:02:34 -05:00
let material = lastTrace.material[0];
let color = material.color;
let {r, g, b} = color;
material.colorSave = {r, g, b};
2020-12-01 18:19:28 -05:00
color.r = 1;
2020-12-01 00:02:34 -05:00
color.g = 0;
color.b = 0;
2020-11-30 18:46:56 -05:00
};
2020-12-01 00:02:34 -05:00
func.traceHoverUp = function(int) {
2020-12-01 18:19:28 -05:00
if (!int) return;
func.traceToggle(int.object);
};
func.traceToggle = function(obj) {
let material = obj.material[0];
let { color, colorSave } = material;
let { widget, poly } = obj.trace;
let wannot = API.widgets.annotate(widget.id);
let atrace = wannot.trace = wannot.trace || [];
let wtrace = widget.trace = widget.trace || [];
let process = current.process;
obj.selected = !obj.selected;
if (obj.selected) {
color.r = colorSave.r = 0.9;
color.g = colorSave.g = 0;
color.b = colorSave.b = 0.1;
poly.traceInfo = {
tool: process.camTraceTool,
speed: process.camTraceSpeed,
plunge: process.camTracePlunge,
path: KIRI.codec.encode(poly)
};
wtrace.push(poly);
atrace.push(poly.traceInfo);
} else {
color.r = colorSave.r = 0x88/255;
color.g = colorSave.g = 0xaa/255;
color.b = colorSave.b = 0x55/255;
wtrace.remove(poly);
atrace.remove(poly.traceInfo);
}
if (atrace.length) {
func.opAdd(traceOp);
} else {
func.opDel(traceOp);
}
2020-12-01 18:19:28 -05:00
API.conf.save();
2020-11-30 18:46:56 -05:00
};
2020-11-30 12:58:13 -05:00
2020-12-01 00:02:34 -05:00
// COMMON TAB/TRACE EVENT HANDLERS
2020-11-25 15:26:24 -05:00
api.event.on("slice.begin", () => {
if (isCamMode) {
2020-11-30 12:58:13 -05:00
func.tabDone();
func.traceDone();
2020-11-25 15:26:24 -05:00
}
});
api.event.on("key.esc", () => {
if (isCamMode) {
2020-11-30 12:58:13 -05:00
func.tabDone();
func.traceDone();
}
});
api.event.on("selection.scale", () => {
if (isCamMode) {
2020-11-30 12:58:13 -05:00
func.tabClear();
func.traceClear();
2020-11-25 15:26:24 -05:00
}
});
api.event.on("widget.rotate", rot => {
if (!isCamMode) {
return;
}
const {widget, x, y, z} = rot;
2020-12-01 18:19:28 -05:00
if (traceOn) {
func.traceDone();
}
clearTraces(widget);
2020-11-25 15:26:24 -05:00
if (x || y) {
2020-11-25 16:46:51 -05:00
clearTabs(widget);
2020-11-25 15:26:24 -05:00
} else {
2020-11-25 16:46:51 -05:00
let tabs = API.widgets.annotate(widget.id).tab || [];
tabs.forEach(rec => {
let { id, pos, rot } = rec;
2020-11-25 16:46:51 -05:00
let tab = widget.tabs[id];
let m4 = new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, 0, z || 0));
// update position vector
let vc = new THREE.Vector3(pos.x, pos.y, pos.z).applyMatrix4(m4);
// update rotation quaternion
rec.rot = new THREE.Quaternion().multiplyQuaternions(
new THREE.Quaternion(rot._x, rot._y, rot._z, rot._w),
new THREE.Quaternion().setFromRotationMatrix(m4)
);
2020-11-25 16:46:51 -05:00
tab.box.geometry.applyMatrix4(m4);
tab.box.position.x = pos.x = vc.x;
tab.box.position.y = pos.y = vc.y;
tab.box.position.z = pos.z = vc.z;
});
SPACE.update();
2020-11-25 15:26:24 -05:00
}
});
api.event.on("mouse.hover.up", int => {
if (!isCamMode) {
return;
}
2020-11-30 18:46:56 -05:00
func.hoverUp(int);
2020-11-25 15:26:24 -05:00
});
api.event.on("mouse.hover", data => {
if (!isCamMode) {
return;
}
2020-11-30 18:46:56 -05:00
func.hover(data);
2020-11-25 15:26:24 -05:00
});
2020-11-14 11:12:12 -05:00
};
2020-11-25 16:46:51 -05:00
function createTabBox(iw, ic, n) {
const { track } = iw;
const { stock, bounds, process } = API.conf.get();
const { camTabsWidth, camTabsHeight, camTabsDepth } = process;
2020-11-26 10:22:18 -05:00
const sz = stock.z || bounds.max.z;
const zp = sz - track.box.d + process.camZBottom - process.camZTopOffset + camTabsHeight / 2;
ic.x += n.x * camTabsDepth / 2; // offset from part
ic.z -= n.y * camTabsDepth / 2; // offset swap z,y
2020-11-25 16:46:51 -05:00
ic.y = zp; // offset swap in world space y,z
const rot = new THREE.Quaternion().setFromAxisAngle(zaxis, Math.atan2(n.y, n.x));
const pos = { x:ic.x, y:ic.y, z:ic.z };
const dim = { x:camTabsDepth, y:camTabsWidth, z:camTabsHeight };
const tab = addbox(pos, 0x0000dd, 'tabb', dim, { rotate: rot });
2020-11-25 16:46:51 -05:00
return { pos, dim, rot, tab, width: camTabsWidth, height: camTabsHeight };
}
function addWidgetTab(widget, rec) {
const { pos, dim, rot, id } = rec;
2020-11-25 15:26:24 -05:00
const tabs = widget.tabs = (widget.tabs || {});
// prevent duplicate restore from repeated settings load calls
if (!tabs[id]) {
pos.box = addbox(
2020-11-25 16:46:51 -05:00
pos, 0x0000dd, id,
dim, { group: widget.mesh, rotate: rot }
2020-11-25 15:26:24 -05:00
);
pos.box.tab = Object.assign({widget, id}, pos);
2020-11-25 15:26:24 -05:00
widget.adds.push(pos.box);
2020-11-25 16:46:51 -05:00
tabs[id] = pos;
2020-11-25 15:26:24 -05:00
}
}
2020-11-25 16:46:51 -05:00
function restoreTabs(widgets) {
widgets.forEach(widget => {
const tabs = API.widgets.annotate(widget.id).tab || [];
tabs.forEach(rec => {
rec = Object.clone(rec);
rec.rot = new THREE.Quaternion(rec.rot._x ,rec.rot._y, rec.rot._z, rec.rot._w);
2020-11-25 16:46:51 -05:00
addWidgetTab(widget, rec);
});
});
}
function clearTabs(widget) {
Object.values(widget.tabs || {}).forEach(rec => {
widget.adds.remove(rec.box);
widget.mesh.remove(rec.box);
});
widget.tabs = {};
delete API.widgets.annotate(widget.id).tab;
}
2020-12-01 18:19:28 -05:00
function clearTraces(widget) {
2020-12-01 19:54:54 -05:00
let stack = widget.trace_stack;
if (stack) {
stack.meshes.forEach(mesh => {
if (mesh.selected) {
func.traceToggle(mesh);
}
});
}
widget.trace = null;
2020-12-01 18:19:28 -05:00
delete API.widgets.annotate(widget.id).trace;
}
2020-11-25 15:26:24 -05:00
function addbox() { return FDM.addbox(...arguments)};
function delbox() { return FDM.delbox(...arguments)};
function animate() {
2020-11-24 11:01:29 -05:00
isAnimate = true;
API.widgets.opacity(isParsed ? 0 : 0.75);
2020-11-24 00:48:45 -05:00
API.hide.slider();
STACKS.clear();
2020-11-24 00:11:49 -05:00
CAM.animate(API);
}
function updateStock(args, event) {
2020-11-24 11:01:29 -05:00
if (isAnimate) {
return;
}
STACKS.remove('bounds');
if (isCamMode && isArrange) {
STACKS.clear();
}
2020-11-14 11:12:12 -05:00
if (!isCamMode) {
if (camStock) {
SPACE.platform.remove(camStock);
camStock = null;
}
2020-11-14 11:12:12 -05:00
return;
}
2020-11-14 11:12:12 -05:00
const refresh = (event === "selection.scale" || event === 'selection.rotate');
let settings = API.conf.get();
let widgets = API.widgets.all();
let proc = settings.process;
let enabled = UI.camStockOn.checked;
let offset = UI.camStockOffset.checked;
let stockSet = offset || (proc.camStockX && proc.camStockY && proc.camStockZ > 0);
let topZ = API.platform.top_z();
let delta = 0;
let csox = 0;
let csoy = 0;
let stock = settings.stock = { };
let compute = enabled && stockSet && widgets.length;
UI.func.animate.style.display = refresh ? '' : 'none';
2020-11-14 11:12:12 -05:00
// create/inject cam stock if stock size other than default
if (compute) {
UI.func.animate.style.display = '';
let csx = proc.camStockX;
let csy = proc.camStockY;
let csz = proc.camStockZ;
2020-11-14 11:12:12 -05:00
if (offset) {
let min = { x: Infinity, y: Infinity, z: 0 };
let max = { x: -Infinity, y: -Infinity, z: -Infinity };
widgets.forEach(function(widget) {
let wbnd = widget.getBoundingBox(refresh);
let wpos = widget.track.pos;
min = {
x: Math.min(min.x, wpos.x + wbnd.min.x),
y: Math.min(min.y, wpos.y + wbnd.min.y),
z: 0
};
max = {
x: Math.max(max.x, wpos.x + wbnd.max.x),
y: Math.max(max.y, wpos.y + wbnd.max.y),
z: Math.max(max.z, wbnd.max.z)
};
});
csx += max.x - min.x;
csy += max.y - min.y;
csz += max.z - min.z;
csox = min.x + ((max.x - min.x) / 2);
csoy = min.y + ((max.y - min.y) / 2);
}
if (!camStock) {
let geo = new THREE.BoxGeometry(1, 1, 1);
let mat = new THREE.MeshBasicMaterial({
color: 0x777777,
opacity: 0.2,
transparent: true,
side:THREE.DoubleSide
});
camStock = new THREE.Mesh(geo, mat);
camStock.renderOrder = 2;
SPACE.platform.add(camStock);
}
stock = settings.stock = {
x: csx,
y: csy,
z: csz,
center: {
x: csox,
y: csoy,
z: csz / 2
}
};
camStock.scale.x = csx + 0.005;
camStock.scale.y = csy + 0.005;
camStock.scale.z = csz + 0.005;
camStock.position.x = csox;
camStock.position.y = csoy;
camStock.position.z = csz / 2;
delta = csz - topZ;
} else if (camStock) {
SPACE.platform.remove(camStock);
camStock = null;
delta = 0;
}
const {x, y, z} = stock;
2020-11-14 12:07:05 -05:00
if (x && y && z && !STACKS.getStack('bounds')) {
2020-11-30 22:36:06 -05:00
const render = new KIRI.Layers().setLayer('bounds', { face: 0xaaaaaa, line: 0xaaaaaa });
const stack = STACKS.setFreeMem(false).create('bounds', SPACE.platform.world);
2020-11-14 11:12:12 -05:00
stack.add(render.addPolys([
newPolygon().centerRectangle({x:csox, y:csoy, z:0}, x, y),
newPolygon().centerRectangle({x:csox, y:csoy, z}, x, y)
], { thin: true } ));
const hx = x/2, hy = y/2;
2020-11-26 10:22:18 -05:00
const sz = stock.z || 0;
2020-11-14 11:12:12 -05:00
stack.add(render.addLines([
2020-11-26 10:22:18 -05:00
newPoint(csox + hx, csoy - hy, 0), newPoint(csox + hx, csoy - hy, sz),
newPoint(csox + hx, csoy + hy, 0), newPoint(csox + hx, csoy + hy, sz),
newPoint(csox - hx, csoy - hy, 0), newPoint(csox - hx, csoy - hy, sz),
newPoint(csox - hx, csoy + hy, 0), newPoint(csox - hx, csoy + hy, sz),
2020-11-14 11:12:12 -05:00
], { thin: true }));
STACKS.setFreeMem(true);
2020-11-14 11:12:12 -05:00
}
API.platform.update_top_z(delta);
API.platform.update_origin();
SPACE.update();
}
2020-11-05 18:29:04 -05:00
})();