diff --git a/src/geo/mesh.js b/src/geo/mesh.js deleted file mode 100644 index a4d1165c..00000000 --- a/src/geo/mesh.js +++ /dev/null @@ -1,387 +0,0 @@ -/** Copyright Stewart Allen -- All Rights Reserved */ - -"use strict"; - -// dep: geo.base -gapp.register("geo.mesh", [], (root, exports) => { - -const { base } = root; -const TEST = 0; - -class Mesh { - constructor(params = {}) { - this.precision = Math.pow(10, params.precision || 6); - if (params.vertices) { - this.setData(params.vertices, params.faces); - } - } - - /** - * set vertices and faces of the mesh. if only vertices are provided - * then the data is assumed to be un-indexed and will be indexed into - * faces. if faces are provided, they are assumed to be index references - * into the vertex data. removes invalid faces. - * - * the end result is face data mapped to an indexed set of unique vertices. - * - * @param {number[]} vertices - * @param {number[]} faces - */ - setData(vertices, faces) { - if (!vertices) { - throw "missing vertices"; - } - if (vertices.length % 3 !== 0) { - throw "invalid vertices"; - } - // when face/index data is missing, vertices need to be normalized - if (!faces) { - if (TEST) console.time('generate faces'); - faces = []; - let fcac = {}; // seen face hash - let fnew = []; // accumulate vertex triplets - let nuvt = []; // new vertex list - let hash = {}; // find vertex matches - let prec = this.precision; - let dups = 0; - // let cull = 0; - for (let i=0, l=vertices.length; i l !== this && !l.used && l.faces.length === 1); - } - - adjacentUsed() { - return vmap[this.v1] - .concat(vmap[this.v2]) - .filter(l => l !== this && l.used && l.faces.length === 1); - } - - touches(line) { - return this.v1 === line.v1 || - this.v1 === line.v2 || - this.v2 === line.v1 || - this.v2 === line.v2; - } - - unitVector() { - if (this.unit !== undefined) { - return this.unit; - } - let v1 = this.v1; - let v2 = this.v2; - let d = [ - vertices[v1] - vertices[v2], - vertices[v1 + 1] - vertices[v2 + 1], - vertices[v1 + 2] - vertices[v2 + 2], - ]; - let max = Math.max(...d.map(v => Math.abs(v))); - // console.log({d, max}); - return this.unit = d.map(v => v / max); - } - } - - function diffUnitVector(uv1, uv2) { - let diff = 0; - for (let i=0; i<3; i++) { - diff += Math.abs(uv1[i] - uv2[i]); - } - return diff; - } - - function getLine(v1, v2) { - let s1 = vertices[v1] + vertices[v1+1]*1000 + vertices[v1+2]*100000; - let s2 = vertices[v2] + vertices[v2+1]*1000 + vertices[v2+2]*100000; - let key = s1 <= s2 ? [v1,v2].join('-') : [v2,v1].join('-'); - let line = hash[key]; - if (!line) { - // point order will be swapped for reconstructed faces - // to preserve chirality (assuming face normals are correct) - line = hash[key] = new Line(v1, v2); - line.key = key; - lines.push(line); - let lm1 = vmap[v1] = vmap[v1] || []; - let lm2 = vmap[v2] = vmap[v2] || []; - lm1.push(line); - lm2.push(line); - } - return line; - } - - function getXYZ(v) { - return {x: vertices[v], y: vertices[v+1], z: vertices[v+2]}; - } - - for (let i=0, l=this.faces.length; i l.faces.length === 1); - let loops = this.loops = []; - - // connect edge lines into closed loops - for (let i=0, l=edges.length; i 2) { - // console.log('cannot start on a split'); - continue; - } - // line.used = true; - let loop = [ ]; - // build line through adjacent lines - while (true) { - let adjacent = line.adjacentUnused(); - if (adjacent.length === 0) { - let first = loop[0]; - let last = loop.last(); - loop.open = loop.length < 3 - || (first.v1 !== last.v1 - && first.v2 !== last.v2 - && first.v1 !== last.v2 - && first.v2 !== last.v1); - // console.log({term: line, adj: line.adjacentUsed(), open, loop}); - break; - } else if (adjacent.length === 1) { - if (line.v2 !== adjacent[0].v1) { - let tmp = adjacent[0].v1; - adjacent[0].v1 = adjacent[0].v2; - adjacent[0].v2 = tmp; - if (TEST > 1) console.log('chirality mismatch fixed'); - } - line = adjacent[0]; - } else if (adjacent.length === 2) { - // follow edges according to chirality - line = adjacent[0].v1 === line.v2 ? - adjacent[0] : - adjacent[1] - } else { - if (TEST > 1) console.log('error adjacent', line, adjacent, loops.length, loop.length); - line.split = adjacent; - line = adjacent[0]; - } - loop.push(line); - line.used = true; - } - if (loop.length) { - loops.push(loop); - } - } - - // attempt to connect open loops - if (loops.length > 1) { - outer: for (let i=0; i l && l.length <= 2); - if (TEST) console.log({edges, loops, shorts: this.shorts}); - - // filter out null and short loops - this.loops = loops = loops.filter(l => l && l.length > 2); - if (TEST > 1) console.log({loops_filtered: loops}); - - // rotate/flatten to Z plane and use earcut to generate faces - // because earcut emits point indexes, no need to un-rotate - function emitLoop(loop) { - let lastPoint; - let pindex = []; - let points = []; - let dx = 0, dy = 0, dz = 0; - - // gather points, find axis with least deviaton to swap with Z - let loop1 = loop.slice(); - loop1.push(loop[0]); - for (let i=0; i= 0) { - dx = Math.max(dx, Math.abs(vertices[lastPoint] - vertices[nextPoint])); - dy = Math.max(dy, Math.abs(vertices[lastPoint+1] - vertices[nextPoint+1])); - dz = Math.max(dz, Math.abs(vertices[lastPoint+2] - vertices[nextPoint+2])); - } - lastPoint = nextPoint; - } - - // swap Z axis with least delta axis - let swap = 2; - if (dy < dx && dy < dz) { - // swap y,z - swap = 1; - } else if (dx < dy && dx < dz) { - // swap x,z - swap = 0; - } - if (swap < 2) { - // console.log({swap_axis: swap}); - for (let point of points) { - let tmpz = point[2]; - point[2] = point[swap]; - point[swap] = tmpz; - } - } - - let fpoints = points.flat(); - let ec = earcut(fpoints, undefined, 3); - if (TEST > 2) console.log({points, fpoints, ec, dx, dy, dz}); - - for (let point of ec) { - faces.push(pindex[point]); - } - } - - // emit loops - let faceCount = this.faces.length; - for (let loop of loops) { - emitLoop(loop); - } - - this.newFaces = this.faces.length - faceCount; - if (TEST) console.log({newFaces: this.newFaces}); - - if (TEST) console.timeEnd('heal'); - return this; - } -}; - -gapp.overlay(base, { Mesh }); - -}); diff --git a/src/kiri-run/worker.js b/src/kiri-run/worker.js index d1ff3370..64fb59bf 100644 --- a/src/kiri-run/worker.js +++ b/src/kiri-run/worker.js @@ -257,17 +257,6 @@ kiri.worker = { send.done(vertices); }, - heal(data, send) { - let { vertices, refresh } = data; - let mesh = new base.Mesh({vertices}).heal(); - if (mesh.newFaces || refresh) { - vertices = mesh.unrolled().toFloat32(); - send.done({vertices}, [vertices]); - } else { - send.done({}); - } - }, - snap(data, send) { current.snap = data; send.done(); diff --git a/src/kiri/client.js b/src/kiri/client.js index 6860fd5d..1c1c1dc2 100644 --- a/src/kiri/client.js +++ b/src/kiri/client.js @@ -138,12 +138,6 @@ const client = exports({ }); }, - heal(vertices, callback, refresh) { - send("heal", {vertices, refresh}, (output) => { - callback(output); - }); - }, - config(obj) { send("config", obj, noop); }, diff --git a/src/kiri/init.js b/src/kiri/init.js index c06d7867..1b1cfa25 100644 --- a/src/kiri/init.js +++ b/src/kiri/init.js @@ -2798,7 +2798,6 @@ gapp.register("kiri.init", [], (root, exports) => { $('render-wire').onclick = () => { api.view.wireframe(true, 0, api.space.is_dark() ? 0.25 : 0.5); }; $('render-solid').onclick = () => { api.view.wireframe(false, 0, 1); }; // mesh buttons - $('mesh-heal').onclick = () => { api.widgets.heal() }; $('mesh-swap').onclick = () => { api.widgets.replace() }; $('mesh-export-stl').onclick = () => { objectsExport('stl') }; $('mesh-export-obj').onclick = () => { objectsExport('obj') }; diff --git a/src/kiri/widget.js b/src/kiri/widget.js index 758194d5..97c21440 100644 --- a/src/kiri/widget.js +++ b/src/kiri/widget.js @@ -3,7 +3,6 @@ "use strict"; // dep: geo.base -// dep: geo.mesh // dep: geo.point // dep: geo.points // dep: geo.polygons @@ -224,58 +223,6 @@ class Widget { } } - heal(debug, refresh) { - if (debug) { - let mesh = this.debugMesh().heal(); - let verts = mesh.vertices; - let edges = mesh.edges; - let split = mesh.edges.filter(l => l.split); - let layrz = new kiri.Layers(); - layrz.setLayer("edges", {line: 0}); - for (let line of edges) { - layrz.addLine( - newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2]), - newPoint(verts[line.v2], verts[line.v2+1], verts[line.v2+2]) - ); - } - for (let l=0; l { - kiri.client.heal(this.getVertices().array, data => { - if (data.vertices) { - this.loadVertices(data.vertices); - this.modified = true; - } else { - this.modified = false; - } - resolve(this.modified); - }, refresh); - }); - } - - debugMesh(precision) { - return new base.Mesh({precision, vertices: this.getVertices().array}); - } - // should go away and be replaced by getGeoVertices getVertices() { return this.mesh.geometry.attributes.position; diff --git a/src/kiri/widgets.js b/src/kiri/widgets.js index bcf6a500..e52d383f 100644 --- a/src/kiri/widgets.js +++ b/src/kiri/widgets.js @@ -60,24 +60,6 @@ function replace(vertices) { } } -function heal() { - if (!WIDGETS.length) { - return; - } - let marker = api.show.alert("Analyzing objects", 100000); - setTimeout(() => { - Promise.all(WIDGETS.map(w => w.heal())).then(mod => { - api.hide.alert(marker); - let healed = mod.filter(m => m).length; - if (healed) { - api.show.alert(`${healed} Object${healed ? 's':''} healed`); - } else { - api.show.alert('Nothing found to heal'); - } - }); - }, 1); -} - function meshes() { let out = []; widgets.each(widget => { @@ -98,7 +80,6 @@ const widgets = api.widgets = { load: Widget.loadFromCatalog, new: newWidget, map, - heal, meshes, replace, opacity, diff --git a/web/kiri/index.html b/web/kiri/index.html index 90c3b6cb..5692461b 100644 --- a/web/kiri/index.html +++ b/web/kiri/index.html @@ -149,7 +149,6 @@ -