complete body separation code
This commit is contained in:
parent
d5114f11a7
commit
406cacc453
5 changed files with 72 additions and 9 deletions
|
|
@ -14,6 +14,7 @@ Full docs @ https://docs.grid.space/projects/kiri-moto
|
|||
|
||||
## Mesh:Tool
|
||||
|
||||
* `C` multi-body identification and isolation
|
||||
* `-` parameterize svg and image import
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -400,6 +400,26 @@ const tool = {
|
|||
});
|
||||
},
|
||||
|
||||
isolate(models) {
|
||||
models = fallback(models);
|
||||
api.log.emit('isolating bodies').pin();
|
||||
let promises = [];
|
||||
let mcore = new Matrix4().makeRotationX(Math.PI / 2);
|
||||
for (let m of models) {
|
||||
let p = worker.model_isolate({ id: m.id }).then(bodies => {
|
||||
bodies = bodies.map(vert => new mesh.model({
|
||||
file: m.file,
|
||||
mesh: vert.toFloat32()
|
||||
})).map( nm => nm.applyMatrix4(mcore.clone().multiply(m.mesh.matrixWorld)) );
|
||||
mesh.api.group.new(bodies, undefined, "isolate").setSelected();
|
||||
});
|
||||
promises.push(p);
|
||||
}
|
||||
Promise.all(promises).then(() => {
|
||||
api.log.emit('isolation complete').unpin();
|
||||
});
|
||||
},
|
||||
|
||||
mapFaces(models) {
|
||||
models = fallback(models);
|
||||
api.log.emit('mapping faces').pin();
|
||||
|
|
|
|||
|
|
@ -377,6 +377,7 @@ function ui_build() {
|
|||
h.div({ _: "repair", class: "head" }),
|
||||
// h.div({ class: "vsep" }),
|
||||
h.button({ _: 'analyze', onclick: tool.analyze }),
|
||||
h.button({ _: 'isolate', onclick: tool.isolate }),
|
||||
h.button({ _: 'patch', onclick: tool.repair }),
|
||||
// h.button({ _: 'rebuild', onclick: tool.rebuild }),
|
||||
h.button({ _: 'clean', onclick: tool.clean }),
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ mesh.tool = class MeshTool {
|
|||
}
|
||||
|
||||
generateFaceMap(vertices) {
|
||||
this.checkVertices(vertices, 3);
|
||||
this.vertices = this.checkVertices(vertices, 3);
|
||||
const normals = this.normals = [];
|
||||
const sides = this.sides = [];
|
||||
const _va = new THREE.Vector3();
|
||||
|
|
@ -158,12 +158,13 @@ mesh.tool = class MeshTool {
|
|||
return sides.map(side => this.side2face[side].filter(v => v != face)).flat();
|
||||
}
|
||||
|
||||
findConnectedSurface(faces, radians, filterZ) {
|
||||
const found = {};
|
||||
// depends on generateFaceMap() being run first
|
||||
findConnectedSurface(faces, radians, filterZ, found = {}) {
|
||||
const norms = this.normals;
|
||||
if (filterZ) {
|
||||
faces = faces.filter(f => norms[f][2] >= filterZ);
|
||||
}
|
||||
const checked = {};
|
||||
const check = faces.slice();
|
||||
for (let face of faces) {
|
||||
found[face] = 1;
|
||||
|
|
@ -173,11 +174,17 @@ mesh.tool = class MeshTool {
|
|||
while (check.length) {
|
||||
const face = check.shift();
|
||||
const norm = norms[face];
|
||||
// if (!norm || norm.length < 3) {
|
||||
// throw `invalid face ${face}`;
|
||||
// }
|
||||
if (filterZ !== undefined && norm[2] < filterZ) {
|
||||
continue;
|
||||
}
|
||||
const fadj = this.getAdjacentFaces(face).filter(f => !found[f]);
|
||||
const fadj = this.getAdjacentFaces(face);
|
||||
for (let f of fadj) {
|
||||
if (found[f] || checked[f]) {
|
||||
continue;
|
||||
}
|
||||
// #1 most accurate
|
||||
// const nf = this.normals[f];
|
||||
// _v1.set(nf[0], nf[1], nf[2]);
|
||||
|
|
@ -195,6 +202,7 @@ mesh.tool = class MeshTool {
|
|||
if (fn <= radians) {
|
||||
faces.push(f);
|
||||
check.push(f)
|
||||
checked[f] = 1;
|
||||
found[f] = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -202,6 +210,29 @@ mesh.tool = class MeshTool {
|
|||
return faces;
|
||||
}
|
||||
|
||||
// depends on generateFaceMap() being run first
|
||||
isolateBodies() {
|
||||
const verts = this.checkVertices(this.vertices);
|
||||
const bodies = [];
|
||||
const used = {};
|
||||
for (let i=0, l=this.normals.length-1; i<l; i++) {
|
||||
if (used[i]) {
|
||||
continue;
|
||||
}
|
||||
const body = this.findConnectedSurface([i], Infinity, undefined, used);
|
||||
if (body.length) {
|
||||
// todo: pre-allocate known length
|
||||
// then copy array regions from verts to bverts
|
||||
const bverts = [];
|
||||
for (let f of body) {
|
||||
bverts.push(...verts.slice(f*9, f*9+9));
|
||||
}
|
||||
bodies.push(bverts);
|
||||
}
|
||||
}
|
||||
return bodies;
|
||||
}
|
||||
|
||||
/**
|
||||
* finds edge lines which are line segments on a single face.
|
||||
* construct ordered line maps with array of connected edges.
|
||||
|
|
|
|||
|
|
@ -76,16 +76,21 @@ function analyze(id, opt = {}) {
|
|||
return tool;
|
||||
}
|
||||
|
||||
function mapFaces(id, opt = {}) {
|
||||
function isolateBodies(id) {
|
||||
let tool = mapFaces(id);
|
||||
log(`${id} | isolating bodies`);
|
||||
return tool.isolateBodies();
|
||||
}
|
||||
|
||||
function mapFaces(id) {
|
||||
let rec = cache[id];
|
||||
let { geo, tool } = rec;
|
||||
if (!tool) {
|
||||
tool = rec.tool = new mesh.tool();
|
||||
}
|
||||
const vertices = geo.attributes.position.array;
|
||||
if (!tool.normals) {
|
||||
log(`${id} | generating face map`);
|
||||
tool.generateFaceMap(vertices);
|
||||
tool.generateFaceMap(geo.attributes.position.array);
|
||||
}
|
||||
return tool;
|
||||
}
|
||||
|
|
@ -275,11 +280,16 @@ let model = {
|
|||
},
|
||||
|
||||
mapFaces(data) {
|
||||
let { id, opt } = data;
|
||||
let tool = mapFaces(id, opt);
|
||||
let { id } = data;
|
||||
let tool = mapFaces(id);
|
||||
return { mapped: true };
|
||||
},
|
||||
|
||||
isolate(data) {
|
||||
let { id } = data;
|
||||
return isolateBodies(id);
|
||||
},
|
||||
|
||||
// given model and point, locate matching vertices, lines, and faces
|
||||
select(data) {
|
||||
let { id, x, y, z, a, b, c, matrix, surface } = data;
|
||||
|
|
|
|||
Loading…
Reference in a new issue