GPS实时位置监控及芯片获取的经纬度转百度坐标算法

最近做的项目是实时监控车载LED广告屏,通过浏览器来查看车辆位置,实时监控,车辆历史轨迹,并能设置电子围栏。这个工程完全自由发挥,领导只提意见,给了我足够的空间,设计、UI、编码都可以自己发挥。

第一版效果图

实时更新

因为是实时,那么就要不停的获得各个设备的最新地理坐标,我们公司卖出的控制卡芯片每 30 秒向服务器发送一次坐标。
最初我们是每 30 秒更新一次设备位置,效果是每30秒所有图标(marker)集体更新一次,而29秒钟页面没任何变化,很不直观。
后来的做法是将请求到的所有设备数据分批分配到这30秒钟间去更新,这样,每秒钟都有几个图标在动,体验就要好很多。

  sleepTime = i % 30;
  (function(id, sleepTime, bd09point, timestamp, current_status, speed) {
    setTimeout(function () {
...
    }, sleeptime * 1000);
  })(id, sleepTime, bd09point, timestamp, current_status, speed);
}

芯片获取的经纬度转百度坐标算法

考虑到 GPS 历史轨迹需用百度鹰眼的纠偏绑路功能效果比较好,我使用百度地图来做为基本地图,但百度用到的坐标和我们 GPS 芯片或北斗芯片获取的坐标数据不是对等的,需要转换,即用到以下的WGS84ToBD09方法。

//使用
 bd09point = WGS84ToBD09("123.49412", "43.51536");
//算法
/*>
 * HelperFunction_辅助函数 坐标转换
 * WGS84坐标系:即地球坐标系,国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系,谷歌地图采用的是WGS84地理坐标系(中国范围除外)
 * GCJ02坐标系:即火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系,谷歌中国地图和搜搜中国地图采用的是GCJ02地理坐标系
 * BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系
 */
function WGS84ToBD09(_wgsLon, _wgsLat) {
    var GCJ02 = wgs84Togcj02(_wgsLon, _wgsLat);
    var BD09 = gcj02Tobd09(GCJ02.lon, GCJ02.lat);
    return BD09;
}
function BD09ToWGS84(_bdLon, _bdLat) {
    var GCJ02 = bd09Togcj02(_bdLon, _bdLat);
    var WGS84 = gcj02Towgs84(GCJ02.lon, GCJ02.lat);
    return WGS84;
}
/*> GCJ02 to BD09 */
function gcj02Tobd09(_gcjLon, _gcjLat) {
    var x_pi = 3.14159265358979324 * 3000.0 / 180.0;
    var x = _gcjLon;
    var y = _gcjLat;
    var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
    var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
    var bdLon = z * Math.cos(theta) + 0.0065;
    var bdLat = z * Math.sin(theta) + 0.006;
    return {"lon" : bdLon,"lat" : bdLat};
}
/*> BD09 to GCJ02 */
function bd09Togcj02(_bdLon, _bdLat) {
    var x_pi = 3.14159265358979324 * 3000.0 / 180.0;
    var x = _bdLon - 0.0065;
    var y = _bdLat - 0.006;
    var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
    var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
    var gcjLon = z * Math.cos(theta);
    var gcjLat = z * Math.sin(theta);
    return {"lon" : gcjLon,"lat" : gcjLat};
}
/*> WGS84 to GCJ02 */
var PI = 3.1415926535897932384626;
var A = 6378245.0;
var E = 0.00669342162296594323;
function wgs84Togcj02(_wgsLon, _wgsLat) {
    _wgsLat = parseFloat(_wgsLat);
    _wgsLon = parseFloat(_wgsLon);
    if (outOfChina(_wgsLon, _wgsLat))
    {
        return {"lon": _wgsLon,"lat":_wgsLat};
    }
    var dLat = transformLat(_wgsLon - 105.0, _wgsLat - 35.0);
    var dLon = transformLon(_wgsLon - 105.0, _wgsLat - 35.0);
    var radLat = _wgsLat / 180.0 * PI;
    var magic = Math.sin(radLat);
    magic = 1 - E * magic * magic;
    var sqrtMagic = Math.sqrt(magic);
    dLat = (dLat * 180.0) / ((A * (1 - E)) / (magic * sqrtMagic) * PI);
    dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
    return {"lon": _wgsLon + dLon,"lat":_wgsLat + dLat};
}
/*> GCJ02 to WGS84 */
function gcj02Towgs84(_gcjLon, _gcjLat) {
    _gcjLat = parseFloat(_gcjLat);
    _gcjLon = parseFloat(_gcjLon);
    if (outOfChina(_gcjLon, _gcjLat))
    {
        return {"lon": _gcjLon,"lat":_gcjLat};
    }
    var dLat = transformLat(_gcjLon - 105.0, _gcjLat - 35.0);
    var dLon = transformLon(_gcjLon - 105.0, _gcjLat - 35.0);
    var radLat = _gcjLat / 180.0 * PI;
    var magic = Math.sin(radLat);
    magic = 1 - E * magic * magic;
    var sqrtMagic = Math.sqrt(magic);
    dLat = (dLat * 180.0) / ((A * (1 - E)) / (magic * sqrtMagic) * PI);
    dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
    return {"lon": _gcjLon - dLon,"lat":_gcjLat - dLat};
}
/*> 是否在大陆范围外 参数为芯片坐标 */
function outOfChina(_lon, _lat) {
    if (_lon < 72.004 || _lon > 137.8347) {
        return true;
    }
    if (_lat < 0.8293 || _lat > 55.8271) {
        return true;
    }
    return false;
}
function transformLat(x, y) {
    var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
    return ret;
}
function transformLon(x, y) {
    var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
    return ret;
}

芯片距离单位-海里

芯片获得的GPS距离单位是海里,需要转换成常用的公里制

/* HelperFunction_辅助函数: 海里转公里 */
function getSpeed(_haili) {
    return (_haili*1.852).toFixed(0);
}

Leave a Reply

Your email address will not be published. Required fields are marked *