mapbox-gl
Version:
A WebGL interactive maps library
69 lines (60 loc) • 2.94 kB
JavaScript
// @flow
import LngLat from '../lng_lat.js';
import {clamp, degToRad, radToDeg} from '../../util/util.js';
import {MAX_MERCATOR_LATITUDE} from '../mercator_coordinate.js';
import Projection from './projection.js';
import type {ProjectedPoint} from './projection.js';
const maxPhi = degToRad(MAX_MERCATOR_LATITUDE);
export default class WinkelTripel extends Projection {
project(lng: number, lat: number): ProjectedPoint {
lat = degToRad(lat);
lng = degToRad(lng);
const cosLat = Math.cos(lat);
const twoOverPi = 2 / Math.PI;
const alpha = Math.acos(cosLat * Math.cos(lng / 2));
const sinAlphaOverAlpha = Math.sin(alpha) / alpha;
const x = 0.5 * (lng * twoOverPi + (2 * cosLat * Math.sin(lng / 2)) / sinAlphaOverAlpha) || 0;
const y = 0.5 * (lat + Math.sin(lat) / sinAlphaOverAlpha) || 0;
return {
x: (x / Math.PI + 0.5) * 0.5,
y: 1 - (y / Math.PI + 1) * 0.5,
z: 0
};
}
unproject(x: number, y: number): LngLat {
// based on https://github.com/d3/d3-geo-projection, MIT-licensed
x = (2 * x - 0.5) * Math.PI;
y = (2 * (1 - y) - 1) * Math.PI;
let lambda = x;
let phi = y;
let i = 25;
const epsilon = 1e-6;
let dlambda = 0, dphi = 0;
do {
const cosphi = Math.cos(phi),
sinphi = Math.sin(phi),
sinphi2 = 2 * sinphi * cosphi,
sin2phi = sinphi * sinphi,
cos2phi = cosphi * cosphi,
coslambda2 = Math.cos(lambda / 2),
sinlambda2 = Math.sin(lambda / 2),
sinlambda = 2 * coslambda2 * sinlambda2,
sin2lambda2 = sinlambda2 * sinlambda2,
C = 1 - cos2phi * coslambda2 * coslambda2,
F = C ? 1 / C : 0,
E = C ? Math.acos(cosphi * coslambda2) * Math.sqrt(1 / C) : 0,
fx = 0.5 * (2 * E * cosphi * sinlambda2 + lambda * 2 / Math.PI) - x,
fy = 0.5 * (E * sinphi + phi) - y,
dxdlambda = 0.5 * F * (cos2phi * sin2lambda2 + E * cosphi * coslambda2 * sin2phi) + 1 / Math.PI,
dxdphi = F * (sinlambda * sinphi2 / 4 - E * sinphi * sinlambda2),
dydlambda = 0.125 * F * (sinphi2 * sinlambda2 - E * sinphi * cos2phi * sinlambda),
dydphi = 0.5 * F * (sin2phi * coslambda2 + E * sin2lambda2 * cosphi) + 0.5,
denominator = dxdphi * dydlambda - dydphi * dxdlambda;
dlambda = (fy * dxdphi - fx * dydphi) / denominator;
dphi = (fx * dydlambda - fy * dxdlambda) / denominator;
lambda = clamp(lambda - dlambda, -Math.PI, Math.PI);
phi = clamp(phi - dphi, -maxPhi, maxPhi);
} while ((Math.abs(dlambda) > epsilon || Math.abs(dphi) > epsilon) && --i > 0);
return new LngLat(radToDeg(lambda), radToDeg(phi));
}
}