搭建基于瓦片的离线地图应用
文章目录
- 1、瓦片名称
- 2、地图精度的等级
- 3、坐标计算
- 4、根据经纬度获取瓦片编号
- 5、获取指定地图范围的全部瓦片
- 6、离线地图应用
1、瓦片名称
瓦片的命名约定
- 瓦片是一个个精度为 256x256 像素的 PNG 文件;
- 瓦片文件存储路径的格式为:/zoom-level/x/y.png;
提供瓦片的服务称为瓦片服务器,不同的瓦片服务器,获取瓦片文件的 url 会有些差异,但整体相似,例如:
瓦片服务 | URL 格式 | zoom 等级 |
---|---|---|
OSM ‘standard’ style | http://[abc].tile.openstreetmap.org/zoom/x/y.png | 0-19 |
OpenCycleMap | http://[abc].tile.thunderforest.com/cycle/zoom/x/y.png | 0-22 |
Thunderforest Transport | http://[abc].tile.thunderforest.com/transport/zoom/x/y.png | 0-22 |
MapQuest As of July 11, 2016, direct tile access has been discontinued. | http://otile[1234].mqcdn.com/tiles/1.0.0/osm/zoom/x/y.jpg (“otile1-s.mqcdn.com” etc. for https) | 0-18 |
MapQuest Open Aerial, As of July 11, 2016, direct tile access has been discontinued. | http://otile[1234].mqcdn.com/tiles/1.0.0/sat/zoom/x/y.jpg | 0-11 globally, 12+ in the U.S. |
Stamen Terrain | http://tile.stamen.com/terrain-background/zoom/x/y.jpg | 4-18, US-only (for now) |
有些瓦片服务器,如 OSM,OpenCycleMap,会提供多个域名,比如 a.tile.openstreetmap.org
, b.tile.openstreetmap.org
, c.tile.openstreetmap.org
,这样可以提高瓦片获取的效率。
2、地图精度的等级
URL 中的 zoom 参数用来指定地图的精度等级:
zoom level | tile coverage | number of tiles | tile size(*) in degrees |
---|---|---|---|
0 | 1 tile covers whole world | 1 tile | 360° x 170.1022° |
1 | 2 × 2 tiles | 4 tiles | 180° x 85.0511° |
2 | 4 × 4 tiles | 16 tiles | 90° x [variable] |
n | 2n × 2n tiles | 22n tiles | 360/2n° x [variable] |
12 | 4096 x 4096 tiles | 16 777 216 | 0.0879° x [variable] |
16 | 232 ≈ 4 295 million tiles | ||
17 | 17.2 billion tiles | ||
18 | 68.7 billion tiles | ||
19 | Maximum zoom for Mapnik layer | 274.9 billion tiles |
(*)
每个瓦片所占据的地图的宽度(经度)是常数,为 360°2n\frac{360°}{{2}^n}2n360°,但是瓦片所占据的高度并不如此,一般来说,同一维度的瓦片具有相同的高度,但是从赤道往两极,瓦片占有的高度会不断增大。
详细情况可参考:Zoom levels
地球经度范围为 [-180°, 180°], 维度范围 [-90°, 90°]。
3、坐标计算
在墨卡托投影坐标系中:x 的取值从 0 (西经180°) 到 2zoom−12^{zoom}-12zoom−1 (东经180°);y 的取值从 0(北纬 85°)到 2zoom−12^{zoom}-12zoom−1 (南纬85°)。那么,如何根据经纬度来确定瓦片的编号呢?
以从 WGS84(经纬度坐标系 EPSG:4326 )到伪墨卡托投影投影坐标系(EPSG:3857)投影为例:
EPSG:4326 坐标为 (x, y), x 为坐标的经度,y 为纬度;
经纬度转瓦片编号:
import math
def deg2num(lat_deg, lon_deg, zoom):lat_rad = math.radians(lat_deg)n = 2.0 ** zoomxtile = int((lon_deg + 180.0) / 360.0 * n)ytile = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n)return (xtile, ytile)
瓦片编号转经纬度:
import math
def num2deg(xtile, ytile, zoom):n = 2.0 ** zoomlon_deg = xtile / n * 360.0 - 180.0lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))lat_deg = math.degrees(lat_rad)return (lat_deg, lon_deg)
4、根据经纬度获取瓦片编号
1、将经纬度转换为弧度: 弧度=度∗π180弧度 = \frac{度* π}{180}弧度=180度∗π
2、弧度转换为墨卡托投影:
x = 坐标x的弧度
y = arsinh(tan(lat)) = log[tan(lat) + sec(lat)] = log(tan(lat) + 1/cos(lat))
# python
# y_radian 为纬度对应的弧度
y = math.log(math.tan(y_radian) + 1/math.cos(y_radian))
例如:坐标点 (90°, 45°) 对应的 墨卡托坐标为 (1.57, 0.87)
3、根据墨卡托坐标,求解瓦片编号:
# python
import math
def deg2num(lon_deg, lat_deg, zoom): lat_rad = math.radians(lat_deg)n = 2.0 ** zoomxtile = int((lon_deg + 180.0) / 360.0 * n)ytile = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n)return (xtile, ytile)
比如上海的经纬度坐标 (121.3457, 31.200),根据上面的函数可求:
x | y | zoom |
---|---|---|
6 | 3 | 3 |
13 | 6 | 4 |
26 | 13 | 5 |
53 | 26 | 6 |
857 | 418 | 10 |
219433 | 107138 | 18 |
请求相应的瓦片:
http://mt2.google.cn/vt/lyrs=y&hl=zh-CN&gl=cn&x=13714&y=6696&z=14
5、获取指定地图范围的全部瓦片
下面示例,可以获取经纬度范围在: [105.5108, 105.9285 ], [30.2358, 30.40] 的 zoom 等级为 13 的全部瓦片。需要自己根据经纬度计算瓦片的编号范围。
瓦片服务使用谷歌卫星地图:"http://mt2.google.cn/vt/lyrs=y&hl=zh-CN&gl=cn&x=%d&y=%d&z=%d"
github
示例代码:
private static int zoom = 13;private static int xMin = 6496;private static int xMax = 6506;private static int yMin = 3369;private static int yMax = 3373;private static String URL = "http://mt2.google.cn/vt/lyrs=y&hl=zh-CN&gl=cn&x=%d&y=%d&z=%d";private static AtomicInteger request = new AtomicInteger(0);private static AtomicInteger response = new AtomicInteger(0);public static void main(String[] args) {load13();sleep();}private static String getURL(int x, int y, int z) {return String.format(URL, x,y,z);}public static void sleep() {while (request.get() == 0 || request.get() != response.get()) {try {Thread.sleep(500);System.out.print(". ");} catch (InterruptedException e) {e.printStackTrace();}}}public static void load13() {for (int i = xMin; i <= xMax; i++) {File dir = new File("tiles/13/" + i);if (!dir.exists()){dir.mkdirs();}for (int j = yMin; j < yMax; j++) {request.incrementAndGet();final int y = j;WebClient.create().get().uri(getURL(i, j, 13)).accept(MediaType.IMAGE_PNG).retrieve().bodyToMono(Resource.class).subscribe((resource)-> {try {String image = String.format("%s/%d.png", dir.getPath(), y);System.out.println(image);BufferedImage bufferedImage = ImageIO.read(resource.getInputStream());ImageIO.write(bufferedImage, "png", new File(image));response.incrementAndGet();} catch (IOException e) {e.printStackTrace();}});}}}
6、离线地图应用
使用 openlayers3 来构建离线地图 web 应用。
<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title>openlayers3</title><link rel="stylesheet" href="ol.css" /><script type="text/javascript" src="ol.js"></script><style>html{height: 100%;width: 100%;padding:0;margin:0;}body{height: 100%;width: 100%;padding:0;margin:0;}.map {height: 100%;width: 100%;}</style>
</head><body><div id="map" class="map"></div>
<script>// http://a.tile.openstreetmap.org/{z}/{x}/{y}.png// 谷歌卫星地图: http://mt2.google.cn/vt/lyrs=y&hl=zh-CN&gl=cn&x={x}&y={y}&z={z} // 谷歌街道地图: http://mt2.google.cn/vt/lyrs=m&hl=zh-CN&gl=cn&x={x}&y={y}&z={z}// https://{a-c}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=0e6fc415256d4fbb9b5166a718591d71// https://tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=0e6fc415256d4fbb9b5166a718591d71// https://tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey=0e6fc415256d4fbb9b5166a718591d71// https://tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=0e6fc415256d4fbb9b5166a718591d71// https://a.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}{r}.png// https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png// https://tile.opentopomap.org/{z}/{x}/{y}.png// https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png// https://a.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png// 高德地图 http://wprd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7let tile = new ol.layer.Tile({// extent: ol.proj.transformExtent([121.185, 31.117, 121.745, 31.375], "EPSG:4326", "EPSG:3857"),source: new ol.source.XYZ({url: 'tiles/{z}/{x}/{y}.png',tilePixelRatio: 1,minZoom:10,maxZoom:20})})var sate = new ol.layer.Group({layers: [tile]});var map = new ol.Map({view: new ol.View({center: ol.proj.fromLonLat([105.67, 30.28]),// center: [121.469, 31.226],zoom: 13,minZoom: 10,maxZoom: 20}),layers: [sate],target: 'map'});
</script>
</body>
</html>
将瓦片目录 tiles 与上面的页面放在同一目录下,然后用浏览器打开,就可以使用离线地图了。
搭建基于瓦片的离线地图应用相关推荐
- 基于百度制作离线地图及优化
1.修改百度离线包,调用本地离线瓦片 https://blog.csdn.net/wml00000/article/details/82219015 2.瓦片下载 Math.pow(2, (18 - ...
- 【CentOS7】在服务器上搭建基于Aria2的离线下载器
说明 在平时从网上下载文件时,有时会遇到即使一个几十兆的文件都要下一天的困境,如果使用远程服务器先登录ssh,再通过wget.scp的方式下载文件又比较费事.参考网上有人用Aria2搭建离线下载器 ...
- 搭建离线瓦片地图服务并用QGIS显示离线地图
需求的提出: 由于业务需求,展示GIS时,不能连接互联网,也就是说不能调用互联网上提供的地图服务. 因为不能联网,所以必须在局域网或本机上搭建离线瓦片地图服务.本文讲述如何搭建离线瓦片 ...
- geoserver离线地图服务搭建和图层发布
前言 项目用到了GIS地图,在浏览器进行展示.起初使用了在线的高德地图.高德官网api丰富,且都是中文,很好用,也很方便.但是随着需求的变更,项目环境也从互联网变成了内网环境.所以高德地图就不能再用了 ...
- 3、 如何搭建高德离线地图服务
谷歌(百度.高德)离线地图开发环境搭建 发布时间:2018-01-17 版权: 1.说明 离线地图开发环境支持谷歌地图.百度地图.高德地图等等所有常用地图类型,支持在局域网内的地图部署.二次开发. 2 ...
- 离线地图开发环境搭建
离线地图开发环境搭建 1.说明 离线地图开发环境支持多种地图源,一套代码,任意地图服务,支持在局域网内的地图部署.二次开发. 2.实现 第一步:下载安装离线地图开发环境 BIEGMAP Server离 ...
- BIGEMAP谷歌(百度、高德)离线地图开发环境搭建
谷歌(百度.高德)离线地图开发环境搭建 发布时间:2018-01-17 版权: 1.说明 离线地图开发环境支持谷歌地图.百度地图.高德地图等等所有常用地图类型,支持在局域网内的地图部署.二次开发. 2 ...
- 如何搭建高德离线地图服务
1.说明 离线地图开发环境支持谷歌地图.百度地图.高德地图等等所有常用地图类型,支持在局域网内的地图部署.二次开发. 2.实现 第一步:下载安装离线地图开发环境 BIEGMAP离线地图服务器(开发版) ...
- 基于winform的GIS离线地图
基于winform的离线地图项目 1.下载GMap(一个国外开源控件,codeplex有源码),不了解的百度一下, 2.项目引入GMap.NET.Core和GMap.NET.WindowsForms ...
最新文章
- OWASP Mutillidae II:保持冷静并保持警惕——闯关小结
- 彻底了解JS中难懂的闭包
- Windows批处理符号简介、常用Dos命令
- 印度永久封禁了微信、百度、TikTok 等 59 款中国 App……
- Jquery页面跳转
- windows 配置 Gitlab、Gitee(码云) 的git开发环境
- Android平台ROM的定制及精简教程
- mysql中drop语法错误_MySQL DROP TABLE操作以及 DROP 大表时的注意事项
- sql统计各部门的的男女员工数
- html%2b怎么转换成加号,url 参数的加号变成空格处理
- Semantic Proximity Search on Heterogeneous Graph by Proximity Embedding
- 大学英语综合教程二 Unit 5 课文内容英译中 中英翻译
- 成功在于实践作文_人生贵在实践作文800字
- sunday 算法python实现
- 兑吧解决Windows 组件存储已损坏,0x80073712错误
- 用Java抓取10年大乐透中奖数据
- Google Earth Engine(GEE)——逐月降水数据下载和直方图表展示
- win 10 QT 5.15.2 modbus QModbusRtuSerialMaster 客户端
- 【头歌】Linux Linux从入门到精通
- 图论在识别人脑网络连通性模式中的应用
热门文章
- 要想学好C语言,你必须得懂的基础知识大全!本文将带你深度学习
- KALDI脚本文件解释
- [工具]python中文分词---【jieba】
- PAT_乙级 1016 部分A+B(15)
- 这几款免费的思维导图软件你或许没用过,快来试试吧
- Nginx 日志采集与分析
- 浙江大学计算机学院各专业介绍ppt模板,浙大硕士论文答辩经典ppt模板(几乎涵盖各种ppt制作技巧).ppt...
- 互联网晚报 | 6月26日 星期日 |​ ​​官方澄清“i茅台”将上线“500毫升53度飞天茅台”;一批顶流基金经理调仓...
- 安装bazel遇到的坑
- el-tree实现仅限叶子节点显示勾选框,并且只能单选