add POLY.xor, poly.intersects, and option to xor sliced results instead of union on healing
This commit is contained in:
parent
955cfec263
commit
1d352f8459
3 changed files with 65 additions and 1 deletions
|
|
@ -1219,6 +1219,25 @@ class Polygon {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return true if any line segments on either poly crosses the other
|
||||||
|
// this is a shallow test and does not inspect inners
|
||||||
|
intersects(poly) {
|
||||||
|
let p0 = this.points.slice(); p0.push(p0[0]);
|
||||||
|
let p1 = poly.points.slice(); p1.push(p1[0]);
|
||||||
|
for (let i=1; i<p0.length; i++) {
|
||||||
|
let a = p0[i-1];
|
||||||
|
let b = p0[i];
|
||||||
|
for (let j=1; j<p1.length; j++) {
|
||||||
|
let c = p1[j-1];
|
||||||
|
let d = p1[j];
|
||||||
|
if (util.intersect(a, b, c, d, base.key.SEGINT)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* using two points, split polygon into two open polygons
|
* using two points, split polygon into two open polygons
|
||||||
* or return null if p1,p2 does not intersect or poly is open
|
* or return null if p1,p2 does not intersect or poly is open
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ const ClipperLib = self.ClipperLib,
|
||||||
EndType = ClipperLib.EndType,
|
EndType = ClipperLib.EndType,
|
||||||
JoinType = ClipperLib.JoinType,
|
JoinType = ClipperLib.JoinType,
|
||||||
PolyTree = ClipperLib.PolyTree,
|
PolyTree = ClipperLib.PolyTree,
|
||||||
|
ClipXOR = ClipType.ctXor,
|
||||||
ClipDiff = ClipType.ctDifference,
|
ClipDiff = ClipType.ctDifference,
|
||||||
ClipUnion = ClipType.ctUnion,
|
ClipUnion = ClipType.ctUnion,
|
||||||
ClipIntersect = ClipType.ctIntersection,
|
ClipIntersect = ClipType.ctIntersection,
|
||||||
|
|
@ -58,6 +59,7 @@ const POLYS = base.polygons = {
|
||||||
inner,
|
inner,
|
||||||
nest,
|
nest,
|
||||||
diff,
|
diff,
|
||||||
|
xor,
|
||||||
setZ,
|
setZ,
|
||||||
filter,
|
filter,
|
||||||
toClipper,
|
toClipper,
|
||||||
|
|
@ -486,7 +488,47 @@ function diff(setA, setB, z) {
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Polygon} poly clipping mask
|
||||||
|
* @returns {?Polygon[]}
|
||||||
|
*/
|
||||||
|
function xor(set, z) {
|
||||||
|
z = z || set[0].getZ();
|
||||||
|
outer: for (;;) {
|
||||||
|
// sort largest to smallest area
|
||||||
|
set.sort((a,b) => b.area() - a.area());
|
||||||
|
for (let i=0; i<set.length; i++) {
|
||||||
|
let p0 = set[i];
|
||||||
|
for (let j=i+1; j<set.length; j++) {
|
||||||
|
let p1 = set[j];
|
||||||
|
// if polys overlap, xor and check result
|
||||||
|
// if output differs from input, update set
|
||||||
|
// and start from scratch
|
||||||
|
if (p1.overlaps(p0) && p1.intersects(p0)) {
|
||||||
|
let xor = p0.xor(p1);
|
||||||
|
if (xor.length === 2) {
|
||||||
|
let same0 = Math.abs(p0.area() - xor[0].area()) + Math.abs(p1.area() - xor[1].area()) < 0.01;
|
||||||
|
let same1 = Math.abs(p1.area() - xor[0].area()) + Math.abs(p0.area() - xor[1].area()) < 0.01;
|
||||||
|
if (same0 || same1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log({ p0, p1, xor, i, j });
|
||||||
|
set[i] = null;
|
||||||
|
set[j] = null;
|
||||||
|
set = set.filter(o => o);
|
||||||
|
set.appendAll(xor);
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// exit when no change to set occur
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slice.doProjectedFills()
|
* Slice.doProjectedFills()
|
||||||
|
|
|
||||||
|
|
@ -387,6 +387,9 @@ async function sliceZ(z, points, options = {}) {
|
||||||
let rval = { z, lines };
|
let rval = { z, lines };
|
||||||
if (groupFn) {
|
if (groupFn) {
|
||||||
let groups = groupFn(lines, z, options);
|
let groups = groupFn(lines, z, options);
|
||||||
|
if (options.xor) {
|
||||||
|
groups = POLY.xor(groups);
|
||||||
|
}
|
||||||
if (options.union) {
|
if (options.union) {
|
||||||
let points = groups.map(p => p.length).reduce((a,b) => a + b);
|
let points = groups.map(p => p.length).reduce((a,b) => a + b);
|
||||||
// simplistic healing of non-manifold meshes
|
// simplistic healing of non-manifold meshes
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue