确定Cesium Map Tile的纬度/长度边界

时间:2016-03-24 16:57:44

标签: java math latitude-longitude cesium

我正在尝试根据我们存储在数据库中的数据生成地图图块,并使用UrlTemplateImageryProvider将它们提供给Cesium。对于每个地图图块,我需要知道纬度/长度边界以便找到匹配的数据。我使用与Google地图相同的图块方案,并使用http://host/tiles/zoom/x/y之类的请求。最初我一直在使用公式将这些地图图块坐标转换为此处的纬度/长度边界:http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_bounding_box但现在我想知道这是不是正确使用的投影。

首先,我看到的所有Web Mercator文档都说Tile 0,0 @ zoom lvl 0应该涵盖整个世界。那不是我用Cesium看到的(缩放级别0有2个图块)。也就是说,我的计算似乎适用于缩放级别0,1,2和3,但是当我进入缩放级别4时,纬度计算开始向南移动。如果我在2D Google Map上绘制我生成的lat,长点,它们看起来是正确的,但我可以清楚地看到铯请求的切片有不同的边界。所以我现在假设我只是使用错误的投影来计算图块边界。

我也在这里尝试过计算:http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/ 从像素转换为米,转换为纬度/经度,但它们似乎与网络墨卡托计算结果相同。

那么有人可以帮我弄清楚如何为Cesium请求的瓷砖计算Lat / Long边界框吗?

以下是我基于Slippy Map Tiles的方法:

public static Box getLatLonBoundsForTile(int zoom, int x, int y) {
    double longitudeMin = tile2lon(x, zoom);
    double longitudeMax = tile2lon(x + 1, zoom);
    double latitudeMin = tile2lat(y + 1, zoom);
    double latitudeMax = tile2lat(y, zoom);

    Point swPoint = new Point(longitudeMin, latitudeMin);
    Point nePoint = new Point(longitudeMax, latitudeMax);

    return new Box(swPoint, nePoint);
}

public static double getColsForZoomLevel(int zoom) {
    if (zoom == 0) return 2;
    int noTiles = 8 * (int) (Math.pow(4, zoom - 1));
    return noTiles / getRowsForZoomLevel(zoom);
}
public static double getRowsForZoomLevel(int zoom) {
    if (zoom == 0) return 1;
    return Math.pow(2, zoom);
}
public static double tile2lon(int x, int zoom) {
    return x / getColsForZoomLevel(zoom) * 360.0 - 180;
}

public static double tile2lat(int y, int zoom) {
    double n = Math.PI - (2.0 * Math.PI * y) / getRowsForZoomLevel(zoom);
    return Math.toDegrees(Math.atan(Math.sinh(n)));
}

2 个答案:

答案 0 :(得分:1)

Cesium包含一个类WebMercatorTilingSchemesource),用于计算切片的纬度/经度值(以弧度表示),在根级别具有可配置数量的切片。

对于3D渲染,通常瓦片是方形的,在所有级别上具有2的2的幂边缘长度,例如256×256像素图像。地球本身通常包裹着矩形纹理(360度宽,180度高)。为了解决这个问题,平铺方案的0级通常是两个瓷砖宽,但只有一个瓷砖高(2 x 1)。下一级是4 x 2平铺,然后是8 x 4,16 x 8等等。

要实时查看此操作,请加载Cesium Inspector,在页面右侧查找一些选项,点击+旁边的小Terrain,然后将其放入Show tile coordinates上的复选标记。对于级别,使用L绘制坐标,在平铺方案中使用XY绘制坐标。

答案 1 :(得分:0)

我刚刚发现我首先引起了这个问题。我强迫Cesium在UrlTemplateImageryProvider中使用GeographicTilingScheme。我之前的配置是这样的:

var layer = new Cesium.UrlTemplateImageryProvider({
    url : '/map/tile/{z}/{x}/{y}?debug=true',
    credit : '© Me',
    tilingScheme : new Cesium.GeographicTilingScheme(),
    maximumLevel : 11
});

我从docs中的示例复制了哪些内容。所以,现在我从配置中删除了tilingScheme,它默认为WebMercatorTilingScheme。这是新的配置:

var layer = new Cesium.UrlTemplateImageryProvider({
    url : '/map/tile/{z}/{x}/{y}?debug=true',
    credit : '© Me',
    maximumLevel : 11
});

一旦我这样做了,我不得不删除2个tile @ zoom level 0的假设并将其改回1,现在一切都可以正常使用上述方法!我刚刚改变了这个方法:

public static double getColsForZoomLevel(int zoom) {
    return getRowsForZoomLevel(zoom);
}

所以这一切都归结为古老的教训,首先检查简单的事情。