174 lines
4.4 KiB
JavaScript
174 lines
4.4 KiB
JavaScript
|
// Heavily based on this tmerc projection implementation
|
||
|
// https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/tmerc.js
|
||
|
|
||
|
import pj_enfn from '../common/pj_enfn';
|
||
|
import pj_mlfn from '../common/pj_mlfn';
|
||
|
import pj_inv_mlfn from '../common/pj_inv_mlfn';
|
||
|
import adjust_lon from '../common/adjust_lon';
|
||
|
|
||
|
import {EPSLN, HALF_PI} from '../constants/values';
|
||
|
import sign from '../common/sign';
|
||
|
|
||
|
export function init() {
|
||
|
this.x0 = this.x0 !== undefined ? this.x0 : 0;
|
||
|
this.y0 = this.y0 !== undefined ? this.y0 : 0;
|
||
|
this.long0 = this.long0 !== undefined ? this.long0 : 0;
|
||
|
this.lat0 = this.lat0 !== undefined ? this.lat0 : 0;
|
||
|
|
||
|
if (this.es) {
|
||
|
this.en = pj_enfn(this.es);
|
||
|
this.ml0 = pj_mlfn(this.lat0, Math.sin(this.lat0), Math.cos(this.lat0), this.en);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Transverse Mercator Forward - long/lat to x/y
|
||
|
long/lat in radians
|
||
|
*/
|
||
|
export function forward(p) {
|
||
|
var lon = p.x;
|
||
|
var lat = p.y;
|
||
|
|
||
|
var delta_lon = adjust_lon(lon - this.long0);
|
||
|
var con;
|
||
|
var x, y;
|
||
|
var sin_phi = Math.sin(lat);
|
||
|
var cos_phi = Math.cos(lat);
|
||
|
|
||
|
if (!this.es) {
|
||
|
var b = cos_phi * Math.sin(delta_lon);
|
||
|
|
||
|
if ((Math.abs(Math.abs(b) - 1)) < EPSLN) {
|
||
|
return (93);
|
||
|
}
|
||
|
else {
|
||
|
x = 0.5 * this.a * this.k0 * Math.log((1 + b) / (1 - b)) + this.x0;
|
||
|
y = cos_phi * Math.cos(delta_lon) / Math.sqrt(1 - Math.pow(b, 2));
|
||
|
b = Math.abs(y);
|
||
|
|
||
|
if (b >= 1) {
|
||
|
if ((b - 1) > EPSLN) {
|
||
|
return (93);
|
||
|
}
|
||
|
else {
|
||
|
y = 0;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
y = Math.acos(y);
|
||
|
}
|
||
|
|
||
|
if (lat < 0) {
|
||
|
y = -y;
|
||
|
}
|
||
|
|
||
|
y = this.a * this.k0 * (y - this.lat0) + this.y0;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
var al = cos_phi * delta_lon;
|
||
|
var als = Math.pow(al, 2);
|
||
|
var c = this.ep2 * Math.pow(cos_phi, 2);
|
||
|
var cs = Math.pow(c, 2);
|
||
|
var tq = Math.abs(cos_phi) > EPSLN ? Math.tan(lat) : 0;
|
||
|
var t = Math.pow(tq, 2);
|
||
|
var ts = Math.pow(t, 2);
|
||
|
con = 1 - this.es * Math.pow(sin_phi, 2);
|
||
|
al = al / Math.sqrt(con);
|
||
|
var ml = pj_mlfn(lat, sin_phi, cos_phi, this.en);
|
||
|
|
||
|
x = this.a * (this.k0 * al * (1 +
|
||
|
als / 6 * (1 - t + c +
|
||
|
als / 20 * (5 - 18 * t + ts + 14 * c - 58 * t * c +
|
||
|
als / 42 * (61 + 179 * ts - ts * t - 479 * t))))) +
|
||
|
this.x0;
|
||
|
|
||
|
y = this.a * (this.k0 * (ml - this.ml0 +
|
||
|
sin_phi * delta_lon * al / 2 * (1 +
|
||
|
als / 12 * (5 - t + 9 * c + 4 * cs +
|
||
|
als / 30 * (61 + ts - 58 * t + 270 * c - 330 * t * c +
|
||
|
als / 56 * (1385 + 543 * ts - ts * t - 3111 * t)))))) +
|
||
|
this.y0;
|
||
|
}
|
||
|
|
||
|
p.x = x;
|
||
|
p.y = y;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Transverse Mercator Inverse - x/y to long/lat
|
||
|
*/
|
||
|
export function inverse(p) {
|
||
|
var con, phi;
|
||
|
var lat, lon;
|
||
|
var x = (p.x - this.x0) * (1 / this.a);
|
||
|
var y = (p.y - this.y0) * (1 / this.a);
|
||
|
|
||
|
if (!this.es) {
|
||
|
var f = Math.exp(x / this.k0);
|
||
|
var g = 0.5 * (f - 1 / f);
|
||
|
var temp = this.lat0 + y / this.k0;
|
||
|
var h = Math.cos(temp);
|
||
|
con = Math.sqrt((1 - Math.pow(h, 2)) / (1 + Math.pow(g, 2)));
|
||
|
lat = Math.asin(con);
|
||
|
|
||
|
if (y < 0) {
|
||
|
lat = -lat;
|
||
|
}
|
||
|
|
||
|
if ((g === 0) && (h === 0)) {
|
||
|
lon = 0;
|
||
|
}
|
||
|
else {
|
||
|
lon = adjust_lon(Math.atan2(g, h) + this.long0);
|
||
|
}
|
||
|
}
|
||
|
else { // ellipsoidal form
|
||
|
con = this.ml0 + y / this.k0;
|
||
|
phi = pj_inv_mlfn(con, this.es, this.en);
|
||
|
|
||
|
if (Math.abs(phi) < HALF_PI) {
|
||
|
var sin_phi = Math.sin(phi);
|
||
|
var cos_phi = Math.cos(phi);
|
||
|
var tan_phi = Math.abs(cos_phi) > EPSLN ? Math.tan(phi) : 0;
|
||
|
var c = this.ep2 * Math.pow(cos_phi, 2);
|
||
|
var cs = Math.pow(c, 2);
|
||
|
var t = Math.pow(tan_phi, 2);
|
||
|
var ts = Math.pow(t, 2);
|
||
|
con = 1 - this.es * Math.pow(sin_phi, 2);
|
||
|
var d = x * Math.sqrt(con) / this.k0;
|
||
|
var ds = Math.pow(d, 2);
|
||
|
con = con * tan_phi;
|
||
|
|
||
|
lat = phi - (con * ds / (1 - this.es)) * 0.5 * (1 -
|
||
|
ds / 12 * (5 + 3 * t - 9 * c * t + c - 4 * cs -
|
||
|
ds / 30 * (61 + 90 * t - 252 * c * t + 45 * ts + 46 * c -
|
||
|
ds / 56 * (1385 + 3633 * t + 4095 * ts + 1574 * ts * t))));
|
||
|
|
||
|
lon = adjust_lon(this.long0 + (d * (1 -
|
||
|
ds / 6 * (1 + 2 * t + c -
|
||
|
ds / 20 * (5 + 28 * t + 24 * ts + 8 * c * t + 6 * c -
|
||
|
ds / 42 * (61 + 662 * t + 1320 * ts + 720 * ts * t)))) / cos_phi));
|
||
|
}
|
||
|
else {
|
||
|
lat = HALF_PI * sign(y);
|
||
|
lon = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p.x = lon;
|
||
|
p.y = lat;
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
export var names = ["Fast_Transverse_Mercator", "Fast Transverse Mercator"];
|
||
|
export default {
|
||
|
init: init,
|
||
|
forward: forward,
|
||
|
inverse: inverse,
|
||
|
names: names
|
||
|
};
|