区县级瓦片下载与合并(TIF、PNG)
区县级瓦片下载与合并TIF、PNGTL;DR输入“区县adcode 瓦片服务XYZ/WMTS Zoom 输出格式PNG/GeoTIFF”自动得到可直接使用的离线成果 ️介绍这是一个可以给定一个区县边界GeoJSON如何确定需要下载哪些瓦片并最终输出可用的 PNG 或 GeoTIFF含地理参考成果。这类能力常见于离线底图制作、项目现场无网应急、专题图快速成图、以及把“在线瓦片服务”沉淀为“本地可控资源”等场景。本文将围绕本仓库现有实现完整讲清楚从 GeoJSON 到瓦片范围推导、下载、合并、写入坐标参考的全过程并给出可复现的接口契约与关键代码片段 ✨你将获得一份可复用的“GeoJSON → BBox → TileRange”算法认知框架 对 Web Mercator / WGS84 / CGCS2000EPSG:3857/4326/4490关系的工程化理解 一条可落地的“合并输出 PNG/GeoTIFF”实践路径可在 QGIS 正确对齐 说明本文不修改模块代码文中所有实现说明以仓库现状为准避免对未实现能力做额外承诺。页面示意2.1 数据来源说明2.1.1 行政区与 GeoJSON 边界本项目使用的省/市/区行政区划数据与区县边界 GeoJSON 数据来源于 DataV.GeoAtlas 地理小工具行政区划选择器https://datav.aliyun.com/portal/school/atlas/area_selector该页面说明其数据源来自高德开放平台数据版本更新于仅供学习交流使用。下载步骤以“北京市海淀区”为例打开上述页面搜索“海淀区”或输入 adcode海淀区110108选择输出类型为 GeoJSON下载得到110108.jsonGeoJSON FeatureCollection本项目后端实际请求的 GeoJSON 地址模板为https://geo.datav.aliyun.com/areas_v3/bound/{adcode}.json例如海淀区https://geo.datav.aliyun.com/areas_v3/bound/110108.json2.1.2 瓦片服务XYZ / WMTS本文只列出项目当前内置的服务选项来自前端下拉框并说明其关键属性。注意不同服务的授权方式、更新频率可能随时间调整建议以服务提供方说明为准。XYZHTTP URL 模板典型 256×256 像素瓦片服务地址模板协议授权方式坐标系/切片矩阵OpenStreetMaphttps://tile.openstreetmap.org/{z}/{x}/{y}.pngXYZ无公共服务可能有限流策略EPSG:3857Web MercatorArcGIS World Imageryhttps://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}XYZ无公共服务可能有限流策略EPSG:3857Web MercatorOpenTopoMaphttps://tile.opentopomap.org/{z}/{x}/{y}.pngXYZ无公共服务可能有限流策略EPSG:3857Web MercatorCARTO Lighthttps://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.pngXYZ无公共服务可能有限流策略EPSG:3857Web MercatorWMTSOGC WMTS服务地址模板项目内置协议授权方式坐标系/切片矩阵天地图影像经纬度http://t0.tianditu.gov.cn/img_c/wmts?...TILEMATRIXSETc...tkWMTS需tkEPSG:4326经纬度天地图影像Webhttp://t0.tianditu.gov.cn/img_w/wmts?...TILEMATRIXSETw...tkWMTS需tkEPSG:3857Web Mercator空间分辨率与“更新频率”不同分辨率可计算瓦片“空间分辨率”主要由 zoom 决定。以 Web Mercator 为例设地球半径 (R6378137)单位米瓦片尺寸为 256 像素zoom 为 (z)则公式 (2-1)赤道处米/像素meters per pixelmpp(z) (2 * π * R) / (256 * 2^z)说明mpp(z)缩放级别 z 下的米/像素R地球半径Web Mercator 通常取 6378137 米256标准瓦片大小256 × 256 像素z瓦片缩放级别zoom level这意味着 zoom 每增加 1 级分辨率提升 2 倍米/像素减半。例如z 0 → 156543.0339 m/pixel z 10 → 152.87 m/pixel z 18 → 0.597 m/pixel2.2 模块的基本概念2.2.1 四至BBox与坐标换算① BBox 定义本文的 BBox 使用经纬度外接矩形表达minLon, minLat, maxLon, maxLat它表示“能覆盖整个行政区边界的最小矩形范围”。② WGS84 与 Web Mercator 互转公式Web MercatorEPSG:3857可理解为把经纬度投影到“米”为单位的平面坐标。设经度 ( \lambda )弧度、纬度 ( \varphi )弧度则公式 (2-2)经纬度 → Web Mercator单位米x R * λ y R * ln( tan( π/4 φ/2 ) )说明R地球半径Web Mercator 通常取 6378137λ经度弧度φ纬度弧度x、yWeb Mercator 投影坐标米公式 (2-3)Web Mercator → 经纬度弧度λ x / R φ 2 * atan( exp( y / R ) ) - π/2说明x、yWeb Mercator 坐标米λ经度弧度φ纬度弧度工程实现时通常需要对纬度做裁剪避免 (\tan) 或 (\ln) 溢出常见上限约为 85.05112878°。③ 度-米-像素三层换算推导Web Mercator 这条链路很直观度 → 弧度 → 米公式 2-2米 → 像素公式 2-1 给出 mpp像素 → 瓦片256 像素一片下面给出项目中“分辨率”的 Java 推导片段来自GeoToolsReprojectingWriter的瓦片范围推导逻辑doubleoriginShift2.0*Math.PI*6378137.0/2.0;doubleresolution(2.0*Math.PI*6378137.0)/(256.0*(1Lzoom));其中resolution就是公式 (2-1) 的 (\mathrm{mpp}(z))。2.2.2 XYZ 瓦片编号规则与由 bbox 反算行列号① XYZ 规则Web MercatorXYZ 瓦片通常使用z缩放级别x从左到右递增y从上到下递增注意与某些 TMS 方案相反② 层级与分辨率对照表示例以公式 (2-1) 为准赤道处可得到以下典型值Zoom (z)m/px赤道每瓦片覆盖约米0156543.033940075016.69178271.516920037508.34239135.758510018754.17319567.87925009377.0949783.93962504688.548611.4962156543.03“每瓦片覆盖” m/px * 256。③ 由 bbox 反算 tileCol/tileRow项目实现在本项目中核心逻辑集中在TileUtils.tilesForBbox(...)bbox → 命中的瓦片坐标集合TileUtils.TileMatrixSet.lonLatToTile(...)经纬度 → (x,y,z)精简后的核心算法如下以WEB_MERCATOR为例intn1zoom;intx(int)Math.floor((lon180.0)/360.0*n);doublelatRadMath.toRadians(lat);inty(int)Math.floor((1.0-Math.log(Math.tan(latRad)(1.0/Math.cos(latRad)))/Math.PI)/2.0*n);当 bbox 给出minLon/maxLon/minLat/maxLat时项目采用“左上角 右下角”转换成瓦片坐标再取矩形范围TileCoordnwmatrixSet.lonLatToTile(bbox.minLon(),bbox.maxLat(),zoom);TileCoordsematrixSet.lonLatToTile(bbox.maxLon(),bbox.minLat(),zoom);随后对 (minX…maxX, minY…maxY) 生成瓦片列表并限制最大数量以避免 OOM。坐标系识别下载任务会传入sourceEpsgEPSG:3857 / EPSG:4326后端以此选择切片矩阵。对应逻辑见TileDownloadService.detectMatrixSet(...)。2.2.3 TIF / GeoTIFF 结构与本项目支持情况① TIFF 与 GeoTIFF 简述TIFF一种通用栅格文件容器格式可存储多种像素类型与压缩方式。GeoTIFF在 TIFF 基础上通过一组地理标签GeoTIFF Tags / GeoKeys描述影像的坐标参考与空间定位从而使其能在 GIS 软件中“对齐到正确的位置”。GeoTIFF 常见关键标签包括ModelPixelScaleTag像元大小单位与 CRS 相关ModelTiepointTag像元与地理坐标的锚点GeoKeyDirectoryTag坐标系统与投影信息EPSG 等② 本项目写出方式与依赖版本本项目当前通过 GeoTools 写出 GeoTIFFGeoTiffTileWriter使用GridCoverageFactoryGeoTiffWriter依赖版本GeoTools27.2见pom.xml的geotools.version写出逻辑精简CoordinateReferenceSystemcrsCRS.decode(EPSG:4326,true);Envelope2DenvnewEnvelope2D(crs,minLon,minLat,widthDeg,heightDeg);GridCoverage2Dcoveragefactory.create(tiles,image,env);newGeoTiffWriter(tmp).write(coverage,null);③ BigTIFF / Cloud Optimized GeoTIFFCOG支持说明当前代码使用的是标准GeoTiffWriter直接写出文件未显式开启 BigTIFF 或 COG 专项优化参数。如果需要支持更大文件或云原生访问一般需要选择 BigTIFF 写出参数当文件超过 4GB 时COG 需要内部分块tiling、概览层overviews与排序优化这些属于扩展方向本文不做“已支持”的承诺。2.3 功能实现与关键代码说明2.3.1 整体架构图TileDownloader.vueRegionControllerTileDownloadServiceGeoJsonBboxUtilsTileUtils.TileMatrixSet tilesForBboxTileUtils.http 缓存/下载TileUtils.mergeToTileImage/mergeToImageGeoToolsReprojectingWriterPNG / GeoTIFF Writer2.3.2 数据流程GeoJSON 解析入口TileDownloadService.fetchRegionBBox(adcode)通过 URL 拉取 GeoJSON。BBOX 提取GeoJsonBboxUtils.extractBBox(InputStream)递归遍历geometry.coordinates计算极值。瓦片行列计算TileUtils.tilesForBbox(bbox, zoom, matrixSet)根据TileMatrixSet把 bbox 映射到瓦片矩形范围。多线程下载合并模式TileUtils.mergeToImage(...)使用线程池并发下载。非合并模式downloadAsXyz(...)使用并行流批量落盘。无损合并合并模式mergeToImage把每张 256×256 瓦片绘制到同一张BufferedImage画布中。坐标系写入GeoTIFF/ 直接输出PNG合并模式通过GeoToolsReprojectingWriter可选后再由 PNG 或 GeoTIFF writer 输出到文件。2.3.3 核心类精简源码A) GeoJSON → BBox文件src/main/java/com/example/gisgallery/common/util/geojson/GeoJsonBboxUtils.javapublicstaticTileUtils.BBoxextractBBox(JsonNoderoot)throwsIOException{if(root.has(bbox)){JsonNodebroot.get(bbox);if(b.isArray()b.size()4){returnnewTileUtils.BBox(b.get(0).asDouble(),b.get(1).asDouble(),b.get(2).asDouble(),b.get(3).asDouble());}}Stringtyperoot.has(type)?root.get(type).asText():;if(FeatureCollection.equalsIgnoreCase(type)){JsonNodefeaturesroot.get(features);if(features!nullfeatures.isArray()){returncalculateBBoxFromFeatures(features);}}thrownewIOException(无法从 GeoJSON 中提取或计算有效的 BBox);}B) bbox → tiles矩形范围文件src/main/java/com/example/gisgallery/common/util/TileUtils.javaTileCoordnwmatrixSet.lonLatToTile(bbox.minLon(),bbox.maxLat(),zoom);TileCoordsematrixSet.lonLatToTile(bbox.maxLon(),bbox.minLat(),zoom);intminXclamp(Math.min(nw.x(),se.x()),0,width-1);intmaxXclamp(Math.max(nw.x(),se.x()),0,width-1);intminYclamp(Math.min(nw.y(),se.y()),0,height-1);intmaxYclamp(Math.max(nw.y(),se.y()),0,height-1);C) 下载与合并输出PNG / GeoTIFF文件src/main/java/com/example/gisgallery/gridtile/application/service/TileDownloadService.javaStringexttif.equalsIgnoreCase(request.getFormat())?tif:png;TileUtils.TileImageWriterbaseWritertif.equalsIgnoreCase(request.getFormat())?GeoTiffTileWriter.writer():TileUtils.OutputFormat.PNG.writer();TileUtils.TileImageWriterwriternewGeoToolsReprojectingWriter(baseWriter,request.getTargetEpsg());2.3.4 性能基准当前代码未内置基准测试类。建议把“单区县、0–8 级”作为一个可验证的工程目标并在本机按以下方式测量计时下载任务提交后记录开始/结束时间观察输出文件大小与数量监控 JVMjcmd pid VM.native_memory summary或 IDE profiler公开瓦片服务可能有并发/频率限制性能结果会受到网络与服务端策略影响。本文不对具体秒数做硬性保证。2.4 前端实现哪些内容2.4.1 技术栈与请求封装Vue 3 Vite项目frontend/Axios统一请求封装frontend/src/utils/request.jsAPIfrontend/src/api/gridtile.js2.4.2 当前页面已实现的交互文件frontend/src/components/TileDownloader.vue当前页面包含省/市/区三级联动选择瓦片服务选择XYZ/WMTS源坐标系选择EPSG:3857 / EPSG:4326输出格式选择PNG / GeoTIFF是否合并输出合并文件 vs z/x/y 目录结构提交任务后展示taskId与outputPath当前页面未包含GeoJSON 地图可视化、bbox 拖拽调整、下载实时进度条、断点续传 UI。这些属于后续可扩展功能若要实现需要新增后端“任务进度查询/任务取消”等接口与前端轮询/订阅机制。2.4.3 与后端 REST 接口契约OpenAPI 3.0 片段以下片段与当前后端接口一致RegionControlleropenapi:3.0.3info:title:GIS Gallery-GridTile APIversion:0.1.0paths:/api/gridtile/regions:get:summary:获取行政区划树responses:200:description:OKcontent:application/json:schema:type:objectproperties:code:{type:integer,example:200}message:{type:string,example:success}data:{type:object}/api/gridtile/download:post:summary:提交区县瓦片下载任务requestBody:required:truecontent:application/json:schema:type:objectrequired:[adcode,regionName,zoomLevels,serviceUrl,merge]properties:adcode:{type:integer,example:110108}regionName:{type:string,example:北京市海淀区}zoomLevels:type:arrayitems:{type:integer}example:[8]serviceUrl:type:stringexample:https://tile.openstreetmap.org/{z}/{x}/{y}.pngmerge:{type:boolean,example:true}sourceEpsg:{type:string,example:EPSG:3857}targetEpsg:{type:string,example:EPSG:4490}format:{type:string,enum:[png,tif],example:tif}responses:200:description:OKcontent:application/json:schema:type:objectproperties:code:{type:integer,example:200}message:{type:string,example:success}data:type:objectproperties:taskId:{type:string}status:{type:string,example:RUNNING}outputPath:{type:string}2.5 总结GeoJSON 驱动通过区县边界 geometry 自动计算 bbox避免手工框选误差坐标链路明确源坐标系3857/4326→ 瓦片矩阵 → 输出坐标系4326/4490合并与非合并两条路径满足“可视化成图”和“离线切片”两类场景GeoTIFF 输出通过 GeoTools 为合并影像写入地理参考便于在 QGIS/ArcGIS 中加载3. 开箱即用代码仓库 本专栏对应的完整工程已开源按 README 步骤即可运行后端一体化打包 / 前后端分离开发均支持https://github.com/clpz299/gis-gallery.git ⭐