remove mapFaces and promote indexFaces as a replacement
This commit is contained in:
parent
0d58db27ed
commit
abf20eb11b
3 changed files with 45 additions and 102 deletions
|
|
@ -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();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
114
src/mesh/tool.js
114
src/mesh/tool.js
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue