add mirroring, exclude normals from bounds, fix paint selection update

This commit is contained in:
Stewart Allen 2022-01-20 00:01:48 -05:00
commit 5d2f4ac02e
7 changed files with 88 additions and 7 deletions

View file

@ -276,6 +276,7 @@ function space_init(data) {
case 'KeyF':
return selection.floor().focus();
case 'KeyM':
if (shiftKey) return api.tool.mirror();
return api.tool.merge();
case 'KeyA':
return api.tool.analyze();

View file

@ -140,6 +140,8 @@ let selection = {
}
// update saved selection id list
prefs.save( prefs.map.space.select = selected.map(s => s.id) );
// force repaint in case of idle
space.update();
return selection;
},
@ -293,6 +295,9 @@ function fallback(models, strict) {
let tool = {
merge(models) {
models = fallback(models);
if (models.length <= 1) {
return api.log.emit('nothing to merge');
}
api.log.emit(`merging ${models.length} models`).pin();
worker.model_merge(models.map(m => {
return { id: m.id, matrix: m.matrix }
@ -313,6 +318,12 @@ let tool = {
}
},
mirror() {
for (let m of selection.models()) {
m.mirror();
}
},
invert() {
for (let m of selection.models()) {
m.invert(api.mode.get());

View file

@ -267,6 +267,7 @@ function ui_build() {
// h.div({ class: "vsep" }),
h.button({ _: 'duplicate', onclick: tool.duplicate }),
h.button({ _: 'merge', onclick: tool.merge }),
h.button({ _: 'mirror', onclick: tool.mirror }),
h.button({ _: 'split', onclick: call.edit_split }),
h.button({ _: 'invert', onclick: tool.invert }),
]),

View file

@ -108,6 +108,13 @@ mesh.group = class MeshGroup extends mesh.object {
return this.centerXY().floor();
}
scale(x = 1, y = 1, z = 1) {
for (let m of this.models) {
m.scale(x, y, z);
}
return this;
}
// center objects to group bounds
// dependent on first being added to world/scene
centerModels() {
@ -141,6 +148,11 @@ mesh.group = class MeshGroup extends mesh.object {
model.select(...arguments);
}
}
// ok, this is confusing, but necessary for now :/
setSelected() {
super.select();
}
};
})();

View file

@ -108,16 +108,45 @@ mesh.model = class MeshModel extends mesh.object {
return this.mesh.matrixWorld.elements;
}
// override and translate mesh
move(x = 0, y = 0, z = 0) {
let arr = this.attributes.position.array;
for (let i=0, l=arr.length; i<l; ) {
arr[i] = arr[i++] + x;
arr[i] = arr[i++] + y;
arr[i] = arr[i++] + z;
}
this.reload(arr);
return this;
}
// override and translate mesh
scale(x = 1, y = 1, z = 1) {
let arr = this.attributes.position.array;
for (let i=0, l=arr.length; i<l; ) {
arr[i] = arr[i++] *= x;
arr[i] = arr[i++] *= y;
arr[i] = arr[i++] *= z;
}
this.reload(arr);
return this;
}
mirror() {
return this.duplicate({ mirror: true });
}
// return new group containing just this model in world coordinates
duplicate() {
duplicate(opt = {}) {
worker.model_duplicate({
matrix: this.matrix,
id: this.id
id: this.id,
opt
}).then(data => {
mesh.api.group.new([new mesh.model({
file: `${this.file}-dup`,
file: `${this.file}`,
mesh: data
})]).select();
})]).setSelected();
});
}
@ -357,7 +386,7 @@ mesh.model = class MeshModel extends mesh.object {
this.group.add(model = new mesh.model({
file: `${this.file}`,
mesh: o2
}).applyMatrix4(m4)).select();
}).applyMatrix4(m4)).setSelected();
if (o1.length) {
// this becomes bottom
this.reload(o1);

View file

@ -103,6 +103,10 @@ let util = mesh.util = {
// https://discourse.threejs.org/t/bounding-box-bigger-than-concave-object-extrudegeometry/26073/2
// https://discourse.threejs.org/t/invalid-bounds-generated-for-some-orientations/33205
box3expand(box3, object) {
if (object._no_bounds) {
return;
}
let geometry = object.geometry;
object.updateWorldMatrix(geometry ? true : false, false);
@ -183,6 +187,7 @@ let util = mesh.util = {
this.size = size;
this.type = 'FaceNormalsHelper';
this.matrixAutoUpdate = false;
this._no_bounds = true;
this.update();
}

View file

@ -72,8 +72,30 @@ let model = {
// return new vertices in world coordinates
duplicate(data) {
let { id, matrix } = data;
return translate_encode(id, matrix);
let { id, matrix, opt } = data;
let array = translate_encode(id, matrix);
if (opt.mirror) {
// find max z and invert z
let maxz = -Infinity;
for (let i=2, l=array.length; i<l; i += 3) {
maxz = Math.max(maxz, array[i]);
array[i] = -array[i];
}
maxz *= 2;
for (let i=0, l=array.length; i<l; i += 9) {
// swap first two vertices in face to invert normals
let v1 = array.slice(i, i+3);
for (let j=0; j<3; j++) {
array[i+j] = array[i+j+3];
array[i+j+3] = v1[j];
}
// move part up in Z
array[i+2] += maxz;
array[i+5] += maxz;
array[i+8] += maxz;
}
}
return array;
},
// merge several model vertices into a single array