欢迎光临散文网 会员登陆 & 注册

分享proj4js中经纬度和兰伯特投影的转换代码

2022-09-15 17:48 作者:地理信息技术杂谈  | 我要投稿

兰伯特投影简介参见百科搜索: 

兰伯特投影在气象数据的处理中,是比较常用的投影坐标系,根据不同区域、范围进行投影。

proj4是专业的坐标转换类库,有各种语言版本的,C++,java,js,python版等,可以很方便的将坐标从一个坐标系转换到另一个坐标系。在前端使用的时候,应用场景需要转换大量的坐标,就会发现使用proj4js存在性能问题,查看了一下proj4js的源代码,发现类库每次调用初始化很多不相关的类型,对象等,所以,在基础上,进行了提取。

转换代码及说明

//初始化常用的变量,直接换算成弧度,提升计算性能

var EPSLN = (typeof Number.EPSILON === 'undefined') ? 1.0e-10 : Number.EPSILON;

var conv = 180 / Math.PI;

var HALF_PI = Math.PI / 2;

var SPI = 3.14159265359;

var TWO_PI = 2 * Math.PI;

var a = 6378137;

var b = 6356752.314245179;

var e = 0.08181919084262157;

var lat1 = 0.52359877559829;

var lat2 = 1.04719755119659; 

var long0 = 1.8029251173101;

var lat0 = 0;

var k0 = 1; 

var ns;

var f0;

var rh;

//常用的转换参数,直接提取引用

var tsfnz = function(eccent, phi, sinphi) {

 var con = eccent * sinphi;

 var com = 0.5 * eccent;

 con = Math.pow(((1 - con) / (1 + con)), com);

 return(Math.tan(0.5 * (HALF_PI - phi)) / con);

 };

var sign = function(x) {

 return x < 0 ? -1 : 1;

 };

 var msfnz = function(eccent, sinphi, cosphi) {

 var con = eccent * sinphi;

 return cosphi / (Math.sqrt(1 - con * con));

 };

var adjust_lon = function(x) {

return(Math.abs(x) <= SPI) ? x : (x - (sign(x) * TWO_PI));

 };

var phi2z = function(eccent, ts) {

var eccnth = 0.5 * eccent;

var con, dphi;

var phi = HALF_PI - 2 * Math.atan(ts);

for(var i = 0; i <= 15; i++) {

con = eccent * Math.sin(phi);

dphi = HALF_PI - 2 * Math.atan(ts * (Math.pow(((1 - con) / (1 + con)), eccnth))) - phi;

phi += dphi;

if(Math.abs(dphi) <= 0.0000000001) {

  return phi;

 }

}

return -9999;

};     

//根据proj4的坐标系描述字符串,解析其中的参数

function init(prjstr) {

if(prjstr.indexOf(" ") > -1) {

var _prjArr = prjstr.split(" ");

_prjArr.forEach(function(item, index, input) {

if(item.indexOf("lat_0") > -1) {

 lat0 = parseFloat(item.split("=")[1]) / conv;

 }

 })

 }

var sin1 = Math.sin(lat1);

var cos1 = Math.cos(lat1);

var ms1 = msfnz(e, sin1, cos1);

var ts1 = tsfnz(e, lat1, sin1);

var sin2 = Math.sin(lat2);

var cos2 = Math.cos(lat2);

var ms2 = msfnz(e, sin2, cos2);

var ts2 = tsfnz(e, lat2, sin2);

var ts0 = tsfnz(e, lat0, Math.sin(lat0));

if(Math.abs(lat1 - lat2) > EPSLN) {

 ns = Math.log(ms1 / ms2) / Math.log(ts1 / ts2);

 else {

   ns = sin1;

 }

if(isNaN(ns)) {

  ns = sin1;

 }

f0 = ms1 / (ns * Math.pow(ts1, ns));

rh = a * f0 * Math.pow(ts0, ns);

}    

//经纬度坐标转换兰伯特坐标

function projCood(lon, lat) {

lon = lon / conv;

lat = lat / conv;

if(Math.abs(2 * Math.abs(lat) - Math.PI) <= EPSLN) {

lat = sign(lat) * (HALF_PI - 2 * EPSLN);

}

var con = Math.abs(Math.abs(lat) - HALF_PI);

 var ts, rh1;

 if(con > EPSLN) {

 ts = tsfnz(e, lat, Math.sin(lat));

rh1 = a * f0 * Math.pow(ts, ns);

else {

 con = lat * ns;

  if(con <= 0) {

   return null;

   }

rh1 = 0;

 }

var theta = ns * adjust_lon(lon - long0);

var nlon = (rh1 * Math.sin(theta));

var nlat = (rh - rh1 * Math.cos(theta));

 return [nlon, nlat];

 }

 //兰伯特坐标转经纬度坐标

function inverseProj(x1, y1) {

var rh1, con, ts;

var lat, lon;

var x = x1 / k0;

var y = (rh - y1 / k0);

if(ns > 0) {

rh1 = Math.sqrt(x * x + y * y);

con = 1;

else {

rh1 = -Math.sqrt(x * x + y * y);

con = -1;

 }

var theta = 0;

if(rh1 !== 0) {

theta = Math.atan2((con * x), (con * y));

  }

if((rh1 !== 0) || (ns > 0)) {

 con = 1 / ns;

 ts = Math.pow((rh1 / (a * f0)), con);

lat = phi2z(e, ts);

if(lat === -9999) {

return null;

 }

 else {

  lat = -HALF_PI;

}

 lon = adjust_lon(theta / ns + long0);

 return [lon * conv, conv * lat];

 }


对于在应用中的其他坐标系转换,同样能够在其中进行代码提取。

https://mp.weixin.qq.com/s?__biz=MzU2ODYzNzc4OQ==&mid=2247485646&idx=1&sn=4f9e87af9be3fe2c2a26a5464953666e&chksm=fc8ba8fccbfc21ea9a069c0dbae33c174bfea5b09b4a0931220f490ebbb3518e2d0fc5e478a9&token=1743499510&lang=zh_CN#rd

分享proj4js中经纬度和兰伯特投影的转换代码的评论 (共 条)

分享到微博请遵守国家法律