【发布时间】:2021-08-31 20:38:24
【问题描述】:
我在EPSG:4326 投影中有一张地图,我想使用EPSG:3857 瓦片集,例如 Mapbox 中的瓦片集。但是,到目前为止,我还不能让它工作。
在this discussion ahocevar 中解释说,不支持或计划任意重新投影矢量切片,因为矢量剪辑会很复杂,并且会从弯曲的剪辑路径中引入伪影。 3857 和 4326 相对于彼此是正方形的,但支持在两者之间重新投影的代码会使库变得复杂。
ahocevar 还提到了一种解决方法,涉及来自隐藏地图的图像切片。但是,这没有任何意义,因为在任何情况下,3857 个图块都不会与 4326 个图块网格对齐,因为任何变换都无法改变图块边界的位置。
我知道有渲染到屏幕外画布和使用 Mapbox GL 的示例,但这两个都不理想,因为它们在库中运行(例如,它不适用于 map.getFeaturesAtPixel)。我想知道 openlayers 本身是否有办法做到这一点。
这是一个尝试:https://codesandbox.io/s/mvt-3857-to-4326-attempt-qsf07
以下是相关代码:
const mapboxSource = new VectorTileSource({
attributions: '© <a href="https://www.mapbox.com/map-feedback/">Mapbox</a> ' +
'© <a href="https://www.openstreetmap.org/copyright">' +
'OpenStreetMap contributors</a>',
projection: 'EPSG:4326',
tileUrlFunction: (tileCoord) => {
// Use the tile coordinate as a pseudo URL for caching purposes
return JSON.stringify(tileCoord);
},
tileLoadFunction: async (tile, urlToken) => {
const tileCoord = JSON.parse(urlToken);
console.log('tileCoord', tileCoord);
const [z, x, y] = tileCoord;
const tileUrl = url
.replace('{z}', String(z))
.replace('{x}', String(x))
.replace('{y}', String(y))
.replace('{a-d}', 'abcd'.substr(((x << z) + y) % 4, 1))
;
try {
const response = await fetch(tileUrl);
if (!response.ok) throw new Error();
const arrayBuffer = await response.arrayBuffer();
// Transform the vector tile's arrayBuffer into features and add them to the tile.
const {layers} = new VectorTile(new Protobuf(arrayBuffer));
const geojsonFeatures = [];
Object.keys(layers).forEach((layerName) => {
const layer = layers[layerName];
for (let i = 0, len = layer.length; i < len; i++) {
const geojson = layer.feature(i).toGeoJSON(x, y, z);
geojson.properties.layer = layerName;
geojsonFeatures.push(geojson);
}
});
const features = geojsonFormat.readFeatures({
type: 'FeatureCollection',
features: geojsonFeatures,
});
tile.setFeatures(features);
} catch (e) {
console.log(e);
debugger;
tile.setState(TileState.ERROR);
}
},
这只会正确加载 z:0。放大后,MVT 图层不再与 OSM 底图对齐。
我还尝试使用toContext 直接绘制到 TileImages,但无法弄清楚从坐标到图块像素的映射,而且光栅重投影看起来非常模糊。所以我放弃了,只使用了 Maptiler 的 4326 瓦片集,但我想解决这个问题。是否可以在 4326 的地图上渲染 3857 的瓦片?
谢谢
【问题讨论】:
-
证明可以将 EPSG:3857 矢量切片渲染为 EPSG:4326 地图codesandbox.io/s/drag-and-drop-custom-mvt-forked-2jr6n
-
几年前我在我们的姊妹网站上写了一个关于 gis 的问题(其中一些答案)(链接在右上角的图标上)。简而言之:开放层和传单在 z 上有不同的约定,我不得不对服务器端做一个额外的补丁(但微不足道)。
-
@Mike 是的,将单个图块绘制到 VectorLayer 很容易。但我需要将它与 Tile 图层集成,以便 openlayers 管理瓷砖的加载。如果不是,那么我必须根据视图状态手动管理磁贴加载,所以我不妨像offscreen-canvas 或mapbox-layer 示例那样绘制到画布上。但我希望它可以在 OpenLayers 中以某种方式使用 VectorTile/ImageTile 图层。
-
@GiacomoCatenazzi 是这个问题吗?:gis.stackexchange.com/questions/180356/…
-
@Matthias:是的,所以你看到你需要在 openlayer 中更正 x,y,z (但它可能取决于后端)。所以:我能够做到(而且我更喜欢大规模),但似乎没有太多支持(或者只是从未测试过)
标签: openlayers openlayers-6 vector-tiles proj4js