计算 256 像素图块的静态 mapbox img 的经纬度

Calculate lat long on static mapbox img for 256px tiles

我有一个只有中心点 lat/long 的静态图像(例如 https://api.mapbox.com/styles/v1/mapbox/light-v9/static/-78.4649,42.5128,5,0,0/300x200),我想借助 canvas。 但我需要以某种方式计算这些标记的 xy 坐标。 所以我知道 map(lat/long) 的中心和 lat/long 标记坐标。有什么方法可以将 lat/long 转换为 xy 只知道缩放级别和中心?

或者如果我知道中心的 xy lat/long(它始终是相同的 150px * 100px)和缩放级别,我可以计算其他标记的 xy 吗?

我有很多标记(>200,它们都是自定义生成的 svg 等等)要放在这张地图上。由于标记限制等原因,我无法使用 mapbox mapbox 静态地图。

UPD: 根据评论我更新了问题。

256px的方块如何计算?

如果您要进行线性插值,则需要知道 lat/long 和 x/y 两点。除非您还有像素的转换指标,否则只有中心点是不可能的 - 即。 50 像素是 .1 增量 lat/long.

如果您有两个点的 lat/long 和 x/y,您可以将比率创建为 y1 - y2 / lat1-lat2 或 x1-x2/long1-long2,每个结果应该相同比率

那么它就相对容易了,假设比率是 5 意思是 5px/l 所以你有一个距离中心点 (3,-4) 的点,你只需multiple 找到像素偏移量 (15,-20) 并将其添加到中心 = (165, 80).

由于您的所有图像都以相同的比例缩放,您可以手动计算一次比例并将其存储为常数。

sudo/untested python:

def getRatio(latlongs=[(1,1),(0,0)], xys=[(5,5),(0,0)]:
  return (xys[0][1]-xys[1][1]) / (latlongs[0][0] - latlongs[1][0])

centerLatLong = (5,5)
centerXY = (150, 100)

def getCoord(lat,long,ratio):
  y = (lat-centerLatLong[0])*ratio + centerXY[1]
  x = (long-centerLatLong[1])*ratio + centerXY[0]
  return x, y

根据 OP 评论,为了简单起见,我假设请求的图像是方形的(TILE_SIZE 可以分解为 TILE_SIZE_XTILE_SIZE_Y 组件) .我还假设图像是 256 像素宽 TILE_SIZE=256

我给出了相对于图像中心(distanceInPixels 函数)和左下角(imageCoordinates 函数)的像素坐标。如果有必要,更改到左上角应该是微不足道的(X 将等于 Y = TILE_SIZE -Y)。

<!DOCTYPE html>
<html>
<body>      
<p id="demo"></p>    
<script>
    var latLngMarker = {};
    var latLngCenter = {};  
// Image dimensions in pixels
    var TILE_SIZE = 256; 
    var zoom = 5;   
// Coordinates of the marker to be projected on the image
    latLngMarker.lat = 41.850;
    latLngMarker.lng = -87.650; 
// Coordinates of the image center  
    latLngCenter.lat = 41.850; 
    latLngCenter.lng = -87.650;
// Coordinates projected on the cartographic plane (Mercator)     
    var centerProjected = project(latLngCenter);
    var markerProjected = project(latLngMarker);

// The result should be X=Y=0, because I made Marker Lat Lng  = Center Lat Lng
    var distanceFromCenter = distanceInPixels(centerProjected, markerProjected);
    alert("X: " + distanceFromCenter.x + " Y: " + distanceFromCenter.y);

// The result should be X=Y=256/2=128 for the same reason      
    var coords = imageCoordinates(centerProjected, markerProjected);
    alert("X: " + coords.x + " Y: " + coords.y);

    // The horizontal distance represented by one pixel for a given latitude and zoom level
    function pixelResolution (latLng, zoom) {
        var radius = 6378137.0 // semi-axis of WGS84 ellipsoid
        var circumference =  2 * Math.PI * radius;
        var distancePerImage = circumference * Math.cos(latLng.lat * Math.PI / 180.0) / Math.pow(2,zoom);
        var distancePerPixel = distancePerImage / TILE_SIZE;
        return distancePerPixel
    }   

    // Web mercator projection.
    function project(latLng) {
        var siny = Math.sin(latLng.lat * Math.PI / 180);
        siny = Math.min(Math.max(siny, -0.9999), 0.9999);
        var xy = {};
        xy.x = TILE_SIZE * (0.5 + latLng.lng / 360);
        xy.y = TILE_SIZE * (0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI));       
        return xy
    }

    // Marker pixel coordinates relative to the image Center 
    function distanceInPixels(centerProjected, markerProjected) {
        var delta = {};
        var spacing = pixelResolution(latLngCenter, zoom);
        delta.x = Math.round((centerProjected.x - markerProjected.x)/spacing);
        delta.y = Math.round((centerProjected.y - markerProjected.y)/spacing);
        return delta
    }   

    // Marker pixel coordinates relative to the Lower Left Corner
    function imageCoordinates(centerProjected, markerProjected) {
        var pixelCoordinates = {};
        var spacing = pixelResolution(latLngCenter, zoom);
        var deltaPixels = distanceInPixels(centerProjected, markerProjected);
        pixelCoordinates.x = TILE_SIZE / 2 - deltaPixels.x;
        pixelCoordinates.y = TILE_SIZE / 2 - deltaPixels.y;
        return pixelCoordinates
    }       
</script>    
</body>
</html>

注意:我可以确认 pixelResolution 函数仅适用于尺寸为 2 次幂的正方形图像块。Math.pow(2,zoom); 片段泄露了游戏信息!

Web 墨卡托函数基于:

https://developers-dot-devsite-v2-prod.appspot.com/maps/documentation/javascript/examples/map-coordinates

一个像素表示的水平距离:

https://wiki.openstreetmap.org/wiki/Zoom_levels

另请参阅:

https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale