fix sketch move / normal calcs

This commit is contained in:
Stewart Allen 2024-07-24 19:30:44 -04:00
commit 27783b521b
5 changed files with 123 additions and 60 deletions

View file

@ -285,7 +285,7 @@ function space_init(data) {
case 'Backspace': case 'Backspace':
case 'Delete': case 'Delete':
let mode = api.mode.get(); 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(); selection.delete();
} else { } else {
for (let m of selection.models()) { for (let m of selection.models()) {
@ -334,9 +334,6 @@ function space_init(data) {
}); });
space.mouse.upSelect((int, event) => { space.mouse.upSelect((int, event) => {
if (int?.object?.sketch) {
int.object.sketch.drag({ end: int.object });
}
if (event && event.target.nodeName === "CANVAS") { if (event && event.target.nodeName === "CANVAS") {
const model = int?.object?.model; const model = int?.object?.model;
const sketch = int?.object?.sketch; const sketch = int?.object?.sketch;
@ -404,8 +401,14 @@ function space_init(data) {
space.mouse.onDrag((delta, offset, up = false) => { space.mouse.onDrag((delta, offset, up = false) => {
const { mode, modes } = api; const { mode, modes } = api;
if (delta && delta.event.shiftKey) { if (delta && delta.event.shiftKey) {
selection.count() && selection.move(delta.x, delta.y, 0); if (selection.count()) {
} else if (mode.is([ modes.object, modes.tool ])) { 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; return api.objects().length > 0;
} }
}); });

View file

@ -66,6 +66,10 @@ const selection = {
return mdl; return mdl;
}, },
sketches(strict) {
return selection.list(strict).filter(s => s.type === 'sketch');
},
contains(object) { contains(object) {
return selected.contains(object); return selected.contains(object);
}, },
@ -196,6 +200,13 @@ const selection = {
return selection; return selection;
}, },
drag(opt = {}) {
for (let s of selection.sketches()) {
s.drag(opt);
}
return selection;
},
move(dx = 0, dy = 0, dz = 0) { move(dx = 0, dy = 0, dz = 0) {
for (let s of [...selection.groups(), ...selection.sketches()]) { for (let s of [...selection.groups(), ...selection.sketches()]) {
s.move(dx, dy, dz); s.move(dx, dy, dz);
@ -425,6 +436,26 @@ let add = {
sketch.add(new mesh.sketch(opt)); 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() { input() {
api.modal.dialog({ api.modal.dialog({
title: "vertices", title: "vertices",
@ -448,6 +479,7 @@ let add = {
const nmdl = new mesh.model({ file: "box", mesh: vert }); const nmdl = new mesh.model({ file: "box", mesh: vert });
const ngrp = group.new([ nmdl ]); const ngrp = group.new([ nmdl ]);
ngrp.scale(10, 10, 10).floor(); ngrp.scale(10, 10, 10).floor();
return ngrp;
}, },
cylinder(opt = {}) { cylinder(opt = {}) {
@ -456,7 +488,7 @@ let add = {
api.modal.hide(); api.modal.hide();
if (diameter && height) { if (diameter && height) {
const center = { x:0, y:0, z:0 }; 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) facets = Math.max(3, facets || diameter * 3)
const cyl = newPolygon().centerCircle(center, diameter/2, facets); const cyl = newPolygon().centerCircle(center, diameter/2, facets);
if (bore && bore < diameter) { if (bore && bore < diameter) {
@ -469,7 +501,7 @@ let add = {
} }
} }
if (opt.facets && opt.diameter && opt.height) { if (opt.facets && opt.diameter && opt.height) {
gencyl(opt.diameter, opt.height, opt.facets); return gencyl(opt.diameter, opt.height, opt.facets);
} else { } else {
api.modal.dialog({ api.modal.dialog({
title: "cylinder", title: "cylinder",
@ -565,10 +597,10 @@ let file = {
id: m.id, matrix: m.matrix, file: m.file id: m.id, matrix: m.matrix, file: m.file
} }); } });
if (recs.length === 0) { if (recs.length === 0) {
return api.log.emit(`no models to export`); return log(`no models to export`);
} }
function doit(ext = 'obj') { 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"; let file = api.modal.bound.filename.value || "export.obj";
if (file.toLowerCase().indexOf(`.${ext}`) < 0) { if (file.toLowerCase().indexOf(`.${ext}`) < 0) {
file = `${file}.${ext}`; file = `${file}.${ext}`;
@ -607,9 +639,9 @@ const tool = {
merge(models) { merge(models) {
models = fallback(models); models = fallback(models);
if (models.length < 2) { 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 => { worker.model_merge(models.map(m => {
return { id: m.id, matrix: m.matrix } return { id: m.id, matrix: m.matrix }
})) }))
@ -620,16 +652,16 @@ const tool = {
mesh: data mesh: data
})]).promote(); })]).promote();
api.selection.set([group]); api.selection.set([group]);
api.log.emit('merge complete').unpin(); log('merge complete').unpin();
}); });
}, },
union(models) { union(models) {
models = fallback(models); models = fallback(models);
if (models.length < 2) { 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 => { worker.model_union(models.map(m => {
return { id: m.id, matrix: m.matrix } return { id: m.id, matrix: m.matrix }
})) }))
@ -642,19 +674,19 @@ const tool = {
api.selection.set([group]); api.selection.set([group]);
}) })
.catch(error => { .catch(error => {
api.log.emit(`union error: ${error}`); log(`union error: ${error}`);
}) })
.finally(() => { .finally(() => {
api.log.emit('union complete').unpin(); log('union complete').unpin();
}); });
}, },
difference(models) { difference(models) {
models = fallback(models); models = fallback(models);
if (models.length < 2) { 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 => { worker.model_difference(models.map(m => {
return { id: m.id, matrix: m.matrix } return { id: m.id, matrix: m.matrix }
})) }))
@ -667,19 +699,19 @@ const tool = {
api.selection.set([group]); api.selection.set([group]);
}) })
.catch(error => { .catch(error => {
api.log.emit(`diff error: ${error}`); log(`diff error: ${error}`);
}) })
.finally(() => { .finally(() => {
api.log.emit('diff complete').unpin(); log('diff complete').unpin();
}); });
}, },
intersect(models) { intersect(models) {
models = fallback(models); models = fallback(models);
if (models.length < 2) { 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 => { worker.model_intersect(models.map(m => {
return { id: m.id, matrix: m.matrix } return { id: m.id, matrix: m.matrix }
})) }))
@ -692,19 +724,19 @@ const tool = {
api.selection.set([group]); api.selection.set([group]);
}) })
.catch(error => { .catch(error => {
api.log.emit(`intersect error: ${error}`); log(`intersect error: ${error}`);
}) })
.finally(() => { .finally(() => {
api.log.emit('intersect complete').unpin(); log('intersect complete').unpin();
}); });
}, },
subtract(models) { subtract(models) {
models = fallback(models); models = fallback(models);
if (models.length < 2) { 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 => { worker.model_subtract(models.map(m => {
return { id: m.id, matrix: m.matrix, tool: m.tool() } return { id: m.id, matrix: m.matrix, tool: m.tool() }
})) }))
@ -717,10 +749,10 @@ const tool = {
api.selection.set([group]); api.selection.set([group]);
}) })
.catch(error => { .catch(error => {
api.log.emit(`subtract error: ${error}`); log(`subtract error: ${error}`);
}) })
.finally(() => { .finally(() => {
api.log.emit('subtract complete').unpin(); log('subtract complete').unpin();
}); });
}, },
@ -749,7 +781,7 @@ const tool = {
return; return;
} }
if (models.length > 1) { if (models.length > 1) {
return api.log.emit('rename requires a single selection'); return log('rename requires a single selection');
} }
let onclick = onkeydown = (ev) => { let onclick = onkeydown = (ev) => {
if (ev.code && ev.code !== 'Enter') { if (ev.code && ev.code !== 'Enter') {
@ -772,7 +804,7 @@ const tool = {
if (models.length === 0) { if (models.length === 0) {
return; return;
} }
api.log.emit(`regrouping ${models.length} model(s)`); log(`regrouping ${models.length} model(s)`);
let bounds = util.bounds(models); let bounds = util.bounds(models);
let { mid } = bounds; let { mid } = bounds;
return Promise.all(models.map(m => m.ungroup())).then(() => { return Promise.all(models.map(m => m.ungroup())).then(() => {
@ -785,7 +817,7 @@ const tool = {
analyze(models, opt = { compound: true }) { analyze(models, opt = { compound: true }) {
models = fallback(models); models = fallback(models);
api.log.emit('analyzing mesh(es)').pin(); log('analyzing mesh(es)').pin();
let promises = []; let promises = [];
let mcore = new Matrix4().makeRotationX(Math.PI / 2); let mcore = new Matrix4().makeRotationX(Math.PI / 2);
for (let m of models) { for (let m of models) {
@ -803,13 +835,13 @@ const tool = {
promises.push(p); promises.push(p);
} }
return Promise.all(promises).then(() => { return Promise.all(promises).then(() => {
api.log.emit('analysis complete').unpin(); log('analysis complete').unpin();
}); });
}, },
isolate(models) { isolate(models) {
models = fallback(models); models = fallback(models);
api.log.emit('isolating bodies').pin(); log('isolating bodies').pin();
let promises = []; let promises = [];
let mcore = new Matrix4().makeRotationX(Math.PI / 2); let mcore = new Matrix4().makeRotationX(Math.PI / 2);
let mark = Date.now(); let mark = Date.now();
@ -824,14 +856,14 @@ const tool = {
promises.push(p); promises.push(p);
} }
return Promise.all(promises).then(() => { return Promise.all(promises).then(() => {
api.log.emit('isolation complete').unpin(); log('isolation complete').unpin();
// api.log.emit(`... isolate time = ${Date.now() - mark}`); // log(`... isolate time = ${Date.now() - mark}`);
}); });
}, },
indexFaces(models, opt = {}) { indexFaces(models, opt = {}) {
models = fallback(models); models = fallback(models);
api.log.emit('mapping faces').pin(); log('mapping faces').pin();
let promises = []; let promises = [];
let mark = Date.now(); let mark = Date.now();
for (let m of models) { for (let m of models) {
@ -841,8 +873,8 @@ const tool = {
promises.push(p); promises.push(p);
} }
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
api.log.emit('mapping complete').unpin(); log('mapping complete').unpin();
// api.log.emit(`... index time = ${Date.now() - mark}`); // log(`... index time = ${Date.now() - mark}`);
}); });
}, },
@ -872,9 +904,9 @@ const tool = {
repair(models) { repair(models) {
models = fallback(models); models = fallback(models);
api.log.emit('repairing mesh(es)').pin(); log('repairing mesh(es)').pin();
tool.heal(models, { merge: true }).then(() => { tool.heal(models, { merge: true }).then(() => {
api.log.emit('repair commplete').unpin(); log('repair commplete').unpin();
api.selection.update(); api.selection.update();
}); });
}, },
@ -882,7 +914,7 @@ const tool = {
clean(models) { clean(models) {
models = fallback(models); models = fallback(models);
tool.heal(models, { merge: false }).then(() => { tool.heal(models, { merge: false }).then(() => {
api.log.emit('cleaning complete').unpin(); log('cleaning complete').unpin();
api.selection.update(); api.selection.update();
}); });
}, },
@ -1172,6 +1204,10 @@ const api = exports({
isDebug: self.debug === true isDebug: self.debug === true
}); });
function log() {
api.log.emit(...arguments);
}
const { broker } = gapp; const { broker } = gapp;
const call = broker.send; const call = broker.send;

View file

@ -398,9 +398,11 @@ function ui_build() {
h.div({ _: "add", class: "head" }), h.div({ _: "add", class: "head" }),
h.div({ class: "back"}), h.div({ class: "back"}),
h.div({ class: "pop"}, [ h.div({ class: "pop"}, [
h.button({ _: 'circle', onclick() { add.cylinder() } }), h.button({ _: 'circle', onclick() { add.circle() } }),
h.button({ _: 'square', onclick() { add.cube() } }), h.button({ _: 'rectangle', onclick() { add.rectangle() } }),
h.button({ _: 'gear', onclick() { add.gear() } }), // h.button({ _: 'gear', onclick() { add.gear() } }),
h.hr(),
h.button({ _: 'sketch', onclick() { add.sketch() } }),
]) ])
]), ]),
h.div([ h.div([

View file

@ -7,7 +7,7 @@
// dep: moto.license // dep: moto.license
// dep: moto.client // dep: moto.client
// dep: mesh.object // dep: mesh.object
// use: mesh.api // dep: mesh.api
// use: mesh.util // use: mesh.util
// use: mesh.group // use: mesh.group
gapp.register("mesh.sketch", [], (root, exports) => { 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 { PlaneGeometry, EdgesGeometry, SphereGeometry, Vector3, Mesh, Group } = THREE;
const { mesh, moto } = root; const { mesh, moto } = root;
const { space } = moto; const { space } = moto;
const { api, util } = mesh;
const mapp = mesh; const mapp = mesh;
const worker = moto.client.fn; const worker = moto.client.fn;
@ -26,6 +27,10 @@ const material = {
highlight: new LineBasicMaterial({ color: 0x88ffdd, side: DoubleSide, transparent: true, opacity: 0.50 }), 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 **/ /** 2D plane containing open and closed polygons which can be extruded **/
mesh.sketch = class MeshSketch extends mesh.object { mesh.sketch = class MeshSketch extends mesh.object {
constructor(opt = {}) { constructor(opt = {}) {
@ -65,35 +70,43 @@ mesh.sketch = class MeshSketch extends mesh.object {
group.add(outline); group.add(outline);
group.add(plane); group.add(plane);
this.update(); util.defer(() => this.update());
} }
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; // group.rotation.x = -Math.PI/2;
plane.scale.set(scale.x, scale.y, 1); 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.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++) { for (let i=0; i<4; i++) {
const handle = handles[i]; const handle = handles[i];
const corner = corners[i]; const corner = corners[i];
handle.position.set( handle.position.set(
(corner[0] * scale.x) + center.x, (corner[0] * scale.x),// + center.x,
(corner[1] * scale.y) + center.y, (corner[1] * scale.y),// + center.y,
(corner[2] * scale.z) + center.z (corner[2] * scale.z),// + center.z
); );
} }
// const nv = new Vector3(normal.x, normal.y, normal.z); const { position } = group;
// const tp = new Vector3().addVectors(group.position, nv); group.lookAt(new Vector3(
// group.lookAt(tp); normal.x + position.x,
normal.z + position.z,
normal.y - position.y,
));
this.#db_save(); this.#db_save();
} }
lookat(x,y,z) {
this.group.lookAt(new Vector3(x,y,z));
moto.space.update();
}
#db_save() { #db_save() {
const { center, normal, scale, type, file } = this; const { center, normal, scale, type, file } = this;
mapp.db.space.put(this.id, { center, normal, scale, type, file }); 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) { 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); const handle = handles.indexOf(dragging);
if (dragging === plane) { if (dragging === plane) {
center.x += x; center.x += x;
@ -171,22 +184,30 @@ mesh.sketch = class MeshSketch extends mesh.object {
scale.z += z * sf[2]; scale.z += z * sf[2];
this.update(); this.update();
} else { } else {
console.log({ sketch_move: [...arguments] }); this.center = {x, y, z};
this.update();
} }
} }
drag(opt = {}) { drag(opt = {}) {
const { plane, handles, dragging } = this; const { plane, handles, dragging } = this;
if (opt.start) { if (opt.start) {
// console.log({ drag_start: opt.start, plane, same: opt.start === plane });
this.dragging = opt.start; this.dragging = opt.start;
} else if (opt.end) { } else if (opt.end) {
console.log({ drag_end: opt.end }); this.dragging = undefined;
} else { } else {
console.log({ invalid_sketch_drag: opt }); console.log({ invalid_sketch_drag: opt });
} }
} }
add_circle() {
log(this.file || this.id, '| add circle');
}
add_rectangle() {
log(this.file || this.id, '| add rectangle');
}
} }
}); });

View file

@ -963,6 +963,7 @@ gapp.register("moto.space", [], (root, exports) => {
} }
mouseStart = null; mouseStart = null;
} else if (mouseDrag && mouseDragStart) { } else if (mouseDrag && mouseDragStart) {
// fired on mouse drag end
mouseDrag(null,null,true); mouseDrag(null,null,true);
} }
mouseDragPoint = null; mouseDragPoint = null;