import {geoProjectionMutator as projectionMutator} from "d3-geo"; import {abs, atan2, cos, degrees, epsilon, radians, sin, tan} from "./math.js"; export function armadilloRaw(phi0) { var sinPhi0 = sin(phi0), cosPhi0 = cos(phi0), sPhi0 = phi0 >= 0 ? 1 : -1, tanPhi0 = tan(sPhi0 * phi0), k = (1 + sinPhi0 - cosPhi0) / 2; function forward(lambda, phi) { var cosPhi = cos(phi), cosLambda = cos(lambda /= 2); return [ (1 + cosPhi) * sin(lambda), (sPhi0 * phi > -atan2(cosLambda, tanPhi0) - 1e-3 ? 0 : -sPhi0 * 10) + k + sin(phi) * cosPhi0 - (1 + cosPhi) * sinPhi0 * cosLambda // TODO D3 core should allow null or [NaN, NaN] to be returned. ]; } forward.invert = function(x, y) { var lambda = 0, phi = 0, i = 50; do { var cosLambda = cos(lambda), sinLambda = sin(lambda), cosPhi = cos(phi), sinPhi = sin(phi), A = 1 + cosPhi, fx = A * sinLambda - x, fy = k + sinPhi * cosPhi0 - A * sinPhi0 * cosLambda - y, dxdLambda = A * cosLambda / 2, dxdPhi = -sinLambda * sinPhi, dydLambda = sinPhi0 * A * sinLambda / 2, dydPhi = cosPhi0 * cosPhi + sinPhi0 * cosLambda * sinPhi, denominator = dxdPhi * dydLambda - dydPhi * dxdLambda, dLambda = (fy * dxdPhi - fx * dydPhi) / denominator / 2, dPhi = (fx * dydLambda - fy * dxdLambda) / denominator; if (abs(dPhi) > 2) dPhi /= 2; lambda -= dLambda, phi -= dPhi; } while ((abs(dLambda) > epsilon || abs(dPhi) > epsilon) && --i > 0); return sPhi0 * phi > -atan2(cos(lambda), tanPhi0) - 1e-3 ? [lambda * 2, phi] : null; }; return forward; } export default function() { var phi0 = 20 * radians, sPhi0 = phi0 >= 0 ? 1 : -1, tanPhi0 = tan(sPhi0 * phi0), m = projectionMutator(armadilloRaw), p = m(phi0), stream_ = p.stream; p.parallel = function(_) { if (!arguments.length) return phi0 * degrees; tanPhi0 = tan((sPhi0 = (phi0 = _ * radians) >= 0 ? 1 : -1) * phi0); return m(phi0); }; p.stream = function(stream) { var rotate = p.rotate(), rotateStream = stream_(stream), sphereStream = (p.rotate([0, 0]), stream_(stream)), precision = p.precision(); p.rotate(rotate); rotateStream.sphere = function() { sphereStream.polygonStart(), sphereStream.lineStart(); for (var lambda = sPhi0 * -180; sPhi0 * lambda < 180; lambda += sPhi0 * 90) sphereStream.point(lambda, sPhi0 * 90); if (phi0) while (sPhi0 * (lambda -= 3 * sPhi0 * precision) >= -180) { sphereStream.point(lambda, sPhi0 * -atan2(cos(lambda * radians / 2), tanPhi0) * degrees); } sphereStream.lineEnd(), sphereStream.polygonEnd(); }; return rotateStream; }; return p .scale(218.695) .center([0, 28.0974]); }