使用 Cesium 查询属性名与属性值

  

        在我最近的项目中,我开发一个 移动端离线地下管网系统,目的是通过 Cesium 来渲染地下管网的 3D 模型,并实现属性查询功能。由于这是一个离线系统,不依赖后端服务器来查询属性,因此我选择使用 Cesium 提供的接口,直接从 3D Tiles 数据中提取属性名并进行属性查询。

                在这个过程中,我的管网模型被切分成了 3D Tiles 格式,瓦片为 b3dm 文件,并且包含 Batch Table,用于存储每个模型实例的属性信息。在这篇博客中,我将分享如何利用 Cesium 的接口,通过图层名动态获取属性名,并进一步基于属性名和属性值查询管网信息。

在使用 Cesium 渲染 3D Tiles 数据时,文件结构至关重要。通过你提供的截图可以看出,我的 3D Tiles 数据包括以下几个关键文件:

  1. tileset.json:描述 3D Tiles 数据结构的元数据文件,包含每个瓦片的位置、层次以及引用的具体数据文件。
  2. grid_0_0.b3dm:一个 b3dm 文件,存储了模型的几何数据(如 glTF 数据)。
  3. grid_0_0_batchTable.json:一个 Batch Table 文件,存储模型的属性信息,用于描述每个模型实例(如名称、编号、材质等)。

        离线系统意味着所有数据都需要在本地运行,包括三维模型的渲染和属性查询。这带来了以下挑战和需求:

  1. 离线数据存储:模型切片为 3D Tiles 格式,瓦片数据保存在本地。
  2. 属性存储方式:属性信息通过 Batch Table 存储在每个 b3dm 瓦片中。
  3. 离线高效查询:在没有后端服务支持的情况下,需要直接从 3D Tiles 中提取属性并查询。

通过 Cesium 的 API,我们可以直接从瓦片的 Batch Table 中读取属性,无需额外开发后端逻辑。

核心代码实现

1. 获取属性名

在 Cesium 中,属性存储在每个 b3dm 瓦片的 Batch Table 中。我们可以递归遍历瓦片树,从每个瓦片中提取属性名。

async getPipelineFieldsFromFeatures(layerKey) {
  // 获取指定的图层
  const layer = this.pipelineLayers[layerKey.value];

  if (!layer || !(layer instanceof Cesium.Cesium3DTileset)) {
    console.error(
      `无法找到图层或图层不是有效的 Cesium3DTileset 实例: ${layerKey}`
    );
    return [];
  }

  try {
    // 确保瓦片加载完成
    await layer.readyPromise;

    // 使用 Set 确保属性字段唯一
    const uniqueFields = new Set();

    // 遍历图层中的所有瓦片
    const traverseTiles = (tile) => {
      if (tile.content && tile.content.featuresLength > 0) {
        for (let i = 0; i < tile.content.featuresLength; i++) {
          // 获取瓦片中的每个 Feature(模型实例)
          const feature = tile.content.getFeature(i);
          // 获取 Feature 的所有属性名
          const propertyIds = feature.getPropertyIds();
          propertyIds.forEach((prop) => uniqueFields.add(prop));
        }
      }
      // 递归遍历子瓦片
      tile.children.forEach(traverseTiles);
    };

    // 从根瓦片开始递归
    traverseTiles(layer._root);

    // 格式化输出属性名
    return Array.from(uniqueFields).map((field) => ({
      label: field, // 属性名的显示值
      value: field, // 属性名的真实值
    }));
  } catch (error) {
    console.error(`从图层 "${layerKey}" 提取字段失败:`, error);
    return [];
  }
}

        用户选择图层后,会动态加载该图层的所有属性字段,供用户选择查询条件。管网系统中可能包括以下属性:

  • 起点编号
  • 终点编号
  • 材质
  • 埋深
  • 规格

2. 基于属性名查询属性值

获取属性名后,我们可以通过用户指定的条件(属性名和属性值)查询模型实例。

async queryFeaturesByProperty(layerKey, fieldName, fieldValue) {
  // 获取指定的图层
  const layer = this.pipelineLayers[layerKey.value];

  if (!layer || !(layer instanceof Cesium.Cesium3DTileset)) {
    console.error(
      `无法找到图层或图层不是有效的 Cesium3DTileset 实例: ${layerKey}`
    );
    return [];
  }

  try {
    // 确保瓦片加载完成
    await layer.readyPromise;

    const matchingFeatures = [];

    // 遍历瓦片
    const traverseTiles = (tile) => {
      if (tile.content && tile.content.featuresLength > 0) {
        for (let i = 0; i < tile.content.featuresLength; i++) {
          const feature = tile.content.getFeature(i);

          // 根据属性值匹配实例
          if (feature.getProperty(fieldName) === fieldValue) {
            matchingFeatures.push(feature);
          }
        }
      }
      tile.children.forEach(traverseTiles);
    };

    traverseTiles(layer._root);

    return matchingFeatures;
  } catch (error) {
    console.error(`查询图层 "${layerKey}" 的属性失败:`, error);
    return [];
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值