UNPKG

3.27 kBJavaScriptView Raw
1import { geoProjection as projection, geoStream } from "d3-geo";
2import { scan } from "d3-array";
3import { asin, degrees, epsilon, sqrt } from "./math.js";
4import { lagrangeRaw } from "./lagrange.js";
5import { complexAdd, complexMul, complexNorm2, complexPow } from "./complex.js";
6
7// w1 = gamma(1/n) * gamma(1 - 2/n) / n / gamma(1 - 1/n)
8// https://bl.ocks.org/Fil/852557838117687bbd985e4b38ff77d4
9var w = [-1 / 2, sqrt(3) / 2],
10 w1 = [1.7666387502854533, 0],
11 m = 0.3 * 0.3;
12
13// Approximate \int _0 ^sm(z) dt / (1 - t^3)^(2/3)
14// sm maps a triangle to a disc, sm^-1 does the opposite
15function sm_1(z) {
16 var k = [0, 0];
17
18 // rotate to have s ~= 1
19 var rot = complexPow(
20 w,
21 scan(
22 [0, 1, 2].map(function(i) {
23 return -complexMul(z, complexPow(w, [i, 0]))[0];
24 })
25 )
26 );
27
28 var y = complexMul(rot, z);
29 y = [1 - y[0], -y[1]];
30
31 // McIlroy formula 5 p6 and table for F3 page 16
32 var F0 = [
33 1.44224957030741,
34 0.240374928384568,
35 0.0686785509670194,
36 0.0178055502507087,
37 0.00228276285265497,
38 -1.48379585422573e-3,
39 -1.64287728109203e-3,
40 -1.02583417082273e-3,
41 -4.83607537673571e-4,
42 -1.67030822094781e-4,
43 -2.45024395166263e-5,
44 2.14092375450951e-5,
45 2.55897270486771e-5,
46 1.73086854400834e-5,
47 8.72756299984649e-6,
48 3.18304486798473e-6,
49 4.79323894565283e-7,
50 -4.58968389565456e-7,
51 -5.62970586787826e-7,
52 -3.92135372833465e-7
53 ];
54
55 var F = [0, 0];
56 for (var i = F0.length; i--; ) F = complexAdd([F0[i], 0], complexMul(F, y));
57
58 k = complexMul(
59 complexAdd(w1, complexMul([-F[0], -F[1]], complexPow(y, 1 - 2 / 3))),
60 complexMul(rot, rot)
61 );
62
63 // when we are close to [0,0] we switch to another approximation:
64 // https://www.wolframalpha.com/input/?i=(-2%2F3+choose+k)++*+(-1)%5Ek++%2F+(k%2B1)+with+k%3D0,1,2,3,4
65 // the difference is _very_ tiny but necessary
66 // if we want projection(0,0) === [0,0]
67 var n = complexNorm2(z);
68 if (n < m) {
69 var H0 = [
70 1,
71 1 / 3,
72 5 / 27,
73 10 / 81,
74 22 / 243 //…
75 ];
76 var z3 = complexPow(z, [3, 0]);
77 var h = [0, 0];
78 for (i = H0.length; i--; ) h = complexAdd([H0[i], 0], complexMul(h, z3));
79 h = complexMul(h, z);
80 k = complexAdd(complexMul(k, [n / m, 0]), complexMul(h, [1 - n / m, 0]));
81 }
82
83 return k;
84}
85
86var lagrange1_2 = lagrangeRaw ? lagrangeRaw(0.5) : null;
87export function coxRaw(lambda, phi) {
88 var s = lagrange1_2(lambda, phi);
89 var t = sm_1([s[1] / 2, s[0] / 2]);
90 return [t[1], t[0]];
91}
92
93// the Sphere should go *exactly* to the vertices of the triangles
94// because they are singular points
95function sphere() {
96 var c = 2 * asin(1 / sqrt(5)) * degrees;
97 return {
98 type: "Polygon",
99 coordinates: [
100 [[0, 90], [-180, -c + epsilon], [0, -90], [180, -c + epsilon], [0, 90]]
101 ]
102 };
103}
104
105export default function() {
106 var p = projection(coxRaw);
107
108 var stream_ = p.stream;
109 p.stream = function(stream) {
110 var rotate = p.rotate(),
111 rotateStream = stream_(stream),
112 sphereStream = (p.rotate([0, 0]), stream_(stream));
113 p.rotate(rotate);
114 rotateStream.sphere = function() {
115 geoStream(sphere(), sphereStream);
116 };
117 return rotateStream;
118 };
119
120 return p
121 .scale(188.305)
122 .translate([480, 333.167]);
123}