【问题标题】:Determining Lat/Long bounds for Cesium Map Tiles确定 Cesium Map Tiles 的纬度/经度边界
【发布时间】:2016-03-24 16:57:43
【问题描述】:

我正在尝试根据我们存储在数据库中的数据生成地图图块,并使用 UrlTemplateImageryProvider 将它们提供给 Cesium。对于每个地图图块,我需要知道纬度/经度边界才能找到匹配的数据。我正在使用与谷歌地图相同的图块方案,请求类似于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 谷歌地图上绘制我生成的经纬度点,它们看起来是正确的,但我可以清楚地看到 cesium 请求的图块具有不同的界限。所以我现在假设我只是使用错误的投影来计算图块边界。

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

那么谁能帮我弄清楚如何计算 Cesium 请求的瓷砖的纬度/经度边界框?

以下是我基于 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)));
}

【问题讨论】:

    标签: java math latitude-longitude cesium


    【解决方案1】:

    Cesium 包含一个类 WebMercatorTilingScheme (source),它计算瓦片的纬度/经度值(以弧度为单位),在根级别具有可配置的瓦片数量。

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

    要实时查看此操作,请加载Cesium Inspector,在页面右侧查找一些选项,单击Terrain 旁边的小+,然后勾选Show tile coordinates .使用L 绘制水平坐标,使用XY 绘制平铺方案中的位置。

    【讨论】:

    • 感谢您的信息。当我发现我实际上根本没有使用那个平铺方案时,我正在努力实现 WebMercatorTilingScheme 中的计算!感谢您指出 Cesium Inspector。这是一个方便的工具!
    【解决方案2】:

    我刚刚发现问题是我一开始就造成的。我强迫 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 个图块 @ 缩放级别 0 并将其更改回 1,现在一切都可以使用上述方法正常工作!我只是像这样改变了这个方法:

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

    所以这一切都归结为首先检查简单事物的古老课程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-17
      • 2014-05-15
      • 2011-07-29
      • 1970-01-01
      • 2017-03-03
      • 2013-01-16
      • 2013-03-17
      • 2013-10-27
      相关资源
      最近更新 更多