remove mapFaces and promote indexFaces as a replacement

This commit is contained in:
Stewart Allen 2022-04-14 13:39:18 -04:00
commit abf20eb11b
3 changed files with 45 additions and 102 deletions

View file

@ -405,6 +405,7 @@ const tool = {
api.log.emit('isolating bodies').pin();
let promises = [];
let mcore = new Matrix4().makeRotationX(Math.PI / 2);
let mark = Date.now();
for (let m of models) {
let p = worker.model_isolate({ id: m.id }).then(bodies => {
bodies = bodies.map(vert => new mesh.model({
@ -417,23 +418,24 @@ const tool = {
}
Promise.all(promises).then(() => {
api.log.emit('isolation complete').unpin();
// api.log.emit(`... isolate time = ${Date.now() - mark}`);
});
},
mapFaces(models, opt = {}) {
indexFaces(models, opt = {}) {
models = fallback(models);
api.log.emit('mapping faces').pin();
let promises = [];
let mark = Date.now();
for (let m of models) {
let p = worker.model_mapFaces({ id: m.id, opt }).then(data => {
let p = worker.model_indexFaces({ id: m.id, opt }).then(data => {
// console.log({map_info: data});
});
promises.push(p);
}
Promise.all(promises).then(() => {
api.log.emit('mapping complete').unpin();
api.log.emit(`... map time = ${Date.now() - mark}`);
// api.log.emit(`... index time = ${Date.now() - mark}`);
});
},
@ -508,7 +510,7 @@ const mode = {
check() {
if (prefs.map.mode === modes.surface) {
tool.mapFaces();
tool.indexFaces();
}
},

View file

@ -9,6 +9,7 @@ gapp.register("mesh.tool", [], (root, exports) => {
const { mesh } = root;
const { geom } = mesh;
const { Vector3 } = THREE;
const empty = 0xffffffff;
/**
* tool for identiying defects and healing them
@ -100,49 +101,6 @@ mesh.tool = class MeshTool {
return this;
}
generateFaceMap(vertices) {
this.vertices = this.checkVertices(vertices, 3);
const normals = this.normals = [];
const sides = this.sides = [];
const _va = new Vector3();
const _vb = new Vector3();
const _vc = new Vector3();
for (let i=0, ni=0, l=vertices.length; i<l; ) {
_va.set(vertices[i++], vertices[i++], vertices[i++]);
_vb.set(vertices[i++], vertices[i++], vertices[i++]);
_vc.set(vertices[i++], vertices[i++], vertices[i++]);
const vn = THREE.computeFaceNormal(_va, _vb, _vc);
normals.push([vn.x, vn.y, vn.z]);
}
const prec = this.precision;
const vround = vertices.map(v => (v * prec) | 0);
const sidekeyid = {};
const side2face = this.side2face = [];
for (let i=0, side=0, face=0, l=vround.length; i<l; ) {
const v1 = [ vround[i++], vround[i++], vround[i++] ].join(',');
const v2 = [ vround[i++], vround[i++], vround[i++] ].join(',');
const v3 = [ vround[i++], vround[i++], vround[i++] ].join(',');
const s1 = ( v1 < v2 ? [ v1, v2] : [ v2, v1 ] ).join('=');
const s2 = ( v2 < v3 ? [ v2, v3] : [ v3, v2 ] ).join('=');
const s3 = ( v3 < v1 ? [ v3, v1] : [ v1, v3 ] ).join('=');
const smap = [ s1, s2, s3 ].map(key => {
let id = sidekeyid[key];
if (id >= 0) {
return id;
}
id = sidekeyid[key] = side++;
side2face.push([]);
return id;
});
for (let sfa of smap.map(id => side2face[id])) {
sfa.push(face);
}
sides[face] = smap;
face++;
}
return this;
}
// combines generatedFaces() and generateFaceMap()
// face record: vi1, vi2, vi3, nx, ny, nz
// vi = vertex index
@ -155,7 +113,7 @@ mesh.tool = class MeshTool {
const fcount = vcount / 3;
const vround = vertices.map(v => (v * prec) | 0);
// side records [ vi0, vi1, fn1, fn2 ]
const sides = new Uint32Array(fcount * 4);
const sides = new Uint32Array(fcount * 4 * 3).fill(empty);
// map of side index to face count
const srecs = {};
// side extended records when face count exceeds 2 (bad mesh)
@ -200,7 +158,6 @@ mesh.tool = class MeshTool {
const s2 = (v2 < v0 ? v2 + "," + v0 : v0 + "," +v2);
// for storing raw vertex offset in side record
const [ vr0, vr1, vr2 ] = viraw;
// const vv = [ vr0, vr1, vr1, vr2, vr2, vr0 ];
// store face indexes into sdrec array for each side
const smap = [ s0, s1, s2 ].map((key,ki) => {
let sid = simap[key], sdoff, sdcnt;
@ -208,8 +165,6 @@ mesh.tool = class MeshTool {
sid = simap[key] = sn++;
sdcnt = srecs[sid] = 1;
sdoff = sid * 4;
// sides[sdoff] = vv[ki * 2];
// sides[sdoff + 1] = vv[ki * 2 + 1];
sides[sdoff] = viraw[ki];
sides[sdoff + 1] = viraw[(ki + 1) % 3];
} else {
@ -238,44 +193,51 @@ mesh.tool = class MeshTool {
this.indexed = {
faces, sides, sideExt
};
console.log(this.indexed);
}
getAdjacentFaces(face) {
if (!this.sides) {
throw "missing sides";
if (!this.indexed) {
throw "missing index";
}
if (!this.side2face) {
throw "missing side2face";
}
const sides = this.sides[face];
if (!sides) {
const { faces, sides } = this.indexed;
const foff = face * 6;
const s0 = faces[foff + 3];
const s1 = faces[foff + 4];
const s2 = faces[foff + 5];
const farr = [
sides[s0 * 4 + 2],
sides[s0 * 4 + 3],
sides[s1 * 4 + 2],
sides[s1 * 4 + 3],
sides[s2 * 4 + 2],
sides[s2 * 4 + 3]
].filter(f => f !== empty && f !== face);
if (!farr.length) {
console.log(`no adjacent faces to ${face}`);
return [];
}
return sides.map(side => this.side2face[side].filter(v => v != face)).flat();
return farr;
}
// depends on generateFaceMap() being run first
findConnectedSurface(faces, radians, filterZ, found = {}) {
const norms = this.normals;
if (!this.indexed) {
throw "missing index";
}
const norms = this.indexed.faces;
if (filterZ) {
faces = faces.filter(f => norms[f][2] >= filterZ);
// optional filter to z normal >= value
faces = faces.filter(f => norms[f * 6 + 2] >= filterZ);
}
const checked = {};
const check = faces.slice();
for (let face of faces) {
found[face] = 1;
}
// const _v1 = new Vector3();
// const _v2 = new Vector3();
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) {
const froot = face * 6;
if (filterZ !== undefined && norms[froot +2] < filterZ) {
continue;
}
const fadj = this.getAdjacentFaces(face);
@ -283,20 +245,12 @@ mesh.tool = class MeshTool {
if (found[f] || checked[f]) {
continue;
}
// #1 most accurate
// const nf = this.normals[f];
// _v1.set(nf[0], nf[1], nf[2]);
// _v2.set(norm[0], norm[1], norm[2]);
// const fn = _v1.angleTo(_v2);
// #2 slightly less so
// const pf = Math.PI / 4;
// const fn = Math.sin(pf * Math.sqrt(this.normals[f]
// .map((v,i) => Math.pow(norm[i] - v, 2))
// .reduce((a,v) => a + v)));
// #3 fastest, still good
const fn = Math.sqrt(norms[f]
.map((v,i) => Math.pow(norm[i] - v, 2))
.reduce((a,v) => a + v));
const aroot = f * 6;
let sum = 0;
for (let i=0; i<3; i++) {
sum += Math.pow(norms[froot + i] - norms[aroot + i], 2);
}
const fn = Math.sqrt(sum);
if (fn <= radians) {
faces.push(f);
check.push(f)
@ -313,7 +267,7 @@ mesh.tool = class MeshTool {
const verts = this.checkVertices(this.vertices);
const bodies = [];
const used = {};
for (let i=0, l=this.normals.length-1; i<l; i++) {
for (let i=0, l=verts.length / 9; i<l; i++) {
if (used[i]) {
continue;
}

View file

@ -77,31 +77,18 @@ function analyze(id, opt = {}) {
}
function isolateBodies(id) {
let tool = mapFaces(id);
let tool = indexFaces(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();
}
if (!tool.normals) {
log(`${id} | generating face map`);
tool.generateFaceMap(geo.attributes.position.array);
}
return tool;
}
function indexFaces(id) {
let rec = cache[id];
let { geo, tool } = rec;
if (!tool) {
tool = rec.tool = new mesh.tool();
}
if (!tool.normals) {
if (!tool.indexed) {
log(`${id} | indexing mesh`);
tool.index(geo.attributes.position.array);
}
@ -292,9 +279,9 @@ let model = {
};
},
mapFaces(data) {
indexFaces(data) {
let { id, opt } = data;
let tool = opt.index ? indexFaces(id) : mapFaces(id);
let tool = indexFaces(id);
return { mapped: true };
},
@ -350,7 +337,7 @@ let model = {
}
// if the geometry has indexed faces and radians are set, find surface
const tool = rec.tool;
if (tool && tool.sides && radians) {
if (tool && tool.indexed && radians) {
const match = tool.findConnectedSurface(faces, radians, filterZ);
return { faces: match, edges, verts, point };
}