From a2a5fc1cd44f85da273b4586cd271c7e30603082 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Sun, 28 Jul 2024 13:30:20 -0400 Subject: [PATCH] add sketch z scaling, item ordering, sensible grouping on union --- src/main/mesh.js | 4 +- src/mesh/api.js | 37 +++++++++++++++--- src/mesh/build.js | 10 ++++- src/mesh/sketch.js | 94 ++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 119 insertions(+), 26 deletions(-) diff --git a/src/main/mesh.js b/src/main/mesh.js index b2921bdb..72649504 100644 --- a/src/main/mesh.js +++ b/src/main/mesh.js @@ -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)) diff --git a/src/mesh/api.js b/src/mesh/api.js index a61501d3..d29ebd00 100644 --- a/src/mesh/api.js +++ b/src/mesh/api.js @@ -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 diff --git a/src/mesh/build.js b/src/mesh/build.js index 39a6671f..c4933177 100644 --- a/src/mesh/build.js +++ b/src/mesh/build.js @@ -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; diff --git a/src/mesh/sketch.js b/src/mesh/sketch.js index 23c28b3b..b6e01844 100644 --- a/src/mesh/sketch.js +++ b/src/mesh/sketch.js @@ -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); } }