在进行GIS开发的过程中,对于地理数据的可视化因为国内外各个主流的开发包或者第三方地图插件所使用的坐标系并不统一再加上精确度等问题,使得数据坐标位置的匹配成为一个难点,这里根据相关资料和自己掌握的内容,对常用坐标系以及转换进行简单介绍,并以Mapbox和Unity为例,将经纬度与unity世界坐标的转换进行了代码实现。
GIS开发过程中我们常接触到的坐标系主要有三类:地理坐标系、平面投影坐标系和空间直角坐标系,以下基于此进行介绍,并对unity中坐标系进行说明。
简单来说,地理坐标系就是用经纬度来表示地面点位的球面坐标系,单位是度,其中又可分为地心坐标系和参心坐标系。
以地球质心为原点建立的空间直角坐标系,或以球心与地球质心重合的地球椭球面为基准面所建立的大地坐标系。
WGS-84、CGCS2000,都是属于地心坐标系。
参心坐标系是以参考椭球的几何中心为原点的大地坐标系,参心大地坐标系可以通过高斯投影计算转化为平面直角坐标系。
常见的参心坐标系有北京54和西安80。
简单来说,就是按照一定的数学法则(投影类型)将经纬网投影到平面上,得到基于X、Y值来表示地面点位的坐标系统,单位通常是米,按照投影的类型又可分为若干投影坐标系,投影方法很多,以下仅介绍几种常用投影坐标系,墨卡托投影、高斯-克吕格投影,UTM投影、兰伯特等角投影。
一种等角正切圆柱投影,假设把地球(椭球体)放在一个圆柱里,标准纬线与圆柱相切,然后再假想地球中心有一光源,将球面上的图形投影到圆柱上,再把这个圆柱体展开就是标准纬线的墨卡托投影。保证了方向和角度的正确性,但是离标准纬线越远。纬线的间隔会越大形状变形越严重。
国外大部分地图产商使用的是Web墨卡托投影,如Goole Map、mapbox等。和普通墨卡托投影的区别是把其中的椭球体换成了标准球体。
全称为“通用横轴墨卡托投影”,一种等角横轴割圆柱投影。椭圆柱割地球于南纬80度、北纬84度,中央经线的长度比为0.9996,投影后两条相割的经线没有变形。所有距离、方向、形状和面积在中央经线的 15º 范围内都相当准确。然而,在15°频带之外,横向墨卡托投影在尺寸、距离和方向方面的失真显著增加。横向墨卡托投影是保形的,形状在小区域中是真实的。
我国的卫星影像资料常用UTM投影。
又名"等角横切圆柱投影”,中央经线的长度不变,也是横轴墨卡托投影的变种。这种投影在长度和面积上变形都很小,且计算简便,被广泛用在大比例尺地形图的绘制上。
圆柱投影在真实展现整个地球方面较为适用,墨卡托投影是流行的导航选择,横轴墨卡托投影是大比例尺制图的理想选择。
设想用一个正圆锥切于或割于球面,应用等角条件将地球面投影到圆锥面上,然后沿一母线展开成平面。投影后纬线为同心圆圆弧,经线为同心圆半径。没有角度变形,经线长度比和纬线长度比相等。适于制作沿纬线分布的中纬度地区中、小比例尺地图。我国1:100万地形图采用兰勃特投影。
与圆柱地图不同,圆锥地图投影通常不适合绘制全球级的大尺度区域,更适合绘制大陆和区域地图。
也是unity中使用的三维坐标系,使用X,Y,Z值来表示空间中的点位,可以和经纬度坐标系进行转换,平面投影坐标系和空间直角坐标系都属于笛卡尔坐标系统。。
unity中的世界坐标就是在unity世界中的三维坐标,使用左手坐标系。其中transform.Position 是指在整个unity世界中的位置坐标 ,transform.LocalPosition 是相对于父对象位置的坐标 即局部坐标
以屏幕左下角为坐标原点,,向上为Y轴正方向,向右为X轴正方向,其Z轴坐标是相机的世界坐标中Z轴的负值。
将屏幕坐标参数标准化,其Z轴坐标是相机的世界坐标中Z轴的负值,表示深度。
原点在左上角,属于二维坐标系,Z值永远为0
底层接口(HTML5 Geolocation或ios、安卓API)通过GPS设备获取的坐标使用的是WGS-84坐标系,即原始坐标数据,国内对WGS-84数据进行了严格限制,因此国内常用地图坐标系都或多或少存在着偏差;
高德地图、腾讯地图以及谷歌中国区地图使用的是GCJ-02坐标系,也称火星坐标系,基于Wgs-84坐标系采用了一定的加密偏移算法;
百度地图使用的是BD-09坐标系,在火星坐标系基础上再次进行了加密;
mapbox等国外大部分地图使用的都是Web墨卡托(投影方法),即WGS84 Web 墨卡托投影坐标系,默认底图是从openstreetmap转入的使用Wgs-84坐标系;
坐标转换详细Python代码入口
这位博主给出的转换Python代码十分详细,转换关系如上图,这里就不再介绍了,后续作者可能会基于其他语言或者对其他坐标系进行一个坐标转换代码的编写与说明。
球面坐标转换成原点位于地球中心的笛卡尔坐标(α,β,r)→(x,y,z):
笛卡尔坐标转换成球面坐标(x,y,z)→(α,β,r):
主要为Mapbox相关函数的调用,具体函数内容可以在MapBox查看到。
(1)主要代码
mousePosScreen.z = _referenceCamera.transform.localPosition.y;
//屏幕坐标默认Z=0,这里将相机到平面的垂直距离赋给Z
var pos = _referenceCamera.ScreenToWorldPoint(mousePosScreen);
//将屏幕上的点转换到世界坐标中
var latlongDelta = _mapManager.WorldToGeoPosition(pos);
//世界坐标转经纬度,_mapManager为AbstractMap类
(2)WorldToGeoPosition详细代码
public virtual Vector2d WorldToGeoPosition(Vector3 realworldPoint)
{
var scaleFactor = Mathf.Pow(2, (InitialZoom - AbsoluteZoom));
//InitialZoom:初始地图放大系数;AbsoluteZoom:当前地图放大系数
//scaleFactor:缩放因子为2的InitialZoom - AbsoluteZoom次方
return (Root.InverseTransformPoint(realworldPoint)).GetGeoPosition(CenterMercator, WorldRelativeScale * scaleFactor);
//InverseTransformPoint:将世界空间转换为局部空间
//GetGeoPosition:得到地理坐标系,根据墨卡托坐标和WgS坐标的转换公式
//CenterMercator为中心位置的墨卡托坐标
}
(1)主要代码
Vector3 WorldPosition =_mapManager=GeoToWorldPoisition(location);
//location为当前位置经纬度
WorldPosition.y=---;
//根据需要给高度赋值,若有瓦片无需此行代码,则默认根据瓦片赋高度值
(2)详细代码
var scaleFactor = Mathf.Pow(2, (InitialZoom - AbsoluteZoom));
var worldPos = Conversions.GeoToWorldPosition(latitudeLongitude, CenterMercator, WorldRelativeScale * scaleFactor).ToVector3xz();
//墨卡托转世界坐标
return Root.TransformPoint(worldPos);
//这里根据需要将3D坐标转换世界坐标或本地坐标
博客内容主要为自己搜集资料总结,加深自己对这部分理论的理解,不能保证完全正确,仅供参考,若有错误之处,敬请指正!
部分图片源于网络,侵删!