2025-07-06 13:13:11 -04:00
|
|
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
|
|
|
|
|
2025-07-09 13:00:52 -04:00
|
|
|
import { api } from '../../core/api.js';
|
2025-07-10 16:54:02 -04:00
|
|
|
import { env, clearPops, isDark } from './client.js';
|
2025-07-06 13:13:11 -04:00
|
|
|
import { CAM } from './driver-fe.js';
|
2025-07-09 13:00:52 -04:00
|
|
|
import { Layers } from '../../core/layers.js';
|
|
|
|
|
import { Stack } from '../../core/stack.js';
|
2025-07-06 13:13:11 -04:00
|
|
|
|
|
|
|
|
export let traceOn = false;
|
|
|
|
|
export let lastTrace;
|
|
|
|
|
|
|
|
|
|
export function setLastTrace(trace) {
|
|
|
|
|
lastTrace = trace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function traceAdd(ev) {
|
|
|
|
|
if (traceOn) {
|
|
|
|
|
return traceDone();
|
|
|
|
|
}
|
2025-07-06 13:32:51 -04:00
|
|
|
clearPops();
|
2025-07-06 13:13:11 -04:00
|
|
|
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();
|
2025-07-10 16:54:02 -04:00
|
|
|
color.setHex(isDark() ? 0x0066ff : 0x0000ff);
|
2025-07-06 13:13:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2025-11-21 20:12:55 -05:00
|
|
|
if (!(material && obj.trace)) return;
|
2025-07-06 13:13:11 -04:00
|
|
|
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) {
|
2025-07-10 16:54:02 -04:00
|
|
|
color.setHex(isDark() ? 0xdd0011 : 0xff0033);
|
2025-07-06 13:13:11 -04:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|