使用 EPSG:25832 投影在 Leaflet 中垂直对齐 TMS 瓷砖

2022-01-12 00:00:00 gis leaflet javascript proj4js

我正在使用带有 Proj4Leaflet 的 Leaflet 来处理 25832 中的图块.该应用程序非常简单:我正在尝试将 EPSG:25832 中的图块叠加到全尺寸底图上.我已经从 tilemap 元信息中复制了各个分辨率和来源.我面临的问题是地图没有对齐,一旦我放大图块,就没有按正确的顺序放置.我很感激这里的任何支持(顺便说一下,

解决方案

这归结为 TMS 瓦片是倒置的(向北时它会变高,而默认的 TileLayers 会在向南时 Y 坐标变大).

看看 处理此特定功能的传单代码将阐明该问题:

 if (this._map && !this._map.options.crs.infinite) {var reverseY = this._globalTileRange.max.y - coords.y;如果(this.options.tms){数据['y'] = 倒置 Y;}数据['-y'] = 倒置 Y;}

在此处计算图块的正确 Y 坐标有两点至关重要:

  • CRS 必须是有限的(它必须有边界)
  • 必须有一个有限的全局图块范围(在 Leaflet 中为 最终由 CRS 边界定义,而不是 TileLayer 边界)

长话短说,您的 CRS 应该用已知的界限来定义.对于这种特殊情况,请从 TMS 功能文档中获取信息...

...在定义Leaflet CRS时变成了一个L.Bounds定义,比如...

//定义 CRSvar rs25832 = 新 L.Proj.CRS('EPSG:25832',proj4rs25832def,{来源:[273211.2532533697, 6111822.37943825],决议:决议,界限:[[273211.2532533697, 5200000],[961083.6232988155, 6111822.37943825]]});

东西应该可以正常工作(无需将 CRS 传递给 tilelayer,因为它们都会使用地图),如 工作示例.

I am using Leaflet with Proj4Leaflet to work with tiles in 25832. The application is fairly simple: I am trying to overlay tiles in EPSG:25832 onto a omniscale basemap. I have copied the individual resolutions and origin from the tilemap meta information. The problem I am facing is that the map is not aligned and once I zoom in the tiles are not placed in the correct order. I'd appreciate any kind of support here (by the way, this is a working example which is using openlayers).

I guess I am doing something wrong here:

// Set resolutions
var resolutions = [156367.7919628329,78183.89598141646,39091.94799070823,19545.973995354114,9772.986997677057,4886.4934988385285,2443.2467494192642,1221.6233747096321,610.8116873548161,305.40584367740803,152.70292183870401,76.35146091935201,38.175730459676004,19.087865229838002,9.543932614919001,4.7719663074595005,2.3859831537297502,1.1929915768648751];

// Define CRS
var rs25832 = new L.Proj.CRS(
    'EPSG:25832',
    proj4rs25832def, 
    {
        origin: [ 273211.2532533697, 6111822.37943825 ],
        resolutions: resolutions
    }
);

...using the tiles information from https://mapproxy.bba.atenekom.eu/tms/1.0.0/privat_alle_50_mbit/germany .

Afterwards I add a tile layer

var url = 'https://mapproxy.bba.atenekom.eu/tms/1.0.0/privat_alle_50_mbit/germany/{z}/{x}/{y}.png';  

var tileLayer = L.tileLayer(
    url, 
    {
        tms: true,
        crs: rs25832,
        continuousWorld: true,
        maxZoom: resolutions.length
    }
);

And add them to the map..

// Setup map
var map = L.map('map', {
    crs: rs25832,
    center: [ 50.8805, 7.3389 ],
    zoom:5,
    maxZoom: resolutions.length,
    layers: [ baseWms, tileLayer ]
});

The bare minimum of code can be found here: https://jsfiddle.net/6gcam7w5/8/

解决方案

This boils down to how the Y coordinate of TMS tiles is inverted (it becomes higher when going north, as opposed to default TileLayers, in which the Y coordinate becomes larger when going south).

Having a look on the Leaflet code that takes care of this specific feature will shed some light on the issue:

    if (this._map && !this._map.options.crs.infinite) {
        var invertedY = this._globalTileRange.max.y - coords.y;
        if (this.options.tms) {
            data['y'] = invertedY;
        }
        data['-y'] = invertedY;
    }

There are two things critical to calculating the right Y coordinate for your tiles here:

  • The CRS must be finite (it must have bounds)
  • There must be a finite global tile range (which in Leaflet is ultimately defined by the CRS bounds and not the TileLayer bounds)

Long story short, your CRS should be defined with known bounds. For this particular case, taking information from the TMS capabilities document...

<BoundingBox minx="273211.2532533697" miny="5200000.0" maxx="961083.6232988155" maxy="6111822.37943825"/>

...and turned into a L.Bounds definition when defining the Leaflet CRS, like...

// Define CRS
var rs25832 = new L.Proj.CRS(
    'EPSG:25832',
    proj4rs25832def, 
    {
        origin: [ 273211.2532533697, 6111822.37943825 ],
        resolutions: resolutions,
        bounds: [[273211.2532533697, 5200000],[961083.6232988155, 6111822.37943825]]
    }
);

Stuff should just work (with no need to pass the CRS to the tilelayers, since they will all use the map's), as in this working example.

相关文章