您的位置 首页 > 数码极客

如何利用高德api批量转换坐标

LBS,基于位置的服务(Location Based Service),近年来已经无处不在,尤其是我们前端,相信或多或少都有接触一些地图API服务,比如高德、百度啊、谷歌啊~ 但是用的时候可能看到下面这些字眼:比如BD09、火星坐标、WGS84……不由得还是蒙圈了啊

那么接下来,我们就来了解一下,关于当前用到的一些互联网地图的基础坐标转换知识~

0、首先给大家出一个题

地图上的经纬度转换到平面坐标时,和平面坐标的XY的对应关系是什么,就是经度(longitude)和维度(latitude)分别给对应X,Y中的谁?

这是在实际中经常会用到的一个知识点,我之前没有想太多,反正就把数值往里尝试,因为位置差异很大,正确还是错误一眼就看出来了的,但是这样其实很不好,被师兄说了,我一个GISer的连这个都弄不明白不应该,哈哈哈。不求甚解是可以的,但是专业性还是要强化的。

来看看上面的图:经纬度大家都知道,地球上横线是纬度,纵线是经度。这也导致了我们下意识就会觉得,横线是X,纵线是Y。这样的认知显然是错误的。

但其实,横线是刻画了Y轴上的刻度,纵线是刻画了X轴上的刻度,这里要用到投影的角度来看问题。

所以大家要记住经纬XY:

  • 经度 (longitude) —— 对应 X

  • 维度 ( latitude ) —— 对应 Y

一、当前互联网地图的坐标系现状

1.地球坐标 (WGS84)

国际标准,从专业 GPS 设备中取出的数据的坐标系。国际地图提供商使用的坐标系。

2.火星坐标 (GCJ-02)也叫国测局坐标系

中国标准,从国行移动设备中定位获取的坐标数据使用这个坐标系。

国家规定: 国内出版的各种地图系统(包括电子形式),必须至少采用GCJ-02对地理位置进行首次加密。

3.百度坐标 (BD-09)

百度标准,百度 SDK,百度地图,Geocoding 使用(百度在火星坐标上的二次加密)。

二、互联网在线地图使用的坐标系

火星坐标系:

  • iOS 地图(其实是高德)

  • Gogole地图

  • 搜搜、阿里云、高德地图

百度坐标系:当然只有百度地图

WGS84坐标系:国际标准,谷歌国外地图、osm地图等国外的地图一般都是这个。

三、从设备获取经纬度(GPS)坐标

如果使用的是百度sdk那么可以获得百度坐标(bd09)或者火星坐标(GCJ02),默认是bd09。

如果使用的是ios的原生定位库,那么获得的坐标是WGS84。

如果使用的是高德sdk,那么获取的坐标是GCJ02。

四、坐标转换方法--JS版本

我在之前的一篇文章里,基于Ionic框架的使用讲到了地图定位:ionic2入门教程(六)地图服务(谷歌、高德、百度定位),现在重新写一个小demo来实现我们的坐标转换。

关于方法,我找到了应该是最通用的一种,源码地址——作者wandergis,大部分的转换方式应该都是基于他的这个版本,相关说明也是最清楚的。

实际中我们可能会用到不同的地图,那么就对应到不同坐标系的转换,比如说,你有一份wgs84的数据服务,你要展现在百度或者高德地图上,这时候你就需要转换了。

我这里的例子是,我用到百度搜索地名,得到经纬度,但是我要将它绘制在以84为坐标系的地图leaflet之上,这时候我就需要将返回的经纬度进行转换。

我们先用百度搜索广州塔,定位中心

基于我们选择的OpenStreetMap,未转换之前,我们用百度搜索广州塔返回的值画点,可以看出很明显是偏移了的:

<h1>百度地名搜索</h1> <input type="text" id="searchVal"> <button id="searchBtn">广州市内搜索</button> <div id="map1"> </div> <script> var searchBtn = document.getElementById('searchBtn'); var mymap = L.map('map1').setView([39.897445, 116.331398], 13); L.tileLayer( '{id}/{z}/{x}/{y}.png?access_token=;, { maxZoom: 18, attribution: 'Map data &copy; <a href=";>OpenStreetMap</a> contributors, ' + '<a href=";>CC-BY-SA</a>, ' + 'Imagery © <a href=";>Mapbox</a>', id: 'ma; }).addTo(mymap); // 创建地址解析器实例 = function () { var searchVal = document.getElementById('searchVal').value; var myGeo = new BMap.Geocoder(); // 将地址解析结果显示在地图上,并调整地图视野 myGeo.getPoint(searchVal, function (point) { if (point) { con(point); L.marker([]).addTo(mymap); mymap.setView([],15); } else { alert("您选择地址没有解析到结果!"); } }, "广州市"); }

转换代码如下:

/** * copy from * Created by Wandergis on 2015/7/8. * 提供了百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换 *///UMD魔法代码// if the module has no dependencies, the above pattern can be simplified to(function (root, factory) { if (typeof define === 'function' && de) { // AMD. Register as an anonymous module. define([], factory); } else if (typeof module === 'object' && module.exports) { // Node. Does not work with strict CommonJS, but // only CommonJS-like environments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.coordtransform = factory(); } }(this, function () { //定义一些常量 var x_PI = 3.149324 * 3000.0 / 180.0; var PI = 3.14932384626; var a = 6378245.0; var ee = 0.00669342162296594323; /** * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换 * 即 百度 转 谷歌、高德 * @param bd_lon * @param bd_lat * @returns {*[]} */ var bd09togcj02 = function bd09togcj02(bd_lon, bd_lat) { var bd_lon = +bd_lon; var bd_lat = +bd_lat; var x = bd_lon - 0.0065; var y = bd_lat - 0.006; var z = Ma(x * x + y * y) - 0.00002 * Ma(y * x_PI); var theta = Ma(y, x) - 0.000003 * Ma(x * x_PI); var gg_lng = z * Ma(theta); var gg_lat = z * Ma(theta); return [gg_lng, gg_lat] }; /** * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换 * 即谷歌、高德 转 百度 * @param lng * @param lat * @returns {*[]} */ var gcj02tobd09 = function gcj02tobd09(lng, lat) { var lat = +lat; var lng = +lng; var z = Ma(lng * lng + lat * lat) + 0.00002 * Ma(lat * x_PI); var theta = Ma(lat, lng) + 0.000003 * Ma(lng * x_PI); var bd_lng = z * Ma(theta) + 0.0065; var bd_lat = z * Ma(theta) + 0.006; return [bd_lng, bd_lat] }; /** * WGS84转GCj02 * @param lng * @param lat * @returns {*[]} */ var wgs84togcj02 = function wgs84togcj02(lng, lat) { var lat = +lat; var lng = +lng; if (out_of_china(lng, lat)) { return [lng, lat] } else { var dlat = transformlat(lng - 105.0, lat - 35.0); var dlng = transformlng(lng - 105.0, lat - 35.0); var radlat = lat / 180.0 * PI; var magic = Ma(radlat); magic = 1 - ee * magic * magic; var sqrtmagic = Ma(magic); dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); dlng = (dlng * 180.0) / (a / sqrtmagic * Ma(radlat) * PI); var mglat = lat + dlat; var mglng = lng + dlng; return [mglng, mglat] } }; /** * GCJ02 转换为 WGS84 * @param lng * @param lat * @returns {*[]} */ var gcj02towgs84 = function gcj02towgs84(lng, lat) { var lat = +lat; var lng = +lng; if (out_of_china(lng, lat)) { return [lng, lat] } else { var dlat = transformlat(lng - 105.0, lat - 35.0); var dlng = transformlng(lng - 105.0, lat - 35.0); var radlat = lat / 180.0 * PI; var magic = Ma(radlat); magic = 1 - ee * magic * magic; var sqrtmagic = Ma(magic); dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); dlng = (dlng * 180.0) / (a / sqrtmagic * Ma(radlat) * PI); var mglat = lat + dlat; var mglng = lng + dlng; return [lng * 2 - mglng, lat * 2 - mglat] } }; var transformlat = function transformlat(lng, lat) { var lat = +lat; var lng = +lng; var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Ma(lng)); ret += * Ma * lng * PI) + 20.0 * Ma * lng * PI)) * 2.0 / 3.0; ret += * Ma(lat * PI) + 40.0 * Ma(lat / 3.0 * PI)) * 2.0 / 3.0; ret += * Ma(lat / 12.0 * PI) + 320 * Ma(lat * PI / 30.0)) * 2.0 / 3.0; return ret }; var transformlng = function transformlng(lng, lat) { var lat = +lat; var lng = +lng; var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Ma(lng)); ret += * Ma * lng * PI) + 20.0 * Ma * lng * PI)) * 2.0 / 3.0; ret += * Ma(lng * PI) + 40.0 * Ma(lng / 3.0 * PI)) * 2.0 / 3.0; ret += * Ma(lng / 12.0 * PI) + 300.0 * Ma(lng / 30.0 * PI)) * 2.0 / 3.0; return ret }; /** * 判断是否在国内,不在国内则不做偏移 * @param lng * @param lat * @returns {boolean} */ var out_of_china = function out_of_china(lng, lat) { var lat = +lat; var lng = +lng; // 纬度3.86~53.55,经度73.66~135.05 return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55); }; return { bd09togcj02: bd09togcj02, gcj02tobd09: gcj02tobd09, wgs84togcj02: wgs84togcj02, gcj02towgs84: gcj02towgs84 } }));

坐标转换后显示如下,我们需要将百度坐标转成火星坐标再转成wgs84,因为我们用的地图是openstreet,是wgs84坐标系。

可以看到,下面中三个点中,有一个已经是正确了的

myGeo.getPoint(searchVal, function (point) { if (point) { con(point); // bd09->gcj02 var myPoint = coord, ); con(myPoint); // gcj02->wgs84 var myPoint2 = coord(myPoint[0], myPoint[1]); con(myPoint2); var latlng = L.latLng([myPoint[1], myPoint[0]]); var latlng2 = L.latLng([myPoint2[1], myPoint2[0]]); // 画点 L.marker(point).addTo(mymap); L.marker(latlng).addTo(mymap); L.marker(latlng2).addTo(mymap); // 设置中心 mymap.setView([, ], 13); } else { alert("您选择地址没有解析到结果!"); } }, "广州市");

源码:

五、EPSG:3857

如果你用到了leaflet/openlayers/arcgis jsAPI的话,应该还有一个点需要了解。

这个算是题外话,因为一般都是学gis的才会用到这些,一般情况下百度高德这些大概都能够满足需求了。

像用到这些地图的情况,经常会涉及到EPSG:3857 或者OpenLayers:900913,acrgis: 102100(3857)。

EPSG:3857 其实是EPSG协会(European Petroleum Survey Group)为 Web Wercator 最终设立的WKID,也就是现在我们常用的Web 地图的坐标系,并且给定官方命名 “WGS 84 / Pseudo-Mercator“。

Web Mercator 是一个投影坐标系统,其基准面是 WGS 1984 。

WGS 1984 是一个长半轴(a)为6378137,短半轴(b)为6356752.314245179 的椭球体,扁率(f)为298.257223563,f=(a-b)/a 。

但是,Web Mercator 坐标系使用的投影方法不是严格意义的墨卡托投影而是一个被 EPSG称为伪墨卡托的投影方法,这个伪墨卡托投影方法的大名是 Popular Visualization Pseudo Mercator,PVPM。

Google 最先发明了这套系统,在投影过程中,将表示地球的参考椭球体近似的作为正球体处理(正球体半径 R = 椭球体半长轴 a)。

后来,Web Mercator 在 Web 地图领域被广泛使用,这个坐标系就名声大噪。尽管这个坐标系由于精度问题一度不被GIS专业人士接受,但最终 EPSG 还是给了 WKID:3857。

所以其实看到EPSG:3857,就知道,当前的坐标系是wgs84,而这个属性,通常在地图的默认设置中。就是说,如果你不改,这些地图就应该是wgs84坐标系。

六、坐标转换方法--TS版本(待完成)

如果对你有帮助的话,能否考虑打赏a cup of coffee,比心。

最后是老师整理的一些资料,全套的前端视频,还包含代码简洁,企业模式下的技能学习应用,比学校课堂讲的更适合工作和实践,价值得有3万吧,顶一个月工资了都,不过放着也是放着,分享出来大家不用去大海捞针的收集,想要的评论区评论或者私信“领资料”就可以了。

责任编辑: 鲁达

1.内容基于多重复合算法人工智能语言模型创作,旨在以深度学习研究为目的传播信息知识,内容观点与本网站无关,反馈举报请
2.仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证;
3.本站属于非营利性站点无毒无广告,请读者放心使用!

“如何利用高德api批量转换坐标”边界阅读