import {range} from "d3-array"; import {geoStream, geoProjectionMutator as projectionMutator} from "d3-geo"; import {collignonRaw} from "./collignon"; import {cylindricalEqualAreaRaw} from "./cylindricalEqualArea"; import {abs, floor, max, min, pi, radians, sqrtPi, tau} from "./math"; var healpixParallel = 41 + 48 / 36 + 37 / 3600, // for K=3; TODO automate healpixLambert = cylindricalEqualAreaRaw(0); export function healpixRaw(H) { var phi0 = healpixParallel * radians, dx = collignonRaw(pi, phi0)[0] - collignonRaw(-pi, phi0)[0], y0 = healpixLambert(0, phi0)[1], y1 = collignonRaw(0, phi0)[1], dy1 = sqrtPi - y1, k = tau / H, w = 4 / tau, h = y0 + (dy1 * dy1 * 4) / tau; function forward(lambda, phi) { var point, phi2 = abs(phi); if (phi2 > phi0) { var i = min(H - 1, max(0, floor((lambda + pi) / k))); lambda += pi * (H - 1) / H - i * k; point = collignonRaw(lambda, phi2); point[0] = point[0] * tau / dx - tau * (H - 1) / (2 * H) + i * tau / H; point[1] = y0 + (point[1] - y1) * 4 * dy1 / tau; if (phi < 0) point[1] = -point[1]; } else { point = healpixLambert(lambda, phi); } point[0] *= w, point[1] /= h; return point; } forward.invert = function(x, y) { x /= w, y *= h; var y2 = abs(y); if (y2 > y0) { var i = min(H - 1, max(0, floor((x + pi) / k))); x = (x + pi * (H - 1) / H - i * k) * dx / tau; var point = collignonRaw.invert(x, 0.25 * (y2 - y0) * tau / dy1 + y1); point[0] -= pi * (H - 1) / H - i * k; if (y < 0) point[1] = -point[1]; return point; } return healpixLambert.invert(x, y); }; return forward; } function sphere(step) { return { type: "Polygon", coordinates: [ range(-180, 180 + step / 2, step).map(function(x, i) { return [x, i & 1 ? 90 - 1e-6 : healpixParallel]; }) .concat(range(180, -180 - step / 2, -step).map(function(x, i) { return [x, i & 1 ? -90 + 1e-6 : -healpixParallel]; })) ] }; } export default function() { var H = 4, m = projectionMutator(healpixRaw), p = m(H), stream_ = p.stream; p.lobes = function(_) { return arguments.length ? m(H = +_) : H; }; p.stream = function(stream) { var rotate = p.rotate(), rotateStream = stream_(stream), sphereStream = (p.rotate([0, 0]), stream_(stream)); p.rotate(rotate); rotateStream.sphere = function() { geoStream(sphere(180 / H), sphereStream); }; return rotateStream; }; return p .scale(239.75); }