-
Notifications
You must be signed in to change notification settings - Fork 201
/
hyperelliptical.js
73 lines (59 loc) · 1.7 KB
/
hyperelliptical.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import {geoProjectionMutator as projectionMutator} from "d3-geo";
import {abs, asin, pi, pow, sign, sin} from "./math.js";
import {integrate} from "./integrate.js";
export function hyperellipticalRaw(alpha, k, gamma) {
function elliptic (f) {
return alpha + (1 - alpha) * pow(1 - pow(f, k), 1 / k);
}
function z(f) {
return integrate(elliptic, 0, f, 1e-4);
}
var G = 1 / z(1),
n = 1000,
m = (1 + 1e-8) * G,
approx = [];
for (var i = 0; i <= n; i++)
approx.push(z(i / n) * m);
function Y(sinphi) {
var rmin = 0, rmax = n, r = n >> 1;
do {
if (approx[r] > sinphi) rmax = r; else rmin = r;
r = (rmin + rmax) >> 1;
} while (r > rmin);
var u = approx[r + 1] - approx[r];
if (u) u = (sinphi - approx[r + 1]) / u;
return (r + 1 + u) / n;
}
var ratio = 2 * Y(1) / pi * G / gamma;
var forward = function(lambda, phi) {
var y = Y(abs(sin(phi))),
x = elliptic(y) * lambda;
y /= ratio;
return [ x, (phi >= 0) ? y : -y ];
};
forward.invert = function(x, y) {
var phi;
y *= ratio;
if (abs(y) < 1) phi = sign(y) * asin(z(abs(y)) * G);
return [ x / elliptic(abs(y)), phi ];
};
return forward;
}
export default function() {
var alpha = 0,
k = 2.5,
gamma = 1.183136, // affine = sqrt(2 * gamma / pi) = 0.8679
m = projectionMutator(hyperellipticalRaw),
p = m(alpha, k, gamma);
p.alpha = function(_) {
return arguments.length ? m(alpha = +_, k, gamma) : alpha;
};
p.k = function(_) {
return arguments.length ? m(alpha, k = +_, gamma) : k;
};
p.gamma = function(_) {
return arguments.length ? m(alpha, k, gamma = +_) : gamma;
};
return p
.scale(152.63);
}