stub in subtraction. jscad subtract seems to be broken at the api, though

This commit is contained in:
Stewart Allen 2022-04-20 16:53:28 -04:00
commit c7298d2a9f
7 changed files with 113 additions and 47 deletions

View file

@ -21,6 +21,7 @@ const worker = moto.client.fn
const groups = [];
let selected = [];
let tools = [];
const selection = {
// @returns {MeshObject[]} or all groups if not strict and no selection
@ -57,28 +58,32 @@ const selection = {
},
// @param group {MeshObject[]}
set(objects) {
set(objects, toolist) {
selected = objects;
tools = toolist || [];
util.defer(selection.update);
},
// @param group {MeshObject}
add(object) {
add(object, tool) {
// pendantic code necessary to minimize re-entrant api calls
if (object.models) {
// if group, remove discrete selected members
for (let m of object.models) {
if (selected.contains(m)) {
selection.remove(m);
tools.remove(m);
}
}
} else {
// if model, remove selcted group
if (selected.contains(object.group)) {
selection.remove(object.group);
tools.remove(objec.group);
}
}
selected.addOnce(object);
if (tool) tools.addOnce(object);
util.defer(selection.update);
},
@ -92,23 +97,27 @@ const selection = {
delete() {
for (let s of selection.list()) {
selection.remove(s);
tools.remove(s);
s.showBounds(false);
s.remove();
}
},
// @param group {MeshObject}
toggle(object) {
toggle(object, tool) {
if (selected.contains(object)) {
selection.remove(object);
tools.remove(object);
} else {
selection.add(object);
if (tool) tools.addOnce(object);
}
},
clear() {
for (let s of selection.list()) {
selection.remove(s);
tools.remove(s);
}
for (let m of api.model.list()) {
m.clearSelections();
@ -135,10 +144,11 @@ const selection = {
selected = selected.filter(sel => !mgsel.contains(sel)).filter(v => v);
// highlight selected
for (let object of selected) {
object.select(true);
object.select(true, tools.contains(object));
}
// update saved selection id list
prefs.save( prefs.map.space.select = selected.map(s => s.id) );
prefs.save( prefs.map.space.tools = tools.map(s => s.id) );
// force repaint in case of idle
space.update();
return selection;
@ -277,6 +287,7 @@ let add = {
} })
]) ]
});
api.modal.bound.gencyl.focus();
}
}
};
@ -366,6 +377,22 @@ const tool = {
});
},
subtract(models) {
models = fallback(models);
api.log.emit(`subtract ${models.length} model(s)`).pin();
worker.model_subtract(models.map(m => {
return { id: m.id, matrix: m.matrix, tool: m.tool() }
}))
.then(data => {
let group = api.group.new([new mesh.model({
file: `subtracted`,
mesh: data
})]).promote();
api.selection.set([group]);
api.log.emit('subtract complete').unpin();
});
},
duplicate() {
for (let m of selection.models()) {
m.duplicate();
@ -536,9 +563,8 @@ const tool = {
const modes = {
object: "object",
tool: "tool",
face: "face",
line: "line",
vertex: "vertex",
surface: "surface"
};
@ -577,23 +603,22 @@ const mode = {
mode.set(modes.object);
},
tool() {
if (mode.is([ modes.face, modes.surface ])) {
selection.clear();
}
mode.set(modes.tool);
},
face() {
if (mode.is([ modes.object ])) {
if (mode.is([ modes.object, modes.tool ])) {
selection.clear();
}
mode.set(modes.face);
},
line() {
mode.set(modes.line);
},
vertex() {
mode.set(modes.vertex);
},
surface() {
if (mode.is([ modes.object ])) {
if (mode.is([ modes.object, modes.tool ])) {
selection.clear();
}
mode.set(modes.surface);

View file

@ -342,13 +342,13 @@ function ui_build() {
let { file, selection, mode, tool, prefs, add } = api;
// top/center mode selector
h.bind(modes, [
h.bind(modes, [ h.div([
h.button({ _: 'object', id: "mode-object", onclick() { mode.object() } }),
h.button({ _: 'face', id: "mode-face", onclick() { mode.face() } }),
h.button({ _: 'line', id: "mode-line", onclick() { mode.line() } }),
h.button({ _: 'vertex', id: "mode-vertex", onclick() { mode.vertex() } }),
h.button({ _: 'tool', id: "mode-tool", onclick() { mode.tool() } }),
]), h.div([
h.button({ _: 'surface', id: "mode-surface", onclick() { mode.surface() } }),
]);
h.button({ _: 'face', id: "mode-face", onclick() { mode.face() } }),
]) ]);
// create hotkey/action menu (top/left)
h.bind(actions, [
@ -376,9 +376,13 @@ function ui_build() {
h.button({ _: 'regroup', onclick: tool.regroup }),
h.button({ _: 'merge', onclick: tool.merge }),
h.button({ _: 'mirror', onclick: tool.mirror }),
h.button({ _: 'union', onclick: tool.union }),
h.button({ _: 'split', onclick: call.edit_split }),
]),
h.div([
h.div({ _: "bool", class: "head" }),
h.button({ _: 'union', onclick: tool.union }),
h.button({ _: 'subtract', onclick: tool.subtract }),
]),
h.div([
h.div({ _: "normal", class: "head" }),
h.button({ _: 'invert', onclick: tool.invert }),

View file

@ -40,6 +40,15 @@ let materials = mesh.material = {
color: 0x00e000,
opacity: 1
}),
// model selected as tool
tool: new MeshPhongMaterial({
side: DoubleSide,
transparent: true,
shininess: 125,
specular: 0x202020,
color: 0xe00000,
opacity: 1
}),
// face selected (for groups ranges)
face: new MeshPhongMaterial({
side: DoubleSide,
@ -78,6 +87,7 @@ mesh.model = class MeshModel extends mesh.object {
this.mats = {
normal: materials.normal.clone(),
select: materials.select.clone(),
tool: materials.tool.clone(),
face: materials.face.clone()
};
@ -266,14 +276,16 @@ mesh.model = class MeshModel extends mesh.object {
}
// get, set, or toggle selection of model (coloring)
select(bool) {
select(bool, stool) {
const cmat = this.mesh.material[0];
const { normal, select, tool } = this.mats;
if (bool === undefined) {
return this.mesh.material[0] === this.mats.normal;
return cmat !== normal;
}
if (bool.toggle) {
return this.select(!this.select());
return this.select(!this.select(), cmat === tool);
}
this.mesh.material[0] = bool ? this.mats.select : this.mats.normal;
this.mesh.material[0] = bool ? (stool ? tool : select) : normal;
return bool;
}
@ -282,6 +294,13 @@ mesh.model = class MeshModel extends mesh.object {
return this.select();
}
tool(bool) {
if (bool === undefined) {
return this.mesh.material[0] === this.mats.tool;
}
return this.select(this.selected(), bool);
}
opacity(ov, opt = {}) {
let mat = this.mesh.material;
if (ov === undefined) {

View file

@ -150,6 +150,20 @@ let model = {
return base.CSG.toPositionArray(union);
},
subtract(recs) {
let bases = recs.filter(rec => !rec.tool)
.map(rec => translate_encode(rec.id, rec.matrix))
.map(a => base.CSG.fromPositionArray(a));
let tools = recs.filter(rec => rec.tool)
.map(rec => translate_encode(rec.id, rec.matrix))
.map(a => base.CSG.fromPositionArray(a));
let subs = [];
for (let obj of bases) {
subs.appendAll(base.CSG.subtract(obj, ...tools));
}
return base.CSG.toPositionArray(subs);
},
// used to generate a list for split snapping
zlist(data) {
let { id, matrix, round } = data;