2020-06-03 22:39:30 -04:00
|
|
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
2020-05-04 12:10:16 -04:00
|
|
|
|
2020-06-03 22:39:30 -04:00
|
|
|
"use strict";
|
2020-05-04 12:10:16 -04:00
|
|
|
|
|
|
|
|
// only active in workers
|
2020-06-03 22:39:30 -04:00
|
|
|
if (!self.window) (function() {
|
2020-05-04 12:10:16 -04:00
|
|
|
|
|
|
|
|
if (!self.geo) self.geo = {};
|
|
|
|
|
|
|
|
|
|
const factor = self.base.config.clipper;
|
|
|
|
|
const geo = self.geo;
|
2021-06-22 21:33:46 -04:00
|
|
|
const debug = false;
|
2020-05-04 12:10:16 -04:00
|
|
|
|
2021-06-21 23:26:54 -04:00
|
|
|
geo.poly = {
|
2021-06-22 17:16:01 -04:00
|
|
|
diff: polyDiff,
|
2021-06-21 23:26:54 -04:00
|
|
|
union: polyUnion,
|
|
|
|
|
offset: polyOffset
|
|
|
|
|
};
|
2020-05-04 12:10:16 -04:00
|
|
|
|
|
|
|
|
function log() {
|
|
|
|
|
console.log(...arguments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function writePoly(view, poly, inner) {
|
|
|
|
|
if (inner) {
|
|
|
|
|
poly.setCounterClockwise();
|
|
|
|
|
} else {
|
|
|
|
|
poly.setClockwise();
|
|
|
|
|
}
|
|
|
|
|
let count = 1;
|
|
|
|
|
let points = poly.points;
|
|
|
|
|
let inners = poly.inner;
|
|
|
|
|
view.writeU16(points.length, true);
|
|
|
|
|
for (let i=0, il=points.length; i<il; i++) {
|
|
|
|
|
let point = points[i];
|
|
|
|
|
view.writeI32((point.x * factor)|0, true);
|
|
|
|
|
view.writeI32((point.y * factor)|0, true);
|
|
|
|
|
}
|
|
|
|
|
if (inners) {
|
|
|
|
|
for (let i=0, il=inners.length; i<il; i++) {
|
|
|
|
|
count += writePoly(view, inners[i], true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readPoly(view, z) {
|
|
|
|
|
let points = view.readU16(true);
|
|
|
|
|
if (points === 0) return;
|
|
|
|
|
let poly = self.base.newPolygon();
|
|
|
|
|
while (points-- > 0) {
|
|
|
|
|
poly.add(view.readI32(true)/factor, view.readI32(true)/factor, z || 0);
|
|
|
|
|
}
|
|
|
|
|
return poly;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function polyOffset(polys, offset, z) {
|
|
|
|
|
let wasm = geo.wasm,
|
|
|
|
|
memat = wasm.malloc(1024 * 128),
|
|
|
|
|
writer = new DataWriter(wasm.heap, memat),
|
|
|
|
|
pcount = 0;
|
|
|
|
|
polys.forEach(poly => pcount += writePoly(writer, poly));
|
|
|
|
|
let resat = wasm.offset(memat, pcount, offset * factor),
|
|
|
|
|
reader = new DataReader(wasm.heap, resat),
|
|
|
|
|
out = [];
|
|
|
|
|
for (;;) {
|
|
|
|
|
let poly = readPoly(reader, z);
|
|
|
|
|
if (poly) {
|
|
|
|
|
out.push(poly);
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-22 22:04:26 -04:00
|
|
|
if (debug) {
|
|
|
|
|
console.log({offset: polys, resat, memat, len: resat - memat});
|
|
|
|
|
}
|
2020-05-04 12:10:16 -04:00
|
|
|
wasm.free(memat);
|
2020-05-04 20:08:22 -04:00
|
|
|
return polyNest(out);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-21 23:26:54 -04:00
|
|
|
function polyUnion(polys, z) {
|
|
|
|
|
let wasm = geo.wasm,
|
|
|
|
|
memat = wasm.malloc(1024 * 128),
|
|
|
|
|
writer = new DataWriter(wasm.heap, memat),
|
|
|
|
|
pcount = 0;
|
|
|
|
|
polys.forEach(poly => pcount += writePoly(writer, poly));
|
|
|
|
|
let resat = wasm.union(memat, pcount, pcount * factor),
|
|
|
|
|
reader = new DataReader(wasm.heap, resat),
|
|
|
|
|
out = [];
|
|
|
|
|
for (;;) {
|
|
|
|
|
let poly = readPoly(reader, z);
|
|
|
|
|
if (poly) {
|
|
|
|
|
out.push(poly);
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
wasm.free(memat);
|
|
|
|
|
return polyNest(out);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 17:16:01 -04:00
|
|
|
function polyDiff(polysA, polysB, z) {
|
|
|
|
|
let wasm = geo.wasm,
|
|
|
|
|
memat = wasm.malloc(1024 * 128),
|
|
|
|
|
writer = new DataWriter(wasm.heap, memat),
|
|
|
|
|
pcountA = 0,
|
|
|
|
|
pcountB = 0;
|
|
|
|
|
polysA.forEach(poly => pcountA += writePoly(writer, poly));
|
|
|
|
|
polysB.forEach(poly => pcountB += writePoly(writer, poly));
|
|
|
|
|
let resat = wasm.diff(memat, pcountA, pcountB, (pcountA + pcountB) * factor),
|
|
|
|
|
reader = new DataReader(wasm.heap, resat),
|
|
|
|
|
out = [];
|
|
|
|
|
for (;;) {
|
|
|
|
|
let poly = readPoly(reader, z);
|
|
|
|
|
if (poly) {
|
|
|
|
|
out.push(poly);
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-22 21:33:46 -04:00
|
|
|
// if (debug) {
|
|
|
|
|
// console.log({diff_resat: resat, memat, delta: resat-memat});
|
|
|
|
|
// }
|
2021-06-22 17:16:01 -04:00
|
|
|
wasm.free(memat);
|
|
|
|
|
return polyNest(out);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 20:08:22 -04:00
|
|
|
// nest closed polygons without existing parent / child relationships
|
|
|
|
|
function polyNest(polys) {
|
|
|
|
|
polys.sort((a,b) => {
|
|
|
|
|
return b.bounds.minx - a.bounds.minx;
|
|
|
|
|
});
|
|
|
|
|
// from smallest to largest, check for enclosing bounds and nest
|
|
|
|
|
for (let i=0, il=polys.length; i<il; i++) {
|
|
|
|
|
let smaller = polys[i];
|
|
|
|
|
// prevent parent poly from being consumed
|
|
|
|
|
if (smaller.inner) continue;
|
|
|
|
|
for (let j=i+1; j<il; j++) {
|
|
|
|
|
let larger = polys[j];
|
|
|
|
|
if (larger.bounds.contains(smaller.bounds)) {
|
|
|
|
|
larger.addInner(smaller);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let tops = [];
|
|
|
|
|
for (let i=0, il=polys.length; i<il; i++) {
|
|
|
|
|
let poly = polys[i];
|
|
|
|
|
if (!poly.parent) {
|
|
|
|
|
tops.push(poly);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return tops;
|
2020-05-04 12:10:16 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-22 21:33:46 -04:00
|
|
|
function runTests() {
|
|
|
|
|
let newPolygon = self.base.newPolygon;
|
|
|
|
|
let p1 = newPolygon().add(0,0).add(4,0).add(4,4).add(0,4);
|
|
|
|
|
let p2 = p1.clone().setZ(0).move({x:2, y:2});
|
|
|
|
|
let d1 = geo.poly.diff([p1], [p2], 0);
|
|
|
|
|
let d2 = geo.poly.diff([p2], [p1], 0);
|
|
|
|
|
console.log('diff',{p1:p1.points, p2:p2.points, d1:d1[0].points, d2:d2[0].points});
|
|
|
|
|
let o1 = geo.poly.offset([p1], 1, 0);
|
|
|
|
|
console.log('offs',{o1:o1[0].points});
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 12:10:16 -04:00
|
|
|
fetch('/wasm/kiri-geo.wasm')
|
|
|
|
|
.then(response => response.arrayBuffer())
|
|
|
|
|
.then(bytes => WebAssembly.instantiate(bytes, {
|
|
|
|
|
env: {
|
|
|
|
|
polygon: (a,b) => { console.log('polygon',a,b) },
|
|
|
|
|
point: (a,b) => { console.log('point',a,b) },
|
2021-06-22 21:33:46 -04:00
|
|
|
abc: (a,b,c) => { console.log('abc',a,b,c) }
|
2020-05-04 12:10:16 -04:00
|
|
|
},
|
|
|
|
|
wasi_snapshot_preview1: {
|
|
|
|
|
args_get: (count,bufsize) => { return 0 },
|
|
|
|
|
args_sizes_get: (count,bufsize) => { },
|
|
|
|
|
environ_get: (count,bufsize) => { return 0 },
|
|
|
|
|
environ_sizes_get: (count,bufsize) => { },
|
|
|
|
|
proc_exit: (code) => { return code }
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
.then(results => {
|
|
|
|
|
let {module, instance} = results;
|
|
|
|
|
let {exports} = instance;
|
|
|
|
|
let heap = new DataView(exports.memory.buffer);
|
|
|
|
|
let wasm = geo.wasm = {
|
|
|
|
|
heap,
|
2021-06-21 23:26:54 -04:00
|
|
|
exports,
|
2020-05-04 12:10:16 -04:00
|
|
|
memory: exports.memory,
|
2021-06-22 21:33:46 -04:00
|
|
|
memmax: exports.memory.buffer.byteLength,
|
2020-05-04 12:10:16 -04:00
|
|
|
malloc: exports.mem_get,
|
2021-06-21 23:26:54 -04:00
|
|
|
free: exports.mem_clr,
|
2021-06-22 17:16:01 -04:00
|
|
|
diff: exports.poly_diff,
|
2021-06-21 23:26:54 -04:00
|
|
|
union: exports.poly_union,
|
2021-06-22 22:04:26 -04:00
|
|
|
offset: exports.poly_offset,
|
|
|
|
|
set_debug: exports.set_debug
|
2020-05-04 12:10:16 -04:00
|
|
|
};
|
2021-06-22 21:33:46 -04:00
|
|
|
if (debug) {
|
2021-06-22 22:04:26 -04:00
|
|
|
wasm.set_debug(1);
|
2021-06-22 21:33:46 -04:00
|
|
|
runTests();
|
|
|
|
|
}
|
2020-05-04 12:10:16 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
})();
|