add mesh patterning

This commit is contained in:
Stewart Allen 2024-07-20 02:24:40 -04:00
commit 8aae9885e8
4 changed files with 79 additions and 15 deletions

View file

@ -12,7 +12,7 @@
gapp.register("mesh.api", [], (root, exports) => {
const { Matrix4, Vector3 } = THREE;
const { mesh, moto } = root;
const { base, mesh, moto } = root;
const { space } = moto;
const { util } = mesh;
@ -229,6 +229,58 @@ const selection = {
}
};
const pattern = {
/**
* @param {int} count number of entities
* @param {float[]} center [x,y,z]
*/
circle(count, center) {
async function doit(count, center = [0,0,0]) {
api.modal.hide();
let models = selection.models();
let [ cx, cy, cz ] = center;
for (let model of models) {
await api.tool.regroup([ model ]);
let pos = model.group.position().clone();
let stepr = (Math.PI * 2) / count;
let modnu = [ model ];
for (let i=1; i<count; i++) {
let clone = await model.duplicate();
let [x, y] = base.util.rotate(pos.x - cx, pos.y - cy, stepr * i);
clone.group.rotate(0, 0, stepr * i);
clone.group.position(x + cx, y + cy, pos.z);
modnu.push(clone);
}
await api.tool.regroup(modnu);
}
}
if (!count) {
api.modal.dialog({
title: "object pattern",
body: [ h.div({ class: "addgear" }, [
h.label('total count'),
h.input({ value: 3, size: 5, id: "_count" }),
h.label('center x,y,z'),
h.input({ value: "0,0,0", size: 5, id: "_center" }),
h.button({ _: "create", onclick() {
doit(
parseInt(api.modal.bound._count.value) || 3,
api.modal.bound._center.value.split(',').map(v => parseFloat(v))
);
} })
]) ]
});
api.modal.bound._count.focus();
} else {
doit(count, origin);
}
},
grid() {
}
};
const group = {
// @returns {MeshGroup[]}
list() {
@ -565,8 +617,8 @@ const tool = {
api.log.emit(`regrouping ${models.length} model(s)`);
let bounds = util.bounds(models);
let { mid } = bounds;
Promise.all(models.map(m => m.ungroup())).then(() => {
mesh.api.group.new(models)
return Promise.all(models.map(m => m.ungroup())).then(() => {
return mesh.api.group.new(models)
.centerModels()
.position(mid.x, mid.y, mid.z)
.setSelected();
@ -592,7 +644,7 @@ const tool = {
});
promises.push(p);
}
Promise.all(promises).then(() => {
return Promise.all(promises).then(() => {
api.log.emit('analysis complete').unpin();
});
},
@ -613,7 +665,7 @@ const tool = {
});
promises.push(p);
}
Promise.all(promises).then(() => {
return Promise.all(promises).then(() => {
api.log.emit('isolation complete').unpin();
// api.log.emit(`... isolate time = ${Date.now() - mark}`);
});
@ -902,6 +954,8 @@ const api = exports({
selection,
pattern,
group,
model,

View file

@ -398,6 +398,14 @@ function ui_build() {
h.button({ _: 'intersect', onclick: tool.intersect }),
])
]),
h.div([
h.div({ _: "pattern", class: "head" }),
h.div({ class: "back"}),
h.div({ class: "pop"}, [
h.button({ _: 'circular', onclick() { api.pattern.circle() } }),
h.button({ _: 'grid', onclick() { api.pattern.grid } }),
])
]),
h.div([
h.div({ _: "models", class: "head" }),
h.div({ class: "back"}),

View file

@ -155,18 +155,19 @@ mesh.model = class MeshModel extends mesh.object {
// return new group containing just this model in world coordinates
duplicate(opt = {}) {
worker.model_duplicate({
return worker.model_duplicate({
matrix: this.matrix,
id: this.id,
opt
opt: { mirror: opt.mirror}
}).then(data => {
let group = mesh.api.group.new([new mesh.model({
file: `${this.file}`,
mesh: data
})]).setSelected();
let model = new mesh.model({ file: `${this.file}`, mesh: data });
let group = opt.group || mesh.api.group.new();
group.add(model);
group.setSelected();
if (opt.mirror) {
group.move(0, 0, group.bounds.dim.z);
}
return model;
});
}
@ -460,9 +461,10 @@ mesh.model = class MeshModel extends mesh.object {
// release from a group but remain in memory and storage
// so it can be re-assigned to another group
ungroup() {
this.group.remove(this, { free: false });
this.group = undefined;
if (this.group) {
this.group.remove(this, { free: false });
this.group = undefined;
}
return worker.model_duplicate({
matrix: this.matrix,
id: this.id,

View file

@ -230,7 +230,7 @@ button:hover {
}
.addgear {
gap: 5px;
gap: 5px 10px;
display: grid;
grid-template-columns: 1fr 50px;
}