1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | import { abs, cos, degrees, pi, radians, sin, sign, sqrt, tan } from "./math.js";
|
10 | import { cartesianCross, cartesianDegrees, cartesianDot, sphericalDegrees } from "./cartesian.js";
|
11 | import polyhedral from "./polyhedral/index.js";
|
12 | import { geoProjectionMutator as projectionMutator } from "d3-geo";
|
13 | import {solve2d} from "./newton.js";
|
14 |
|
15 | export default function(faceProjection) {
|
16 | faceProjection =
|
17 | faceProjection ||
|
18 | function() {
|
19 | return cahillKeyesProjection().scale(1);
|
20 | };
|
21 |
|
22 | var octahedron = [[0, 90], [-90, 0], [0, 0], [90, 0], [180, 0], [0, -90]];
|
23 |
|
24 | octahedron = [
|
25 | [0, 2, 1],
|
26 | [0, 3, 2],
|
27 | [5, 1, 2],
|
28 | [5, 2, 3],
|
29 | [0, 1, 4],
|
30 | [0, 4, 3],
|
31 | [5, 4, 1],
|
32 | [5, 3, 4]
|
33 | ].map(function(face) {
|
34 | return face.map(function(i) {
|
35 | return octahedron[i];
|
36 | });
|
37 | });
|
38 |
|
39 | var ck = octahedron.map(function(face) {
|
40 | var xyz = face.map(cartesianDegrees),
|
41 | n = xyz.length,
|
42 | a = xyz[n - 1],
|
43 | b,
|
44 | theta = 17 * radians,
|
45 | cosTheta = cos(theta),
|
46 | sinTheta = sin(theta),
|
47 | hexagon = [];
|
48 | for (var i = 0; i < n; ++i) {
|
49 | b = xyz[i];
|
50 | hexagon.push(
|
51 | sphericalDegrees([
|
52 | a[0] * cosTheta + b[0] * sinTheta,
|
53 | a[1] * cosTheta + b[1] * sinTheta,
|
54 | a[2] * cosTheta + b[2] * sinTheta
|
55 | ]),
|
56 | sphericalDegrees([
|
57 | b[0] * cosTheta + a[0] * sinTheta,
|
58 | b[1] * cosTheta + a[1] * sinTheta,
|
59 | b[2] * cosTheta + a[2] * sinTheta
|
60 | ])
|
61 | );
|
62 | a = b;
|
63 | }
|
64 | return hexagon;
|
65 | });
|
66 |
|
67 | var cornerNormals = [];
|
68 |
|
69 | var parents = [-1, 3, 0, 2, 0, 1, 4, 5];
|
70 |
|
71 | ck.forEach(function(hexagon, j) {
|
72 | var face = octahedron[j],
|
73 | n = face.length,
|
74 | normals = (cornerNormals[j] = []);
|
75 | for (var i = 0; i < n; ++i) {
|
76 | ck.push([
|
77 | face[i],
|
78 | hexagon[(i * 2 + 2) % (2 * n)],
|
79 | hexagon[(i * 2 + 1) % (2 * n)]
|
80 | ]);
|
81 | parents.push(j);
|
82 | normals.push(
|
83 | cartesianCross(
|
84 | cartesianDegrees(hexagon[(i * 2 + 2) % (2 * n)]),
|
85 | cartesianDegrees(hexagon[(i * 2 + 1) % (2 * n)])
|
86 | )
|
87 | );
|
88 | }
|
89 | });
|
90 |
|
91 | var faces = ck.map(function(face) {
|
92 | return {
|
93 | project: faceProjection(face),
|
94 | face: face
|
95 | };
|
96 | });
|
97 |
|
98 | parents.forEach(function(d, i) {
|
99 | var parent = faces[d];
|
100 | parent && (parent.children || (parent.children = [])).push(faces[i]);
|
101 | });
|
102 | return polyhedral(faces[0], face, 0, true)
|
103 | .scale(0.023975)
|
104 | .rotate([20, 0])
|
105 | .center([0,-17]);
|
106 |
|
107 | function face(lambda, phi) {
|
108 | var cosPhi = cos(phi),
|
109 | p = [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
|
110 |
|
111 | var hexagon =
|
112 | lambda < -pi / 2
|
113 | ? phi < 0 ? 6 : 4
|
114 | : lambda < 0
|
115 | ? phi < 0 ? 2 : 0
|
116 | : lambda < pi / 2 ? (phi < 0 ? 3 : 1) : phi < 0 ? 7 : 5;
|
117 |
|
118 | var n = cornerNormals[hexagon];
|
119 |
|
120 | return faces[
|
121 | cartesianDot(n[0], p) < 0
|
122 | ? 8 + 3 * hexagon
|
123 | : cartesianDot(n[1], p) < 0
|
124 | ? 8 + 3 * hexagon + 1
|
125 | : cartesianDot(n[2], p) < 0 ? 8 + 3 * hexagon + 2 : hexagon
|
126 | ];
|
127 | }
|
128 | }
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 | export function cahillKeyesRaw(mg) {
|
135 | var CK = {
|
136 | lengthMG: mg
|
137 | };
|
138 |
|
139 | preliminaries();
|
140 |
|
141 | function preliminaries() {
|
142 | var pointN, lengthMB, lengthMN, lengthNG, pointU;
|
143 | var m = 29,
|
144 | p = 15,
|
145 | p73a,
|
146 | lF,
|
147 | lT,
|
148 | lM,
|
149 | l,
|
150 | pointV,
|
151 | k = sqrt(3);
|
152 |
|
153 | CK.lengthMA = 940 / 10000 * CK.lengthMG;
|
154 | CK.lengthParallel0to73At0 = CK.lengthMG / 100;
|
155 | CK.lengthParallel73to90At0 =
|
156 | (CK.lengthMG - CK.lengthMA - CK.lengthParallel0to73At0 * 73) / (90 - 73);
|
157 | CK.sin60 = k / 2;
|
158 | CK.cos60 = 0.5;
|
159 | CK.pointM = [0, 0];
|
160 | CK.pointG = [CK.lengthMG, 0];
|
161 | pointN = [CK.lengthMG, CK.lengthMG * tan(30 * radians)];
|
162 | CK.pointA = [CK.lengthMA, 0];
|
163 | CK.pointB = lineIntersection(CK.pointM, 30, CK.pointA, 45);
|
164 | CK.lengthAG = distance(CK.pointA, CK.pointG);
|
165 | CK.lengthAB = distance(CK.pointA, CK.pointB);
|
166 | lengthMB = distance(CK.pointM, CK.pointB);
|
167 | lengthMN = distance(CK.pointM, pointN);
|
168 | lengthNG = distance(pointN, CK.pointG);
|
169 | CK.pointD = interpolate(lengthMB, lengthMN, pointN, CK.pointM);
|
170 | CK.pointF = [CK.lengthMG, lengthNG - lengthMB];
|
171 | CK.pointE = [
|
172 | pointN[0] - CK.lengthMA * sin(30 * radians),
|
173 | pointN[1] - CK.lengthMA * cos(30 * radians)
|
174 | ];
|
175 | CK.lengthGF = distance(CK.pointG, CK.pointF);
|
176 | CK.lengthBD = distance(CK.pointB, CK.pointD);
|
177 | CK.lengthBDE = CK.lengthBD + CK.lengthAB;
|
178 | CK.lengthGFE = CK.lengthGF + CK.lengthAB;
|
179 | CK.deltaMEq = CK.lengthGFE / 45;
|
180 | CK.lengthAP75 = (90 - 75) * CK.lengthParallel73to90At0;
|
181 | CK.lengthAP73 = CK.lengthMG - CK.lengthMA - CK.lengthParallel0to73At0 * 73;
|
182 | pointU = [
|
183 | CK.pointA[0] + CK.lengthAP73 * cos(30 * radians),
|
184 | CK.pointA[1] + CK.lengthAP73 * sin(30 * radians)
|
185 | ];
|
186 | CK.pointT = lineIntersection(pointU, -60, CK.pointB, 30);
|
187 |
|
188 | p73a = parallel73(m);
|
189 | lF = p73a.lengthParallel73;
|
190 | lT = lengthTorridSegment(m);
|
191 | lM = lengthMiddleSegment(m);
|
192 | l = p * (lT + lM + lF) / 73;
|
193 | pointV = [0, 0];
|
194 | CK.pointC = [0, 0];
|
195 | CK.radius = 0;
|
196 |
|
197 | l = l - lT;
|
198 | pointV = interpolate(l, lM, jointT(m), jointF(m));
|
199 | CK.pointC[1] =
|
200 | (pointV[0] * pointV[0] +
|
201 | pointV[1] * pointV[1] -
|
202 | CK.pointD[0] * CK.pointD[0] -
|
203 | CK.pointD[1] * CK.pointD[1]) /
|
204 | (2 * (k * pointV[0] + pointV[1] - k * CK.pointD[0] - CK.pointD[1]));
|
205 | CK.pointC[0] = k * CK.pointC[1];
|
206 | CK.radius = distance(CK.pointC, CK.pointD);
|
207 |
|
208 | return CK;
|
209 | }
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 | function distance(p1, p2) {
|
216 | var deltaX = p1[0] - p2[0],
|
217 | deltaY = p1[1] - p2[1];
|
218 | return sqrt(deltaX * deltaX + deltaY * deltaY);
|
219 | }
|
220 |
|
221 |
|
222 |
|
223 |
|
224 | function interpolate(length, totalLength, start, end) {
|
225 | var xy = [
|
226 | start[0] + (end[0] - start[0]) * length / totalLength,
|
227 | start[1] + (end[1] - start[1]) * length / totalLength
|
228 | ];
|
229 | return xy;
|
230 | }
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | function lineIntersection(point1, slope1, point2, slope2) {
|
236 |
|
237 | var m1 = tan(slope1 * radians),
|
238 | m2 = tan(slope2 * radians),
|
239 | p = [0, 0];
|
240 | p[0] =
|
241 | (m1 * point1[0] - m2 * point2[0] - point1[1] + point2[1]) / (m1 - m2);
|
242 | p[1] = m1 * (p[0] - point1[0]) + point1[1];
|
243 | return p;
|
244 | }
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 | function circleLineIntersection(cc, r, p1, p2) {
|
254 | var x1 = p1[0],
|
255 | y1 = p1[1],
|
256 | x2 = p2[0],
|
257 | y2 = p2[1],
|
258 | xc = cc[0],
|
259 | yc = cc[1],
|
260 | a = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1),
|
261 | b = 2 * ((x2 - x1) * (x1 - xc) + (y2 - y1) * (y1 - yc)),
|
262 | c =
|
263 | xc * xc + yc * yc + x1 * x1 + y1 * y1 - 2 * (xc * x1 + yc * y1) - r * r,
|
264 | d = b * b - 4 * a * c,
|
265 | u1 = 0,
|
266 | u2 = 0,
|
267 | x = 0,
|
268 | y = 0;
|
269 | if (a === 0) {
|
270 | return [0, [0, 0]];
|
271 | } else if (d < 0) {
|
272 | return [0, [0, 0]];
|
273 | }
|
274 | u1 = (-b + sqrt(d)) / (2 * a);
|
275 | u2 = (-b - sqrt(d)) / (2 * a);
|
276 | if (0 <= u1 && u1 <= 1) {
|
277 | x = x1 + u1 * (x2 - x1);
|
278 | y = y1 + u1 * (y2 - y1);
|
279 | return [1, [x, y]];
|
280 | } else if (0 <= u2 && u2 <= 1) {
|
281 | x = x1 + u2 * (x2 - x1);
|
282 | y = y1 + u2 * (y2 - y1);
|
283 | return [1, [x, y]];
|
284 | } else {
|
285 | return [0, [0, 0]];
|
286 | }
|
287 | }
|
288 |
|
289 |
|
290 |
|
291 |
|
292 | function rotate(xy, angle) {
|
293 | var xynew = [0, 0];
|
294 |
|
295 | if (angle === -60) {
|
296 | xynew[0] = xy[0] * CK.cos60 + xy[1] * CK.sin60;
|
297 | xynew[1] = -xy[0] * CK.sin60 + xy[1] * CK.cos60;
|
298 | } else if (angle === -120) {
|
299 | xynew[0] = -xy[0] * CK.cos60 + xy[1] * CK.sin60;
|
300 | xynew[1] = -xy[0] * CK.sin60 - xy[1] * CK.cos60;
|
301 | } else {
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 | xynew[0] = xy[0] * cos(angle * radians) - xy[1] * sin(angle * radians);
|
308 | xynew[1] = xy[0] * sin(angle * radians) + xy[1] * cos(angle * radians);
|
309 | }
|
310 |
|
311 | return xynew;
|
312 | }
|
313 |
|
314 |
|
315 | function truncate(n) {
|
316 | return Math[n > 0 ? "floor" : "ceil"](n);
|
317 | }
|
318 |
|
319 | function equator(m) {
|
320 | var l = CK.deltaMEq * m,
|
321 | jointE = [0, 0];
|
322 | if (l <= CK.lengthGF) {
|
323 | jointE = [CK.pointG[0], l];
|
324 | } else {
|
325 | l = l - CK.lengthGF;
|
326 | jointE = interpolate(l, CK.lengthAB, CK.pointF, CK.pointE);
|
327 | }
|
328 | return jointE;
|
329 | }
|
330 |
|
331 | function jointE(m) {
|
332 | return equator(m);
|
333 | }
|
334 |
|
335 | function jointT(m) {
|
336 | return lineIntersection(CK.pointM, 2 * m / 3, jointE(m), m / 3);
|
337 | }
|
338 |
|
339 | function jointF(m) {
|
340 | if (m === 0) {
|
341 | return [CK.pointA + CK.lengthAB, 0];
|
342 | }
|
343 | var xy = lineIntersection(CK.pointA, m, CK.pointM, 2 * m / 3);
|
344 | return xy;
|
345 | }
|
346 |
|
347 | function lengthTorridSegment(m) {
|
348 | return distance(jointE(m), jointT(m));
|
349 | }
|
350 |
|
351 | function lengthMiddleSegment(m) {
|
352 | return distance(jointT(m), jointF(m));
|
353 | }
|
354 |
|
355 | function parallel73(m) {
|
356 | var p73 = [0, 0],
|
357 | jF = jointF(m),
|
358 | lF = 0,
|
359 | xy = [0, 0];
|
360 | if (m <= 30) {
|
361 | p73[0] = CK.pointA[0] + CK.lengthAP73 * cos(m * radians);
|
362 | p73[1] = CK.pointA[1] + CK.lengthAP73 * sin(m * radians);
|
363 | lF = distance(jF, p73);
|
364 | } else {
|
365 | p73 = lineIntersection(CK.pointT, -60, jF, m);
|
366 | lF = distance(jF, p73);
|
367 | if (m > 44) {
|
368 | xy = lineIntersection(CK.pointT, -60, jF, 2 / 3 * m);
|
369 | if (xy[0] > p73[0]) {
|
370 | p73 = xy;
|
371 | lF = -distance(jF, p73);
|
372 | }
|
373 | }
|
374 | }
|
375 | return {
|
376 | parallel73: p73,
|
377 | lengthParallel73: lF
|
378 | };
|
379 | }
|
380 |
|
381 | function parallel75(m) {
|
382 | return [
|
383 | CK.pointA[0] + CK.lengthAP75 * cos(m * radians),
|
384 | CK.pointA[1] + CK.lengthAP75 * sin(m * radians)
|
385 | ];
|
386 | }
|
387 |
|
388 |
|
389 | function ll2mp(lon, lat) {
|
390 | var south = [0, 6, 7, 8, 5],
|
391 | o = truncate((lon + 180) / 90 + 1),
|
392 | p,
|
393 | m = (lon + 720) % 90 - 45,
|
394 | s = sign(m);
|
395 |
|
396 | m = abs(m);
|
397 | if (o === 5) o = 1;
|
398 | if (lat < 0) o = south[o];
|
399 | p = abs(lat);
|
400 | return [m, p, s, o];
|
401 | }
|
402 |
|
403 | function zoneA(m, p) {
|
404 | return [CK.pointA[0] + (90 - p) * 104, 0];
|
405 | }
|
406 |
|
407 | function zoneB(m, p) {
|
408 | return [CK.pointG[0] - p * 100, 0];
|
409 | }
|
410 |
|
411 | function zoneC(m, p) {
|
412 | var l = 104 * (90 - p);
|
413 | return [
|
414 | CK.pointA[0] + l * cos(m * radians),
|
415 | CK.pointA[1] + l * sin(m * radians)
|
416 | ];
|
417 | }
|
418 |
|
419 | function zoneD(m /*, p */) {
|
420 |
|
421 | return equator(m);
|
422 | }
|
423 |
|
424 | function zoneE(m, p) {
|
425 | var l = 1560 + (75 - p) * 100;
|
426 | return [
|
427 | CK.pointA[0] + l * cos(m * radians),
|
428 | CK.pointA[1] + l * sin(m * radians)
|
429 | ];
|
430 | }
|
431 |
|
432 | function zoneF(m, p) {
|
433 | return interpolate(p, 15, CK.pointE, CK.pointD);
|
434 | }
|
435 |
|
436 | function zoneG(m, p) {
|
437 | var l = p - 15;
|
438 | return interpolate(l, 58, CK.pointD, CK.pointT);
|
439 | }
|
440 |
|
441 | function zoneH(m, p) {
|
442 | var p75 = parallel75(45),
|
443 | p73a = parallel73(m),
|
444 | p73 = p73a.parallel73,
|
445 | lF = distance(CK.pointT, CK.pointB),
|
446 | lF75 = distance(CK.pointB, p75),
|
447 | l = (75 - p) * (lF75 + lF) / 2,
|
448 | xy = [0, 0];
|
449 | if (l <= lF75) {
|
450 | xy = interpolate(l, lF75, p75, CK.pointB);
|
451 | } else {
|
452 | l = l - lF75;
|
453 | xy = interpolate(l, lF, CK.pointB, p73);
|
454 | }
|
455 | return xy;
|
456 | }
|
457 |
|
458 | function zoneI(m, p) {
|
459 | var p73a = parallel73(m),
|
460 | lT = lengthTorridSegment(m),
|
461 | lM = lengthMiddleSegment(m),
|
462 | l = p * (lT + lM + p73a.lengthParallel73) / 73,
|
463 | xy;
|
464 | if (l <= lT) {
|
465 | xy = interpolate(l, lT, jointE(m), jointT(m));
|
466 | } else if (l <= lT + lM) {
|
467 | l = l - lT;
|
468 | xy = interpolate(l, lM, jointT(m), jointF(m));
|
469 | } else {
|
470 | l = l - lT - lM;
|
471 | xy = interpolate(l, p73a.lengthParallel73, jointF(m), p73a.parallel73);
|
472 | }
|
473 | return xy;
|
474 | }
|
475 |
|
476 | function zoneJ(m, p) {
|
477 | var p75 = parallel75(m),
|
478 | lF75 = distance(jointF(m), p75),
|
479 | p73a = parallel73(m),
|
480 | p73 = p73a.parallel73,
|
481 | lF = p73a.lengthParallel73,
|
482 | l = (75 - p) * (lF75 - lF) / 2,
|
483 | xy = [0, 0];
|
484 |
|
485 | if (l <= lF75) {
|
486 | xy = interpolate(l, lF75, p75, jointF(m));
|
487 | } else {
|
488 | l = l - lF75;
|
489 | xy = interpolate(l, -lF, jointF(m), p73);
|
490 | }
|
491 | return xy;
|
492 | }
|
493 |
|
494 | function zoneK(m, p, l15) {
|
495 | var l = p * l15 / 15,
|
496 | lT = lengthTorridSegment(m),
|
497 | lM = lengthMiddleSegment(m),
|
498 | xy = [0, 0];
|
499 | if (l <= lT) {
|
500 |
|
501 | xy = interpolate(l, lT, jointE(m), jointT(m));
|
502 | } else {
|
503 |
|
504 | l = l - lT;
|
505 | xy = interpolate(l, lM, jointT(m), jointF(m));
|
506 | }
|
507 | return xy;
|
508 | }
|
509 |
|
510 | function zoneL(m, p, l15) {
|
511 | var p73a = parallel73(m),
|
512 | p73 = p73a.parallel73,
|
513 | lT = lengthTorridSegment(m),
|
514 | lM = lengthMiddleSegment(m),
|
515 | xy,
|
516 | lF = p73a.lengthParallel73,
|
517 | l = l15 + (p - 15) * (lT + lM + lF - l15) / 58;
|
518 | if (l <= lT) {
|
519 |
|
520 | xy = interpolate(l, lT, jointE(m), jointF(m));
|
521 | } else if (l <= lT + lM) {
|
522 |
|
523 | l = l - lT;
|
524 | xy = interpolate(l, lM, jointT(m), jointF(m));
|
525 | } else {
|
526 |
|
527 | l = l - lT - lM;
|
528 | xy = interpolate(l, lF, jointF(m), p73);
|
529 | }
|
530 | return xy;
|
531 | }
|
532 |
|
533 |
|
534 |
|
535 |
|
536 | function mp2xy(m, p) {
|
537 | var xy = [0, 0],
|
538 | lT,
|
539 | p15a,
|
540 | p15,
|
541 | flag15,
|
542 | l15;
|
543 |
|
544 | if (m === 0) {
|
545 |
|
546 | if (p >= 75) {
|
547 | xy = zoneA(m, p);
|
548 | } else {
|
549 | xy = zoneB(m, p);
|
550 | }
|
551 | } else if (p >= 75) {
|
552 | xy = zoneC(m, p);
|
553 | } else if (p === 0) {
|
554 | xy = zoneD(m, p);
|
555 | } else if (p >= 73 && m <= 30) {
|
556 | xy = zoneE(m, p);
|
557 | } else if (m === 45) {
|
558 | if (p <= 15) {
|
559 | xy = zoneF(m, p);
|
560 | } else if (p <= 73) {
|
561 | xy = zoneG(m, p);
|
562 | } else {
|
563 | xy = zoneH(m, p);
|
564 | }
|
565 | } else {
|
566 | if (m <= 29) {
|
567 | xy = zoneI(m, p);
|
568 | } else {
|
569 |
|
570 | if (p >= 73) {
|
571 | xy = zoneJ(m, p);
|
572 | } else {
|
573 |
|
574 | p15a = circleLineIntersection(
|
575 | CK.pointC,
|
576 | CK.radius,
|
577 | jointT(m),
|
578 | jointF(m)
|
579 | );
|
580 | flag15 = p15a[0];
|
581 | p15 = p15a[1];
|
582 | lT = lengthTorridSegment(m);
|
583 | if (flag15 === 1) {
|
584 |
|
585 | l15 = lT + distance(jointT(m), p15);
|
586 | } else {
|
587 |
|
588 | p15a = circleLineIntersection(
|
589 | CK.pointC,
|
590 | CK.radius,
|
591 | jointE(m),
|
592 | jointT(m)
|
593 | );
|
594 | flag15 = p15a[0];
|
595 | p15 = p15a[1];
|
596 | if (flag15 === 0) {
|
597 |
|
598 |
|
599 | }
|
600 | l15 = lT - distance(jointT(m), p15);
|
601 | }
|
602 | if (p <= 15) {
|
603 | xy = zoneK(m, p, l15);
|
604 | } else {
|
605 |
|
606 | xy = zoneL(m, p, l15);
|
607 | }
|
608 | }
|
609 | }
|
610 | }
|
611 | return xy;
|
612 | }
|
613 |
|
614 |
|
615 |
|
616 | function mj2g(xy, octant) {
|
617 | var xynew = [0, 0];
|
618 |
|
619 | if (octant === 0) {
|
620 | xynew = rotate(xy, -60);
|
621 | } else if (octant === 1) {
|
622 | xynew = rotate(xy, -120);
|
623 | xynew[0] -= CK.lengthMG;
|
624 | } else if (octant === 2) {
|
625 | xynew = rotate(xy, -60);
|
626 | xynew[0] -= CK.lengthMG;
|
627 | } else if (octant === 3) {
|
628 | xynew = rotate(xy, -120);
|
629 | xynew[0] += CK.lengthMG;
|
630 | } else if (octant === 4) {
|
631 | xynew = rotate(xy, -60);
|
632 | xynew[0] += CK.lengthMG;
|
633 | } else if (octant === 5) {
|
634 | xynew = rotate([2 * CK.lengthMG - xy[0], xy[1]], -60);
|
635 | xynew[0] += CK.lengthMG;
|
636 | } else if (octant === 6) {
|
637 | xynew = rotate([2 * CK.lengthMG - xy[0], xy[1]], -120);
|
638 | xynew[0] -= CK.lengthMG;
|
639 | } else if (octant === 7) {
|
640 | xynew = rotate([2 * CK.lengthMG - xy[0], xy[1]], -60);
|
641 | xynew[0] -= CK.lengthMG;
|
642 | } else if (octant === 8) {
|
643 | xynew = rotate([2 * CK.lengthMG - xy[0], xy[1]], -120);
|
644 | xynew[0] += CK.lengthMG;
|
645 | } else {
|
646 |
|
647 |
|
648 |
|
649 |
|
650 | return xynew;
|
651 | }
|
652 |
|
653 | return xynew;
|
654 | }
|
655 |
|
656 |
|
657 |
|
658 | function forward(lambda, phi) {
|
659 |
|
660 | var lon = lambda * degrees,
|
661 | lat = phi * degrees,
|
662 | res = ll2mp(lon, lat),
|
663 | m = res[0],
|
664 | p = res[1],
|
665 | s = res[2],
|
666 | o = res[3],
|
667 | xy = mp2xy(m, p),
|
668 | mm = mj2g([xy[0], s * xy[1]], o);
|
669 |
|
670 | return mm;
|
671 | }
|
672 |
|
673 | forward.invert = solve2d(forward);
|
674 |
|
675 | return forward;
|
676 | }
|
677 |
|
678 | function cahillKeyesProjection() {
|
679 | var mg = 10000,
|
680 | m = projectionMutator(cahillKeyesRaw);
|
681 | return m(mg);
|
682 | }
|