GIS Java 生成四至图

news2025/1/22 12:58:45

目录

前言

操作步骤:

1,求出多边形的四至点

2,下载地图

3,绘制多边形


前言

对于地图上的一个多边形地块,其四至图就是能够覆盖这个多边形的最小矩形,也就是求出这个多边形的最东点,最西点,最南点,最北点,即四至点,其中最西点和最北点构成左上角,最南点和最东点构成右下点,只要知道了左上角和右下角,就知道这个最小覆盖矩形了。

前端生成四至图是比较简单的,后端如何生成四至图呢?后端生成四至图得到的是一个图片,图片的底图是天地图,在这个底图之上就是多边形。多边形的坐标长这样:"[[31.21729,121.583274],[31.217096,121.58378],[31.216985,121.583457],[31.21729,121.583274]]",它是4326的坐标系,第一个坐标和最后一个坐标是同一个,首尾相连,下图就是它的四至图。

操作步骤:

1,求出多边形的四至点

        即多边形的最东点,最西点,最南点,最北点,然后我们就知道四至图的左上点和右下点这两个点的地理坐标,根据这两个点求出它们各自在天地图的瓦片位置 (x,y) 。

/**
 * 计算瓦片行列号
 * @param latitude  纬度
 * @param longitude 经度
 * @param zoom      缩放级别
 * @return 瓦片行列号数组,格式为 [col, row]
 */
public static int[] calculateTileXY(double latitude, double longitude, int zoom) {
    double n = Math.pow(2, zoom);
    double mercX = (longitude + 180) / 360;
    double mercY = (1 - Math.log(Math.tan(Math.toRadians(latitude)) + 1 / Math.cos(Math.toRadians(latitude))) / Math.PI) / 2;

    int tileX = (int) Math.floor(mercX * n);
    int tileY = (int) Math.floor(mercY * n);

    return new int[]{tileX, tileY};
}

2,下载地图

        下载从左上点到右下点的所有小瓦片图片,并把这些小瓦片地图图片合并为一张完整的大地图图片,这些小瓦片地图的名称依次命名为 1.png,2.png....。下载次序是从左上角开始从左到右,从上到下依次生成图片。记得下载的时候需要有天地图的秘钥 tk 。

int k = 1;
// 从左上角开始从左到右,从上到下依次生成图片,图片序号依次递增
for (int j = leftUp[1]; j <= rightDown[1]; j++) {
    for (int i = leftUp[0]; i <= rightDown[0]; i++) {
        System.out.println("/" + j + "/" + i);
        HttpOkUtil.downloadImg("http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile" +
                "&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=" + zoom +
                "&TILEROW=" + j + "&TILECOL=" + i + "&tk=xx", pathParent + k + ".png");
        k++;
    }
}

 下载得到的小瓦片大概长这样

 

 融合地图代码:

    /**
     * 合并瓦片图片
     *
     * @param tiles           包含所有瓦片及其行列信息的列表
     * @param outputImagePath 输出合并后地图的文件路径
     * @throws IOException 如果图像文件读取失败或写入失败
     */
    public static void mergeTiles(List<BufferedImage> tiles, String outputImagePath, int widthCnt, int heightCnt) throws IOException {
        // 假设所有瓦片都是正方形,获取瓦片的宽度和高度
        int tileWidth = tiles.get(0).getWidth();
        int tileHeight = tiles.get(0).getHeight();

        // 计算合并后图像的尺寸
        int width = tileWidth * widthCnt;// (int) Math.ceil(Math.sqrt(tiles.size())) * tileWidth;
        int height = tileHeight * heightCnt;// (int) Math.ceil(Math.sqrt(tiles.size())) * tileHeight;// width; //
        // 假设合并后的地图是正方形

        // 创建一个新的图像,用于合并后的地图
        BufferedImage mergedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        // 使用Graphics2D来绘制图像
        Graphics2D g2d = mergedImage.createGraphics();

        // 绘制瓦片到新图像上
        int x = 0;
        int y = 0;
        for (BufferedImage tile : tiles) {
            g2d.drawImage(tile, x, y, null);
            x += tileWidth;
            if (x >= width) {
                x = 0;
                y += tileHeight;
            }
        }

        // 释放Graphics2D资源
        g2d.dispose();

        // 将合并后的图像写入文件
        ImageIO.write(mergedImage, "PNG", new File(outputImagePath));
    }

3,绘制多边形

        在这张融合好的大地图图片上绘制多边形和四至矩形图,因为大地图图片和小瓦片是 png 格式,没有地图坐标,所有要把 path 中的点相对于其在瓦片中的位置按比例进行计算。因为每个小瓦片都是 256*256 的像素格式,所以大地图就是 (256*width,256*height) ,以大地图的左上点为相对起始点开始绘画,可以精确到像素级。

// boundingBox 就是四至图,有左上,右下两个点,也就是西北点,东南点,即west,east,north,south这四个属性
for (GeoPoint point : list) {
    int[] pointXy = FourBoundariesGraphUtil.calculateTileXY(point.getY(), point.getX(), zoom);
    FourBoundariesGraphUtil.BoundingBox tmp = FourBoundariesGraphUtil.tile2boundingBox(pointXy[0], pointXy[1], zoom);
    res.add((pointXy[0] - originX) * 256 + (int) ((point.getX() - tmp.west) / (tmp.east - tmp.west) * 256));
    res.add((pointXy[1] - originY) * 256 + (int) ((tmp.north - point.getY()) / (tmp.north - tmp.south) * 256));
}

public static class BoundingBox {
        double north;
        double south;
        double east;
        double west;

        public double[] get_tianditu_info() {
            return new double[]{west, north, east, south};
        }
    }

    public static BoundingBox tile2boundingBox(final int x, final int y, final int zoom) {
        BoundingBox bb = new BoundingBox();
        bb.north = tile2lat(y, zoom);
        bb.south = tile2lat(y + 1, zoom);
        bb.west = tile2lon(x, zoom);
        bb.east = tile2lon(x + 1, zoom);
        return bb;
    }

    public static double tile2lon(int x, int z) {
        return x / Math.pow(2.0, z) * 360.0 - 180;
    }

    public static double tile2lat(int y, int z) {
        double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
        return Math.toDegrees(Math.atan(Math.sinh(n)));
    }
/**
 * 计算瓦片行列号
 * @param latitude  纬度
 * @param longitude 经度
 * @param zoom      缩放级别
 * @return 瓦片行列号数组,格式为 [col, row]
 */
public static int[] calculateTileXY(double latitude, double longitude, int zoom) {
    double n = Math.pow(2, zoom);
    double mercX = (longitude + 180) / 360;
    double mercY = (1 - Math.log(Math.tan(Math.toRadians(latitude)) + 1 / Math.cos(Math.toRadians(latitude))) / Math.PI) / 2;

    int tileX = (int) Math.floor(mercX * n);
    int tileY = (int) Math.floor(mercY * n);

    return new int[]{tileX, tileY};
}

把得到的坐标点绘制到图片,这个需要使用 Java Image 的 api,百度一下就知道了。如果需要在大地图图片里写其他的信息但发现大地图图片生成得有些小了,那就在下载瓦片的地方减小左上角或增大右下角的位置,多留一点空间,如果有其他的要求,也可以对生成好的地图图片进行裁剪。下载的地图可以是任意级别经度,只要天地图支持,默认是18级最大精度。

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

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

相关文章

如何从浅入深理解transformer?

前言 在人工智能的浩瀚海洋中&#xff0c;大模型目前无疑是其中一颗璀璨的明星。从简单的图像识别到复杂的自然语言处理&#xff0c;大模型在各个领域都取得了令人瞩目的成就。而在这其中&#xff0c;Transformer模型更是成为大模型技术的核心。 一、大模型的行业发展现状如…

AI实时免费在线图片工具3:人物换脸、图像编辑

1、FaceAdapter 人物换脸 https://huggingface.co/spaces/FaceAdapter/FaceAdapter 2、InstaDrag https://github.com/magic-research/InstaDrag

M-G364PD惯性测量单元:相机及微小层面的革命性应用

在现代科技飞速发展的今天&#xff0c;精准控制和精确测量是众多高端设备实现卓越性能的关键。爱普生推出的M-G364PD惯性测量单元&#xff08;IMU&#xff09;&#xff0c;因其卓越的性能和微小尺寸&#xff0c;成为相机以及其他微小层面应用的理想选择&#xff0c;为科技创新提…

实现计算器的基本操作:加减乘除与百分数

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、加减乘除的实现 1. 操作数与操作符 2. 逻辑处理 3. 示例代码 三、求百分数…

vue3 setup 使用 beforeRouteEnter 组件内路由守卫

vue3 setup 使用 beforeRouteEnter 组件内路由守卫 setup 中只有onBeforeRouteLeave、onBeforeRouteUpdate两个钩子函数&#xff0c; 没有beforeRouteEnter对应的钩子函数&#xff0c;所以无法在setup中直接使用 <script setup> onBeforeRouteLeave((to, from) > {// …

曹凯自然歌唱法·歌唱真谛说在罗浮山罗浮院子开讲

在追求梦想、享受音乐的道路上&#xff0c;每个人都渴望找到属于自己的声音&#xff0c;释放内心的情感。2024年5月18日&#xff0c;广东省发展中医药事业基金会与广州曹凯自然歌唱法学会携手在罗浮院子举行了隆重的挂牌仪式&#xff0c;同时“刷新声乐教育与演绎模式&#xff…

Golang | Leetcode Golang题解之第119题杨辉三角II

题目&#xff1a; 题解&#xff1a; func getRow(rowIndex int) []int {row : make([]int, rowIndex1)row[0] 1for i : 1; i < rowIndex; i {row[i] row[i-1] * (rowIndex - i 1) / i}return row }

Spring Boot 整合 spring-boot-starter-mail 实现邮件发送和账户激活

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

销量逆袭!敦煌店铺如何靠自养号测评轻松引爆市场?

对于众多卖家而言&#xff0c;踏入中国领先的B2B跨境电商平台&#xff0c;如同步入了充满无尽机会的金矿。然而&#xff0c;有些卖家在平台上努力经营&#xff0c;但订单却寥寥无几。那么&#xff0c;究竟是什么原因导致了这种情况&#xff1f;接下来&#xff0c;我们将结合实际…

chrome谷歌浏览器开启Gemini Nano模型

前提 确保您的操作系统语言设置为英语(美国) 可能还需要将 Chrome 浏览器的语言更改为英语(美国)。 下载dev或Canary版本Chrome Chrome Canary Chrome Dev 注意:确认您的版本高于 127.0.6512.0。 其中一个Chrome版本不行就切换另外一个版本 绕过性能检查 Tab输入: …

java基础-chapter15(io流)

io流&#xff1a;存储和读取数据的解决方案 I:input O:output io流的作用&#xff1a;用于读写数据&#xff08;本地文件,网络&#xff09; io流按照流向可以分为&#xff1a; 输出流&#xff1a;程序->文件 输入流&#xff1a;文件->程序 io流按照操作文件…

跨境电商如何收款?6大常用收款方式对比!

收款是跨境中关键的一环&#xff0c;选择一个安全、高效、成本合理的收款工具很重要。每个跨境人都要先想好选择合适的收款方式&#xff0c;今天就给跨境人们总结了6个主流的跨境收款工具&#xff0c;大家可以根据自己的实际情况进行对比选择。 1、PayPal 适用平台&#xff1a;…

python | 类的实现

和实例有关的&#xff0c;通过对象名&#xff0c;打点调用 实例属性&#xff0c;实例方法 stuStudent("XiaoMing",18) print(stu.name) 类属性、静态方法和类方法都是通过类名直接调用 Student.name 静态方法和类方法都不能调用实例属性和实例方法 动态绑定 如果是函…

SpringBoot中MyBatisPlus的使用

MyBatis Plus 是 MyBatis 的增强工具&#xff0c;提供了许多强大的功能&#xff0c;简化了 MyBatis 的使用。下面是在 Spring Boot 中使用 MyBatis Plus 的步骤&#xff1a; 添加依赖&#xff1a;在 Maven 或 Gradle 的配置文件中添加 MyBatis Plus 的依赖。 配置数据源&#…

MFC工控项目实例之二添加iPlotx控件

承接专栏《MFC工控项目实例之一主菜单制作》 在WIN10下使用Visual C 6.0 &#xff08;完整绿色版&#xff09;添加iPlotx控件的方法。 1、在资源主对话框界面点击鼠标右键如图选择插入Active控件点击进入。 2、选择iPlotx Contrlolh点击确定。 3、在对话框界面插入iPlotx控件。…

数组的应用-24点游戏

目录 24点游戏 游戏规则 游戏主要分为三部分 电脑出牌 用户输入算式 电脑判断胜负 总结 24点游戏 游戏规则&#xff1a; 54张扑克抽出大小王&#xff0c;剩余52张用来用于游戏&#xff1b;每一轮从52张牌中随机抽出4张&#xff1b;玩家运用加&#xff0c;减&#xff0…

LeetCode2300咒语和药水的成功对数

题目描述 解析 先对药水排序后每个咒语去二分查找最低满足的药水的位置。 class Solution {public int[] successfulPairs(int[] spells, int[] potions, long success) {int n spells.length, m potions.length;Arrays.sort(potions);for (int i 0; i < n; i) {long ta…

使用 Vue 3 和 vue-print-nb 插件实现复杂申请表的打印

文章目录 1&#xff1a;创建 Vue 3 项目2&#xff1a;安装 vue-print-nb 插件3&#xff1a;配置 vue-print-nb 插件4&#xff1a;创建一个复杂的申请表5&#xff1a;使用 ApplicationForm 组件6&#xff1a;运行项目 在开发管理系统或申请表打印功能时&#xff0c;打印功能是一…

2.6 Docker部署多个前端项目

2.6 Docker部署多个项目 三. 部署前端项目 1.将前端项目打包到同一目录下&#xff08;tcm-ui&#xff09; 2. 部署nginx容器 docker run --namenginx -p 9090:9090 -p 9091:9091 -d nginx3. 复制nginx.conf文件到主机目录 docker cp nginx:/etc/nginx/nginx.conf /root/ja…

【R基础】如何开始学习R-从下载R及Rstudio开始

文章目录 概要下载R流程下载Rstudio流程下载完成-打开 概要 提示&#xff1a;如何开始学习R-从下载R及Rstudio开始&#xff0c;此处我只是想下载指定版本R4.3.3 下载R流程 链接: R官网 文件下载到本地 下载文件展示 按照向导指示安装 下载Rstudio流程 链接: Rstudio官网…