// 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 };