function brushField(field, stroke, weight) {
let cells = new Map();
let visited = new Set();
let n = stroke.length;
const modify = () => {
for (let [key, { seed, angle }] of cells) {
let [ix, iy] = key.split(",").map((x) => +x);
let d =
Math.sqrt((seed[0] - ix) ** 2 + (seed[1] - iy) ** 2) * field.cellSize;
let alpha = weight(d);
let newAngle = angleLerp(field.getCell(ix, iy), angle, alpha);
field.setCell(ix, iy, newAngle);
visited.add([ix, iy].toString());
}
};
const propagate = () => {
let { nx, ny } = field;
let newCells = new Map();
let dist = new Map();
for (let [key, { seed, angle }] of cells) {
let [ix, iy] = key.split(",").map((x) => +x);
for (let [dx, dy] of [
[-1, -1],
[-1, 0],
[-1, 1],
[1, -1],
[1, 0],
[1, 1],
[0, -1],
[0, 1]
]) {
let [jx, jy] = [ix + dx, iy + dy];
if (jx >= 0 && jx < nx && jy >= 0 && jy < ny) {
let nkey = [jx, jy].toString();
if (visited.has(nkey)) continue;
let d = (seed[0] - jx) ** 2 + (seed[1] - jy) ** 2;
if (dist.has(nkey) && dist.get(nkey) < d) continue;
dist.set(nkey, d);
newCells.set(nkey, { seed, angle });
}
}
}
cells = newCells;
};
if (n < 2) return;
for (let i = 0; i < n; i++) {
let p = stroke[i];
let prev = i > 0 ? stroke[i - 1] : p;
let next = i + 1 < n ? stroke[i + 1] : p;
let v = next.sub(prev).normalize();
let [ix, iy] = field.getCellIndex(p.x, p.y);
let key = [ix, iy].toString();
visited.add(key);
let angle = Math.atan2(v.y, v.x);
cells.set(key, { seed: [ix, iy], angle });
}
for (let i = 0; i < width / field.cellSize && cells.size > 0; i++) {
modify();
propagate();
}
}