墨卡托投影,是正轴等角圆柱投影,又称等角圆柱投影,圆柱投影的一种,由荷兰地图学家墨卡托(G. Mercator)于1569年创拟。为地图投影方法中影响最大的。
设想一个与地轴方向一致的圆柱切于或割于地球,按等角条件将经纬网投影到圆柱面上,将圆柱面展为平面后,得平面经纬线网。投影后经线是一组竖直的等距离平行直线,纬线是垂直于经线的一组平行直线。各相邻纬线间隔由赤道向两极增大。一点上任何方向的长度比均相等,即没有角度变形,而面积变形显著,随远离基准纬线而增大。该投影具有等角航线被表示成直线的特性,故广泛用于编制航海图和航空图等。
墨卡托投影,是一种"等角正切圆柱投影”,由荷兰地图学家墨卡托(Gerhardus Mercator 1512-1594)在1569年拟定。
假设地球被围在一中空的圆柱里,其基准纬线与圆柱相切(赤道)接触,然后再假想地球中心有一盏灯,把球面上的图形投影到圆柱体上,再把圆柱体展开,这就是一幅选定基准纬线上的“墨卡托投影”绘制出的地图。 墨卡托投影没有角度变形,由每一点向各方向的长度比相等,它的经纬线都是平行直线,且相交成直角,经线间隔相等,纬线间隔从基准纬线处向两极逐渐增大。墨卡托投影的地图上长度和面积变形明显,但基准纬线处无变形,从基准纬线处向两极变形逐渐增大,但因为它具有各个方向均等扩大的特性,保持了方向和相互位置关系的正确。在地图上保持方向和角度的正确是墨卡托投影的优点,墨卡托投影地图常用作航海图和航空图,如果循着墨卡托投影图上两点间的直线航行,方向不变可以一直到达目的地,因此它对船舰在航行中定位、确定航向都具有有利条件,给航海者带来很大方便。中华人民共和国国家标准“海底地形图编绘规范”(GB/T 17834-1999)中5.1.3.1款规定 1:25万及更小比例尺图采用墨卡托投影,基本比例尺图(即1:5万,1:25万,1:100万)采用统一基准纬线30°,非基本比例尺图以制图区域中纬为基准纬线。基准纬线取至整度或整分。
百度地图和Google Maps使用的投影方法都是墨卡托投影。
经过墨卡托投影后的经线是均匀分布,在此主要介绍纬度的变换方法。
墨卡托投影把纬度为Φ (-90°<Φ<90°)的点投影到:y = sign(Φ)*ln(tan(45° + abs(Φ/2))
其中:
当Φ<0时,sign(Φ)=-1;
当Φ=0时,sign(Φ)=0;
当Φ>0时,sign(Φ)=1;
abs(Φ)是Φ的绝对值。
这种投影算法使得赤道附近的纬线较密,极地附近的纬线较稀。极点被投影到无穷远,所以这种投影不适合在高纬度地区使用。Google Maps的选取的范围为 -π 以上知识即可实现编程转换。 墨卡托投影有以下特点: 墨卡托投影是按等角条件修改透视圆筒投影而得到的投影。 等角(也称为保形)是指当地图上任何一点的各方向具有相同的比例,称为局部保形,透视圆筒投影如下图所示: 墨卡托投影对透视圆筒投影改造点:要使圆筒投影称为等角的性质,必须使由赤道向两极经线逐渐伸长的倍数与经线上各点相应的纬度扩大的倍数相同。 地球赤道的圆周长为2ΠR(R为赤道半径),而各纬线圈周长为2ΠR(表示对应的纬度),因此,墨卡托投影地图上纬线长与地球上实际纬线长的比值为: 既然各纬度的纬线扩大(正割)倍,为了保持等角,各纬线通过处的经线也要相应的扩大倍。 这时,经线方向上的长度比才能与纬线方向上的长度比相等。 注意:投影地图上经纬线的伸长与纬度的正割成比例变化,随纬度增高极具拉伸,到极点成为无穷大;面积的扩大更为明显,在的地方面积要扩大四倍(因为 = 2,面积比是长度比的两倍,所以是四倍)。如下图所示,地理上等半径圆在高纬度面积明显扩大。 俄罗斯的领土面积为1700万平方千米,我国是960万平方千米,俄罗斯不到我国的2倍大。但是看看下面我们最常见的世界地图,目测俄罗斯差不多是中国的3倍大。为什么会这样呢? 我们经常称欧美为西方国家,中国为东方国家。但地图上美国明明在我国右边,也就是东边,为什么呢? 要解释这些,要从我们常用的世界地图的绘制方法和原理入手。地球是近似于圆形的球体,如地球仪展示的。而我们在手机、电脑或者纸上最常见的世界地图是一个平面图。一个球的表面和一个平面是怎么相互转换的呢,方法如下图。 用一张纸卷成圆柱,围住地球仪;然后在地球仪的球心放一个发光的灯泡,地球仪上的地图会在圆柱纸上形成投影;把这张纸平展开,就是我们常见平面世界地图。 上面所讲的投影法叫墨卡托投影(Mercator Projection),广泛应用于航海和航空领域,是我们最常接触到的世界地图的绘法。还有其它诸多的绘法如兰勃特投影、高斯投影等,应用在各专业领域。地图学是一门严谨的科学,需要数学模型和精确的公式计算,再做近似处理,墨卡托投影数学模型如下。 地形面积按墨卡托投影投射到平面后是有一定变形的,纬度越高,也就是越靠近两极变形越大。如下图,红色圆圈实际面积是一样大的,但投影到平面后,靠近两极的就变得更大了,赤道附近的变形就小。 所以真实面积比例的世界地图如下图,附上动态对比图。这就能解释为什么俄罗斯面积看起来有3倍中国大了。 我们看到的世界地图大部分是太平洋在中间,环太平洋国家都能够清晰的展示出来。中国也在比较居中的位置,所以我们国内看到的大部分是这个角度的地图。西方国家很多地图则转了一个角度,0度经线和纬线在居中位置,如下图,这样看来中国在最右边。这就能解释为什么中国被称为东方国家了。 我们都知道格陵兰岛是世界最大的岛屿,如果真的像我们在地图上看到的那样,它的面积跟非洲差不多的话,那它早就晋升为大陆了,就不能称之为岛屿了。所以,这就是墨卡托投影的弊端,我们从地图上看到的国家面积是不能直接比较大小的。不仅如此,世界地图上的比例尺也是不精准的,因为面积发生改变,长度肯定也会有所改变。高纬度形变大,低纬度形变小,所以用同一个比例来统一衡量,肯定是不准确的。 世界地图的绘制方法千奇百怪,墨卡托投影法属于舍弃面积,保留其它属性。那么另一种非主流的地图绘制法高尔-皮德斯投影就属于舍弃形状,保留面积。上图中,我们可以看到这种绘制方法下的世界地图,非洲的面积在图上差不多是14个格陵兰岛,这也和实际情况符合。但陆地形状却已经严重扭曲了。 无论用哪种绘制方法都会产生属性的缺失,选择最适合我们的世界地图才是关键的。400多年前为了满足航海需要,墨卡托发明了墨卡托投影法,以扭曲地图为代价,使经纬线在平面的地图上相互垂直,航海家们只需要将起点和终点在平面上连成一条直线,就可以知道航线与经纬线的角度,这才方便确定方位,我们称之为等角航线。在那个大航海时代,这个诞生的地图绘法能很好的帮助船只规划航线,在海上为船只导航,从而获得了大量的推广和应用。 以前没有卫星定位导航,航海船长使用的是罗盘导航,类似指南针。墨卡托地图经线和纬线都是横竖垂直的,和地球一致。如果从一个地方开船去另一个地方,在地图上将2个地点连成一条直线,然后就可以量出这条直线和经纬线的夹角。在海面上,罗盘上的指南针相当于经线(地球的两个磁极和地理的南北极只是接近,不完全重合),船头航行方向和指南针有夹角,当始终保持这个夹角和地图上的夹角一致时,就能抵达目的地。 当然航海还需要太阳、月亮、星星等天文知识和丰富的海上经验以帮助判断,纠正偏差才能顺利在海上找到方向。 地图上2点之间连成的直线,在航海上叫等角航线。等角线在实际球体的表面是一条曲线,向两极螺旋盘卷,如下图。现代因为有更先进的太空卫星导航,航空和航海走的大部分是大圆航线。起点,终点和地心这三个点可以确定一个面,用这个面去切地球,和地表相交形成的弧线就是大圆线,是地表两个点之间的最短路径。大圆航线明显要比等角航线路程要短,特别是纬度跨度大的远距离。如下图部分全球大圆航空线。 平面地图上的直线,反映到地球三维的球形上,其实是一条曲线,所以说等角航线在行驶过程中,实际是一条曲线,并不是最短路径。几百年前的航海家,在墨卡托投影下的地图中走了远路,但定位精准,最终都能到达目的地。 我们平常在地图上看到飞机的航线是曲线也是这个道理,这才是真实情况下的最短路径。飞机实际飞行过程在地球三维的球面上,这个三维空间的最短的路径,在二维面上就变成了一条曲线,也叫大圆航线。 在墨卡托地图发明以前,存在过上千种奇形怪状的地图,这些都是人类文明进步的曲折路。 以整个世界范围,赤道作为标准纬线,本初子午线作为中央经线,两者交点为坐标原点,向东向北为正,向西向南为负。 X轴:由于赤道半径为6378137米,则赤道周长为2*PI*r = 20037508.3427892,因此X轴的取值范围:[-20037508.3427892,20037508.3427892]。 Y轴:由墨卡托投影的公式可知,同时上图也有示意,当纬度φ接近两极,即90°时,y值趋向于无穷。这是那些"懒惰的工程师"就把Y轴的取值范围也限定在[-20037508.3427892,20037508.3427892]之间,搞个正方形。 懒人的好处,众所周知,事先切好静态图片,提高访问效率云云。俺只是告诉你为什么会是这样子。因此在投影坐标系(米)下的范围是:最小(-20037508.3427892, -20037508.3427892 )到最大 (20037508.3427892, 20037508.3427892)。 对应的地理坐标系: 按道理,先讲地理坐标系才是,比如球体还是椭球体是地理坐标系的事情,和墨卡托投影本关联不大。简单来说,投影坐标系(PROJCS)是平面坐标系,以米为单位;而地理坐标系(GEOGCS)是椭球面坐标系,以经纬度为单位。具体可参考《坐标系、坐标参照系、坐标变换、投影变换》。 经度:这边没问题,可取全球范围:[-180,180]。 参考文献: https://blog.csdn.net/chelen_jak/article/details/80415642 http://blog.geohey.com/-ge-xiao-you-xi-rang-ni-che-di-nong-dong-mo-qia-tuo-tou-ying/ https://baike.baidu.com/item/%E5%A2%A8%E5%8D%A1%E6%89%98%E6%8A%95%E5%BD%B1/5477927?fr=aladdin https://baijiahao.baidu.com/s?id=1614646233100272620&wfr=spider&for=pc https://blog.csdn.net/mr_jianrong/article/details/72625811 https://blog.csdn.net/qq_35732147/article/details/83856513#4.3%E3%80%81Web%E5%A2%A8%E5%8D%A1%E6%89%98%E6%8A%95%E5%BD%B1 墨卡托投影坐标系(Mercator Projection)原理及实现C代码墨卡托投影的特点
我们最常看到的世界地图并不真实
墨卡托坐标与经纬度相互转换C++实现
纬度:上面已知,纬度不可能到达90°,懒人们为了正方形而取的-20037508.3427892,经过反计算,可得到纬度85.05112877980659。因此纬度取值范围是[-85.05112877980659,85.05112877980659]。其余的地区怎么办?没事,企鹅们不在乎。
因此,地理坐标系(经纬度)对应的范围是:最小(-180,-85.05112877980659),最大(180, 85.05112877980659)。至于其中的Datum、坐标转换等就不再多言。//该类用于保存墨卡托坐标点
class Mercator_Point
{
public:
explicit Mercator_Point(double pos_x=0,double pos_y=0):x(pos_x),y(pos_y){ }
double getX() {
return x;
}
void setX(double x) {
this->x = x;
}
double getY() {
return y;
}
void setY(double y) {
this->y = y;
}
private:
double x;
double y;
};
//该类用于保存经纬度点
class LonLat_Point
{
public:
explicit LonLat_Point(double longitude=0, double latitude=0):Lon(longitude),La(latitude) {}
double getlongitude() {
return Lon;
}
void setlongitude(double longitude) {
this->Lon = longitude;
}
double getlatitude() {
return La;
}
void setlatitude(double latitude) {
this->La = latitude;
}
private:
double Lon; //经度
double La; //纬度
};
//经纬度转墨卡托坐标
Mercator_Point lonLatToMercator(LonLat_Point LonLat)
{
Mercator_Point mercator;
double x = (LonLat.getlongitude() * 20037508.342789 / 180);
double y = log(tan((90 + LonLat.getlatitude()) * M_PI / 360)) / (M_PI / 180);
y = (double)(y * 20037508.342789 / 180);
mercator.setX(x);
mercator.setY(y);
return mercator;
}
//墨卡托坐标转经纬度
LonLat_Point mercatorToLonLat(Mercator_Point mercator)
{
LonLat_Point lonlat;
double x = (mercator.getX() / 20037508.342789 * 180);
double y = (mercator.getY() / 20037508.342789 * 180);
y = (double)(180 / M_PI * (2 * atan( exp(y * M_PI / 180)) - M_PI / 2));
lonlat.setlongitude(x);
lonlat.setlatitude(y);
return lonlat;
}