var tsfnz = require('../common/tsfnz');
|
var adjust_lon = require('../common/adjust_lon');
|
var phi2z = require('../common/phi2z');
|
var HALF_PI = Math.PI/2;
|
var FORTPI = Math.PI/4;
|
var EPSLN = 1.0e-10;
|
|
/* Initialize the Oblique Mercator projection
|
------------------------------------------*/
|
exports.init = function() {
|
this.no_off = this.no_off || false;
|
this.no_rot = this.no_rot || false;
|
|
if (isNaN(this.k0)) {
|
this.k0 = 1;
|
}
|
var sinlat = Math.sin(this.lat0);
|
var coslat = Math.cos(this.lat0);
|
var con = this.e * sinlat;
|
|
this.bl = Math.sqrt(1 + this.es / (1 - this.es) * Math.pow(coslat, 4));
|
this.al = this.a * this.bl * this.k0 * Math.sqrt(1 - this.es) / (1 - con * con);
|
var t0 = tsfnz(this.e, this.lat0, sinlat);
|
var dl = this.bl / coslat * Math.sqrt((1 - this.es) / (1 - con * con));
|
if (dl * dl < 1) {
|
dl = 1;
|
}
|
var fl;
|
var gl;
|
if (!isNaN(this.longc)) {
|
//Central point and azimuth method
|
|
if (this.lat0 >= 0) {
|
fl = dl + Math.sqrt(dl * dl - 1);
|
}
|
else {
|
fl = dl - Math.sqrt(dl * dl - 1);
|
}
|
this.el = fl * Math.pow(t0, this.bl);
|
gl = 0.5 * (fl - 1 / fl);
|
this.gamma0 = Math.asin(Math.sin(this.alpha) / dl);
|
this.long0 = this.longc - Math.asin(gl * Math.tan(this.gamma0)) / this.bl;
|
|
}
|
else {
|
//2 points method
|
var t1 = tsfnz(this.e, this.lat1, Math.sin(this.lat1));
|
var t2 = tsfnz(this.e, this.lat2, Math.sin(this.lat2));
|
if (this.lat0 >= 0) {
|
this.el = (dl + Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
|
}
|
else {
|
this.el = (dl - Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
|
}
|
var hl = Math.pow(t1, this.bl);
|
var ll = Math.pow(t2, this.bl);
|
fl = this.el / hl;
|
gl = 0.5 * (fl - 1 / fl);
|
var jl = (this.el * this.el - ll * hl) / (this.el * this.el + ll * hl);
|
var pl = (ll - hl) / (ll + hl);
|
var dlon12 = adjust_lon(this.long1 - this.long2);
|
this.long0 = 0.5 * (this.long1 + this.long2) - Math.atan(jl * Math.tan(0.5 * this.bl * (dlon12)) / pl) / this.bl;
|
this.long0 = adjust_lon(this.long0);
|
var dlon10 = adjust_lon(this.long1 - this.long0);
|
this.gamma0 = Math.atan(Math.sin(this.bl * (dlon10)) / gl);
|
this.alpha = Math.asin(dl * Math.sin(this.gamma0));
|
}
|
|
if (this.no_off) {
|
this.uc = 0;
|
}
|
else {
|
if (this.lat0 >= 0) {
|
this.uc = this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
|
}
|
else {
|
this.uc = -1 * this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
|
}
|
}
|
|
};
|
|
|
/* Oblique Mercator forward equations--mapping lat,long to x,y
|
----------------------------------------------------------*/
|
exports.forward = function(p) {
|
var lon = p.x;
|
var lat = p.y;
|
var dlon = adjust_lon(lon - this.long0);
|
var us, vs;
|
var con;
|
if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
|
if (lat > 0) {
|
con = -1;
|
}
|
else {
|
con = 1;
|
}
|
vs = this.al / this.bl * Math.log(Math.tan(FORTPI + con * this.gamma0 * 0.5));
|
us = -1 * con * HALF_PI * this.al / this.bl;
|
}
|
else {
|
var t = tsfnz(this.e, lat, Math.sin(lat));
|
var ql = this.el / Math.pow(t, this.bl);
|
var sl = 0.5 * (ql - 1 / ql);
|
var tl = 0.5 * (ql + 1 / ql);
|
var vl = Math.sin(this.bl * (dlon));
|
var ul = (sl * Math.sin(this.gamma0) - vl * Math.cos(this.gamma0)) / tl;
|
if (Math.abs(Math.abs(ul) - 1) <= EPSLN) {
|
vs = Number.POSITIVE_INFINITY;
|
}
|
else {
|
vs = 0.5 * this.al * Math.log((1 - ul) / (1 + ul)) / this.bl;
|
}
|
if (Math.abs(Math.cos(this.bl * (dlon))) <= EPSLN) {
|
us = this.al * this.bl * (dlon);
|
}
|
else {
|
us = this.al * Math.atan2(sl * Math.cos(this.gamma0) + vl * Math.sin(this.gamma0), Math.cos(this.bl * dlon)) / this.bl;
|
}
|
}
|
|
if (this.no_rot) {
|
p.x = this.x0 + us;
|
p.y = this.y0 + vs;
|
}
|
else {
|
|
us -= this.uc;
|
p.x = this.x0 + vs * Math.cos(this.alpha) + us * Math.sin(this.alpha);
|
p.y = this.y0 + us * Math.cos(this.alpha) - vs * Math.sin(this.alpha);
|
}
|
return p;
|
};
|
|
exports.inverse = function(p) {
|
var us, vs;
|
if (this.no_rot) {
|
vs = p.y - this.y0;
|
us = p.x - this.x0;
|
}
|
else {
|
vs = (p.x - this.x0) * Math.cos(this.alpha) - (p.y - this.y0) * Math.sin(this.alpha);
|
us = (p.y - this.y0) * Math.cos(this.alpha) + (p.x - this.x0) * Math.sin(this.alpha);
|
us += this.uc;
|
}
|
var qp = Math.exp(-1 * this.bl * vs / this.al);
|
var sp = 0.5 * (qp - 1 / qp);
|
var tp = 0.5 * (qp + 1 / qp);
|
var vp = Math.sin(this.bl * us / this.al);
|
var up = (vp * Math.cos(this.gamma0) + sp * Math.sin(this.gamma0)) / tp;
|
var ts = Math.pow(this.el / Math.sqrt((1 + up) / (1 - up)), 1 / this.bl);
|
if (Math.abs(up - 1) < EPSLN) {
|
p.x = this.long0;
|
p.y = HALF_PI;
|
}
|
else if (Math.abs(up + 1) < EPSLN) {
|
p.x = this.long0;
|
p.y = -1 * HALF_PI;
|
}
|
else {
|
p.y = phi2z(this.e, ts);
|
p.x = adjust_lon(this.long0 - Math.atan2(sp * Math.cos(this.gamma0) - vp * Math.sin(this.gamma0), Math.cos(this.bl * us / this.al)) / this.bl);
|
}
|
return p;
|
};
|
|
exports.names = ["Hotine_Oblique_Mercator", "Hotine Oblique Mercator", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin", "Hotine_Oblique_Mercator_Azimuth_Center", "omerc"];
|