speed up face generation for healing
This commit is contained in:
parent
2f2b104d72
commit
955d9b9a3f
4 changed files with 36 additions and 24 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
const BASE = self.base = self.base || {};
|
const BASE = self.base = self.base || {};
|
||||||
|
const TEST = 0;
|
||||||
|
|
||||||
if (BASE.Mesh) {
|
if (BASE.Mesh) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -12,7 +13,7 @@
|
||||||
|
|
||||||
BASE.Mesh = class Mesh {
|
BASE.Mesh = class Mesh {
|
||||||
constructor(params = {}) {
|
constructor(params = {}) {
|
||||||
this.precision = params.precision || 6;
|
this.precision = Math.pow(10, params.precision || 6);
|
||||||
if (params.vertices) {
|
if (params.vertices) {
|
||||||
this.setData(params.vertices, params.faces);
|
this.setData(params.vertices, params.faces);
|
||||||
}
|
}
|
||||||
|
|
@ -38,21 +39,24 @@
|
||||||
}
|
}
|
||||||
// when face/index data is missing, vertices need to be normalized
|
// when face/index data is missing, vertices need to be normalized
|
||||||
if (!faces) {
|
if (!faces) {
|
||||||
|
if (TEST) console.time('generate faces');
|
||||||
faces = [];
|
faces = [];
|
||||||
let fcac = {}; // seen face hash
|
let fcac = {}; // seen face hash
|
||||||
let fnew = []; // accumulate vertex triplets
|
let fnew = []; // accumulate vertex triplets
|
||||||
let nuvt = []; // new vertex list
|
let nuvt = []; // new vertex list
|
||||||
let hash = {}; // find vertex matches
|
let hash = {}; // find vertex matches
|
||||||
let prec = this.precision;
|
let prec = this.precision;
|
||||||
|
let dups = 0;
|
||||||
|
// let cull = 0;
|
||||||
for (let i=0, l=vertices.length; i<l; i += 3) {
|
for (let i=0, l=vertices.length; i<l; i += 3) {
|
||||||
let x = vertices[i];
|
let x = vertices[i];
|
||||||
let y = vertices[i+1];
|
let y = vertices[i+1];
|
||||||
let z = vertices[i+2];
|
let z = vertices[i+2];
|
||||||
let key = [
|
let key = [
|
||||||
x.toFixed(prec),
|
(x * prec) | 0,
|
||||||
y.toFixed(prec),
|
(y * prec) | 0,
|
||||||
z.toFixed(prec)
|
(z * prec) | 0
|
||||||
].join(',');
|
].join('');
|
||||||
let vpos = hash[key];
|
let vpos = hash[key];
|
||||||
if (vpos === undefined) {
|
if (vpos === undefined) {
|
||||||
hash[key] = vpos = nuvt.length;
|
hash[key] = vpos = nuvt.length;
|
||||||
|
|
@ -63,20 +67,25 @@
|
||||||
fnew.push(vpos);
|
fnew.push(vpos);
|
||||||
if (fnew.length === 3) {
|
if (fnew.length === 3) {
|
||||||
// cull invalid faces (shares 2 or more points)
|
// cull invalid faces (shares 2 or more points)
|
||||||
if (fnew[0] === fnew[1] || fnew[0] === fnew[2] || fnew[1] === fnew[2]) {
|
// if (fnew[0] === fnew[1] || fnew[0] === fnew[2] || fnew[1] === fnew[2]) {
|
||||||
fnew = [];
|
// fnew = [];
|
||||||
continue;
|
// cull++;
|
||||||
}
|
// continue;
|
||||||
|
// }
|
||||||
let key = fnew.slice().sort().join('-');
|
let key = fnew.slice().sort().join('-');
|
||||||
// drop duplicate faces (even when reversed - thus the sort)
|
// drop duplicate faces (sort handles reverse order)
|
||||||
if (!fcac[key]) {
|
if (!fcac[key]) {
|
||||||
faces.appendAll(fnew);
|
faces.appendAll(fnew);
|
||||||
|
} else {
|
||||||
|
dups++;
|
||||||
}
|
}
|
||||||
fcac[key] = key;
|
fcac[key] = key;
|
||||||
fnew = [];
|
fnew = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vertices = nuvt;
|
vertices = nuvt;
|
||||||
|
if (TEST) console.timeEnd('generate faces');
|
||||||
|
if (TEST) console.log({dups, faces:faces.length/3});
|
||||||
}
|
}
|
||||||
this.vertices = vertices;
|
this.vertices = vertices;
|
||||||
this.faces = faces;
|
this.faces = faces;
|
||||||
|
|
@ -101,6 +110,8 @@
|
||||||
* connect lines into polys. earcut polys into new faces.
|
* connect lines into polys. earcut polys into new faces.
|
||||||
*/
|
*/
|
||||||
heal() {
|
heal() {
|
||||||
|
if (TEST) console.time('heal');
|
||||||
|
|
||||||
let vertices = this.vertices;
|
let vertices = this.vertices;
|
||||||
let faces = this.faces;
|
let faces = this.faces;
|
||||||
let hash = {}; // key to line map
|
let hash = {}; // key to line map
|
||||||
|
|
@ -117,7 +128,7 @@
|
||||||
addFace(face) {
|
addFace(face) {
|
||||||
if (this.faces.indexOf(face) < 0) {
|
if (this.faces.indexOf(face) < 0) {
|
||||||
this.faces.push(face);
|
this.faces.push(face);
|
||||||
} else {
|
} else if (TEST) {
|
||||||
console.log('adding face to line twice', this, face);
|
console.log('adding face to line twice', this, face);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -204,7 +215,6 @@
|
||||||
// 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);
|
||||||
let loops = this.loops = [];
|
let loops = this.loops = [];
|
||||||
// console.log({edges});
|
|
||||||
|
|
||||||
// connect edge lines into closed loops
|
// connect edge lines into closed loops
|
||||||
for (let i=0, l=edges.length; i<l; i++) {
|
for (let i=0, l=edges.length; i<l; i++) {
|
||||||
|
|
@ -237,7 +247,7 @@
|
||||||
let tmp = adjacent[0].v1;
|
let tmp = adjacent[0].v1;
|
||||||
adjacent[0].v1 = adjacent[0].v2;
|
adjacent[0].v1 = adjacent[0].v2;
|
||||||
adjacent[0].v2 = tmp;
|
adjacent[0].v2 = tmp;
|
||||||
// console.log('chirality mismatch fixed');
|
if (TEST > 1) console.log('chirality mismatch fixed');
|
||||||
}
|
}
|
||||||
line = adjacent[0];
|
line = adjacent[0];
|
||||||
} else if (adjacent.length === 2) {
|
} else if (adjacent.length === 2) {
|
||||||
|
|
@ -246,7 +256,7 @@
|
||||||
adjacent[0] :
|
adjacent[0] :
|
||||||
adjacent[1]
|
adjacent[1]
|
||||||
} else {
|
} else {
|
||||||
// console.log('error adjacent', line, adjacent, loops.length, loop.length);
|
if (TEST > 1) console.log('error adjacent', line, adjacent, loops.length, loop.length);
|
||||||
line.split = adjacent;
|
line.split = adjacent;
|
||||||
line = adjacent[0];
|
line = adjacent[0];
|
||||||
}
|
}
|
||||||
|
|
@ -290,13 +300,14 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log({loops})
|
|
||||||
|
|
||||||
// store invalid loops for display / culling
|
// store invalid loops for display / culling
|
||||||
this.shorts = loops.filter(l => l && l.length <= 2);
|
this.shorts = loops.filter(l => l && l.length <= 2);
|
||||||
|
if (TEST) console.log({edges, loops, shorts: this.shorts});
|
||||||
|
|
||||||
// filter out null and short loops
|
// filter out null and short loops
|
||||||
this.loops = loops = loops.filter(l => l && l.length > 2);
|
this.loops = loops = loops.filter(l => l && l.length > 2);
|
||||||
// console.log({loops})
|
if (TEST > 1) console.log({loops_filtered: loops});
|
||||||
|
|
||||||
// rotate/flatten to Z plane and use earcut to generate faces
|
// rotate/flatten to Z plane and use earcut to generate faces
|
||||||
// because earcut emits point indexes, no need to un-rotate
|
// because earcut emits point indexes, no need to un-rotate
|
||||||
|
|
@ -353,7 +364,7 @@
|
||||||
|
|
||||||
let fpoints = points.flat();
|
let fpoints = points.flat();
|
||||||
let ec = earcut(fpoints, undefined, 3);
|
let ec = earcut(fpoints, undefined, 3);
|
||||||
// console.log({points, fpoints, ec, dx, dy, dz});
|
if (TEST > 2) console.log({points, fpoints, ec, dx, dy, dz});
|
||||||
|
|
||||||
for (let point of ec) {
|
for (let point of ec) {
|
||||||
faces.push(pindex[point]);
|
faces.push(pindex[point]);
|
||||||
|
|
@ -367,8 +378,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.newFaces = this.faces.length - faceCount;
|
this.newFaces = this.faces.length - faceCount;
|
||||||
// console.log({newFaces: this.newFaces});
|
if (TEST) console.log({newFaces: this.newFaces});
|
||||||
|
|
||||||
|
if (TEST) console.timeEnd('heal');
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -126,8 +126,8 @@ KIRI.work = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
heal: function(vertices, callback) {
|
heal: function(vertices, callback, refresh) {
|
||||||
send("heal", {vertices}, function(output) {
|
send("heal", {vertices, refresh}, function(output) {
|
||||||
callback(output);
|
callback(output);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -386,7 +386,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PRO.heal = function(debug) {
|
PRO.heal = function(debug, refresh) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
let mesh = this.debugMesh().heal();
|
let mesh = this.debugMesh().heal();
|
||||||
let verts = mesh.vertices;
|
let verts = mesh.vertices;
|
||||||
|
|
@ -430,7 +430,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
this.modified = false;
|
this.modified = false;
|
||||||
}
|
}
|
||||||
resolve(this.modified);
|
resolve(this.modified);
|
||||||
});
|
}, refresh);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -203,9 +203,9 @@ KIRI.worker = {
|
||||||
},
|
},
|
||||||
|
|
||||||
heal: function(data, send) {
|
heal: function(data, send) {
|
||||||
let { vertices } = data;
|
let { vertices, refresh } = data;
|
||||||
let mesh = new base.Mesh({vertices}).heal();
|
let mesh = new base.Mesh({vertices}).heal();
|
||||||
if (mesh.newFaces) {
|
if (mesh.newFaces || refresh) {
|
||||||
vertices = mesh.unrolled().toFloat32();
|
vertices = mesh.unrolled().toFloat32();
|
||||||
send.done({vertices}, [vertices]);
|
send.done({vertices}, [vertices]);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue