java矢量切片实现

news/2024/10/17 12:21:51/

概述

可通过多种方式实现矢量切片的制作,前面讲到了基于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中添加layerMvtLayer layer = mvtBuilder.getOrCreateLayer("province-polygon");//向layer中添加featurefor (Feature feature : areaFeatureCollection.getFeatures()) {//这里简单地从内存中取数据并判断其是否与瓦片有交集,实际运用中可从数据库查询,例如postgis的ST_intersects函数if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {layer.addFeature(feature);}}//如法炮制添加layerlayer = mvtBuilder.getOrCreateLayer("province-line");for (Feature feature : lineFeatureCollection.getFeatures()) {if (mvtBuilder.getBbox().envIntersects(feature.getGeometry())) {layer.addFeature(feature);}}//如法炮制添加layerlayer = 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写进HttpServletResponseprivate 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.ppmy.cn/news/86684.html

相关文章

【Unity】实现无缝地图

无缝地图是沙盒游戏的标配&#xff0c;可以极大提升玩家体验和沉浸感。 无缝地图的实现过程还是比较复杂的&#xff0c;在这里做一下实现笔记 1、地图分块&#xff1a; 将地图划分为较小的块&#xff0c;例如瓦片或区块。每个块可以是一个独立的游戏对象或地形块。确定每个块…

全国第六届研究生数学建模竞赛-110 警车配置及巡逻方案

目录 摘 要: 1 问题重述 2 问题分析 3 模型假设 4 符号定义与说明 4.1 符号表定义

vim的使用、vim入门的三种常用模式、以及vim中常用的命令(超详细)

vim 入门的三种常用模式&#xff1a;分别是 1. 命令模式、2. 插入/编辑模式、3. 底行模式 1. 命令模式 控制屏幕光标的移动&#xff0c;字符、字或行的删除&#xff0c;移动复制某区段及进入Insert mode下&#xff0c;或者到 last line mode 如下&#xff0c;这个就是命令模式…

【数据结构】KMP算法概述

KMP算法&#xff0c;全称为Knuth-Morris-Pratt算法&#xff0c;是一种用于字符串匹配的算法。它的核心思想是利用已知信息来避免无用的比较操作&#xff0c;从而提高算法效率。KMP算法的时间复杂度为O(n m)&#xff0c;其中n为模式串的长度&#xff0c;m为文本串的长度。 本文…

JNDI学习笔记

最近在研究JNDI注入漏洞&#xff0c;就先浅浅的学习以下JNDI相关知识。 JNDI对各种目录服务的实现进行抽象和统一化。 在 Java 应用中除了以常规方式使用名称服务(比如使用 DNS 解析域名)&#xff0c;另一个常见的用法是使用目录服务作为对象存储的系统&#xff0c;即用目录服务…

Spring Cloud(Kilburn 2022.0.2版本)系列教程(二) 服务消费者(RestTemplate+Loadbalancer)

Spring Cloud(Kilburn 2022.0.2版本)系列教程(二) 服务消费者(RestTemplate+Loadbalancer) 为了更好的浏览体验,欢迎光顾勤奋的凯尔森同学个人博客http://www.huerpu.cc:7000 一、服务消费 可以参考上节eurekaClientConsumer。 在启动类中,我们已经注入了一个restTemplate…

Linux音频和视频命令速查表

在Linux系统中&#xff0c;有许多命令可以帮助我们处理音频和视频文件&#xff0c;从基本的播放和转码&#xff0c;到编辑和处理音频、视频流。 本文将提供一个Linux音频和视频命令速查表&#xff0c;帮助您快速查找并了解各种常用的命令及其用法。 音频命令 播放音频文件 a…

超长溢出头部省略打点,坑这么大,技巧这么多?

目录 需求 利用 direction 实现头部超长溢出打点 简单介绍一下 direction&#xff1a; 另外两个与排版相关的属性还有&#xff1a; direction: rtl 会导致使用下划线 _ 连接的数字内容排版错误 多方案解决 方案一&#xff1a;两次 direction 反转 当然&#xff0c;这里…