java矢量切片实现

2023-05-27 14:33:25 浏览数 (2)

概述

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

实现代码

后端代码

  1. 引入依赖
代码语言:javascript复制
<dependency>
      <artifactId>giscat-vector-mvt</artifactId>
      <groupId>org.wowtools</groupId>
      <version>g1.6.1</version>
</dependency>
  1. MvtController
代码语言:javascript复制
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);
        }
    }
}

前端代码

代码语言:javascript复制
<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>

0 人点赞