s2-tools
Version:
A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.
150 lines • 4.5 kB
JavaScript
import { ProjectionBase } from '.';
import { EPSLN, HALF_PI } from '../constants';
import { adjustLon, asinz } from '../common';
/**
* # van der Grinten (I)
*
* **Classification**: Miscellaneous
*
* **Available forms**: Forward and inverse, spherical projection
*
* **Defined area**: Global
*
* **Alias**: vandg
*
* **Domain**: 2D
*
* **Input type**: Geodetic coordinates
*
* **Output type**: Projected coordinates
*
* ## Projection String
* ```
* +proj=vandg
* ```
*
* ## Parameters
*
* All parameters are optional.
*
* - `+lon_0=<value>`: Central meridian.
* - `+R=<value>`: Radius of the sphere.
* - `+x_0=<value>`: False easting.
* - `+y_0=<value>`: False northing.
*
* 
*/
export class VanDerGrinten extends ProjectionBase {
name = 'VanDerGrinten';
static names = ['VanDerGrinten', 'Van_der_Grinten_I', 'vandg'];
// VanDerGrinten specific variables
R;
/**
* Preps an VanDerGrinten projection
* @param params - projection specific parameters
*/
constructor(params) {
super(params);
// R = 6370997 -> Radius of earth
this.R = this.a;
}
/**
* VanDerGrinten forward equations--mapping lon-lat to x-y
* @param p - lon-lat WGS84 point
*/
forward(p) {
const { abs, PI, sin, cos, sqrt, tan } = Math;
const { x: lon, y: lat } = p;
const dlon = adjustLon(lon - this.long0);
let x, y;
if (abs(lat) <= EPSLN) {
x = this.x0 + this.R * dlon;
y = this.y0;
}
const theta = asinz(2 * abs(lat / PI));
if (abs(dlon) <= EPSLN || abs(abs(lat) - HALF_PI) <= EPSLN) {
x = this.x0;
if (lat >= 0) {
y = this.y0 + PI * this.R * tan(0.5 * theta);
}
else {
y = this.y0 + PI * this.R * -tan(0.5 * theta);
}
// return(OK);
}
const al = 0.5 * abs(PI / dlon - dlon / PI);
const asq = al * al;
const sinth = sin(theta);
const costh = cos(theta);
const g = costh / (sinth + costh - 1);
const gsq = g * g;
const m = g * (2 / sinth - 1);
const msq = m * m;
let con = (PI *
this.R *
(al * (g - msq) + sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq)))) /
(msq + asq);
if (dlon < 0) {
con = -con;
}
x = this.x0 + con;
//con = abs(con / (PI * this.R));
const q = asq + g;
con = (PI * this.R * (m * q - al * sqrt((msq + asq) * (asq + 1) - q * q))) / (msq + asq);
if (lat >= 0) {
//y = this.y0 + PI * this.R * sqrt(1 - con * con - 2 * al * con);
y = this.y0 + con;
}
else {
//y = this.y0 - PI * this.R * sqrt(1 - con * con - 2 * al * con);
y = this.y0 - con;
}
p.x = x;
p.y = y;
}
/**
* VanDerGrinten inverse equations--mapping x-y to lon-lat
* @param p - VanDerGrinten point
*/
inverse(p) {
const { abs, PI, cos, sqrt, acos } = Math;
let lon, lat;
p.x -= this.x0;
p.y -= this.y0;
let con = PI * this.R;
const xx = p.x / con;
const yy = p.y / con;
const xys = xx * xx + yy * yy;
const c1 = -abs(yy) * (1 + xys);
const c2 = c1 - 2 * yy * yy + xx * xx;
const c3 = -2 * c1 + 1 + 2 * yy * yy + xys * xys;
const d = (yy * yy) / c3 + ((2 * c2 * c2 * c2) / c3 / c3 / c3 - (9 * c1 * c2) / c3 / c3) / 27;
const a1 = (c1 - (c2 * c2) / 3 / c3) / c3;
const m1 = 2 * sqrt(-a1 / 3);
con = (3 * d) / a1 / m1;
if (abs(con) > 1) {
if (con >= 0) {
con = 1;
}
else {
con = -1;
}
}
const th1 = acos(con) / 3;
if (p.y >= 0) {
lat = (-m1 * cos(th1 + PI / 3) - c2 / 3 / c3) * PI;
}
else {
lat = -(-m1 * cos(th1 + PI / 3) - c2 / 3 / c3) * PI;
}
if (abs(xx) < EPSLN) {
lon = this.long0;
}
else {
lon = adjustLon(this.long0 + (PI * (xys - 1 + sqrt(1 + 2 * (xx * xx - yy * yy) + xys * xys))) / 2 / xx);
}
p.x = lon;
p.y = lat;
}
}
//# sourceMappingURL=vandg.js.map