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

@ -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;
}