From 9f73e6e3c3f95a05afccbc3657cf5cd10c45b5cf Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Tue, 11 Jan 2022 14:41:49 -0500 Subject: [PATCH] stub in ungrouping, add analysis step --- src/main/mesh.js | 6 ++++-- src/mesh/api.js | 8 +++++++- src/mesh/model.js | 33 ++++++++++++++++++++++----------- src/mesh/tool.js | 25 +++++++++++++++++++++---- src/mesh/work.js | 41 +++++++++++++++++++++++++++++------------ 5 files changed, 83 insertions(+), 30 deletions(-) diff --git a/src/main/mesh.js b/src/main/mesh.js index a555b47c..c55767f5 100644 --- a/src/main/mesh.js +++ b/src/main/mesh.js @@ -79,7 +79,7 @@ function restore_space() { let count = 0; let space = moto.Space; let parray = []; - let mcache; + let mcache = {}; mesh.db.admin.get("camera") .then(saved => { if (saved) { @@ -158,7 +158,7 @@ function space_init(data) { case 'KeyD': if (shiftKey) { for (let m of selection.models()) { - m.debug(); + m.duplicate(); } } break; @@ -182,6 +182,8 @@ function space_init(data) { return selection.boundsBox({toggle:true}); case 'KeyH': return space.view.home(); + case 'KeyA': + return api.tool.analyze(); case 'KeyR': return api.tool.repair(); case 'KeyT': diff --git a/src/mesh/api.js b/src/mesh/api.js index 8b3762dc..7ce3611f 100644 --- a/src/mesh/api.js +++ b/src/mesh/api.js @@ -258,7 +258,13 @@ let file = { let tool = { analyze() { - console.log('...analyze todo'); + api.log.emit('analyzing mesh(es)...').pin(); + for (let m of selection.models()) { + worker.model_analyze(m.id).then(data => { + console.log({data}); + api.log.emit('analysis complete').unpin(); + }); + } }, repair() { diff --git a/src/mesh/model.js b/src/mesh/model.js index 6c47b9c0..2bcc35f6 100644 --- a/src/mesh/model.js +++ b/src/mesh/model.js @@ -79,14 +79,14 @@ mesh.model = class MeshModel extends mesh.object { return this.mesh.matrixWorld.elements; } - debug() { - worker.model_debug({ + // return new group containing just this model in world coordinates + duplicate() { + worker.model_duplicate({ matrix: this.matrix, id: this.id }).then(data => { - // for debugging matrix ops return mesh.api.group.new([new mesh.model({ - file: `synth-${this.name}`, + file: `${this.file}-dup`, mesh: data })]); }); @@ -101,12 +101,6 @@ mesh.model = class MeshModel extends mesh.object { meh.receiveShadow = true; meh.castShadow = true; meh.renderOrder = 1; - // center vertices then restore mesh object position - // still this doesn't work. scale broken for bounding boxes - let { mid } = meh.getBoundingBox(); - geo.moveMesh(-mid.x, -mid.y, -mid.z); - geo.computeBoundingBox(); - this.move(mid.x, mid.y, mid.z); // sets fallback opacity for wireframe toggle this.opacity(1); // this ref allows clicks to be traced to models and groups @@ -116,7 +110,7 @@ mesh.model = class MeshModel extends mesh.object { } reload(vertices, indices, normals) { - this.wireframe(false); + let was = this.wireframe(false); let geo = this.mesh.geometry; geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); geo.setAttribute('normal', undefined); @@ -125,6 +119,8 @@ mesh.model = class MeshModel extends mesh.object { if (!normals) geo.computeVertexNormals(); // sync data to worker worker.model_load({id: this.id, name: this.name, vertices, indices}); + // restore wireframe state + this.wireframe(was); } get group() { @@ -150,6 +146,19 @@ mesh.model = class MeshModel extends mesh.object { return this.vertices / 3; } + // todo -- put model into its own group + ungroup() { + // get current world coordinates + let { mid } = meh.getBoundingBox(); + // transform mesh into world coordinates + // move mesh to origin + // create and add to group + // move group center back to original center + geo.moveMesh(-mid.x, -mid.y, -mid.z); + geo.computeBoundingBox(); + this.move(mid.x, mid.y, mid.z); + } + visible(bool) { if (bool === undefined) { return this.mesh.visible; @@ -204,6 +213,7 @@ mesh.model = class MeshModel extends mesh.object { if (bool.toggle) { return this.wireframe(this._wire ? false : true, opt); } + let was = this._wire ? true : false; if (this._wire) { this.mesh.remove(this._wire); this._wire = undefined; @@ -215,6 +225,7 @@ mesh.model = class MeshModel extends mesh.object { this.opacity({temp: opt.opacity || 0}); } space.update(); + return was; } remove() { diff --git a/src/mesh/tool.js b/src/mesh/tool.js index 38849b3c..17bbf2ff 100644 --- a/src/mesh/tool.js +++ b/src/mesh/tool.js @@ -113,7 +113,7 @@ mesh.tool = class MeshTool { * construct ordered line maps with array of connected edges. * connect lines into polys. earcut polys into new faces. */ - heal() { + heal(opt = { merge: true }) { let vertices = this.vertices; let faces = this.faces; let hash = {}; // key to line map @@ -314,6 +314,7 @@ mesh.tool = class MeshTool { // 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 faces = []; let lastPoint; let pindex = []; let points = []; @@ -371,17 +372,33 @@ mesh.tool = class MeshTool { for (let point of ec) { faces.push(pindex[point]); } + + // newly generated faces + return faces; } - // emit loops - let faceCount = this.faces.length; + // create area faces covering loops + let areas = this.areas = []; for (let loop of loops) { - emitLoop(loop); + this.areas.push(emitLoop(loop)); } + // track newly created faces when loop areas are merged + let faceCount = this.faces.length; + if (opt.merge) { + this.merge(); + } this.newFaces = this.faces.length - faceCount; + return this; } + + // merge poly areas into faces + merge() { + for (let area of this.areas || []) { + this.faces.appendAll(area); + } + } }; })(); diff --git a/src/mesh/work.js b/src/mesh/work.js index b411dd5a..7d31fc84 100644 --- a/src/mesh/work.js +++ b/src/mesh/work.js @@ -38,6 +38,20 @@ function translate_encode(id, matrix) { return geo.attributes.position.array; } +function analyze(id) { + log(`${id} | indexing...`); + let geo = cache[id].geo; + let tool = new mesh.tool({ + vertices: geo.attributes.position.array, + faces: geo.index ? geo.index.array : undefined, + debug: false + }); + log(`${id} | analyzing...`); + tool.heal(); + dbug.log(tool); + return tool; +} + let model = { load(data) { let { vertices, indices, name, id } = data; @@ -47,7 +61,8 @@ let model = { cacheUpdate(id, { name, geo, matrix: core_matrix.clone() }); }, - debug(data) { + // return new vertices in world coordinates + duplicate(data) { let { id, matrix } = data; return translate_encode(id, matrix); throw "should not here"; @@ -55,21 +70,23 @@ let model = { let geo = rec.geo.clone(); let m4 = core_matrix.clone().multiply( new THREE.Matrix4().fromArray(matrix) ); geo.applyMatrix4(m4); - // for debugging state / matrix ops return geo.attributes.position.array; }, + analyze(id) { + let tool = analyze(id); + let { stats, newFaces } = tool; + let { cull, dups, faces } = stats; + log(`${id} | face count=${faces} bad=${cull} dup=${dups}`); + log(`${id} | open loops=${tool.loops.length} edges=${tool.edges.length}`); + return { + new: newFaces + }; + }, + heal(id) { - log(`${id} | indexing...`); - let geo = cache[id].geo; - let tool = new mesh.tool({ - vertices: geo.attributes.position.array, - faces: geo.index ? geo.index.array : undefined, - debug: false - }); - log(`${id} | healing...`); - tool.heal(); - dbug.log(tool); + let tool = analyze(id); + log(`${id} | unrolling...`); return true || tool.newFaces ? { vertices: tool.unrolled().toFloat32(), } : 0;