cesium 加载天图层tilematrix为什么需要+1才能正常显示?

  • cesium 版本:1.123

cesium 加载天地图

cesiumConfig.baseLayer = new Cesium.ImageryLayer(new Cesium.WebMapTileServiceImageryProvider({
  url: `${tdtUrl}img_c/wmts?tk=${tdt_tk}`,
  layer: 'img',
  style: 'default',
  format: 'tiles',
  tileMatrixSetID: 'c',
  subdomains: subdomains,
  maximumLevel: 18,
  tilingScheme: new Cesium.GeographicTilingScheme(),
  tileMatrixLabels: Array.from({ length: 18 }, (v, k) => k + 1),
}));
tileMatrixLabels: Array.from({ length: 18 }, (v, k) => k + 1),这里+1是因为天地图的图层是从1开始,是正常的。
image.png

使用geoserver发布的wmts服务

viewer.scene.imageryLayers.add(
  new Cesium.ImageryLayer(
    new Cesium.WebMapTileServiceImageryProvider({
      url: 'http://172.88.0.31:9090/geoserver/cloud/ht/gwc/service/wmts',
      layer: 'ht:t_ds_imp_ynsbj_cn2k',
      style: '',
      tileMatrixSetID: 'CGCS2000',
      format: 'image/png',
      maximumLevel: 20,
      rectangle: Cesium.Rectangle.fromDegrees(94.5, 21.11, 109.5, 29.3),
      tileMatrixLabels: Array.from({ length: 20 }, (v, k) => `CGCS2000:${k + 1}`),
      tilingScheme: new Cesium.GeographicTilingScheme()
    })
  )
);
同样是2000坐标系,为什么我自己发的图层就需要+1?而我的服务是从0开始的。
image.png
  • 必须所有图层都+1才能正常显示
  • 如果不加1显示这样
    天地图:
    e0ce64d27f1fc34c545d98db72bbdad.png
    我的图层:
    c8dff02552dd7ac9d1068ada503e745.png

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <script src="https://cdn.bootcdn.net/ajax/libs/cesium/1.123.0/Cesium.js"></script>
  <link href="https://cdn.bootcdn.net/ajax/libs/cesium/1.123.0/Widgets/widgets.css" rel="stylesheet" />
</head>

<body>
  <div id="map"></div>
</body>

<script>
  // 替换默认的坐标系为CGCS2000
  Cesium.Ellipsoid.CGCS2000 = Object.freeze(
    // eslint-disable-next-line no-loss-of-precision
    new Cesium.Ellipsoid(6378137.0, 6378137.0, 6356752.31414035585)
  );

  Cesium.Ellipsoid.WGS84 = Cesium.Ellipsoid.CGCS2000;
  Cesium.Ellipsoid._default = Cesium.Ellipsoid.CGCS2000;

  let cesiumConfig = {
    animation: false,
    baseLayerPicker: false,
    fullscreenButton: false,
    geocoder: false,
    homeButton: false,
    infoBox: false,
    sceneModePicker: false,
    scene3DOnly: true,
    selectionIndicator: false,
    timeline: false,
    navigationHelpButton: false,
    baselLayerPicker: false,
    shadows: false,
    shouldAnimate: false,
    vrButton: false,
    requestRenderMode: true,
    mapProjection: new Cesium.GeographicProjection(Cesium.Ellipsoid.CGCS2000),
    contextOptions: {
      webgl: {
        alpha: true,
        depth: false,
        stencil: true,
        antialias: true,
        premultipliedAlpha: true,
        preserveDrawingBuffer: true,
        failIfMajorPerformanceCaveat: true
      },
      allowTextureFilterAnisotropic: true
    },
  };

  let tdtUrl = 'https://t{s}.tianditu.gov.cn/';
  let subdomains = [1, 2, 3, 4, 5, 6, 7];
  let tdt_tk = '';

  // 经纬度投影
  cesiumConfig.baseLayer = new Cesium.ImageryLayer(new Cesium.WebMapTileServiceImageryProvider({
    url: `${tdtUrl}img_c/wmts?tk=${tdt_tk}`,
    layer: 'img',
    style: 'default',
    format: 'tiles',
    tileMatrixSetID: 'c',
    subdomains: subdomains,
    maximumLevel: 18,
    tilingScheme: new Cesium.GeographicTilingScheme(),
    tileMatrixLabels: Array.from({ length: 18 }, (v, k) => k + 1),
  }));

  let cesiumBox = document.getElementById('map');
  let viewer = new Cesium.Viewer(cesiumBox, cesiumConfig);

  Cesium.CesiumTerrainProvider.fromUrl('https://t6.tianditu.gov.cn/mapservice/GetTiles?lxys=2,3,1&VERSION=1.0.0&tk=', {
    requestWaterMask: true,
    requestVertexNormals: true,
  }).then(terrainProvider => {
    viewer.terrainProvider = terrainProvider;
  });
  

  // 添加我的图层
  viewer.scene.imageryLayers.add(
    new Cesium.ImageryLayer(
      new Cesium.WebMapTileServiceImageryProvider({
        url: 'http://172.88.0.31:9090/geoserver/cloud/ht/gwc/service/wmts',
        layer: 'ht:t_ds_imp_ynsbj_cn2k',
        style: '',
        tileMatrixSetID: 'CGCS2000',
        format: 'image/png',
        maximumLevel: 20,
        rectangle: Cesium.Rectangle.fromDegrees(94.5, 21.11, 109.5, 29.3),
        tileMatrixLabels: Array.from({ length: 20 }, (v, k) => `CGCS2000:${k + 1}`),
        tilingScheme: new Cesium.GeographicTilingScheme()
      })
    )
  );
  

</script>

<style>
  html,
  body,
  #map {
    width: 100%;
    height: 100vh;
    margin: 0;
    padding: 0;
  }
</style>

</html>
阅读 620
avatarAI BotBETA

WMTS服务的tileMatrixLabels需要+1的原因与服务端的矩阵标识符定义方式有关。关键差异点如下:

  1. 天地图规范
    天地图WMTS服务强制要求tileMatrix从1开始命名(符合OGC标准),其矩阵标识符格式为纯数字层级序列,例如:1,2,3...18
  2. GeoServer的特殊实现
    GeoServer生成的WMTS矩阵标识符默认会带EPSG代码前缀(即使你使用CGCS2000),实际标识符格式为:CGCS2000:0,CGCS2000:1...CGCS2000:n(从0开始)
  3. Cesium的匹配机制
    Cesium通过tileMatrixLabels数组与服务端的实际矩阵标识符做全量匹配。若:

    tileMatrixLabels: ["CGCS2000:0","CGCS2000:1"...] // 你的服务实际标识符

    但你的代码若写成:

    Array.from({length:20}, (v,k) => `CGCS2000:${k}`) // 正确写法应该不需要+1

    此时会出现服务端标识符与客户端不匹配的404错误

  4. 为何必须+1
    通过你的截图分析,实际你的GeoServer服务并没有生成预期的CGCS2000:0标识符,而是意外生成了CGCS2000:1开始的标识符。这通常由以下原因导致:

    • GeoServer的GridSet配置错误(检查gwc的gridsets定义)
    • 发布数据时zoom level的起始值被错误设置为1
    • 自定义的gridset未正确继承CRS参数

解决方案

  1. 检查GeoServer的Tile Matrix定义:
    访问 http://你的地址/gwc/demo/ 查看实际生成的矩阵标识符
  2. 根据实际标识符动态生成labels:

    // 若服务端标识符是 CGCS2000:1 开始
    tileMatrixLabels: Array.from({length:20}, (_,k) => `CGCS2000:${k+1}`)
  3. (推荐) 修复GeoServer配置:
    在GeoServer的Gridsets中明确定义矩阵标识符从0开始,确保与服务端实际标识符一致
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题