使用天地图API进行坐标反查
我习惯使用奥维地图进行旅行规划。但是奥维地图的搜索系统并不是很好使,特别是一些比较「野」的地方,很多名字都搜不着。
这个时候,就需要借助于坐标拾取器来进行搜索。常用的几个地图的坐标拾取器链接如下:
- 高德:https://lbs.amap.com/tools/picker(未认证用户只能获取小数点后两位的坐标)
- 百度:https://lbs.baidu.com/maptool/getpoint(未认证用户只能获取小数点后两位的坐标)
- 腾讯:https://lbs.qq.com/getPoint
- 谷歌:https://www.google.com/maps(搜索后直接从地址栏里复制)
这里面最麻烦的是腾讯,每次搜索之前还要先选中所在地市。而最好使的则是百度,因为可以同时得到多个结果。高德和腾讯都只会返回一个结果,而这个结果大概率不是我想要的。
另外,奥维地图自带的卫星地图都是使用天地图的影像标注作为叠加层,而且其中有一些地理标记在上面的地图里都搜不到,但是却在天地图的数据库中。这时我们就需要使用天地图进行坐标反查。
可惜的是,天地图并没有提供类似上面的链接。有一个网页demo,但是也不是很好使,要显示具体的坐标还需要自己改造。
因此,我考虑直接使用它的Web服务API进行查询。
使用Web服务API,需要先注册并申请密钥。
需要注意的是,在创建应用的时候,「应用类型」要选择「服务器端」,并在「服务类型」里勾选上「地理编码服务」和「逆地理编码服务」(或者直接全选即可)。
为了不明文储存密钥,我使用了pass程序来保存并读取密钥:
1 | ## 初始化 |
1. 对地名进行地址解析
首先,是将地址数据转换为经纬度坐标,即地理编码查询,命令如下:
1 | # 地名->CSG2000坐标 |
最后使用了jq将坐标转化为了可以直接复制到奥维地图里面的形式。
2. 对坐标进行反地址解析
反过来,我们也可以将经纬度坐标转换为地址数据,即逆地理编码查询。不过需要特别注意坐标系的问题。
- 奥维地图:输入支持WSG84、GCJ-02、BD-09坐标系,输出(复制)只支持GCJ02坐标系。
- 天地图:使用CGCS2000坐标系。
不过CGCS2000坐标和WSG84坐标之间的非常接近,两者差异在±6cm以内,因此在实际使用中我们可以基本默认二者是等同的。
由奥维地图复制得到的GCJ02坐标,我们先使用coordtransform转换为WSG84坐标,然后再进行查询:
1 | # 附近GCJ02坐标->地名信息 |
中间比较繁琐的事情进行各种格式的转换:
- 奥维地图复制得到的坐标:
g95.93463182,30.73686994 - coordtransform的输入/输出格式:
{type: 'Point', coordinates: [95.934117, 30.739689]} - 天地图API的查询参数:
postStr={'lon':95.934117,'lat':30.739689,'ver':1}
3. 二者相结合
直接对地名进行解析,经常得不到想要的结果。因为我们输入的地名只有具体的名字,而相近的名字可能有多个,甚至可能返回一个相隔十万八千里的地方。
例如,在川藏中线上一个德嘎拉垭口,如果直接查询tianditu_point 德嘎拉,得到的却是拉孜县的德嘎拉的坐标,并不是我们想要的。必须查询tianditu_point 洛隆县德嘎拉才能得到正确的坐标。
原因是天地图的地理编码API需要的是结构化地址数据(如:北京市海淀区莲花池西路28号),而我一般为了方便,都只输入地点的名称。
因此,我们可以把二者结合起来,可以直接先在奥维地图要找的点附近复制经纬度(直接右击➟选择「经纬度」➟点击「复制经纬度」即可),然后先进行反解析获取地名,再转化为精确的坐标即可:
1 | tianditu_near() { |
例如,在德嘎拉垭口附近随意复制一点的坐标,然后调用:tianditu_near g95.93524611,30.73651378,即可得到:
1 | { |
将最后的坐标复制进奥维地图,即可得到对应点。
为了方便使用,我们还可以使用更好输入的别名:
1 | alias tpoint="tianditu_point" |