package re-organization
This commit is contained in:
parent
7176ab0822
commit
678316ac95
98 changed files with 63 additions and 62 deletions
686
src/kiri-mode/fdm/client.js
Normal file
686
src/kiri-mode/fdm/client.js
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
"use strict";
|
||||
|
||||
(function() {
|
||||
|
||||
let KIRI = self.kiri,
|
||||
BASE = self.base,
|
||||
UTIL = BASE.util,
|
||||
FDM = KIRI.driver.FDM,
|
||||
SPACE, API, VIEWS, LANG, PROC, UI, UC,
|
||||
nextID = Date.now(),
|
||||
p1, p2, iw,
|
||||
lastBox,
|
||||
lastMode, lastView,
|
||||
lastPillar, fromPillar,
|
||||
isFdmMode = false,
|
||||
addingSupports = false,
|
||||
alert = [],
|
||||
boxes = {},
|
||||
func = {};
|
||||
|
||||
FDM.init = function(kiri, api) {
|
||||
UI = api.ui;
|
||||
UC = api.uc;
|
||||
API = api;
|
||||
SPACE = api.const.SPACE;
|
||||
VIEWS = api.const.VIEWS;
|
||||
LANG = KIRI.lang.current;
|
||||
PROC = Object.keys(kiri.conf.defaults.fdm.p);
|
||||
|
||||
let rangeVars = {
|
||||
// slice
|
||||
"sliceShells": LANG.sl_shel_s,
|
||||
"sliceFillType": LANG.fi_type,
|
||||
"sliceFillWidth": LANG.fi_wdth_s,
|
||||
"sliceFillSparse": LANG.fi_pcnt_s,
|
||||
"sliceSolidMinArea": LANG.ad_msol_s,
|
||||
"firstLayerRate": LANG.fl_rate_s,
|
||||
"firstLayerPrintMult": LANG.fl_mult_s,
|
||||
// prepare
|
||||
"sliceShellOrder": LANG.sl_ordr_s,
|
||||
"sliceFillOverlap": LANG.fi_over_s,
|
||||
"outputFeedrate": LANG.ou_feed_s,
|
||||
"outputFinishrate": LANG.ou_fini_s,
|
||||
"outputShellMult": LANG.ou_shml_s,
|
||||
"outputFillMult": LANG.ou_flml_s,
|
||||
"outputSparseMult": LANG.ou_spml_s,
|
||||
"outputRetractWipe": LANG.ad_wpln_s,
|
||||
"outputShortPoly": LANG.ad_spol_s,
|
||||
"outputMinSpeed": LANG.ad_mins_s,
|
||||
"outputCoastDist": LANG.ad_scst_s,
|
||||
"outputLoops": LANG.ag_loop_s,
|
||||
"sliceSupportDensity": LANG.sp_dens_s,
|
||||
"sliceSupportOffset": LANG.sp_offs_s,
|
||||
"sliceLayerStart": LANG.sl_strt_s,
|
||||
"firstLayerBrim": LANG.fl_brim_s,
|
||||
"firstLayerBrimIn": LANG.fl_brin_s,
|
||||
"firstLayerBrimTrig": LANG.fl_brmn_s,
|
||||
"firstLayerBrimGap": LANG.fl_brgp_s,
|
||||
// export
|
||||
"zHopDistance": LANG.ad_zhop_s,
|
||||
"arcTolerance": LANG.ad_zhop_s,
|
||||
"antiBacklash": LANG.ad_abkl_s,
|
||||
"outputTemp": LANG.ou_nozl_s,
|
||||
"outputBedTemp": LANG.ou_bedd_s,
|
||||
"outputFanSpeed": LANG.ou_fans_s,
|
||||
"outputRetractDist": LANG.ad_rdst_s,
|
||||
"outputRetractSpeed": LANG.outputRetractSpeed,
|
||||
"outputRetractDwell": LANG.ad_rdwl_s,
|
||||
};
|
||||
|
||||
for (let key of Object.keys(rangeVars)) {
|
||||
if (UI[key]) {
|
||||
UI[key].range = true;
|
||||
}
|
||||
}
|
||||
|
||||
function filterSynth() {
|
||||
api.widgets.filter((widget) => {
|
||||
if (widget.track.synth) {
|
||||
api.const.SPACE.world.remove(widget.mesh);
|
||||
kiri.Widget.Groups.remove(widget);
|
||||
}
|
||||
return !widget.track.synth
|
||||
});
|
||||
}
|
||||
|
||||
function clearRanges() {
|
||||
API.conf.get().process.ranges = [];
|
||||
UI.rangeGroup.firstElementChild.innerHTML = '';
|
||||
}
|
||||
|
||||
function updateRanges(ranges = []) {
|
||||
UI.rangeGroup.style.display = isFdmMode && ranges && ranges.length ? 'flex' : 'none';
|
||||
let html = [];
|
||||
let bind = [];
|
||||
let now = Date.now();
|
||||
let sorted = ranges.sort((a,b) => b.lo - a.lo);
|
||||
for (let range of sorted) {
|
||||
let id = (now++).toString(36);
|
||||
let rows = Object.entries(range.fields).map(a => `<div><label class="pad">${rangeVars[a[0]]}</label><span></span><label class="val">${a[1]}</label></div>`).join('');
|
||||
let hover = `<div id="hov_${id}" class="range-detail">${rows}</div>`;
|
||||
let info = `<button id="sel_${id}" class="j-center grow">${range.lo} - ${range.hi}</button><button id="del_${id}"><i class="far fa-trash-alt"></i></button>`;
|
||||
html.appendAll([
|
||||
`<div id="rng_${id}" class="range-info">${hover}${info}</div>`
|
||||
]);
|
||||
bind.push({id, range});
|
||||
}
|
||||
UI.rangeGroup.firstElementChild.innerHTML = html.join('');
|
||||
for (let rec of bind) {
|
||||
$(`sel_${rec.id}`).onclick = () => {
|
||||
api.show.layer(rec.range.hi, rec.range.lo);
|
||||
};
|
||||
$(`del_${rec.id}`).onclick = () => {
|
||||
let io = ranges.indexOf(rec.range);
|
||||
ranges.splice(io,1);
|
||||
updateRanges(ranges);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
api.event.on("boolean.click", func.updateSupportButtons = () => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
for (let btn of [
|
||||
UI.ssaGen,
|
||||
UI.ssmAdd,
|
||||
UI.ssmDun,
|
||||
UI.ssmClr
|
||||
]) {
|
||||
btn.disabled = UI.sliceSupportEnable.checked;
|
||||
}
|
||||
if (UI.sliceSupportEnable.checked) {
|
||||
func.sclear();
|
||||
}
|
||||
});
|
||||
|
||||
api.event.on("function.animate", (mode) => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
if (!API.conf.get().controller.danger) {
|
||||
return;
|
||||
}
|
||||
let pct = 0;
|
||||
let int = setInterval(function() {
|
||||
if (pct <= 1) {
|
||||
api.const.STACKS.setFraction(pct);
|
||||
pct += 0.05;
|
||||
} else {
|
||||
api.const.STACKS.setFraction(1);
|
||||
clearTimeout(int);
|
||||
}
|
||||
}, 50);
|
||||
// let slider = $('top-slider');
|
||||
// slider.style.display = 'flex';
|
||||
// slider.oninput = slider.onchange = (ev) => {
|
||||
// api.const.STACKS.setFraction(parseInt(ev.target.value)/100);
|
||||
// };
|
||||
});
|
||||
api.event.on("mode.set", mode => {
|
||||
isFdmMode = mode === 'FDM';
|
||||
lastMode = mode;
|
||||
updateVisiblity();
|
||||
});
|
||||
api.event.on("view.set", view => {
|
||||
lastView = view;
|
||||
updateVisiblity();
|
||||
filterSynth();
|
||||
func.sdone();
|
||||
// let ranges = API.conf.get().process.ranges;
|
||||
if (isFdmMode) {
|
||||
if (lastView === VIEWS.SLICE) {
|
||||
for (let key of PROC) {
|
||||
if (UI[key] && !UI[key].range) {
|
||||
UI[key].disabled = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let key of PROC) {
|
||||
if (UI[key]) UI[key].disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// UI.rangeGroup.style.display = ranges && ranges.length ? 'flex' : 'none';
|
||||
});
|
||||
api.event.on("range.updates", updateRanges);
|
||||
api.event.on("settings.load", (settings) => {
|
||||
if (settings.mode !== 'FDM') return;
|
||||
settings.process.outputOriginCenter = (settings.device.originCenter || false);
|
||||
restoreSupports(api.widgets.all());
|
||||
updateRanges(settings.process.ranges);
|
||||
});
|
||||
api.event.on("settings.saved", (settings) => {
|
||||
updateRanges(settings.process.ranges);
|
||||
func.updateSupportButtons();
|
||||
// let ranges = settings.process.ranges;
|
||||
// UI.rangeGroup.style.display = isFdmMode && ranges && ranges.length ? 'flex' : 'none';
|
||||
});
|
||||
api.event.on("button.click", target => {
|
||||
switch (target) {
|
||||
case api.ui.ssaGen: return func.sgen();
|
||||
case api.ui.ssmAdd: return func.sadd();
|
||||
case api.ui.ssmDun: return func.sdone();
|
||||
case api.ui.ssmClr:
|
||||
// return api.uc.confirm("clear supports?").then(ok => {
|
||||
// if (ok) func.sclear();
|
||||
// });
|
||||
func.sclear();
|
||||
}
|
||||
});
|
||||
api.event.on("fdm.supports.detect", func.sgen = () => {
|
||||
let alerts = [];
|
||||
let { process, device } = api.conf.get();
|
||||
if (!device.bedBelt) {
|
||||
if (process.sliceSupportAngle < 10) {
|
||||
alerts.push(api.show.alert("angles below 10 degrees may fail"));
|
||||
}
|
||||
}
|
||||
alerts.push(api.show.alert("analyzing part(s)...", 1000));
|
||||
FDM.support_generate(array => {
|
||||
func.sclear();
|
||||
api.hide.alert(undefined,alerts);
|
||||
for (let rec of array) {
|
||||
let { widget, supports } = rec;
|
||||
let wa = API.widgets.annotate(widget.id);
|
||||
let ws = wa.support || [];
|
||||
for (let support of supports) {
|
||||
let { from, to, mid } = support;
|
||||
let dw = api.conf.get().process.sliceSupportSize / 2;
|
||||
let dh = from.z - to.z;
|
||||
let rec = {
|
||||
x: mid.x,
|
||||
y: mid.y,
|
||||
z: mid.z,
|
||||
dw,
|
||||
dh,
|
||||
id: Math.random() * 0xffffffffff
|
||||
};
|
||||
addWidgetSupport(widget, rec);
|
||||
ws.push(Object.clone(rec));
|
||||
}
|
||||
wa.support = ws;
|
||||
}
|
||||
api.event.emit("fdm.supports.detected");
|
||||
});
|
||||
});
|
||||
api.event.on("fdm.supports.add", func.sadd = () => {
|
||||
alert = api.show.alert("[esc] key cancels support editing");
|
||||
api.feature.hover = addingSupports = true;
|
||||
});
|
||||
api.event.on("fdm.supports.done", func.sdone = () => {
|
||||
delbox('intZ');
|
||||
delbox('intW');
|
||||
delbox('supp');
|
||||
api.hide.alert(alert);
|
||||
api.feature.hover = addingSupports = false;
|
||||
fromPillar = undefined;
|
||||
});
|
||||
api.event.on("fdm.supports.clear", func.sclear = () => {
|
||||
func.sdone();
|
||||
if (clearAllWidgetSupports()) {
|
||||
API.conf.save();
|
||||
}
|
||||
});
|
||||
api.event.on("slice.begin", () => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
func.sdone();
|
||||
updateVisiblity();
|
||||
|
||||
// synth support widget for each widget group
|
||||
let synth = [];
|
||||
for (let group of kiri.Widget.Groups.list()) {
|
||||
let merge = group.filter(w => w.sups).map(w => Object.values(w.sups)).flat();
|
||||
if (!merge.length) {
|
||||
continue;
|
||||
}
|
||||
let boxen = merge.map(m => {
|
||||
let geo = m.box.geometry.clone();
|
||||
if (geo.index) geo = geo.toNonIndexed();
|
||||
return geo.translate(m.x, m.y, m.z);
|
||||
});
|
||||
for (let box of boxen) {
|
||||
// eliminate / normalize uv to allow other widget merge
|
||||
box.setAttribute('uv',new THREE.BufferAttribute(new Float32Array(0), 3));
|
||||
}
|
||||
let bbg = THREE.BufferGeometryUtils.mergeBufferGeometries(boxen);
|
||||
let sw = kiri.newWidget(null, group);
|
||||
let fwp = group[0].track.pos;
|
||||
sw.loadGeometry(bbg);
|
||||
sw._move(fwp.x, fwp.y, fwp.z);
|
||||
api.widgets.add(sw);
|
||||
sw.track.synth = true;
|
||||
api.const.SPACE.world.add(sw.mesh);
|
||||
}
|
||||
});
|
||||
api.event.on("slice.end", () => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
api.event.on("key.esc", () => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
func.sdone()
|
||||
});
|
||||
api.event.on("selection.scale", () => {
|
||||
if (isFdmMode) {
|
||||
clearRanges();
|
||||
func.sclear();
|
||||
}
|
||||
});
|
||||
api.event.on("widget.delete", widget => {
|
||||
if (isFdmMode) {
|
||||
clearRanges();
|
||||
return;
|
||||
}
|
||||
});
|
||||
api.event.on("widget.duplicate", (widget, oldwidget) => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
let ann = API.widgets.annotate(widget.id);
|
||||
if (ann.support) {
|
||||
for (let supp of Object.values(ann.support)) {
|
||||
supp.id = Math.abs(Math.random() * 0xffffffffffff);
|
||||
}
|
||||
restoreSupports([widget]);
|
||||
}
|
||||
});
|
||||
api.event.on("widget.mirror", widget => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
let ann = API.widgets.annotate(widget.id);
|
||||
let sups = ann.support || [];
|
||||
sups.forEach(sup => {
|
||||
let wsup = widget.sups[sup.id];
|
||||
wsup.box.position.x = wsup.x = sup.x = -sup.x;
|
||||
});
|
||||
});
|
||||
api.event.on("widget.rotate", rot => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
let {widget, x, y, z} = rot;
|
||||
if (x || y) {
|
||||
clearWidgetSupports(widget);
|
||||
} else {
|
||||
let ann = API.widgets.annotate(widget.id);
|
||||
let sups = ann.support || [];
|
||||
sups.forEach(sup => {
|
||||
let wsup = widget.sups[sup.id];
|
||||
let vc = new THREE.Vector3(sup.x, sup.y, sup.z);
|
||||
let m4 = new THREE.Matrix4();
|
||||
m4 = m4.makeRotationFromEuler(new THREE.Euler(x || 0, y || 0, z || 0));
|
||||
vc.applyMatrix4(m4);
|
||||
wsup.box.position.x = wsup.x = sup.x = vc.x;
|
||||
wsup.box.position.y = wsup.y = sup.y = vc.y;
|
||||
wsup.box.position.z = wsup.z = sup.z = vc.z;
|
||||
});
|
||||
}
|
||||
});
|
||||
api.event.on("mouse.hover.up", func.hoverup = (on = {}) => {
|
||||
let { event } = on;
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
if (!addingSupports) {
|
||||
return;
|
||||
}
|
||||
delbox('supp');
|
||||
if (lastPillar) {
|
||||
removeWidgetSupport(lastPillar.widget, lastPillar);
|
||||
return;
|
||||
}
|
||||
if (!iw) return;
|
||||
let { point, dim } = lastBox;
|
||||
p1.y = Math.max(0, p1.y);
|
||||
p2.y = Math.max(0, p2.y);
|
||||
let rz = dim.rz;
|
||||
let dh = dim.z;
|
||||
let dw = api.conf.get().process.sliceSupportSize / 2;
|
||||
let ip = iw.track.pos;
|
||||
let wa = api.widgets.annotate(iw.id);
|
||||
let ws = (wa.support = wa.support || []);
|
||||
let id = ++nextID;
|
||||
let rec = {x: point.x - ip.x, y: -point.z - ip.y, z: point.y, rz, dw, dh, id};
|
||||
if (fromPillar && event && event.shiftKey) {
|
||||
let targets = api.widgets.meshes().append(SPACE.internals().platform);
|
||||
let from = fromPillar,
|
||||
d = {
|
||||
x: rec.x - from.x,
|
||||
y: rec.y - from.y,
|
||||
z: rec.z - from.z
|
||||
};
|
||||
let dist = Math.sqrt(d.x*d.x + d.y*d.y + d.z*d.z);
|
||||
let lerp = UTIL.lerp(0,dist,dw).map(v => v/dist);
|
||||
let angle = rec.rz = Math.atan2(d.y,d.x);
|
||||
let fromrec = ws.filter(r => r.id === from.id)[0];
|
||||
if (fromrec) {
|
||||
from.rz = fromrec.rz = angle;
|
||||
removeWidgetSupport(iw, fromPillar);
|
||||
ws.push(Object.clone(fromrec));
|
||||
addWidgetSupport(iw, fromrec);
|
||||
}
|
||||
lerp.pop();
|
||||
let seed = Math.random();
|
||||
for (let pct of lerp) {
|
||||
let point = new THREE.Vector3(from.x + d.x * pct, from.z + d.z * pct, from.y + d.y * pct);
|
||||
addSupportAtPoint(targets, point, ip, angle, seed++);
|
||||
}
|
||||
}
|
||||
ws.push(Object.clone(rec));
|
||||
fromPillar = addWidgetSupport(iw, rec);
|
||||
API.conf.save();
|
||||
});
|
||||
function addSupportAtPoint(targets, point, ip, angle, id) {
|
||||
let up = new THREE.Vector3(0,1,0)
|
||||
let dn = new THREE.Vector3(0,-1,0)
|
||||
let rp = new THREE.Vector3(point.x + ip.x, point.y, -point.z - ip.y);
|
||||
let iup = new THREE.Raycaster(rp, up)
|
||||
.intersectObjects(targets, false)
|
||||
.filter(t => !t.object.pillar);
|
||||
if (iup.length && iup.length % 2 === 0) {
|
||||
let idn = new THREE.Raycaster(rp, dn)
|
||||
.intersectObjects(targets, false)
|
||||
.filter(t => !t.object.pillar);
|
||||
if (idn.length && idn.length % 2 === 0) {
|
||||
iw = iup[0].object.widget || iw;
|
||||
let wa = api.widgets.annotate(iw.id);
|
||||
let ws = (wa.support = wa.support || []);
|
||||
let phi = iup[0].point;
|
||||
let plo = idn[0].point;
|
||||
let ply = Math.max(0, plo.y);
|
||||
let mp = (phi.y + ply) / 2;
|
||||
let dy = Math.abs(phi.y - ply);
|
||||
let dw = api.conf.get().process.sliceSupportSize / 2;
|
||||
let rec = { rz:angle, x:point.x, y:point.z, z:mp, dw, dh:dy, id };
|
||||
ws.push(Object.clone(rec));
|
||||
fromPillar = addWidgetSupport(iw, rec);
|
||||
}
|
||||
}
|
||||
}
|
||||
api.event.on("mouse.hover", data => {
|
||||
if (!isFdmMode) {
|
||||
return;
|
||||
}
|
||||
if (!addingSupports) {
|
||||
return;
|
||||
}
|
||||
delbox('supp');
|
||||
const { int, type, point, event } = data;
|
||||
const pillar = int ? int.object.pillar : undefined;
|
||||
if (lastPillar) {
|
||||
lastPillar.box.material.color.r = 0;
|
||||
lastPillar = null;
|
||||
}
|
||||
if (pillar) {
|
||||
pillar.box.material.color.r = 0.5;
|
||||
lastPillar = pillar;
|
||||
if (event && (event.metaKey || event.ctrlKey)) {
|
||||
return func.hoverup();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (int && type === 'widget') {
|
||||
iw = int.object.widget || iw;
|
||||
} else {
|
||||
iw = null;
|
||||
}
|
||||
p1 = point;
|
||||
let dir = new THREE.Vector3(0,1,0)
|
||||
let ray = new THREE.Raycaster(point, dir);
|
||||
let rz = int && int.face ? Math.atan2(int.face.normal.y, int.face.normal.x) : 0;
|
||||
// when on object, project down on downward faces
|
||||
if (int && int.face && int.face.normal.z < -0.1) {
|
||||
dir.y = -1;
|
||||
}
|
||||
let targets = api.widgets.meshes().append(SPACE.internals().platform);
|
||||
let i2 = ray.intersectObjects(targets, false)
|
||||
.filter(t => !t.object.pillar) // eliminate other pillars
|
||||
.filter(i => i.distance > 0.1); // false matches close to origin of ray
|
||||
if (i2.length && i2.length % 2 === 0) {
|
||||
p2 = i2[0].point;
|
||||
iw = i2[0].object.widget || iw;
|
||||
let p1y = Math.max(0, p1.y);
|
||||
let p2y = Math.max(0, p2.y);
|
||||
let hy = (p1y + p2y) / 2;
|
||||
let dy = Math.abs(p1y - p2y);
|
||||
let dw = api.conf.get().process.sliceSupportSize / 2;
|
||||
addbox({x:p1.x, y:hy, z:p1.z}, 0x0000dd, 'supp', {
|
||||
x:dw, y:dw, z:dy, rz
|
||||
});
|
||||
}
|
||||
if (event && event.altKey) {
|
||||
return func.hoverup();
|
||||
}
|
||||
});
|
||||
api.event.on("export.debug", msg => {
|
||||
if (msg.arcQ && msg.arcQ.length > 2) {
|
||||
if (xpdebug) {
|
||||
xpdebug.destroy();
|
||||
xpdebug = undefined;
|
||||
}
|
||||
let poly = BASE.newPolygon().setOpen();
|
||||
for (let rec of msg.arcQ) {
|
||||
rec.z += 1;
|
||||
poly.addObj(rec);
|
||||
}
|
||||
|
||||
let layers = new KIRI.Layers();
|
||||
let layer = layers.setLayer("arcq", { line: 0xff00ff, face: 0xff00ff, opacity: 1 });
|
||||
layer.addPoly(poly, {thin:true});
|
||||
|
||||
layer = layers.setLayer("arcc", { line: 0xff0000, face: 0xff0000, opacity: 1 });
|
||||
for (let center of msg.arcQ.center) {
|
||||
center.z += 0.5;
|
||||
layer.addPoly(BASE.newPolygon().centerCircle(
|
||||
center, center.r, 20
|
||||
));
|
||||
}
|
||||
|
||||
xpdebug = new KIRI.Stack(SPACE.platform.world, false);
|
||||
xpdebug.addLayers(layers);
|
||||
xpdebug.setVisible(0,Infinity);
|
||||
xpdebug.show();
|
||||
|
||||
SPACE.refresh();
|
||||
|
||||
console.log(msg, poly);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let xpdebug;
|
||||
let supsave = {};
|
||||
let suptimer;
|
||||
|
||||
function scheduleSupportSave(widget) {
|
||||
clearTimeout(suptimer);
|
||||
supsave[widget.id] = widget;
|
||||
suptimer = setTimeout(() => {
|
||||
for (let w of Object.values(supsave)) {
|
||||
w.saveState();
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function activeSupports() {
|
||||
const active = [];
|
||||
API.widgets.all().forEach(widget => {
|
||||
Object.values(widget.sups || {}).forEach(support => {
|
||||
active.push(support.box);
|
||||
support.box.support = true;
|
||||
});
|
||||
});
|
||||
return active;
|
||||
}
|
||||
|
||||
function restoreSupports(widgets) {
|
||||
widgets.forEach(widget => {
|
||||
const supports = API.widgets.annotate(widget.id).support || [];
|
||||
supports.forEach(pos => {
|
||||
addWidgetSupport(widget, pos);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addWidgetSupport(widget, pos) {
|
||||
const { x, y, z, rz, dw, dh, id } = pos;
|
||||
const sups = widget.sups = (widget.sups || {});
|
||||
// prevent duplicate restore from repeated settings load calls
|
||||
if (!sups[id]) {
|
||||
pos.box = addbox(
|
||||
{ x, y, z }, 0x0000dd, id,
|
||||
{ x:dw, y:dw, z:dh, rz }, { group: widget.mesh }
|
||||
);
|
||||
pos.box.pillar = Object.assign({widget}, pos);
|
||||
sups[id] = pos;
|
||||
widget.adds.push(pos.box);
|
||||
scheduleSupportSave(widget);
|
||||
}
|
||||
return sups[id];
|
||||
}
|
||||
|
||||
function removeWidgetSupport(widget, rec) {
|
||||
const {box, id} = rec;
|
||||
widget.adds.remove(box);
|
||||
widget.mesh.remove(box);
|
||||
delete widget.sups[id];
|
||||
let sa = API.widgets.annotate(widget.id).support;
|
||||
let ix = 0;
|
||||
sa.forEach((rec,i) => {
|
||||
if (rec.id === id) {
|
||||
ix = i;
|
||||
}
|
||||
});
|
||||
sa.splice(ix,1);
|
||||
API.conf.save();
|
||||
scheduleSupportSave(widget);
|
||||
fromPillar = undefined;
|
||||
}
|
||||
|
||||
function updateVisiblity() {
|
||||
API.widgets.all().forEach(w => {
|
||||
setSupportVisiblity(w, lastMode === 'FDM' && lastView === VIEWS.ARRANGE);
|
||||
});
|
||||
}
|
||||
|
||||
function setSupportVisiblity(widget, bool) {
|
||||
Object.values(widget.sups || {}).forEach(support => {
|
||||
support.box.visible = bool;
|
||||
});
|
||||
}
|
||||
|
||||
function clearAllWidgetSupports() {
|
||||
let cleared = 0;
|
||||
API.widgets.all().forEach(widget => {
|
||||
cleared += clearWidgetSupports(widget);
|
||||
});
|
||||
return cleared;
|
||||
}
|
||||
|
||||
function clearWidgetSupports(widget) {
|
||||
let cleared = 0;
|
||||
Object.values(widget.sups || {}).forEach(support => {
|
||||
widget.adds.remove(support.box);
|
||||
widget.mesh.remove(support.box);
|
||||
cleared++;
|
||||
});
|
||||
widget.sups = {};
|
||||
delete API.widgets.annotate(widget.id).support;
|
||||
scheduleSupportSave(widget);
|
||||
return cleared;
|
||||
}
|
||||
|
||||
function delbox(name) {
|
||||
const old = boxes[name];
|
||||
if (old) {
|
||||
old.groupTo.remove(old);
|
||||
}
|
||||
}
|
||||
|
||||
function addbox(point, color, name, dim = {x:1,y:1,z:1,rz:0}, opt = {}) {
|
||||
delbox(name);
|
||||
const box = boxes[name] = new THREE.Mesh(
|
||||
new THREE.BoxGeometry(dim.x, dim.y, dim.z),
|
||||
new THREE.MeshPhongMaterial({
|
||||
transparent: true,
|
||||
opacity: 0.5,
|
||||
color
|
||||
})
|
||||
);
|
||||
box.position.x = point.x;
|
||||
box.position.y = point.y;
|
||||
box.position.z = point.z;
|
||||
|
||||
lastBox = {point, dim};
|
||||
|
||||
const group = opt.group || SPACE.scene
|
||||
group.add(box);
|
||||
box.groupTo = group;
|
||||
|
||||
if (dim.rz) {
|
||||
opt.rotate = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), dim.rz);
|
||||
}
|
||||
if (opt.rotate) {
|
||||
opt.matrix = new THREE.Matrix4().makeRotationFromQuaternion(opt.rotate);
|
||||
}
|
||||
if (opt.matrix) {
|
||||
box.geometry.applyMatrix4(opt.matrix);
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
FDM.delbox = delbox;
|
||||
FDM.addbox = addbox;
|
||||
FDM.restoreSupports = restoreSupports;
|
||||
|
||||
})();
|
||||
Loading…
Reference in a new issue