discMultipleTransport = {
let indices = [],
temp = [],
projection,
deltas;
return (
points,
radius,
{ dirs = 3, strength = 1, profile = chordAreaInverse, classes = 1 } = {}
) => {
const n = points.length / 2;
const r = new Array(classes);
if (n !== indices.length) {
indices = Uint32Array.from(d3.range(n));
temp = Uint32Array.from(d3.range(n));
projection = new Float32Array(n);
deltas = new Float32Array(2 * n);
}
const a = 2 * Math.PI * Math.random();
deltas.fill(0);
for (let d = 0; d < dirs; d++) {
const ap = a + ((Math.PI / 2) * d) / dirs,
sa = Math.sin(ap),
ca = Math.cos(ap);
for (const i of indices)
projection[i] = ca * points[2 * i] + sa * points[2 * i + 1];
temp.sort((i, j) => projection[i] - projection[j]);
const order = d3.sort(
d3.range(classes),
(i) =>
Math.cos((2 * i * Math.PI) / classes) * ca +
Math.sin((2 * i * Math.PI) / classes) * sa
);
r.fill(0);
for (let j = 0; j < n + classes - 1; ++j) {
const c = order[temp[j] % classes];
const k = c + classes * r[c]++;
indices[k] = temp[j];
}
for (let k = 0; k < n; k++) {
const i = indices[k],
ideal = radius * profile(k / (n + 1)),
delta = ideal - projection[i];
deltas[2 * i] += ca * delta;
deltas[2 * i + 1] += sa * delta;
}
}
for (let i = 0; i < points.length; i++)
points[i] += (deltas[i] / dirs) * strength;
};
}