first sketch union
This commit is contained in:
parent
b8ccf456c1
commit
54ffc506bd
4 changed files with 172 additions and 28 deletions
|
|
@ -110,6 +110,19 @@ class Polygon {
|
|||
return this;
|
||||
}
|
||||
|
||||
toObject() {
|
||||
return {
|
||||
points: this.toArray(),
|
||||
inner: this.inner?.map(i => i.toArray())
|
||||
};
|
||||
}
|
||||
|
||||
fromObject(obj) {
|
||||
this.fromArray(obj.points);
|
||||
this.inner = obj.inner?.map(a => newPolygon().fromArray(a))
|
||||
return this;
|
||||
}
|
||||
|
||||
matches(poly) {
|
||||
let tarr = Array.isArray(poly) ? poly : poly.toArray();
|
||||
let parr = this.toArray();
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ const selection = {
|
|||
return mdl;
|
||||
},
|
||||
|
||||
sketch() {
|
||||
return selection.sketches()[0];
|
||||
},
|
||||
|
||||
sketches() {
|
||||
return selection.list(true).filter(s => s.type === 'sketch');
|
||||
},
|
||||
|
|
@ -130,11 +134,10 @@ const selection = {
|
|||
|
||||
// remove all
|
||||
delete() {
|
||||
let list = selection.list(true);
|
||||
if (list[0]?.type === 'sketch' && list[0].selection_delete()) {
|
||||
if (sketch.selection.delete()) {
|
||||
return;
|
||||
}
|
||||
for (let s of list) {
|
||||
for (let s of selection.list()) {
|
||||
selection.remove(s);
|
||||
tools.remove(s);
|
||||
s.showBounds(false);
|
||||
|
|
@ -160,9 +163,8 @@ const selection = {
|
|||
},
|
||||
|
||||
clear() {
|
||||
let list = selection.list(true);
|
||||
if (list[0]?.type === 'sketch' && list[0].selection_clear()) {
|
||||
return false;
|
||||
if (sketch.selection.clear()) {
|
||||
return;
|
||||
}
|
||||
for (let s of selection.list()) {
|
||||
selection.remove(s);
|
||||
|
|
@ -442,8 +444,60 @@ let sketch = {
|
|||
|
||||
extrude() {
|
||||
selection.sketches(true).forEach(sketch => {
|
||||
sketch.extrude();
|
||||
sketch.extrude(...arguments);
|
||||
});
|
||||
},
|
||||
|
||||
selection: {
|
||||
get one() {
|
||||
return selection.sketch();
|
||||
},
|
||||
|
||||
list() {
|
||||
return selection.sketches();
|
||||
},
|
||||
|
||||
clear() {
|
||||
let list = selection.list(true);
|
||||
return list[0]?.type === 'sketch' && list[0].selection.clear();
|
||||
},
|
||||
|
||||
delete() {
|
||||
let list = selection.list(true);
|
||||
return list[0]?.type === 'sketch' && list[0].selection.delete();
|
||||
}
|
||||
},
|
||||
|
||||
boolean: {
|
||||
group() {
|
||||
sketch.selection.one?.boolean.group();
|
||||
},
|
||||
|
||||
ungroup() {
|
||||
sketch.selection.one?.boolean.ungroup();
|
||||
},
|
||||
|
||||
union() {
|
||||
sketch.selection.one?.boolean.union();
|
||||
},
|
||||
|
||||
intersect() {
|
||||
sketch.selection.one?.boolean.intersect();
|
||||
},
|
||||
|
||||
difference() {
|
||||
sketch.selection.one?.boolean.difference();
|
||||
}
|
||||
},
|
||||
|
||||
pattern: {
|
||||
circle() {
|
||||
sketch.selection.one?.pattern.circle();
|
||||
},
|
||||
|
||||
grid() {
|
||||
sketch.selection.one?.pattern.grid();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ function ui_build() {
|
|||
h.bind(logger, [ h.div({ id: 'logtext' }) ]);
|
||||
|
||||
// a few shortcuts to api calls
|
||||
let { file, selection, mode, tool, prefs, add } = api;
|
||||
let { file, selection, mode, tool, sketch, prefs, add } = api;
|
||||
|
||||
// top/center mode selector
|
||||
h.bind(modes, [ h.div([
|
||||
|
|
@ -415,7 +415,7 @@ function ui_build() {
|
|||
h.button({ _: 'wireframe', onclick() { api.wireframe() } }),
|
||||
])
|
||||
]),
|
||||
h.div([
|
||||
h.div({ class: "sketch-off" }, [
|
||||
h.div({ _: "boolean", class: "head" }),
|
||||
h.div({ class: "back"}),
|
||||
h.div({ class: "pop"}, [
|
||||
|
|
@ -425,7 +425,19 @@ function ui_build() {
|
|||
h.button({ _: 'difference', onclick: tool.difference }),
|
||||
])
|
||||
]),
|
||||
h.div([
|
||||
h.div({ class: "sketch-on" }, [
|
||||
h.div({ _: "boolean", class: "head" }),
|
||||
h.div({ class: "back"}),
|
||||
h.div({ class: "pop"}, [
|
||||
h.button({ _: 'union', onclick: sketch.boolean.union }),
|
||||
h.button({ _: 'intersect', onclick: sketch.boolean.intersect }),
|
||||
h.button({ _: 'difference', onclick: sketch.boolean.difference }),
|
||||
h.hr(),
|
||||
h.button({ _: 'group', onclick: sketch.boolean.union }),
|
||||
h.button({ _: 'ungroup', onclick: sketch.boolean.union }),
|
||||
])
|
||||
]),
|
||||
h.div({ class: "sketch-off" }, [
|
||||
h.div({ _: "pattern", class: "head" }),
|
||||
h.div({ class: "back"}),
|
||||
h.div({ class: "pop"}, [
|
||||
|
|
@ -433,6 +445,22 @@ function ui_build() {
|
|||
h.button({ _: 'grid', onclick() { api.pattern.grid() } }),
|
||||
])
|
||||
]),
|
||||
h.div({ class: "sketch-on" }, [
|
||||
h.div({ _: "pattern", class: "head" }),
|
||||
h.div({ class: "back"}),
|
||||
h.div({ class: "pop"}, [
|
||||
h.button({ _: 'circular', onclick() { sketch.pattern.circle() } }),
|
||||
h.button({ _: 'grid', onclick() { sketch.pattern.grid() } }),
|
||||
])
|
||||
]),
|
||||
h.div({ class: "sketch-on" }, [
|
||||
h.div({ _: "extrude", class: "head" }),
|
||||
h.div({ class: "back"}),
|
||||
h.div({ class: "pop"}, [
|
||||
h.button({ _: 'sketch', onclick() { sketch.extrude() } }),
|
||||
h.button({ _: 'selection', onclick() { sketch.extrude({ selection: true }) } }),
|
||||
])
|
||||
]),
|
||||
h.div({ class: "sketch-off" }, [
|
||||
h.div({ _: "models", class: "head" }),
|
||||
h.div({ class: "back"}),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// dep: add.array
|
||||
// dep: add.three
|
||||
// dep: geo.polygon
|
||||
// dep: geo.polygons
|
||||
// dep: moto.license
|
||||
// dep: moto.client
|
||||
// dep: mesh.object
|
||||
|
|
@ -23,6 +24,7 @@ const { newPolygon } = base;
|
|||
|
||||
const mapp = mesh;
|
||||
const worker = moto.client.fn;
|
||||
const POLYS = base.polygons;
|
||||
|
||||
const material = {
|
||||
normal: new MeshBasicMaterial({ color: 0x888888, side: DoubleSide, transparent: true, opacity: 0.25 }),
|
||||
|
|
@ -131,28 +133,62 @@ mesh.sketch = class MeshSketch extends mesh.object {
|
|||
}).reverse();
|
||||
}
|
||||
|
||||
get selected_items() {
|
||||
return this.items.filter(i => i.selected);
|
||||
get selection() {
|
||||
let sketch = this;
|
||||
return {
|
||||
// for boolean and patterning, we need the polygon artifacts
|
||||
mesh_items() {
|
||||
return sketch.group.children.filter(c => c.sketch_item && c.sketch_item.selected);
|
||||
},
|
||||
|
||||
// return true if any selections were cleared
|
||||
clear() {
|
||||
let sel = sketch.items.filter(i => i.selected);
|
||||
if (sel.length) {
|
||||
sel.forEach(s => s.selected = false);
|
||||
sketch.render();
|
||||
}
|
||||
return sel.length;
|
||||
},
|
||||
|
||||
// return true if any selections were deleted
|
||||
delete() {
|
||||
let sel = sketch.items.filter(i => i.selected);
|
||||
if (sel.length) {
|
||||
sketch.items = sketch.items.filter(i => !i.selected);
|
||||
sketch.render();
|
||||
}
|
||||
return sel.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return true if any selections were cleared
|
||||
selection_clear() {
|
||||
let sel = this.items.filter(i => i.selected);
|
||||
if (sel.length) {
|
||||
sel.forEach(s => s.selected = false);
|
||||
this.render();
|
||||
get boolean() {
|
||||
let sketch = this;
|
||||
return {
|
||||
union() {
|
||||
let items = sketch.selection.mesh_items();
|
||||
let polys = items.map(i => i.sketch_item.poly);
|
||||
let union = POLYS.union(polys, 0, true);
|
||||
console.log('sketch union', union);
|
||||
sketch.selection.delete();
|
||||
for (let poly of union) {
|
||||
sketch.add_polygon({ poly });
|
||||
}
|
||||
}
|
||||
}
|
||||
return sel.length;
|
||||
}
|
||||
|
||||
// return true if any selections were deleted
|
||||
selection_delete() {
|
||||
let sel = this.items.filter(i => i.selected);
|
||||
if (sel.length) {
|
||||
this.items = this.items.filter(i => !i.selected);
|
||||
this.render();
|
||||
get pattern() {
|
||||
return {
|
||||
circle() {
|
||||
console.log('sketch pattern circle');
|
||||
},
|
||||
|
||||
grid() {
|
||||
console.log('sketch pattern grid');
|
||||
}
|
||||
}
|
||||
return sel.length;
|
||||
}
|
||||
|
||||
rename(newname) {
|
||||
|
|
@ -250,6 +286,13 @@ mesh.sketch = class MeshSketch extends mesh.object {
|
|||
this.render();
|
||||
}
|
||||
|
||||
add_polygon(opt = {}) {
|
||||
log(this.file || this.id, '| add polygon');
|
||||
Object.assign(opt, { center: {x:0, y:0, z:0} }, opt);
|
||||
this.items.push({ type: "polygon", ...opt, ...opt.poly.toObject() });
|
||||
this.render();
|
||||
}
|
||||
|
||||
// render items unto the group object
|
||||
render() {
|
||||
let { group } = this;
|
||||
|
|
@ -264,9 +307,12 @@ mesh.sketch = class MeshSketch extends mesh.object {
|
|||
}
|
||||
|
||||
extrude(opt = {}) {
|
||||
let { z } = opt;
|
||||
let { z, selection } = opt;
|
||||
let models = [];
|
||||
for (let item of this.group.children.filter(c => c.sketch_item)) {
|
||||
let items = this.group.children
|
||||
.filter(c => c.sketch_item)
|
||||
.filter(c => !selection || c.sketch_item.selected);
|
||||
for (let item of items) {
|
||||
let vert = item.sketch_item.extrude(z || 10);
|
||||
let nmdl = new mesh.model({ file: "item", mesh: vert.toFloat32() });
|
||||
models.push(nmdl);
|
||||
|
|
@ -318,6 +364,9 @@ class SketchItem {
|
|||
poly = newPolygon().centerCircle(center, radius, points).annotate({ item } );
|
||||
} else if (type === 'rectangle') {
|
||||
poly = newPolygon().centerRectangle(center, width, height).annotate({ item });
|
||||
} else if (type === 'polygon') {
|
||||
poly = newPolygon().fromObject(item);
|
||||
poly.move(center);
|
||||
} else {
|
||||
throw `invalid sketch type: ${type}`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue