Published
Edited
Dec 14, 2021
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
points = [
[5, 100],
[5, 5],
[45, 5],
[a, 100 - a],
[100, 55],
[100, 100]
]
Insert cell
function getWeights(points, [x, y]) {
// 1. center on [x, y]
const n = points.length;
const s = points.map(([xi, yi]) => [xi - x, yi - y]);

// 2. compute the cross product of each triangle [0, s[i], s[i+1]] (A2, double area)
// and their dot product (D)
const A2 = new Float32Array(n);
const D = new Float32Array(n);

for (let i = 0; i < n; i++) {
const i1 = (i + 1) % n;
const p = s[i];
const q = s[i1];
A2[i] = p[0] * q[1] - p[1] * q[0];
D[i] = p[0] * q[0] + p[1] * q[1];
}

// 3. compute the weight of each vertex
const weights = new Float32Array(n);

for (let i = 0; i < n; i++) {
const i_ = (i - 1 + n) % n;
const i1 = (i + 1) % n;
const p = s[i];
const q = s[i1];
const q_ = s[i_];

const r = Math.hypot(...p);

// Is s[i] the point?
if (r < 1e-6) {
weights[i] = INF;
continue;
}

// s[i] and s[i+1] collinear?
const r1 = Math.hypot(...q);
const coll = Math.abs(A2[i]) === 0;
if (coll && D[i] < 0) {
weights[i] = INF * (r1 / (r + r1));
continue;
}

const r_1 = Math.hypot(...s[i_]);
// s[i] and s[i-1] collinear?
const coll_ = Math.abs(A2[i_]) === 0;
if (coll_ && D[i_] < 0) {
weights[i] = INF * (r_1 / (r + r_1));
continue;
}

// normal case: difference of the half-tangents
weights[i] =
(coll ? 0 : (r1 - D[i] / r) / A2[i]) +
(coll_ ? 0 : (r_1 - D[i_] / r) / A2[i_]);
}

// 3. normalize
const S = d3.sum(weights);
for (let i = 0; i < n; i++) weights[i] /= S;

return weights;
}
Insert cell
INF = 1e36
Insert cell
check = (p) => {
const w = getWeights(points, p);
return [
d3.sum(points, (p, k) => p[0] * w[k]),
d3.sum(points, (p, k) => p[1] * w[k])
];
}
Insert cell
A = {
const p = 210;
const A = d3
.range(points.length)
.map((i) => Float32Array.from({ length: p * p }).fill(NaN));

for (let i = 0; i < p; i++) {
for (let j = 0; j < p; j++) {
const x = i / 2;
const y = j / 2;
const W = getWeights(points, [x, y]);
for (let k = 0; k < points.length; k++)
A[k][i + p * j] = W.contains ? Math.abs(W[k]) : W[k];
}
}
return A;
}
Insert cell
import { heatmap } from "@fil/heatmap"
Insert cell
import { acos, tan } from "@fil/math"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more