1.介绍
1.1 GIS之坐标系
坐标系是GIS的重中之重,一般来说,工作底图平面坐标系应采用国家大地坐标系CGCS2000(或相当于精度WGS84坐标系),投影方式采用高斯-克吕格投影,高程基准采用1985国家高程基准。
1.2 地理坐标系(GCS,Geographic Coordinate System)
地理坐标系其实是用了一个规则的球面来代表地球表面。在球面上画一张经纬网,球面上的点就有了它的经纬度,这就是地球上每一点的坐标。因此,地球坐标系中的坐标是以经纬度来表示的。
1.3 我国常见的GCS-地理坐标系
坐标系名称 | 特点及用途 |
---|---|
地心坐标系 | 用于卫星测量,全球导航和地球研究 |
北京54坐标系 | 对应椭球为克拉索夫斯基椭球,平均误差29m |
西安80坐标系 | 国际大地测量与地球物理联合会第16届大会确定的坐标系 |
WGS-84坐标系 | 是目前国际上统一采用的大地坐标系,GPS也是采用此坐标系 |
大地坐标系 | 以参考椭球面为基准面 |
1.4 国内常见地图API的投影坐标系
API名称 | 投影坐标系 | 描述 |
---|---|---|
百度地图 | 百度坐标(bd09) | 在gcj_02的基础上二次加密而成 |
腾讯搜搜地图 | 火星坐标系(gcj_02) | 国家加密后坐标 |
阿里云地图 | 火星坐标系(gcj_02) | 国家加密后坐标 |
高德地图 | 火星坐标系(gcj_02) | 国家加密后坐标 |
搜狐搜狗地图 | 搜狗坐标系 | 在gcj_02的基础上二次加密而成 |
图灵51地图 | 火星坐标系(gcj_02) | 国家加密后坐标 |
火星坐标其实是国家对于地理数据的保密插件,其原理就是对真实的坐标经过人为的加偏处理算法,将真实的坐标加密成虚假的坐标,但这个加偏算法不是线性加偏,所以每个地方的偏移情况会有所不同,一般会有100m-nkM不等,所以这个坐标系被称为火星坐标系。
所有的电子地图,导航仪,都需要加入这个火星坐标的国家保密插件。其具体的工作流程如下图所示:
1.5 bd09,gcj02,wgs84三种投影坐标系相互转化(python代码)
# -*- coding: utf-8 -*-
import json
import urllib
import math
# import numpy as np
x_pi = 3.14159265358979324 * 3000.0 / 180.0
pi = 3.1415926535897932384626 # π
a = 6378245.0 # 长半轴
ee = 0.00669342162296594323 # 偏心率平方
'''
输入(经度,维度)
'''
def bd09_to_gcj02(bd_lon, bd_lat):
"""
百度坐标系(BD-09)转火星坐标系(GCJ-02)
百度——>谷歌、高德
:param bd_lat:百度坐标纬度
:param bd_lon:百度坐标经度
:return:转换后的坐标列表形式
"""
x = bd_lon - 0.0065
y = bd_lat - 0.006
z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
gg_lng = z * math.cos(theta)
gg_lat = z * math.sin(theta)
return [gg_lng, gg_lat]
def gcj02_to_wgs84(lng, lat):
"""
GCJ02(火星坐标系)转GPS84
:param lng:火星坐标系的经度
:param lat:火星坐标系纬度
:return:
"""
if out_of_china(lng, lat):
return [lng, lat]
dlat = _transformlat(lng - 105.0, lat - 35.0)
dlng = _transformlng(lng - 105.0, lat - 35.0)
radlat = lat / 180.0 * pi
magic = math.sin(radlat)
magic = 1 - ee * magic * magic
sqrtmagic = math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
mglat = lat + dlat
mglng = lng + dlng
return [lng * 2 - mglng, lat * 2 - mglat]
def bd09_to_wgs84(bd_lon, bd_lat):
lon, lat = bd09_to_gcj02(bd_lon, bd_lat)
return gcj02_to_wgs84(lon, lat)
def bd09_to_wgs84(bd_lon, bd_lat):
lon, lat = bd09_to_gcj02(bd_lon, bd_lat)
return gcj02_to_wgs84(lon, lat)
def gcj02_to_bd09(lng, lat):
"""
火星坐标系(GCJ-02)转百度坐标系(BD-09)
谷歌、高德——>百度
:param lng:火星坐标经度
:param lat:火星坐标纬度
:return:
"""
z = math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * x_pi)
theta = math.atan2(lat, lng) + 0.000003 * math.cos(lng * x_pi)
bd_lng = z * math.cos(theta) + 0.0065
bd_lat = z * math.sin(theta) + 0.006
return [bd_lng, bd_lat]
def wgs84_to_gcj02(lng, lat):
"""
WGS84转GCJ02(火星坐标系)
:param lng:WGS84坐标系的经度
:param lat:WGS84坐标系的纬度
:return:
"""
if out_of_china(lng, lat): # 判断是否在国内
return [lng, lat]
dlat = _transformlat(lng - 105.0, lat - 35.0)
dlng = _transformlng(lng - 105.0, lat - 35.0)
radlat = lat / 180.0 * pi
magic = math.sin(radlat)
magic = 1 - ee * magic * magic
sqrtmagic = math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
mglat = lat + dlat
mglng = lng + dlng
return [mglng, mglat]
def wgs84_to_bd09(lon, lat):
lon, lat = wgs84_to_gcj02(lon, lat)
return gcj02_to_bd09(lon, lat)
def out_of_china(lng, lat):
"""
判断是否在国内,不在国内不做偏移
:param lng:
:param lat:
:return:
"""
return not (lng > 73.66 and lng < 135.05 and lat > 3.86 and lat < 53.55)
def _transformlng(lng, lat):
ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
math.sin(2.0 * lng * pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(lng * pi) + 40.0 *
math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
return ret
def _transformlat(lng, lat):
ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \
0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
math.sin(2.0 * lng * pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(lat * pi) + 40.0 *
math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
math.sin(lat * pi / 30.0)) * 2.0 / 3.0
return ret