OpenLayers中的球面墨卡托投影
最近看OpenLayers,研究到地图投影时找到官方的文档,就翻译了一下,由于英文能力差,翻译不好的地方,请看原文
原文地址:http://docs.openlayers.org/library/spherical_mercator.html
球面墨卡托投影
该文档说明了什么是球面墨卡托投影以及何时使用该投影。文档中包含一些必要的背景知识、商用图层的代码演示、添加WMS图层以及使用OpenLayers进行投影变换的内容。要求读者对投影变换和OpenLayers有一个基本的了解。
什么是球面墨卡托投影?
球面墨卡托投影在OpenLayers community版本和其他OSG community版本中都有使用。Google Maps,微软Virtual Earth,Yahoo Maps和其他商业地图API的提供者都使用该投影。
该投影是将地球当作一个球体而不是椭球体,然后应用墨卡托投影的方法,将地图投影到一个地图平面上。
为了正确的在商业地图API上叠加地图数据,就必须使用该投影。最基本的是在商业地图API上显示栅格瓦片地图——例如TMS,WMS以及其他类似的瓦片。
为了更好的使用商业地图API,基于Google Maps的数据生成人员也需要使用该投影。最基本的例如OpenStreetMap,栅格地图瓦片都是使用的“球面墨卡托投影”。
GIS中,通常用“EPSG”的代码来表示一种地图投影。最常用的“EPSG:4326”,在地图上将经纬度直接当作X /Y对待。球面墨卡托投影在官方指定的代码为EPSG:3785。但是在官方发布之前,很多软件已经使用了EPSG:900931代码来表示该投影,OpenLayers仍然使用这个非官方的代码。看到“EPSG:4326”字符,就是经纬度坐标的描述,看到“EPSG:900931”则是用“米”做单位的x/y坐标的描述。
创建地图
首先我们创建一个使用球面墨卡托投影的地图。在这里我们使用基于微软Virtual Earth API的地图。以下的HTML代码将在地图中用到。
1 <html>
2 <head>
3 <title>OpenLayers Example</title>
4 <script src='http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1'></script>
5 <script src="http://openlayers.org/api/OpenLayers.js%22%3E%3C/script>
6 </head>
7 <body>
8 <div style="width:100%; height:100%" id="map"></div>
9 <script defer='defer' type='text/javascript'>
10 // Code goes here
11 </script>
12 </body>
13 </html>
就下来添加Virtual Earth图层作为地图的基础图层
1 var map = new OpenLayers.Map('map');
2 var layer = new OpenLayers.Layer.VirtualEarth("Virtual Earth",
3 {
4 sphericalMercator: true,
5 maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34)
6 });
7 map.addLayer(layer);
8 map.zoomToMaxExtent();
这样就创建了一副地图。像这样的地图,应该着重注意:setCenter不能再使用经纬度坐标,而应该是投影以后以“米”为单位的坐标。你可以拖动该地图,但是如果你不理解球面墨卡托投影,接下来做任何功能都将非常困难。
该地图的maxResolution根据一些默认值进行计算,通常球面墨卡托投影的地图范围是经度-180~180,纬度-85.0511~85.0511,这是因为墨卡托投影两极将变形到无穷远处,必须排除掉北极和南极区域,剩下的区域投影后正好是一个正方形,投影后的范围是从 -20037508.34到20037508.34。
地图的maxResolution默认值的计算方法是:将该范围匹配在边长为256像素的图片上,结果maxResolution的值就是156543.0339。在图层中默认的就是该值,不需要通过图层options来设置了。
如果将球面墨卡托投影的WMS或者TMS图层作为一个单独的图层,需要指定图层的maxResolution属性,另外还需要定义该图层的maxExtent。
使用投影坐标
OpenLayers提供了在客户端进行投影变换的工具,可以将经纬度坐标转换为球面墨卡托坐标。文档中首先在setCenter或者其他函数中需要使用坐标转换,接着演示如何通过使用map的displayProjection选项来将地图的坐标系显示为其他的投影坐标。
Points,Bounds投影变换
首先创建一个投影对象作为默认的投影,标准的经纬度投影的字符串是“EPSG:4326”——基于WGS84的参考椭球面(如果你的数据和Google Maps匹配很准,就是这种投影)。
接着创建一个对象保存你的坐标,然后转换
var proj = new OpenLayers.Projection("EPSG:4326");
var point = new OpenLayers.LonLat(-71, 42);
point.transform(proj, map.getProjectionObject());
该点已经转换为球面墨卡托投影坐标,你可以传递给map的setCenter方法:
map.setCenter(point);
也可以直接在setCenter中调用:
var proj = new OpenLayers.Projection("EPSG:4326");
var point = new OpenLayers.LonLat(-71, 42);
map.setCenter(point.transform(proj, map.getProjectionObject()));
通过这种方法,可以使用经纬度坐标来设置地图中心。
还可以使用相同的方法来投影变换OpenLayers.Bounds对象:同样用Bounds对象的transfrom方法:
var bounds = new OpenLayers.Bounds(-74.047185, 40.679648, -73.907005, 40.882078)
bounds.transform(proj, map.getProjectionObject());
坐标变换后替换掉原来的对象,因此不需要重新定义一个变量。
Geometries的投影变换
Geometry对象和LonLat与Bounds对象一样拥有坐标转换方法。在你的应用程序代码中创建的geometry对象添加到图层上之前,应该先进行坐标转换,同样从图层获取得到的geometry对象在别的地方使用,也需要坐标转换。
由于所有的坐标转换都是更新对象自身,所以想添加一个geometry到图层上,不应该直接调用转换方法,而是克隆一个geometry对象后再调用:
var feature = vector_layer.features[0];
var geometry = feature.geometry.clone();
geometry.transform(layerProj, targetProj);
矢量数据的投影变换
创建一副带投影的地图后,很可能需要将矢量数据进行投影变换然后添加到基础地图上,完成这个工作,只需要简单的设置好矢量数据的投影,并确定地图的投影就可以了。
var map = new OpenLayers.Map("map", {
projection: new OpenLayers.Projection("EPSG:900913")
});
var myBaseLayer = new OpenLayers.Layer.Google("Google",
{'sphericalMercator': true,
'maxExtent': new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34)
});
map.addLayer(myBaseLayer);
var myGML = new OpenLayers.Layer.GML("GML", "mygml.gml", {
projection: new OpenLayers.Projection("EPSG:4326")
});
map.addLayer(myGML);
可以使用该方法加载任何OpenLayers支持格式的矢量数据,包括WKT,GeoJSON,KML和其他一些格式,在GML图层上指定format选项。
var geojson = new OpenLayers.Layer.GML("GeoJSON", "geo.json", {
projection: new OpenLayers.Projection("EPSG:4326"),
format: OpenLayers.Format.GeoJSON
});
map.addLayer(geojson);
设置了图层的投影属性后,如果手动添加features到图层上(比如调用layer.addFeatures),在添加到图层上之前必须进行坐标转换。
投影变换后的数据的序列化
OpenLayers中矢量数据序列化的方法是将矢量图层上获取数据集合传递给格式化类写数据。在一个具有投影的地图中,我们获取到的数据是已经投影变换过的,为了进行数据转换,需要使用内部投影和外部投影两个参数给格式化类,然后再用格式化类序列化数据。
var format = new OpenLayers.Format.GeoJSON({
'internalProjection': new OpenLayers.Projection("EPSG:900913"),
'externalProjection': new OpenLayers.Projection("EPSG:4326")
});
var jsonstring = format.write(vector_layer.features);
在控件中显示投影坐标
有些控件可以将地图坐标显示给用户,有的直接显示,有的包含在超链接中。MousePosition和Permalink控件(包括ArgParser控件)都是用地图所使用地图投影坐标——也就是球面墨卡托坐标。为了避免用户混淆不清,OpenLayers可以通过displayProjection设置控件的坐标系,将地图坐标系转换为显示坐标系。
要使用这一功能,在创建地图时需要指定projection和displayProjection选项,控件将自动选择这些选项的设置。
var map = new OpenLayers.Map("map", {
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
map.addControl(new OpenLayers.Control.Permalink());
map.addControl(new OpenLayers.Control.MousePosition());
这样你就可以正常加载地图了。
创建球面墨卡托投影栅格图片
球面墨卡托投影如此重要的一个原因是只有这种投影能让你将图片地图正确的叠加到类似于Google Maps这样的商业图层上。在浏览器是使用栅格地图,在一个瘦GIS客户端是不可能对图片进行重新投影,只能是所有的图片使用同样的投影。
如何生成球面墨卡托投影的瓦片地图取决于你使用什么软件来创建地图图片。MapServer的使用包含在此文档中。
MapServer
MapServer采用proj.4来支持地图投影。为了转换为球面墨卡托投影,需要在proj.4的data目录下添加投影定义。
Linux环境下,打开/usr/share/proj/epsg文件,在文件尾部添加一行:
<900913> +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs
然后在地图文件中添加投影在wms_srs元数据中:
map
web
metadata
wms_srs "EPSG:4326 EPSG:900913"
end
end
# Layers go here
end
这样就可以通过MapServer的WMS服务请求使用球面墨卡托投影的瓦片地图,通过OpenLayers很好的和商业数据匹配。
var options = {
projection: new OpenLayers.Projection("EPSG:900913"),
units: "m",
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34,
20037508.34, 20037508.34)
}; map = new OpenLayers.Map('map', options); // create Google Mercator layers
var gmap = new OpenLayers.Layer.Google(
"Google Streets",
{'sphericalMercator': true,
'maxExtent': new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34)
}
); // create WMS layer
var wms = new OpenLayers.Layer.WMS(
"World Map",
"http://vmap0.tiles.osgeo.org/wms/vmap0",
{'layers': 'basic', 'transparent': true}
); map.addLayers(gmap, wms);
WMS图层自动继承地图基础图层的投影,所以不需要在图层中设置投影选项。
GeoServer
最新版的GeoServer已经支持EPSG:900913,因此不需要额外添加投影。把GeoServer的图层作为WMS添加到地图上即可。
自定义瓦片地图
另一个使用球面墨卡托投影的场合是加载自定义的瓦片地图。很多瓦片使用和Google Maps一样的投影,而且是使用同样的z/x/y语法来访问瓦片。
如果你的瓦片是依照Google的瓦片编码规则(从世界的左上角开始,按照x,y,z编码),通过简单的修改get_url函数,就可以用TMS图层来加载这些瓦片。
首先定义getURL函数:允许接受bounds作为参数,然后按照以下方法编写:
function get_my_url (bounds) {
var res = this.map.getResolution();
var x = Math.round ((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
var y = Math.round ((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
var z = this.map.getZoom(); var path = z + "/" + x + "/" + y + "." + this.type;
var url = this.url;
if (url instanceof Array) {
url = this.selectUrl(path, url);
}
return url + path;
}
然后,创建TMS图层,传入一个选项告诉图层自定义瓦片的加载函数是什么:
new OpenLayers.Layer.TMS("Name",
"http://example.com/",
{ 'type':'png', 'getURL':get_my_url });
自己编写的函数将覆盖getURL函数,请求自己的瓦片来代替标准的TMS瓦片。
这样做,你的地图选项还需要包含和Google Maps一样的maxExtent和maxResolution。
new OpenLayers.Map("map", {
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
numZoomLevels:18,
maxResolution:156543.0339,
units:'m',
projection: "EPSG:900913",
displayProjection: new OpenLayers.Projection("EPSG:4326")
});
球面墨卡托投影和EPSG的其他命名
球面墨卡托投影在OpenLayers中使用代码EPSG:900913,很多其他的服务比如OpenStreetMap, Bing和Yahoo也用同样的投影,但并不一定要用EPSG:900913代码,一些其他的代码比如EPSG:3857 和EPSG:102113也在使用。现在官方统一规定了代码EPSG:3857来代替EPSG:900913(http://www.epsg-registry.org/export.htm?gml=urn:ogc:def:crs:EPSG::3857)。因此,如果你想合并OpenLayers球面墨卡托投影的叠加图层,不管该图层使用的是其他代码还是官方的代码,你必须确保OpenLayers请求的是EPSG:3857或者别的代码而不是EPSG:900913。在加载一个图层到地图上之前,重写图层的投影来完成这些工作。代码如下:
// set transformation functions from/to alias projection
OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.SphericalMercator.projectForward);
OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:4326", OpenLayers.Layer.SphericalMercator.projectInverse); // create sphericalmercator layers
var googleLayer = new OpenLayers.Layer.Google("Google", {"sphericalMercator": true});
var osmLayer = new OpenLayers.Layer.OSM("OpenStreetMap"); // override default epsg code
aliasproj = new OpenLayers.Projection("EPSG:3857");
googleLayer.projection = osmLayer.projection = aliasproj; //add baselayers to map
map.addLayers([googleLayer, osmLayer]);
这样,叠加图层(例如WMS图层)将使用3857代码,并在4326和3857之间完成坐标变换。
OpenLayers中的球面墨卡托投影的更多相关文章
- OpenLayers中的图层
OpenLayers有多个不同的图层类,每一个都可以连接到不同的地图服务器.例如通过Layer.WMS类可以连接到WMS地图服务器,通过Layer.Google类可以连接到谷歌地图服务器.OpenLa ...
- OpenLayers中地图缩放级别的设置方法
来源于:http://www.cnblogs.com/sailheart/archive/2011/03/15/1984519.html 一.概述 在OpenLayers中,地图必须具有一个缩放级别的 ...
- OpenLayers中的Layer概念和实践--Openlayers调用WMS服务
整理转自:http://hi.baidu.com/lixuweiok/item/c406a4e6a6d390e7fa42ba4b 本章我认为是这本书的真正开端,终于开始讲一些有意思的东西了.. 在这一 ...
- OpenLayers中的图层(转载)
作者:田念明出处:http://www.cnblogs.com/nianming/本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法 ...
- openlayers中单击获取要素
openlayers中单击获取要素 分类专栏: GIS 总结 OpenLayers 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: ...
- openlayers中的自定制工具栏,包含画点、线、面
先是在projectquantan-master这个项目中有一个EditingPanel这个工具条,也挺好的,功能挺全的,但是有一点就是只有画多边形的一个按钮,没有point和path俩个的,所以就想 ...
- Openlayers中layer介绍
1.base layers & overlay layers base layer:最底层的layer,其它的图层是在他之上,最先增加的图层默认作为base layer. overlay la ...
- openlayers中实现点的拖拽(modify),在layer中增加修改删除point。
最近忙着整地图,都忘记了总结来沉淀自己,自我检讨一下. 总结一下最近使用openlayer时学习的内容,先说下我的业务逻辑吧,在室内地图中 1,点击新增在地图上新增一个可以拖拽的点,拖拽完成后确定位置 ...
- openLayers中WMTS结合GeoServer呈现瓦片地图
首先看openlayers官网中wmts模块,https://openlayers.org/en/latest/apidoc/module-ol_source_WMTS-WMTS.html,里面的参数 ...
随机推荐
- golang学习笔记5 用bee工具创建项目 bee工具简介
golang学习笔记5 用bee工具创建项目 bee工具简介 Bee 工具的使用 - beego: 简约 & 强大并存的 Go 应用框架https://beego.me/docs/instal ...
- vue之component
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data.computed.watch.methods 以及生命周期钩子等.仅有的例外是像 el 这样根实例特有的选 ...
- xml.dom——文档对象模型API
文档对象模型,或者“DOM”,是一个跨语言API的World Wide Web Consortium(W3C)来访问和修改XML文档.DOM的实现提供了一个XML文档树结构,或允许客户机代码从头开始建 ...
- 阿里云部署Java web项目
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了如何在阿里云上安装JDK.Tomcat以及其配置过程.最后以一个实例来演示在 ...
- javaweb笔记—04(预编译和泛型)
预编译:ps对象1.ps可进行预编译,占位符传值,性能高于sta的(数据库驱动层有优化)2.比较灵活,数据库将预编译的SQL缓存了,第二次访问,就不用预编译,直接执行.3.较为安全,不会发生SQL注入 ...
- shell =~ 引发的思考
=~不是按位取反 1.[[]] if [[]]中引用变量不用加 双引号(")了,而if[]中变量必须加双引号,如if[ -n "$test" ],不然一些特殊的地方,会出 ...
- i2c调试碰到的问题
i2c eeprom i2cget两次结果不一致 i2cset没成功. device里只看到50,却冒出了51地址. i2ctools是针对8bit地址的,而我们的eeprom都是用16bit add ...
- log4j2笔记 #04# Appender的三个基本款以及RollingFile的各种示例配置
粗糙笔记,留着备用. 三个基本款分别是ConsoleAppender.FileAppender(以及他的堂哥RandomAccessFileAppender).RollingFileAppender( ...
- Golang接口简单了解
在Golang中,一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口. package main import "fmt" type Animal interface ...
- 简单了解一下php的迭代生成器yield
yield是从PHP5.5开始有的,关于yidle的说明鸟哥的博客做了详细说明,我觉得是有点复杂,在看了几篇其他的帖子还有案例,我大概知道yield的作用就是在做大量数据循环处理的时候,能节省很大一部 ...