• 天地图WMTS地图瓦片下载


            最近在开发个人项目中遇到了这样一个问题,即:本地开发使用天地图在线地图服务,部署到线上时,突然想到——天地图提供的开放地图服务是需要申请秘钥key才能够使用的,而且需要连接外网,同时也是有访问次数限制的,那么,如果是在内网环境中如何进行迁移呢?

            其实解决方案很简单:通常在项目开发中,我们是通过第三方地图数据下载器进行遥感影像/电子地图/矢量数据下载,然后将其处理之后,发布到自己的专用服务器上。但是对于个人开发者而言,数据下载第一步往往最为艰难,因为不仅要考虑数据可靠性、现势性、完备性等,还要考虑坐标系是否正确,如果不正确的话,还要进行坐标系转换、影像纠偏处理等等,很是麻烦。

            然而如果有WMS/WFS/WMTS等地图服务发布经验的小伙伴,脑瓜一拍,立刻就明白常规地图服务是怎么回事了。天地图提供的WMTS服务也不例外,其实就是通过建立影像金字塔,然后逐层切分,转换为256*256的n张图片,供前端地图开发使用。

            于是,按照天地图的瓦片剖分规则(更为详细的可以自行深入研究哈),在第level层级,对应的行列数分别是:

    int rowCount = (int) Math.pow(2, level); //行数
    int colCount = (int) Math.pow(2, level); //列数

            对于条件有限的小伙伴来讲,可以通过网络编程简单抓取前几级的地图瓦片,然后进行使用即可。当然,只是兴趣使然,拿本篇文章做一下日常开发记录,我个人是不建议这样做的哈,毕竟有“盗用他人劳动成果”,即:白嫖的嫌疑,相比之下,更为推荐通过Nginx代理天地图服务,将其丝滑的缓存到本地的方案。 

            基于Java的下载第8层级的示例代码如下,可根据需要自行调节参数。

    1. package com.example.xwd;
    2. import java.io.*;
    3. import java.net.MalformedURLException;
    4. import java.net.URL;
    5. import java.net.URLConnection;
    6. public class DownloadTIles {
    7. public static void main(String[] args) {
    8. String outPath = "D:\\文档资料\\tiles\\";
    9. downWorld1To3(outPath,8,8);
    10. }
    11. //计算瓦片范围-世界范围-[1-TopLevel级]
    12. private static void downWorld1To3(String basePath, int lowLevel, int TopLevel) {
    13. System.out.println("basePath=" + basePath);
    14. for (int level = lowLevel; level <= TopLevel; level++) {
    15. int rowCount = (int) Math.pow(2, level); //行数
    16. int colCount = (int) Math.pow(2, level); //列数
    17. System.out.println("level:" + level + "row:" + rowCount + ",col:" + colCount);
    18. //下载瓦片
    19. for (int j = 0; j < colCount; j++) {
    20. for (int i = 0; i < rowCount; i++) {
    21. String url_tilePath = "http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&tk=您的天地图key=" + i +
    22. "&TILECOL=" + j
    23. + "&TILEMATRIX=" + level;//拼接请求路径
    24. String save_tilePath = level + "/" + j + "/";//拼接存储路径
    25. String save_fileName = +i + ".png";//拼接存储名称
    26. String fullFolder = basePath + save_tilePath;
    27. File folder = new File(fullFolder);
    28. System.out.println(folder.getAbsolutePath());
    29. if (!folder.exists()) {
    30. folder.mkdirs();
    31. }
    32. File file = new File(folder, save_fileName);
    33. System.out.println("存储路径:" + file.getAbsolutePath());
    34. downloadTilePNG(url_tilePath, file);
    35. }
    36. }
    37. }
    38. }
    39. private static void downloadTilePNG(String tileUrl, File outFile) {
    40. URL url = null;
    41. URLConnection urlConnection = null;
    42. InputStream inputStream = null;
    43. OutputStream outputStream = null;
    44. int len = -1;
    45. byte[] buffer = new byte[1024];
    46. try {
    47. url = new URL(tileUrl);
    48. urlConnection = url.openConnection();
    49. urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 SLBrowser/8.0.1.5162 SLBChan/111");
    50. inputStream = urlConnection.getInputStream();
    51. outputStream = new FileOutputStream(outFile);
    52. while ((len = inputStream.read(buffer)) != -1) {
    53. outputStream.write(buffer, 0, len);
    54. }
    55. System.out.println("success:" + tileUrl);
    56. } catch (MalformedURLException e) {
    57. e.printStackTrace();
    58. } catch (IOException e) {
    59. e.printStackTrace();
    60. System.out.println("error:" + tileUrl);
    61. } finally {
    62. if (outputStream != null) {
    63. try {
    64. outputStream.close();
    65. } catch (IOException e) {
    66. e.printStackTrace();
    67. }
    68. }
    69. if (inputStream != null) {
    70. try {
    71. inputStream.close();
    72. } catch (IOException e) {
    73. e.printStackTrace();
    74. }
    75. }
    76. }
    77. }
    78. }

           然后得到如下所示的瓦片结果,并将其使用Nginx进行资源发布,

    1. #user nobody;
    2. worker_processes 1;
    3. #error_log logs/error.log;
    4. #error_log logs/error.log notice;
    5. #error_log logs/error.log info;
    6. #pid logs/nginx.pid;
    7. events {
    8. worker_connections 1024;
    9. }
    10. http {
    11. include mime.types;
    12. default_type application/octet-stream;
    13. #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    14. # '$status $body_bytes_sent "$http_referer" '
    15. # '"$http_user_agent" "$http_x_forwarded_for"';
    16. #access_log logs/access.log main;
    17. sendfile on;
    18. #tcp_nopush on;
    19. #keepalive_timeout 0;
    20. keepalive_timeout 65;
    21. #gzip on;
    22. server {
    23. listen 80;
    24. add_header 'Access-Control-Allow-Origin' '*';
    25. server_name localhost;
    26. #charset koi8-r;
    27. #access_log logs/host.access.log main;
    28. location / {
    29. root html;
    30. index index.html index.htm;
    31. }
    32. }
    33. }

            最终使用Cesium.js做本地测试示例代码以及效果如下,

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="utf-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta
    7. name="viewport"
    8. content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    9. />
    10. <title>Documenttitle>
    11. <link href="../../Build/Cesium/Widgets/widgets.css" rel="stylesheet"/>
    12. <script src="../../Build/Cesium/Cesium.js"> script>
    13. <style>
    14. *{
    15. padding: 0;
    16. margin: 0;
    17. box-sizing: border-box;
    18. }
    19. html,body{
    20. width: 100%;
    21. height: 100%;
    22. }
    23. #map{
    24. position: absolute;
    25. top: 0;
    26. left: 0;
    27. width: 100%;
    28. height: 100%;
    29. }
    30. style>
    31. head>
    32. <body>
    33. <div id="map">div>
    34. <script>
    35. Cesium.Ion.defaultAccessToken = "Your AccessToken"
    36. const viewer = new Cesium.Viewer("map")
    37. viewer.scene.imageryLayers.removeAll();
    38. viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
    39. url: "http://localhost:80/tiles/" + '/{z}/{x}/{y}.png',
    40. minimumLevel: 0,
    41. maximumLevel: 7
    42. }));
    43. script>
    44. body>
    45. html>

     

     

  • 相关阅读:
    跟着实例学Go语言(三)
    科技云报道:不卷自研大模型,金山办公如何创新生成式AI?
    LayUI项目学习
    一言不合就重构
    19-29-k8s-基本命令-yaml-kubectl
    ​基于光通信的6G水下信道建模综述
    php初级教程十 过滤器
    彻底搞明白概率论:随机事件,样本空间,必然事件,不可能事件
    Dasviewer软件在浏览模型时能通过经纬度定位点吗?
    通俗介绍人工智能是什么
  • 原文地址:https://blog.csdn.net/weixin_43524214/article/details/132864103