From 72d9469699315b5eca06c6229acaa979ac63f162 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sat, 15 Jan 2022 23:17:53 -0500 Subject: [PATCH] add z split snapping and work translation caching --- src/main/mesh.js | 38 ++++++++++++++++++++++++++++++-------- src/mesh/model.js | 16 +++++++++++++--- src/mesh/work.js | 28 +++++++++++++++++++++++----- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/main/mesh.js b/src/main/mesh.js index 21b3c859..d2219fc7 100644 --- a/src/main/mesh.js +++ b/src/main/mesh.js @@ -145,30 +145,52 @@ let split = { geo = new PlaneGeometry(1,1), mat = new MeshPhongMaterial({ side: DoubleSide, - color: 0x999999, + color: 0x5555aa, transparent: false, - opacity: 0.1 + opacity: 0.5 }) ); space.scene.add(obj); + // hide until first hover + obj.visible = false; // enable temp mode - let state = split.state = { button, obj }; + let state = split.state = { button, obj, zlist:[] }; + let models = state.models = api.selection.models(); + let meshes = models.map(m => m.mesh); + // get z list for snapping + Promise.all(models.map(m => m.zlist(3))).then(zs => { + for (let z of zs.flat()) { + state.zlist.addOnce(z); + } + }); // for split and lay flat modes space.mouse.onHover((int, event, ints) => { - let models = state.models = api.selection.models(); - let meshes = models.map(m => m.mesh); if (!event) { return meshes; } + obj.visible = false; let { button, buttons } = event; if (buttons) { return; } let { dim, mid } = util.bounds(meshes); let { x, y, z } = int.point; + // snap to zlist when shift pressed + let { zlist } = state; + mat.color.set(0x5555aa); + obj.visible = true; + if (event.shiftKey && zlist.length) { + for (let v of zlist) { + if (Math.abs(v - y) < 0.1) { + mat.color.set(0xaa5555); + y = v; + break; + } + } + } // y is z in model space for the purposes of a split state.plane = { z: y }; - obj.scale.set(dim.x, dim.y, 1); + obj.scale.set(dim.x + 2, dim.y + 2, 1); obj.position.set(mid.x, y, -mid.y); }); temp_mode = split; @@ -176,9 +198,9 @@ let split = { select() { let { log } = mesh.api; - let { models, plane } = split.state; + let { models, plane, zlist } = split.state; log.emit(`splitting ${models.length} model(s) at ${plane.z.round(3)}`).pin(); - Promise.all(models.map(m => m.split(plane))).then(() => { + Promise.all(models.map(m => m.split(plane))).then(models => { log.emit('split complete').unpin(); split.end(); }); diff --git a/src/mesh/model.js b/src/mesh/model.js index 4904cb51..b9f5fe42 100644 --- a/src/mesh/model.js +++ b/src/mesh/model.js @@ -350,9 +350,10 @@ mesh.model = class MeshModel extends mesh.object { let { id, matrix } = this; worker.model_split({id, matrix, z}).then(data => { let { o1, o2 } = data; + let model; // new model becomes top if (o2.length) - this.group.add(new mesh.model({ + this.group.add(model = new mesh.model({ file: `${this.file}`, mesh: o2 }).applyMatrix4(m4)).select(); @@ -362,8 +363,17 @@ mesh.model = class MeshModel extends mesh.object { } else { this.remove(); } - // and we're done - resolve(); + // return the split model + resolve(model); + }); + }); + } + + zlist(round = 2) { + return new Promise((resolve,reject) => { + let { id, matrix } = this; + worker.model_zlist({id, matrix, round}).then(data => { + resolve(data); }); }); } diff --git a/src/mesh/work.js b/src/mesh/work.js index c6a56d5d..f3d117b4 100644 --- a/src/mesh/work.js +++ b/src/mesh/work.js @@ -36,10 +36,15 @@ function cacheUpdate(id, data) { // translate original mesh vertices into UI world view (PI/2 rotation on X) function translate_encode(id, matrix) { let rec = cache[id]; - let geo = rec.geo.clone(); - let mat = core_matrix.clone().multiply(new Matrix4().fromArray(matrix)); - geo.applyMatrix4(mat); - return geo.attributes.position.array; + let mkey = matrix.map(v => v.round(6)).join('-'); + if (!rec || !rec.trans || rec.mkey !== mkey) { + let geo = rec.geo.clone(); + let mat = core_matrix.clone().multiply(new Matrix4().fromArray(matrix)); + geo.applyMatrix4(mat); + rec.mkey = mkey; + rec.trans = geo.attributes.position.array + } + return rec.trans; } function analyze(id, opt = {}) { @@ -62,7 +67,7 @@ let model = { let geo = new BufferGeometry(); geo.setAttribute('position', new BufferAttribute(vertices, 3)); if (indices) geo.setIndex(new BufferAttribute(indices, 1)); - cacheUpdate(id, { name, geo, matrix: core_matrix.clone() }); + cacheUpdate(id, { name, geo, xmatrix: core_matrix.clone(), trans: undefined }); }, // return new vertices in world coordinates @@ -83,6 +88,19 @@ let model = { return data; }, + // used to generate a list for split snapping + zlist(data) { + let { id, matrix, round } = data; + let zlist = {}; + let pos = translate_encode(id, matrix); + for (let i=0, l=pos.length; i