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
if (!faces) {
faces = [];
let fcac = {}; // seen face hash
let fnew = []; // accumulate vertex triplets
let nuvt = []; // new vertex list
let hash = {}; // find vertex matches
let prec = this.precision;
@ -58,7 +60,22 @@
nuvt.push(y);
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;
}
@ -99,12 +116,31 @@
addFace(face) {
if (this.faces.indexOf(face) < 0) {
this.faces.push(face);
// } else {
// console.log('adding face to line twice', this, face);
} else {
console.log('adding face to line twice', this, face);
}
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() {
if (this.unit !== undefined) {
return this.unit;
@ -171,22 +207,27 @@
if (line.used) {
continue;
}
// cannot start on split
if (line.adjacentUnused().length > 2) {
console.log('cannot start on a split');
continue;
}
// line.used = true;
let loop = [ line ];
let loop = [ ];
// build line through adjacent lines
while (true) {
let adjacent = vmap[line.v1]
.concat(vmap[line.v2])
.filter(l => l !== line && !l.used && l.faces.length === 1);
let adjacent = line.adjacentUnused();
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;
}
if (adjacent.length > 2) {
console.log('error adjacent', line, adjacent, loops.length, loop.length);
line.error = adjacent;
// break;
}
if (adjacent.length === 1) {
} else if (adjacent.length === 1) {
if (line.v2 !== adjacent[0].v1) {
let tmp = adjacent[0].v1;
adjacent[0].v1 = adjacent[0].v2;
@ -194,41 +235,56 @@
// console.log('chirality mismatch fixed');
}
line = adjacent[0];
} else {
} else if (adjacent.length === 2) {
// follow edges according to chirality
line = adjacent[0].v1 === line.v2 ?
adjacent[0] :
adjacent[1]
} else {
// console.log('error adjacent', line, adjacent, loops.length, loop.length);
line.split = adjacent;
line = adjacent[0];
}
loop.push(line);
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);
}
// 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
function emitLoop1(loop) {

View file

@ -307,14 +307,14 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
};
PRO.heal = function(debug) {
let mesh = this.debugMesh();
let mesh = this.debugMesh(undefined);
mesh.heal();
if (debug) {
let verts = mesh.vertices;
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();
layrz.setLayer("edges", {line: 0xff0000});
layrz.setLayer("edges", {line: 0});
for (let line of edges) {
layrz.addLine(
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++) {
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]) {
layrz.addLine(
BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2] - 0.03),
BASE.newPoint(verts[line.v2], verts[line.v2+1], verts[line.v2+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] - zo)
);
}
}
layrz.setLayer("error", {line: 0x0000ff});
for (let line of error) {
layrz.setLayer("split", {line: 0xff00ff});
for (let line of split) {
layrz.addLine(
BASE.newPoint(verts[line.v1], verts[line.v1+1], verts[line.v1+2] - 0.06),
BASE.newPoint(verts[line.v2], verts[line.v2+1], verts[line.v2+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.6)
);
}
let stack = new KIRI.Stack(this.mesh);
stack.addLayers(layrz);
return { layrz, stack };
return { mesh, layrz, stack };
}
if (mesh.newFaces) {
this.loadVertices(mesh.unrolled().toFloat32());