天地图WMTS地图瓦片下载

news2025/1/21 2:50:57

        最近在开发个人项目中遇到了这样一个问题,即:本地开发使用天地图在线地图服务,部署到线上时,突然想到——天地图提供的开放地图服务是需要申请秘钥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层级的示例代码如下,可根据需要自行调节参数。

package com.example.xwd;


import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class DownloadTIles {

    public static void main(String[] args) {
        String outPath = "D:\\文档资料\\tiles\\";
        downWorld1To3(outPath,8,8);
    }


    //计算瓦片范围-世界范围-[1-TopLevel级]
    private static void downWorld1To3(String basePath, int lowLevel, int TopLevel) {
        System.out.println("basePath=" + basePath);
        for (int level = lowLevel; level <= TopLevel; level++) {
            int rowCount = (int) Math.pow(2, level); //行数
            int colCount = (int) Math.pow(2, level); //列数
            System.out.println("level:" + level + "row:" + rowCount + ",col:" + colCount);
            //下载瓦片
            for (int j = 0; j < colCount; j++) {
                for (int i = 0; i < rowCount; i++) {
                    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 +
                            "&TILECOL=" + j
                            + "&TILEMATRIX=" + level;//拼接请求路径
                    String save_tilePath = level + "/" + j + "/";//拼接存储路径
                    String save_fileName = +i + ".png";//拼接存储名称
                    String fullFolder = basePath + save_tilePath;
                    File folder = new File(fullFolder);
                    System.out.println(folder.getAbsolutePath());
                    if (!folder.exists()) {
                        folder.mkdirs();
                    }
                    File file = new File(folder, save_fileName);
                    System.out.println("存储路径:" + file.getAbsolutePath());
                    downloadTilePNG(url_tilePath, file);
                }
            }
        }

    }


    private static void downloadTilePNG(String tileUrl, File outFile) {
        URL url = null;
        URLConnection urlConnection = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        int len = -1;
        byte[] buffer = new byte[1024];
        try {
            url = new URL(tileUrl);
            urlConnection = url.openConnection();
            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");
            inputStream = urlConnection.getInputStream();
            outputStream = new FileOutputStream(outFile);
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            System.out.println("success:" + tileUrl);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("error:" + tileUrl);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

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


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        add_header 'Access-Control-Allow-Origin' '*';
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

    }


}

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

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <title>Document</title>
    <link href="../../Build/Cesium/Widgets/widgets.css" rel="stylesheet"/>
    <script src="../../Build/Cesium/Cesium.js"> </script>
    <style>
        *{
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
        html,body{
            width: 100%;
            height: 100%;
        }
        #map{
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <script>
        Cesium.Ion.defaultAccessToken = "Your AccessToken"
        const viewer = new Cesium.Viewer("map")
        viewer.scene.imageryLayers.removeAll();

        viewer.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({
            url: "http://localhost:80/tiles/" + '/{z}/{x}/{y}.png',
            minimumLevel: 0,
            maximumLevel: 7
        }));
    </script>
</body>

</html>

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1007395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

八、MySql表的复合查询

文章目录 一、基本查询回顾二、多表查询&#xff08;一&#xff09;笛卡尔积的初步过滤&#xff08;二&#xff09;例子1.显示部门号为10的部门名&#xff0c;员工名和工资2.显示各个员工的姓名&#xff0c;工资&#xff0c;及工资级别 三、自连接&#xff08;一&#xff09;定…

基于SSM的校园快递一站式服务系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Consensus-AI论文搜索引擎 直接从论文中找答案

Consensus介绍 Consensus是一个人工智能AI论文搜索引擎&#xff0c;一个可以在科学论文中找到答案的搜索引擎&#xff0c;使用人工智能从数亿篇科学论文数据库中即时提取和聚合易于使用&#xff0c;搜索结果在几秒内即可完成&#xff0c;而且100%无广告。 截图 提示&#xf…

朋友圈大佬都去读研了,这份备考书单我码住了

作者简介&#xff1a; 辭七七&#xff0c;目前大二&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

Golang 单元测试合集整理,(我最常用 gomonkey)欢迎收藏

无论写什么样的语言&#xff0c;单元测试都是必不可少的&#xff0c;它可以极大的提高我们的代码质量&#xff0c;减少各种低级错误和 bug 无论你是一个靠谱合格的码农&#xff0c;还是一个优秀的程序员&#xff0c;单元测试都是咱们必须落实的一环 单元测试比较容易&#xf…

python:使用RESTful API(flask)调用python程序传递参数,实现Web端调用python程序

问题描述 现有一个用python写的程序&#xff08;或者是一个或几个的函数接口&#xff09;&#xff0c;需要在Web前端调用python写的函数。如果直接用前端java来调用会很不方便&#xff0c;而且会出现各种麻烦的问题&#xff0c;下面给出如何在web前端调用python的接口。 解决…

STM32WB55开发(2)----修改蓝牙地址

STM32WB55开发----2.修改蓝牙地址 概述硬件准备视频教学样品申请完整代码下载选择芯片型号配置时钟源配置时钟树RTC时钟配置查看开启STM32_WPAN条件配置HSEM配置IPCC配置RTC启动RF开启蓝牙设置工程信息工程文件设置修改置BLE设备公共地址Ble_Hci_Gap_Gatt_Init结果演示 概述 在…

更多场景、更多选择,Milvus 新消息队列 NATS 了解一下

在 Milvus 的云原生架构中&#xff0c;消息队列&#xff08;Log Broker&#xff09;可谓任重道远&#xff0c;它不仅要具备流式数据持久性、支持 TT 同步、事件通知等能力&#xff0c;还要确保工作节点从系统崩溃中恢复时增量数据的完整性。 在 Milvus 的架构中&#xff0c;一切…

【计算机视觉 | 语义分割】干货:语义分割常见算法介绍合集(一)

文章目录 一、U-Net二、Fully Convolutional Network三、SegNet四、DeepLab五、DeepLabv3六、UNet七、PSPNet八、EfficientDet九、SegFormer十、ENet 一、U-Net U-Net 是一种语义分割架构。 它由收缩路径和扩张路径组成。 收缩路径遵循卷积网络的典型架构。 它由两个 3x3 卷积…

基于SSM的学生信息管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Python 图形化界面基础篇:使用包装器( Pack )布局元素

Python 图形化界面基础篇&#xff1a;使用包装器&#xff08; Pack &#xff09;布局元素 引言什么是 Tkinter 的 Pack 布局&#xff1f;步骤1&#xff1a;导入 Tkinter 模块步骤2&#xff1a;创建 Tkinter 窗口步骤3&#xff1a;创建和使用 Pack 布局步骤4&#xff1a; Pack 布…

Android codec2 编码 -- 基于录屏

文章目录 前言android 原生的应用srcreenrecordMediaCodec获取编码数据流程 前言 本篇文章主要是理解Android 12编码的流程&#xff0c; 首先从上层的应用出发理解mediacodec提供给外部API的用法。然后针对每个api 分析编码各个流程中框架中的流程。 熟悉一个框架的流程 可以…

嵌入式这个领域会变得过于内卷吗?

今日话题&#xff0c;嵌入式这个领域会变得过于内卷吗&#xff1f;嵌入式开发主要服务于第二产业&#xff0c;尤其是制造业&#xff0c;包括电器、电气、机械、汽车、装备、航空航天等行业的“智能制造”部门&#xff0c;稳定性较强&#xff0c;不像互联网行业那样波动大。因此…

【LangChain系列 8】Prompt模版——少样本prompt模版(二)

原文地址&#xff1a;【LangChain系列 8】Prompt模版——少样本prompt模版(二) 本文速读&#xff1a; 固定少样本prompt模版 动态少样本prompt模版 在上篇文章中介绍了少样本模版的基本用法&#xff0c;本文将介绍 对话模型(chat model) 中 少样本prompt模版的用法。 LangCh…

C语言双向链表

文章目录 前言双向链表链表头结点的创建节点尾插与尾删节点头插与头删特定位置插入或删除节点链表节点查找双向链表的销毁 链表的打印 前言 假期时间因为为学校开学考试做准备所以一直没更新博客&#xff0c;今天开始博客会陆续更新。 双向链表 之前我们说过了顺序表和单链表…

加密狗软件有什么作用?

加密狗软件是一种用于加密和保护计算机软件和数据的安全设备。它通常是一个硬件设备&#xff0c;可以通过USB接口连接到计算机上。加密狗软件的作用主要体现在以下几个方面&#xff1a; 软件保护&#xff1a;加密狗软件可以对软件进行加密和授权&#xff0c;防止未经授权的用户…

K8S:kubectl陈述式、声明式资源管理及金丝雀部署

文章目录 一.陈述式资源管理方法1.陈述式资源管理概念2.基本信息查看&#xff08;1&#xff09;查看版本信息&#xff08;2&#xff09;查看资源对象简写&#xff08;3&#xff09;查看集群信息&#xff08;4&#xff09;配置kubectl自动补全&#xff08;5&#xff09;node节点…

【Java实战项目】【超详细过程】—大饼的图片服务器4

目录 1.引入servlet依赖2.处理客户端请求2.1 上传图片2.1.1.获取图片属性写入数据库&#xff08;1&#xff09;创建factory对象和fileUpload对象为获取图片信息做准备&#xff08;2&#xff09;将获取到的文件信息存到列表items中&#xff08;3&#xff09;获取列表items中第一…

无涯教程-JavaScript - XNPV函数

描述 XNPV函数返回的现金Stream量表的净现值不一定是周期性的。要计算一系列定期现金Stream量的净现值,请使用NPV函数。 语法 XNPV (rate, values, dates)争论 Argument描述Required/OptionalRateThe discount rate to apply to the cash flows.RequiredValues 与日期付款时…

(已解决)AttributeError: module ‘cv2.gapi.wip.draw‘ has no attribute ‘Text‘

问题描述 今天再跑Caption-Anything项目的时候&#xff0c;最开始的时候就报了这样一个错误&#xff1a;AttributeError: module cv2.gapi.wip.draw has no attribute Text。 Caption-Anything是一种多功能的图像处理工具&#xff0c;结合了Segment Anything&#xff0c;Visual…