GIS动态矢量切片
前言
有关矢量切片以及MVT(MapBox Vector Tile)自行搜索了解,不再赘述。
接口格式 http://domain:port/map/vector/tile/{z}/{x}/{y}
,其中z代表缩放层级,x、y代表当前行列号
一、方法
采用postgis的函数ST_AsMVT、ST_AsMVTGeom、ST_TileEnvelope函数,实现此功能。
简单讲 ST_TileEnvelope
函数用于计算行列并返回对应的矩形范围,ST_AsMVTGeom
返回图层中对应行的坐标,ST_AsMVT
返回二进制的Mapbox Vector Tile
数据。
函数解释
ST_AsMVT:返回一个二进制Mapbox Vector Tile
二、环境
Postresql 12.x + Postgis + Spring Boot
三、实现
MapBoxVectorTile
package com.osgeo.vectortile.domain;
import lombok.Data;
@Data
public class MapBoxVectorTile {
private byte[] tile;
}
MapBoxVectorTileMapper
package com.osgeo.vectortile.mapper;
import com.baomidou.mybatisplus.annotation.SqlParser;
import com.osgeo.vectortile.domain.MapBoxVectorTile;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface MapBoxVectorTileMapper {
@SqlParser(filter=true)
MapBoxVectorTile vectorTitle2(@Param("z") Integer z, @Param("x") Integer x, @Param("y") Integer y, @Param("dpi") Integer dpi);
}
MapBoxVectorTileMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.osgeo.vectortile.mapper.MapBoxVectorTileMapper">
<resultMap type="com.osgeo.vectortile.domain.MapBoxVectorTile" id="MapBoxVectorTileResult">
<result property="tile" column="tile"/>
</resultMap>
<select id="vectorTitle2" resultMap="MapBoxVectorTileResult">
SELECT ST_AsMVT(tiletable.*, 'gb_title', #{dpi}) as tile
FROM (SELECT id,
project_name as name,
approval_year as "year",
build_address as poi,
dept_id as dept,
ST_AsMVTGeom(geo_rangeline, ST_Transform(ST_TileEnvelope(#{z}, #{x}, #{y}), 4326), #{dpi}) as geom
from (select *
from gbt_project_info
where 1 = 1
and ST_Intersects(ST_Transform(ST_TileEnvelope(#{z}, #{x}, #{y}), 4326),
geo_rangeline)) ta) as tiletable
where tiletable.geom is not null;
</select>
</mapper>
MapBoxVectorTileServiceImpl
package com.osgeo.vectortile.service.impl;
import com.osgeo.vectortile.mapper.MapBoxVectorTileMapper;
import com.osgeo.vectortile.service.MapBoxVectorTileService;
import com.osgeo.vectortile.utils.MapBoxVectorTileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MapBoxVectorTileServiceImpl implements MapBoxVectorTileService {
@Autowired
MapBoxVectorTileMapper mapper;
@Override
public byte[] vectorTitle(Integer z, Integer x, Integer y) {
Integer dpi = MapBoxVectorTileUtil.zoom2dpi(z);
return mapper.vectorTitle2(z, x, y, dpi).getTile();
}
}
package com.osgeo.vectortile.utils;
import com.osgeo.vectortile.domain.TileBox;
import java.util.HashMap;
import java.util.Map;
public class MapBoxVectorTileUtil {
private static Map<Integer, Integer> map;
static {
map = new HashMap<>();
map.put(1, 2);
map.put(2, 2);
map.put(3, 2);
map.put(5, 2);
map.put(6, 2);
map.put(7, 512);
map.put(8, 512);
map.put(9, 1024);
map.put(10, 1024);
map.put(11, 1024);
map.put(12, 1024);
map.put(13, 2048);
map.put(14, 2048);
map.put(15, 4096);
map.put(16, 4096);
map.put(17, 4096);
map.put(18, 4096);
map.put(19, 4096);
map.put(20, 4096);
}
public static Integer zoom2dpi(Integer z) {
return map.containsKey(z) ? map.get(z) : 2048;
}
}
MapBoxVectorTileService
package com.osgeo.vectortile.service;
public interface MapBoxVectorTileService {
byte[] vectorTitle(Integer z, Integer x, Integer y);
}
MapBoxVectorTileController
package com.osgeo.vectortile.controller;
import com.osgeo.vectortile.service.MapBoxVectorTileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@RestController
@RequestMapping("/map/vector/tile")
public class MapBoxVectorTileController {
@Autowired
MapBoxVectorTileService service;
@GetMapping("/new/{z}/{x}/{y}")
public void vectorTitle2(@PathVariable("z")Integer z, @PathVariable("x") Integer x, @PathVariable("y") Integer y, HttpServletResponse response){
response.setContentType("application/x-protobuf;type=mapbox-vector;chartset=UTF-8");
byte[] tile = service.vectorTitle2(z, x, y);
// 输出文件流
OutputStream os = null;
InputStream is = null;
try {
is = new ByteArrayInputStream(tile);
os = response.getOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}