analysis returns actionable data for visualization
This commit is contained in:
parent
f500ee0f5c
commit
ae0a884088
5 changed files with 93 additions and 42 deletions
|
|
@ -155,10 +155,12 @@ function space_init(data) {
|
||||||
}
|
}
|
||||||
let { shiftKey, metaKey, ctrlKey, code } = evt;
|
let { shiftKey, metaKey, ctrlKey, code } = evt;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
case 'KeyI':
|
||||||
|
return api.file.import();
|
||||||
|
case 'KeyX':
|
||||||
|
return api.file.export();
|
||||||
case 'KeyD':
|
case 'KeyD':
|
||||||
if (shiftKey) {
|
if (shiftKey) return selection.duplicate();
|
||||||
return selection.duplicate();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 'KeyC':
|
case 'KeyC':
|
||||||
return selection.centerXY().focus();
|
return selection.centerXY().focus();
|
||||||
|
|
@ -166,10 +168,10 @@ function space_init(data) {
|
||||||
return selection.floor().focus();
|
return selection.floor().focus();
|
||||||
case 'KeyM':
|
case 'KeyM':
|
||||||
return selection.merge();
|
return selection.merge();
|
||||||
case 'KeyI':
|
case 'KeyA':
|
||||||
return api.file.import();
|
return selection.analyze();
|
||||||
case 'KeyX':
|
case 'KeyR':
|
||||||
return api.file.export();
|
return selection.repair();
|
||||||
case 'KeyV':
|
case 'KeyV':
|
||||||
return selection.focus();
|
return selection.focus();
|
||||||
case 'KeyW':
|
case 'KeyW':
|
||||||
|
|
@ -182,10 +184,6 @@ 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':
|
|
||||||
return api.tool.repair();
|
|
||||||
case 'KeyT':
|
case 'KeyT':
|
||||||
return space.view.top();
|
return space.view.top();
|
||||||
case 'KeyZ':
|
case 'KeyZ':
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,14 @@ let selection = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
analyze() {
|
||||||
|
tool.analyze(selection.models());
|
||||||
|
},
|
||||||
|
|
||||||
|
repair() {
|
||||||
|
tool.repair(selection.models());
|
||||||
|
},
|
||||||
|
|
||||||
merge() {
|
merge() {
|
||||||
tool.merge(selection.models());
|
tool.merge(selection.models());
|
||||||
},
|
},
|
||||||
|
|
@ -283,24 +291,33 @@ let tool = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
analyze() {
|
analyze(models) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
api.log.emit('analyzing mesh(es)...').pin();
|
api.log.emit('analyzing mesh(es)...').pin();
|
||||||
for (let m of selection.models()) {
|
let areas = [];
|
||||||
|
let edges = [];
|
||||||
|
for (let m of models) {
|
||||||
let p = worker.model_analyze(m.id).then(data => {
|
let p = worker.model_analyze(m.id).then(data => {
|
||||||
// console.log({data});
|
areas.appendAll(data.mapped.areas);
|
||||||
|
edges.appendAll(data.mapped.edges);
|
||||||
});
|
});
|
||||||
promises.push(p);
|
promises.push(p);
|
||||||
}
|
}
|
||||||
Promise.all(promises).then(() => {
|
Promise.all(promises).then(() => {
|
||||||
|
let newmdl = areas.map(area => new mesh.model({
|
||||||
|
file: (area.length/3).toString(),
|
||||||
|
mesh: area.toFloat32()
|
||||||
|
}));
|
||||||
|
mesh.api.group.new(newmdl);
|
||||||
|
console.log({ areas, edges, newmdl });
|
||||||
api.log.emit('analysis complete').unpin();
|
api.log.emit('analysis complete').unpin();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
repair() {
|
repair(models) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
api.log.emit('repairing mesh(es)...').pin();
|
api.log.emit('repairing mesh(es)...').pin();
|
||||||
for (let m of selection.models()) {
|
for (let m of models) {
|
||||||
let p = worker.model_heal(m.id).then(data => {
|
let p = worker.model_heal(m.id).then(data => {
|
||||||
if (data) {
|
if (data) {
|
||||||
m.reload(
|
m.reload(
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ mesh.model = class MeshModel extends mesh.object {
|
||||||
matrix: this.matrix,
|
matrix: this.matrix,
|
||||||
id: this.id
|
id: this.id
|
||||||
}).then(data => {
|
}).then(data => {
|
||||||
return mesh.api.group.new([new mesh.model({
|
mesh.api.group.new([new mesh.model({
|
||||||
file: `${this.file}-dup`,
|
file: `${this.file}-dup`,
|
||||||
mesh: data
|
mesh: data
|
||||||
})]);
|
})]);
|
||||||
|
|
|
||||||
|
|
@ -91,23 +91,13 @@ mesh.tool = class MeshTool {
|
||||||
} else {
|
} else {
|
||||||
faces = faces.map(v => v*3);
|
faces = faces.map(v => v*3);
|
||||||
}
|
}
|
||||||
|
// unique vertex array
|
||||||
this.vertices = vertices;
|
this.vertices = vertices;
|
||||||
|
// unique face array. elements are offset into vertices
|
||||||
this.faces = faces;
|
this.faces = faces;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return non-indexed vertex list (for compatibility)
|
|
||||||
unrolled() {
|
|
||||||
let out = [];
|
|
||||||
let vertices = this.vertices;
|
|
||||||
for (let face of this.faces) {
|
|
||||||
out.push(vertices[face]);
|
|
||||||
out.push(vertices[face+1]);
|
|
||||||
out.push(vertices[face+2]);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds edge lines which are line segments on a single face.
|
* finds edge lines which are line segments on a single face.
|
||||||
* construct ordered line maps with array of connected edges.
|
* construct ordered line maps with array of connected edges.
|
||||||
|
|
@ -212,10 +202,16 @@ mesh.tool = class MeshTool {
|
||||||
let l3 = getLine(v3, v1).addFace(i);
|
let l3 = getLine(v3, v1).addFace(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// array of unique line segment records with vertices
|
||||||
|
// and a list of faces. one = edge, two = inside
|
||||||
|
// all lines should be inside or object is not manifold
|
||||||
|
// but does not preclude self-intersecting geometries
|
||||||
this.lines = lines;
|
this.lines = lines;
|
||||||
|
|
||||||
// lines belonging to only one face are on the edge of a hole
|
// lines belonging to only one face are on the edge of a hole
|
||||||
let edges = this.edges = lines.filter(l => l.faces.length === 1);
|
let edges = this.edges = lines.filter(l => l.faces.length === 1);
|
||||||
|
|
||||||
|
// arrays of connected edges that form a closed loop
|
||||||
let loops = this.loops = [];
|
let loops = this.loops = [];
|
||||||
|
|
||||||
// connect edge lines into closed loops
|
// connect edge lines into closed loops
|
||||||
|
|
@ -383,22 +379,64 @@ mesh.tool = class MeshTool {
|
||||||
this.areas.push(emitLoop(loop));
|
this.areas.push(emitLoop(loop));
|
||||||
}
|
}
|
||||||
|
|
||||||
// track newly created faces when loop areas are merged
|
// auto-merge newly found enclosed areas
|
||||||
let faceCount = this.faces.length;
|
|
||||||
if (opt.merge) {
|
if (opt.merge) {
|
||||||
this.merge();
|
this.merge();
|
||||||
}
|
}
|
||||||
this.newFaces = this.faces.length - faceCount;
|
|
||||||
|
// de-reference loops and edges
|
||||||
|
if (opt.mapped) {
|
||||||
|
this.mapped = {
|
||||||
|
edges: this.expandLoop(this.edges),
|
||||||
|
areas: this.areas.map(a => this.expandArray(a))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge poly areas into faces
|
// add vertex data from given index into array
|
||||||
|
appendVertex(index, array = []) {
|
||||||
|
let vertx = this.vertices;
|
||||||
|
array.push(vertx[index++]);
|
||||||
|
array.push(vertx[index++]);
|
||||||
|
array.push(vertx[index]);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add vertices from a vertex index list to an array
|
||||||
|
expandArray(indices, array = []) {
|
||||||
|
for (let i of indices) {
|
||||||
|
this.appendVertex(i, array);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn loop into XYZ vertex array
|
||||||
|
expandLoop(loop, array = []) {
|
||||||
|
for (let line of loop) {
|
||||||
|
this.appendVertex(line.v1, array);
|
||||||
|
this.appendVertex(line.v2, array);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge generated poly areas into faces
|
||||||
merge() {
|
merge() {
|
||||||
for (let area of this.areas || []) {
|
for (let area of this.areas || []) {
|
||||||
this.faces.appendAll(area);
|
this.faces.appendAll(area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return non-indexed vertex list (for compatibility)
|
||||||
|
unrolled() {
|
||||||
|
let out = [];
|
||||||
|
let vertices = this.vertices;
|
||||||
|
for (let face of this.faces) {
|
||||||
|
this.appendVertex(face, out);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ function translate_encode(id, matrix) {
|
||||||
return geo.attributes.position.array;
|
return geo.attributes.position.array;
|
||||||
}
|
}
|
||||||
|
|
||||||
function analyze(id) {
|
function analyze(id, opt = {}) {
|
||||||
log(`${id} | indexing...`);
|
log(`${id} | indexing...`);
|
||||||
let geo = cache[id].geo;
|
let geo = cache[id].geo;
|
||||||
let tool = new mesh.tool({
|
let tool = new mesh.tool({
|
||||||
|
|
@ -47,7 +47,7 @@ function analyze(id) {
|
||||||
debug: false
|
debug: false
|
||||||
});
|
});
|
||||||
log(`${id} | analyzing...`);
|
log(`${id} | analyzing...`);
|
||||||
tool.heal();
|
tool.heal(opt);
|
||||||
dbug.log(tool);
|
dbug.log(tool);
|
||||||
return tool;
|
return tool;
|
||||||
}
|
}
|
||||||
|
|
@ -80,22 +80,20 @@ let model = {
|
||||||
},
|
},
|
||||||
|
|
||||||
analyze(id) {
|
analyze(id) {
|
||||||
let tool = analyze(id);
|
let tool = analyze(id, { mapped: true });
|
||||||
let { stats, newFaces } = tool;
|
let { stats, mapped } = tool;
|
||||||
let { cull, dups, faces } = stats;
|
let { cull, dups, faces } = stats;
|
||||||
log(`${id} | face count=${faces} bad=${cull} dup=${dups}`);
|
log(`${id} | face count=${faces} bad=${cull} dup=${dups}`);
|
||||||
log(`${id} | open loops=${tool.loops.length} edges=${tool.edges.length}`);
|
log(`${id} | open loops=${tool.loops.length} edges=${tool.edges.length}`);
|
||||||
return {
|
return { stats, mapped };
|
||||||
new: newFaces
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
heal(id) {
|
heal(id) {
|
||||||
let tool = analyze(id);
|
let tool = analyze(id);
|
||||||
log(`${id} | unrolling...`);
|
log(`${id} | unrolling...`);
|
||||||
return true || tool.newFaces ? {
|
return {
|
||||||
vertices: tool.unrolled().toFloat32(),
|
vertices: tool.unrolled().toFloat32(),
|
||||||
} : 0;
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue