grid-apps-cmms/src/geo/wasm.js

191 lines
6 KiB
JavaScript
Raw Normal View History

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
function log() {
console.log(...arguments);
}
function writePolys(view, polys) {
let pcount = 0;
for (let poly of polys) {
pcount += writePoly(view, poly);
}
return pcount;
}
2020-05-04 12:10:16 -04:00
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 readPolys(view, z, out = []) {
2020-05-04 12:10:16 -04:00
for (;;) {
let poly = readPoly(view, z);
2020-05-04 12:10:16 -04:00
if (poly) {
out.push(poly);
} else {
break;
}
}
return out;
}
function polyOffset(polys, offset, z) {
let wasm = geo.wasm,
2021-06-23 11:13:45 -04:00
buffer = geo.wasm.shared,
pcount = writePolys(new DataWriter(wasm.heap, buffer), polys),
resat = wasm.fn.offset(buffer, pcount, offset * factor),
out = readPolys(new DataReader(wasm.heap, resat), z);
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,
2021-06-23 11:13:45 -04:00
buffer = geo.wasm.shared,
pcount = writePolys(new DataWriter(wasm.heap, buffer), polys),
resat = wasm.fn.union(buffer, pcount),
out = readPolys(new DataReader(wasm.heap, resat), z);
2021-06-21 23:26:54 -04:00
return polyNest(out);
}
2021-06-23 11:13:45 -04:00
function polyDiff(polysA, polysB, z, AB, BA) {
2021-06-22 17:16:01 -04:00
let wasm = geo.wasm,
2021-06-23 11:13:45 -04:00
buffer = geo.wasm.shared,
writer = new DataWriter(wasm.heap, buffer),
pcountA = writePolys(writer, polysA),
pcountB = writePolys(writer, polysB),
2021-06-23 11:13:45 -04:00
resat = wasm.fn.diff(buffer, pcountA, pcountB, AB?1:0, BA?1:0, base.config.clipperClean),
reader = new DataReader(wasm.heap, resat);
if (AB) {
AB.appendAll(polyNest(readPolys(reader, z)));
}
if (BA) {
BA.appendAll(polyNest(readPolys(reader, z)));
}
2021-06-22 17:16:01 -04:00
}
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});
2021-06-23 11:13:45 -04:00
let d1 = [];
let d2 = [];
geo.wasm.js.diff([p1], [p2], 0, d1, d2);
2021-06-22 21:33:46 -04:00
console.log('diff',{p1:p1.points, p2:p2.points, d1:d1[0].points, d2:d2[0].points});
2021-06-23 11:13:45 -04:00
let o1 = geo.wasm.js.offset([p1], 1, 0);
2021-06-22 21:33:46 -04:00
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 => {
2021-06-23 11:13:45 -04:00
let { module, instance } = results;
let { exports } = instance;
2020-05-04 12:10:16 -04:00
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-23 11:13:45 -04:00
set_debug: exports.set_debug
};
wasm.shared = wasm.malloc(1024 * 1024 * 10),
wasm.fn = {
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-23 11:13:45 -04:00
offset: exports.poly_offset
};
wasm.js = {
diff: polyDiff,
union: polyUnion,
offset: polyOffset
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
});
})();