#分享 , #编码
前文 用workflow转换Google地图kmz数据为geojson数据 中提到了我是如何获取Google Map里MyMap的数据,并自动转换为GeoJSON数据应用在博客上的。
但是最近在查看我更新的地点时,发现有部分数据实际应用在Mapbox中会存在偏差,导致很多定位在陆地上的地点漂移到了江河之上。比如这个 重庆来福士广场
就漂移到了长江上。
其实这个问题我发现已经满久的了,之前也咨询了一下 昱行 和 大发哥,不过他们的给的方案我没太弄明白,当时碍于技术问题一直处于搁置状态,最近因为重新更新了地点,又把这个问题给勾了起来。
不过这次这个问题让我联想起之前在将华为的数据导入到Strava时好像也遇到过,同样也是坐标偏移的问题,当时同步软件里有个「使用XX坐标系」的选项,启用之后重新同步的数据就可以在Strava正常显示了。
所以我尝试找了个坐标系在线转换工具 EasyMap ,这个工具可以很方便的进行多种坐标系的互相转换,我试着将转换好的GeoJSON数据复制进去,并转换成WGS84坐标系后在贴到 Mapbox 的在线 GeoJSON 工具 https://geojson.io/ 中预览,发现定位已经正确显示,应该可以确定就是这个问题。
奇怪的是我之前查过GoogleMap的坐标系标准就是WGS84呀?为什么实际上是GCJ02呢?
接下来就是修改上次的转换代码,在获取定位坐标的时候想办法将坐标进一步转换成WGS84坐标系即可。
幸运的是Github有大佬分享了一个基于python的互转脚本 coordTransform_py
,该脚本提供了以下特性,同时还提供了一个js版本:
此模块用于百度坐标系(bd-09)、火星坐标系(国测局坐标系、gcj02)、WGS84坐标系的相互转换,并提供中文地址到坐标的转换功能,仅使用Python标准模块,无其他依赖。
中文地址到坐标转换使用高德地图API,需要申请API KEY。
需要js版本可以移步coordtransform
所以我们在之前 convert_kmz_to_geojson.py
文件中引入该库,并对坐标进行处理:
import os
import sys
import json
import zipfile
import xml.etree.ElementTree as ET
from shapely.geometry import shape, Point, LineString, Polygon, mapping
from coordTransform_utils import gcj02_to_wgs84 # 引入gcj02 to wgs84的转入函数
def convert_kmz_to_geojson(kmz_file_path, geojson_file_path):
with zipfile.ZipFile(kmz_file_path, 'r') as kmz:
kml_content = kmz.read('doc.kml')
root = ET.fromstring(kml_content)
geojson_content = kml_to_geojson(root)
with open(geojson_file_path, 'w') as geojson_file:
json.dump(geojson_content, geojson_file, indent=4)
def kml_to_geojson(element):
geojson = {
"type": "FeatureCollection",
"features": []
}
for placemark in element.iterfind('.//{http://www.opengis.net/kml/2.2}Placemark'):
feature = {
"type": "Feature",
"properties": {},
"geometry": None
}
for name in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}name'):
feature["properties"]["name"] = name.text
for description in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}description'):
feature["properties"]["description"] = description.text
for point in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}Point'):
coords = point.find('{http://www.opengis.net/kml/2.2}coordinates').text.strip()
lon, lat, _ = map(float, coords.split(','))
# 在获取坐标时进行转换
feature["geometry"] = mapping(Point(gcj02_to_wgs84(lon, lat)[0], gcj02_to_wgs84(lon, lat)[1]))
for linestring in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}LineString'):
coords = linestring.find('{http://www.opengis.net/kml/2.2}coordinates').text.strip()
points = [tuple(map(float, coord.split(',')))[:2] for coord in coords.split()]
feature["geometry"] = mapping(LineString(points))
for polygon in placemark.iterfind('.//{http://www.opengis.net/kml/2.2}Polygon'):
outer_boundary = polygon.find('.//{http://www.opengis.net/kml/2.2}outerBoundaryIs')
if outer_boundary is not None:
coords = outer_boundary.find('.//{http://www.opengis.net/kml/2.2}coordinates').text.strip()
points = [tuple(map(float, coord.split(',')))[:2] for coord in coords.split()]
feature["geometry"] = mapping(Polygon([points]))
if feature["geometry"] is not None:
geojson["features"].append(feature)
return geojson
if __name__ == "__main__":
# kmz_file_path = "sys.argv[1]"
# geojson_file_path = sys.argv[2]
kmz_file_path = "downloaded_file.kmz"
geojson_file_path = "downloaded_file.json"
convert_kmz_to_geojson(kmz_file_path, geojson_file_path)
目前足迹功能还会出现比较卡的情况,但是目前还没处理头绪,幸运的卡顿只是略微影响使用,就留待下次处理把。
加入评论