From 27783b521b0c8d3733349a790f30aeeff0441d23 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Wed, 24 Jul 2024 19:30:44 -0400 Subject: [PATCH] fix sketch move / normal calcs --- src/main/mesh.js | 15 ++++--- src/mesh/api.js | 108 ++++++++++++++++++++++++++++++--------------- src/mesh/build.js | 8 ++-- src/mesh/sketch.js | 51 ++++++++++++++------- src/moto/space.js | 1 + 5 files changed, 123 insertions(+), 60 deletions(-) diff --git a/src/main/mesh.js b/src/main/mesh.js index 420b1b65..87a71b42 100644 --- a/src/main/mesh.js +++ b/src/main/mesh.js @@ -285,7 +285,7 @@ function space_init(data) { case 'Backspace': case 'Delete': let mode = api.mode.get(); - if ([api.modes.object, api.modes.tool].contains(mode)) { + if ([api.modes.object, api.modes.tool, api.modes.sketch].contains(mode)) { selection.delete(); } else { for (let m of selection.models()) { @@ -334,9 +334,6 @@ function space_init(data) { }); space.mouse.upSelect((int, event) => { - if (int?.object?.sketch) { - int.object.sketch.drag({ end: int.object }); - } if (event && event.target.nodeName === "CANVAS") { const model = int?.object?.model; const sketch = int?.object?.sketch; @@ -404,8 +401,14 @@ function space_init(data) { space.mouse.onDrag((delta, offset, up = false) => { const { mode, modes } = api; if (delta && delta.event.shiftKey) { - selection.count() && selection.move(delta.x, delta.y, 0); - } else if (mode.is([ modes.object, modes.tool ])) { + if (selection.count()) { + selection.move(delta.x, delta.y, 0); + } + } else if (up) { + if (selection.count()) { + selection.drag({ end: true }); + } + } else if (mode.is([ modes.object, modes.tool, modes.sketch ])) { return api.objects().length > 0; } }); diff --git a/src/mesh/api.js b/src/mesh/api.js index 1aaa4469..58310115 100644 --- a/src/mesh/api.js +++ b/src/mesh/api.js @@ -66,6 +66,10 @@ const selection = { return mdl; }, + sketches(strict) { + return selection.list(strict).filter(s => s.type === 'sketch'); + }, + contains(object) { return selected.contains(object); }, @@ -196,6 +200,13 @@ const selection = { return selection; }, + drag(opt = {}) { + for (let s of selection.sketches()) { + s.drag(opt); + } + return selection; + }, + move(dx = 0, dy = 0, dz = 0) { for (let s of [...selection.groups(), ...selection.sketches()]) { s.move(dx, dy, dz); @@ -425,6 +436,26 @@ let add = { sketch.add(new mesh.sketch(opt)); }, + /** add sketch components */ + + circle() { + let sel = selection.sketches(); + if (!sel.length) { + return log('select a sketch'); + } + return sel[0].add_circle(...arguments); + }, + + rectangle() { + let sel = selection.sketches(); + if (!sel.length) { + return log('select a sketch'); + } + return sel[0].add_rectangle(...arguments); + }, + + /** add models */ + input() { api.modal.dialog({ title: "vertices", @@ -448,6 +479,7 @@ let add = { const nmdl = new mesh.model({ file: "box", mesh: vert }); const ngrp = group.new([ nmdl ]); ngrp.scale(10, 10, 10).floor(); + return ngrp; }, cylinder(opt = {}) { @@ -456,7 +488,7 @@ let add = { api.modal.hide(); if (diameter && height) { const center = { x:0, y:0, z:0 }; - api.log.emit(`add cylinder faces=${facets} height=${height} diameter=${diameter}`); + log(`add cylinder faces=${facets} height=${height} diameter=${diameter}`); facets = Math.max(3, facets || diameter * 3) const cyl = newPolygon().centerCircle(center, diameter/2, facets); if (bore && bore < diameter) { @@ -469,7 +501,7 @@ let add = { } } if (opt.facets && opt.diameter && opt.height) { - gencyl(opt.diameter, opt.height, opt.facets); + return gencyl(opt.diameter, opt.height, opt.facets); } else { api.modal.dialog({ title: "cylinder", @@ -565,10 +597,10 @@ let file = { id: m.id, matrix: m.matrix, file: m.file } }); if (recs.length === 0) { - return api.log.emit(`no models to export`); + return log(`no models to export`); } function doit(ext = 'obj') { - api.log.emit(`exporting ${recs.length} model(s)`); + log(`exporting ${recs.length} model(s)`); let file = api.modal.bound.filename.value || "export.obj"; if (file.toLowerCase().indexOf(`.${ext}`) < 0) { file = `${file}.${ext}`; @@ -607,9 +639,9 @@ const tool = { merge(models) { models = fallback(models); if (models.length < 2) { - return api.log.emit('nothing to merge'); + return log('nothing to merge'); } - api.log.emit(`merging ${models.length} models`).pin(); + log(`merging ${models.length} models`).pin(); worker.model_merge(models.map(m => { return { id: m.id, matrix: m.matrix } })) @@ -620,16 +652,16 @@ const tool = { mesh: data })]).promote(); api.selection.set([group]); - api.log.emit('merge complete').unpin(); + log('merge complete').unpin(); }); }, union(models) { models = fallback(models); if (models.length < 2) { - return api.log.emit('nothing to union'); + return log('nothing to union'); } - api.log.emit(`union ${models.length} models`).pin(); + log(`union ${models.length} models`).pin(); worker.model_union(models.map(m => { return { id: m.id, matrix: m.matrix } })) @@ -642,19 +674,19 @@ const tool = { api.selection.set([group]); }) .catch(error => { - api.log.emit(`union error: ${error}`); + log(`union error: ${error}`); }) .finally(() => { - api.log.emit('union complete').unpin(); + log('union complete').unpin(); }); }, difference(models) { models = fallback(models); if (models.length < 2) { - return api.log.emit('nothing to diff'); + return log('nothing to diff'); } - api.log.emit(`diff ${models.length} models`).pin(); + log(`diff ${models.length} models`).pin(); worker.model_difference(models.map(m => { return { id: m.id, matrix: m.matrix } })) @@ -667,19 +699,19 @@ const tool = { api.selection.set([group]); }) .catch(error => { - api.log.emit(`diff error: ${error}`); + log(`diff error: ${error}`); }) .finally(() => { - api.log.emit('diff complete').unpin(); + log('diff complete').unpin(); }); }, intersect(models) { models = fallback(models); if (models.length < 2) { - return api.log.emit('nothing to intersect'); + return log('nothing to intersect'); } - api.log.emit(`intersect ${models.length} models`).pin(); + log(`intersect ${models.length} models`).pin(); worker.model_intersect(models.map(m => { return { id: m.id, matrix: m.matrix } })) @@ -692,19 +724,19 @@ const tool = { api.selection.set([group]); }) .catch(error => { - api.log.emit(`intersect error: ${error}`); + log(`intersect error: ${error}`); }) .finally(() => { - api.log.emit('intersect complete').unpin(); + log('intersect complete').unpin(); }); }, subtract(models) { models = fallback(models); if (models.length < 2) { - return api.log.emit('nothing to subtract'); + return log('nothing to subtract'); } - api.log.emit(`subtract ${models.length} models`).pin(); + log(`subtract ${models.length} models`).pin(); worker.model_subtract(models.map(m => { return { id: m.id, matrix: m.matrix, tool: m.tool() } })) @@ -717,10 +749,10 @@ const tool = { api.selection.set([group]); }) .catch(error => { - api.log.emit(`subtract error: ${error}`); + log(`subtract error: ${error}`); }) .finally(() => { - api.log.emit('subtract complete').unpin(); + log('subtract complete').unpin(); }); }, @@ -749,7 +781,7 @@ const tool = { return; } if (models.length > 1) { - return api.log.emit('rename requires a single selection'); + return log('rename requires a single selection'); } let onclick = onkeydown = (ev) => { if (ev.code && ev.code !== 'Enter') { @@ -772,7 +804,7 @@ const tool = { if (models.length === 0) { return; } - api.log.emit(`regrouping ${models.length} model(s)`); + log(`regrouping ${models.length} model(s)`); let bounds = util.bounds(models); let { mid } = bounds; return Promise.all(models.map(m => m.ungroup())).then(() => { @@ -785,7 +817,7 @@ const tool = { analyze(models, opt = { compound: true }) { models = fallback(models); - api.log.emit('analyzing mesh(es)').pin(); + log('analyzing mesh(es)').pin(); let promises = []; let mcore = new Matrix4().makeRotationX(Math.PI / 2); for (let m of models) { @@ -803,13 +835,13 @@ const tool = { promises.push(p); } return Promise.all(promises).then(() => { - api.log.emit('analysis complete').unpin(); + log('analysis complete').unpin(); }); }, isolate(models) { models = fallback(models); - api.log.emit('isolating bodies').pin(); + log('isolating bodies').pin(); let promises = []; let mcore = new Matrix4().makeRotationX(Math.PI / 2); let mark = Date.now(); @@ -824,14 +856,14 @@ const tool = { promises.push(p); } return Promise.all(promises).then(() => { - api.log.emit('isolation complete').unpin(); - // api.log.emit(`... isolate time = ${Date.now() - mark}`); + log('isolation complete').unpin(); + // log(`... isolate time = ${Date.now() - mark}`); }); }, indexFaces(models, opt = {}) { models = fallback(models); - api.log.emit('mapping faces').pin(); + log('mapping faces').pin(); let promises = []; let mark = Date.now(); for (let m of models) { @@ -841,8 +873,8 @@ const tool = { promises.push(p); } Promise.all(promises).then(() => { - api.log.emit('mapping complete').unpin(); - // api.log.emit(`... index time = ${Date.now() - mark}`); + log('mapping complete').unpin(); + // log(`... index time = ${Date.now() - mark}`); }); }, @@ -872,9 +904,9 @@ const tool = { repair(models) { models = fallback(models); - api.log.emit('repairing mesh(es)').pin(); + log('repairing mesh(es)').pin(); tool.heal(models, { merge: true }).then(() => { - api.log.emit('repair commplete').unpin(); + log('repair commplete').unpin(); api.selection.update(); }); }, @@ -882,7 +914,7 @@ const tool = { clean(models) { models = fallback(models); tool.heal(models, { merge: false }).then(() => { - api.log.emit('cleaning complete').unpin(); + log('cleaning complete').unpin(); api.selection.update(); }); }, @@ -1172,6 +1204,10 @@ const api = exports({ isDebug: self.debug === true }); +function log() { + api.log.emit(...arguments); +} + const { broker } = gapp; const call = broker.send; diff --git a/src/mesh/build.js b/src/mesh/build.js index 703c33b9..6763c959 100644 --- a/src/mesh/build.js +++ b/src/mesh/build.js @@ -398,9 +398,11 @@ function ui_build() { h.div({ _: "add", class: "head" }), h.div({ class: "back"}), h.div({ class: "pop"}, [ - h.button({ _: 'circle', onclick() { add.cylinder() } }), - h.button({ _: 'square', onclick() { add.cube() } }), - h.button({ _: 'gear', onclick() { add.gear() } }), + h.button({ _: 'circle', onclick() { add.circle() } }), + h.button({ _: 'rectangle', onclick() { add.rectangle() } }), + // h.button({ _: 'gear', onclick() { add.gear() } }), + h.hr(), + h.button({ _: 'sketch', onclick() { add.sketch() } }), ]) ]), h.div([ diff --git a/src/mesh/sketch.js b/src/mesh/sketch.js index 3afe991c..a98fb78e 100644 --- a/src/mesh/sketch.js +++ b/src/mesh/sketch.js @@ -7,7 +7,7 @@ // dep: moto.license // dep: moto.client // dep: mesh.object -// use: mesh.api +// dep: mesh.api // use: mesh.util // use: mesh.group gapp.register("mesh.sketch", [], (root, exports) => { @@ -16,6 +16,7 @@ const { MeshBasicMaterial, LineBasicMaterial, LineSegments, DoubleSide } = THREE const { PlaneGeometry, EdgesGeometry, SphereGeometry, Vector3, Mesh, Group } = THREE; const { mesh, moto } = root; const { space } = moto; +const { api, util } = mesh; const mapp = mesh; const worker = moto.client.fn; @@ -26,6 +27,10 @@ const material = { highlight: new LineBasicMaterial({ color: 0x88ffdd, side: DoubleSide, transparent: true, opacity: 0.50 }), }; +function log() { + mesh.api.log.emit(...arguments); +} + /** 2D plane containing open and closed polygons which can be extruded **/ mesh.sketch = class MeshSketch extends mesh.object { constructor(opt = {}) { @@ -65,35 +70,43 @@ mesh.sketch = class MeshSketch extends mesh.object { group.add(outline); group.add(plane); - this.update(); + util.defer(() => this.update()); } update() { - const { plane, outline, center, handles, corners, normal, scale } = this; + const { group, plane, outline, center, handles, corners, normal, scale } = this; // group.rotation.x = -Math.PI/2; plane.scale.set(scale.x, scale.y, 1); - plane.position.set(center.x, center.y, center.z); + group.position.set(center.x, center.y, center.z); outline.scale.set(scale.x, scale.y, 1); - outline.position.set(center.x, center.y, center.z); + // outline.position.set(center.x, center.y, center.z); for (let i=0; i<4; i++) { const handle = handles[i]; const corner = corners[i]; handle.position.set( - (corner[0] * scale.x) + center.x, - (corner[1] * scale.y) + center.y, - (corner[2] * scale.z) + center.z + (corner[0] * scale.x),// + center.x, + (corner[1] * scale.y),// + center.y, + (corner[2] * scale.z),// + center.z ); } - // const nv = new Vector3(normal.x, normal.y, normal.z); - // const tp = new Vector3().addVectors(group.position, nv); - // group.lookAt(tp); + const { position } = group; + group.lookAt(new Vector3( + normal.x + position.x, + normal.z + position.z, + normal.y - position.y, + )); this.#db_save(); } + lookat(x,y,z) { + this.group.lookAt(new Vector3(x,y,z)); + moto.space.update(); + } + #db_save() { const { center, normal, scale, type, file } = this; mapp.db.space.put(this.id, { center, normal, scale, type, file }); @@ -149,7 +162,7 @@ mesh.sketch = class MeshSketch extends mesh.object { } move(x, y, z = 0) { - const { center, scale, plane, handles, dragging } = this; + const { group, center, scale, plane, handles, dragging } = this; const handle = handles.indexOf(dragging); if (dragging === plane) { center.x += x; @@ -171,22 +184,30 @@ mesh.sketch = class MeshSketch extends mesh.object { scale.z += z * sf[2]; this.update(); } else { - console.log({ sketch_move: [...arguments] }); + this.center = {x, y, z}; + this.update(); } } drag(opt = {}) { const { plane, handles, dragging } = this; if (opt.start) { - // console.log({ drag_start: opt.start, plane, same: opt.start === plane }); this.dragging = opt.start; } else if (opt.end) { - console.log({ drag_end: opt.end }); + this.dragging = undefined; } else { console.log({ invalid_sketch_drag: opt }); } } + add_circle() { + log(this.file || this.id, '| add circle'); + } + + add_rectangle() { + log(this.file || this.id, '| add rectangle'); + } + } }); \ No newline at end of file diff --git a/src/moto/space.js b/src/moto/space.js index 3104db4c..2a81ad34 100644 --- a/src/moto/space.js +++ b/src/moto/space.js @@ -963,6 +963,7 @@ gapp.register("moto.space", [], (root, exports) => { } mouseStart = null; } else if (mouseDrag && mouseDragStart) { + // fired on mouse drag end mouseDrag(null,null,true); } mouseDragPoint = null;