java矢量切片实现

news2024/10/6 6:54:35

概述

可通过多种方式实现矢量切片的制作,前面讲到了基于postgis数据库、tippecanoe、Qgis等方式,本文讲述基于spring Boot框架下java的实现。

实现效果

image.png

实现代码

后端代码

  1. 引入依赖
<dependency>
      <artifactId>giscat-vector-mvt</artifactId>
      <groupId>org.wowtools</groupId>
      <version>g1.6.1</version>
</dependency>
  1. MvtController
package com.lzugis.controller;

import com.lzugis.utils.FileUtil;
import io.swagger.annotations.Api;
import org.locationtech.jts.geom.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wowtools.giscat.vector.mvt.MvtBuilder;
import org.wowtools.giscat.vector.mvt.MvtLayer;
import org.wowtools.giscat.vector.pojo.Feature;
import org.wowtools.giscat.vector.pojo.FeatureCollection;
import org.wowtools.giscat.vector.pojo.converter.GeoJsonFeatureConverter;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Api(tags = "矢量切片")
@RestController
@RequestMapping("tile")
public class MvtController {
    private static final FeatureCollection areaFeatureCollection;//面数据
    private static final FeatureCollection lineFeatureCollection;//线数据
    private static final FeatureCollection pointFeatureCollection;//点数据
    private static final GeometryFactory geometryFactory = new GeometryFactory();
    private static final FileUtil fileUtil = new FileUtil();

    static {
        //构造示例数据
        GeometryFactory gf = new GeometryFactory();
        String strJson = fileUtil.getFileContent("data\\province.geojson");
        areaFeatureCollection = GeoJsonFeatureConverter.fromGeoJsonFeatureCollection(strJson, gf);
        ArrayList<Feature> pointFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
        ArrayList<Feature> lineFeatures = new ArrayList<>(areaFeatureCollection.getFeatures().size());
        for (Feature feature : areaFeatureCollection.getFeatures()) {
            Feature pointFeature = new Feature();
            ArrayList center = (ArrayList) feature.getProperties().get("center");
            if (center != null) {
                Point point = gf.createPoint(new Coordinate((Double) center.get(0), (Double) center.get(1)));
                Map map = new HashMap();
                map.put("name", feature.getProperties().get("name"));
                pointFeature.setProperties(map);
                pointFeature.setGeometry(point);
                pointFeatures.add(pointFeature);
            }
            Feature lineFeature = new Feature();
            if (feature.getGeometry() instanceof MultiPolygon) {
                MultiPolygon multiPolygon = (MultiPolygon) feature.getGeometry();
                LineString[] lines = new LineString[multiPolygon.getNumGeometries()];
                for (int i = 0; i < multiPolygon.getNumGeometries(); i++) {
                    Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
                    lines[i] = gf.createLineString(polygon.getExteriorRing().getCoordinates());
                }
                MultiLineString ml = gf.createMultiLineString(lines);
                lineFeature.setGeometry(ml);
            } else {
                LineString line = gf.createLineString(feature.getGeometry().getCoordinates());
                lineFeature.setGeometry(line);
            }
            lineFeatures.add(lineFeature);
        }
        lineFeatureCollection = new FeatureCollection();
        lineFeatureCollection.setFeatures(lineFeatures);
        pointFeatureCollection = new FeatureCollection();
        pointFeatureCollection.setFeatures(pointFeatures);
    }

    @RequestMapping("/{z}/{x}/{y}")
    public void getTile(@PathVariable byte z, @PathVariable int x, @PathVariable int y, HttpServletResponse response) {
        //构造一个MvtBuilder对象
        MvtBuilder mvtBuilder = new MvtBuilder(z, x, y, geometryFactory);
        //向mvt中添加layer
        MvtLayer layer = mvtBuilder.getOrCreateLayer("province-polygon");
        //向layer中添加feature
        for (Feature feature : areaFeatureCollection.getFeatures()) {
            //这里简单地从内存中取数据并判断其是否与瓦片有交集,实际运用中可从数据库查询,例如postgis的ST_intersects函数
            if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
                layer.addFeature(feature);
            }
        }
        //如法炮制添加layer
        layer = mvtBuilder.getOrCreateLayer("province-line");
        for (Feature feature : lineFeatureCollection.getFeatures()) {
            if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
                layer.addFeature(feature);
            }
        }
        //如法炮制添加layer
        layer = mvtBuilder.getOrCreateLayer("province-point");
        for (Feature feature : pointFeatureCollection.getFeatures()) {
            if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {
                layer.addFeature(feature);
            }
        }
        //数据添加完毕,转为
        byte[] bytes = mvtBuilder.toBytes();
        String vtContentType = "application/octet-stream";
        exportByte(bytes, vtContentType, response);
    }
    //将bytes写进HttpServletResponse
    private void exportByte(byte[] bytes, String contentType, HttpServletResponse response) {
        response.setContentType(contentType);
        try (OutputStream os = response.getOutputStream()) {
            os.write(bytes);
            os.flush();
        } catch (org.apache.catalina.connector.ClientAbortException e) {
            //地图移动时客户端主动取消, 产生异常"你的主机中的软件中止了一个已建立的连接",无需处理
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

前端代码

<div id="map"></div>
 <script>
     var mapStyle = {
         "version": 8,
         "name": "Dark",
         "sources": {
             'province-data': {
                 'type': 'vector',
                 'tiles': ['http://localhost:18888/lzugis/tile/{z}/{x}/{y}']
             }
         },
         "layers": [
             {
                 'id': 'province-line',
                 'type': 'line',
                 'source': 'province-data',
                 'source-layer': 'province-line',
                 'paint': {
                     'line-color': '#31aa00',
                     'line-width': 2
                 }
             },
             {
                 'id': 'province-point',
                 'type': 'circle',
                 'source': 'province-data',
                 'source-layer': 'province-point',
                 'paint': {
                     'circle-color': '#f00',
                     'circle-radius': 5
                 }
             }
         ]
     };
     window.map = new mapboxgl.Map({
         container: 'map',
         maxZoom: 10,
         minZoom: 3,
         zoom: 3,
         center: [109.1699, 45.9719],
         style: mapStyle,
         attributionControl: false
     });
     map.on('click', function (e) {
         const coords = e.lngLat;
         const r = [
             [e.point.x - 5, e.point.y - 5],
             [e.point.x + 5, e.point.y + 5],
         ];
         const features = map.queryRenderedFeatures(r, {});
         console.log(features);
     })
 </script>

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

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

相关文章

Microsoft Office 2021安装

哈喽&#xff0c;大家好。今天一起学习的是office2021的安装&#xff0c;有兴趣的小伙伴也可以来一起试试手。 一、测试演示参数 演示操作系统&#xff1a;Windows 11 支持Win10安装&#xff0c;不支持Win7、XP系统 系统类型&#xff1a;64位 演示版本&#xff1a;cn_office_…

公有云弊端尽显,“云回迁”真的来了吗?

5到10年前&#xff0c;如果一家企业制定数字化转型战略&#xff0c;那么这项战略的核心大概率是将业务迁移上云。 现在&#xff0c;多数企业的业务已在云中“开花结果”&#xff0c;与以往不同的是&#xff0c;原先的一“朵”云变成了一“片”云。 没错&#xff0c;多云战略正…

Java集合底层原理总结

文章目录 一、集合分类二、遍历集合方式三、单列集合3.1 List3.1.1 ArrayList底层分析3.1.2 LinkedList底层分析 3.2 Set3.2.1 HashSet&#xff08;无序&#xff09;底层分析3.2.2 LinkedHashSet&#xff08;有序&#xff0c;存取一致&#xff09;3.2.3 TreeSet&#xff08;可排…

[LitCTF 2023]easy_shark

下载附件解压出现密码提示 使用010editor打开&#xff0c;发现frflags和deflags都被修改了&#xff0c;这就会造成压缩包伪加密 将它们都改回0&#xff0c;另存为再打开&#xff0c;不再出现密码提示 使用wirshark打开 过滤http并追踪&#xff0c;在最后一个包里找到了类似fla…

车载以太网 - SomeIP - 协议用例 - on-wire

目录 Specification of the SOME/IP on-wire format 1.1、验证Response报文中的源IP地址为Request报文中的目标IP地址

搭建stm32电机控制代码框架(二)——Stm32CubeMx配置定时器

搭建了基础的环境&#xff0c;配置了一个简单的工程后&#xff0c;CubeMx的基本操作就会了。然后基于这个操作往下推进&#xff0c;开始对关键模块定时器的攻略&#xff0c;这个部分需要先熟悉一下Stm32的定时器基本原理。 《STM32参考手册》中仅对定时器的介绍就已经占了100多…

C++的最后一道坎 | 百万年薪的程序员

| 导语 C 的起源可以追溯到 40 年前&#xff0c;但它仍然是当今使用最广泛的编程语言之一&#xff0c;C发明人Bjarne Stroustrup 一开始没想到 C 会获得如此大的成功&#xff0c;他说&#xff1a;“C 的成功显然令人惊讶。我认为它的成功取决于其最初的设计目标&#xff0c;就是…

用nginx实现一个直播服务—RTMP推流和HTTP-FLV拉流

目录 一、环境准备 二、安装编译nginx所需的安装包和下载nginx原代码包 三、nginx配置 四、启动nginx服务 五、测试推流和拉流服务 六、摄像头数据采集 七、查看统计 这篇文章主要记录用nginx实现直播服务&#xff0c;通过RTMP推流和通过HTTP-FLV或RTMP拉流&#xff0c;…

DJ5-4 链路层交换机

目录 一、链路层交换机 二、交换机&#xff1a;支持多节点同时传输 三、交换机&#xff1a;转发表或称交换表 四、交互机&#xff1a;自学习 1. 单个交换机自学习/转发的例子 2. 多个交换机自学习/转发的例子 五、交换机&#xff1a;数据帧的过滤/转发 六、交换机的交换…

css基础技巧

1. emmet语法 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>…

如何在CSDN获取更多的铁粉?

一、铁粉的定义 要想获取铁粉&#xff0c;首先我们得知道什么是铁粉&#xff0c;根据官方给出定义是下面这样的&#xff1a; 【铁粉】具体规则如下&#xff1a; 铁粉 90 天内有阅读&#xff0c;购买专栏或其他互动&#xff0c;并且原力等级 > 0 的粉丝。 也就是说你的原力…

数据结构——二叉树_(上)

学习二叉树之前我们首先要对树有一个认识&#xff0c;树是一种非线性结构&#xff0c;它是由n(n>0)个有限节点组成的一个具有层次关系的节点&#xff1b;而这个层次结构倒过来看就十分的像一棵树&#xff0c;所以起名树结构。 跟现实中的树一样&#xff0c;树结构也有一个根…

Altium Designer18基础

原理图 第5课 元件库介绍及电阻容模型的创建.mp4_哔哩哔哩_bilibili 原理图库&#xff08;schLib&#xff09; 1. 创建原理图库&#xff1a; panels -> SCHLIB&#xff1a;左侧弹出SCH Lib窗口 Add&#xff1a;新建原理图库 点击原理图库名称&#xff1a;进入原理图库设置…

【短视频矩阵系统源码搭建+二开源码定制部署】

短视频矩阵源码的框架有很多种&#xff0c;根据不同的业务需求和技术要求&#xff0c;可选择适合的框架。目前常见的短视频矩阵源码框架有&#xff1a;Flutter、React Native、Vue、Angular等前端框架&#xff1b;Spring Boot、Laravel等后端框架&#xff1b;FFmpeg、Pusher、W…

ChatGPT“保姆级教程”——手把手教你5分钟快速AI智能文字转爆款视频(剪映+百度AIGC平台)

目录 前言ChatGPT 剪映ChatGPT生成视频文档安装专业版剪映使用剪映一键出片保姆集教程 百度AIGC平台注册百度AIGC平台使用百度AIGC平台一键出片保姆集教程 总结其它资料下载 前言 在这个数字时代&#xff0c;视频已经成为了最流行的内容形式之一。而如何自动将文字转化为引人…

JavaScript实现输入学生姓名,按q键程序结束的代码

以下为实现输入输入学生姓名&#xff0c;按q键程序结束的程序代码和运行截图 目录 前言 一、输入学生姓名&#xff0c;按q键程序结束 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#…

Web应用技术(第十三周/第二次练习/7h)

本次练习基于how2java和课本&#xff0c;学习MyBatis高级映和分页 1.MyBatis高级映射&#xff1a;1.1 相关XML标签及其属性&#xff1a;&#xff08;1&#xff09;mapper标签&#xff1a;&#xff08;2&#xff09;DOCTYPE标签&#xff1a;&#xff08;3&#xff09;typeAliase…

【MySQL】MySQL体系架构

文章目录 背景一、MySQL体系架构二、网络连接层三、数据库服务层3.1 连接池3.2 系统管理和控制工具3.3 SQL接口3.4 解析树3.5 查询优化器3.6 缓存 四、存储引擎层五、系统文件层5.1 日志文件5.2 数据文件5.3 配置文件5.4 pid文件5.5 socket文件 背景 很多小伙伴工作很长时间了…

【OJ比赛日历】快周末了,不来一场比赛吗? #05.27-06.02 #14场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-05-27&#xff08;周六&#xff09; #8场比赛2023-05-28…

Holocube-第一集

准备工作&#xff1a; 装备&#xff1a; ESP 8266 D1 MINI1.3寸 TFT 屏幕分光棱镜25.4mm面包板、杜邦线、数据线等配件 软件&#xff1a; Arduino(本人使用1.8.16)---驱动ch341 初始arduino简单程序&#xff0c;对esp8266上传代码&#xff0c;能正常运行。正式开始 坑1&…