diff --git a/src/load/svg.js b/src/load/svg.js index 28ebc607..14ce201c 100644 --- a/src/load/svg.js +++ b/src/load/svg.js @@ -31,12 +31,14 @@ function parse(text, opt = { soup: true }) { for (let i = 0; i < paths.length; i++) { let path = paths[i]; let shapes = path.toShapes(true); + let type = path.userData?.node?.nodeName; if (fromSoup) { for (let node of shapes) { let { shape, holes } = node.extractPoints(); for (let path of [ shape, ...holes ]) { let poly = base.newPolygon().addPoints(path.map(p => base.newPoint(p.x, -p.y, 0))); if (poly.appearsClosed()) poly.points.pop(); + if (type === 'polyline') poly.setOpen(true); polys.push(poly); } } diff --git a/src/main/mesh.js b/src/main/mesh.js index c4253b83..01797c80 100644 --- a/src/main/mesh.js +++ b/src/main/mesh.js @@ -573,7 +573,7 @@ function load_files(files) { } function load_files_opt(files, opt) { - load.File.load([...files], opt) + return load.File.load([...files], opt) .then(data => call.space_load(data)) .catch(error => log(error).pin({}) && dbug.error(error)) // .finally(() => mesh.api.log.hide()); diff --git a/src/mesh/api.js b/src/mesh/api.js index 50caee5b..d9b8f46c 100644 --- a/src/mesh/api.js +++ b/src/mesh/api.js @@ -479,6 +479,7 @@ let sketch = { api.modal.bound._height.focus(); }, + // related to items selections in a selected sketch arrange: { group() { sketch.selection.ifcan((sketch, items) => { @@ -502,6 +503,7 @@ let sketch = { rec.poly.move({ x: -center.x, y: -center.y, z:0 }); Object.assign(rec.item, rec.poly.toObject()); } + selection.centerXY(); sketch.render(); }); }, @@ -588,6 +590,7 @@ let sketch = { }, }, + // related to items selections in a selected sketch boolean: { nest() { sketch.selected.one?.boolean.nest(); @@ -614,6 +617,7 @@ let sketch = { } }, + // related to items selections in a selected sketch pattern: { circle() { sketch.selected.one?.pattern.circle(); @@ -1266,6 +1270,11 @@ const prefs = { dark: false, select: [] }, + sketch: { + close_poly: false, + open_thick: 1, + open_type: 'miter' + }, normals: { length: 0.25, color_lite: 0xffff00, diff --git a/src/mesh/build.js b/src/mesh/build.js index a35967a3..a9165c2d 100644 --- a/src/mesh/build.js +++ b/src/mesh/build.js @@ -226,7 +226,7 @@ api.welcome = function(version = "unknown") { api.settings = function() { const { util } = mesh; const { prefs } = api; - const { surface, normals, space, wireframe } = prefs.map; + const { surface, normals, space, sketch, wireframe } = prefs.map; const { dark } = space; const set1 = h.div([ @@ -311,8 +311,31 @@ api.settings = function() { }), ]); + let ot = sketch.open_type; + let srr = () => { api.sketch.list().forEach(s => s.render()) }; + const set7 = h.div([ + h.label({ class: "header", _: 'open poly'}), + h.label('auto close'), + h.input({ type: "checkbox", + onchange: ev => prefs.save( (sketch.close_poly = !sketch.close_poly) && srr() ), + [ sketch.close_poly === true ? 'checked' : 'unchecked' ] : 1 + }), + h.label('thickness'), + h.input({ type: "text", size: 5, value: parseFloat(sketch.open_thick || 1), + onchange: ev => prefs.save( (sketch.open_thick = parseFloat(ev.target.value)) && srr() ) + }), + h.label('type'), + h.select({ type: "text", value: sketch.open_type, + onchange: ev => prefs.save( (sketch.open_type = ev.target.value) && srr() ) + }, [ + h.option({ _: 'square', [ot === 'square' ? 'selected' : '']: '' }), + h.option({ _: 'miter', [ot === 'miter' ? 'selected' : '']: '' }), + h.option({ _: 'round', [ot === 'round' ? 'selected' : '']: ''}), + ]), + ]); + modal.show('settings', h.div({ class: "settings" }, [ - set1, set2, set3, set4, set5, set6 + set1, set2, set3, set4, set5, set6, set7 ] )); } diff --git a/src/mesh/sketch.js b/src/mesh/sketch.js index 12b481ff..49faeafd 100644 --- a/src/mesh/sketch.js +++ b/src/mesh/sketch.js @@ -136,6 +136,10 @@ mesh.sketch = class MeshSketch extends mesh.object { }).reverse(); } + get elements() { + return this.group.children.filter(c => c.sketch_item); + } + get selection() { let sketch = this; return { @@ -434,7 +438,7 @@ mesh.sketch = class MeshSketch extends mesh.object { } add_item(item, opt = {}) { - item.selected = opt.select || false; + // item.selected = opt.select || false; this.items.push(item); this.render(); } @@ -526,6 +530,7 @@ class SketchItem { let { item, sketch, order } = this; let { material } = mesh; let { type, center, width, height, radius, points, spacing, poly, selected } = item; + let { close_poly, open_thick, open_type } = api.prefs.map.sketch; if (type === 'circle') { let circumference = 2 * Math.PI * radius; points = points || Math.floor(circumference / (spacing || 1)); @@ -535,6 +540,7 @@ class SketchItem { } else if (type === 'polygon') { poly = newPolygon().fromObject(item); poly.move(center); + if (poly.isOpen() && !close_poly) poly = poly.offset_open(open_thick, open_type)[0]; } else { throw `invalid sketch type: ${type}`; } diff --git a/web/mesh/index.css b/web/mesh/index.css index b1eacb2c..cffe2b24 100644 --- a/web/mesh/index.css +++ b/web/mesh/index.css @@ -406,15 +406,12 @@ button:hover { /** settings dialog **/ -.settings { - gap: 5px; -} - .settings { gap: 5px; display: grid; background-color: #fff; grid: min-content 1fr / min-content 1fr; + grid-template-columns: 1fr 1fr 1fr; } .settings > div {