add z split snapping and work translation caching
This commit is contained in:
parent
c4fd0cef74
commit
72d9469699
3 changed files with 66 additions and 16 deletions
|
|
@ -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();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<l; ) {
|
||||
let v1 = new Vector3(pos[i++], pos[i++], pos[i++]);
|
||||
let z = v1.z.round(round || 2);
|
||||
zlist[z] = '';
|
||||
}
|
||||
return Object.keys(zlist);
|
||||
},
|
||||
|
||||
// split a model along an axis at a given point
|
||||
// return two arrays of vertices for each resulting object
|
||||
split(data) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue