You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

求助:SharpMap中WMTS/TMS Server实现及数据加载问题解决

SharpMap中WMTS/TMS Server实现问题排查与解决

老哥,我太懂你这种卡壳的憋屈了——SharpMap里WMTS/TMS和WMS看着像孪生兄弟,但底层的瓦片逻辑、坐标处理差得挺远,光照搬WMS的数据库查询肯定行不通。结合我之前踩过的坑,给你捋捋问题出在哪,以及怎么改:

核心差异:WMS vs WMTS/TMS

WMS是按需查询任意范围的数据,而WMTS/TMS是基于固定网格的瓦片切片,每个请求只对应某一个精准瓦片的范围。你之前直接复用WMS的DatabaseUtil.SqlServer调用,最大的问题就是没适配瓦片的核心参数:

  • WMS用的是请求传入的任意bbox,WMTS/TMS则需要通过TileMatrix(瓦片层级)、TileRow(行号)、TileCol(列号)计算出当前瓦片的专属bbox
  • WMS的渲染尺寸是动态的,WMTS/TMS的瓦片尺寸通常是固定的(比如256x256),你传的new Size(1,1)完全不符合瓦片渲染的要求

具体修改步骤

1. 正确计算瓦片的专属BBox

首先得把WMTS请求里的瓦片参数转换成实际的地理范围:

// 先定义你的瓦片矩阵集(比如Web墨卡托EPSG:3857的标准瓦片集)
var tileMatrixSet = new TileMatrixSet(
    "EPSG:3857",
    new CoordinateSystemFactory().CreateFromWkt(SharpMap.CoordinateSystems.WebMercator.WKT),
    new List<TileMatrix>
    {
        new TileMatrix("0", 0, 1, 1, 256, 256, new Envelope(-20037508.3427892, 20037508.3427892, -20037508.3427892, 20037508.3427892))
        // 这里要补充所有你支持的瓦片层级的参数,比如1级、2级...
    }
);

// 根据请求的TileMatrix、TileRow、TileCol计算当前瓦片的BBox
var tileMatrix = tileMatrixSet.GetTileMatrix(request.TileMatrix);
var tileBBox = tileMatrix.GetTileEnvelope(request.TileRow, request.TileCol);

2. 适配数据库查询参数

把原来的WMS风格查询改成适配瓦片的版本:

// 瓦片尺寸改成标准的256x256(或者你定义的瓦片大小)
var tileSize = new Size(256, 256);
// 用计算好的瓦片专属BBox,而不是直接用请求传入的BBox
var features = DatabaseUtil.SqlServer(
    ConnectionString(),
    Layers(),
    tileSize,
    tileBBox,
    "id"
);

注意:如果你的SQL Server数据坐标系和WMTS的坐标系不一致(比如数据是EPSG:4326,WMTS是EPSG:3857),必须在查询前做坐标转换,比如用SharpMap的CoordinateTransformationtileBBox转成数据的坐标系,或者在SQL语句里用ST_Transform做转换。

3. 修复瓦片渲染逻辑

你说处理程序只画框体,大概率是渲染代码只处理了瓦片边界,没把查询到的要素渲染进去。正确的瓦片渲染流程应该是:

// 创建地图,设置尺寸为瓦片大小,范围为瓦片BBox
var map = new Map(tileSize);
map.CoordinateSystem = tileMatrixSet.CoordinateSystem;
map.Envelope = tileBBox;

// 创建矢量图层,添加查询到的要素
var vectorLayer = new VectorLayer("DataLayer");
vectorLayer.DataSource = new FeatureCollectionDataSource(features);
// 可以设置图层的样式,比如颜色、线宽
vectorLayer.Style.Fill = new SolidBrush(Color.FromArgb(128, Color.Blue));
vectorLayer.Style.Outline = new Pen(Color.Black, 1);

map.Layers.Add(vectorLayer);

// 渲染瓦片图片
var image = map.Render();
// 把image返回给WMTS请求的客户端

调试小技巧

  • 先把计算出来的tileBBox打印出来,直接在SQL Server里执行空间查询,比如:
    SELECT * FROM your_table WHERE ST_Intersects(geometry_column, ST_GeomFromText('POLYGON((x1 y1, x2 y1, x2 y2, x1 y2, x1 y1))', 3857))
    
    如果SQL里查不到数据,那肯定是坐标转换或者BBox计算的问题。
  • 对比WMS和WMTS的查询范围,看看两者的坐标系、范围是否匹配,有没有出现“查询范围和数据范围完全不重叠”的情况。

内容的提问来源于stack exchange,提问作者Takudzwa Mawarire

火山引擎 最新活动