function geoEllipse(p0, p1, radius) {
const precision = 6;
const i = d3.geoInterpolate(p0, p1),
alpha = i.distance / 2,
theta = radius * radians,
A = tan(alpha),
A2 = A * A,
D = tan(theta),
D2 = D * D,
R = 1 / sqrt(1 + D2),
Z = R * D,
Y = R * sqrt(D2 - A2);
if (alpha > pi / 2 || theta < alpha) return null;
if (theta >= pi - alpha) return { type: "Sphere" };
let ring = [];
for (let i = 0; i < 360; i += precision) {
const t = i * radians,
c = cos(t),
s = sin(t);
const y = s * Z,
z = c * Y,
x = sqrt(1 - y * y - z * z) * Math.sign(D);
ring.push(spherical([x, y, z]).map(d => d * degrees));
}
ring.push(ring[0]);
if (D < 0) ring.reverse();
const o = i(0.5),
a = d3.geoRotation([-o[0], -o[1]])(p0),
b = i.distance / 2,
y = -asin(sin(a[1] * radians) / sin(b)),
r = [-o[0], -o[1], -(a[0] > 0 ? pi - y : y) * degrees];
return {
type: "Polygon",
coordinates: [ring.map(d3.geoRotation(r).invert)]
};
}