var HALF_PI = Math.PI/2;
|
var FORTPI = Math.PI/4;
|
var EPSLN = 1.0e-10;
|
var qsfnz = require('../common/qsfnz');
|
var adjust_lon = require('../common/adjust_lon');
|
/*
|
reference
|
"New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
|
The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
|
*/
|
|
exports.S_POLE = 1;
|
exports.N_POLE = 2;
|
exports.EQUIT = 3;
|
exports.OBLIQ = 4;
|
|
|
/* Initialize the Lambert Azimuthal Equal Area projection
|
------------------------------------------------------*/
|
exports.init = function() {
|
var t = Math.abs(this.lat0);
|
if (Math.abs(t - HALF_PI) < EPSLN) {
|
this.mode = this.lat0 < 0 ? this.S_POLE : this.N_POLE;
|
}
|
else if (Math.abs(t) < EPSLN) {
|
this.mode = this.EQUIT;
|
}
|
else {
|
this.mode = this.OBLIQ;
|
}
|
if (this.es > 0) {
|
var sinphi;
|
|
this.qp = qsfnz(this.e, 1);
|
this.mmf = 0.5 / (1 - this.es);
|
this.apa = this.authset(this.es);
|
switch (this.mode) {
|
case this.N_POLE:
|
this.dd = 1;
|
break;
|
case this.S_POLE:
|
this.dd = 1;
|
break;
|
case this.EQUIT:
|
this.rq = Math.sqrt(0.5 * this.qp);
|
this.dd = 1 / this.rq;
|
this.xmf = 1;
|
this.ymf = 0.5 * this.qp;
|
break;
|
case this.OBLIQ:
|
this.rq = Math.sqrt(0.5 * this.qp);
|
sinphi = Math.sin(this.lat0);
|
this.sinb1 = qsfnz(this.e, sinphi) / this.qp;
|
this.cosb1 = Math.sqrt(1 - this.sinb1 * this.sinb1);
|
this.dd = Math.cos(this.lat0) / (Math.sqrt(1 - this.es * sinphi * sinphi) * this.rq * this.cosb1);
|
this.ymf = (this.xmf = this.rq) / this.dd;
|
this.xmf *= this.dd;
|
break;
|
}
|
}
|
else {
|
if (this.mode === this.OBLIQ) {
|
this.sinph0 = Math.sin(this.lat0);
|
this.cosph0 = Math.cos(this.lat0);
|
}
|
}
|
};
|
|
/* Lambert Azimuthal Equal Area forward equations--mapping lat,long to x,y
|
-----------------------------------------------------------------------*/
|
exports.forward = function(p) {
|
|
/* Forward equations
|
-----------------*/
|
var x, y, coslam, sinlam, sinphi, q, sinb, cosb, b, cosphi;
|
var lam = p.x;
|
var phi = p.y;
|
|
lam = adjust_lon(lam - this.long0);
|
|
if (this.sphere) {
|
sinphi = Math.sin(phi);
|
cosphi = Math.cos(phi);
|
coslam = Math.cos(lam);
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
y = (this.mode === this.EQUIT) ? 1 + cosphi * coslam : 1 + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
|
if (y <= EPSLN) {
|
return null;
|
}
|
y = Math.sqrt(2 / y);
|
x = y * cosphi * Math.sin(lam);
|
y *= (this.mode === this.EQUIT) ? sinphi : this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
|
}
|
else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
|
if (this.mode === this.N_POLE) {
|
coslam = -coslam;
|
}
|
if (Math.abs(phi + this.phi0) < EPSLN) {
|
return null;
|
}
|
y = FORTPI - phi * 0.5;
|
y = 2 * ((this.mode === this.S_POLE) ? Math.cos(y) : Math.sin(y));
|
x = y * Math.sin(lam);
|
y *= coslam;
|
}
|
}
|
else {
|
sinb = 0;
|
cosb = 0;
|
b = 0;
|
coslam = Math.cos(lam);
|
sinlam = Math.sin(lam);
|
sinphi = Math.sin(phi);
|
q = qsfnz(this.e, sinphi);
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
sinb = q / this.qp;
|
cosb = Math.sqrt(1 - sinb * sinb);
|
}
|
switch (this.mode) {
|
case this.OBLIQ:
|
b = 1 + this.sinb1 * sinb + this.cosb1 * cosb * coslam;
|
break;
|
case this.EQUIT:
|
b = 1 + cosb * coslam;
|
break;
|
case this.N_POLE:
|
b = HALF_PI + phi;
|
q = this.qp - q;
|
break;
|
case this.S_POLE:
|
b = phi - HALF_PI;
|
q = this.qp + q;
|
break;
|
}
|
if (Math.abs(b) < EPSLN) {
|
return null;
|
}
|
switch (this.mode) {
|
case this.OBLIQ:
|
case this.EQUIT:
|
b = Math.sqrt(2 / b);
|
if (this.mode === this.OBLIQ) {
|
y = this.ymf * b * (this.cosb1 * sinb - this.sinb1 * cosb * coslam);
|
}
|
else {
|
y = (b = Math.sqrt(2 / (1 + cosb * coslam))) * sinb * this.ymf;
|
}
|
x = this.xmf * b * cosb * sinlam;
|
break;
|
case this.N_POLE:
|
case this.S_POLE:
|
if (q >= 0) {
|
x = (b = Math.sqrt(q)) * sinlam;
|
y = coslam * ((this.mode === this.S_POLE) ? b : -b);
|
}
|
else {
|
x = y = 0;
|
}
|
break;
|
}
|
}
|
|
p.x = this.a * x + this.x0;
|
p.y = this.a * y + this.y0;
|
return p;
|
};
|
|
/* Inverse equations
|
-----------------*/
|
exports.inverse = function(p) {
|
p.x -= this.x0;
|
p.y -= this.y0;
|
var x = p.x / this.a;
|
var y = p.y / this.a;
|
var lam, phi, cCe, sCe, q, rho, ab;
|
|
if (this.sphere) {
|
var cosz = 0,
|
rh, sinz = 0;
|
|
rh = Math.sqrt(x * x + y * y);
|
phi = rh * 0.5;
|
if (phi > 1) {
|
return null;
|
}
|
phi = 2 * Math.asin(phi);
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
sinz = Math.sin(phi);
|
cosz = Math.cos(phi);
|
}
|
switch (this.mode) {
|
case this.EQUIT:
|
phi = (Math.abs(rh) <= EPSLN) ? 0 : Math.asin(y * sinz / rh);
|
x *= sinz;
|
y = cosz * rh;
|
break;
|
case this.OBLIQ:
|
phi = (Math.abs(rh) <= EPSLN) ? this.phi0 : Math.asin(cosz * this.sinph0 + y * sinz * this.cosph0 / rh);
|
x *= sinz * this.cosph0;
|
y = (cosz - Math.sin(phi) * this.sinph0) * rh;
|
break;
|
case this.N_POLE:
|
y = -y;
|
phi = HALF_PI - phi;
|
break;
|
case this.S_POLE:
|
phi -= HALF_PI;
|
break;
|
}
|
lam = (y === 0 && (this.mode === this.EQUIT || this.mode === this.OBLIQ)) ? 0 : Math.atan2(x, y);
|
}
|
else {
|
ab = 0;
|
if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
|
x /= this.dd;
|
y *= this.dd;
|
rho = Math.sqrt(x * x + y * y);
|
if (rho < EPSLN) {
|
p.x = 0;
|
p.y = this.phi0;
|
return p;
|
}
|
sCe = 2 * Math.asin(0.5 * rho / this.rq);
|
cCe = Math.cos(sCe);
|
x *= (sCe = Math.sin(sCe));
|
if (this.mode === this.OBLIQ) {
|
ab = cCe * this.sinb1 + y * sCe * this.cosb1 / rho;
|
q = this.qp * ab;
|
y = rho * this.cosb1 * cCe - y * this.sinb1 * sCe;
|
}
|
else {
|
ab = y * sCe / rho;
|
q = this.qp * ab;
|
y = rho * cCe;
|
}
|
}
|
else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
|
if (this.mode === this.N_POLE) {
|
y = -y;
|
}
|
q = (x * x + y * y);
|
if (!q) {
|
p.x = 0;
|
p.y = this.phi0;
|
return p;
|
}
|
ab = 1 - q / this.qp;
|
if (this.mode === this.S_POLE) {
|
ab = -ab;
|
}
|
}
|
lam = Math.atan2(x, y);
|
phi = this.authlat(Math.asin(ab), this.apa);
|
}
|
|
|
p.x = adjust_lon(this.long0 + lam);
|
p.y = phi;
|
return p;
|
};
|
|
/* determine latitude from authalic latitude */
|
exports.P00 = 0.33333333333333333333;
|
exports.P01 = 0.17222222222222222222;
|
exports.P02 = 0.10257936507936507936;
|
exports.P10 = 0.06388888888888888888;
|
exports.P11 = 0.06640211640211640211;
|
exports.P20 = 0.01641501294219154443;
|
|
exports.authset = function(es) {
|
var t;
|
var APA = [];
|
APA[0] = es * this.P00;
|
t = es * es;
|
APA[0] += t * this.P01;
|
APA[1] = t * this.P10;
|
t *= es;
|
APA[0] += t * this.P02;
|
APA[1] += t * this.P11;
|
APA[2] = t * this.P20;
|
return APA;
|
};
|
|
exports.authlat = function(beta, APA) {
|
var t = beta + beta;
|
return (beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t + t) + APA[2] * Math.sin(t + t + t));
|
};
|
exports.names = ["Lambert Azimuthal Equal Area", "Lambert_Azimuthal_Equal_Area", "laea"];
|