stub in ungrouping, add analysis step

This commit is contained in:
Stewart Allen 2022-01-11 14:41:49 -05:00
commit 9f73e6e3c3
5 changed files with 83 additions and 30 deletions

View file

@ -79,7 +79,7 @@ function restore_space() {
let count = 0; let count = 0;
let space = moto.Space; let space = moto.Space;
let parray = []; let parray = [];
let mcache; let mcache = {};
mesh.db.admin.get("camera") mesh.db.admin.get("camera")
.then(saved => { .then(saved => {
if (saved) { if (saved) {
@ -158,7 +158,7 @@ function space_init(data) {
case 'KeyD': case 'KeyD':
if (shiftKey) { if (shiftKey) {
for (let m of selection.models()) { for (let m of selection.models()) {
m.debug(); m.duplicate();
} }
} }
break; break;
@ -182,6 +182,8 @@ function space_init(data) {
return selection.boundsBox({toggle:true}); return selection.boundsBox({toggle:true});
case 'KeyH': case 'KeyH':
return space.view.home(); return space.view.home();
case 'KeyA':
return api.tool.analyze();
case 'KeyR': case 'KeyR':
return api.tool.repair(); return api.tool.repair();
case 'KeyT': case 'KeyT':

View file

@ -258,7 +258,13 @@ let file = {
let tool = { let tool = {
analyze() { 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() { repair() {

View file

@ -79,14 +79,14 @@ mesh.model = class MeshModel extends mesh.object {
return this.mesh.matrixWorld.elements; return this.mesh.matrixWorld.elements;
} }
debug() { // return new group containing just this model in world coordinates
worker.model_debug({ duplicate() {
worker.model_duplicate({
matrix: this.matrix, matrix: this.matrix,
id: this.id id: this.id
}).then(data => { }).then(data => {
// for debugging matrix ops
return mesh.api.group.new([new mesh.model({ return mesh.api.group.new([new mesh.model({
file: `synth-${this.name}`, file: `${this.file}-dup`,
mesh: data mesh: data
})]); })]);
}); });
@ -101,12 +101,6 @@ mesh.model = class MeshModel extends mesh.object {
meh.receiveShadow = true; meh.receiveShadow = true;
meh.castShadow = true; meh.castShadow = true;
meh.renderOrder = 1; 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 // sets fallback opacity for wireframe toggle
this.opacity(1); this.opacity(1);
// this ref allows clicks to be traced to models and groups // 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) { reload(vertices, indices, normals) {
this.wireframe(false); let was = this.wireframe(false);
let geo = this.mesh.geometry; let geo = this.mesh.geometry;
geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); geo.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geo.setAttribute('normal', undefined); geo.setAttribute('normal', undefined);
@ -125,6 +119,8 @@ mesh.model = class MeshModel extends mesh.object {
if (!normals) geo.computeVertexNormals(); if (!normals) geo.computeVertexNormals();
// sync data to worker // sync data to worker
worker.model_load({id: this.id, name: this.name, vertices, indices}); worker.model_load({id: this.id, name: this.name, vertices, indices});
// restore wireframe state
this.wireframe(was);
} }
get group() { get group() {
@ -150,6 +146,19 @@ mesh.model = class MeshModel extends mesh.object {
return this.vertices / 3; 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) { visible(bool) {
if (bool === undefined) { if (bool === undefined) {
return this.mesh.visible; return this.mesh.visible;
@ -204,6 +213,7 @@ mesh.model = class MeshModel extends mesh.object {
if (bool.toggle) { if (bool.toggle) {
return this.wireframe(this._wire ? false : true, opt); return this.wireframe(this._wire ? false : true, opt);
} }
let was = this._wire ? true : false;
if (this._wire) { if (this._wire) {
this.mesh.remove(this._wire); this.mesh.remove(this._wire);
this._wire = undefined; this._wire = undefined;
@ -215,6 +225,7 @@ mesh.model = class MeshModel extends mesh.object {
this.opacity({temp: opt.opacity || 0}); this.opacity({temp: opt.opacity || 0});
} }
space.update(); space.update();
return was;
} }
remove() { remove() {

View file

@ -113,7 +113,7 @@ mesh.tool = class MeshTool {
* construct ordered line maps with array of connected edges. * construct ordered line maps with array of connected edges.
* connect lines into polys. earcut polys into new faces. * connect lines into polys. earcut polys into new faces.
*/ */
heal() { heal(opt = { merge: true }) {
let vertices = this.vertices; let vertices = this.vertices;
let faces = this.faces; let faces = this.faces;
let hash = {}; // key to line map 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 // rotate/flatten to Z plane and use earcut to generate faces
// because earcut emits point indexes, no need to un-rotate // because earcut emits point indexes, no need to un-rotate
function emitLoop(loop) { function emitLoop(loop) {
let faces = [];
let lastPoint; let lastPoint;
let pindex = []; let pindex = [];
let points = []; let points = [];
@ -371,17 +372,33 @@ mesh.tool = class MeshTool {
for (let point of ec) { for (let point of ec) {
faces.push(pindex[point]); faces.push(pindex[point]);
} }
// newly generated faces
return faces;
} }
// emit loops // create area faces covering loops
let faceCount = this.faces.length; let areas = this.areas = [];
for (let loop of loops) { 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; this.newFaces = this.faces.length - faceCount;
return this; return this;
} }
// merge poly areas into faces
merge() {
for (let area of this.areas || []) {
this.faces.appendAll(area);
}
}
}; };
})(); })();

View file

@ -38,6 +38,20 @@ function translate_encode(id, matrix) {
return geo.attributes.position.array; 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 = { let model = {
load(data) { load(data) {
let { vertices, indices, name, id } = data; let { vertices, indices, name, id } = data;
@ -47,7 +61,8 @@ let model = {
cacheUpdate(id, { name, geo, matrix: core_matrix.clone() }); cacheUpdate(id, { name, geo, matrix: core_matrix.clone() });
}, },
debug(data) { // return new vertices in world coordinates
duplicate(data) {
let { id, matrix } = data; let { id, matrix } = data;
return translate_encode(id, matrix); return translate_encode(id, matrix);
throw "should not here"; throw "should not here";
@ -55,21 +70,23 @@ let model = {
let geo = rec.geo.clone(); let geo = rec.geo.clone();
let m4 = core_matrix.clone().multiply( new THREE.Matrix4().fromArray(matrix) ); let m4 = core_matrix.clone().multiply( new THREE.Matrix4().fromArray(matrix) );
geo.applyMatrix4(m4); geo.applyMatrix4(m4);
// for debugging state / matrix ops
return geo.attributes.position.array; 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) { heal(id) {
log(`${id} | indexing...`); let tool = analyze(id);
let geo = cache[id].geo; log(`${id} | unrolling...`);
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);
return true || tool.newFaces ? { return true || tool.newFaces ? {
vertices: tool.unrolled().toFloat32(), vertices: tool.unrolled().toFloat32(),
} : 0; } : 0;