sort out sketch element dragging

This commit is contained in:
Stewart Allen 2024-07-25 14:05:44 -04:00
commit 2eb3582eca
4 changed files with 113 additions and 48 deletions

View file

@ -329,22 +329,34 @@ function space_init(data) {
]);
// mouse hover/click handlers. required to enable model drag in space.js
space.mouse.downSelect((int, event) => {
// called two ways:
// without args to return a list of selectable targets
// with args when a selection is made
space.mouse.downSelect((int, event, ints) => {
if (int?.object?.sketch) {
int.object.sketch.drag({ start: int.object });
} else if (int?.object?.sketch_item) {
int.object.sketch_item.sketch.drag({ start: int.object });
}
if (event?.shiftKey) {
return api.objects();
} else {
return undefined;
}
return event && event.shiftKey ? api.objects() : undefined;
});
// called two ways:
// without args to return a list of selectable targets
// with args when a selection is made
space.mouse.upSelect((int, event, ints) => {
if (ints?.length > 1) {
// ensure sketch items are returned before sketch plane / handles
let polys = ints.filter(i => i.object.poly);
int = polys.length ? polys[0] : int;
let els = ints.filter(i => i.object.sketch_item);
int = els.length ? els[0] : int;
}
if (event && event.target.nodeName === "CANVAS") {
const model = int?.object?.model;
const sketch = int?.object?.sketch;
if (event?.target?.nodeName === "CANVAS") {
// a selection was made
const { model, sketch, sketch_item } = int?.object || {};
const { altKey, ctrlKey, metaKey, shiftKey } = event;
if (mesh.split.active()) {
return mesh.split.select(model);
@ -400,21 +412,25 @@ function space_init(data) {
} else {
selection.toggle(sketch);
}
} else if (sketch_item) {
sketch_item.toggle();
}
} else {
let sketches = api.selection.sketches(true);
// return objects upSelect can choose from
let visible = api.objects().filter(o => o.visible);
let sketches = api.selection.sketches();
if (sketches.length) {
// when sketch selected, return sketch items, too
return sketches[0].object.children;
// when sketch selected, append sketch items, too
visible.appendAll(sketches[0].object.children);
};
return api.objects().filter(o => o.visible);
return visible;
}
});
space.mouse.onDrag((delta, offset, up = false) => {
const { mode, modes } = api;
if (delta && delta.event.shiftKey) {
if (selection.count()) {
let { mode, modes } = api;
if (delta) {
if (delta.event?.shiftKey && selection.count()) {
selection.move(delta.x, delta.y, 0);
}
} else if (up) {
@ -422,7 +438,8 @@ function space_init(data) {
selection.drag({ end: true });
}
} else if (mode.is([ modes.object, modes.tool, modes.sketch ])) {
return api.objects().length > 0;
// return true if there are draggable elements
return api.objects().length > 0 || api.selection.sketches().length;
}
});
}

View file

@ -49,10 +49,6 @@ const selection = {
return grp;
},
sketches(strict) {
return selection.list(strict).filter(s => s.type === 'sketch');
},
// return selected models + models from selected groups
models(strict) {
let all = selection.list(strict);
@ -66,8 +62,12 @@ const selection = {
return mdl;
},
sketches(strict) {
return selection.list(strict).filter(s => s.type === 'sketch');
sketches() {
return selection.list(true).filter(s => s.type === 'sketch');
},
sketch_items() {
return selection.list(true).filter(s => s.type === 'sketch_item')
},
contains(object) {
@ -174,6 +174,7 @@ const selection = {
// update selection and wireframe for all objects
update() {
// de-select all
for (let group of groups) {
group.select(false);
group.normals(prefs.map.space.norm || false);

View file

@ -126,7 +126,9 @@ mesh.sketch = class MeshSketch extends mesh.object {
}
get meshes() {
return this.group.children.filter(c => c.sketch ? c : undefined);
return this.group.children.filter(c => {
return c.sketch || (c.sketch_item && c.sketch_item.selected) ? c : undefined
}).reverse();
}
rename(newname) {
@ -158,6 +160,7 @@ mesh.sketch = class MeshSketch extends mesh.object {
for (let handle of handles) {
handle.material = bool ? material.highlight : plane.material;
}
this.render();
return bool;
}
@ -183,6 +186,14 @@ mesh.sketch = class MeshSketch extends mesh.object {
scale.y += y * sf[1];
scale.z += z * sf[2];
this.update();
} else if (Array.isArray(dragging)) {
for (let item of dragging) {
let { center } = item;
center.x += x;
center.y += y;
center.z += z;
}
this.render();
} else {
this.center = {x, y, z};
this.update();
@ -190,9 +201,10 @@ mesh.sketch = class MeshSketch extends mesh.object {
}
drag(opt = {}) {
const { plane, handles, dragging } = this;
let { items } = this;
if (opt.start) {
this.dragging = opt.start;
let selected = items.filter(i => i.selected);
this.dragging = opt.start.sketch_item ? selected : opt.start;
} else if (opt.end) {
this.dragging = undefined;
} else {
@ -218,44 +230,79 @@ mesh.sketch = class MeshSketch extends mesh.object {
render() {
let { group } = this;
// remove previous item/poly-based children of group
group.children.filter(c => c.poly).forEach(c => group.remove(c));
group.children.filter(c => c.sketch_item).forEach(c => group.remove(c));
// mapy items into polys into meshes to add to group
this.items.map(item => {
let { type, center, width, height, radius, spacing, poly } = item;
if (type === 'circle') {
let circumference = 2 * Math.PI * radius;
let points = Math.floor(circumference / (spacing || 1));
poly = newPolygon().centerCircle(center, radius, points).annotate({ item } );
} else if (type === 'rectangle') {
poly = newPolygon().centerRectangle(center, width, height).annotate({ item });
}
return poly;
}).filter(o => o).forEach(poly => {
let vrt = poly.extrude(0).toFloat32();
let geo = new BufferGeometry();
geo.setAttribute('position', new BufferAttribute(vrt, 3));
let meh = new Mesh(geo, mesh.material.normal);
meh.renderOrder = -1;
meh.poly = poly;
group.add(meh);
});
for (let si of this.items.map(i => new SketchItem(this, i))) {
group.add(si.mesh);
}
this.update();
}
extrude(opt = {}) {
let { z } = opt;
let models = [];
for (let item of this.group.children.filter(c => c.poly)) {
let vert = item.poly.extrude(z || 10);
let nmdl = new mesh.model({ file: "poly", mesh: vert.toFloat32() });
console.log({ extrude: this });
for (let item of this.group.children.filter(c => c.sketch_item)) {
let vert = item.sketch_item.extrude(z || 10);
let nmdl = new mesh.model({ file: "item", mesh: vert.toFloat32() });
models.push(nmdl);
}
if (models.length) {
log('extrude', this.file || this.id, 'into', models.length, 'solid(s)');
let { center } = this;
let ngrp = api.group.new(models);
ngrp.floor();
ngrp.move(center.x, center.y, center.z + 0.001);
}
}
}
class SketchItem {
constructor(sketch, item) {
this.sketch = sketch;
this.item = item;
this.update();
}
get type() {
return "sketch_item";
}
get selected() {
return this.item.selected;
}
toggle() {
this.item.selected = !this.item.selected;
this.update();
this.sketch.render();
}
extrude(opt = {}) {
return this.poly.extrude(opt);
}
update() {
let { item, sketch } = this;
let { material } = mesh;
let { type, center, width, height, radius, spacing, poly, selected } = item;
if (type === 'circle') {
let circumference = 2 * Math.PI * radius;
let points = Math.floor(circumference / (spacing || 1));
poly = newPolygon().centerCircle(center, radius, points).annotate({ item } );
} else if (type === 'rectangle') {
poly = newPolygon().centerRectangle(center, width, height).annotate({ item });
} else {
throw `invalid sketch type: ${type}`;
}
this.poly = poly;
let vrt = poly.extrude(0).toFloat32();
let geo = new BufferGeometry();
geo.setAttribute('position', new BufferAttribute(vrt, 3));
let meh = this.mesh = new Mesh(geo, selected && sketch.select() ? material.select : material.normal);
meh.renderOrder = -1;
meh.sketch_item = this;
}
}
});

View file

@ -896,7 +896,7 @@ gapp.register("moto.space", [], (root, exports) => {
viewControl.enabled = false;
}
if (selectInt) {
mouseDownSelect(selectInt, event);
mouseDownSelect(selectInt, event, int);
}
if (mouseDown) mouseDown(event, int);
}