add sketch z scaling, item ordering, sensible grouping on union

This commit is contained in:
Stewart Allen 2024-07-28 13:30:20 -04:00
commit a2a5fc1cd4
4 changed files with 119 additions and 26 deletions

View file

@ -486,7 +486,7 @@ function load_files(files) {
return diam ? poly.offset_open(diam / 2, 'round') : null;
}).filter(p => p).flat();
for (let set of [ closed, open, circs, rects ]) {
let group = Date.now().toString(36);
let group = mesh.util.uuid();
for (let poly of set) {
sketch.add.polygon({ poly, group });
}
@ -497,7 +497,7 @@ function load_files(files) {
if (sketch && has_svg) {
load.File.load([...files], { flat: true })
.then(polys => polys.forEach(set => {
let group = Date.now().toString(36);
let group = mesh.util.uuid();
set.forEach(poly => sketch.add.polygon({ poly, group }))
}))
.catch(error => dbug.error(error))

View file

@ -483,16 +483,13 @@ let sketch = {
arrange: {
group() {
sketch.selection.ifcan((sketch, items) => {
let group = Date.now().toString(36);
items.forEach(i => i.group = group);
log('grouped', items.length, 'sketch items');
sketch.arrange.group(items);
}, 2);
},
ungroup() {
sketch.selection.ifcan((sketch, items) => {
items.forEach(i => delete i.group);
log('ungrouped', items.length, 'sketch items');
sketch.arrange.ungroup(items);
});
},
@ -524,7 +521,35 @@ let sketch = {
});
sketch.render();
});
}
},
down() {
sketch.selection.ifcan((sketch, items) => {
items.forEach(item => sketch.arrange.down(item));
sketch.render();
});
},
up() {
sketch.selection.ifcan((sketch, items) => {
items.forEach(item => sketch.arrange.up(item));
sketch.render();
});
},
top() {
sketch.selection.ifcan((sketch, items) => {
items.forEach(item => sketch.arrange.top(item));
sketch.render();
});
},
bottom() {
sketch.selection.ifcan((sketch, items) => {
items.forEach(item => sketch.arrange.bottom(item));
sketch.render();
});
},
},
// related to a selected sketch

View file

@ -488,6 +488,12 @@ function ui_build() {
h.hr(),
h.button({ _: 'flip-h', onclick: sketch.arrange.fliph }),
h.button({ _: 'flip-v', onclick: sketch.arrange.flipv }),
h.hr(),
h.button({ _: 'down', onclick: sketch.arrange.down }),
h.button({ _: 'up', onclick: sketch.arrange.up }),
h.hr(),
h.button({ _: 'top', onclick: sketch.arrange.top }),
h.button({ _: 'bottom', onclick: sketch.arrange.bottom }),
])
]),
h.div({ class: "sketch-on" }, [
@ -784,7 +790,7 @@ function ui_build() {
let sk_vars = sblock('sketch', sketch.file || sketch.id, grid(
util.extract(bounds.center, map),
util.extract(bounds.size, map),
[ "center", "size" ], und, 'sketch'
[ "center", "scale" ], und, 'sketch'
));
let sel_item;
let si_vars = sel.slice(0,1).map(item => item.sketch_item.item).map(item => {
@ -825,7 +831,7 @@ function ui_build() {
sketch.center[axis] = nval;
sketch.render();
}, { sketch: true });
let el2 = bound[`sketch_val_${axis.toUpperCase()}_size`];
let el2 = bound[`sketch_val_${axis.toUpperCase()}_scale`];
el2.classList.add('editable');
el2.onclick = field_edit(`${axis} size`, (nval, oval) => {
sketch.scale[axis] = nval;

View file

@ -81,7 +81,7 @@ mesh.sketch = class MeshSketch extends mesh.object {
group.add(...handles, outline, plane);
util.defer(() => this.render());
this.render_defer();
}
update() {
@ -205,9 +205,7 @@ mesh.sketch = class MeshSketch extends mesh.object {
let polys = items.map(i => i.sketch_item.poly);
let union = POLYS.union(polys, 0, true);
sketch.selection.delete();
for (let poly of union) {
sketch.add.polygon({ poly });
}
sketch.arrange.group(union.map(poly => sketch.add.polygon({ poly })));
},
intersect() {
@ -268,6 +266,57 @@ mesh.sketch = class MeshSketch extends mesh.object {
}
}
get arrange() {
let sketch = this;
let { items } = sketch;
return {
move(item, target) {
let pos = items.indexOf(item);
if (pos < 0 || pos >= items.length) {
throw new Error('index out of bounds');
}
if (target === 'top') {
let x = items.splice(pos,1);
return items.appendAll(x);
} else if (target === 'bottom') {
let x = items.splice(pos,1);
return sketch.items = [...x, ...items];
}
let newPos = { 'down': pos - 1, 'up': pos + 1 }[target];
if (newPos >= 0 && newPos < items.length) {
[items[pos], items[newPos]] = [items[newPos], items[pos]];
}
},
up(item) {
sketch.arrange.move(item, 'up');
},
down(item) {
sketch.arrange.move(item, 'down');
},
top(item) {
sketch.arrange.move(item, 'top');
},
bottom(item) {
sketch.arrange.move(item, 'bottom');
},
group(items) {
let group = Date.now().toString(36);
items.forEach(i => i.group = group);
sketch.render();
},
ungroup(items) {
items.forEach(i => i.group = mesh.util.uuid());
sketch.render();
}
}
}
get pattern() {
return {
circle() {
@ -411,7 +460,7 @@ mesh.sketch = class MeshSketch extends mesh.object {
let sketch = this;
return {
circle(opt = {}) {
sketch.add.item({
return sketch.add.item({
type: "circle",
selected: true,
...Object.assign({}, { center: {x:0, y:0, z:0}, radius:5 }, opt)
@ -419,7 +468,7 @@ mesh.sketch = class MeshSketch extends mesh.object {
},
rectangle(opt = {}) {
sketch.add.polygon({
return sketch.add.polygon({
...opt,
poly: newPolygon().centerRectangle(
opt.center || {x:0, y:0, z:0},
@ -433,7 +482,7 @@ mesh.sketch = class MeshSketch extends mesh.object {
let poly = opt.poly;
delete opt.poly;
let { width, miter } = poly._svg || {};
sketch.add.item({
return sketch.add.item({
type: "polygon",
width,
miter,
@ -444,8 +493,10 @@ mesh.sketch = class MeshSketch extends mesh.object {
},
item(item, opt = {}) {
item.group = item.group || mesh.util.uuid();
sketch.items.push(item);
sketch.render();
sketch.render_defer();
return item;
}
}
}
@ -453,17 +504,27 @@ mesh.sketch = class MeshSketch extends mesh.object {
// render items unto the group object
render() {
let { group } = this;
let group_order = {};
let group_next = 0;
let scale = this.scale.z;
// remove previous item/poly-based children of group
group.children.filter(c => c.sketch_item || c.sketch_line).forEach(c => group.remove(c));
// mapy items into polys into meshes to add to group
for (let si of this.items.map((i,o) => new SketchItem(this, i, o))) {
group.add(si.mesh);
group.add(...si.outs);
// map items into polys into meshes to add to group
for (let item of this.items) {
let order = scale ? (group_order[item.group] ?? group_next++) : group_next++;
group_order[item.group] = order;
let sketch_item = new SketchItem(this, item, order);
group.add(sketch_item.mesh);
group.add(...sketch_item.outs);
}
this.update();
space.refresh();
}
render_defer() {
util.defer(() => this.render());
}
extrude(opt = {}) {
let { selection, height, chamfer, chamfer_top, chamfer_bottom } = opt;
let models = [];
@ -533,11 +594,12 @@ class SketchItem {
}
update() {
let bump = 0.0025;
let { item, sketch, order } = this;
let { material } = mesh;
let { type, center, width, height, miter, radius, points, spacing, poly, selected } = item;
let { open_close, open_width, open_type } = api.prefs.map.sketch;
let base = 0.025;
let bump = sketch.scale.z || 0.0001;
if (type === 'circle') {
let circumference = 2 * Math.PI * radius;
points = points || Math.floor(circumference / (spacing || 1));
@ -566,7 +628,7 @@ class SketchItem {
meh.renderOrder = -1;
meh.sketch_item = this;
// bump z to avoid z order conflict and ensure item ray intersect priority
meh.position.z += bump + (order * bump);
meh.position.z += base + (order * bump);
// create poly outline(s)
let outs = this.outs = [];
for (let p of [poly, ...(poly.inner || [])]) {
@ -576,8 +638,8 @@ class SketchItem {
let out = new THREE.Line(lge, material.wireline);
out.renderOrder = -1;
out.sketch_line = this;
out.position.z += bump + (order * bump);
// out.renderOrder = bump * order;
out.position.z += base + (order * bump);
out.renderOrder = -10 + (bump * order);
outs.push(out);
}
}