add sketch scaling, selection persistence
This commit is contained in:
parent
acc6f652c2
commit
ef0f4c3efd
4 changed files with 108 additions and 29 deletions
|
|
@ -131,8 +131,8 @@ async function restore_space() {
|
|||
db_space.remove(id);
|
||||
}
|
||||
} else if (data.type === 'sketch') {
|
||||
claimed.push(data);
|
||||
mesh.api.add.sketch(data);
|
||||
claimed.push(id);
|
||||
mesh.api.add.sketch({ id, ...data });
|
||||
}
|
||||
}
|
||||
for (let id of claimed) {
|
||||
|
|
@ -163,7 +163,8 @@ async function restore_space() {
|
|||
let tolist = space.tools || [];
|
||||
let tmodel = api.model.list().filter(m => tolist.contains(m.id));
|
||||
let tgroup = api.group.list().filter(m => tolist.contains(m.id));
|
||||
api.selection.set([...smodel, ...sgroup], [...tmodel, ...tgroup]);
|
||||
let sklist = api.sketch.list().filter(s => selist.contains(s.id));
|
||||
api.selection.set([...smodel, ...sgroup, ...sklist], [...tmodel, ...tgroup]);
|
||||
// restore edit mode
|
||||
api.mode[mode]();
|
||||
// restore dark mode
|
||||
|
|
@ -326,10 +327,16 @@ function space_init(data) {
|
|||
|
||||
// mouse hover/click handlers. required to enable model drag in space.js
|
||||
space.mouse.downSelect((int, event) => {
|
||||
if (int?.object?.sketch) {
|
||||
int.object.sketch.drag({ start: int.object });
|
||||
}
|
||||
return event && event.shiftKey ? api.objects() : undefined;
|
||||
});
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ 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);
|
||||
|
|
@ -81,6 +85,7 @@ const selection = {
|
|||
case 'sketch':
|
||||
selected = selected.filter(s => s.type === 'sketch');
|
||||
tools.length = 0;
|
||||
mesh.edges?.end();
|
||||
break;
|
||||
case 'group':
|
||||
case 'model':
|
||||
|
|
@ -191,7 +196,7 @@ const selection = {
|
|||
},
|
||||
|
||||
move(dx = 0, dy = 0, dz = 0) {
|
||||
for (let s of selection.groups()) {
|
||||
for (let s of [...selection.groups(), ...selection.sketches()]) {
|
||||
s.move(dx, dy, dz);
|
||||
}
|
||||
return selection;
|
||||
|
|
@ -1144,7 +1149,7 @@ const api = exports({
|
|||
// return model objects suitable for finding ray intersections
|
||||
return [
|
||||
...group.list().map(o => o.models).flat().map(o => o.mesh),
|
||||
...sketches.map(s => s.object)
|
||||
...sketches.map(s => s.meshes).flat()
|
||||
];
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
gapp.register("mesh.sketch", [], (root, exports) => {
|
||||
|
||||
const { MeshBasicMaterial, LineBasicMaterial, LineSegments, DoubleSide } = THREE;
|
||||
const { PlaneGeometry, EdgesGeometry, SphereGeometry, Vector3, Mesh } = THREE;
|
||||
const { PlaneGeometry, EdgesGeometry, SphereGeometry, Vector3, Mesh, Group } = THREE;
|
||||
const { mesh, moto } = root;
|
||||
const { space } = moto;
|
||||
|
||||
|
|
@ -21,11 +21,9 @@ const mapp = mesh;
|
|||
const worker = moto.client.fn;
|
||||
|
||||
const material = {
|
||||
plane: new MeshBasicMaterial({ color: 0x888888, side: DoubleSide, transparent: true, opacity: 0.25 }),
|
||||
outline: new LineBasicMaterial({ color: 0x88dddd, side: DoubleSide, transparent: true, opacity: 0.25 }),
|
||||
handle: new MeshBasicMaterial({ color: 0x88dddd, side: DoubleSide, transparent: true, opacity: 0.25 }),
|
||||
highlight: new LineBasicMaterial({ color: 0x88ffdd, side: DoubleSide, transparent: true, opacity: 0.5 }),
|
||||
selected: new MeshBasicMaterial({ color: 0x88aa88, side: DoubleSide, transparent: true, opacity: 0.25 }),
|
||||
normal: new MeshBasicMaterial({ color: 0x888888, side: DoubleSide, transparent: true, opacity: 0.25 }),
|
||||
selected: new MeshBasicMaterial({ color: 0x889988, side: DoubleSide, transparent: true, opacity: 0.25 }),
|
||||
highlight: new LineBasicMaterial({ color: 0x88ffdd, side: DoubleSide, transparent: true, opacity: 0.50 }),
|
||||
};
|
||||
|
||||
/** 2D plane containing open and closed polygons which can be extruded **/
|
||||
|
|
@ -34,45 +32,64 @@ mesh.sketch = class MeshSketch extends mesh.object {
|
|||
super(opt.id);
|
||||
|
||||
this.file = opt.file || this.id;
|
||||
this.scale = opt.scale || { x: 10, y: 10 };
|
||||
this.scale = opt.scale || { x: 10, y: 10, z: 0 };
|
||||
this.center = opt.center || { x: 0, y: 0, z: 0 };
|
||||
this.normal = opt.normal || { x: 0, y: 0, z: 1 };
|
||||
|
||||
const planeGeometry = new PlaneGeometry(1, 1);
|
||||
const planeMaterial = material.plane;
|
||||
const plane = this.plane = new Mesh(planeGeometry, planeMaterial);
|
||||
const group = this.group = new Group();
|
||||
group.sketch = this;
|
||||
|
||||
const outlineGeometry = new EdgesGeometry(planeGeometry);
|
||||
const outlineMaterial = material.outline;
|
||||
const outline = this.outline = new LineSegments(outlineGeometry, outlineMaterial);
|
||||
plane.add(outline);
|
||||
const planeGeometry = new PlaneGeometry(1, 1);
|
||||
const planeMaterial = material.normal;
|
||||
const plane = this.plane = new Mesh(planeGeometry, planeMaterial);
|
||||
plane.sketch = this;
|
||||
|
||||
const handleGeometry = new SphereGeometry(0.05, 16, 16);
|
||||
const handleMaterial = material.handle;
|
||||
const outlineGeometry = new EdgesGeometry(planeGeometry);
|
||||
const outlineMaterial = material.normal;
|
||||
const outline = this.outline = new LineSegments(outlineGeometry, outlineMaterial);
|
||||
|
||||
const handles = [];
|
||||
const corners = [ [-0.5, 0.5, 0], [0.5, 0.5, 0], [-0.5, -0.5, 0], [0.5, -0.5, 0] ];
|
||||
const handleGeometry = new SphereGeometry(0.5, 16, 16);
|
||||
const handleMaterial = material.normal;
|
||||
|
||||
const handles = this.handles = [];
|
||||
const corners = this.corners = [ [-0.5, 0.5, 0], [0.5, 0.5, 0], [-0.5, -0.5, 0], [0.5, -0.5, 0] ];
|
||||
|
||||
for (let corner of corners) {
|
||||
const handle = new Mesh(handleGeometry, handleMaterial);
|
||||
handle.position.set(...corner);
|
||||
plane.add(handle);
|
||||
handles.push(handle);
|
||||
group.add(handle);
|
||||
handle.sketch = this;
|
||||
}
|
||||
|
||||
group.add(outline);
|
||||
group.add(plane);
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
update() {
|
||||
const { plane, center, normal, scale, type } = this;
|
||||
const { 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);
|
||||
outline.scale.set(scale.x, scale.y, 1);
|
||||
outline.position.set(center.x, center.y, center.z);
|
||||
|
||||
const normalVector = new Vector3(normal.x, normal.y, normal.z);
|
||||
const targetPoint = new Vector3().addVectors(plane.position, normalVector);
|
||||
plane.lookAt(targetPoint);
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
// const nv = new Vector3(normal.x, normal.y, normal.z);
|
||||
// const tp = new Vector3().addVectors(group.position, nv);
|
||||
// group.lookAt(tp);
|
||||
|
||||
this.#db_save();
|
||||
}
|
||||
|
|
@ -92,7 +109,11 @@ mesh.sketch = class MeshSketch extends mesh.object {
|
|||
}
|
||||
|
||||
get object() {
|
||||
return this.plane;
|
||||
return this.group;
|
||||
}
|
||||
|
||||
get meshes() {
|
||||
return this.group.children.filter(c => c.sketch ? c : undefined);
|
||||
}
|
||||
|
||||
rename(newname) {
|
||||
|
|
@ -109,17 +130,61 @@ mesh.sketch = class MeshSketch extends mesh.object {
|
|||
}
|
||||
|
||||
unhighlight() {
|
||||
this.outline.material = material.outline;
|
||||
this.outline.material = material.normal;
|
||||
}
|
||||
|
||||
select(bool) {
|
||||
const { plane, handles } = this;
|
||||
if (bool === undefined) {
|
||||
return this.plane.material === material.selected;
|
||||
return plane.material === material.selected;
|
||||
}
|
||||
if (bool.toggle) {
|
||||
return this.select(!this.select());
|
||||
}
|
||||
return this.plane.material = (bool ? material.selected : material.plane);
|
||||
plane.material = (bool ? material.selected : material.normal);
|
||||
for (let handle of handles) {
|
||||
handle.material = bool ? material.highlight : plane.material;
|
||||
}
|
||||
return bool;
|
||||
}
|
||||
|
||||
move(x, y, z = 0) {
|
||||
const { center, scale, plane, handles, dragging } = this;
|
||||
const handle = handles.indexOf(dragging);
|
||||
if (dragging === plane) {
|
||||
center.x += x;
|
||||
center.y += y;
|
||||
center.z += z;
|
||||
this.update();
|
||||
} else if (handle >= 0) {
|
||||
const sf = [
|
||||
[-1, 1, 1],
|
||||
[ 1, 1, 1],
|
||||
[-1,-1, 1],
|
||||
[ 1,-1, 1],
|
||||
][handle];
|
||||
center.x += x / 2;
|
||||
center.y += y / 2;
|
||||
center.z += z / 2;
|
||||
scale.x += x * sf[0];
|
||||
scale.y += y * sf[1];
|
||||
scale.z += z * sf[2];
|
||||
this.update();
|
||||
} else {
|
||||
console.log({ sketch_move: [...arguments] });
|
||||
}
|
||||
}
|
||||
|
||||
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 });
|
||||
} else {
|
||||
console.log({ invalid_sketch_drag: opt });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -876,6 +876,8 @@ gapp.register("moto.space", [], (root, exports) => {
|
|||
isVis = trackTo.visible;
|
||||
if (mouseDownSelect) selection = mouseDownSelect(undefined, event);
|
||||
if (selection && selection.length > 0) {
|
||||
// selection = selection.map(o => o.isGroup ? o.children : o).flat();
|
||||
// console.log({ selection });
|
||||
trackTo.visible = true;
|
||||
let int = intersect(selection.slice().append(trackTo), false);
|
||||
trackTo.visible = isVis;
|
||||
|
|
|
|||
Loading…
Reference in a new issue