Doodle3D-Core/workers/trace.worker.js

84 lines
2.0 KiB
JavaScript

import 'babel-polyfill';
import * as POTRACE from '@doodle3d/potrace-js';
import { POTRACE_OPTIONS } from '../src/constants/d2Constants.js';
self.addEventListener('message', (event) => {
switch (event.data.msg) {
case 'FLOOD_FILL':
const { imageData, start, tolerance } = event.data;
self.postMessage({
msg: 'FLOOD_FILL',
status: 'OK',
traceData: floodFill(imageData, start, tolerance)
});
break;
case 'TRACE':
const { fill, width, height } = event.data;
const bitmap = new POTRACE.Bitmap(width, height);
for (let i = 0; i < fill.length; i ++) {
const index = fill[i];
bitmap.data[index] = 1;
}
self.postMessage({
msg: 'TRACE',
status: 'OK',
paths: POTRACE.getPaths(POTRACE.traceBitmap(bitmap, POTRACE_OPTIONS))
});
break;
default:
break;
}
});
function floodFill(imageData, start, tolerance) {
const { width, height } = imageData;
const compairIndex = start.y * width + start.x;
const stack = [compairIndex];
const done = { [compairIndex]: true };
const edge = [];
const fill = [];
while (stack.length > 0) {
const index = stack.pop();
const value = imageData.data[index];
const pass = value < tolerance;
if (!pass) {
edge.push(index);
continue;
}
fill.push(index);
const left = index % width !== 0;
const right = index % width !== width - 1;
const top = Math.floor(index / width) !== 0;
const bottom = Math.floor(index / width) !== height - 1;
const neighbours = [];
if (left) neighbours.push(index - 1);
if (right) neighbours.push(index + 1);
if (top) neighbours.push(index - width);
if (bottom) neighbours.push(index + width);
if (neighbours.length !== 4) edge.push(index);
for (let i = 0; i < neighbours.length; i ++) {
const neighbourIndex = neighbours[i];
if (!done[neighbourIndex]) stack.push(neighbourIndex);
done[neighbourIndex] = true;
}
}
return { edge, fill };
}