我想通过输入经度和纬度从服务器获取地图图块。 由于地图图块像网格一样排列,因此我需要将经度和纬度转换为 x 和 y 位置。
我正确地实现了这个算法,但不幸的是这些不是瓦片服务器的正确坐标。 正如您在这里看到的http://tools.geofabrik.de/map/#12/52.5106/13.3989&type=Geofabrik_Standard&grid=1 柏林的正确图块坐标是缩放级别 12 上的 (2200, 1343),而算法给出的是 (2645, 1894)。
算法中的错误在哪里,或者我对这种转换如何工作的误解?
Tilesname WebCalc似乎使用与slippy maptilenames wiki页面上提供的相同代码,并输出与Geofabrik工具相同的图块名称。所以算法一定是正确的,错误似乎出在你的实现中,但你没有向我们展示。
哦,我很确定你只是混淆了经纬度。如果我以错误的顺序在 Tilesname WebCalc 中输入坐标,那么它也会返回您问题中给出的“错误”图块名称。所以你的代码没问题,只是你调用方式不对而已。
以下代码采用 lng、lat 和缩放并返回 X 和 Y 值,Z 是缩放。你需要把它放在 url 中,瞧你就得到了图块
const EARTH_RADIUS = 6378137;
const MAX_LATITUDE = 85.0511287798;
function project (lat, lng)
{
var d = Math.PI / 180,
max = MAX_LATITUDE,
lat = Math.max(Math.min(max, lat), -max),
sin = Math.sin(lat * d);
return {x: EARTH_RADIUS * lng * d,
y: EARTH_RADIUS * Math.log((1 + sin) / (1 - sin)) / 2
};
}
function zoomScale (zoom)
{
return 256 * Math.pow(2, zoom);
}
function transform (point, scale) {
scale = scale || 1;
point.x = scale * (2.495320233665337e-8 * point.x + 0.5);
point.y = scale * (-2.495320233665337e-8 * point.y + 0.5);
return point;
}
var point1 = project (lat1, lng1);
var scaledZoom = zoomScale (zoom);
point1 = transform (point1, scaledZoom);
point1 就是你需要的 X 和 Y
@ wiki.openstreetmap.org提供了一些代码。
使用示例:
let lon2tile = (lon,zoom) => { return (Math.floor((lon+180)/360*Math.pow(2,zoom))); }
let lat2tile = (lat,zoom) => { return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom))); }
let zoom = 12,
latitude = 48.858,
longitude = 2.295,
x = lon2tile(longitude, zoom),
y = lat2tile(latitude, zoom);
console.log(
zoom, x, y
)
img.src = `https://a.tile.openstreetmap.org/${zoom}/${x}/${y}.png`
<img id="img"></img>
https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#ECMAScript_(JavaScript/ActionScript,_etc.)