Public
Edited
May 16, 2023
Importers
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// See https://math.stackexchange.com/a/1361717/659913
function quadBezier(a, b, c, precision = 0.1){
return recursiveSubdivision(interpolateQuadBezier(a, b, c), precision);
}
Insert cell
class Node {
constructor(value, point, next = null) {
this.value = value; // t value
this.point = point; // corresponding interpolator(t)
this.next = next;
}
}
Insert cell
// Recursive subdivision using perpendicular distance threshold
function recursiveSubdivision(interpolator, precision, maxIters = 1e3){
let start = new Node(0, interpolator(0));
let mid = new Node(0.5, interpolator(0.5));
let end = new Node(1, interpolator(1));
start.next = mid;
mid.next = end;

let iters = 0;
while (iters < maxIters) {
let any = false;
let current = start;
while (current && current.next) {
const t = 0.5 * (current.value + current.next.value);
const p = interpolator(t);
if (length([ p, midpoint([current.point, current.next.point]) ]) > precision) {
// Insert the new point
any = true;
let newPoint = new Node(t, p, current.next);
current.next = newPoint;
current = newPoint.next; // Skip the next pair since we've already checked it
} else {
current = current.next; // Move to the next pair
}
}

// If there are no more lengths exceeding the threshold, end the algorithm
if (!any) {
break;
} else {
iters++;
}
}

// Collect the points into an array
let points = [];
let current = start;
while (current) {
points.push(current.point);
current = current.next;
}
return points;
}
Insert cell
// See https://math.stackexchange.com/questions/26846/is-there-an-explicit-form-for-cubic-b%C3%A9zier-curves
function interpolateQuadBezier(a, b, c){
const interpolate = (i, t) => pow((1 - t), 2) * a[i] + 2 * t * (1 - t) * b[i] + pow(t, 2) * c[i];
return t => [interpolate(0, t), interpolate(1, t)]
}
Insert cell
function length(line) {
const [[x0, y0], [x1, y1]] = line;
return sqrt(pow(x1 - x0, 2) + pow(y1 - y0, 2));
}
Insert cell
function midpoint(line) {
const [[x0, y0], [x1, y1]] = line;
return [0.5 * (x0 + x1), 0.5 * (y0 + y1)];
}
Insert cell
pow = Math.pow
Insert cell
sqrt = Math.sqrt
Insert cell
color = d3.interpolateTurbo;
Insert cell
r = 8
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