add merging of open loops

This commit is contained in:
Stewart Allen 2021-09-08 01:59:18 -04:00
commit e97eb9ad1d
2 changed files with 101 additions and 44 deletions

View file

@ -39,6 +39,8 @@
// 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) {
faces = []; faces = [];
let fcac = {}; // seen face hash
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;
@ -58,7 +60,22 @@
nuvt.push(y); nuvt.push(y);
nuvt.push(z); nuvt.push(z);
} }
faces.push(vpos); fnew.push(vpos);
if (fnew.length === 3) {
if (fnew[0] === fnew[1] || fnew[0] === fnew[2] || fnew[1] === fnew[2]) {
// console.log('invalid face', fnew);
fnew = [];
continue;
}
let key = fnew.slice().sort().join('-');
if (!fcac[key]) {
faces.appendAll(fnew);
// } else {
// console.log('dup face', key);
}
fcac[key] = key;
fnew = [];
}
} }
vertices = nuvt; vertices = nuvt;
} }
@ -99,12 +116,31 @@
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 {
// console.log('adding face to line twice', this, face); console.log('adding face to line twice', this, face);
} }
return this; return this;
} }
adjacentUnused() {
return vmap[this.v1]
.concat(vmap[this.v2])
.filter(l => l !== this && !l.used && l.faces.length === 1);
}
adjacentUsed() {
return vmap[this.v1]
.concat(vmap[this.v2])
.filter(l => l !== this && l.used && l.faces.length === 1);
}
touches(line) {
return this.v1 === line.v1 ||
this.v1 === line.v2 ||
this.v2 === line.v1 ||
this.v2 === line.v2;
}
unitVector() { unitVector() {
if (this.unit !== undefined) { if (this.unit !== undefined) {
return this.unit; return this.unit;
@ -171,22 +207,27 @@
if (line.used) { if (line.used) {
continue; continue;
} }
// cannot start on split
if (line.adjacentUnused().length > 2) {
console.log('cannot start on a split');
continue;
}
// line.used = true; // line.used = true;
let loop = [ line ]; let loop = [ ];
// build line through adjacent lines // build line through adjacent lines
while (true) { while (true) {
let adjacent = vmap[line.v1] let adjacent = line.adjacentUnused();
.concat(vmap[line.v2])
.filter(l => l !== line && !l.used && l.faces.length === 1);
if (adjacent.length === 0) { if (adjacent.length === 0) {
let first = loop[0];
let last = loop.last();
loop.open = loop.length < 3
|| (first.v1 !== last.v1
&& first.v2 !== last.v2
&& first.v1 !== last.v2
&& first.v2 !== last.v1);
// console.log({term: line, adj: line.adjacentUsed(), open, loop});
break; break;
} } else if (adjacent.length === 1) {
if (adjacent.length > 2) {
console.log('error adjacent', line, adjacent, loops.length, loop.length);
line.error = adjacent;
// break;
}
if (adjacent.length === 1) {
if (line.v2 !== adjacent[0].v1) { if (line.v2 !== adjacent[0].v1) {
let tmp = adjacent[0].v1; let tmp = adjacent[0].v1;
adjacent[0].v1 = adjacent[0].v2; adjacent[0].v1 = adjacent[0].v2;
@ -194,41 +235,56 @@
// console.log('chirality mismatch fixed'); // console.log('chirality mismatch fixed');
} }
line = adjacent[0]; line = adjacent[0];
} else { } else if (adjacent.length === 2) {
// follow edges according to chirality // follow edges according to chirality
line = adjacent[0].v1 === line.v2 ? line = adjacent[0].v1 === line.v2 ?
adjacent[0] : adjacent[0] :
adjacent[1] adjacent[1]
} else {
// console.log('error adjacent', line, adjacent, loops.length, loop.length);
line.split = adjacent;
line = adjacent[0];
} }
loop.push(line); loop.push(line);
line.used = true; line.used = true;
} }
// drop co-linear points because they can't be connected into valid faces
// fixup remaining line by dropping common point and using dropped line's point
// todo: disabled until faces are fixed up, too. otherwise, problems
if (false) for (let j=0, jl=loop.length; j<jl-1; j++) {
let l1 = loop[j];
if (l1.del) {
continue;
}
for (let k=j+1; k<jl; k++) {
let l2 = loop[k];
if (l2.del) {
continue;
}
// todo
if (diffUnitVector(l1.unitVector(), l2.unitVector()) < 0.0001) {
// console.log('collinear', l1, l2);
l2.del = true;
l1.v2 = l2.v2;
}
}
}
loop = loop.filter(l => !l.del);
loops.push(loop); loops.push(loop);
} }
// console.log({loops}); // attempt to connect open loops
if (loops.length > 1) {
outer: for (let i=0; i<loops.length-1; i++) {
let l1 = loops[i];
if (!(l1 && l1.open)) {
continue;
}
for (let j=i+1; j<loops.length; j++) {
let l2 = loops[j];
if (!(l2 && l2.open)) {
continue;
}
let nuloop;
if (l1[0].touches(l2[0])) {
nuloop = [...l1, ...l2.reverse()];
} else if (l1[0].touches(l2.last())) {
nuloop = [...l2, ...l1];
} else if (l1.last().touches(l2[0])) {
nuloop = [...l1, ...l2];
} else if (l1.last().touches(l2.last())) {
nuloop = [...l1, ...l2.reverse()];
}
if (nuloop) {
nuloop.open = true;
loops.push(nuloop);
loops[i] = loops[j] = undefined;
continue outer;
}
}
}
}
this.loops = loops = loops.filter(l => l && l.length > 2);
console.log({loops});
// progressive boundary run algorithm // progressive boundary run algorithm
function emitLoop1(loop) { function emitLoop1(loop) {

View file

@ -307,14 +307,14 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
}; };
PRO.heal = function(debug) { PRO.heal = function(debug) {
let mesh = this.debugMesh(); let mesh = this.debugMesh(undefined);
mesh.heal(); mesh.heal();
if (debug) { if (debug) {
let verts = mesh.vertices; let verts = mesh.vertices;
let edges = mesh.edges; let edges = mesh.edges;
let error = mesh.edges.filter(l => l.error); let split = mesh.edges.filter(l => l.split);
let layrz = new KIRI.Layers(); let layrz = new KIRI.Layers();
layrz.setLayer("edges", {line: 0xff0000}); layrz.setLayer("edges", {line: 0});
for (let line of edges) { for (let line of edges) {
layrz.addLine( layrz.addLine(
BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2]), BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2]),
@ -322,24 +322,25 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
); );
} }
for (let l=0; l<mesh.loops.length; l++) { for (let l=0; l<mesh.loops.length; l++) {
layrz.setLayer(`loop ${l}`, {line: l % 2 === 0 ? 0xff00ff : 0x00ff00}); layrz.setLayer(`loop ${l}`, {line: [ 0xff0000, 0x00ff00, 0x0000ff ][l % 3]});
let zo = [0.15, 0.3, 0.45][l % 3];
for (let line of mesh.loops[l]) { for (let line of mesh.loops[l]) {
layrz.addLine( layrz.addLine(
BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2] - 0.03), BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2] - zo),
BASE.newPoint(verts[line.v2], verts[line.v2+1], verts[line.v2+2] - 0.03) BASE.newPoint(verts[line.v2], verts[line.v2+1], verts[line.v2+2] - zo)
); );
} }
} }
layrz.setLayer("error", {line: 0x0000ff}); layrz.setLayer("split", {line: 0xff00ff});
for (let line of error) { for (let line of split) {
layrz.addLine( layrz.addLine(
BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2] - 0.06), BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2] - 0.6),
BASE.newPoint(verts[line.v2], verts[line.v2+1], verts[line.v2+2] - 0.06) BASE.newPoint(verts[line.v2], verts[line.v2+1], verts[line.v2+2] - 0.6)
); );
} }
let stack = new KIRI.Stack(this.mesh); let stack = new KIRI.Stack(this.mesh);
stack.addLayers(layrz); stack.addLayers(layrz);
return { layrz, stack }; return { mesh, layrz, stack };
} }
if (mesh.newFaces) { if (mesh.newFaces) {
this.loadVertices(mesh.unrolled().toFloat32()); this.loadVertices(mesh.unrolled().toFloat32());