From 94311917e78e73d66baead6c9ee6456e60d48dda Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Thu, 13 Jan 2022 20:23:48 -0500 Subject: [PATCH] add vertext deletion. move mode menu to top --- src/main/mesh.js | 17 +++++--- src/mesh/api.js | 4 +- src/mesh/build.js | 16 +++++--- src/mesh/model.js | 96 +++++++++++++++++++++++++++++++++++++++++----- src/mesh/work.js | 3 +- web/mesh/index.css | 24 ++++++++++-- 6 files changed, 133 insertions(+), 27 deletions(-) diff --git a/src/main/mesh.js b/src/main/mesh.js index 8b1b9e58..c8f50b02 100644 --- a/src/main/mesh.js +++ b/src/main/mesh.js @@ -220,10 +220,17 @@ function space_init(data) { break; case 'Backspace': case 'Delete': - for (let s of selection.list(true)) { - selection.remove(s); - s.showBounds(false); - s.remove(); + let mode = api.mode.get(); + if (mode !== api.modes.object) { + for (let m of selection.models()) { + m.deleteSelections(mode); + } + } else { + for (let s of selection.list(true)) { + selection.remove(s); + s.showBounds(false); + s.remove(); + } } estop(evt); break; @@ -275,7 +282,7 @@ function space_init(data) { // rotate selected face towawrd z "floor" group.faceDown(int.face.normal); } else { - let modes = api.mode.modes; + let { modes } = api; switch(api.mode.get()) { case modes.object: selection.toggle(shiftKey ? model : model.group); diff --git a/src/mesh/api.js b/src/mesh/api.js index fa3fd465..a83616e6 100644 --- a/src/mesh/api.js +++ b/src/mesh/api.js @@ -408,8 +408,6 @@ let mode = { vertex() { mode.set(modes.vertex); }, - - modes }; // persisted preference map @@ -498,6 +496,8 @@ let api = mesh.api = { mode, + modes, + selection, group, diff --git a/src/mesh/build.js b/src/mesh/build.js index 29b67934..5598558d 100644 --- a/src/mesh/build.js +++ b/src/mesh/build.js @@ -198,6 +198,7 @@ function ui_build() { h.div({ id: 'spinner', class: 'spin' }) ]), // display and action areas + h.div({ id: 'modes' }), h.div({ id: 'actions' }), h.div({ id: 'grouplist'}), h.div({ id: 'selectlist'}), @@ -205,7 +206,7 @@ function ui_build() { h.div({ id: 'download', class: "hide" }) ]); - let { actions, grouplist, selectlist, logger } = bound; + let { modes, actions, grouplist, selectlist, logger } = bound; // create slid in/out logging window h.bind(logger, [ h.div({ id: 'logtext' }) ]); @@ -213,6 +214,14 @@ function ui_build() { // a few shortcuts to api calls let { file, selection, mode, tool, prefs } = api; + // top/center mode selector + h.bind(modes, [ + 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() } }), + ]); + // create hotkey/action menu (top/left) h.bind(actions, [ h.div([ @@ -236,11 +245,6 @@ function ui_build() { h.button({ _: 'analyze', onclick: tool.analyze }), h.button({ _: 'repair', onclick: tool.repair }), h.button({ _: 'clean', onclick: tool.clean }), - h.div({ class: "vsep" }), - 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() } }), ]), ]); diff --git a/src/mesh/model.js b/src/mesh/model.js index 0312e2d0..867646be 100644 --- a/src/mesh/model.js +++ b/src/mesh/model.js @@ -82,6 +82,14 @@ mesh.model = class MeshModel extends mesh.object { face: materials.face.clone() }; + // information about selected faces, lines, and vertices + // vertex compound keys are sorted least index to greatest + this.sel = { + faces: [], // first index into vertices + lines: {}, // key = vertex-vertex, val = [ faces ] + verts: {}, // key = x-y-z, val = { faces:[], sphere } + }; + this.file = file || 'unnamed'; this.load(mesh || vertices, indices, normals); // persist in db so it can be restored on page load @@ -289,8 +297,52 @@ mesh.model = class MeshModel extends mesh.object { } } - updateSelectedFaces() { - let faces = this._faces = this._faces || []; + clearSelections() { + console.log('todo: clearSelections'); + } + + deleteSelections(mode) { + let { geometry } = this.mesh; + let { groups } = geometry; + let { array } = geometry.attributes.position; + let newtot = 0; + // filter to unselected groups + groups = groups.filter(g => g.materialIndex === 0); + for (let group of groups) { + let start = group.start * 3; + let count = group.count * 3; + newtot += group.count < Infinity ? count : array.length - start; + } + // nothing to do if new length is the same + if (newtot === array.length) { + return; + } + let newverts = new Float32Array(newtot); + let pos = 0; + // copy back unselected faces + for (let group of groups) { + let start = group.start * 3; + let count = group.count * 3; + if (count === Infinity) count = array.length - start; + let slice = array.slice(start, start + count); + newverts.set(slice, pos); + pos += count; + } + this.reload(newverts); + // clear face selections (since they've been deleted); + this.sel.faces = []; + this.updateSelections(); + + // let { modes } = mesh.api; + // switch (mode) { + // case modes.face: + // console.log('delete selected faces'); + // break; + // } + } + + updateSelections() { + let faces = this.sel.faces; let groups = []; if (faces && faces.length) { faces = faces.sort((a,b) => a - b).slice(); @@ -320,27 +372,51 @@ mesh.model = class MeshModel extends mesh.object { } toggleSelectedFaces(toggle = []) { - let faces = this._faces = this._faces || []; + let faces = this.sel.faces; for (let t of toggle) { faces.remove(t) || faces.addOnce(t); } - this.updateSelectedFaces(); + } + + toggleSelectedVertices(vert) { + if (Array.isArray(vert)) { + for (let e of vert) { + this.toggleSelectedVertices(e); + } + return; + } + let sel = this.sel; + let key = [x,y,z].map(v => v.round(5)).join('-'); + let rec = sel.verts[key]; + if (rec) { + delete sel.verts[key]; + space.scene.remove(rec.sphere); + } else { + let geometry = new THREE.SphereGeometry( 0.5, 16, 16 ); + let material = new MeshPhongMaterial( { color: 0x777777, transparent: true, opacity: 0.25 } ); + let sphere = new Mesh( geometry, material ); + sphere.position.set(x, y, z); + space.scene.add(sphere); + sel.verts[key] = { + sphere, + faces, + verts + }; + } } // find adjacent faces to clicked point/line on a face find(point, face) { - // let geometry = new THREE.SphereGeometry( 0.5, 16, 16 ); - // let material = new MeshPhongMaterial( { color: 0x777777, transparent: true, opacity: 0.25 } ); - // let sphere = new Mesh( geometry, material ); let { x, y, z } = point; let { a, b, c } = face; - // sphere.position.set(x,y,z); - // space.scene.add(sphere); worker.model_select({ id: this.id, x, y:-z, z:y, a, b, c, matrix: this.matrix }).then(data => { - let { faces, edges, verts } = data; + let { faces, edges, verts, point } = data; + console.log({data}); + // this.toggleSelectedVertices(verts); this.toggleSelectedFaces(faces); + this.updateSelections(); }); } diff --git a/src/mesh/work.js b/src/mesh/work.js index df0c0d96..5d21caed 100644 --- a/src/mesh/work.js +++ b/src/mesh/work.js @@ -114,6 +114,7 @@ let model = { let faces = []; let verts = []; let edges = []; + let point; for (let i=0, l=arr.length; i