1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | import { atan, degrees } from "./math.js";
|
9 | import polyhedral from "./polyhedral/index.js";
|
10 | import { default as grayFullerRaw } from "./grayfuller.js";
|
11 | import {
|
12 | geoCentroid as centroid,
|
13 | geoContains as contains,
|
14 | geoGnomonic as gnomonic,
|
15 | geoProjection as projection
|
16 | } from "d3-geo";
|
17 | import { range } from "d3-array";
|
18 |
|
19 | function airoceanRaw(faceProjection) {
|
20 | var theta = atan(0.5) * degrees;
|
21 |
|
22 |
|
23 |
|
24 | var vertices = [[0, 90], [0, -90]].concat(
|
25 | range(10).map(function(i) {
|
26 | var phi = (i * 36 + 180) % 360 - 180;
|
27 | return [phi, i & 1 ? theta : -theta];
|
28 | })
|
29 | );
|
30 |
|
31 |
|
32 | var polyhedron = [
|
33 | [0, 3, 11],
|
34 | [0, 5, 3],
|
35 | [0, 7, 5],
|
36 | [0, 9, 7],
|
37 | [0, 11, 9],
|
38 | [2, 11, 3],
|
39 | [3, 4, 2],
|
40 | [4, 3, 5],
|
41 | [5, 6, 4],
|
42 | [6, 5, 7],
|
43 | [7, 8, 6],
|
44 | [8, 7, 9],
|
45 | [9, 10, 8],
|
46 | [10, 9, 11],
|
47 | [11, 2, 10],
|
48 | [1, 2, 4],
|
49 | [1, 4, 6],
|
50 | [1, 6, 8],
|
51 | [1, 8, 10],
|
52 | [1, 10, 2]
|
53 | ].map(function(face) {
|
54 | return face.map(function(i) {
|
55 | return vertices[i];
|
56 | });
|
57 | });
|
58 |
|
59 |
|
60 | polyhedron.forEach(function(face) {
|
61 | face.centroid = centroid({ type: "MultiPoint", coordinates: face });
|
62 | });
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | (function() {
|
68 | var face, tmp, mid, centroid;
|
69 |
|
70 |
|
71 | face = polyhedron[15];
|
72 | centroid = face.centroid;
|
73 | tmp = face.slice();
|
74 | face[0] = centroid;
|
75 |
|
76 | face = [tmp[0], centroid, tmp[2]];
|
77 | face.centroid = centroid;
|
78 | polyhedron.push(face);
|
79 |
|
80 | face = [tmp[0], tmp[1], centroid];
|
81 | face.centroid = centroid;
|
82 | polyhedron.push(face);
|
83 |
|
84 |
|
85 | face = polyhedron[14];
|
86 | centroid = face.centroid;
|
87 | tmp = face.slice();
|
88 |
|
89 |
|
90 | var proj = gnomonic()
|
91 | .scale(1)
|
92 | .translate([0, 0])
|
93 | .rotate([-centroid[0], -centroid[1]]);
|
94 | var a = proj(face[1]),
|
95 | b = proj(face[2]);
|
96 | mid = proj.invert([(a[0] + b[0]) / 2, (a[1] + b[1]) / 2]);
|
97 | face[1] = mid;
|
98 |
|
99 |
|
100 | face = [tmp[0], tmp[1], mid];
|
101 | face.centroid = centroid;
|
102 | polyhedron.push(face);
|
103 |
|
104 |
|
105 | face = polyhedron[19];
|
106 | centroid = face.centroid;
|
107 | tmp = face.slice();
|
108 | face[1] = mid;
|
109 |
|
110 |
|
111 | face = [mid, tmp[0], tmp[1]];
|
112 | face.centroid = centroid;
|
113 | polyhedron.push(face);
|
114 | })();
|
115 |
|
116 | var airocean = function(faceProjection) {
|
117 | faceProjection =
|
118 | faceProjection ||
|
119 | function(face) {
|
120 |
|
121 | var c = face.centroid;
|
122 | return gnomonic()
|
123 | .scale(1)
|
124 | .translate([0, 0])
|
125 | .rotate([-c[0], -c[1]]);
|
126 | };
|
127 |
|
128 | var faces = polyhedron.map(function(face, i) {
|
129 | var polygon = face.slice();
|
130 | polygon.push(polygon[0]);
|
131 |
|
132 | return {
|
133 | face: face,
|
134 | site: face.centroid,
|
135 | id: i,
|
136 | contains: function(lambda, phi) {
|
137 | return contains({ type: "Polygon", coordinates: [polygon] }, [
|
138 | lambda * degrees,
|
139 | phi * degrees
|
140 | ]);
|
141 | },
|
142 | project: faceProjection(face)
|
143 | };
|
144 | });
|
145 |
|
146 |
|
147 | var parents = [
|
148 |
|
149 | -1,
|
150 | 0,
|
151 | 1,
|
152 | 11,
|
153 | 13,
|
154 |
|
155 |
|
156 | 6,
|
157 | 7,
|
158 | 1,
|
159 | 7,
|
160 | 8,
|
161 |
|
162 | 9,
|
163 | 10,
|
164 | 11,
|
165 | 12,
|
166 | 13,
|
167 |
|
168 |
|
169 | 6,
|
170 | 8,
|
171 | 10,
|
172 | 17,
|
173 | 21,
|
174 | 16,
|
175 | 15,
|
176 | 19,
|
177 | 19
|
178 | ];
|
179 |
|
180 | parents.forEach(function(d, i) {
|
181 | var node = faces[d];
|
182 | node && (node.children || (node.children = [])).push(faces[i]);
|
183 | });
|
184 |
|
185 | function face(lambda, phi) {
|
186 | for (var i = 0; i < faces.length; i++) {
|
187 | if (faces[i].contains(lambda, phi)) return faces[i];
|
188 | }
|
189 | }
|
190 |
|
191 |
|
192 | var proj = polyhedral(
|
193 | faces[0],
|
194 | face
|
195 | );
|
196 |
|
197 | proj.faces = faces;
|
198 | return proj;
|
199 | };
|
200 |
|
201 | return airocean(faceProjection);
|
202 | }
|
203 |
|
204 | export default function () {
|
205 | var p = airoceanRaw(function(face) {
|
206 | var c = face.centroid;
|
207 |
|
208 | face.direction =
|
209 | Math.abs(c[1] - 52.62) < 1 || Math.abs(c[1] + 10.81) < 1 ? 0 : 60;
|
210 | return projection(grayFullerRaw())
|
211 | .scale(1)
|
212 | .translate([0, 0])
|
213 | .rotate([-c[0], -c[1], face.direction || 0]);
|
214 | });
|
215 |
|
216 | return p
|
217 | .rotate([-83.65929, 25.44458, -87.45184])
|
218 | .angle(-60)
|
219 | .scale(45.4631)
|
220 | .center([126, 0]);
|
221 | }
|